OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include <string> | |
6 | |
7 #include "base/memory/ref_counted.h" | |
8 #include "base/memory/scoped_ptr.h" | |
9 #include "base/memory/scoped_vector.h" | |
10 #include "base/strings/stringprintf.h" | |
11 #include "base/strings/utf_string_conversions.h" | |
12 #include "net/base/address_list.h" | |
13 #include "net/base/io_buffer.h" | |
14 #include "net/base/net_errors.h" | |
15 #include "net/base/net_util.h" | |
16 #include "net/base/request_priority.h" | |
17 #include "net/dns/host_cache.h" | |
18 #include "net/dns/mock_host_resolver.h" | |
19 #include "net/http/http_auth_challenge_tokenizer.h" | |
20 #include "net/http/http_auth_handler_mock.h" | |
21 #include "net/http/http_network_session.h" | |
22 #include "net/http/http_network_transaction.h" | |
23 #include "net/http/http_request_info.h" | |
24 #include "net/http/http_server_properties_impl.h" | |
25 #include "net/proxy/proxy_config_service.h" | |
26 #include "net/proxy/proxy_service.h" | |
27 #include "net/socket/client_socket_handle.h" | |
28 #include "net/socket/client_socket_pool_histograms.h" | |
29 #include "net/socket/client_socket_pool_manager.h" | |
30 #include "net/socket/socket_test_util.h" | |
31 #include "net/ssl/ssl_config_service_defaults.h" | |
32 #include "testing/gmock/include/gmock/gmock.h" | |
33 #include "testing/gtest/include/gtest/gtest.h" | |
34 | |
35 using testing::StrEq; | |
36 | |
37 namespace net { | |
38 | |
39 namespace { | |
40 | |
41 class SimpleProxyConfigService : public ProxyConfigService { | |
42 public: | |
43 virtual void AddObserver(Observer* observer) OVERRIDE { | |
44 observer_ = observer; | |
45 } | |
46 | |
47 virtual void RemoveObserver(Observer* observer) OVERRIDE { | |
48 if (observer_ == observer) { | |
49 observer_ = NULL; | |
50 } | |
51 } | |
52 | |
53 virtual ConfigAvailability GetLatestProxyConfig( | |
54 ProxyConfig* config) OVERRIDE { | |
55 *config = config_; | |
56 return CONFIG_VALID; | |
57 } | |
58 | |
59 void IncrementConfigId() { | |
60 config_.set_id(config_.id() + 1); | |
61 observer_->OnProxyConfigChanged(config_, ProxyConfigService::CONFIG_VALID); | |
62 } | |
63 | |
64 private: | |
65 ProxyConfig config_; | |
66 Observer* observer_; | |
67 }; | |
68 | |
69 class HttpPipelinedNetworkTransactionTest : public testing::Test { | |
70 public: | |
71 HttpPipelinedNetworkTransactionTest() | |
72 : histograms_("a"), | |
73 pool_(1, 1, &histograms_, &factory_) { | |
74 } | |
75 | |
76 void Initialize(bool force_http_pipelining) { | |
77 // Normally, this code could just go in SetUp(). For a few of these tests, | |
78 // we change the default number of sockets per group. That needs to be done | |
79 // before we construct the HttpNetworkSession. | |
80 proxy_config_service_ = new SimpleProxyConfigService(); | |
81 proxy_service_.reset(new ProxyService(proxy_config_service_, NULL, NULL)); | |
82 ssl_config_ = new SSLConfigServiceDefaults; | |
83 auth_handler_factory_.reset(new HttpAuthHandlerMock::Factory()); | |
84 | |
85 HttpNetworkSession::Params session_params; | |
86 session_params.client_socket_factory = &factory_; | |
87 session_params.proxy_service = proxy_service_.get(); | |
88 session_params.host_resolver = &mock_resolver_; | |
89 session_params.ssl_config_service = ssl_config_.get(); | |
90 session_params.http_auth_handler_factory = auth_handler_factory_.get(); | |
91 session_params.http_server_properties = | |
92 http_server_properties_.GetWeakPtr(); | |
93 session_params.force_http_pipelining = force_http_pipelining; | |
94 session_params.http_pipelining_enabled = true; | |
95 session_ = new HttpNetworkSession(session_params); | |
96 } | |
97 | |
98 void AddExpectedConnection(MockRead* reads, size_t reads_count, | |
99 MockWrite* writes, size_t writes_count) { | |
100 DeterministicSocketData* data = new DeterministicSocketData( | |
101 reads, reads_count, writes, writes_count); | |
102 data->set_connect_data(MockConnect(SYNCHRONOUS, OK)); | |
103 if (reads_count || writes_count) { | |
104 data->StopAfter(reads_count + writes_count); | |
105 } | |
106 factory_.AddSocketDataProvider(data); | |
107 data_vector_.push_back(data); | |
108 } | |
109 | |
110 enum RequestInfoOptions { | |
111 REQUEST_DEFAULT, | |
112 REQUEST_MAIN_RESOURCE, | |
113 }; | |
114 | |
115 HttpRequestInfo* GetRequestInfo( | |
116 const char* filename, RequestInfoOptions options = REQUEST_DEFAULT) { | |
117 std::string url = base::StringPrintf("http://localhost/%s", filename); | |
118 HttpRequestInfo* request_info = new HttpRequestInfo; | |
119 request_info->url = GURL(url); | |
120 request_info->method = "GET"; | |
121 if (options == REQUEST_MAIN_RESOURCE) { | |
122 request_info->load_flags = LOAD_MAIN_FRAME; | |
123 } | |
124 request_info_vector_.push_back(request_info); | |
125 return request_info; | |
126 } | |
127 | |
128 void ExpectResponse(const std::string& expected, | |
129 HttpNetworkTransaction& transaction, | |
130 IoMode io_mode) { | |
131 scoped_refptr<IOBuffer> buffer(new IOBuffer(expected.size())); | |
132 if (io_mode == ASYNC) { | |
133 EXPECT_EQ(ERR_IO_PENDING, transaction.Read(buffer.get(), expected.size(), | |
134 callback_.callback())); | |
135 data_vector_[0]->RunFor(1); | |
136 EXPECT_EQ(static_cast<int>(expected.length()), callback_.WaitForResult()); | |
137 } else { | |
138 EXPECT_EQ(static_cast<int>(expected.size()), | |
139 transaction.Read(buffer.get(), expected.size(), | |
140 callback_.callback())); | |
141 } | |
142 std::string actual(buffer->data(), expected.size()); | |
143 EXPECT_THAT(actual, StrEq(expected)); | |
144 EXPECT_EQ(OK, transaction.Read(buffer.get(), expected.size(), | |
145 callback_.callback())); | |
146 } | |
147 | |
148 void CompleteTwoRequests(int data_index, int stop_at_step) { | |
149 scoped_ptr<HttpNetworkTransaction> one_transaction( | |
150 new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get())); | |
151 TestCompletionCallback one_callback; | |
152 EXPECT_EQ(ERR_IO_PENDING, | |
153 one_transaction->Start(GetRequestInfo("one.html"), | |
154 one_callback.callback(), BoundNetLog())); | |
155 EXPECT_EQ(OK, one_callback.WaitForResult()); | |
156 | |
157 HttpNetworkTransaction two_transaction(DEFAULT_PRIORITY, session_.get()); | |
158 TestCompletionCallback two_callback; | |
159 EXPECT_EQ(ERR_IO_PENDING, | |
160 two_transaction.Start(GetRequestInfo("two.html"), | |
161 two_callback.callback(), BoundNetLog())); | |
162 | |
163 TestCompletionCallback one_read_callback; | |
164 scoped_refptr<IOBuffer> buffer(new IOBuffer(8)); | |
165 EXPECT_EQ(ERR_IO_PENDING, | |
166 one_transaction->Read(buffer.get(), 8, | |
167 one_read_callback.callback())); | |
168 | |
169 data_vector_[data_index]->SetStop(stop_at_step); | |
170 data_vector_[data_index]->Run(); | |
171 EXPECT_EQ(8, one_read_callback.WaitForResult()); | |
172 data_vector_[data_index]->SetStop(10); | |
173 std::string actual(buffer->data(), 8); | |
174 EXPECT_THAT(actual, StrEq("one.html")); | |
175 EXPECT_EQ(OK, one_transaction->Read(buffer.get(), 8, | |
176 one_read_callback.callback())); | |
177 | |
178 EXPECT_EQ(OK, two_callback.WaitForResult()); | |
179 ExpectResponse("two.html", two_transaction, SYNCHRONOUS); | |
180 } | |
181 | |
182 void CompleteFourRequests(RequestInfoOptions options) { | |
183 scoped_ptr<HttpNetworkTransaction> one_transaction( | |
184 new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get())); | |
185 TestCompletionCallback one_callback; | |
186 EXPECT_EQ(ERR_IO_PENDING, | |
187 one_transaction->Start(GetRequestInfo("one.html", options), | |
188 one_callback.callback(), BoundNetLog())); | |
189 EXPECT_EQ(OK, one_callback.WaitForResult()); | |
190 | |
191 HttpNetworkTransaction two_transaction(DEFAULT_PRIORITY, session_.get()); | |
192 TestCompletionCallback two_callback; | |
193 EXPECT_EQ(ERR_IO_PENDING, | |
194 two_transaction.Start(GetRequestInfo("two.html", options), | |
195 two_callback.callback(), BoundNetLog())); | |
196 | |
197 HttpNetworkTransaction three_transaction(DEFAULT_PRIORITY, session_.get()); | |
198 TestCompletionCallback three_callback; | |
199 EXPECT_EQ(ERR_IO_PENDING, | |
200 three_transaction.Start(GetRequestInfo("three.html", options), | |
201 three_callback.callback(), | |
202 BoundNetLog())); | |
203 | |
204 HttpNetworkTransaction four_transaction(DEFAULT_PRIORITY, session_.get()); | |
205 TestCompletionCallback four_callback; | |
206 EXPECT_EQ(ERR_IO_PENDING, | |
207 four_transaction.Start(GetRequestInfo("four.html", options), | |
208 four_callback.callback(), BoundNetLog())); | |
209 | |
210 ExpectResponse("one.html", *one_transaction.get(), SYNCHRONOUS); | |
211 EXPECT_EQ(OK, two_callback.WaitForResult()); | |
212 ExpectResponse("two.html", two_transaction, SYNCHRONOUS); | |
213 EXPECT_EQ(OK, three_callback.WaitForResult()); | |
214 ExpectResponse("three.html", three_transaction, SYNCHRONOUS); | |
215 | |
216 one_transaction.reset(); | |
217 EXPECT_EQ(OK, four_callback.WaitForResult()); | |
218 ExpectResponse("four.html", four_transaction, SYNCHRONOUS); | |
219 } | |
220 | |
221 DeterministicMockClientSocketFactory factory_; | |
222 ClientSocketPoolHistograms histograms_; | |
223 MockTransportClientSocketPool pool_; | |
224 ScopedVector<DeterministicSocketData> data_vector_; | |
225 TestCompletionCallback callback_; | |
226 ScopedVector<HttpRequestInfo> request_info_vector_; | |
227 | |
228 SimpleProxyConfigService* proxy_config_service_; | |
229 scoped_ptr<ProxyService> proxy_service_; | |
230 MockHostResolver mock_resolver_; | |
231 scoped_refptr<SSLConfigService> ssl_config_; | |
232 scoped_ptr<HttpAuthHandlerMock::Factory> auth_handler_factory_; | |
233 HttpServerPropertiesImpl http_server_properties_; | |
234 scoped_refptr<HttpNetworkSession> session_; | |
235 }; | |
236 | |
237 TEST_F(HttpPipelinedNetworkTransactionTest, OneRequest) { | |
238 Initialize(false); | |
239 | |
240 MockWrite writes[] = { | |
241 MockWrite(SYNCHRONOUS, 0, "GET /test.html HTTP/1.1\r\n" | |
242 "Host: localhost\r\n" | |
243 "Connection: keep-alive\r\n\r\n"), | |
244 }; | |
245 MockRead reads[] = { | |
246 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"), | |
247 MockRead(SYNCHRONOUS, 2, "Content-Length: 9\r\n\r\n"), | |
248 MockRead(SYNCHRONOUS, 3, "test.html"), | |
249 }; | |
250 AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes)); | |
251 | |
252 HttpNetworkTransaction transaction(DEFAULT_PRIORITY, session_.get()); | |
253 EXPECT_EQ(ERR_IO_PENDING, | |
254 transaction.Start(GetRequestInfo("test.html"), callback_.callback(), | |
255 BoundNetLog())); | |
256 EXPECT_EQ(OK, callback_.WaitForResult()); | |
257 ExpectResponse("test.html", transaction, SYNCHRONOUS); | |
258 } | |
259 | |
260 TEST_F(HttpPipelinedNetworkTransactionTest, ReusePipeline) { | |
261 Initialize(false); | |
262 | |
263 MockWrite writes[] = { | |
264 MockWrite(SYNCHRONOUS, 0, "GET /one.html HTTP/1.1\r\n" | |
265 "Host: localhost\r\n" | |
266 "Connection: keep-alive\r\n\r\n"), | |
267 MockWrite(SYNCHRONOUS, 3, "GET /two.html HTTP/1.1\r\n" | |
268 "Host: localhost\r\n" | |
269 "Connection: keep-alive\r\n\r\n"), | |
270 }; | |
271 MockRead reads[] = { | |
272 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"), | |
273 MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"), | |
274 MockRead(ASYNC, 4, "one.html"), | |
275 MockRead(SYNCHRONOUS, 5, "HTTP/1.1 200 OK\r\n"), | |
276 MockRead(SYNCHRONOUS, 6, "Content-Length: 8\r\n\r\n"), | |
277 MockRead(SYNCHRONOUS, 7, "two.html"), | |
278 }; | |
279 AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes)); | |
280 | |
281 CompleteTwoRequests(0, 5); | |
282 } | |
283 | |
284 TEST_F(HttpPipelinedNetworkTransactionTest, ReusesOnSpaceAvailable) { | |
285 int old_max_sockets = ClientSocketPoolManager::max_sockets_per_group( | |
286 HttpNetworkSession::NORMAL_SOCKET_POOL); | |
287 ClientSocketPoolManager::set_max_sockets_per_group( | |
288 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); | |
289 Initialize(false); | |
290 | |
291 MockWrite writes[] = { | |
292 MockWrite(SYNCHRONOUS, 0, "GET /one.html HTTP/1.1\r\n" | |
293 "Host: localhost\r\n" | |
294 "Connection: keep-alive\r\n\r\n"), | |
295 MockWrite(SYNCHRONOUS, 4, "GET /two.html HTTP/1.1\r\n" | |
296 "Host: localhost\r\n" | |
297 "Connection: keep-alive\r\n\r\n"), | |
298 MockWrite(SYNCHRONOUS, 7, "GET /three.html HTTP/1.1\r\n" | |
299 "Host: localhost\r\n" | |
300 "Connection: keep-alive\r\n\r\n"), | |
301 MockWrite(SYNCHRONOUS, 12, "GET /four.html HTTP/1.1\r\n" | |
302 "Host: localhost\r\n" | |
303 "Connection: keep-alive\r\n\r\n"), | |
304 }; | |
305 MockRead reads[] = { | |
306 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"), | |
307 MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"), | |
308 MockRead(SYNCHRONOUS, 3, "one.html"), | |
309 MockRead(SYNCHRONOUS, 5, "HTTP/1.1 200 OK\r\n"), | |
310 MockRead(SYNCHRONOUS, 6, "Content-Length: 8\r\n\r\n"), | |
311 MockRead(SYNCHRONOUS, 8, "two.html"), | |
312 MockRead(SYNCHRONOUS, 9, "HTTP/1.1 200 OK\r\n"), | |
313 MockRead(SYNCHRONOUS, 10, "Content-Length: 10\r\n\r\n"), | |
314 MockRead(SYNCHRONOUS, 11, "three.html"), | |
315 MockRead(SYNCHRONOUS, 13, "HTTP/1.1 200 OK\r\n"), | |
316 MockRead(SYNCHRONOUS, 14, "Content-Length: 9\r\n\r\n"), | |
317 MockRead(SYNCHRONOUS, 15, "four.html"), | |
318 }; | |
319 AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes)); | |
320 | |
321 CompleteFourRequests(REQUEST_DEFAULT); | |
322 | |
323 ClientSocketPoolManager::set_max_sockets_per_group( | |
324 HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_sockets); | |
325 } | |
326 | |
327 TEST_F(HttpPipelinedNetworkTransactionTest, WontPipelineMainResource) { | |
328 int old_max_sockets = ClientSocketPoolManager::max_sockets_per_group( | |
329 HttpNetworkSession::NORMAL_SOCKET_POOL); | |
330 ClientSocketPoolManager::set_max_sockets_per_group( | |
331 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); | |
332 Initialize(false); | |
333 | |
334 MockWrite writes[] = { | |
335 MockWrite(SYNCHRONOUS, 0, "GET /one.html HTTP/1.1\r\n" | |
336 "Host: localhost\r\n" | |
337 "Connection: keep-alive\r\n\r\n"), | |
338 MockWrite(SYNCHRONOUS, 4, "GET /two.html HTTP/1.1\r\n" | |
339 "Host: localhost\r\n" | |
340 "Connection: keep-alive\r\n\r\n"), | |
341 MockWrite(SYNCHRONOUS, 8, "GET /three.html HTTP/1.1\r\n" | |
342 "Host: localhost\r\n" | |
343 "Connection: keep-alive\r\n\r\n"), | |
344 MockWrite(SYNCHRONOUS, 12, "GET /four.html HTTP/1.1\r\n" | |
345 "Host: localhost\r\n" | |
346 "Connection: keep-alive\r\n\r\n"), | |
347 }; | |
348 MockRead reads[] = { | |
349 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"), | |
350 MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"), | |
351 MockRead(SYNCHRONOUS, 3, "one.html"), | |
352 MockRead(SYNCHRONOUS, 5, "HTTP/1.1 200 OK\r\n"), | |
353 MockRead(SYNCHRONOUS, 6, "Content-Length: 8\r\n\r\n"), | |
354 MockRead(SYNCHRONOUS, 7, "two.html"), | |
355 MockRead(SYNCHRONOUS, 9, "HTTP/1.1 200 OK\r\n"), | |
356 MockRead(SYNCHRONOUS, 10, "Content-Length: 10\r\n\r\n"), | |
357 MockRead(SYNCHRONOUS, 11, "three.html"), | |
358 MockRead(SYNCHRONOUS, 13, "HTTP/1.1 200 OK\r\n"), | |
359 MockRead(SYNCHRONOUS, 14, "Content-Length: 9\r\n\r\n"), | |
360 MockRead(SYNCHRONOUS, 15, "four.html"), | |
361 }; | |
362 AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes)); | |
363 | |
364 CompleteFourRequests(REQUEST_MAIN_RESOURCE); | |
365 | |
366 ClientSocketPoolManager::set_max_sockets_per_group( | |
367 HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_sockets); | |
368 } | |
369 | |
370 TEST_F(HttpPipelinedNetworkTransactionTest, UnknownSizeEvictsToNewPipeline) { | |
371 Initialize(false); | |
372 | |
373 MockWrite writes[] = { | |
374 MockWrite(SYNCHRONOUS, 0, "GET /one.html HTTP/1.1\r\n" | |
375 "Host: localhost\r\n" | |
376 "Connection: keep-alive\r\n\r\n"), | |
377 }; | |
378 MockRead reads[] = { | |
379 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n\r\n"), | |
380 MockRead(ASYNC, 2, "one.html"), | |
381 MockRead(SYNCHRONOUS, OK, 3), | |
382 }; | |
383 AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes)); | |
384 | |
385 MockWrite writes2[] = { | |
386 MockWrite(SYNCHRONOUS, 0, "GET /two.html HTTP/1.1\r\n" | |
387 "Host: localhost\r\n" | |
388 "Connection: keep-alive\r\n\r\n"), | |
389 }; | |
390 MockRead reads2[] = { | |
391 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"), | |
392 MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"), | |
393 MockRead(SYNCHRONOUS, 3, "two.html"), | |
394 }; | |
395 AddExpectedConnection(reads2, arraysize(reads2), writes2, arraysize(writes2)); | |
396 | |
397 CompleteTwoRequests(0, 3); | |
398 } | |
399 | |
400 TEST_F(HttpPipelinedNetworkTransactionTest, ConnectionCloseEvictToNewPipeline) { | |
401 Initialize(false); | |
402 | |
403 MockWrite writes[] = { | |
404 MockWrite(SYNCHRONOUS, 0, "GET /one.html HTTP/1.1\r\n" | |
405 "Host: localhost\r\n" | |
406 "Connection: keep-alive\r\n\r\n"), | |
407 MockWrite(SYNCHRONOUS, 3, "GET /two.html HTTP/1.1\r\n" | |
408 "Host: localhost\r\n" | |
409 "Connection: keep-alive\r\n\r\n"), | |
410 }; | |
411 MockRead reads[] = { | |
412 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"), | |
413 MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"), | |
414 MockRead(ASYNC, 4, "one.html"), | |
415 MockRead(SYNCHRONOUS, ERR_SOCKET_NOT_CONNECTED, 5), | |
416 }; | |
417 AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes)); | |
418 | |
419 MockWrite writes2[] = { | |
420 MockWrite(SYNCHRONOUS, 0, "GET /two.html HTTP/1.1\r\n" | |
421 "Host: localhost\r\n" | |
422 "Connection: keep-alive\r\n\r\n"), | |
423 }; | |
424 MockRead reads2[] = { | |
425 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"), | |
426 MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"), | |
427 MockRead(SYNCHRONOUS, 3, "two.html"), | |
428 }; | |
429 AddExpectedConnection(reads2, arraysize(reads2), writes2, arraysize(writes2)); | |
430 | |
431 CompleteTwoRequests(0, 5); | |
432 } | |
433 | |
434 TEST_F(HttpPipelinedNetworkTransactionTest, ErrorEvictsToNewPipeline) { | |
435 Initialize(false); | |
436 | |
437 MockWrite writes[] = { | |
438 MockWrite(SYNCHRONOUS, 0, "GET /one.html HTTP/1.1\r\n" | |
439 "Host: localhost\r\n" | |
440 "Connection: keep-alive\r\n\r\n"), | |
441 MockWrite(SYNCHRONOUS, 3, "GET /two.html HTTP/1.1\r\n" | |
442 "Host: localhost\r\n" | |
443 "Connection: keep-alive\r\n\r\n"), | |
444 }; | |
445 MockRead reads[] = { | |
446 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n\r\n"), | |
447 MockRead(SYNCHRONOUS, ERR_FAILED, 2), | |
448 }; | |
449 AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes)); | |
450 | |
451 MockWrite writes2[] = { | |
452 MockWrite(SYNCHRONOUS, 0, "GET /two.html HTTP/1.1\r\n" | |
453 "Host: localhost\r\n" | |
454 "Connection: keep-alive\r\n\r\n"), | |
455 }; | |
456 MockRead reads2[] = { | |
457 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"), | |
458 MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"), | |
459 MockRead(SYNCHRONOUS, 3, "two.html"), | |
460 }; | |
461 AddExpectedConnection(reads2, arraysize(reads2), writes2, arraysize(writes2)); | |
462 | |
463 HttpNetworkTransaction one_transaction(DEFAULT_PRIORITY, session_.get()); | |
464 TestCompletionCallback one_callback; | |
465 EXPECT_EQ(ERR_IO_PENDING, | |
466 one_transaction.Start(GetRequestInfo("one.html"), | |
467 one_callback.callback(), BoundNetLog())); | |
468 EXPECT_EQ(OK, one_callback.WaitForResult()); | |
469 | |
470 HttpNetworkTransaction two_transaction(DEFAULT_PRIORITY, session_.get()); | |
471 TestCompletionCallback two_callback; | |
472 EXPECT_EQ(ERR_IO_PENDING, | |
473 two_transaction.Start(GetRequestInfo("two.html"), | |
474 two_callback.callback(), BoundNetLog())); | |
475 | |
476 scoped_refptr<IOBuffer> buffer(new IOBuffer(1)); | |
477 EXPECT_EQ(ERR_FAILED, | |
478 one_transaction.Read(buffer.get(), 1, callback_.callback())); | |
479 EXPECT_EQ(OK, two_callback.WaitForResult()); | |
480 ExpectResponse("two.html", two_transaction, SYNCHRONOUS); | |
481 } | |
482 | |
483 TEST_F(HttpPipelinedNetworkTransactionTest, SendErrorEvictsToNewPipeline) { | |
484 Initialize(false); | |
485 | |
486 MockWrite writes[] = { | |
487 MockWrite(ASYNC, ERR_FAILED, 0), | |
488 }; | |
489 AddExpectedConnection(NULL, 0, writes, arraysize(writes)); | |
490 | |
491 MockWrite writes2[] = { | |
492 MockWrite(SYNCHRONOUS, 0, "GET /two.html HTTP/1.1\r\n" | |
493 "Host: localhost\r\n" | |
494 "Connection: keep-alive\r\n\r\n"), | |
495 }; | |
496 MockRead reads2[] = { | |
497 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"), | |
498 MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"), | |
499 MockRead(SYNCHRONOUS, 3, "two.html"), | |
500 }; | |
501 AddExpectedConnection(reads2, arraysize(reads2), writes2, arraysize(writes2)); | |
502 | |
503 HttpNetworkTransaction one_transaction(DEFAULT_PRIORITY, session_.get()); | |
504 TestCompletionCallback one_callback; | |
505 EXPECT_EQ(ERR_IO_PENDING, | |
506 one_transaction.Start(GetRequestInfo("one.html"), | |
507 one_callback.callback(), BoundNetLog())); | |
508 | |
509 HttpNetworkTransaction two_transaction(DEFAULT_PRIORITY, session_.get()); | |
510 TestCompletionCallback two_callback; | |
511 EXPECT_EQ(ERR_IO_PENDING, | |
512 two_transaction.Start(GetRequestInfo("two.html"), | |
513 two_callback.callback(), BoundNetLog())); | |
514 | |
515 data_vector_[0]->RunFor(1); | |
516 EXPECT_EQ(ERR_FAILED, one_callback.WaitForResult()); | |
517 | |
518 EXPECT_EQ(OK, two_callback.WaitForResult()); | |
519 ExpectResponse("two.html", two_transaction, SYNCHRONOUS); | |
520 } | |
521 | |
522 TEST_F(HttpPipelinedNetworkTransactionTest, RedirectDrained) { | |
523 Initialize(false); | |
524 | |
525 MockWrite writes[] = { | |
526 MockWrite(SYNCHRONOUS, 0, "GET /redirect.html HTTP/1.1\r\n" | |
527 "Host: localhost\r\n" | |
528 "Connection: keep-alive\r\n\r\n"), | |
529 MockWrite(SYNCHRONOUS, 3, "GET /two.html HTTP/1.1\r\n" | |
530 "Host: localhost\r\n" | |
531 "Connection: keep-alive\r\n\r\n"), | |
532 }; | |
533 MockRead reads[] = { | |
534 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 302 OK\r\n"), | |
535 MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"), | |
536 MockRead(ASYNC, 4, "redirect"), | |
537 MockRead(SYNCHRONOUS, 5, "HTTP/1.1 200 OK\r\n"), | |
538 MockRead(SYNCHRONOUS, 6, "Content-Length: 8\r\n\r\n"), | |
539 MockRead(SYNCHRONOUS, 7, "two.html"), | |
540 }; | |
541 AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes)); | |
542 | |
543 scoped_ptr<HttpNetworkTransaction> one_transaction( | |
544 new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get())); | |
545 TestCompletionCallback one_callback; | |
546 EXPECT_EQ(ERR_IO_PENDING, | |
547 one_transaction->Start(GetRequestInfo("redirect.html"), | |
548 one_callback.callback(), BoundNetLog())); | |
549 EXPECT_EQ(OK, one_callback.WaitForResult()); | |
550 | |
551 HttpNetworkTransaction two_transaction(DEFAULT_PRIORITY, session_.get()); | |
552 TestCompletionCallback two_callback; | |
553 EXPECT_EQ(ERR_IO_PENDING, | |
554 two_transaction.Start(GetRequestInfo("two.html"), | |
555 two_callback.callback(), BoundNetLog())); | |
556 | |
557 one_transaction.reset(); | |
558 data_vector_[0]->RunFor(2); | |
559 data_vector_[0]->SetStop(10); | |
560 | |
561 EXPECT_EQ(OK, two_callback.WaitForResult()); | |
562 ExpectResponse("two.html", two_transaction, SYNCHRONOUS); | |
563 } | |
564 | |
565 TEST_F(HttpPipelinedNetworkTransactionTest, BasicHttpAuthentication) { | |
566 Initialize(false); | |
567 | |
568 MockWrite writes[] = { | |
569 MockWrite(SYNCHRONOUS, 0, "GET /one.html HTTP/1.1\r\n" | |
570 "Host: localhost\r\n" | |
571 "Connection: keep-alive\r\n\r\n"), | |
572 MockWrite(SYNCHRONOUS, 5, "GET /one.html HTTP/1.1\r\n" | |
573 "Host: localhost\r\n" | |
574 "Connection: keep-alive\r\n" | |
575 "Authorization: auth_token\r\n\r\n"), | |
576 }; | |
577 MockRead reads[] = { | |
578 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 401 Authentication Required\r\n"), | |
579 MockRead(SYNCHRONOUS, 2, | |
580 "WWW-Authenticate: Basic realm=\"Secure Area\"\r\n"), | |
581 MockRead(SYNCHRONOUS, 3, "Content-Length: 20\r\n\r\n"), | |
582 MockRead(SYNCHRONOUS, 4, "needs authentication"), | |
583 MockRead(SYNCHRONOUS, 6, "HTTP/1.1 200 OK\r\n"), | |
584 MockRead(SYNCHRONOUS, 7, "Content-Length: 8\r\n\r\n"), | |
585 MockRead(SYNCHRONOUS, 8, "one.html"), | |
586 }; | |
587 AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes)); | |
588 | |
589 HttpAuthHandlerMock* mock_auth = new HttpAuthHandlerMock; | |
590 std::string challenge_text = "Basic"; | |
591 HttpAuthChallengeTokenizer challenge(challenge_text.begin(), | |
592 challenge_text.end()); | |
593 GURL origin("localhost"); | |
594 EXPECT_TRUE(mock_auth->InitFromChallenge(&challenge, | |
595 HttpAuth::AUTH_SERVER, | |
596 origin, | |
597 BoundNetLog())); | |
598 auth_handler_factory_->AddMockHandler(mock_auth, HttpAuth::AUTH_SERVER); | |
599 | |
600 HttpNetworkTransaction transaction(DEFAULT_PRIORITY, session_.get()); | |
601 EXPECT_EQ(ERR_IO_PENDING, | |
602 transaction.Start(GetRequestInfo("one.html"), | |
603 callback_.callback(), | |
604 BoundNetLog())); | |
605 EXPECT_EQ(OK, callback_.WaitForResult()); | |
606 | |
607 AuthCredentials credentials(base::ASCIIToUTF16("user"), | |
608 base::ASCIIToUTF16("pass")); | |
609 EXPECT_EQ(OK, transaction.RestartWithAuth(credentials, callback_.callback())); | |
610 | |
611 ExpectResponse("one.html", transaction, SYNCHRONOUS); | |
612 } | |
613 | |
614 TEST_F(HttpPipelinedNetworkTransactionTest, OldVersionDisablesPipelining) { | |
615 Initialize(false); | |
616 | |
617 MockWrite writes[] = { | |
618 MockWrite(SYNCHRONOUS, 0, "GET /pipelined.html HTTP/1.1\r\n" | |
619 "Host: localhost\r\n" | |
620 "Connection: keep-alive\r\n\r\n"), | |
621 }; | |
622 MockRead reads[] = { | |
623 MockRead(SYNCHRONOUS, 1, "HTTP/1.0 200 OK\r\n"), | |
624 MockRead(SYNCHRONOUS, 2, "Content-Length: 14\r\n\r\n"), | |
625 MockRead(SYNCHRONOUS, 3, "pipelined.html"), | |
626 }; | |
627 AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes)); | |
628 | |
629 MockWrite writes2[] = { | |
630 MockWrite(SYNCHRONOUS, 0, "GET /one.html HTTP/1.1\r\n" | |
631 "Host: localhost\r\n" | |
632 "Connection: keep-alive\r\n\r\n"), | |
633 }; | |
634 MockRead reads2[] = { | |
635 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"), | |
636 MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"), | |
637 MockRead(ASYNC, 3, "one.html"), | |
638 MockRead(SYNCHRONOUS, OK, 4), | |
639 }; | |
640 AddExpectedConnection(reads2, arraysize(reads2), writes2, arraysize(writes2)); | |
641 | |
642 MockWrite writes3[] = { | |
643 MockWrite(SYNCHRONOUS, 0, "GET /two.html HTTP/1.1\r\n" | |
644 "Host: localhost\r\n" | |
645 "Connection: keep-alive\r\n\r\n"), | |
646 }; | |
647 MockRead reads3[] = { | |
648 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"), | |
649 MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"), | |
650 MockRead(SYNCHRONOUS, 3, "two.html"), | |
651 MockRead(SYNCHRONOUS, OK, 4), | |
652 }; | |
653 AddExpectedConnection(reads3, arraysize(reads3), writes3, arraysize(writes3)); | |
654 | |
655 HttpNetworkTransaction one_transaction(DEFAULT_PRIORITY, session_.get()); | |
656 TestCompletionCallback one_callback; | |
657 EXPECT_EQ(ERR_IO_PENDING, | |
658 one_transaction.Start(GetRequestInfo("pipelined.html"), | |
659 one_callback.callback(), BoundNetLog())); | |
660 EXPECT_EQ(OK, one_callback.WaitForResult()); | |
661 ExpectResponse("pipelined.html", one_transaction, SYNCHRONOUS); | |
662 | |
663 CompleteTwoRequests(1, 4); | |
664 } | |
665 | |
666 TEST_F(HttpPipelinedNetworkTransactionTest, PipelinesImmediatelyIfKnownGood) { | |
667 // The first request gets us an HTTP/1.1. The next 3 test pipelining. When the | |
668 // 3rd request completes, we know pipelining is safe. After the first 4 | |
669 // complete, the 5th and 6th should then be immediately sent pipelined on a | |
670 // new HttpPipelinedConnection. | |
671 int old_max_sockets = ClientSocketPoolManager::max_sockets_per_group( | |
672 HttpNetworkSession::NORMAL_SOCKET_POOL); | |
673 ClientSocketPoolManager::set_max_sockets_per_group( | |
674 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); | |
675 Initialize(false); | |
676 | |
677 MockWrite writes[] = { | |
678 MockWrite(SYNCHRONOUS, 0, "GET /one.html HTTP/1.1\r\n" | |
679 "Host: localhost\r\n" | |
680 "Connection: keep-alive\r\n\r\n"), | |
681 MockWrite(SYNCHRONOUS, 4, "GET /two.html HTTP/1.1\r\n" | |
682 "Host: localhost\r\n" | |
683 "Connection: keep-alive\r\n\r\n"), | |
684 MockWrite(SYNCHRONOUS, 7, "GET /three.html HTTP/1.1\r\n" | |
685 "Host: localhost\r\n" | |
686 "Connection: keep-alive\r\n\r\n"), | |
687 MockWrite(SYNCHRONOUS, 12, "GET /four.html HTTP/1.1\r\n" | |
688 "Host: localhost\r\n" | |
689 "Connection: keep-alive\r\n\r\n"), | |
690 MockWrite(SYNCHRONOUS, 16, "GET /second-pipeline-one.html HTTP/1.1\r\n" | |
691 "Host: localhost\r\n" | |
692 "Connection: keep-alive\r\n\r\n"), | |
693 MockWrite(SYNCHRONOUS, 17, "GET /second-pipeline-two.html HTTP/1.1\r\n" | |
694 "Host: localhost\r\n" | |
695 "Connection: keep-alive\r\n\r\n"), | |
696 }; | |
697 MockRead reads[] = { | |
698 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"), | |
699 MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"), | |
700 MockRead(SYNCHRONOUS, 3, "one.html"), | |
701 MockRead(SYNCHRONOUS, 5, "HTTP/1.1 200 OK\r\n"), | |
702 MockRead(SYNCHRONOUS, 6, "Content-Length: 8\r\n\r\n"), | |
703 MockRead(SYNCHRONOUS, 8, "two.html"), | |
704 MockRead(SYNCHRONOUS, 9, "HTTP/1.1 200 OK\r\n"), | |
705 MockRead(SYNCHRONOUS, 10, "Content-Length: 10\r\n\r\n"), | |
706 MockRead(SYNCHRONOUS, 11, "three.html"), | |
707 MockRead(SYNCHRONOUS, 13, "HTTP/1.1 200 OK\r\n"), | |
708 MockRead(SYNCHRONOUS, 14, "Content-Length: 9\r\n\r\n"), | |
709 MockRead(SYNCHRONOUS, 15, "four.html"), | |
710 MockRead(ASYNC, 18, "HTTP/1.1 200 OK\r\n"), | |
711 MockRead(ASYNC, 19, "Content-Length: 24\r\n\r\n"), | |
712 MockRead(SYNCHRONOUS, 20, "second-pipeline-one.html"), | |
713 MockRead(SYNCHRONOUS, 21, "HTTP/1.1 200 OK\r\n"), | |
714 MockRead(SYNCHRONOUS, 22, "Content-Length: 24\r\n\r\n"), | |
715 MockRead(SYNCHRONOUS, 23, "second-pipeline-two.html"), | |
716 }; | |
717 AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes)); | |
718 | |
719 CompleteFourRequests(REQUEST_DEFAULT); | |
720 | |
721 HttpNetworkTransaction second_one_transaction( | |
722 DEFAULT_PRIORITY, session_.get()); | |
723 TestCompletionCallback second_one_callback; | |
724 EXPECT_EQ(ERR_IO_PENDING, | |
725 second_one_transaction.Start( | |
726 GetRequestInfo("second-pipeline-one.html"), | |
727 second_one_callback.callback(), BoundNetLog())); | |
728 base::MessageLoop::current()->RunUntilIdle(); | |
729 | |
730 HttpNetworkTransaction second_two_transaction( | |
731 DEFAULT_PRIORITY, session_.get()); | |
732 TestCompletionCallback second_two_callback; | |
733 EXPECT_EQ(ERR_IO_PENDING, | |
734 second_two_transaction.Start( | |
735 GetRequestInfo("second-pipeline-two.html"), | |
736 second_two_callback.callback(), BoundNetLog())); | |
737 | |
738 data_vector_[0]->RunFor(3); | |
739 EXPECT_EQ(OK, second_one_callback.WaitForResult()); | |
740 data_vector_[0]->StopAfter(100); | |
741 ExpectResponse("second-pipeline-one.html", second_one_transaction, | |
742 SYNCHRONOUS); | |
743 EXPECT_EQ(OK, second_two_callback.WaitForResult()); | |
744 ExpectResponse("second-pipeline-two.html", second_two_transaction, | |
745 SYNCHRONOUS); | |
746 | |
747 ClientSocketPoolManager::set_max_sockets_per_group( | |
748 HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_sockets); | |
749 } | |
750 | |
751 class DataRunnerObserver : public base::MessageLoop::TaskObserver { | |
752 public: | |
753 DataRunnerObserver(DeterministicSocketData* data, int run_before_task) | |
754 : data_(data), | |
755 run_before_task_(run_before_task), | |
756 current_task_(0) { } | |
757 | |
758 virtual void WillProcessTask(const base::PendingTask& pending_task) OVERRIDE { | |
759 ++current_task_; | |
760 if (current_task_ == run_before_task_) { | |
761 data_->Run(); | |
762 base::MessageLoop::current()->RemoveTaskObserver(this); | |
763 } | |
764 } | |
765 | |
766 virtual void DidProcessTask(const base::PendingTask& pending_task) OVERRIDE {} | |
767 | |
768 private: | |
769 DeterministicSocketData* data_; | |
770 int run_before_task_; | |
771 int current_task_; | |
772 }; | |
773 | |
774 TEST_F(HttpPipelinedNetworkTransactionTest, OpenPipelinesWhileBinding) { | |
775 // There was a racy crash in the pipelining code. This test recreates that | |
776 // race. The steps are: | |
777 // 1. The first request starts a pipeline and requests headers. | |
778 // 2. HttpStreamFactoryImpl::Job tries to bind a pending request to a new | |
779 // pipeline and queues a task to do so. | |
780 // 3. Before that task runs, the first request receives its headers and | |
781 // determines this host is probably capable of pipelining. | |
782 // 4. All of the hosts' pipelines are notified they have capacity in a loop. | |
783 // 5. On the first iteration, the first pipeline is opened up to accept new | |
784 // requests and steals the request from step #2. | |
785 // 6. The pipeline from #2 is deleted because it has no streams. | |
786 // 7. On the second iteration, the host tries to notify the pipeline from step | |
787 // #2 that it has capacity. This is a use-after-free. | |
788 Initialize(false); | |
789 | |
790 MockWrite writes[] = { | |
791 MockWrite(SYNCHRONOUS, 0, "GET /one.html HTTP/1.1\r\n" | |
792 "Host: localhost\r\n" | |
793 "Connection: keep-alive\r\n\r\n"), | |
794 MockWrite(ASYNC, 3, "GET /two.html HTTP/1.1\r\n" | |
795 "Host: localhost\r\n" | |
796 "Connection: keep-alive\r\n\r\n"), | |
797 }; | |
798 MockRead reads[] = { | |
799 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"), | |
800 MockRead(ASYNC, 2, "Content-Length: 8\r\n\r\n"), | |
801 MockRead(SYNCHRONOUS, 4, "one.html"), | |
802 MockRead(SYNCHRONOUS, 5, "HTTP/1.1 200 OK\r\n"), | |
803 MockRead(SYNCHRONOUS, 6, "Content-Length: 8\r\n\r\n"), | |
804 MockRead(SYNCHRONOUS, 7, "two.html"), | |
805 }; | |
806 AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes)); | |
807 | |
808 AddExpectedConnection(NULL, 0, NULL, 0); | |
809 | |
810 HttpNetworkTransaction one_transaction(DEFAULT_PRIORITY, session_.get()); | |
811 TestCompletionCallback one_callback; | |
812 EXPECT_EQ(ERR_IO_PENDING, | |
813 one_transaction.Start(GetRequestInfo("one.html"), | |
814 one_callback.callback(), BoundNetLog())); | |
815 | |
816 data_vector_[0]->SetStop(2); | |
817 data_vector_[0]->Run(); | |
818 | |
819 HttpNetworkTransaction two_transaction(DEFAULT_PRIORITY, session_.get()); | |
820 TestCompletionCallback two_callback; | |
821 EXPECT_EQ(ERR_IO_PENDING, | |
822 two_transaction.Start(GetRequestInfo("two.html"), | |
823 two_callback.callback(), BoundNetLog())); | |
824 // Posted tasks should be: | |
825 // 1. MockHostResolverBase::ResolveNow | |
826 // 2. HttpStreamFactoryImpl::Job::OnStreamReadyCallback for job 1 | |
827 // 3. HttpStreamFactoryImpl::Job::OnStreamReadyCallback for job 2 | |
828 // | |
829 // We need to make sure that the response that triggers OnPipelineFeedback(OK) | |
830 // is called in between when task #3 is scheduled and when it runs. The | |
831 // DataRunnerObserver does that. | |
832 DataRunnerObserver observer(data_vector_[0], 3); | |
833 base::MessageLoop::current()->AddTaskObserver(&observer); | |
834 data_vector_[0]->SetStop(4); | |
835 base::MessageLoop::current()->RunUntilIdle(); | |
836 data_vector_[0]->SetStop(10); | |
837 | |
838 EXPECT_EQ(OK, one_callback.WaitForResult()); | |
839 ExpectResponse("one.html", one_transaction, SYNCHRONOUS); | |
840 EXPECT_EQ(OK, two_callback.WaitForResult()); | |
841 ExpectResponse("two.html", two_transaction, SYNCHRONOUS); | |
842 } | |
843 | |
844 TEST_F(HttpPipelinedNetworkTransactionTest, ProxyChangesWhileConnecting) { | |
845 Initialize(false); | |
846 | |
847 DeterministicSocketData data(NULL, 0, NULL, 0); | |
848 data.set_connect_data(MockConnect(ASYNC, ERR_CONNECTION_REFUSED)); | |
849 factory_.AddSocketDataProvider(&data); | |
850 | |
851 DeterministicSocketData data2(NULL, 0, NULL, 0); | |
852 data2.set_connect_data(MockConnect(ASYNC, ERR_FAILED)); | |
853 factory_.AddSocketDataProvider(&data2); | |
854 | |
855 HttpNetworkTransaction transaction(DEFAULT_PRIORITY, session_.get()); | |
856 EXPECT_EQ(ERR_IO_PENDING, | |
857 transaction.Start(GetRequestInfo("test.html"), callback_.callback(), | |
858 BoundNetLog())); | |
859 | |
860 proxy_config_service_->IncrementConfigId(); | |
861 | |
862 EXPECT_EQ(ERR_FAILED, callback_.WaitForResult()); | |
863 } | |
864 | |
865 TEST_F(HttpPipelinedNetworkTransactionTest, ForcedPipelineSharesConnection) { | |
866 Initialize(true); | |
867 | |
868 MockWrite writes[] = { | |
869 MockWrite(ASYNC, 0, "GET /one.html HTTP/1.1\r\n" | |
870 "Host: localhost\r\n" | |
871 "Connection: keep-alive\r\n\r\n" | |
872 "GET /two.html HTTP/1.1\r\n" | |
873 "Host: localhost\r\n" | |
874 "Connection: keep-alive\r\n\r\n"), | |
875 }; | |
876 MockRead reads[] = { | |
877 MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n"), | |
878 MockRead(ASYNC, 2, "Content-Length: 8\r\n\r\n"), | |
879 MockRead(ASYNC, 3, "one.html"), | |
880 MockRead(ASYNC, 4, "HTTP/1.1 200 OK\r\n"), | |
881 MockRead(ASYNC, 5, "Content-Length: 8\r\n\r\n"), | |
882 MockRead(ASYNC, 6, "two.html"), | |
883 }; | |
884 AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes)); | |
885 | |
886 scoped_ptr<HttpNetworkTransaction> one_transaction( | |
887 new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get())); | |
888 TestCompletionCallback one_callback; | |
889 EXPECT_EQ(ERR_IO_PENDING, | |
890 one_transaction->Start(GetRequestInfo("one.html"), | |
891 one_callback.callback(), BoundNetLog())); | |
892 | |
893 HttpNetworkTransaction two_transaction(DEFAULT_PRIORITY, session_.get()); | |
894 TestCompletionCallback two_callback; | |
895 EXPECT_EQ(ERR_IO_PENDING, | |
896 two_transaction.Start(GetRequestInfo("two.html"), | |
897 two_callback.callback(), BoundNetLog())); | |
898 | |
899 data_vector_[0]->RunFor(3); // Send + 2 lines of headers. | |
900 EXPECT_EQ(OK, one_callback.WaitForResult()); | |
901 ExpectResponse("one.html", *one_transaction.get(), ASYNC); | |
902 one_transaction.reset(); | |
903 | |
904 data_vector_[0]->RunFor(2); // 2 lines of headers. | |
905 EXPECT_EQ(OK, two_callback.WaitForResult()); | |
906 ExpectResponse("two.html", two_transaction, ASYNC); | |
907 } | |
908 | |
909 TEST_F(HttpPipelinedNetworkTransactionTest, | |
910 ForcedPipelineConnectionErrorFailsBoth) { | |
911 Initialize(true); | |
912 | |
913 DeterministicSocketData data(NULL, 0, NULL, 0); | |
914 data.set_connect_data(MockConnect(ASYNC, ERR_FAILED)); | |
915 factory_.AddSocketDataProvider(&data); | |
916 | |
917 scoped_ptr<HttpNetworkTransaction> one_transaction( | |
918 new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get())); | |
919 TestCompletionCallback one_callback; | |
920 EXPECT_EQ(ERR_IO_PENDING, | |
921 one_transaction->Start(GetRequestInfo("one.html"), | |
922 one_callback.callback(), BoundNetLog())); | |
923 | |
924 HttpNetworkTransaction two_transaction(DEFAULT_PRIORITY, session_.get()); | |
925 TestCompletionCallback two_callback; | |
926 EXPECT_EQ(ERR_IO_PENDING, | |
927 two_transaction.Start(GetRequestInfo("two.html"), | |
928 two_callback.callback(), BoundNetLog())); | |
929 | |
930 data.Run(); | |
931 EXPECT_EQ(ERR_FAILED, one_callback.WaitForResult()); | |
932 EXPECT_EQ(ERR_FAILED, two_callback.WaitForResult()); | |
933 } | |
934 | |
935 TEST_F(HttpPipelinedNetworkTransactionTest, ForcedPipelineEvictionIsFatal) { | |
936 Initialize(true); | |
937 | |
938 MockWrite writes[] = { | |
939 MockWrite(ASYNC, 0, "GET /one.html HTTP/1.1\r\n" | |
940 "Host: localhost\r\n" | |
941 "Connection: keep-alive\r\n\r\n" | |
942 "GET /two.html HTTP/1.1\r\n" | |
943 "Host: localhost\r\n" | |
944 "Connection: keep-alive\r\n\r\n"), | |
945 }; | |
946 MockRead reads[] = { | |
947 MockRead(ASYNC, ERR_FAILED, 1), | |
948 }; | |
949 AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes)); | |
950 | |
951 scoped_ptr<HttpNetworkTransaction> one_transaction( | |
952 new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get())); | |
953 TestCompletionCallback one_callback; | |
954 EXPECT_EQ(ERR_IO_PENDING, | |
955 one_transaction->Start(GetRequestInfo("one.html"), | |
956 one_callback.callback(), BoundNetLog())); | |
957 | |
958 HttpNetworkTransaction two_transaction(DEFAULT_PRIORITY, session_.get()); | |
959 TestCompletionCallback two_callback; | |
960 EXPECT_EQ(ERR_IO_PENDING, | |
961 two_transaction.Start(GetRequestInfo("two.html"), | |
962 two_callback.callback(), BoundNetLog())); | |
963 | |
964 data_vector_[0]->RunFor(2); | |
965 EXPECT_EQ(ERR_FAILED, one_callback.WaitForResult()); | |
966 one_transaction.reset(); | |
967 EXPECT_EQ(ERR_PIPELINE_EVICTION, two_callback.WaitForResult()); | |
968 } | |
969 | |
970 TEST_F(HttpPipelinedNetworkTransactionTest, ForcedPipelineOrder) { | |
971 Initialize(true); | |
972 | |
973 MockWrite writes[] = { | |
974 MockWrite(ASYNC, 0, | |
975 "GET /one.html HTTP/1.1\r\n" | |
976 "Host: localhost\r\n" | |
977 "Connection: keep-alive\r\n\r\n" | |
978 "GET /two.html HTTP/1.1\r\n" | |
979 "Host: localhost\r\n" | |
980 "Connection: keep-alive\r\n\r\n" | |
981 "GET /three.html HTTP/1.1\r\n" | |
982 "Host: localhost\r\n" | |
983 "Connection: keep-alive\r\n\r\n" | |
984 "GET /four.html HTTP/1.1\r\n" | |
985 "Host: localhost\r\n" | |
986 "Connection: keep-alive\r\n\r\n" | |
987 ), | |
988 }; | |
989 MockRead reads[] = { | |
990 MockRead(ASYNC, ERR_FAILED, 1), | |
991 }; | |
992 DeterministicSocketData data( | |
993 reads, arraysize(reads), writes, arraysize(writes)); | |
994 data.set_connect_data(MockConnect(ASYNC, OK)); | |
995 factory_.AddSocketDataProvider(&data); | |
996 | |
997 scoped_ptr<HttpNetworkTransaction> one_transaction( | |
998 new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get())); | |
999 TestCompletionCallback one_callback; | |
1000 EXPECT_EQ(ERR_IO_PENDING, | |
1001 one_transaction->Start(GetRequestInfo("one.html"), | |
1002 one_callback.callback(), BoundNetLog())); | |
1003 | |
1004 scoped_ptr<HttpNetworkTransaction> two_transaction( | |
1005 new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get())); | |
1006 TestCompletionCallback two_callback; | |
1007 EXPECT_EQ(ERR_IO_PENDING, | |
1008 two_transaction->Start(GetRequestInfo("two.html"), | |
1009 two_callback.callback(), BoundNetLog())); | |
1010 | |
1011 scoped_ptr<HttpNetworkTransaction> three_transaction( | |
1012 new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get())); | |
1013 TestCompletionCallback three_callback; | |
1014 EXPECT_EQ(ERR_IO_PENDING, | |
1015 three_transaction->Start(GetRequestInfo("three.html"), | |
1016 three_callback.callback(), BoundNetLog())); | |
1017 | |
1018 scoped_ptr<HttpNetworkTransaction> four_transaction( | |
1019 new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get())); | |
1020 TestCompletionCallback four_callback; | |
1021 EXPECT_EQ(ERR_IO_PENDING, | |
1022 four_transaction->Start(GetRequestInfo("four.html"), | |
1023 four_callback.callback(), BoundNetLog())); | |
1024 | |
1025 data.RunFor(3); | |
1026 EXPECT_EQ(ERR_FAILED, one_callback.WaitForResult()); | |
1027 one_transaction.reset(); | |
1028 EXPECT_EQ(ERR_PIPELINE_EVICTION, two_callback.WaitForResult()); | |
1029 two_transaction.reset(); | |
1030 EXPECT_EQ(ERR_PIPELINE_EVICTION, three_callback.WaitForResult()); | |
1031 three_transaction.reset(); | |
1032 EXPECT_EQ(ERR_PIPELINE_EVICTION, four_callback.WaitForResult()); | |
1033 } | |
1034 | |
1035 } // anonymous namespace | |
1036 | |
1037 } // namespace net | |
OLD | NEW |