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 "net/http/http_network_transaction.h" | |
6 | |
7 #include <math.h> // ceil | |
8 #include <stdarg.h> | |
9 #include <string> | |
10 #include <vector> | |
11 | |
12 #include "base/basictypes.h" | |
13 #include "base/compiler_specific.h" | |
14 #include "base/file_path.h" | |
15 #include "base/file_util.h" | |
16 #include "base/memory/scoped_ptr.h" | |
17 #include "base/metrics/histogram.h" | |
18 #include "base/test/test_file_util.h" | |
19 #include "base/utf_string_conversions.h" | |
20 #include "net/base/auth.h" | |
21 #include "net/base/capturing_net_log.h" | |
22 #include "net/base/completion_callback.h" | |
23 #include "net/base/host_cache.h" | |
24 #include "net/base/mock_host_resolver.h" | |
25 #include "net/base/net_log.h" | |
26 #include "net/base/net_log_unittest.h" | |
27 #include "net/base/request_priority.h" | |
28 #include "net/base/ssl_cert_request_info.h" | |
29 #include "net/base/ssl_config_service_defaults.h" | |
30 #include "net/base/ssl_info.h" | |
31 #include "net/base/test_completion_callback.h" | |
32 #include "net/base/upload_data.h" | |
33 #include "net/http/http_auth_handler_digest.h" | |
34 #include "net/http/http_auth_handler_mock.h" | |
35 #include "net/http/http_auth_handler_ntlm.h" | |
36 #include "net/http/http_basic_stream.h" | |
37 #include "net/http/http_net_log_params.h" | |
38 #include "net/http/http_network_session.h" | |
39 #include "net/http/http_network_session_peer.h" | |
40 #include "net/http/http_server_properties_impl.h" | |
41 #include "net/http/http_stream.h" | |
42 #include "net/http/http_stream_factory.h" | |
43 #include "net/http/http_transaction_unittest.h" | |
44 #include "net/proxy/proxy_config_service_fixed.h" | |
45 #include "net/proxy/proxy_resolver.h" | |
46 #include "net/proxy/proxy_service.h" | |
47 #include "net/socket/client_socket_factory.h" | |
48 #include "net/socket/mock_client_socket_pool_manager.h" | |
49 #include "net/socket/socket_test_util.h" | |
50 #include "net/socket/ssl_client_socket.h" | |
51 #include "net/spdy/spdy_framer.h" | |
52 #include "net/spdy/spdy_session.h" | |
53 #include "net/spdy/spdy_session_pool.h" | |
54 #include "net/spdy/spdy_test_util.h" | |
55 #include "testing/gtest/include/gtest/gtest.h" | |
56 #include "testing/platform_test.h" | |
57 | |
58 //----------------------------------------------------------------------------- | |
59 | |
60 namespace { | |
61 | |
62 const string16 kBar(ASCIIToUTF16("bar")); | |
63 const string16 kBar2(ASCIIToUTF16("bar2")); | |
64 const string16 kBar3(ASCIIToUTF16("bar3")); | |
65 const string16 kBaz(ASCIIToUTF16("baz")); | |
66 const string16 kFirst(ASCIIToUTF16("first")); | |
67 const string16 kFoo(ASCIIToUTF16("foo")); | |
68 const string16 kFoo2(ASCIIToUTF16("foo2")); | |
69 const string16 kFoo3(ASCIIToUTF16("foo3")); | |
70 const string16 kFou(ASCIIToUTF16("fou")); | |
71 const string16 kSecond(ASCIIToUTF16("second")); | |
72 const string16 kTestingNTLM(ASCIIToUTF16("testing-ntlm")); | |
73 const string16 kWrongPassword(ASCIIToUTF16("wrongpassword")); | |
74 | |
75 // MakeNextProtos is a utility function that returns a vector of std::strings | |
76 // from its arguments. Don't forget to terminate the argument list with a NULL. | |
77 std::vector<std::string> MakeNextProtos(const char* a, ...) { | |
78 std::vector<std::string> ret; | |
79 ret.push_back(a); | |
80 | |
81 va_list args; | |
82 va_start(args, a); | |
83 | |
84 for (;;) { | |
85 const char* value = va_arg(args, const char*); | |
86 if (value == NULL) | |
87 break; | |
88 ret.push_back(value); | |
89 } | |
90 va_end(args); | |
91 | |
92 return ret; | |
93 } | |
94 | |
95 // SpdyNextProtos returns a vector of NPN protocol strings for negotiating | |
96 // SPDY. | |
97 std::vector<std::string> SpdyNextProtos() { | |
98 return MakeNextProtos("http/1.1", "spdy/2", "spdy/2.1", NULL); | |
99 } | |
100 | |
101 } // namespace | |
102 | |
103 namespace net { | |
104 | |
105 // Helper to manage the lifetimes of the dependencies for a | |
106 // HttpNetworkTransaction. | |
107 struct SessionDependencies { | |
108 // Default set of dependencies -- "null" proxy service. | |
109 SessionDependencies() | |
110 : host_resolver(new MockHostResolver), | |
111 cert_verifier(new CertVerifier), | |
112 proxy_service(ProxyService::CreateDirect()), | |
113 ssl_config_service(new SSLConfigServiceDefaults), | |
114 http_auth_handler_factory( | |
115 HttpAuthHandlerFactory::CreateDefault(host_resolver.get())), | |
116 net_log(NULL) {} | |
117 | |
118 // Custom proxy service dependency. | |
119 explicit SessionDependencies(ProxyService* proxy_service) | |
120 : host_resolver(new MockHostResolver), | |
121 cert_verifier(new CertVerifier), | |
122 proxy_service(proxy_service), | |
123 ssl_config_service(new SSLConfigServiceDefaults), | |
124 http_auth_handler_factory( | |
125 HttpAuthHandlerFactory::CreateDefault(host_resolver.get())), | |
126 net_log(NULL) {} | |
127 | |
128 scoped_ptr<MockHostResolverBase> host_resolver; | |
129 scoped_ptr<CertVerifier> cert_verifier; | |
130 scoped_ptr<ProxyService> proxy_service; | |
131 scoped_refptr<SSLConfigService> ssl_config_service; | |
132 MockClientSocketFactory socket_factory; | |
133 scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory; | |
134 HttpServerPropertiesImpl http_server_properties; | |
135 NetLog* net_log; | |
136 }; | |
137 | |
138 HttpNetworkSession* CreateSession(SessionDependencies* session_deps) { | |
139 net::HttpNetworkSession::Params params; | |
140 params.client_socket_factory = &session_deps->socket_factory; | |
141 params.host_resolver = session_deps->host_resolver.get(); | |
142 params.cert_verifier = session_deps->cert_verifier.get(); | |
143 params.proxy_service = session_deps->proxy_service.get(); | |
144 params.ssl_config_service = session_deps->ssl_config_service; | |
145 params.http_auth_handler_factory = | |
146 session_deps->http_auth_handler_factory.get(); | |
147 params.http_server_properties = &session_deps->http_server_properties; | |
148 params.net_log = session_deps->net_log; | |
149 return new HttpNetworkSession(params); | |
150 } | |
151 | |
152 class HttpNetworkTransactionTest : public PlatformTest { | |
153 protected: | |
154 struct SimpleGetHelperResult { | |
155 int rv; | |
156 std::string status_line; | |
157 std::string response_data; | |
158 }; | |
159 | |
160 virtual void SetUp() { | |
161 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); | |
162 MessageLoop::current()->RunAllPending(); | |
163 spdy::SpdyFramer::set_enable_compression_default(false); | |
164 } | |
165 | |
166 virtual void TearDown() { | |
167 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); | |
168 MessageLoop::current()->RunAllPending(); | |
169 spdy::SpdyFramer::set_enable_compression_default(true); | |
170 // Empty the current queue. | |
171 MessageLoop::current()->RunAllPending(); | |
172 PlatformTest::TearDown(); | |
173 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); | |
174 MessageLoop::current()->RunAllPending(); | |
175 } | |
176 | |
177 // Either |write_failure| specifies a write failure or |read_failure| | |
178 // specifies a read failure when using a reused socket. In either case, the | |
179 // failure should cause the network transaction to resend the request, and the | |
180 // other argument should be NULL. | |
181 void KeepAliveConnectionResendRequestTest(const MockWrite* write_failure, | |
182 const MockRead* read_failure); | |
183 | |
184 SimpleGetHelperResult SimpleGetHelperForData(StaticSocketDataProvider* data[], | |
185 size_t data_count) { | |
186 SimpleGetHelperResult out; | |
187 | |
188 HttpRequestInfo request; | |
189 request.method = "GET"; | |
190 request.url = GURL("http://www.google.com/"); | |
191 request.load_flags = 0; | |
192 | |
193 SessionDependencies session_deps; | |
194 scoped_ptr<HttpTransaction> trans( | |
195 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
196 | |
197 for (size_t i = 0; i < data_count; ++i) { | |
198 session_deps.socket_factory.AddSocketDataProvider(data[i]); | |
199 } | |
200 | |
201 TestCompletionCallback callback; | |
202 | |
203 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
204 EXPECT_TRUE(log.bound().IsLoggingAllEvents()); | |
205 int rv = trans->Start(&request, callback.callback(), log.bound()); | |
206 EXPECT_EQ(ERR_IO_PENDING, rv); | |
207 | |
208 out.rv = callback.WaitForResult(); | |
209 if (out.rv != OK) | |
210 return out; | |
211 | |
212 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
213 // Can't use ASSERT_* inside helper functions like this, so | |
214 // return an error. | |
215 if (response == NULL || response->headers == NULL) { | |
216 out.rv = ERR_UNEXPECTED; | |
217 return out; | |
218 } | |
219 out.status_line = response->headers->GetStatusLine(); | |
220 | |
221 EXPECT_EQ("192.0.2.33", response->socket_address.host()); | |
222 EXPECT_EQ(0, response->socket_address.port()); | |
223 | |
224 rv = ReadTransaction(trans.get(), &out.response_data); | |
225 EXPECT_EQ(OK, rv); | |
226 | |
227 net::CapturingNetLog::EntryList entries; | |
228 log.GetEntries(&entries); | |
229 size_t pos = ExpectLogContainsSomewhere( | |
230 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS, | |
231 NetLog::PHASE_NONE); | |
232 ExpectLogContainsSomewhere( | |
233 entries, pos, | |
234 NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS, | |
235 NetLog::PHASE_NONE); | |
236 | |
237 CapturingNetLog::Entry entry = entries[pos]; | |
238 NetLogHttpRequestParameter* request_params = | |
239 static_cast<NetLogHttpRequestParameter*>(entry.extra_parameters.get()); | |
240 EXPECT_EQ("GET / HTTP/1.1\r\n", request_params->GetLine()); | |
241 EXPECT_EQ("Host: www.google.com\r\n" | |
242 "Connection: keep-alive\r\n\r\n", | |
243 request_params->GetHeaders().ToString()); | |
244 | |
245 return out; | |
246 } | |
247 | |
248 SimpleGetHelperResult SimpleGetHelper(MockRead data_reads[], | |
249 size_t reads_count) { | |
250 StaticSocketDataProvider reads(data_reads, reads_count, NULL, 0); | |
251 StaticSocketDataProvider* data[] = { &reads }; | |
252 return SimpleGetHelperForData(data, 1); | |
253 } | |
254 | |
255 void ConnectStatusHelperWithExpectedStatus(const MockRead& status, | |
256 int expected_status); | |
257 | |
258 void ConnectStatusHelper(const MockRead& status); | |
259 }; | |
260 | |
261 // Fill |str| with a long header list that consumes >= |size| bytes. | |
262 void FillLargeHeadersString(std::string* str, int size) { | |
263 const char* row = | |
264 "SomeHeaderName: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n"; | |
265 const int sizeof_row = strlen(row); | |
266 const int num_rows = static_cast<int>( | |
267 ceil(static_cast<float>(size) / sizeof_row)); | |
268 const int sizeof_data = num_rows * sizeof_row; | |
269 DCHECK(sizeof_data >= size); | |
270 str->reserve(sizeof_data); | |
271 | |
272 for (int i = 0; i < num_rows; ++i) | |
273 str->append(row, sizeof_row); | |
274 } | |
275 | |
276 // Alternative functions that eliminate randomness and dependency on the local | |
277 // host name so that the generated NTLM messages are reproducible. | |
278 void MockGenerateRandom1(uint8* output, size_t n) { | |
279 static const uint8 bytes[] = { | |
280 0x55, 0x29, 0x66, 0x26, 0x6b, 0x9c, 0x73, 0x54 | |
281 }; | |
282 static size_t current_byte = 0; | |
283 for (size_t i = 0; i < n; ++i) { | |
284 output[i] = bytes[current_byte++]; | |
285 current_byte %= arraysize(bytes); | |
286 } | |
287 } | |
288 | |
289 void MockGenerateRandom2(uint8* output, size_t n) { | |
290 static const uint8 bytes[] = { | |
291 0x96, 0x79, 0x85, 0xe7, 0x49, 0x93, 0x70, 0xa1, | |
292 0x4e, 0xe7, 0x87, 0x45, 0x31, 0x5b, 0xd3, 0x1f | |
293 }; | |
294 static size_t current_byte = 0; | |
295 for (size_t i = 0; i < n; ++i) { | |
296 output[i] = bytes[current_byte++]; | |
297 current_byte %= arraysize(bytes); | |
298 } | |
299 } | |
300 | |
301 std::string MockGetHostName() { | |
302 return "WTC-WIN7"; | |
303 } | |
304 | |
305 template<typename ParentPool> | |
306 class CaptureGroupNameSocketPool : public ParentPool { | |
307 public: | |
308 CaptureGroupNameSocketPool(HostResolver* host_resolver, | |
309 CertVerifier* cert_verifier); | |
310 | |
311 const std::string last_group_name_received() const { | |
312 return last_group_name_; | |
313 } | |
314 | |
315 virtual int RequestSocket(const std::string& group_name, | |
316 const void* socket_params, | |
317 RequestPriority priority, | |
318 ClientSocketHandle* handle, | |
319 const CompletionCallback& callback, | |
320 const BoundNetLog& net_log) { | |
321 last_group_name_ = group_name; | |
322 return ERR_IO_PENDING; | |
323 } | |
324 virtual void CancelRequest(const std::string& group_name, | |
325 ClientSocketHandle* handle) {} | |
326 virtual void ReleaseSocket(const std::string& group_name, | |
327 StreamSocket* socket, | |
328 int id) {} | |
329 virtual void CloseIdleSockets() {} | |
330 virtual int IdleSocketCount() const { | |
331 return 0; | |
332 } | |
333 virtual int IdleSocketCountInGroup(const std::string& group_name) const { | |
334 return 0; | |
335 } | |
336 virtual LoadState GetLoadState(const std::string& group_name, | |
337 const ClientSocketHandle* handle) const { | |
338 return LOAD_STATE_IDLE; | |
339 } | |
340 virtual base::TimeDelta ConnectionTimeout() const { | |
341 return base::TimeDelta(); | |
342 } | |
343 | |
344 private: | |
345 std::string last_group_name_; | |
346 }; | |
347 | |
348 typedef CaptureGroupNameSocketPool<TransportClientSocketPool> | |
349 CaptureGroupNameTransportSocketPool; | |
350 typedef CaptureGroupNameSocketPool<HttpProxyClientSocketPool> | |
351 CaptureGroupNameHttpProxySocketPool; | |
352 typedef CaptureGroupNameSocketPool<SOCKSClientSocketPool> | |
353 CaptureGroupNameSOCKSSocketPool; | |
354 typedef CaptureGroupNameSocketPool<SSLClientSocketPool> | |
355 CaptureGroupNameSSLSocketPool; | |
356 | |
357 template<typename ParentPool> | |
358 CaptureGroupNameSocketPool<ParentPool>::CaptureGroupNameSocketPool( | |
359 HostResolver* host_resolver, | |
360 CertVerifier* /* cert_verifier */) | |
361 : ParentPool(0, 0, NULL, host_resolver, NULL, NULL) {} | |
362 | |
363 template<> | |
364 CaptureGroupNameHttpProxySocketPool::CaptureGroupNameSocketPool( | |
365 HostResolver* host_resolver, | |
366 CertVerifier* /* cert_verifier */) | |
367 : HttpProxyClientSocketPool(0, 0, NULL, host_resolver, NULL, NULL, NULL) {} | |
368 | |
369 template<> | |
370 CaptureGroupNameSSLSocketPool::CaptureGroupNameSocketPool( | |
371 HostResolver* host_resolver, | |
372 CertVerifier* cert_verifier) | |
373 : SSLClientSocketPool(0, 0, NULL, host_resolver, cert_verifier, NULL, | |
374 NULL, NULL, "", NULL, NULL, NULL, NULL, NULL, NULL) {} | |
375 | |
376 //----------------------------------------------------------------------------- | |
377 | |
378 // This is the expected return from a current server advertising SPDY. | |
379 static const char kAlternateProtocolHttpHeader[] = | |
380 "Alternate-Protocol: 443:npn-spdy/2.1\r\n\r\n"; | |
381 | |
382 // Helper functions for validating that AuthChallengeInfo's are correctly | |
383 // configured for common cases. | |
384 bool CheckBasicServerAuth(const AuthChallengeInfo* auth_challenge) { | |
385 if (!auth_challenge) | |
386 return false; | |
387 EXPECT_FALSE(auth_challenge->is_proxy); | |
388 EXPECT_EQ("www.google.com:80", auth_challenge->challenger.ToString()); | |
389 EXPECT_EQ("MyRealm1", auth_challenge->realm); | |
390 EXPECT_EQ("basic", auth_challenge->scheme); | |
391 return true; | |
392 } | |
393 | |
394 bool CheckBasicProxyAuth(const AuthChallengeInfo* auth_challenge) { | |
395 if (!auth_challenge) | |
396 return false; | |
397 EXPECT_TRUE(auth_challenge->is_proxy); | |
398 EXPECT_EQ("myproxy:70", auth_challenge->challenger.ToString()); | |
399 EXPECT_EQ("MyRealm1", auth_challenge->realm); | |
400 EXPECT_EQ("basic", auth_challenge->scheme); | |
401 return true; | |
402 } | |
403 | |
404 bool CheckDigestServerAuth(const AuthChallengeInfo* auth_challenge) { | |
405 if (!auth_challenge) | |
406 return false; | |
407 EXPECT_FALSE(auth_challenge->is_proxy); | |
408 EXPECT_EQ("www.google.com:80", auth_challenge->challenger.ToString()); | |
409 EXPECT_EQ("digestive", auth_challenge->realm); | |
410 EXPECT_EQ("digest", auth_challenge->scheme); | |
411 return true; | |
412 } | |
413 | |
414 bool CheckNTLMServerAuth(const AuthChallengeInfo* auth_challenge) { | |
415 if (!auth_challenge) | |
416 return false; | |
417 EXPECT_FALSE(auth_challenge->is_proxy); | |
418 EXPECT_EQ("172.22.68.17:80", auth_challenge->challenger.ToString()); | |
419 EXPECT_EQ(std::string(), auth_challenge->realm); | |
420 EXPECT_EQ("ntlm", auth_challenge->scheme); | |
421 return true; | |
422 } | |
423 | |
424 TEST_F(HttpNetworkTransactionTest, Basic) { | |
425 SessionDependencies session_deps; | |
426 scoped_ptr<HttpTransaction> trans( | |
427 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
428 } | |
429 | |
430 TEST_F(HttpNetworkTransactionTest, SimpleGET) { | |
431 MockRead data_reads[] = { | |
432 MockRead("HTTP/1.0 200 OK\r\n\r\n"), | |
433 MockRead("hello world"), | |
434 MockRead(SYNCHRONOUS, OK), | |
435 }; | |
436 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
437 arraysize(data_reads)); | |
438 EXPECT_EQ(OK, out.rv); | |
439 EXPECT_EQ("HTTP/1.0 200 OK", out.status_line); | |
440 EXPECT_EQ("hello world", out.response_data); | |
441 } | |
442 | |
443 // Response with no status line. | |
444 TEST_F(HttpNetworkTransactionTest, SimpleGETNoHeaders) { | |
445 MockRead data_reads[] = { | |
446 MockRead("hello world"), | |
447 MockRead(SYNCHRONOUS, OK), | |
448 }; | |
449 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
450 arraysize(data_reads)); | |
451 EXPECT_EQ(OK, out.rv); | |
452 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line); | |
453 EXPECT_EQ("hello world", out.response_data); | |
454 } | |
455 | |
456 // Allow up to 4 bytes of junk to precede status line. | |
457 TEST_F(HttpNetworkTransactionTest, StatusLineJunk2Bytes) { | |
458 MockRead data_reads[] = { | |
459 MockRead("xxxHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"), | |
460 MockRead(SYNCHRONOUS, OK), | |
461 }; | |
462 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
463 arraysize(data_reads)); | |
464 EXPECT_EQ(OK, out.rv); | |
465 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line); | |
466 EXPECT_EQ("DATA", out.response_data); | |
467 } | |
468 | |
469 // Allow up to 4 bytes of junk to precede status line. | |
470 TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes) { | |
471 MockRead data_reads[] = { | |
472 MockRead("\n\nQJHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"), | |
473 MockRead(SYNCHRONOUS, OK), | |
474 }; | |
475 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
476 arraysize(data_reads)); | |
477 EXPECT_EQ(OK, out.rv); | |
478 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line); | |
479 EXPECT_EQ("DATA", out.response_data); | |
480 } | |
481 | |
482 // Beyond 4 bytes of slop and it should fail to find a status line. | |
483 TEST_F(HttpNetworkTransactionTest, StatusLineJunk5Bytes) { | |
484 MockRead data_reads[] = { | |
485 MockRead("xxxxxHTTP/1.1 404 Not Found\nServer: blah"), | |
486 MockRead(SYNCHRONOUS, OK), | |
487 }; | |
488 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
489 arraysize(data_reads)); | |
490 EXPECT_EQ(OK, out.rv); | |
491 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line); | |
492 EXPECT_EQ("xxxxxHTTP/1.1 404 Not Found\nServer: blah", out.response_data); | |
493 } | |
494 | |
495 // Same as StatusLineJunk4Bytes, except the read chunks are smaller. | |
496 TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes_Slow) { | |
497 MockRead data_reads[] = { | |
498 MockRead("\n"), | |
499 MockRead("\n"), | |
500 MockRead("Q"), | |
501 MockRead("J"), | |
502 MockRead("HTTP/1.0 404 Not Found\nServer: blah\n\nDATA"), | |
503 MockRead(SYNCHRONOUS, OK), | |
504 }; | |
505 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
506 arraysize(data_reads)); | |
507 EXPECT_EQ(OK, out.rv); | |
508 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line); | |
509 EXPECT_EQ("DATA", out.response_data); | |
510 } | |
511 | |
512 // Close the connection before enough bytes to have a status line. | |
513 TEST_F(HttpNetworkTransactionTest, StatusLinePartial) { | |
514 MockRead data_reads[] = { | |
515 MockRead("HTT"), | |
516 MockRead(SYNCHRONOUS, OK), | |
517 }; | |
518 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
519 arraysize(data_reads)); | |
520 EXPECT_EQ(OK, out.rv); | |
521 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line); | |
522 EXPECT_EQ("HTT", out.response_data); | |
523 } | |
524 | |
525 // Simulate a 204 response, lacking a Content-Length header, sent over a | |
526 // persistent connection. The response should still terminate since a 204 | |
527 // cannot have a response body. | |
528 TEST_F(HttpNetworkTransactionTest, StopsReading204) { | |
529 MockRead data_reads[] = { | |
530 MockRead("HTTP/1.1 204 No Content\r\n\r\n"), | |
531 MockRead("junk"), // Should not be read!! | |
532 MockRead(SYNCHRONOUS, OK), | |
533 }; | |
534 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
535 arraysize(data_reads)); | |
536 EXPECT_EQ(OK, out.rv); | |
537 EXPECT_EQ("HTTP/1.1 204 No Content", out.status_line); | |
538 EXPECT_EQ("", out.response_data); | |
539 } | |
540 | |
541 // A simple request using chunked encoding with some extra data after. | |
542 // (Like might be seen in a pipelined response.) | |
543 TEST_F(HttpNetworkTransactionTest, ChunkedEncoding) { | |
544 MockRead data_reads[] = { | |
545 MockRead("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"), | |
546 MockRead("5\r\nHello\r\n"), | |
547 MockRead("1\r\n"), | |
548 MockRead(" \r\n"), | |
549 MockRead("5\r\nworld\r\n"), | |
550 MockRead("0\r\n\r\nHTTP/1.1 200 OK\r\n"), | |
551 MockRead(SYNCHRONOUS, OK), | |
552 }; | |
553 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
554 arraysize(data_reads)); | |
555 EXPECT_EQ(OK, out.rv); | |
556 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
557 EXPECT_EQ("Hello world", out.response_data); | |
558 } | |
559 | |
560 // Next tests deal with http://crbug.com/56344. | |
561 | |
562 TEST_F(HttpNetworkTransactionTest, | |
563 MultipleContentLengthHeadersNoTransferEncoding) { | |
564 MockRead data_reads[] = { | |
565 MockRead("HTTP/1.1 200 OK\r\n"), | |
566 MockRead("Content-Length: 10\r\n"), | |
567 MockRead("Content-Length: 5\r\n\r\n"), | |
568 }; | |
569 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
570 arraysize(data_reads)); | |
571 EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH, out.rv); | |
572 } | |
573 | |
574 TEST_F(HttpNetworkTransactionTest, | |
575 DuplicateContentLengthHeadersNoTransferEncoding) { | |
576 MockRead data_reads[] = { | |
577 MockRead("HTTP/1.1 200 OK\r\n"), | |
578 MockRead("Content-Length: 5\r\n"), | |
579 MockRead("Content-Length: 5\r\n\r\n"), | |
580 MockRead("Hello"), | |
581 }; | |
582 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
583 arraysize(data_reads)); | |
584 EXPECT_EQ(OK, out.rv); | |
585 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
586 EXPECT_EQ("Hello", out.response_data); | |
587 } | |
588 | |
589 TEST_F(HttpNetworkTransactionTest, | |
590 ComplexContentLengthHeadersNoTransferEncoding) { | |
591 // More than 2 dupes. | |
592 { | |
593 MockRead data_reads[] = { | |
594 MockRead("HTTP/1.1 200 OK\r\n"), | |
595 MockRead("Content-Length: 5\r\n"), | |
596 MockRead("Content-Length: 5\r\n"), | |
597 MockRead("Content-Length: 5\r\n\r\n"), | |
598 MockRead("Hello"), | |
599 }; | |
600 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
601 arraysize(data_reads)); | |
602 EXPECT_EQ(OK, out.rv); | |
603 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
604 EXPECT_EQ("Hello", out.response_data); | |
605 } | |
606 // HTTP/1.0 | |
607 { | |
608 MockRead data_reads[] = { | |
609 MockRead("HTTP/1.0 200 OK\r\n"), | |
610 MockRead("Content-Length: 5\r\n"), | |
611 MockRead("Content-Length: 5\r\n"), | |
612 MockRead("Content-Length: 5\r\n\r\n"), | |
613 MockRead("Hello"), | |
614 }; | |
615 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
616 arraysize(data_reads)); | |
617 EXPECT_EQ(OK, out.rv); | |
618 EXPECT_EQ("HTTP/1.0 200 OK", out.status_line); | |
619 EXPECT_EQ("Hello", out.response_data); | |
620 } | |
621 // 2 dupes and one mismatched. | |
622 { | |
623 MockRead data_reads[] = { | |
624 MockRead("HTTP/1.1 200 OK\r\n"), | |
625 MockRead("Content-Length: 10\r\n"), | |
626 MockRead("Content-Length: 10\r\n"), | |
627 MockRead("Content-Length: 5\r\n\r\n"), | |
628 }; | |
629 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
630 arraysize(data_reads)); | |
631 EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH, out.rv); | |
632 } | |
633 } | |
634 | |
635 TEST_F(HttpNetworkTransactionTest, | |
636 MultipleContentLengthHeadersTransferEncoding) { | |
637 MockRead data_reads[] = { | |
638 MockRead("HTTP/1.1 200 OK\r\n"), | |
639 MockRead("Content-Length: 666\r\n"), | |
640 MockRead("Content-Length: 1337\r\n"), | |
641 MockRead("Transfer-Encoding: chunked\r\n\r\n"), | |
642 MockRead("5\r\nHello\r\n"), | |
643 MockRead("1\r\n"), | |
644 MockRead(" \r\n"), | |
645 MockRead("5\r\nworld\r\n"), | |
646 MockRead("0\r\n\r\nHTTP/1.1 200 OK\r\n"), | |
647 MockRead(SYNCHRONOUS, OK), | |
648 }; | |
649 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
650 arraysize(data_reads)); | |
651 EXPECT_EQ(OK, out.rv); | |
652 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
653 EXPECT_EQ("Hello world", out.response_data); | |
654 } | |
655 | |
656 // Next tests deal with http://crbug.com/98895. | |
657 | |
658 // Checks that a single Content-Disposition header results in no error. | |
659 TEST_F(HttpNetworkTransactionTest, SingleContentDispositionHeader) { | |
660 MockRead data_reads[] = { | |
661 MockRead("HTTP/1.1 200 OK\r\n"), | |
662 MockRead("Content-Disposition: attachment;filename=\"salutations.txt\"r\n"), | |
663 MockRead("Content-Length: 5\r\n\r\n"), | |
664 MockRead("Hello"), | |
665 }; | |
666 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
667 arraysize(data_reads)); | |
668 EXPECT_EQ(OK, out.rv); | |
669 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
670 EXPECT_EQ("Hello", out.response_data); | |
671 } | |
672 | |
673 // Checks that two identical Content-Disposition headers result in an error. | |
674 TEST_F(HttpNetworkTransactionTest, | |
675 DuplicateIdenticalContentDispositionHeaders) { | |
676 MockRead data_reads[] = { | |
677 MockRead("HTTP/1.1 200 OK\r\n"), | |
678 MockRead("Content-Disposition: attachment;filename=\"greetings.txt\"r\n"), | |
679 MockRead("Content-Disposition: attachment;filename=\"greetings.txt\"r\n"), | |
680 MockRead("Content-Length: 5\r\n\r\n"), | |
681 MockRead("Hello"), | |
682 }; | |
683 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
684 arraysize(data_reads)); | |
685 EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION, out.rv); | |
686 } | |
687 | |
688 // Checks that two distinct Content-Disposition headers result in an error. | |
689 TEST_F(HttpNetworkTransactionTest, DuplicateDistinctContentDispositionHeaders) { | |
690 MockRead data_reads[] = { | |
691 MockRead("HTTP/1.1 200 OK\r\n"), | |
692 MockRead("Content-Disposition: attachment;filename=\"greetings.txt\"r\n"), | |
693 MockRead("Content-Disposition: attachment;filename=\"hi.txt\"r\n"), | |
694 MockRead("Content-Length: 5\r\n\r\n"), | |
695 MockRead("Hello"), | |
696 }; | |
697 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
698 arraysize(data_reads)); | |
699 EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION, out.rv); | |
700 } | |
701 | |
702 // Checks the behavior of a single Location header. | |
703 TEST_F(HttpNetworkTransactionTest, SingleLocationHeader) { | |
704 MockRead data_reads[] = { | |
705 MockRead("HTTP/1.1 302 Redirect\r\n"), | |
706 MockRead("Location: http://good.com/\r\n"), | |
707 MockRead("Content-Length: 0\r\n\r\n"), | |
708 MockRead(SYNCHRONOUS, OK), | |
709 }; | |
710 | |
711 HttpRequestInfo request; | |
712 request.method = "GET"; | |
713 request.url = GURL("http://redirect.com/"); | |
714 request.load_flags = 0; | |
715 | |
716 SessionDependencies session_deps; | |
717 scoped_ptr<HttpTransaction> trans( | |
718 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
719 | |
720 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
721 session_deps.socket_factory.AddSocketDataProvider(&data); | |
722 | |
723 TestCompletionCallback callback; | |
724 | |
725 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
726 EXPECT_EQ(ERR_IO_PENDING, rv); | |
727 | |
728 EXPECT_EQ(OK, callback.WaitForResult()); | |
729 | |
730 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
731 ASSERT_TRUE(response != NULL && response->headers != NULL); | |
732 EXPECT_EQ("HTTP/1.1 302 Redirect", response->headers->GetStatusLine()); | |
733 std::string url; | |
734 EXPECT_TRUE(response->headers->IsRedirect(&url)); | |
735 EXPECT_EQ("http://good.com/", url); | |
736 } | |
737 | |
738 // Checks that two identical Location headers result in an error. | |
739 TEST_F(HttpNetworkTransactionTest, DuplicateIdenticalLocationHeaders) { | |
740 MockRead data_reads[] = { | |
741 MockRead("HTTP/1.1 302 Redirect\r\n"), | |
742 MockRead("Location: http://good.com/\r\n"), | |
743 MockRead("Location: http://good.com/\r\n"), | |
744 MockRead("Content-Length: 0\r\n\r\n"), | |
745 MockRead(SYNCHRONOUS, OK), | |
746 }; | |
747 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
748 arraysize(data_reads)); | |
749 EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION, out.rv); | |
750 } | |
751 | |
752 // Checks that two distinct Location headers result in an error. | |
753 TEST_F(HttpNetworkTransactionTest, DuplicateDistinctLocationHeaders) { | |
754 MockRead data_reads[] = { | |
755 MockRead("HTTP/1.1 302 Redirect\r\n"), | |
756 MockRead("Location: http://good.com/\r\n"), | |
757 MockRead("Location: http://evil.com/\r\n"), | |
758 MockRead("Content-Length: 0\r\n\r\n"), | |
759 MockRead(SYNCHRONOUS, OK), | |
760 }; | |
761 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
762 arraysize(data_reads)); | |
763 EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION, out.rv); | |
764 } | |
765 | |
766 // Do a request using the HEAD method. Verify that we don't try to read the | |
767 // message body (since HEAD has none). | |
768 TEST_F(HttpNetworkTransactionTest, Head) { | |
769 HttpRequestInfo request; | |
770 request.method = "HEAD"; | |
771 request.url = GURL("http://www.google.com/"); | |
772 request.load_flags = 0; | |
773 | |
774 SessionDependencies session_deps; | |
775 scoped_ptr<HttpTransaction> trans( | |
776 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
777 | |
778 MockWrite data_writes1[] = { | |
779 MockWrite("HEAD / HTTP/1.1\r\n" | |
780 "Host: www.google.com\r\n" | |
781 "Connection: keep-alive\r\n" | |
782 "Content-Length: 0\r\n\r\n"), | |
783 }; | |
784 MockRead data_reads1[] = { | |
785 MockRead("HTTP/1.1 404 Not Found\r\n"), | |
786 MockRead("Server: Blah\r\n"), | |
787 MockRead("Content-Length: 1234\r\n\r\n"), | |
788 | |
789 // No response body because the test stops reading here. | |
790 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. | |
791 }; | |
792 | |
793 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
794 data_writes1, arraysize(data_writes1)); | |
795 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
796 | |
797 TestCompletionCallback callback1; | |
798 | |
799 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
800 EXPECT_EQ(ERR_IO_PENDING, rv); | |
801 | |
802 rv = callback1.WaitForResult(); | |
803 EXPECT_EQ(OK, rv); | |
804 | |
805 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
806 ASSERT_TRUE(response != NULL); | |
807 | |
808 // Check that the headers got parsed. | |
809 EXPECT_TRUE(response->headers != NULL); | |
810 EXPECT_EQ(1234, response->headers->GetContentLength()); | |
811 EXPECT_EQ("HTTP/1.1 404 Not Found", response->headers->GetStatusLine()); | |
812 | |
813 std::string server_header; | |
814 void* iter = NULL; | |
815 bool has_server_header = response->headers->EnumerateHeader( | |
816 &iter, "Server", &server_header); | |
817 EXPECT_TRUE(has_server_header); | |
818 EXPECT_EQ("Blah", server_header); | |
819 | |
820 // Reading should give EOF right away, since there is no message body | |
821 // (despite non-zero content-length). | |
822 std::string response_data; | |
823 rv = ReadTransaction(trans.get(), &response_data); | |
824 EXPECT_EQ(OK, rv); | |
825 EXPECT_EQ("", response_data); | |
826 } | |
827 | |
828 TEST_F(HttpNetworkTransactionTest, ReuseConnection) { | |
829 SessionDependencies session_deps; | |
830 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
831 | |
832 MockRead data_reads[] = { | |
833 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), | |
834 MockRead("hello"), | |
835 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), | |
836 MockRead("world"), | |
837 MockRead(SYNCHRONOUS, OK), | |
838 }; | |
839 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
840 session_deps.socket_factory.AddSocketDataProvider(&data); | |
841 | |
842 const char* const kExpectedResponseData[] = { | |
843 "hello", "world" | |
844 }; | |
845 | |
846 for (int i = 0; i < 2; ++i) { | |
847 HttpRequestInfo request; | |
848 request.method = "GET"; | |
849 request.url = GURL("http://www.google.com/"); | |
850 request.load_flags = 0; | |
851 | |
852 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
853 | |
854 TestCompletionCallback callback; | |
855 | |
856 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
857 EXPECT_EQ(ERR_IO_PENDING, rv); | |
858 | |
859 rv = callback.WaitForResult(); | |
860 EXPECT_EQ(OK, rv); | |
861 | |
862 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
863 ASSERT_TRUE(response != NULL); | |
864 | |
865 EXPECT_TRUE(response->headers != NULL); | |
866 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
867 | |
868 std::string response_data; | |
869 rv = ReadTransaction(trans.get(), &response_data); | |
870 EXPECT_EQ(OK, rv); | |
871 EXPECT_EQ(kExpectedResponseData[i], response_data); | |
872 } | |
873 } | |
874 | |
875 TEST_F(HttpNetworkTransactionTest, Ignores100) { | |
876 HttpRequestInfo request; | |
877 request.method = "POST"; | |
878 request.url = GURL("http://www.foo.com/"); | |
879 request.upload_data = new UploadData; | |
880 request.upload_data->AppendBytes("foo", 3); | |
881 request.load_flags = 0; | |
882 | |
883 SessionDependencies session_deps; | |
884 scoped_ptr<HttpTransaction> trans( | |
885 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
886 | |
887 MockRead data_reads[] = { | |
888 MockRead("HTTP/1.0 100 Continue\r\n\r\n"), | |
889 MockRead("HTTP/1.0 200 OK\r\n\r\n"), | |
890 MockRead("hello world"), | |
891 MockRead(SYNCHRONOUS, OK), | |
892 }; | |
893 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
894 session_deps.socket_factory.AddSocketDataProvider(&data); | |
895 | |
896 TestCompletionCallback callback; | |
897 | |
898 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
899 EXPECT_EQ(ERR_IO_PENDING, rv); | |
900 | |
901 rv = callback.WaitForResult(); | |
902 EXPECT_EQ(OK, rv); | |
903 | |
904 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
905 ASSERT_TRUE(response != NULL); | |
906 | |
907 EXPECT_TRUE(response->headers != NULL); | |
908 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); | |
909 | |
910 std::string response_data; | |
911 rv = ReadTransaction(trans.get(), &response_data); | |
912 EXPECT_EQ(OK, rv); | |
913 EXPECT_EQ("hello world", response_data); | |
914 } | |
915 | |
916 // This test is almost the same as Ignores100 above, but the response contains | |
917 // a 102 instead of a 100. Also, instead of HTTP/1.0 the response is | |
918 // HTTP/1.1 and the two status headers are read in one read. | |
919 TEST_F(HttpNetworkTransactionTest, Ignores1xx) { | |
920 HttpRequestInfo request; | |
921 request.method = "GET"; | |
922 request.url = GURL("http://www.foo.com/"); | |
923 request.load_flags = 0; | |
924 | |
925 SessionDependencies session_deps; | |
926 scoped_ptr<HttpTransaction> trans( | |
927 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
928 | |
929 MockRead data_reads[] = { | |
930 MockRead("HTTP/1.1 102 Unspecified status code\r\n\r\n" | |
931 "HTTP/1.1 200 OK\r\n\r\n"), | |
932 MockRead("hello world"), | |
933 MockRead(SYNCHRONOUS, OK), | |
934 }; | |
935 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
936 session_deps.socket_factory.AddSocketDataProvider(&data); | |
937 | |
938 TestCompletionCallback callback; | |
939 | |
940 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
941 EXPECT_EQ(ERR_IO_PENDING, rv); | |
942 | |
943 rv = callback.WaitForResult(); | |
944 EXPECT_EQ(OK, rv); | |
945 | |
946 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
947 ASSERT_TRUE(response != NULL); | |
948 | |
949 EXPECT_TRUE(response->headers != NULL); | |
950 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
951 | |
952 std::string response_data; | |
953 rv = ReadTransaction(trans.get(), &response_data); | |
954 EXPECT_EQ(OK, rv); | |
955 EXPECT_EQ("hello world", response_data); | |
956 } | |
957 | |
958 TEST_F(HttpNetworkTransactionTest, Incomplete100ThenEOF) { | |
959 HttpRequestInfo request; | |
960 request.method = "POST"; | |
961 request.url = GURL("http://www.foo.com/"); | |
962 request.load_flags = 0; | |
963 | |
964 SessionDependencies session_deps; | |
965 scoped_ptr<HttpTransaction> trans( | |
966 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
967 | |
968 MockRead data_reads[] = { | |
969 MockRead(SYNCHRONOUS, "HTTP/1.0 100 Continue\r\n"), | |
970 MockRead(ASYNC, 0), | |
971 }; | |
972 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
973 session_deps.socket_factory.AddSocketDataProvider(&data); | |
974 | |
975 TestCompletionCallback callback; | |
976 | |
977 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
978 EXPECT_EQ(ERR_IO_PENDING, rv); | |
979 | |
980 rv = callback.WaitForResult(); | |
981 EXPECT_EQ(OK, rv); | |
982 | |
983 std::string response_data; | |
984 rv = ReadTransaction(trans.get(), &response_data); | |
985 EXPECT_EQ(OK, rv); | |
986 EXPECT_EQ("", response_data); | |
987 } | |
988 | |
989 TEST_F(HttpNetworkTransactionTest, EmptyResponse) { | |
990 HttpRequestInfo request; | |
991 request.method = "POST"; | |
992 request.url = GURL("http://www.foo.com/"); | |
993 request.load_flags = 0; | |
994 | |
995 SessionDependencies session_deps; | |
996 scoped_ptr<HttpTransaction> trans( | |
997 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
998 | |
999 MockRead data_reads[] = { | |
1000 MockRead(ASYNC, 0), | |
1001 }; | |
1002 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
1003 session_deps.socket_factory.AddSocketDataProvider(&data); | |
1004 | |
1005 TestCompletionCallback callback; | |
1006 | |
1007 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
1008 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1009 | |
1010 rv = callback.WaitForResult(); | |
1011 EXPECT_EQ(ERR_EMPTY_RESPONSE, rv); | |
1012 } | |
1013 | |
1014 void HttpNetworkTransactionTest::KeepAliveConnectionResendRequestTest( | |
1015 const MockWrite* write_failure, | |
1016 const MockRead* read_failure) { | |
1017 HttpRequestInfo request; | |
1018 request.method = "GET"; | |
1019 request.url = GURL("http://www.foo.com/"); | |
1020 request.load_flags = 0; | |
1021 | |
1022 SessionDependencies session_deps; | |
1023 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
1024 | |
1025 // Written data for successfully sending both requests. | |
1026 MockWrite data1_writes[] = { | |
1027 MockWrite("GET / HTTP/1.1\r\n" | |
1028 "Host: www.foo.com\r\n" | |
1029 "Connection: keep-alive\r\n\r\n"), | |
1030 MockWrite("GET / HTTP/1.1\r\n" | |
1031 "Host: www.foo.com\r\n" | |
1032 "Connection: keep-alive\r\n\r\n") | |
1033 }; | |
1034 | |
1035 // Read results for the first request. | |
1036 MockRead data1_reads[] = { | |
1037 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), | |
1038 MockRead("hello"), | |
1039 MockRead(ASYNC, OK), | |
1040 }; | |
1041 | |
1042 if (write_failure) { | |
1043 ASSERT_TRUE(!read_failure); | |
1044 data1_writes[1] = *write_failure; | |
1045 } else { | |
1046 ASSERT_TRUE(read_failure); | |
1047 data1_reads[2] = *read_failure; | |
1048 } | |
1049 | |
1050 StaticSocketDataProvider data1(data1_reads, arraysize(data1_reads), | |
1051 data1_writes, arraysize(data1_writes)); | |
1052 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
1053 | |
1054 MockRead data2_reads[] = { | |
1055 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), | |
1056 MockRead("world"), | |
1057 MockRead(ASYNC, OK), | |
1058 }; | |
1059 StaticSocketDataProvider data2(data2_reads, arraysize(data2_reads), NULL, 0); | |
1060 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
1061 | |
1062 const char* kExpectedResponseData[] = { | |
1063 "hello", "world" | |
1064 }; | |
1065 | |
1066 for (int i = 0; i < 2; ++i) { | |
1067 TestCompletionCallback callback; | |
1068 | |
1069 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
1070 | |
1071 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
1072 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1073 | |
1074 rv = callback.WaitForResult(); | |
1075 EXPECT_EQ(OK, rv); | |
1076 | |
1077 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
1078 ASSERT_TRUE(response != NULL); | |
1079 | |
1080 EXPECT_TRUE(response->headers != NULL); | |
1081 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
1082 | |
1083 std::string response_data; | |
1084 rv = ReadTransaction(trans.get(), &response_data); | |
1085 EXPECT_EQ(OK, rv); | |
1086 EXPECT_EQ(kExpectedResponseData[i], response_data); | |
1087 } | |
1088 } | |
1089 | |
1090 TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionNotConnectedOnWrite) { | |
1091 MockWrite write_failure(ASYNC, ERR_SOCKET_NOT_CONNECTED); | |
1092 KeepAliveConnectionResendRequestTest(&write_failure, NULL); | |
1093 } | |
1094 | |
1095 TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionReset) { | |
1096 MockRead read_failure(ASYNC, ERR_CONNECTION_RESET); | |
1097 KeepAliveConnectionResendRequestTest(NULL, &read_failure); | |
1098 } | |
1099 | |
1100 TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionEOF) { | |
1101 MockRead read_failure(SYNCHRONOUS, OK); // EOF | |
1102 KeepAliveConnectionResendRequestTest(NULL, &read_failure); | |
1103 } | |
1104 | |
1105 TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionReset) { | |
1106 HttpRequestInfo request; | |
1107 request.method = "GET"; | |
1108 request.url = GURL("http://www.google.com/"); | |
1109 request.load_flags = 0; | |
1110 | |
1111 SessionDependencies session_deps; | |
1112 scoped_ptr<HttpTransaction> trans( | |
1113 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
1114 | |
1115 MockRead data_reads[] = { | |
1116 MockRead(ASYNC, ERR_CONNECTION_RESET), | |
1117 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used | |
1118 MockRead("hello world"), | |
1119 MockRead(SYNCHRONOUS, OK), | |
1120 }; | |
1121 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
1122 session_deps.socket_factory.AddSocketDataProvider(&data); | |
1123 | |
1124 TestCompletionCallback callback; | |
1125 | |
1126 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
1127 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1128 | |
1129 rv = callback.WaitForResult(); | |
1130 EXPECT_EQ(ERR_CONNECTION_RESET, rv); | |
1131 | |
1132 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
1133 EXPECT_TRUE(response == NULL); | |
1134 } | |
1135 | |
1136 // What do various browsers do when the server closes a non-keepalive | |
1137 // connection without sending any response header or body? | |
1138 // | |
1139 // IE7: error page | |
1140 // Safari 3.1.2 (Windows): error page | |
1141 // Firefox 3.0.1: blank page | |
1142 // Opera 9.52: after five attempts, blank page | |
1143 // Us with WinHTTP: error page (ERR_INVALID_RESPONSE) | |
1144 // Us: error page (EMPTY_RESPONSE) | |
1145 TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionEOF) { | |
1146 MockRead data_reads[] = { | |
1147 MockRead(SYNCHRONOUS, OK), // EOF | |
1148 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used | |
1149 MockRead("hello world"), | |
1150 MockRead(SYNCHRONOUS, OK), | |
1151 }; | |
1152 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
1153 arraysize(data_reads)); | |
1154 EXPECT_EQ(ERR_EMPTY_RESPONSE, out.rv); | |
1155 } | |
1156 | |
1157 // Test that we correctly reuse a keep-alive connection after not explicitly | |
1158 // reading the body. | |
1159 TEST_F(HttpNetworkTransactionTest, KeepAliveAfterUnreadBody) { | |
1160 HttpRequestInfo request; | |
1161 request.method = "GET"; | |
1162 request.url = GURL("http://www.foo.com/"); | |
1163 request.load_flags = 0; | |
1164 | |
1165 SessionDependencies session_deps; | |
1166 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
1167 | |
1168 // Note that because all these reads happen in the same | |
1169 // StaticSocketDataProvider, it shows that the same socket is being reused for | |
1170 // all transactions. | |
1171 MockRead data1_reads[] = { | |
1172 MockRead("HTTP/1.1 204 No Content\r\n\r\n"), | |
1173 MockRead("HTTP/1.1 205 Reset Content\r\n\r\n"), | |
1174 MockRead("HTTP/1.1 304 Not Modified\r\n\r\n"), | |
1175 MockRead("HTTP/1.1 302 Found\r\n" | |
1176 "Content-Length: 0\r\n\r\n"), | |
1177 MockRead("HTTP/1.1 302 Found\r\n" | |
1178 "Content-Length: 5\r\n\r\n" | |
1179 "hello"), | |
1180 MockRead("HTTP/1.1 301 Moved Permanently\r\n" | |
1181 "Content-Length: 0\r\n\r\n"), | |
1182 MockRead("HTTP/1.1 301 Moved Permanently\r\n" | |
1183 "Content-Length: 5\r\n\r\n" | |
1184 "hello"), | |
1185 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), | |
1186 MockRead("hello"), | |
1187 }; | |
1188 StaticSocketDataProvider data1(data1_reads, arraysize(data1_reads), NULL, 0); | |
1189 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
1190 | |
1191 MockRead data2_reads[] = { | |
1192 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. | |
1193 }; | |
1194 StaticSocketDataProvider data2(data2_reads, arraysize(data2_reads), NULL, 0); | |
1195 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
1196 | |
1197 const int kNumUnreadBodies = arraysize(data1_reads) - 2; | |
1198 std::string response_lines[kNumUnreadBodies]; | |
1199 | |
1200 for (size_t i = 0; i < arraysize(data1_reads) - 2; ++i) { | |
1201 TestCompletionCallback callback; | |
1202 | |
1203 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
1204 | |
1205 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
1206 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1207 | |
1208 rv = callback.WaitForResult(); | |
1209 EXPECT_EQ(OK, rv); | |
1210 | |
1211 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
1212 ASSERT_TRUE(response != NULL); | |
1213 | |
1214 ASSERT_TRUE(response->headers != NULL); | |
1215 response_lines[i] = response->headers->GetStatusLine(); | |
1216 | |
1217 // We intentionally don't read the response bodies. | |
1218 } | |
1219 | |
1220 const char* const kStatusLines[] = { | |
1221 "HTTP/1.1 204 No Content", | |
1222 "HTTP/1.1 205 Reset Content", | |
1223 "HTTP/1.1 304 Not Modified", | |
1224 "HTTP/1.1 302 Found", | |
1225 "HTTP/1.1 302 Found", | |
1226 "HTTP/1.1 301 Moved Permanently", | |
1227 "HTTP/1.1 301 Moved Permanently", | |
1228 }; | |
1229 | |
1230 COMPILE_ASSERT(kNumUnreadBodies == arraysize(kStatusLines), | |
1231 forgot_to_update_kStatusLines); | |
1232 | |
1233 for (int i = 0; i < kNumUnreadBodies; ++i) | |
1234 EXPECT_EQ(kStatusLines[i], response_lines[i]); | |
1235 | |
1236 TestCompletionCallback callback; | |
1237 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
1238 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
1239 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1240 rv = callback.WaitForResult(); | |
1241 EXPECT_EQ(OK, rv); | |
1242 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
1243 ASSERT_TRUE(response != NULL); | |
1244 ASSERT_TRUE(response->headers != NULL); | |
1245 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
1246 std::string response_data; | |
1247 rv = ReadTransaction(trans.get(), &response_data); | |
1248 EXPECT_EQ(OK, rv); | |
1249 EXPECT_EQ("hello", response_data); | |
1250 } | |
1251 | |
1252 // Test the request-challenge-retry sequence for basic auth. | |
1253 // (basic auth is the easiest to mock, because it has no randomness). | |
1254 TEST_F(HttpNetworkTransactionTest, BasicAuth) { | |
1255 HttpRequestInfo request; | |
1256 request.method = "GET"; | |
1257 request.url = GURL("http://www.google.com/"); | |
1258 request.load_flags = 0; | |
1259 | |
1260 SessionDependencies session_deps; | |
1261 scoped_ptr<HttpTransaction> trans( | |
1262 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
1263 | |
1264 MockWrite data_writes1[] = { | |
1265 MockWrite("GET / HTTP/1.1\r\n" | |
1266 "Host: www.google.com\r\n" | |
1267 "Connection: keep-alive\r\n\r\n"), | |
1268 }; | |
1269 | |
1270 MockRead data_reads1[] = { | |
1271 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
1272 // Give a couple authenticate options (only the middle one is actually | |
1273 // supported). | |
1274 MockRead("WWW-Authenticate: Basic invalid\r\n"), // Malformed. | |
1275 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
1276 MockRead("WWW-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"), | |
1277 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
1278 // Large content-length -- won't matter, as connection will be reset. | |
1279 MockRead("Content-Length: 10000\r\n\r\n"), | |
1280 MockRead(SYNCHRONOUS, ERR_FAILED), | |
1281 }; | |
1282 | |
1283 // After calling trans->RestartWithAuth(), this is the request we should | |
1284 // be issuing -- the final header line contains the credentials. | |
1285 MockWrite data_writes2[] = { | |
1286 MockWrite("GET / HTTP/1.1\r\n" | |
1287 "Host: www.google.com\r\n" | |
1288 "Connection: keep-alive\r\n" | |
1289 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
1290 }; | |
1291 | |
1292 // Lastly, the server responds with the actual content. | |
1293 MockRead data_reads2[] = { | |
1294 MockRead("HTTP/1.0 200 OK\r\n"), | |
1295 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
1296 MockRead("Content-Length: 100\r\n\r\n"), | |
1297 MockRead(SYNCHRONOUS, OK), | |
1298 }; | |
1299 | |
1300 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
1301 data_writes1, arraysize(data_writes1)); | |
1302 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
1303 data_writes2, arraysize(data_writes2)); | |
1304 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
1305 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
1306 | |
1307 TestCompletionCallback callback1; | |
1308 | |
1309 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
1310 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1311 | |
1312 rv = callback1.WaitForResult(); | |
1313 EXPECT_EQ(OK, rv); | |
1314 | |
1315 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
1316 ASSERT_TRUE(response != NULL); | |
1317 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
1318 | |
1319 TestCompletionCallback callback2; | |
1320 | |
1321 rv = trans->RestartWithAuth( | |
1322 AuthCredentials(kFoo, kBar), callback2.callback()); | |
1323 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1324 | |
1325 rv = callback2.WaitForResult(); | |
1326 EXPECT_EQ(OK, rv); | |
1327 | |
1328 response = trans->GetResponseInfo(); | |
1329 ASSERT_TRUE(response != NULL); | |
1330 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
1331 EXPECT_EQ(100, response->headers->GetContentLength()); | |
1332 } | |
1333 | |
1334 TEST_F(HttpNetworkTransactionTest, DoNotSendAuth) { | |
1335 HttpRequestInfo request; | |
1336 request.method = "GET"; | |
1337 request.url = GURL("http://www.google.com/"); | |
1338 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; | |
1339 | |
1340 SessionDependencies session_deps; | |
1341 scoped_ptr<HttpTransaction> trans( | |
1342 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
1343 | |
1344 MockWrite data_writes[] = { | |
1345 MockWrite("GET / HTTP/1.1\r\n" | |
1346 "Host: www.google.com\r\n" | |
1347 "Connection: keep-alive\r\n\r\n"), | |
1348 }; | |
1349 | |
1350 MockRead data_reads[] = { | |
1351 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
1352 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
1353 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
1354 // Large content-length -- won't matter, as connection will be reset. | |
1355 MockRead("Content-Length: 10000\r\n\r\n"), | |
1356 MockRead(SYNCHRONOUS, ERR_FAILED), | |
1357 }; | |
1358 | |
1359 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
1360 data_writes, arraysize(data_writes)); | |
1361 session_deps.socket_factory.AddSocketDataProvider(&data); | |
1362 TestCompletionCallback callback; | |
1363 | |
1364 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
1365 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1366 | |
1367 rv = callback.WaitForResult(); | |
1368 EXPECT_EQ(0, rv); | |
1369 | |
1370 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
1371 ASSERT_TRUE(response != NULL); | |
1372 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
1373 } | |
1374 | |
1375 // Test the request-challenge-retry sequence for basic auth, over a keep-alive | |
1376 // connection. | |
1377 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAlive) { | |
1378 HttpRequestInfo request; | |
1379 request.method = "GET"; | |
1380 request.url = GURL("http://www.google.com/"); | |
1381 request.load_flags = 0; | |
1382 | |
1383 SessionDependencies session_deps; | |
1384 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
1385 | |
1386 MockWrite data_writes1[] = { | |
1387 MockWrite("GET / HTTP/1.1\r\n" | |
1388 "Host: www.google.com\r\n" | |
1389 "Connection: keep-alive\r\n\r\n"), | |
1390 | |
1391 // After calling trans->RestartWithAuth(), this is the request we should | |
1392 // be issuing -- the final header line contains the credentials. | |
1393 MockWrite("GET / HTTP/1.1\r\n" | |
1394 "Host: www.google.com\r\n" | |
1395 "Connection: keep-alive\r\n" | |
1396 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
1397 }; | |
1398 | |
1399 MockRead data_reads1[] = { | |
1400 MockRead("HTTP/1.1 401 Unauthorized\r\n"), | |
1401 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
1402 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
1403 MockRead("Content-Length: 14\r\n\r\n"), | |
1404 MockRead("Unauthorized\r\n"), | |
1405 | |
1406 // Lastly, the server responds with the actual content. | |
1407 MockRead("HTTP/1.1 200 OK\r\n"), | |
1408 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
1409 MockRead("Content-Length: 5\r\n\r\n"), | |
1410 MockRead("Hello"), | |
1411 }; | |
1412 | |
1413 // If there is a regression where we disconnect a Keep-Alive | |
1414 // connection during an auth roundtrip, we'll end up reading this. | |
1415 MockRead data_reads2[] = { | |
1416 MockRead(SYNCHRONOUS, ERR_FAILED), | |
1417 }; | |
1418 | |
1419 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
1420 data_writes1, arraysize(data_writes1)); | |
1421 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
1422 NULL, 0); | |
1423 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
1424 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
1425 | |
1426 TestCompletionCallback callback1; | |
1427 | |
1428 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
1429 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
1430 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1431 | |
1432 rv = callback1.WaitForResult(); | |
1433 EXPECT_EQ(OK, rv); | |
1434 | |
1435 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
1436 ASSERT_TRUE(response != NULL); | |
1437 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
1438 | |
1439 TestCompletionCallback callback2; | |
1440 | |
1441 rv = trans->RestartWithAuth( | |
1442 AuthCredentials(kFoo, kBar), callback2.callback()); | |
1443 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1444 | |
1445 rv = callback2.WaitForResult(); | |
1446 EXPECT_EQ(OK, rv); | |
1447 | |
1448 response = trans->GetResponseInfo(); | |
1449 ASSERT_TRUE(response != NULL); | |
1450 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
1451 EXPECT_EQ(5, response->headers->GetContentLength()); | |
1452 } | |
1453 | |
1454 // Test the request-challenge-retry sequence for basic auth, over a keep-alive | |
1455 // connection and with no response body to drain. | |
1456 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) { | |
1457 HttpRequestInfo request; | |
1458 request.method = "GET"; | |
1459 request.url = GURL("http://www.google.com/"); | |
1460 request.load_flags = 0; | |
1461 | |
1462 SessionDependencies session_deps; | |
1463 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
1464 | |
1465 MockWrite data_writes1[] = { | |
1466 MockWrite("GET / HTTP/1.1\r\n" | |
1467 "Host: www.google.com\r\n" | |
1468 "Connection: keep-alive\r\n\r\n"), | |
1469 | |
1470 // After calling trans->RestartWithAuth(), this is the request we should | |
1471 // be issuing -- the final header line contains the credentials. | |
1472 MockWrite("GET / HTTP/1.1\r\n" | |
1473 "Host: www.google.com\r\n" | |
1474 "Connection: keep-alive\r\n" | |
1475 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
1476 }; | |
1477 | |
1478 MockRead data_reads1[] = { | |
1479 MockRead("HTTP/1.1 401 Unauthorized\r\n"), | |
1480 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
1481 MockRead("Content-Length: 0\r\n\r\n"), // No response body. | |
1482 | |
1483 // Lastly, the server responds with the actual content. | |
1484 MockRead("HTTP/1.1 200 OK\r\n"), | |
1485 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
1486 MockRead("Content-Length: 5\r\n\r\n"), | |
1487 MockRead("hello"), | |
1488 }; | |
1489 | |
1490 // An incorrect reconnect would cause this to be read. | |
1491 MockRead data_reads2[] = { | |
1492 MockRead(SYNCHRONOUS, ERR_FAILED), | |
1493 }; | |
1494 | |
1495 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
1496 data_writes1, arraysize(data_writes1)); | |
1497 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
1498 NULL, 0); | |
1499 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
1500 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
1501 | |
1502 TestCompletionCallback callback1; | |
1503 | |
1504 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
1505 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
1506 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1507 | |
1508 rv = callback1.WaitForResult(); | |
1509 EXPECT_EQ(OK, rv); | |
1510 | |
1511 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
1512 ASSERT_TRUE(response != NULL); | |
1513 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
1514 | |
1515 TestCompletionCallback callback2; | |
1516 | |
1517 rv = trans->RestartWithAuth( | |
1518 AuthCredentials(kFoo, kBar), callback2.callback()); | |
1519 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1520 | |
1521 rv = callback2.WaitForResult(); | |
1522 EXPECT_EQ(OK, rv); | |
1523 | |
1524 response = trans->GetResponseInfo(); | |
1525 ASSERT_TRUE(response != NULL); | |
1526 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
1527 EXPECT_EQ(5, response->headers->GetContentLength()); | |
1528 } | |
1529 | |
1530 // Test the request-challenge-retry sequence for basic auth, over a keep-alive | |
1531 // connection and with a large response body to drain. | |
1532 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) { | |
1533 HttpRequestInfo request; | |
1534 request.method = "GET"; | |
1535 request.url = GURL("http://www.google.com/"); | |
1536 request.load_flags = 0; | |
1537 | |
1538 SessionDependencies session_deps; | |
1539 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
1540 | |
1541 MockWrite data_writes1[] = { | |
1542 MockWrite("GET / HTTP/1.1\r\n" | |
1543 "Host: www.google.com\r\n" | |
1544 "Connection: keep-alive\r\n\r\n"), | |
1545 | |
1546 // After calling trans->RestartWithAuth(), this is the request we should | |
1547 // be issuing -- the final header line contains the credentials. | |
1548 MockWrite("GET / HTTP/1.1\r\n" | |
1549 "Host: www.google.com\r\n" | |
1550 "Connection: keep-alive\r\n" | |
1551 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
1552 }; | |
1553 | |
1554 // Respond with 5 kb of response body. | |
1555 std::string large_body_string("Unauthorized"); | |
1556 large_body_string.append(5 * 1024, ' '); | |
1557 large_body_string.append("\r\n"); | |
1558 | |
1559 MockRead data_reads1[] = { | |
1560 MockRead("HTTP/1.1 401 Unauthorized\r\n"), | |
1561 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
1562 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
1563 // 5134 = 12 + 5 * 1024 + 2 | |
1564 MockRead("Content-Length: 5134\r\n\r\n"), | |
1565 MockRead(ASYNC, large_body_string.data(), large_body_string.size()), | |
1566 | |
1567 // Lastly, the server responds with the actual content. | |
1568 MockRead("HTTP/1.1 200 OK\r\n"), | |
1569 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
1570 MockRead("Content-Length: 5\r\n\r\n"), | |
1571 MockRead("hello"), | |
1572 }; | |
1573 | |
1574 // An incorrect reconnect would cause this to be read. | |
1575 MockRead data_reads2[] = { | |
1576 MockRead(SYNCHRONOUS, ERR_FAILED), | |
1577 }; | |
1578 | |
1579 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
1580 data_writes1, arraysize(data_writes1)); | |
1581 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
1582 NULL, 0); | |
1583 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
1584 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
1585 | |
1586 TestCompletionCallback callback1; | |
1587 | |
1588 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
1589 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
1590 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1591 | |
1592 rv = callback1.WaitForResult(); | |
1593 EXPECT_EQ(OK, rv); | |
1594 | |
1595 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
1596 ASSERT_TRUE(response != NULL); | |
1597 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
1598 | |
1599 TestCompletionCallback callback2; | |
1600 | |
1601 rv = trans->RestartWithAuth( | |
1602 AuthCredentials(kFoo, kBar), callback2.callback()); | |
1603 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1604 | |
1605 rv = callback2.WaitForResult(); | |
1606 EXPECT_EQ(OK, rv); | |
1607 | |
1608 response = trans->GetResponseInfo(); | |
1609 ASSERT_TRUE(response != NULL); | |
1610 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
1611 EXPECT_EQ(5, response->headers->GetContentLength()); | |
1612 } | |
1613 | |
1614 // Test the request-challenge-retry sequence for basic auth, over a keep-alive | |
1615 // connection, but the server gets impatient and closes the connection. | |
1616 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveImpatientServer) { | |
1617 HttpRequestInfo request; | |
1618 request.method = "GET"; | |
1619 request.url = GURL("http://www.google.com/"); | |
1620 request.load_flags = 0; | |
1621 | |
1622 SessionDependencies session_deps; | |
1623 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
1624 | |
1625 MockWrite data_writes1[] = { | |
1626 MockWrite("GET / HTTP/1.1\r\n" | |
1627 "Host: www.google.com\r\n" | |
1628 "Connection: keep-alive\r\n\r\n"), | |
1629 // This simulates the seemingly successful write to a closed connection | |
1630 // if the bug is not fixed. | |
1631 MockWrite("GET / HTTP/1.1\r\n" | |
1632 "Host: www.google.com\r\n" | |
1633 "Connection: keep-alive\r\n" | |
1634 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
1635 }; | |
1636 | |
1637 MockRead data_reads1[] = { | |
1638 MockRead("HTTP/1.1 401 Unauthorized\r\n"), | |
1639 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
1640 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
1641 MockRead("Content-Length: 14\r\n\r\n"), | |
1642 // Tell MockTCPClientSocket to simulate the server closing the connection. | |
1643 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), | |
1644 MockRead("Unauthorized\r\n"), | |
1645 MockRead(SYNCHRONOUS, OK), // The server closes the connection. | |
1646 }; | |
1647 | |
1648 // After calling trans->RestartWithAuth(), this is the request we should | |
1649 // be issuing -- the final header line contains the credentials. | |
1650 MockWrite data_writes2[] = { | |
1651 MockWrite("GET / HTTP/1.1\r\n" | |
1652 "Host: www.google.com\r\n" | |
1653 "Connection: keep-alive\r\n" | |
1654 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
1655 }; | |
1656 | |
1657 // Lastly, the server responds with the actual content. | |
1658 MockRead data_reads2[] = { | |
1659 MockRead("HTTP/1.1 200 OK\r\n"), | |
1660 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
1661 MockRead("Content-Length: 5\r\n\r\n"), | |
1662 MockRead("hello"), | |
1663 }; | |
1664 | |
1665 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
1666 data_writes1, arraysize(data_writes1)); | |
1667 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
1668 data_writes2, arraysize(data_writes2)); | |
1669 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
1670 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
1671 | |
1672 TestCompletionCallback callback1; | |
1673 | |
1674 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
1675 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
1676 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1677 | |
1678 rv = callback1.WaitForResult(); | |
1679 EXPECT_EQ(OK, rv); | |
1680 | |
1681 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
1682 ASSERT_TRUE(response != NULL); | |
1683 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
1684 | |
1685 TestCompletionCallback callback2; | |
1686 | |
1687 rv = trans->RestartWithAuth( | |
1688 AuthCredentials(kFoo, kBar), callback2.callback()); | |
1689 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1690 | |
1691 rv = callback2.WaitForResult(); | |
1692 EXPECT_EQ(OK, rv); | |
1693 | |
1694 response = trans->GetResponseInfo(); | |
1695 ASSERT_TRUE(response != NULL); | |
1696 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
1697 EXPECT_EQ(5, response->headers->GetContentLength()); | |
1698 } | |
1699 | |
1700 // Test the request-challenge-retry sequence for basic auth, over a connection | |
1701 // that requires a restart when setting up an SSL tunnel. | |
1702 TEST_F(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAlive) { | |
1703 HttpRequestInfo request; | |
1704 request.method = "GET"; | |
1705 request.url = GURL("https://www.google.com/"); | |
1706 // when the no authentication data flag is set. | |
1707 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; | |
1708 | |
1709 // Configure against proxy server "myproxy:70". | |
1710 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
1711 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
1712 session_deps.net_log = log.bound().net_log(); | |
1713 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
1714 | |
1715 // Since we have proxy, should try to establish tunnel. | |
1716 MockWrite data_writes1[] = { | |
1717 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
1718 "Host: www.google.com\r\n" | |
1719 "Proxy-Connection: keep-alive\r\n\r\n"), | |
1720 | |
1721 // After calling trans->RestartWithAuth(), this is the request we should | |
1722 // be issuing -- the final header line contains the credentials. | |
1723 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
1724 "Host: www.google.com\r\n" | |
1725 "Proxy-Connection: keep-alive\r\n" | |
1726 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
1727 | |
1728 MockWrite("GET / HTTP/1.1\r\n" | |
1729 "Host: www.google.com\r\n" | |
1730 "Connection: keep-alive\r\n\r\n"), | |
1731 }; | |
1732 | |
1733 // The proxy responds to the connect with a 407, using a persistent | |
1734 // connection. | |
1735 MockRead data_reads1[] = { | |
1736 // No credentials. | |
1737 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
1738 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
1739 MockRead("Proxy-Connection: close\r\n\r\n"), | |
1740 | |
1741 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), | |
1742 | |
1743 MockRead("HTTP/1.1 200 OK\r\n"), | |
1744 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
1745 MockRead("Content-Length: 5\r\n\r\n"), | |
1746 MockRead(SYNCHRONOUS, "hello"), | |
1747 }; | |
1748 | |
1749 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
1750 data_writes1, arraysize(data_writes1)); | |
1751 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
1752 SSLSocketDataProvider ssl(ASYNC, OK); | |
1753 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
1754 | |
1755 TestCompletionCallback callback1; | |
1756 | |
1757 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
1758 | |
1759 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
1760 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1761 | |
1762 rv = callback1.WaitForResult(); | |
1763 EXPECT_EQ(OK, rv); | |
1764 net::CapturingNetLog::EntryList entries; | |
1765 log.GetEntries(&entries); | |
1766 size_t pos = ExpectLogContainsSomewhere( | |
1767 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
1768 NetLog::PHASE_NONE); | |
1769 ExpectLogContainsSomewhere( | |
1770 entries, pos, | |
1771 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
1772 NetLog::PHASE_NONE); | |
1773 | |
1774 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
1775 ASSERT_TRUE(response != NULL); | |
1776 ASSERT_FALSE(response->headers == NULL); | |
1777 EXPECT_EQ(407, response->headers->response_code()); | |
1778 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
1779 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
1780 | |
1781 TestCompletionCallback callback2; | |
1782 | |
1783 rv = trans->RestartWithAuth( | |
1784 AuthCredentials(kFoo, kBar), callback2.callback()); | |
1785 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1786 | |
1787 rv = callback2.WaitForResult(); | |
1788 EXPECT_EQ(OK, rv); | |
1789 | |
1790 response = trans->GetResponseInfo(); | |
1791 ASSERT_TRUE(response != NULL); | |
1792 | |
1793 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
1794 EXPECT_EQ(200, response->headers->response_code()); | |
1795 EXPECT_EQ(5, response->headers->GetContentLength()); | |
1796 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
1797 | |
1798 // The password prompt info should not be set. | |
1799 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
1800 | |
1801 trans.reset(); | |
1802 session->CloseAllConnections(); | |
1803 } | |
1804 | |
1805 // Test the request-challenge-retry sequence for basic auth, over a keep-alive | |
1806 // proxy connection, when setting up an SSL tunnel. | |
1807 TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAlive) { | |
1808 HttpRequestInfo request; | |
1809 request.method = "GET"; | |
1810 request.url = GURL("https://www.google.com/"); | |
1811 // Ensure that proxy authentication is attempted even | |
1812 // when the no authentication data flag is set. | |
1813 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; | |
1814 | |
1815 // Configure against proxy server "myproxy:70". | |
1816 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
1817 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
1818 session_deps.net_log = log.bound().net_log(); | |
1819 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
1820 | |
1821 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
1822 | |
1823 // Since we have proxy, should try to establish tunnel. | |
1824 MockWrite data_writes1[] = { | |
1825 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
1826 "Host: www.google.com\r\n" | |
1827 "Proxy-Connection: keep-alive\r\n\r\n"), | |
1828 | |
1829 // After calling trans->RestartWithAuth(), this is the request we should | |
1830 // be issuing -- the final header line contains the credentials. | |
1831 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
1832 "Host: www.google.com\r\n" | |
1833 "Proxy-Connection: keep-alive\r\n" | |
1834 "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"), | |
1835 }; | |
1836 | |
1837 // The proxy responds to the connect with a 407, using a persistent | |
1838 // connection. | |
1839 MockRead data_reads1[] = { | |
1840 // No credentials. | |
1841 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
1842 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
1843 MockRead("Content-Length: 10\r\n\r\n"), | |
1844 MockRead("0123456789"), | |
1845 | |
1846 // Wrong credentials (wrong password). | |
1847 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
1848 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
1849 MockRead("Content-Length: 10\r\n\r\n"), | |
1850 // No response body because the test stops reading here. | |
1851 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. | |
1852 }; | |
1853 | |
1854 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
1855 data_writes1, arraysize(data_writes1)); | |
1856 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
1857 | |
1858 TestCompletionCallback callback1; | |
1859 | |
1860 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
1861 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1862 | |
1863 rv = callback1.WaitForResult(); | |
1864 EXPECT_EQ(OK, rv); | |
1865 net::CapturingNetLog::EntryList entries; | |
1866 log.GetEntries(&entries); | |
1867 size_t pos = ExpectLogContainsSomewhere( | |
1868 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
1869 NetLog::PHASE_NONE); | |
1870 ExpectLogContainsSomewhere( | |
1871 entries, pos, | |
1872 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
1873 NetLog::PHASE_NONE); | |
1874 | |
1875 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
1876 ASSERT_TRUE(response != NULL); | |
1877 ASSERT_FALSE(response->headers == NULL); | |
1878 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
1879 EXPECT_EQ(407, response->headers->response_code()); | |
1880 EXPECT_EQ(10, response->headers->GetContentLength()); | |
1881 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
1882 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
1883 | |
1884 TestCompletionCallback callback2; | |
1885 | |
1886 // Wrong password (should be "bar"). | |
1887 rv = trans->RestartWithAuth( | |
1888 AuthCredentials(kFoo, kBaz), callback2.callback()); | |
1889 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1890 | |
1891 rv = callback2.WaitForResult(); | |
1892 EXPECT_EQ(OK, rv); | |
1893 | |
1894 response = trans->GetResponseInfo(); | |
1895 ASSERT_TRUE(response != NULL); | |
1896 ASSERT_FALSE(response->headers == NULL); | |
1897 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
1898 EXPECT_EQ(407, response->headers->response_code()); | |
1899 EXPECT_EQ(10, response->headers->GetContentLength()); | |
1900 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
1901 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
1902 | |
1903 // Flush the idle socket before the NetLog and HttpNetworkTransaction go | |
1904 // out of scope. | |
1905 session->CloseAllConnections(); | |
1906 } | |
1907 | |
1908 // Test that we don't read the response body when we fail to establish a tunnel, | |
1909 // even if the user cancels the proxy's auth attempt. | |
1910 TEST_F(HttpNetworkTransactionTest, BasicAuthProxyCancelTunnel) { | |
1911 HttpRequestInfo request; | |
1912 request.method = "GET"; | |
1913 request.url = GURL("https://www.google.com/"); | |
1914 request.load_flags = 0; | |
1915 | |
1916 // Configure against proxy server "myproxy:70". | |
1917 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
1918 | |
1919 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
1920 | |
1921 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
1922 | |
1923 // Since we have proxy, should try to establish tunnel. | |
1924 MockWrite data_writes[] = { | |
1925 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
1926 "Host: www.google.com\r\n" | |
1927 "Proxy-Connection: keep-alive\r\n\r\n"), | |
1928 }; | |
1929 | |
1930 // The proxy responds to the connect with a 407. | |
1931 MockRead data_reads[] = { | |
1932 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
1933 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
1934 MockRead("Content-Length: 10\r\n\r\n"), | |
1935 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. | |
1936 }; | |
1937 | |
1938 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
1939 data_writes, arraysize(data_writes)); | |
1940 session_deps.socket_factory.AddSocketDataProvider(&data); | |
1941 | |
1942 TestCompletionCallback callback; | |
1943 | |
1944 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
1945 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1946 | |
1947 rv = callback.WaitForResult(); | |
1948 EXPECT_EQ(OK, rv); | |
1949 | |
1950 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
1951 ASSERT_TRUE(response != NULL); | |
1952 | |
1953 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
1954 EXPECT_EQ(407, response->headers->response_code()); | |
1955 EXPECT_EQ(10, response->headers->GetContentLength()); | |
1956 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
1957 | |
1958 std::string response_data; | |
1959 rv = ReadTransaction(trans.get(), &response_data); | |
1960 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); | |
1961 | |
1962 // Flush the idle socket before the HttpNetworkTransaction goes out of scope. | |
1963 session->CloseAllConnections(); | |
1964 } | |
1965 | |
1966 // Test when a server (non-proxy) returns a 407 (proxy-authenticate). | |
1967 // The request should fail with ERR_UNEXPECTED_PROXY_AUTH. | |
1968 TEST_F(HttpNetworkTransactionTest, UnexpectedProxyAuth) { | |
1969 HttpRequestInfo request; | |
1970 request.method = "GET"; | |
1971 request.url = GURL("http://www.google.com/"); | |
1972 request.load_flags = 0; | |
1973 | |
1974 // We are using a DIRECT connection (i.e. no proxy) for this session. | |
1975 SessionDependencies session_deps; | |
1976 scoped_ptr<HttpTransaction> trans( | |
1977 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
1978 | |
1979 MockWrite data_writes1[] = { | |
1980 MockWrite("GET / HTTP/1.1\r\n" | |
1981 "Host: www.google.com\r\n" | |
1982 "Connection: keep-alive\r\n\r\n"), | |
1983 }; | |
1984 | |
1985 MockRead data_reads1[] = { | |
1986 MockRead("HTTP/1.0 407 Proxy Auth required\r\n"), | |
1987 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
1988 // Large content-length -- won't matter, as connection will be reset. | |
1989 MockRead("Content-Length: 10000\r\n\r\n"), | |
1990 MockRead(SYNCHRONOUS, ERR_FAILED), | |
1991 }; | |
1992 | |
1993 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
1994 data_writes1, arraysize(data_writes1)); | |
1995 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
1996 | |
1997 TestCompletionCallback callback; | |
1998 | |
1999 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
2000 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2001 | |
2002 rv = callback.WaitForResult(); | |
2003 EXPECT_EQ(ERR_UNEXPECTED_PROXY_AUTH, rv); | |
2004 } | |
2005 | |
2006 // Tests when an HTTPS server (non-proxy) returns a 407 (proxy-authentication) | |
2007 // through a non-authenticating proxy. The request should fail with | |
2008 // ERR_UNEXPECTED_PROXY_AUTH. | |
2009 // Note that it is impossible to detect if an HTTP server returns a 407 through | |
2010 // a non-authenticating proxy - there is nothing to indicate whether the | |
2011 // response came from the proxy or the server, so it is treated as if the proxy | |
2012 // issued the challenge. | |
2013 TEST_F(HttpNetworkTransactionTest, HttpsServerRequestsProxyAuthThroughProxy) { | |
2014 HttpRequestInfo request; | |
2015 request.method = "GET"; | |
2016 request.url = GURL("https://www.google.com/"); | |
2017 | |
2018 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
2019 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
2020 session_deps.net_log = log.bound().net_log(); | |
2021 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
2022 | |
2023 // Since we have proxy, should try to establish tunnel. | |
2024 MockWrite data_writes1[] = { | |
2025 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
2026 "Host: www.google.com\r\n" | |
2027 "Proxy-Connection: keep-alive\r\n\r\n"), | |
2028 | |
2029 MockWrite("GET / HTTP/1.1\r\n" | |
2030 "Host: www.google.com\r\n" | |
2031 "Connection: keep-alive\r\n\r\n"), | |
2032 }; | |
2033 | |
2034 MockRead data_reads1[] = { | |
2035 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), | |
2036 | |
2037 MockRead("HTTP/1.1 407 Unauthorized\r\n"), | |
2038 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
2039 MockRead("\r\n"), | |
2040 MockRead(SYNCHRONOUS, OK), | |
2041 }; | |
2042 | |
2043 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
2044 data_writes1, arraysize(data_writes1)); | |
2045 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
2046 SSLSocketDataProvider ssl(ASYNC, OK); | |
2047 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
2048 | |
2049 TestCompletionCallback callback1; | |
2050 | |
2051 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
2052 | |
2053 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
2054 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2055 | |
2056 rv = callback1.WaitForResult(); | |
2057 EXPECT_EQ(ERR_UNEXPECTED_PROXY_AUTH, rv); | |
2058 net::CapturingNetLog::EntryList entries; | |
2059 log.GetEntries(&entries); | |
2060 size_t pos = ExpectLogContainsSomewhere( | |
2061 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
2062 NetLog::PHASE_NONE); | |
2063 ExpectLogContainsSomewhere( | |
2064 entries, pos, | |
2065 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
2066 NetLog::PHASE_NONE); | |
2067 } | |
2068 | |
2069 // Test a simple get through an HTTPS Proxy. | |
2070 TEST_F(HttpNetworkTransactionTest, HttpsProxyGet) { | |
2071 HttpRequestInfo request; | |
2072 request.method = "GET"; | |
2073 request.url = GURL("http://www.google.com/"); | |
2074 | |
2075 // Configure against https proxy server "proxy:70". | |
2076 SessionDependencies session_deps(ProxyService::CreateFixed( | |
2077 "https://proxy:70")); | |
2078 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
2079 session_deps.net_log = log.bound().net_log(); | |
2080 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
2081 | |
2082 // Since we have proxy, should use full url | |
2083 MockWrite data_writes1[] = { | |
2084 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
2085 "Host: www.google.com\r\n" | |
2086 "Proxy-Connection: keep-alive\r\n\r\n"), | |
2087 }; | |
2088 | |
2089 MockRead data_reads1[] = { | |
2090 MockRead("HTTP/1.1 200 OK\r\n"), | |
2091 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
2092 MockRead("Content-Length: 100\r\n\r\n"), | |
2093 MockRead(SYNCHRONOUS, OK), | |
2094 }; | |
2095 | |
2096 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
2097 data_writes1, arraysize(data_writes1)); | |
2098 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
2099 SSLSocketDataProvider ssl(ASYNC, OK); | |
2100 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
2101 | |
2102 TestCompletionCallback callback1; | |
2103 | |
2104 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
2105 | |
2106 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
2107 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2108 | |
2109 rv = callback1.WaitForResult(); | |
2110 EXPECT_EQ(OK, rv); | |
2111 | |
2112 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
2113 ASSERT_TRUE(response != NULL); | |
2114 | |
2115 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
2116 EXPECT_EQ(200, response->headers->response_code()); | |
2117 EXPECT_EQ(100, response->headers->GetContentLength()); | |
2118 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
2119 | |
2120 // The password prompt info should not be set. | |
2121 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
2122 } | |
2123 | |
2124 // Test a SPDY get through an HTTPS Proxy. | |
2125 TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyGet) { | |
2126 HttpRequestInfo request; | |
2127 request.method = "GET"; | |
2128 request.url = GURL("http://www.google.com/"); | |
2129 request.load_flags = 0; | |
2130 | |
2131 // Configure against https proxy server "proxy:70". | |
2132 SessionDependencies session_deps(ProxyService::CreateFixed( | |
2133 "https://proxy:70")); | |
2134 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
2135 session_deps.net_log = log.bound().net_log(); | |
2136 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
2137 | |
2138 // fetch http://www.google.com/ via SPDY | |
2139 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST, | |
2140 false)); | |
2141 MockWrite spdy_writes[] = { CreateMockWrite(*req) }; | |
2142 | |
2143 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2144 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); | |
2145 MockRead spdy_reads[] = { | |
2146 CreateMockRead(*resp), | |
2147 CreateMockRead(*data), | |
2148 MockRead(ASYNC, 0, 0), | |
2149 }; | |
2150 | |
2151 scoped_ptr<DelayedSocketData> spdy_data( | |
2152 new DelayedSocketData( | |
2153 1, // wait for one write to finish before reading. | |
2154 spdy_reads, arraysize(spdy_reads), | |
2155 spdy_writes, arraysize(spdy_writes))); | |
2156 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
2157 | |
2158 SSLSocketDataProvider ssl(ASYNC, OK); | |
2159 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
2160 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
2161 | |
2162 TestCompletionCallback callback1; | |
2163 | |
2164 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
2165 | |
2166 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
2167 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2168 | |
2169 rv = callback1.WaitForResult(); | |
2170 EXPECT_EQ(OK, rv); | |
2171 | |
2172 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
2173 ASSERT_TRUE(response != NULL); | |
2174 ASSERT_TRUE(response->headers != NULL); | |
2175 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
2176 | |
2177 std::string response_data; | |
2178 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
2179 EXPECT_EQ(net::kUploadData, response_data); | |
2180 } | |
2181 | |
2182 // Test a SPDY get through an HTTPS Proxy. | |
2183 TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyGetWithProxyAuth) { | |
2184 HttpRequestInfo request; | |
2185 request.method = "GET"; | |
2186 request.url = GURL("http://www.google.com/"); | |
2187 request.load_flags = 0; | |
2188 | |
2189 // Configure against https proxy server "myproxy:70". | |
2190 SessionDependencies session_deps( | |
2191 ProxyService::CreateFixed("https://myproxy:70")); | |
2192 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
2193 session_deps.net_log = log.bound().net_log(); | |
2194 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
2195 | |
2196 // The first request will be a bare GET, the second request will be a | |
2197 // GET with a Proxy-Authorization header. | |
2198 scoped_ptr<spdy::SpdyFrame> req_get( | |
2199 ConstructSpdyGet(NULL, 0, false, 1, LOWEST, false)); | |
2200 const char* const kExtraAuthorizationHeaders[] = { | |
2201 "proxy-authorization", | |
2202 "Basic Zm9vOmJhcg==", | |
2203 }; | |
2204 scoped_ptr<spdy::SpdyFrame> req_get_authorization( | |
2205 ConstructSpdyGet( | |
2206 kExtraAuthorizationHeaders, arraysize(kExtraAuthorizationHeaders)/2, | |
2207 false, 3, LOWEST, false)); | |
2208 MockWrite spdy_writes[] = { | |
2209 CreateMockWrite(*req_get, 1), | |
2210 CreateMockWrite(*req_get_authorization, 4), | |
2211 }; | |
2212 | |
2213 // The first response is a 407 proxy authentication challenge, and the second | |
2214 // response will be a 200 response since the second request includes a valid | |
2215 // Authorization header. | |
2216 const char* const kExtraAuthenticationHeaders[] = { | |
2217 "proxy-authenticate", | |
2218 "Basic realm=\"MyRealm1\"" | |
2219 }; | |
2220 scoped_ptr<spdy::SpdyFrame> resp_authentication( | |
2221 ConstructSpdySynReplyError( | |
2222 "407 Proxy Authentication Required", | |
2223 kExtraAuthenticationHeaders, arraysize(kExtraAuthenticationHeaders)/2, | |
2224 1)); | |
2225 scoped_ptr<spdy::SpdyFrame> body_authentication( | |
2226 ConstructSpdyBodyFrame(1, true)); | |
2227 scoped_ptr<spdy::SpdyFrame> resp_data(ConstructSpdyGetSynReply(NULL, 0, 3)); | |
2228 scoped_ptr<spdy::SpdyFrame> body_data(ConstructSpdyBodyFrame(3, true)); | |
2229 MockRead spdy_reads[] = { | |
2230 CreateMockRead(*resp_authentication, 2), | |
2231 CreateMockRead(*body_authentication, 3), | |
2232 CreateMockRead(*resp_data, 5), | |
2233 CreateMockRead(*body_data, 6), | |
2234 MockRead(ASYNC, 0, 7), | |
2235 }; | |
2236 | |
2237 scoped_ptr<OrderedSocketData> data( | |
2238 new OrderedSocketData(spdy_reads, arraysize(spdy_reads), | |
2239 spdy_writes, arraysize(spdy_writes))); | |
2240 session_deps.socket_factory.AddSocketDataProvider(data.get()); | |
2241 | |
2242 SSLSocketDataProvider ssl(ASYNC, OK); | |
2243 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
2244 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
2245 | |
2246 TestCompletionCallback callback1; | |
2247 | |
2248 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
2249 | |
2250 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
2251 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2252 | |
2253 rv = callback1.WaitForResult(); | |
2254 EXPECT_EQ(OK, rv); | |
2255 | |
2256 const HttpResponseInfo* const response = trans->GetResponseInfo(); | |
2257 | |
2258 ASSERT_TRUE(response != NULL); | |
2259 ASSERT_TRUE(response->headers != NULL); | |
2260 EXPECT_EQ(407, response->headers->response_code()); | |
2261 EXPECT_TRUE(response->was_fetched_via_spdy); | |
2262 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
2263 | |
2264 TestCompletionCallback callback2; | |
2265 | |
2266 rv = trans->RestartWithAuth( | |
2267 AuthCredentials(kFoo, kBar), callback2.callback()); | |
2268 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2269 | |
2270 rv = callback2.WaitForResult(); | |
2271 EXPECT_EQ(OK, rv); | |
2272 | |
2273 const HttpResponseInfo* const response_restart = trans->GetResponseInfo(); | |
2274 | |
2275 ASSERT_TRUE(response_restart != NULL); | |
2276 ASSERT_TRUE(response_restart->headers != NULL); | |
2277 EXPECT_EQ(200, response_restart->headers->response_code()); | |
2278 // The password prompt info should not be set. | |
2279 EXPECT_TRUE(response_restart->auth_challenge.get() == NULL); | |
2280 } | |
2281 | |
2282 // Test a SPDY CONNECT through an HTTPS Proxy to an HTTPS (non-SPDY) Server. | |
2283 TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyConnectHttps) { | |
2284 HttpRequestInfo request; | |
2285 request.method = "GET"; | |
2286 request.url = GURL("https://www.google.com/"); | |
2287 request.load_flags = 0; | |
2288 | |
2289 // Configure against https proxy server "proxy:70". | |
2290 SessionDependencies session_deps(ProxyService::CreateFixed( | |
2291 "https://proxy:70")); | |
2292 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
2293 session_deps.net_log = log.bound().net_log(); | |
2294 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
2295 | |
2296 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
2297 | |
2298 // CONNECT to www.google.com:443 via SPDY | |
2299 scoped_ptr<spdy::SpdyFrame> connect(ConstructSpdyConnect(NULL, 0, 1)); | |
2300 // fetch https://www.google.com/ via HTTP | |
2301 | |
2302 const char get[] = "GET / HTTP/1.1\r\n" | |
2303 "Host: www.google.com\r\n" | |
2304 "Connection: keep-alive\r\n\r\n"; | |
2305 scoped_ptr<spdy::SpdyFrame> wrapped_get( | |
2306 ConstructSpdyBodyFrame(1, get, strlen(get), false)); | |
2307 scoped_ptr<spdy::SpdyFrame> conn_resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2308 const char resp[] = "HTTP/1.1 200 OK\r\n" | |
2309 "Content-Length: 10\r\n\r\n"; | |
2310 scoped_ptr<spdy::SpdyFrame> wrapped_get_resp( | |
2311 ConstructSpdyBodyFrame(1, resp, strlen(resp), false)); | |
2312 scoped_ptr<spdy::SpdyFrame> wrapped_body( | |
2313 ConstructSpdyBodyFrame(1, "1234567890", 10, false)); | |
2314 scoped_ptr<spdy::SpdyFrame> window_update( | |
2315 ConstructSpdyWindowUpdate(1, wrapped_get_resp->length())); | |
2316 | |
2317 MockWrite spdy_writes[] = { | |
2318 CreateMockWrite(*connect, 1), | |
2319 CreateMockWrite(*wrapped_get, 3), | |
2320 CreateMockWrite(*window_update, 5) | |
2321 }; | |
2322 | |
2323 MockRead spdy_reads[] = { | |
2324 CreateMockRead(*conn_resp, 2, ASYNC), | |
2325 CreateMockRead(*wrapped_get_resp, 4, ASYNC), | |
2326 CreateMockRead(*wrapped_body, 6, ASYNC), | |
2327 CreateMockRead(*wrapped_body, 7, ASYNC), | |
2328 MockRead(ASYNC, 0, 8), | |
2329 }; | |
2330 | |
2331 scoped_ptr<OrderedSocketData> spdy_data( | |
2332 new OrderedSocketData( | |
2333 spdy_reads, arraysize(spdy_reads), | |
2334 spdy_writes, arraysize(spdy_writes))); | |
2335 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
2336 | |
2337 SSLSocketDataProvider ssl(ASYNC, OK); | |
2338 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
2339 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
2340 SSLSocketDataProvider ssl2(ASYNC, OK); | |
2341 ssl2.was_npn_negotiated = false; | |
2342 ssl2.protocol_negotiated = SSLClientSocket::kProtoUnknown; | |
2343 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2); | |
2344 | |
2345 TestCompletionCallback callback1; | |
2346 | |
2347 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
2348 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2349 | |
2350 rv = callback1.WaitForResult(); | |
2351 EXPECT_EQ(OK, rv); | |
2352 | |
2353 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
2354 ASSERT_TRUE(response != NULL); | |
2355 ASSERT_TRUE(response->headers != NULL); | |
2356 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
2357 | |
2358 std::string response_data; | |
2359 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
2360 EXPECT_EQ("1234567890", response_data); | |
2361 } | |
2362 | |
2363 // Test a SPDY CONNECT through an HTTPS Proxy to a SPDY server. | |
2364 TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyConnectSpdy) { | |
2365 HttpRequestInfo request; | |
2366 request.method = "GET"; | |
2367 request.url = GURL("https://www.google.com/"); | |
2368 request.load_flags = 0; | |
2369 | |
2370 // Configure against https proxy server "proxy:70". | |
2371 SessionDependencies session_deps(ProxyService::CreateFixed( | |
2372 "https://proxy:70")); | |
2373 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
2374 session_deps.net_log = log.bound().net_log(); | |
2375 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
2376 | |
2377 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
2378 | |
2379 // CONNECT to www.google.com:443 via SPDY | |
2380 scoped_ptr<spdy::SpdyFrame> connect(ConstructSpdyConnect(NULL, 0, 1)); | |
2381 // fetch https://www.google.com/ via SPDY | |
2382 const char* const kMyUrl = "https://www.google.com/"; | |
2383 scoped_ptr<spdy::SpdyFrame> get(ConstructSpdyGet(kMyUrl, false, 1, LOWEST)); | |
2384 scoped_ptr<spdy::SpdyFrame> wrapped_get(ConstructWrappedSpdyFrame(get, 1)); | |
2385 scoped_ptr<spdy::SpdyFrame> conn_resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2386 scoped_ptr<spdy::SpdyFrame> get_resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2387 scoped_ptr<spdy::SpdyFrame> wrapped_get_resp( | |
2388 ConstructWrappedSpdyFrame(get_resp, 1)); | |
2389 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
2390 scoped_ptr<spdy::SpdyFrame> wrapped_body(ConstructWrappedSpdyFrame(body, 1)); | |
2391 scoped_ptr<spdy::SpdyFrame> window_update_get_resp( | |
2392 ConstructSpdyWindowUpdate(1, wrapped_get_resp->length())); | |
2393 scoped_ptr<spdy::SpdyFrame> window_update_body( | |
2394 ConstructSpdyWindowUpdate(1, wrapped_body->length())); | |
2395 | |
2396 MockWrite spdy_writes[] = { | |
2397 CreateMockWrite(*connect, 1), | |
2398 CreateMockWrite(*wrapped_get, 3), | |
2399 CreateMockWrite(*window_update_get_resp, 5), | |
2400 CreateMockWrite(*window_update_body, 7), | |
2401 }; | |
2402 | |
2403 MockRead spdy_reads[] = { | |
2404 CreateMockRead(*conn_resp, 2, ASYNC), | |
2405 CreateMockRead(*wrapped_get_resp, 4, ASYNC), | |
2406 CreateMockRead(*wrapped_body, 6, ASYNC), | |
2407 MockRead(ASYNC, 0, 8), | |
2408 }; | |
2409 | |
2410 scoped_ptr<OrderedSocketData> spdy_data( | |
2411 new OrderedSocketData( | |
2412 spdy_reads, arraysize(spdy_reads), | |
2413 spdy_writes, arraysize(spdy_writes))); | |
2414 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
2415 | |
2416 SSLSocketDataProvider ssl(ASYNC, OK); | |
2417 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
2418 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
2419 SSLSocketDataProvider ssl2(ASYNC, OK); | |
2420 ssl2.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
2421 ssl2.protocol_negotiated = SSLClientSocket::kProtoSPDY21; | |
2422 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2); | |
2423 | |
2424 TestCompletionCallback callback1; | |
2425 | |
2426 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
2427 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2428 | |
2429 rv = callback1.WaitForResult(); | |
2430 EXPECT_EQ(OK, rv); | |
2431 | |
2432 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
2433 ASSERT_TRUE(response != NULL); | |
2434 ASSERT_TRUE(response->headers != NULL); | |
2435 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
2436 | |
2437 std::string response_data; | |
2438 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
2439 EXPECT_EQ(net::kUploadData, response_data); | |
2440 } | |
2441 | |
2442 // Test a SPDY CONNECT failure through an HTTPS Proxy. | |
2443 TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyConnectFailure) { | |
2444 HttpRequestInfo request; | |
2445 request.method = "GET"; | |
2446 request.url = GURL("https://www.google.com/"); | |
2447 request.load_flags = 0; | |
2448 | |
2449 // Configure against https proxy server "proxy:70". | |
2450 SessionDependencies session_deps(ProxyService::CreateFixed( | |
2451 "https://proxy:70")); | |
2452 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
2453 session_deps.net_log = log.bound().net_log(); | |
2454 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
2455 | |
2456 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
2457 | |
2458 // CONNECT to www.google.com:443 via SPDY | |
2459 scoped_ptr<spdy::SpdyFrame> connect(ConstructSpdyConnect(NULL, 0, 1)); | |
2460 scoped_ptr<spdy::SpdyFrame> get(ConstructSpdyRstStream(1, spdy::CANCEL)); | |
2461 | |
2462 MockWrite spdy_writes[] = { | |
2463 CreateMockWrite(*connect, 1), | |
2464 CreateMockWrite(*get, 3), | |
2465 }; | |
2466 | |
2467 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdySynReplyError(1)); | |
2468 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); | |
2469 MockRead spdy_reads[] = { | |
2470 CreateMockRead(*resp, 2, ASYNC), | |
2471 MockRead(ASYNC, 0, 4), | |
2472 }; | |
2473 | |
2474 scoped_ptr<OrderedSocketData> spdy_data( | |
2475 new OrderedSocketData( | |
2476 spdy_reads, arraysize(spdy_reads), | |
2477 spdy_writes, arraysize(spdy_writes))); | |
2478 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
2479 | |
2480 SSLSocketDataProvider ssl(ASYNC, OK); | |
2481 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
2482 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
2483 SSLSocketDataProvider ssl2(ASYNC, OK); | |
2484 ssl2.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
2485 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2); | |
2486 | |
2487 TestCompletionCallback callback1; | |
2488 | |
2489 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
2490 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2491 | |
2492 rv = callback1.WaitForResult(); | |
2493 EXPECT_EQ(OK, rv); | |
2494 | |
2495 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
2496 ASSERT_TRUE(response != NULL); | |
2497 EXPECT_EQ(500, response->headers->response_code()); | |
2498 } | |
2499 | |
2500 // Test the challenge-response-retry sequence through an HTTPS Proxy | |
2501 TEST_F(HttpNetworkTransactionTest, HttpsProxyAuthRetry) { | |
2502 HttpRequestInfo request; | |
2503 request.method = "GET"; | |
2504 request.url = GURL("http://www.google.com/"); | |
2505 // when the no authentication data flag is set. | |
2506 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; | |
2507 | |
2508 // Configure against https proxy server "myproxy:70". | |
2509 SessionDependencies session_deps( | |
2510 ProxyService::CreateFixed("https://myproxy:70")); | |
2511 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
2512 session_deps.net_log = log.bound().net_log(); | |
2513 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
2514 | |
2515 // Since we have proxy, should use full url | |
2516 MockWrite data_writes1[] = { | |
2517 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
2518 "Host: www.google.com\r\n" | |
2519 "Proxy-Connection: keep-alive\r\n\r\n"), | |
2520 | |
2521 // After calling trans->RestartWithAuth(), this is the request we should | |
2522 // be issuing -- the final header line contains the credentials. | |
2523 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
2524 "Host: www.google.com\r\n" | |
2525 "Proxy-Connection: keep-alive\r\n" | |
2526 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
2527 }; | |
2528 | |
2529 // The proxy responds to the GET with a 407, using a persistent | |
2530 // connection. | |
2531 MockRead data_reads1[] = { | |
2532 // No credentials. | |
2533 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
2534 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
2535 MockRead("Proxy-Connection: keep-alive\r\n"), | |
2536 MockRead("Content-Length: 0\r\n\r\n"), | |
2537 | |
2538 MockRead("HTTP/1.1 200 OK\r\n"), | |
2539 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
2540 MockRead("Content-Length: 100\r\n\r\n"), | |
2541 MockRead(SYNCHRONOUS, OK), | |
2542 }; | |
2543 | |
2544 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
2545 data_writes1, arraysize(data_writes1)); | |
2546 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
2547 SSLSocketDataProvider ssl(ASYNC, OK); | |
2548 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
2549 | |
2550 TestCompletionCallback callback1; | |
2551 | |
2552 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
2553 | |
2554 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
2555 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2556 | |
2557 rv = callback1.WaitForResult(); | |
2558 EXPECT_EQ(OK, rv); | |
2559 | |
2560 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
2561 ASSERT_TRUE(response != NULL); | |
2562 ASSERT_FALSE(response->headers == NULL); | |
2563 EXPECT_EQ(407, response->headers->response_code()); | |
2564 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
2565 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
2566 | |
2567 TestCompletionCallback callback2; | |
2568 | |
2569 rv = trans->RestartWithAuth( | |
2570 AuthCredentials(kFoo, kBar), callback2.callback()); | |
2571 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2572 | |
2573 rv = callback2.WaitForResult(); | |
2574 EXPECT_EQ(OK, rv); | |
2575 | |
2576 response = trans->GetResponseInfo(); | |
2577 ASSERT_TRUE(response != NULL); | |
2578 | |
2579 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
2580 EXPECT_EQ(200, response->headers->response_code()); | |
2581 EXPECT_EQ(100, response->headers->GetContentLength()); | |
2582 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
2583 | |
2584 // The password prompt info should not be set. | |
2585 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
2586 } | |
2587 | |
2588 void HttpNetworkTransactionTest::ConnectStatusHelperWithExpectedStatus( | |
2589 const MockRead& status, int expected_status) { | |
2590 HttpRequestInfo request; | |
2591 request.method = "GET"; | |
2592 request.url = GURL("https://www.google.com/"); | |
2593 request.load_flags = 0; | |
2594 | |
2595 // Configure against proxy server "myproxy:70". | |
2596 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
2597 | |
2598 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
2599 | |
2600 // Since we have proxy, should try to establish tunnel. | |
2601 MockWrite data_writes[] = { | |
2602 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
2603 "Host: www.google.com\r\n" | |
2604 "Proxy-Connection: keep-alive\r\n\r\n"), | |
2605 }; | |
2606 | |
2607 MockRead data_reads[] = { | |
2608 status, | |
2609 MockRead("Content-Length: 10\r\n\r\n"), | |
2610 // No response body because the test stops reading here. | |
2611 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. | |
2612 }; | |
2613 | |
2614 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
2615 data_writes, arraysize(data_writes)); | |
2616 session_deps.socket_factory.AddSocketDataProvider(&data); | |
2617 | |
2618 TestCompletionCallback callback; | |
2619 | |
2620 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
2621 | |
2622 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
2623 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2624 | |
2625 rv = callback.WaitForResult(); | |
2626 EXPECT_EQ(expected_status, rv); | |
2627 } | |
2628 | |
2629 void HttpNetworkTransactionTest::ConnectStatusHelper(const MockRead& status) { | |
2630 ConnectStatusHelperWithExpectedStatus( | |
2631 status, ERR_TUNNEL_CONNECTION_FAILED); | |
2632 } | |
2633 | |
2634 TEST_F(HttpNetworkTransactionTest, ConnectStatus100) { | |
2635 ConnectStatusHelper(MockRead("HTTP/1.1 100 Continue\r\n")); | |
2636 } | |
2637 | |
2638 TEST_F(HttpNetworkTransactionTest, ConnectStatus101) { | |
2639 ConnectStatusHelper(MockRead("HTTP/1.1 101 Switching Protocols\r\n")); | |
2640 } | |
2641 | |
2642 TEST_F(HttpNetworkTransactionTest, ConnectStatus201) { | |
2643 ConnectStatusHelper(MockRead("HTTP/1.1 201 Created\r\n")); | |
2644 } | |
2645 | |
2646 TEST_F(HttpNetworkTransactionTest, ConnectStatus202) { | |
2647 ConnectStatusHelper(MockRead("HTTP/1.1 202 Accepted\r\n")); | |
2648 } | |
2649 | |
2650 TEST_F(HttpNetworkTransactionTest, ConnectStatus203) { | |
2651 ConnectStatusHelper( | |
2652 MockRead("HTTP/1.1 203 Non-Authoritative Information\r\n")); | |
2653 } | |
2654 | |
2655 TEST_F(HttpNetworkTransactionTest, ConnectStatus204) { | |
2656 ConnectStatusHelper(MockRead("HTTP/1.1 204 No Content\r\n")); | |
2657 } | |
2658 | |
2659 TEST_F(HttpNetworkTransactionTest, ConnectStatus205) { | |
2660 ConnectStatusHelper(MockRead("HTTP/1.1 205 Reset Content\r\n")); | |
2661 } | |
2662 | |
2663 TEST_F(HttpNetworkTransactionTest, ConnectStatus206) { | |
2664 ConnectStatusHelper(MockRead("HTTP/1.1 206 Partial Content\r\n")); | |
2665 } | |
2666 | |
2667 TEST_F(HttpNetworkTransactionTest, ConnectStatus300) { | |
2668 ConnectStatusHelper(MockRead("HTTP/1.1 300 Multiple Choices\r\n")); | |
2669 } | |
2670 | |
2671 TEST_F(HttpNetworkTransactionTest, ConnectStatus301) { | |
2672 ConnectStatusHelper(MockRead("HTTP/1.1 301 Moved Permanently\r\n")); | |
2673 } | |
2674 | |
2675 TEST_F(HttpNetworkTransactionTest, ConnectStatus302) { | |
2676 ConnectStatusHelper(MockRead("HTTP/1.1 302 Found\r\n")); | |
2677 } | |
2678 | |
2679 TEST_F(HttpNetworkTransactionTest, ConnectStatus303) { | |
2680 ConnectStatusHelper(MockRead("HTTP/1.1 303 See Other\r\n")); | |
2681 } | |
2682 | |
2683 TEST_F(HttpNetworkTransactionTest, ConnectStatus304) { | |
2684 ConnectStatusHelper(MockRead("HTTP/1.1 304 Not Modified\r\n")); | |
2685 } | |
2686 | |
2687 TEST_F(HttpNetworkTransactionTest, ConnectStatus305) { | |
2688 ConnectStatusHelper(MockRead("HTTP/1.1 305 Use Proxy\r\n")); | |
2689 } | |
2690 | |
2691 TEST_F(HttpNetworkTransactionTest, ConnectStatus306) { | |
2692 ConnectStatusHelper(MockRead("HTTP/1.1 306\r\n")); | |
2693 } | |
2694 | |
2695 TEST_F(HttpNetworkTransactionTest, ConnectStatus307) { | |
2696 ConnectStatusHelper(MockRead("HTTP/1.1 307 Temporary Redirect\r\n")); | |
2697 } | |
2698 | |
2699 TEST_F(HttpNetworkTransactionTest, ConnectStatus400) { | |
2700 ConnectStatusHelper(MockRead("HTTP/1.1 400 Bad Request\r\n")); | |
2701 } | |
2702 | |
2703 TEST_F(HttpNetworkTransactionTest, ConnectStatus401) { | |
2704 ConnectStatusHelper(MockRead("HTTP/1.1 401 Unauthorized\r\n")); | |
2705 } | |
2706 | |
2707 TEST_F(HttpNetworkTransactionTest, ConnectStatus402) { | |
2708 ConnectStatusHelper(MockRead("HTTP/1.1 402 Payment Required\r\n")); | |
2709 } | |
2710 | |
2711 TEST_F(HttpNetworkTransactionTest, ConnectStatus403) { | |
2712 ConnectStatusHelper(MockRead("HTTP/1.1 403 Forbidden\r\n")); | |
2713 } | |
2714 | |
2715 TEST_F(HttpNetworkTransactionTest, ConnectStatus404) { | |
2716 ConnectStatusHelper(MockRead("HTTP/1.1 404 Not Found\r\n")); | |
2717 } | |
2718 | |
2719 TEST_F(HttpNetworkTransactionTest, ConnectStatus405) { | |
2720 ConnectStatusHelper(MockRead("HTTP/1.1 405 Method Not Allowed\r\n")); | |
2721 } | |
2722 | |
2723 TEST_F(HttpNetworkTransactionTest, ConnectStatus406) { | |
2724 ConnectStatusHelper(MockRead("HTTP/1.1 406 Not Acceptable\r\n")); | |
2725 } | |
2726 | |
2727 TEST_F(HttpNetworkTransactionTest, ConnectStatus407) { | |
2728 ConnectStatusHelperWithExpectedStatus( | |
2729 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
2730 ERR_PROXY_AUTH_UNSUPPORTED); | |
2731 } | |
2732 | |
2733 TEST_F(HttpNetworkTransactionTest, ConnectStatus408) { | |
2734 ConnectStatusHelper(MockRead("HTTP/1.1 408 Request Timeout\r\n")); | |
2735 } | |
2736 | |
2737 TEST_F(HttpNetworkTransactionTest, ConnectStatus409) { | |
2738 ConnectStatusHelper(MockRead("HTTP/1.1 409 Conflict\r\n")); | |
2739 } | |
2740 | |
2741 TEST_F(HttpNetworkTransactionTest, ConnectStatus410) { | |
2742 ConnectStatusHelper(MockRead("HTTP/1.1 410 Gone\r\n")); | |
2743 } | |
2744 | |
2745 TEST_F(HttpNetworkTransactionTest, ConnectStatus411) { | |
2746 ConnectStatusHelper(MockRead("HTTP/1.1 411 Length Required\r\n")); | |
2747 } | |
2748 | |
2749 TEST_F(HttpNetworkTransactionTest, ConnectStatus412) { | |
2750 ConnectStatusHelper(MockRead("HTTP/1.1 412 Precondition Failed\r\n")); | |
2751 } | |
2752 | |
2753 TEST_F(HttpNetworkTransactionTest, ConnectStatus413) { | |
2754 ConnectStatusHelper(MockRead("HTTP/1.1 413 Request Entity Too Large\r\n")); | |
2755 } | |
2756 | |
2757 TEST_F(HttpNetworkTransactionTest, ConnectStatus414) { | |
2758 ConnectStatusHelper(MockRead("HTTP/1.1 414 Request-URI Too Long\r\n")); | |
2759 } | |
2760 | |
2761 TEST_F(HttpNetworkTransactionTest, ConnectStatus415) { | |
2762 ConnectStatusHelper(MockRead("HTTP/1.1 415 Unsupported Media Type\r\n")); | |
2763 } | |
2764 | |
2765 TEST_F(HttpNetworkTransactionTest, ConnectStatus416) { | |
2766 ConnectStatusHelper( | |
2767 MockRead("HTTP/1.1 416 Requested Range Not Satisfiable\r\n")); | |
2768 } | |
2769 | |
2770 TEST_F(HttpNetworkTransactionTest, ConnectStatus417) { | |
2771 ConnectStatusHelper(MockRead("HTTP/1.1 417 Expectation Failed\r\n")); | |
2772 } | |
2773 | |
2774 TEST_F(HttpNetworkTransactionTest, ConnectStatus500) { | |
2775 ConnectStatusHelper(MockRead("HTTP/1.1 500 Internal Server Error\r\n")); | |
2776 } | |
2777 | |
2778 TEST_F(HttpNetworkTransactionTest, ConnectStatus501) { | |
2779 ConnectStatusHelper(MockRead("HTTP/1.1 501 Not Implemented\r\n")); | |
2780 } | |
2781 | |
2782 TEST_F(HttpNetworkTransactionTest, ConnectStatus502) { | |
2783 ConnectStatusHelper(MockRead("HTTP/1.1 502 Bad Gateway\r\n")); | |
2784 } | |
2785 | |
2786 TEST_F(HttpNetworkTransactionTest, ConnectStatus503) { | |
2787 ConnectStatusHelper(MockRead("HTTP/1.1 503 Service Unavailable\r\n")); | |
2788 } | |
2789 | |
2790 TEST_F(HttpNetworkTransactionTest, ConnectStatus504) { | |
2791 ConnectStatusHelper(MockRead("HTTP/1.1 504 Gateway Timeout\r\n")); | |
2792 } | |
2793 | |
2794 TEST_F(HttpNetworkTransactionTest, ConnectStatus505) { | |
2795 ConnectStatusHelper(MockRead("HTTP/1.1 505 HTTP Version Not Supported\r\n")); | |
2796 } | |
2797 | |
2798 // Test the flow when both the proxy server AND origin server require | |
2799 // authentication. Again, this uses basic auth for both since that is | |
2800 // the simplest to mock. | |
2801 TEST_F(HttpNetworkTransactionTest, BasicAuthProxyThenServer) { | |
2802 HttpRequestInfo request; | |
2803 request.method = "GET"; | |
2804 request.url = GURL("http://www.google.com/"); | |
2805 request.load_flags = 0; | |
2806 | |
2807 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
2808 | |
2809 // Configure against proxy server "myproxy:70". | |
2810 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction( | |
2811 CreateSession(&session_deps))); | |
2812 | |
2813 MockWrite data_writes1[] = { | |
2814 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
2815 "Host: www.google.com\r\n" | |
2816 "Proxy-Connection: keep-alive\r\n\r\n"), | |
2817 }; | |
2818 | |
2819 MockRead data_reads1[] = { | |
2820 MockRead("HTTP/1.0 407 Unauthorized\r\n"), | |
2821 // Give a couple authenticate options (only the middle one is actually | |
2822 // supported). | |
2823 MockRead("Proxy-Authenticate: Basic invalid\r\n"), // Malformed. | |
2824 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
2825 MockRead("Proxy-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"), | |
2826 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
2827 // Large content-length -- won't matter, as connection will be reset. | |
2828 MockRead("Content-Length: 10000\r\n\r\n"), | |
2829 MockRead(SYNCHRONOUS, ERR_FAILED), | |
2830 }; | |
2831 | |
2832 // After calling trans->RestartWithAuth() the first time, this is the | |
2833 // request we should be issuing -- the final header line contains the | |
2834 // proxy's credentials. | |
2835 MockWrite data_writes2[] = { | |
2836 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
2837 "Host: www.google.com\r\n" | |
2838 "Proxy-Connection: keep-alive\r\n" | |
2839 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
2840 }; | |
2841 | |
2842 // Now the proxy server lets the request pass through to origin server. | |
2843 // The origin server responds with a 401. | |
2844 MockRead data_reads2[] = { | |
2845 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
2846 // Note: We are using the same realm-name as the proxy server. This is | |
2847 // completely valid, as realms are unique across hosts. | |
2848 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
2849 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
2850 MockRead("Content-Length: 2000\r\n\r\n"), | |
2851 MockRead(SYNCHRONOUS, ERR_FAILED), // Won't be reached. | |
2852 }; | |
2853 | |
2854 // After calling trans->RestartWithAuth() the second time, we should send | |
2855 // the credentials for both the proxy and origin server. | |
2856 MockWrite data_writes3[] = { | |
2857 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
2858 "Host: www.google.com\r\n" | |
2859 "Proxy-Connection: keep-alive\r\n" | |
2860 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n" | |
2861 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"), | |
2862 }; | |
2863 | |
2864 // Lastly we get the desired content. | |
2865 MockRead data_reads3[] = { | |
2866 MockRead("HTTP/1.0 200 OK\r\n"), | |
2867 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
2868 MockRead("Content-Length: 100\r\n\r\n"), | |
2869 MockRead(SYNCHRONOUS, OK), | |
2870 }; | |
2871 | |
2872 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
2873 data_writes1, arraysize(data_writes1)); | |
2874 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
2875 data_writes2, arraysize(data_writes2)); | |
2876 StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3), | |
2877 data_writes3, arraysize(data_writes3)); | |
2878 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
2879 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
2880 session_deps.socket_factory.AddSocketDataProvider(&data3); | |
2881 | |
2882 TestCompletionCallback callback1; | |
2883 | |
2884 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
2885 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2886 | |
2887 rv = callback1.WaitForResult(); | |
2888 EXPECT_EQ(OK, rv); | |
2889 | |
2890 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
2891 ASSERT_TRUE(response != NULL); | |
2892 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
2893 | |
2894 TestCompletionCallback callback2; | |
2895 | |
2896 rv = trans->RestartWithAuth( | |
2897 AuthCredentials(kFoo, kBar), callback2.callback()); | |
2898 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2899 | |
2900 rv = callback2.WaitForResult(); | |
2901 EXPECT_EQ(OK, rv); | |
2902 | |
2903 response = trans->GetResponseInfo(); | |
2904 ASSERT_TRUE(response != NULL); | |
2905 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
2906 | |
2907 TestCompletionCallback callback3; | |
2908 | |
2909 rv = trans->RestartWithAuth( | |
2910 AuthCredentials(kFoo2, kBar2), callback3.callback()); | |
2911 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2912 | |
2913 rv = callback3.WaitForResult(); | |
2914 EXPECT_EQ(OK, rv); | |
2915 | |
2916 response = trans->GetResponseInfo(); | |
2917 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
2918 EXPECT_EQ(100, response->headers->GetContentLength()); | |
2919 } | |
2920 | |
2921 // For the NTLM implementation using SSPI, we skip the NTLM tests since we | |
2922 // can't hook into its internals to cause it to generate predictable NTLM | |
2923 // authorization headers. | |
2924 #if defined(NTLM_PORTABLE) | |
2925 // The NTLM authentication unit tests were generated by capturing the HTTP | |
2926 // requests and responses using Fiddler 2 and inspecting the generated random | |
2927 // bytes in the debugger. | |
2928 | |
2929 // Enter the correct password and authenticate successfully. | |
2930 TEST_F(HttpNetworkTransactionTest, NTLMAuth1) { | |
2931 HttpRequestInfo request; | |
2932 request.method = "GET"; | |
2933 request.url = GURL("http://172.22.68.17/kids/login.aspx"); | |
2934 request.load_flags = 0; | |
2935 | |
2936 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockGenerateRandom1, | |
2937 MockGetHostName); | |
2938 SessionDependencies session_deps; | |
2939 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
2940 | |
2941 MockWrite data_writes1[] = { | |
2942 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
2943 "Host: 172.22.68.17\r\n" | |
2944 "Connection: keep-alive\r\n\r\n"), | |
2945 }; | |
2946 | |
2947 MockRead data_reads1[] = { | |
2948 MockRead("HTTP/1.1 401 Access Denied\r\n"), | |
2949 // Negotiate and NTLM are often requested together. However, we only want | |
2950 // to test NTLM. Since Negotiate is preferred over NTLM, we have to skip | |
2951 // the header that requests Negotiate for this test. | |
2952 MockRead("WWW-Authenticate: NTLM\r\n"), | |
2953 MockRead("Connection: close\r\n"), | |
2954 MockRead("Content-Length: 42\r\n"), | |
2955 MockRead("Content-Type: text/html\r\n\r\n"), | |
2956 // Missing content -- won't matter, as connection will be reset. | |
2957 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), | |
2958 }; | |
2959 | |
2960 MockWrite data_writes2[] = { | |
2961 // After restarting with a null identity, this is the | |
2962 // request we should be issuing -- the final header line contains a Type | |
2963 // 1 message. | |
2964 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
2965 "Host: 172.22.68.17\r\n" | |
2966 "Connection: keep-alive\r\n" | |
2967 "Authorization: NTLM " | |
2968 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"), | |
2969 | |
2970 // After calling trans->RestartWithAuth(), we should send a Type 3 message | |
2971 // (the credentials for the origin server). The second request continues | |
2972 // on the same connection. | |
2973 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
2974 "Host: 172.22.68.17\r\n" | |
2975 "Connection: keep-alive\r\n" | |
2976 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA" | |
2977 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA" | |
2978 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBVKW" | |
2979 "Yma5xzVAAAAAAAAAAAAAAAAAAAAACH+gWcm+YsP9Tqb9zCR3WAeZZX" | |
2980 "ahlhx5I=\r\n\r\n"), | |
2981 }; | |
2982 | |
2983 MockRead data_reads2[] = { | |
2984 // The origin server responds with a Type 2 message. | |
2985 MockRead("HTTP/1.1 401 Access Denied\r\n"), | |
2986 MockRead("WWW-Authenticate: NTLM " | |
2987 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCjGpMpPGlYKkAAAAAAAAAALo" | |
2988 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE" | |
2989 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA" | |
2990 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy" | |
2991 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB" | |
2992 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw" | |
2993 "BtAAAAAAA=\r\n"), | |
2994 MockRead("Content-Length: 42\r\n"), | |
2995 MockRead("Content-Type: text/html\r\n\r\n"), | |
2996 MockRead("You are not authorized to view this page\r\n"), | |
2997 | |
2998 // Lastly we get the desired content. | |
2999 MockRead("HTTP/1.1 200 OK\r\n"), | |
3000 MockRead("Content-Type: text/html; charset=utf-8\r\n"), | |
3001 MockRead("Content-Length: 13\r\n\r\n"), | |
3002 MockRead("Please Login\r\n"), | |
3003 MockRead(SYNCHRONOUS, OK), | |
3004 }; | |
3005 | |
3006 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
3007 data_writes1, arraysize(data_writes1)); | |
3008 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
3009 data_writes2, arraysize(data_writes2)); | |
3010 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
3011 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
3012 | |
3013 TestCompletionCallback callback1; | |
3014 | |
3015 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
3016 | |
3017 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
3018 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3019 | |
3020 rv = callback1.WaitForResult(); | |
3021 EXPECT_EQ(OK, rv); | |
3022 | |
3023 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); | |
3024 | |
3025 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
3026 ASSERT_FALSE(response == NULL); | |
3027 EXPECT_TRUE(CheckNTLMServerAuth(response->auth_challenge.get())); | |
3028 | |
3029 TestCompletionCallback callback2; | |
3030 | |
3031 rv = trans->RestartWithAuth(AuthCredentials(kTestingNTLM, kTestingNTLM), | |
3032 callback2.callback()); | |
3033 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3034 | |
3035 rv = callback2.WaitForResult(); | |
3036 EXPECT_EQ(OK, rv); | |
3037 | |
3038 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); | |
3039 | |
3040 response = trans->GetResponseInfo(); | |
3041 ASSERT_TRUE(response != NULL); | |
3042 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
3043 | |
3044 TestCompletionCallback callback3; | |
3045 | |
3046 rv = trans->RestartWithAuth(AuthCredentials(), callback3.callback()); | |
3047 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3048 | |
3049 rv = callback3.WaitForResult(); | |
3050 EXPECT_EQ(OK, rv); | |
3051 | |
3052 response = trans->GetResponseInfo(); | |
3053 ASSERT_TRUE(response != NULL); | |
3054 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
3055 EXPECT_EQ(13, response->headers->GetContentLength()); | |
3056 } | |
3057 | |
3058 // Enter a wrong password, and then the correct one. | |
3059 TEST_F(HttpNetworkTransactionTest, NTLMAuth2) { | |
3060 HttpRequestInfo request; | |
3061 request.method = "GET"; | |
3062 request.url = GURL("http://172.22.68.17/kids/login.aspx"); | |
3063 request.load_flags = 0; | |
3064 | |
3065 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockGenerateRandom2, | |
3066 MockGetHostName); | |
3067 SessionDependencies session_deps; | |
3068 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
3069 | |
3070 MockWrite data_writes1[] = { | |
3071 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
3072 "Host: 172.22.68.17\r\n" | |
3073 "Connection: keep-alive\r\n\r\n"), | |
3074 }; | |
3075 | |
3076 MockRead data_reads1[] = { | |
3077 MockRead("HTTP/1.1 401 Access Denied\r\n"), | |
3078 // Negotiate and NTLM are often requested together. However, we only want | |
3079 // to test NTLM. Since Negotiate is preferred over NTLM, we have to skip | |
3080 // the header that requests Negotiate for this test. | |
3081 MockRead("WWW-Authenticate: NTLM\r\n"), | |
3082 MockRead("Connection: close\r\n"), | |
3083 MockRead("Content-Length: 42\r\n"), | |
3084 MockRead("Content-Type: text/html\r\n\r\n"), | |
3085 // Missing content -- won't matter, as connection will be reset. | |
3086 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), | |
3087 }; | |
3088 | |
3089 MockWrite data_writes2[] = { | |
3090 // After restarting with a null identity, this is the | |
3091 // request we should be issuing -- the final header line contains a Type | |
3092 // 1 message. | |
3093 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
3094 "Host: 172.22.68.17\r\n" | |
3095 "Connection: keep-alive\r\n" | |
3096 "Authorization: NTLM " | |
3097 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"), | |
3098 | |
3099 // After calling trans->RestartWithAuth(), we should send a Type 3 message | |
3100 // (the credentials for the origin server). The second request continues | |
3101 // on the same connection. | |
3102 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
3103 "Host: 172.22.68.17\r\n" | |
3104 "Connection: keep-alive\r\n" | |
3105 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA" | |
3106 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA" | |
3107 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwCWeY" | |
3108 "XnSZNwoQAAAAAAAAAAAAAAAAAAAADLa34/phTTKzNTWdub+uyFleOj" | |
3109 "4Ww7b7E=\r\n\r\n"), | |
3110 }; | |
3111 | |
3112 MockRead data_reads2[] = { | |
3113 // The origin server responds with a Type 2 message. | |
3114 MockRead("HTTP/1.1 401 Access Denied\r\n"), | |
3115 MockRead("WWW-Authenticate: NTLM " | |
3116 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCbVWUZezVGpAAAAAAAAAAALo" | |
3117 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE" | |
3118 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA" | |
3119 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy" | |
3120 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB" | |
3121 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw" | |
3122 "BtAAAAAAA=\r\n"), | |
3123 MockRead("Content-Length: 42\r\n"), | |
3124 MockRead("Content-Type: text/html\r\n\r\n"), | |
3125 MockRead("You are not authorized to view this page\r\n"), | |
3126 | |
3127 // Wrong password. | |
3128 MockRead("HTTP/1.1 401 Access Denied\r\n"), | |
3129 MockRead("WWW-Authenticate: NTLM\r\n"), | |
3130 MockRead("Connection: close\r\n"), | |
3131 MockRead("Content-Length: 42\r\n"), | |
3132 MockRead("Content-Type: text/html\r\n\r\n"), | |
3133 // Missing content -- won't matter, as connection will be reset. | |
3134 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), | |
3135 }; | |
3136 | |
3137 MockWrite data_writes3[] = { | |
3138 // After restarting with a null identity, this is the | |
3139 // request we should be issuing -- the final header line contains a Type | |
3140 // 1 message. | |
3141 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
3142 "Host: 172.22.68.17\r\n" | |
3143 "Connection: keep-alive\r\n" | |
3144 "Authorization: NTLM " | |
3145 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"), | |
3146 | |
3147 // After calling trans->RestartWithAuth(), we should send a Type 3 message | |
3148 // (the credentials for the origin server). The second request continues | |
3149 // on the same connection. | |
3150 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
3151 "Host: 172.22.68.17\r\n" | |
3152 "Connection: keep-alive\r\n" | |
3153 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA" | |
3154 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA" | |
3155 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBO54" | |
3156 "dFMVvTHwAAAAAAAAAAAAAAAAAAAACS7sT6Uzw7L0L//WUqlIaVWpbI" | |
3157 "+4MUm7c=\r\n\r\n"), | |
3158 }; | |
3159 | |
3160 MockRead data_reads3[] = { | |
3161 // The origin server responds with a Type 2 message. | |
3162 MockRead("HTTP/1.1 401 Access Denied\r\n"), | |
3163 MockRead("WWW-Authenticate: NTLM " | |
3164 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCL24VN8dgOR8AAAAAAAAAALo" | |
3165 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE" | |
3166 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA" | |
3167 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy" | |
3168 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB" | |
3169 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw" | |
3170 "BtAAAAAAA=\r\n"), | |
3171 MockRead("Content-Length: 42\r\n"), | |
3172 MockRead("Content-Type: text/html\r\n\r\n"), | |
3173 MockRead("You are not authorized to view this page\r\n"), | |
3174 | |
3175 // Lastly we get the desired content. | |
3176 MockRead("HTTP/1.1 200 OK\r\n"), | |
3177 MockRead("Content-Type: text/html; charset=utf-8\r\n"), | |
3178 MockRead("Content-Length: 13\r\n\r\n"), | |
3179 MockRead("Please Login\r\n"), | |
3180 MockRead(SYNCHRONOUS, OK), | |
3181 }; | |
3182 | |
3183 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
3184 data_writes1, arraysize(data_writes1)); | |
3185 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
3186 data_writes2, arraysize(data_writes2)); | |
3187 StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3), | |
3188 data_writes3, arraysize(data_writes3)); | |
3189 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
3190 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
3191 session_deps.socket_factory.AddSocketDataProvider(&data3); | |
3192 | |
3193 TestCompletionCallback callback1; | |
3194 | |
3195 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
3196 | |
3197 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
3198 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3199 | |
3200 rv = callback1.WaitForResult(); | |
3201 EXPECT_EQ(OK, rv); | |
3202 | |
3203 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); | |
3204 | |
3205 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
3206 ASSERT_TRUE(response != NULL); | |
3207 EXPECT_TRUE(CheckNTLMServerAuth(response->auth_challenge.get())); | |
3208 | |
3209 TestCompletionCallback callback2; | |
3210 | |
3211 // Enter the wrong password. | |
3212 rv = trans->RestartWithAuth(AuthCredentials(kTestingNTLM, kWrongPassword), | |
3213 callback2.callback()); | |
3214 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3215 | |
3216 rv = callback2.WaitForResult(); | |
3217 EXPECT_EQ(OK, rv); | |
3218 | |
3219 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); | |
3220 TestCompletionCallback callback3; | |
3221 rv = trans->RestartWithAuth(AuthCredentials(), callback3.callback()); | |
3222 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3223 rv = callback3.WaitForResult(); | |
3224 EXPECT_EQ(OK, rv); | |
3225 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); | |
3226 | |
3227 response = trans->GetResponseInfo(); | |
3228 ASSERT_FALSE(response == NULL); | |
3229 EXPECT_TRUE(CheckNTLMServerAuth(response->auth_challenge.get())); | |
3230 | |
3231 TestCompletionCallback callback4; | |
3232 | |
3233 // Now enter the right password. | |
3234 rv = trans->RestartWithAuth(AuthCredentials(kTestingNTLM, kTestingNTLM), | |
3235 callback4.callback()); | |
3236 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3237 | |
3238 rv = callback4.WaitForResult(); | |
3239 EXPECT_EQ(OK, rv); | |
3240 | |
3241 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); | |
3242 | |
3243 TestCompletionCallback callback5; | |
3244 | |
3245 // One more roundtrip | |
3246 rv = trans->RestartWithAuth(AuthCredentials(), callback5.callback()); | |
3247 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3248 | |
3249 rv = callback5.WaitForResult(); | |
3250 EXPECT_EQ(OK, rv); | |
3251 | |
3252 response = trans->GetResponseInfo(); | |
3253 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
3254 EXPECT_EQ(13, response->headers->GetContentLength()); | |
3255 } | |
3256 #endif // NTLM_PORTABLE | |
3257 | |
3258 // Test reading a server response which has only headers, and no body. | |
3259 // After some maximum number of bytes is consumed, the transaction should | |
3260 // fail with ERR_RESPONSE_HEADERS_TOO_BIG. | |
3261 TEST_F(HttpNetworkTransactionTest, LargeHeadersNoBody) { | |
3262 HttpRequestInfo request; | |
3263 request.method = "GET"; | |
3264 request.url = GURL("http://www.google.com/"); | |
3265 request.load_flags = 0; | |
3266 | |
3267 SessionDependencies session_deps; | |
3268 scoped_ptr<HttpTransaction> trans( | |
3269 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
3270 | |
3271 // Respond with 300 kb of headers (we should fail after 256 kb). | |
3272 std::string large_headers_string; | |
3273 FillLargeHeadersString(&large_headers_string, 300 * 1024); | |
3274 | |
3275 MockRead data_reads[] = { | |
3276 MockRead("HTTP/1.0 200 OK\r\n"), | |
3277 MockRead(ASYNC, large_headers_string.data(), large_headers_string.size()), | |
3278 MockRead("\r\nBODY"), | |
3279 MockRead(SYNCHRONOUS, OK), | |
3280 }; | |
3281 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
3282 session_deps.socket_factory.AddSocketDataProvider(&data); | |
3283 | |
3284 TestCompletionCallback callback; | |
3285 | |
3286 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
3287 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3288 | |
3289 rv = callback.WaitForResult(); | |
3290 EXPECT_EQ(ERR_RESPONSE_HEADERS_TOO_BIG, rv); | |
3291 | |
3292 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
3293 EXPECT_TRUE(response == NULL); | |
3294 } | |
3295 | |
3296 // Make sure that we don't try to reuse a TCPClientSocket when failing to | |
3297 // establish tunnel. | |
3298 // http://code.google.com/p/chromium/issues/detail?id=3772 | |
3299 TEST_F(HttpNetworkTransactionTest, DontRecycleTransportSocketForSSLTunnel) { | |
3300 HttpRequestInfo request; | |
3301 request.method = "GET"; | |
3302 request.url = GURL("https://www.google.com/"); | |
3303 request.load_flags = 0; | |
3304 | |
3305 // Configure against proxy server "myproxy:70". | |
3306 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
3307 | |
3308 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
3309 | |
3310 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
3311 | |
3312 // Since we have proxy, should try to establish tunnel. | |
3313 MockWrite data_writes1[] = { | |
3314 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
3315 "Host: www.google.com\r\n" | |
3316 "Proxy-Connection: keep-alive\r\n\r\n"), | |
3317 }; | |
3318 | |
3319 // The proxy responds to the connect with a 404, using a persistent | |
3320 // connection. Usually a proxy would return 501 (not implemented), | |
3321 // or 200 (tunnel established). | |
3322 MockRead data_reads1[] = { | |
3323 MockRead("HTTP/1.1 404 Not Found\r\n"), | |
3324 MockRead("Content-Length: 10\r\n\r\n"), | |
3325 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. | |
3326 }; | |
3327 | |
3328 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
3329 data_writes1, arraysize(data_writes1)); | |
3330 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
3331 | |
3332 TestCompletionCallback callback1; | |
3333 | |
3334 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
3335 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3336 | |
3337 rv = callback1.WaitForResult(); | |
3338 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); | |
3339 | |
3340 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
3341 EXPECT_TRUE(response == NULL); | |
3342 | |
3343 // Empty the current queue. This is necessary because idle sockets are | |
3344 // added to the connection pool asynchronously with a PostTask. | |
3345 MessageLoop::current()->RunAllPending(); | |
3346 | |
3347 // We now check to make sure the TCPClientSocket was not added back to | |
3348 // the pool. | |
3349 EXPECT_EQ(0, session->GetTransportSocketPool()->IdleSocketCount()); | |
3350 trans.reset(); | |
3351 MessageLoop::current()->RunAllPending(); | |
3352 // Make sure that the socket didn't get recycled after calling the destructor. | |
3353 EXPECT_EQ(0, session->GetTransportSocketPool()->IdleSocketCount()); | |
3354 } | |
3355 | |
3356 // Make sure that we recycle a socket after reading all of the response body. | |
3357 TEST_F(HttpNetworkTransactionTest, RecycleSocket) { | |
3358 HttpRequestInfo request; | |
3359 request.method = "GET"; | |
3360 request.url = GURL("http://www.google.com/"); | |
3361 request.load_flags = 0; | |
3362 | |
3363 SessionDependencies session_deps; | |
3364 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
3365 | |
3366 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
3367 | |
3368 MockRead data_reads[] = { | |
3369 // A part of the response body is received with the response headers. | |
3370 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\nhel"), | |
3371 // The rest of the response body is received in two parts. | |
3372 MockRead("lo"), | |
3373 MockRead(" world"), | |
3374 MockRead("junk"), // Should not be read!! | |
3375 MockRead(SYNCHRONOUS, OK), | |
3376 }; | |
3377 | |
3378 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
3379 session_deps.socket_factory.AddSocketDataProvider(&data); | |
3380 | |
3381 TestCompletionCallback callback; | |
3382 | |
3383 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
3384 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3385 | |
3386 rv = callback.WaitForResult(); | |
3387 EXPECT_EQ(OK, rv); | |
3388 | |
3389 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
3390 ASSERT_TRUE(response != NULL); | |
3391 | |
3392 EXPECT_TRUE(response->headers != NULL); | |
3393 std::string status_line = response->headers->GetStatusLine(); | |
3394 EXPECT_EQ("HTTP/1.1 200 OK", status_line); | |
3395 | |
3396 EXPECT_EQ(0, session->GetTransportSocketPool()->IdleSocketCount()); | |
3397 | |
3398 std::string response_data; | |
3399 rv = ReadTransaction(trans.get(), &response_data); | |
3400 EXPECT_EQ(OK, rv); | |
3401 EXPECT_EQ("hello world", response_data); | |
3402 | |
3403 // Empty the current queue. This is necessary because idle sockets are | |
3404 // added to the connection pool asynchronously with a PostTask. | |
3405 MessageLoop::current()->RunAllPending(); | |
3406 | |
3407 // We now check to make sure the socket was added back to the pool. | |
3408 EXPECT_EQ(1, session->GetTransportSocketPool()->IdleSocketCount()); | |
3409 } | |
3410 | |
3411 // Make sure that we recycle a SSL socket after reading all of the response | |
3412 // body. | |
3413 TEST_F(HttpNetworkTransactionTest, RecycleSSLSocket) { | |
3414 SessionDependencies session_deps; | |
3415 HttpRequestInfo request; | |
3416 request.method = "GET"; | |
3417 request.url = GURL("https://www.google.com/"); | |
3418 request.load_flags = 0; | |
3419 | |
3420 MockWrite data_writes[] = { | |
3421 MockWrite("GET / HTTP/1.1\r\n" | |
3422 "Host: www.google.com\r\n" | |
3423 "Connection: keep-alive\r\n\r\n"), | |
3424 }; | |
3425 | |
3426 MockRead data_reads[] = { | |
3427 MockRead("HTTP/1.1 200 OK\r\n"), | |
3428 MockRead("Content-Length: 11\r\n\r\n"), | |
3429 MockRead("hello world"), | |
3430 MockRead(SYNCHRONOUS, OK), | |
3431 }; | |
3432 | |
3433 SSLSocketDataProvider ssl(ASYNC, OK); | |
3434 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
3435 | |
3436 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
3437 data_writes, arraysize(data_writes)); | |
3438 session_deps.socket_factory.AddSocketDataProvider(&data); | |
3439 | |
3440 TestCompletionCallback callback; | |
3441 | |
3442 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
3443 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
3444 | |
3445 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
3446 | |
3447 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3448 EXPECT_EQ(OK, callback.WaitForResult()); | |
3449 | |
3450 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
3451 ASSERT_TRUE(response != NULL); | |
3452 ASSERT_TRUE(response->headers != NULL); | |
3453 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
3454 | |
3455 EXPECT_EQ(0, session->GetTransportSocketPool()->IdleSocketCount()); | |
3456 | |
3457 std::string response_data; | |
3458 rv = ReadTransaction(trans.get(), &response_data); | |
3459 EXPECT_EQ(OK, rv); | |
3460 EXPECT_EQ("hello world", response_data); | |
3461 | |
3462 // Empty the current queue. This is necessary because idle sockets are | |
3463 // added to the connection pool asynchronously with a PostTask. | |
3464 MessageLoop::current()->RunAllPending(); | |
3465 | |
3466 // We now check to make sure the socket was added back to the pool. | |
3467 EXPECT_EQ(1, session->GetSSLSocketPool()->IdleSocketCount()); | |
3468 } | |
3469 | |
3470 // Grab a SSL socket, use it, and put it back into the pool. Then, reuse it | |
3471 // from the pool and make sure that we recover okay. | |
3472 TEST_F(HttpNetworkTransactionTest, RecycleDeadSSLSocket) { | |
3473 SessionDependencies session_deps; | |
3474 HttpRequestInfo request; | |
3475 request.method = "GET"; | |
3476 request.url = GURL("https://www.google.com/"); | |
3477 request.load_flags = 0; | |
3478 | |
3479 MockWrite data_writes[] = { | |
3480 MockWrite("GET / HTTP/1.1\r\n" | |
3481 "Host: www.google.com\r\n" | |
3482 "Connection: keep-alive\r\n\r\n"), | |
3483 MockWrite("GET / HTTP/1.1\r\n" | |
3484 "Host: www.google.com\r\n" | |
3485 "Connection: keep-alive\r\n\r\n"), | |
3486 }; | |
3487 | |
3488 MockRead data_reads[] = { | |
3489 MockRead("HTTP/1.1 200 OK\r\n"), | |
3490 MockRead("Content-Length: 11\r\n\r\n"), | |
3491 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), | |
3492 MockRead("hello world"), | |
3493 MockRead(ASYNC, 0, 0) // EOF | |
3494 }; | |
3495 | |
3496 SSLSocketDataProvider ssl(ASYNC, OK); | |
3497 SSLSocketDataProvider ssl2(ASYNC, OK); | |
3498 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
3499 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2); | |
3500 | |
3501 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
3502 data_writes, arraysize(data_writes)); | |
3503 StaticSocketDataProvider data2(data_reads, arraysize(data_reads), | |
3504 data_writes, arraysize(data_writes)); | |
3505 session_deps.socket_factory.AddSocketDataProvider(&data); | |
3506 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
3507 | |
3508 TestCompletionCallback callback; | |
3509 | |
3510 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
3511 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
3512 | |
3513 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
3514 | |
3515 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3516 EXPECT_EQ(OK, callback.WaitForResult()); | |
3517 | |
3518 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
3519 ASSERT_TRUE(response != NULL); | |
3520 ASSERT_TRUE(response->headers != NULL); | |
3521 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
3522 | |
3523 EXPECT_EQ(0, session->GetTransportSocketPool()->IdleSocketCount()); | |
3524 | |
3525 std::string response_data; | |
3526 rv = ReadTransaction(trans.get(), &response_data); | |
3527 EXPECT_EQ(OK, rv); | |
3528 EXPECT_EQ("hello world", response_data); | |
3529 | |
3530 // Empty the current queue. This is necessary because idle sockets are | |
3531 // added to the connection pool asynchronously with a PostTask. | |
3532 MessageLoop::current()->RunAllPending(); | |
3533 | |
3534 // We now check to make sure the socket was added back to the pool. | |
3535 EXPECT_EQ(1, session->GetSSLSocketPool()->IdleSocketCount()); | |
3536 | |
3537 // Now start the second transaction, which should reuse the previous socket. | |
3538 | |
3539 trans.reset(new HttpNetworkTransaction(session)); | |
3540 | |
3541 rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
3542 | |
3543 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3544 EXPECT_EQ(OK, callback.WaitForResult()); | |
3545 | |
3546 response = trans->GetResponseInfo(); | |
3547 ASSERT_TRUE(response != NULL); | |
3548 ASSERT_TRUE(response->headers != NULL); | |
3549 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
3550 | |
3551 EXPECT_EQ(0, session->GetTransportSocketPool()->IdleSocketCount()); | |
3552 | |
3553 rv = ReadTransaction(trans.get(), &response_data); | |
3554 EXPECT_EQ(OK, rv); | |
3555 EXPECT_EQ("hello world", response_data); | |
3556 | |
3557 // Empty the current queue. This is necessary because idle sockets are | |
3558 // added to the connection pool asynchronously with a PostTask. | |
3559 MessageLoop::current()->RunAllPending(); | |
3560 | |
3561 // We now check to make sure the socket was added back to the pool. | |
3562 EXPECT_EQ(1, session->GetSSLSocketPool()->IdleSocketCount()); | |
3563 } | |
3564 | |
3565 // Make sure that we recycle a socket after a zero-length response. | |
3566 // http://crbug.com/9880 | |
3567 TEST_F(HttpNetworkTransactionTest, RecycleSocketAfterZeroContentLength) { | |
3568 HttpRequestInfo request; | |
3569 request.method = "GET"; | |
3570 request.url = GURL("http://www.google.com/csi?v=3&s=web&action=&" | |
3571 "tran=undefined&ei=mAXcSeegAo-SMurloeUN&" | |
3572 "e=17259,18167,19592,19773,19981,20133,20173,20233&" | |
3573 "rt=prt.2642,ol.2649,xjs.2951"); | |
3574 request.load_flags = 0; | |
3575 | |
3576 SessionDependencies session_deps; | |
3577 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
3578 | |
3579 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
3580 | |
3581 MockRead data_reads[] = { | |
3582 MockRead("HTTP/1.1 204 No Content\r\n" | |
3583 "Content-Length: 0\r\n" | |
3584 "Content-Type: text/html\r\n\r\n"), | |
3585 MockRead("junk"), // Should not be read!! | |
3586 MockRead(SYNCHRONOUS, OK), | |
3587 }; | |
3588 | |
3589 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
3590 session_deps.socket_factory.AddSocketDataProvider(&data); | |
3591 | |
3592 TestCompletionCallback callback; | |
3593 | |
3594 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
3595 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3596 | |
3597 rv = callback.WaitForResult(); | |
3598 EXPECT_EQ(OK, rv); | |
3599 | |
3600 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
3601 ASSERT_TRUE(response != NULL); | |
3602 | |
3603 EXPECT_TRUE(response->headers != NULL); | |
3604 std::string status_line = response->headers->GetStatusLine(); | |
3605 EXPECT_EQ("HTTP/1.1 204 No Content", status_line); | |
3606 | |
3607 EXPECT_EQ(0, session->GetTransportSocketPool()->IdleSocketCount()); | |
3608 | |
3609 std::string response_data; | |
3610 rv = ReadTransaction(trans.get(), &response_data); | |
3611 EXPECT_EQ(OK, rv); | |
3612 EXPECT_EQ("", response_data); | |
3613 | |
3614 // Empty the current queue. This is necessary because idle sockets are | |
3615 // added to the connection pool asynchronously with a PostTask. | |
3616 MessageLoop::current()->RunAllPending(); | |
3617 | |
3618 // We now check to make sure the socket was added back to the pool. | |
3619 EXPECT_EQ(1, session->GetTransportSocketPool()->IdleSocketCount()); | |
3620 } | |
3621 | |
3622 TEST_F(HttpNetworkTransactionTest, ResendRequestOnWriteBodyError) { | |
3623 HttpRequestInfo request[2]; | |
3624 // Transaction 1: a GET request that succeeds. The socket is recycled | |
3625 // after use. | |
3626 request[0].method = "GET"; | |
3627 request[0].url = GURL("http://www.google.com/"); | |
3628 request[0].load_flags = 0; | |
3629 // Transaction 2: a POST request. Reuses the socket kept alive from | |
3630 // transaction 1. The first attempts fails when writing the POST data. | |
3631 // This causes the transaction to retry with a new socket. The second | |
3632 // attempt succeeds. | |
3633 request[1].method = "POST"; | |
3634 request[1].url = GURL("http://www.google.com/login.cgi"); | |
3635 request[1].upload_data = new UploadData; | |
3636 request[1].upload_data->AppendBytes("foo", 3); | |
3637 request[1].load_flags = 0; | |
3638 | |
3639 SessionDependencies session_deps; | |
3640 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
3641 | |
3642 // The first socket is used for transaction 1 and the first attempt of | |
3643 // transaction 2. | |
3644 | |
3645 // The response of transaction 1. | |
3646 MockRead data_reads1[] = { | |
3647 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\n"), | |
3648 MockRead("hello world"), | |
3649 MockRead(SYNCHRONOUS, OK), | |
3650 }; | |
3651 // The mock write results of transaction 1 and the first attempt of | |
3652 // transaction 2. | |
3653 MockWrite data_writes1[] = { | |
3654 MockWrite(SYNCHRONOUS, 64), // GET | |
3655 MockWrite(SYNCHRONOUS, 93), // POST | |
3656 MockWrite(SYNCHRONOUS, ERR_CONNECTION_ABORTED), // POST data | |
3657 }; | |
3658 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
3659 data_writes1, arraysize(data_writes1)); | |
3660 | |
3661 // The second socket is used for the second attempt of transaction 2. | |
3662 | |
3663 // The response of transaction 2. | |
3664 MockRead data_reads2[] = { | |
3665 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 7\r\n\r\n"), | |
3666 MockRead("welcome"), | |
3667 MockRead(SYNCHRONOUS, OK), | |
3668 }; | |
3669 // The mock write results of the second attempt of transaction 2. | |
3670 MockWrite data_writes2[] = { | |
3671 MockWrite(SYNCHRONOUS, 93), // POST | |
3672 MockWrite(SYNCHRONOUS, 3), // POST data | |
3673 }; | |
3674 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
3675 data_writes2, arraysize(data_writes2)); | |
3676 | |
3677 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
3678 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
3679 | |
3680 const char* kExpectedResponseData[] = { | |
3681 "hello world", "welcome" | |
3682 }; | |
3683 | |
3684 for (int i = 0; i < 2; ++i) { | |
3685 scoped_ptr<HttpTransaction> trans( | |
3686 new HttpNetworkTransaction(session)); | |
3687 | |
3688 TestCompletionCallback callback; | |
3689 | |
3690 int rv = trans->Start(&request[i], callback.callback(), BoundNetLog()); | |
3691 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3692 | |
3693 rv = callback.WaitForResult(); | |
3694 EXPECT_EQ(OK, rv); | |
3695 | |
3696 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
3697 ASSERT_TRUE(response != NULL); | |
3698 | |
3699 EXPECT_TRUE(response->headers != NULL); | |
3700 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
3701 | |
3702 std::string response_data; | |
3703 rv = ReadTransaction(trans.get(), &response_data); | |
3704 EXPECT_EQ(OK, rv); | |
3705 EXPECT_EQ(kExpectedResponseData[i], response_data); | |
3706 } | |
3707 } | |
3708 | |
3709 // Test the request-challenge-retry sequence for basic auth when there is | |
3710 // an identity in the URL. The request should be sent as normal, but when | |
3711 // it fails the identity from the URL is no longer used. | |
3712 TEST_F(HttpNetworkTransactionTest, IgnoreAuthIdentityInURL) { | |
3713 HttpRequestInfo request; | |
3714 request.method = "GET"; | |
3715 request.url = GURL("http://foo:b@r@www.google.com/"); | |
3716 request.load_flags = LOAD_NORMAL; | |
3717 | |
3718 SessionDependencies session_deps; | |
3719 scoped_ptr<HttpTransaction> trans( | |
3720 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
3721 | |
3722 // The password contains an escaped character -- for this test to pass it | |
3723 // will need to be unescaped by HttpNetworkTransaction. | |
3724 EXPECT_EQ("b%40r", request.url.password()); | |
3725 | |
3726 MockWrite data_writes1[] = { | |
3727 MockWrite("GET / HTTP/1.1\r\n" | |
3728 "Host: www.google.com\r\n" | |
3729 "Connection: keep-alive\r\n\r\n"), | |
3730 }; | |
3731 | |
3732 MockRead data_reads1[] = { | |
3733 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
3734 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
3735 MockRead("Content-Length: 10\r\n\r\n"), | |
3736 MockRead(SYNCHRONOUS, ERR_FAILED), | |
3737 }; | |
3738 | |
3739 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
3740 data_writes1, arraysize(data_writes1)); | |
3741 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
3742 | |
3743 TestCompletionCallback callback1; | |
3744 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
3745 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3746 rv = callback1.WaitForResult(); | |
3747 EXPECT_EQ(OK, rv); | |
3748 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); | |
3749 | |
3750 // Empty the current queue. | |
3751 MessageLoop::current()->RunAllPending(); | |
3752 } | |
3753 | |
3754 // Test that previously tried username/passwords for a realm get re-used. | |
3755 TEST_F(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) { | |
3756 SessionDependencies session_deps; | |
3757 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
3758 | |
3759 // Transaction 1: authenticate (foo, bar) on MyRealm1 | |
3760 { | |
3761 HttpRequestInfo request; | |
3762 request.method = "GET"; | |
3763 request.url = GURL("http://www.google.com/x/y/z"); | |
3764 request.load_flags = 0; | |
3765 | |
3766 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
3767 | |
3768 MockWrite data_writes1[] = { | |
3769 MockWrite("GET /x/y/z HTTP/1.1\r\n" | |
3770 "Host: www.google.com\r\n" | |
3771 "Connection: keep-alive\r\n\r\n"), | |
3772 }; | |
3773 | |
3774 MockRead data_reads1[] = { | |
3775 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
3776 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
3777 MockRead("Content-Length: 10000\r\n\r\n"), | |
3778 MockRead(SYNCHRONOUS, ERR_FAILED), | |
3779 }; | |
3780 | |
3781 // Resend with authorization (username=foo, password=bar) | |
3782 MockWrite data_writes2[] = { | |
3783 MockWrite("GET /x/y/z HTTP/1.1\r\n" | |
3784 "Host: www.google.com\r\n" | |
3785 "Connection: keep-alive\r\n" | |
3786 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
3787 }; | |
3788 | |
3789 // Sever accepts the authorization. | |
3790 MockRead data_reads2[] = { | |
3791 MockRead("HTTP/1.0 200 OK\r\n"), | |
3792 MockRead("Content-Length: 100\r\n\r\n"), | |
3793 MockRead(SYNCHRONOUS, OK), | |
3794 }; | |
3795 | |
3796 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
3797 data_writes1, arraysize(data_writes1)); | |
3798 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
3799 data_writes2, arraysize(data_writes2)); | |
3800 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
3801 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
3802 | |
3803 TestCompletionCallback callback1; | |
3804 | |
3805 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
3806 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3807 | |
3808 rv = callback1.WaitForResult(); | |
3809 EXPECT_EQ(OK, rv); | |
3810 | |
3811 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
3812 ASSERT_TRUE(response != NULL); | |
3813 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
3814 | |
3815 TestCompletionCallback callback2; | |
3816 | |
3817 rv = trans->RestartWithAuth( | |
3818 AuthCredentials(kFoo, kBar), callback2.callback()); | |
3819 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3820 | |
3821 rv = callback2.WaitForResult(); | |
3822 EXPECT_EQ(OK, rv); | |
3823 | |
3824 response = trans->GetResponseInfo(); | |
3825 ASSERT_TRUE(response != NULL); | |
3826 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
3827 EXPECT_EQ(100, response->headers->GetContentLength()); | |
3828 } | |
3829 | |
3830 // ------------------------------------------------------------------------ | |
3831 | |
3832 // Transaction 2: authenticate (foo2, bar2) on MyRealm2 | |
3833 { | |
3834 HttpRequestInfo request; | |
3835 request.method = "GET"; | |
3836 // Note that Transaction 1 was at /x/y/z, so this is in the same | |
3837 // protection space as MyRealm1. | |
3838 request.url = GURL("http://www.google.com/x/y/a/b"); | |
3839 request.load_flags = 0; | |
3840 | |
3841 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
3842 | |
3843 MockWrite data_writes1[] = { | |
3844 MockWrite("GET /x/y/a/b HTTP/1.1\r\n" | |
3845 "Host: www.google.com\r\n" | |
3846 "Connection: keep-alive\r\n" | |
3847 // Send preemptive authorization for MyRealm1 | |
3848 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
3849 }; | |
3850 | |
3851 // The server didn't like the preemptive authorization, and | |
3852 // challenges us for a different realm (MyRealm2). | |
3853 MockRead data_reads1[] = { | |
3854 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
3855 MockRead("WWW-Authenticate: Basic realm=\"MyRealm2\"\r\n"), | |
3856 MockRead("Content-Length: 10000\r\n\r\n"), | |
3857 MockRead(SYNCHRONOUS, ERR_FAILED), | |
3858 }; | |
3859 | |
3860 // Resend with authorization for MyRealm2 (username=foo2, password=bar2) | |
3861 MockWrite data_writes2[] = { | |
3862 MockWrite("GET /x/y/a/b HTTP/1.1\r\n" | |
3863 "Host: www.google.com\r\n" | |
3864 "Connection: keep-alive\r\n" | |
3865 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"), | |
3866 }; | |
3867 | |
3868 // Sever accepts the authorization. | |
3869 MockRead data_reads2[] = { | |
3870 MockRead("HTTP/1.0 200 OK\r\n"), | |
3871 MockRead("Content-Length: 100\r\n\r\n"), | |
3872 MockRead(SYNCHRONOUS, OK), | |
3873 }; | |
3874 | |
3875 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
3876 data_writes1, arraysize(data_writes1)); | |
3877 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
3878 data_writes2, arraysize(data_writes2)); | |
3879 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
3880 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
3881 | |
3882 TestCompletionCallback callback1; | |
3883 | |
3884 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
3885 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3886 | |
3887 rv = callback1.WaitForResult(); | |
3888 EXPECT_EQ(OK, rv); | |
3889 | |
3890 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
3891 ASSERT_TRUE(response != NULL); | |
3892 ASSERT_TRUE(response->auth_challenge.get()); | |
3893 EXPECT_FALSE(response->auth_challenge->is_proxy); | |
3894 EXPECT_EQ("www.google.com:80", | |
3895 response->auth_challenge->challenger.ToString()); | |
3896 EXPECT_EQ("MyRealm2", response->auth_challenge->realm); | |
3897 EXPECT_EQ("basic", response->auth_challenge->scheme); | |
3898 | |
3899 TestCompletionCallback callback2; | |
3900 | |
3901 rv = trans->RestartWithAuth( | |
3902 AuthCredentials(kFoo2, kBar2), callback2.callback()); | |
3903 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3904 | |
3905 rv = callback2.WaitForResult(); | |
3906 EXPECT_EQ(OK, rv); | |
3907 | |
3908 response = trans->GetResponseInfo(); | |
3909 ASSERT_TRUE(response != NULL); | |
3910 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
3911 EXPECT_EQ(100, response->headers->GetContentLength()); | |
3912 } | |
3913 | |
3914 // ------------------------------------------------------------------------ | |
3915 | |
3916 // Transaction 3: Resend a request in MyRealm's protection space -- | |
3917 // succeed with preemptive authorization. | |
3918 { | |
3919 HttpRequestInfo request; | |
3920 request.method = "GET"; | |
3921 request.url = GURL("http://www.google.com/x/y/z2"); | |
3922 request.load_flags = 0; | |
3923 | |
3924 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
3925 | |
3926 MockWrite data_writes1[] = { | |
3927 MockWrite("GET /x/y/z2 HTTP/1.1\r\n" | |
3928 "Host: www.google.com\r\n" | |
3929 "Connection: keep-alive\r\n" | |
3930 // The authorization for MyRealm1 gets sent preemptively | |
3931 // (since the url is in the same protection space) | |
3932 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
3933 }; | |
3934 | |
3935 // Sever accepts the preemptive authorization | |
3936 MockRead data_reads1[] = { | |
3937 MockRead("HTTP/1.0 200 OK\r\n"), | |
3938 MockRead("Content-Length: 100\r\n\r\n"), | |
3939 MockRead(SYNCHRONOUS, OK), | |
3940 }; | |
3941 | |
3942 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
3943 data_writes1, arraysize(data_writes1)); | |
3944 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
3945 | |
3946 TestCompletionCallback callback1; | |
3947 | |
3948 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
3949 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3950 | |
3951 rv = callback1.WaitForResult(); | |
3952 EXPECT_EQ(OK, rv); | |
3953 | |
3954 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
3955 ASSERT_TRUE(response != NULL); | |
3956 | |
3957 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
3958 EXPECT_EQ(100, response->headers->GetContentLength()); | |
3959 } | |
3960 | |
3961 // ------------------------------------------------------------------------ | |
3962 | |
3963 // Transaction 4: request another URL in MyRealm (however the | |
3964 // url is not known to belong to the protection space, so no pre-auth). | |
3965 { | |
3966 HttpRequestInfo request; | |
3967 request.method = "GET"; | |
3968 request.url = GURL("http://www.google.com/x/1"); | |
3969 request.load_flags = 0; | |
3970 | |
3971 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
3972 | |
3973 MockWrite data_writes1[] = { | |
3974 MockWrite("GET /x/1 HTTP/1.1\r\n" | |
3975 "Host: www.google.com\r\n" | |
3976 "Connection: keep-alive\r\n\r\n"), | |
3977 }; | |
3978 | |
3979 MockRead data_reads1[] = { | |
3980 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
3981 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
3982 MockRead("Content-Length: 10000\r\n\r\n"), | |
3983 MockRead(SYNCHRONOUS, ERR_FAILED), | |
3984 }; | |
3985 | |
3986 // Resend with authorization from MyRealm's cache. | |
3987 MockWrite data_writes2[] = { | |
3988 MockWrite("GET /x/1 HTTP/1.1\r\n" | |
3989 "Host: www.google.com\r\n" | |
3990 "Connection: keep-alive\r\n" | |
3991 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
3992 }; | |
3993 | |
3994 // Sever accepts the authorization. | |
3995 MockRead data_reads2[] = { | |
3996 MockRead("HTTP/1.0 200 OK\r\n"), | |
3997 MockRead("Content-Length: 100\r\n\r\n"), | |
3998 MockRead(SYNCHRONOUS, OK), | |
3999 }; | |
4000 | |
4001 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
4002 data_writes1, arraysize(data_writes1)); | |
4003 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
4004 data_writes2, arraysize(data_writes2)); | |
4005 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
4006 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
4007 | |
4008 TestCompletionCallback callback1; | |
4009 | |
4010 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
4011 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4012 | |
4013 rv = callback1.WaitForResult(); | |
4014 EXPECT_EQ(OK, rv); | |
4015 | |
4016 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); | |
4017 TestCompletionCallback callback2; | |
4018 rv = trans->RestartWithAuth(AuthCredentials(), callback2.callback()); | |
4019 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4020 rv = callback2.WaitForResult(); | |
4021 EXPECT_EQ(OK, rv); | |
4022 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); | |
4023 | |
4024 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4025 ASSERT_TRUE(response != NULL); | |
4026 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
4027 EXPECT_EQ(100, response->headers->GetContentLength()); | |
4028 } | |
4029 | |
4030 // ------------------------------------------------------------------------ | |
4031 | |
4032 // Transaction 5: request a URL in MyRealm, but the server rejects the | |
4033 // cached identity. Should invalidate and re-prompt. | |
4034 { | |
4035 HttpRequestInfo request; | |
4036 request.method = "GET"; | |
4037 request.url = GURL("http://www.google.com/p/q/t"); | |
4038 request.load_flags = 0; | |
4039 | |
4040 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
4041 | |
4042 MockWrite data_writes1[] = { | |
4043 MockWrite("GET /p/q/t HTTP/1.1\r\n" | |
4044 "Host: www.google.com\r\n" | |
4045 "Connection: keep-alive\r\n\r\n"), | |
4046 }; | |
4047 | |
4048 MockRead data_reads1[] = { | |
4049 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
4050 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
4051 MockRead("Content-Length: 10000\r\n\r\n"), | |
4052 MockRead(SYNCHRONOUS, ERR_FAILED), | |
4053 }; | |
4054 | |
4055 // Resend with authorization from cache for MyRealm. | |
4056 MockWrite data_writes2[] = { | |
4057 MockWrite("GET /p/q/t HTTP/1.1\r\n" | |
4058 "Host: www.google.com\r\n" | |
4059 "Connection: keep-alive\r\n" | |
4060 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
4061 }; | |
4062 | |
4063 // Sever rejects the authorization. | |
4064 MockRead data_reads2[] = { | |
4065 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
4066 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
4067 MockRead("Content-Length: 10000\r\n\r\n"), | |
4068 MockRead(SYNCHRONOUS, ERR_FAILED), | |
4069 }; | |
4070 | |
4071 // At this point we should prompt for new credentials for MyRealm. | |
4072 // Restart with username=foo3, password=foo4. | |
4073 MockWrite data_writes3[] = { | |
4074 MockWrite("GET /p/q/t HTTP/1.1\r\n" | |
4075 "Host: www.google.com\r\n" | |
4076 "Connection: keep-alive\r\n" | |
4077 "Authorization: Basic Zm9vMzpiYXIz\r\n\r\n"), | |
4078 }; | |
4079 | |
4080 // Sever accepts the authorization. | |
4081 MockRead data_reads3[] = { | |
4082 MockRead("HTTP/1.0 200 OK\r\n"), | |
4083 MockRead("Content-Length: 100\r\n\r\n"), | |
4084 MockRead(SYNCHRONOUS, OK), | |
4085 }; | |
4086 | |
4087 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
4088 data_writes1, arraysize(data_writes1)); | |
4089 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
4090 data_writes2, arraysize(data_writes2)); | |
4091 StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3), | |
4092 data_writes3, arraysize(data_writes3)); | |
4093 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
4094 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
4095 session_deps.socket_factory.AddSocketDataProvider(&data3); | |
4096 | |
4097 TestCompletionCallback callback1; | |
4098 | |
4099 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
4100 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4101 | |
4102 rv = callback1.WaitForResult(); | |
4103 EXPECT_EQ(OK, rv); | |
4104 | |
4105 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); | |
4106 TestCompletionCallback callback2; | |
4107 rv = trans->RestartWithAuth(AuthCredentials(), callback2.callback()); | |
4108 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4109 rv = callback2.WaitForResult(); | |
4110 EXPECT_EQ(OK, rv); | |
4111 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); | |
4112 | |
4113 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4114 ASSERT_TRUE(response != NULL); | |
4115 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
4116 | |
4117 TestCompletionCallback callback3; | |
4118 | |
4119 rv = trans->RestartWithAuth( | |
4120 AuthCredentials(kFoo3, kBar3), callback3.callback()); | |
4121 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4122 | |
4123 rv = callback3.WaitForResult(); | |
4124 EXPECT_EQ(OK, rv); | |
4125 | |
4126 response = trans->GetResponseInfo(); | |
4127 ASSERT_TRUE(response != NULL); | |
4128 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
4129 EXPECT_EQ(100, response->headers->GetContentLength()); | |
4130 } | |
4131 } | |
4132 | |
4133 // Tests that nonce count increments when multiple auth attempts | |
4134 // are started with the same nonce. | |
4135 TEST_F(HttpNetworkTransactionTest, DigestPreAuthNonceCount) { | |
4136 SessionDependencies session_deps; | |
4137 HttpAuthHandlerDigest::Factory* digest_factory = | |
4138 new HttpAuthHandlerDigest::Factory(); | |
4139 HttpAuthHandlerDigest::FixedNonceGenerator* nonce_generator = | |
4140 new HttpAuthHandlerDigest::FixedNonceGenerator("0123456789abcdef"); | |
4141 digest_factory->set_nonce_generator(nonce_generator); | |
4142 session_deps.http_auth_handler_factory.reset(digest_factory); | |
4143 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
4144 | |
4145 // Transaction 1: authenticate (foo, bar) on MyRealm1 | |
4146 { | |
4147 HttpRequestInfo request; | |
4148 request.method = "GET"; | |
4149 request.url = GURL("http://www.google.com/x/y/z"); | |
4150 request.load_flags = 0; | |
4151 | |
4152 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
4153 | |
4154 MockWrite data_writes1[] = { | |
4155 MockWrite("GET /x/y/z HTTP/1.1\r\n" | |
4156 "Host: www.google.com\r\n" | |
4157 "Connection: keep-alive\r\n\r\n"), | |
4158 }; | |
4159 | |
4160 MockRead data_reads1[] = { | |
4161 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
4162 MockRead("WWW-Authenticate: Digest realm=\"digestive\", nonce=\"OU812\", " | |
4163 "algorithm=MD5, qop=\"auth\"\r\n\r\n"), | |
4164 MockRead(SYNCHRONOUS, OK), | |
4165 }; | |
4166 | |
4167 // Resend with authorization (username=foo, password=bar) | |
4168 MockWrite data_writes2[] = { | |
4169 MockWrite("GET /x/y/z HTTP/1.1\r\n" | |
4170 "Host: www.google.com\r\n" | |
4171 "Connection: keep-alive\r\n" | |
4172 "Authorization: Digest username=\"foo\", realm=\"digestive\", " | |
4173 "nonce=\"OU812\", uri=\"/x/y/z\", algorithm=MD5, " | |
4174 "response=\"03ffbcd30add722589c1de345d7a927f\", qop=auth, " | |
4175 "nc=00000001, cnonce=\"0123456789abcdef\"\r\n\r\n"), | |
4176 }; | |
4177 | |
4178 // Sever accepts the authorization. | |
4179 MockRead data_reads2[] = { | |
4180 MockRead("HTTP/1.0 200 OK\r\n"), | |
4181 MockRead(SYNCHRONOUS, OK), | |
4182 }; | |
4183 | |
4184 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
4185 data_writes1, arraysize(data_writes1)); | |
4186 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
4187 data_writes2, arraysize(data_writes2)); | |
4188 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
4189 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
4190 | |
4191 TestCompletionCallback callback1; | |
4192 | |
4193 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
4194 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4195 | |
4196 rv = callback1.WaitForResult(); | |
4197 EXPECT_EQ(OK, rv); | |
4198 | |
4199 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4200 ASSERT_TRUE(response != NULL); | |
4201 EXPECT_TRUE(CheckDigestServerAuth(response->auth_challenge.get())); | |
4202 | |
4203 TestCompletionCallback callback2; | |
4204 | |
4205 rv = trans->RestartWithAuth( | |
4206 AuthCredentials(kFoo, kBar), callback2.callback()); | |
4207 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4208 | |
4209 rv = callback2.WaitForResult(); | |
4210 EXPECT_EQ(OK, rv); | |
4211 | |
4212 response = trans->GetResponseInfo(); | |
4213 ASSERT_TRUE(response != NULL); | |
4214 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
4215 } | |
4216 | |
4217 // ------------------------------------------------------------------------ | |
4218 | |
4219 // Transaction 2: Request another resource in digestive's protection space. | |
4220 // This will preemptively add an Authorization header which should have an | |
4221 // "nc" value of 2 (as compared to 1 in the first use. | |
4222 { | |
4223 HttpRequestInfo request; | |
4224 request.method = "GET"; | |
4225 // Note that Transaction 1 was at /x/y/z, so this is in the same | |
4226 // protection space as digest. | |
4227 request.url = GURL("http://www.google.com/x/y/a/b"); | |
4228 request.load_flags = 0; | |
4229 | |
4230 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
4231 | |
4232 MockWrite data_writes1[] = { | |
4233 MockWrite("GET /x/y/a/b HTTP/1.1\r\n" | |
4234 "Host: www.google.com\r\n" | |
4235 "Connection: keep-alive\r\n" | |
4236 "Authorization: Digest username=\"foo\", realm=\"digestive\", " | |
4237 "nonce=\"OU812\", uri=\"/x/y/a/b\", algorithm=MD5, " | |
4238 "response=\"d6f9a2c07d1c5df7b89379dca1269b35\", qop=auth, " | |
4239 "nc=00000002, cnonce=\"0123456789abcdef\"\r\n\r\n"), | |
4240 }; | |
4241 | |
4242 // Sever accepts the authorization. | |
4243 MockRead data_reads1[] = { | |
4244 MockRead("HTTP/1.0 200 OK\r\n"), | |
4245 MockRead("Content-Length: 100\r\n\r\n"), | |
4246 MockRead(SYNCHRONOUS, OK), | |
4247 }; | |
4248 | |
4249 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
4250 data_writes1, arraysize(data_writes1)); | |
4251 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
4252 | |
4253 TestCompletionCallback callback1; | |
4254 | |
4255 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
4256 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4257 | |
4258 rv = callback1.WaitForResult(); | |
4259 EXPECT_EQ(OK, rv); | |
4260 | |
4261 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4262 ASSERT_TRUE(response != NULL); | |
4263 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
4264 } | |
4265 } | |
4266 | |
4267 // Test the ResetStateForRestart() private method. | |
4268 TEST_F(HttpNetworkTransactionTest, ResetStateForRestart) { | |
4269 // Create a transaction (the dependencies aren't important). | |
4270 SessionDependencies session_deps; | |
4271 scoped_ptr<HttpNetworkTransaction> trans( | |
4272 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
4273 | |
4274 // Setup some state (which we expect ResetStateForRestart() will clear). | |
4275 trans->read_buf_ = new IOBuffer(15); | |
4276 trans->read_buf_len_ = 15; | |
4277 trans->request_headers_.SetHeader("Authorization", "NTLM"); | |
4278 | |
4279 // Setup state in response_ | |
4280 HttpResponseInfo* response = &trans->response_; | |
4281 response->auth_challenge = new AuthChallengeInfo(); | |
4282 response->ssl_info.cert_status = static_cast<CertStatus>(-1); // Nonsensical. | |
4283 response->response_time = base::Time::Now(); | |
4284 response->was_cached = true; // (Wouldn't ever actually be true...) | |
4285 | |
4286 { // Setup state for response_.vary_data | |
4287 HttpRequestInfo request; | |
4288 std::string temp("HTTP/1.1 200 OK\nVary: foo, bar\n\n"); | |
4289 std::replace(temp.begin(), temp.end(), '\n', '\0'); | |
4290 scoped_refptr<HttpResponseHeaders> headers(new HttpResponseHeaders(temp)); | |
4291 request.extra_headers.SetHeader("Foo", "1"); | |
4292 request.extra_headers.SetHeader("bar", "23"); | |
4293 EXPECT_TRUE(response->vary_data.Init(request, *headers)); | |
4294 } | |
4295 | |
4296 // Cause the above state to be reset. | |
4297 trans->ResetStateForRestart(); | |
4298 | |
4299 // Verify that the state that needed to be reset, has been reset. | |
4300 EXPECT_TRUE(trans->read_buf_.get() == NULL); | |
4301 EXPECT_EQ(0, trans->read_buf_len_); | |
4302 EXPECT_TRUE(trans->request_headers_.IsEmpty()); | |
4303 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
4304 EXPECT_TRUE(response->headers.get() == NULL); | |
4305 EXPECT_FALSE(response->was_cached); | |
4306 EXPECT_EQ(0U, response->ssl_info.cert_status); | |
4307 EXPECT_FALSE(response->vary_data.is_valid()); | |
4308 } | |
4309 | |
4310 // Test HTTPS connections to a site with a bad certificate | |
4311 TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificate) { | |
4312 HttpRequestInfo request; | |
4313 request.method = "GET"; | |
4314 request.url = GURL("https://www.google.com/"); | |
4315 request.load_flags = 0; | |
4316 | |
4317 SessionDependencies session_deps; | |
4318 scoped_ptr<HttpTransaction> trans( | |
4319 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
4320 | |
4321 MockWrite data_writes[] = { | |
4322 MockWrite("GET / HTTP/1.1\r\n" | |
4323 "Host: www.google.com\r\n" | |
4324 "Connection: keep-alive\r\n\r\n"), | |
4325 }; | |
4326 | |
4327 MockRead data_reads[] = { | |
4328 MockRead("HTTP/1.0 200 OK\r\n"), | |
4329 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
4330 MockRead("Content-Length: 100\r\n\r\n"), | |
4331 MockRead(SYNCHRONOUS, OK), | |
4332 }; | |
4333 | |
4334 StaticSocketDataProvider ssl_bad_certificate; | |
4335 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
4336 data_writes, arraysize(data_writes)); | |
4337 SSLSocketDataProvider ssl_bad(ASYNC, ERR_CERT_AUTHORITY_INVALID); | |
4338 SSLSocketDataProvider ssl(ASYNC, OK); | |
4339 | |
4340 session_deps.socket_factory.AddSocketDataProvider(&ssl_bad_certificate); | |
4341 session_deps.socket_factory.AddSocketDataProvider(&data); | |
4342 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_bad); | |
4343 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
4344 | |
4345 TestCompletionCallback callback; | |
4346 | |
4347 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
4348 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4349 | |
4350 rv = callback.WaitForResult(); | |
4351 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv); | |
4352 | |
4353 rv = trans->RestartIgnoringLastError(callback.callback()); | |
4354 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4355 | |
4356 rv = callback.WaitForResult(); | |
4357 EXPECT_EQ(OK, rv); | |
4358 | |
4359 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4360 | |
4361 ASSERT_TRUE(response != NULL); | |
4362 EXPECT_EQ(100, response->headers->GetContentLength()); | |
4363 } | |
4364 | |
4365 // Test HTTPS connections to a site with a bad certificate, going through a | |
4366 // proxy | |
4367 TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificateViaProxy) { | |
4368 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
4369 | |
4370 HttpRequestInfo request; | |
4371 request.method = "GET"; | |
4372 request.url = GURL("https://www.google.com/"); | |
4373 request.load_flags = 0; | |
4374 | |
4375 MockWrite proxy_writes[] = { | |
4376 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
4377 "Host: www.google.com\r\n" | |
4378 "Proxy-Connection: keep-alive\r\n\r\n"), | |
4379 }; | |
4380 | |
4381 MockRead proxy_reads[] = { | |
4382 MockRead("HTTP/1.0 200 Connected\r\n\r\n"), | |
4383 MockRead(SYNCHRONOUS, OK) | |
4384 }; | |
4385 | |
4386 MockWrite data_writes[] = { | |
4387 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
4388 "Host: www.google.com\r\n" | |
4389 "Proxy-Connection: keep-alive\r\n\r\n"), | |
4390 MockWrite("GET / HTTP/1.1\r\n" | |
4391 "Host: www.google.com\r\n" | |
4392 "Connection: keep-alive\r\n\r\n"), | |
4393 }; | |
4394 | |
4395 MockRead data_reads[] = { | |
4396 MockRead("HTTP/1.0 200 Connected\r\n\r\n"), | |
4397 MockRead("HTTP/1.0 200 OK\r\n"), | |
4398 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
4399 MockRead("Content-Length: 100\r\n\r\n"), | |
4400 MockRead(SYNCHRONOUS, OK), | |
4401 }; | |
4402 | |
4403 StaticSocketDataProvider ssl_bad_certificate( | |
4404 proxy_reads, arraysize(proxy_reads), | |
4405 proxy_writes, arraysize(proxy_writes)); | |
4406 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
4407 data_writes, arraysize(data_writes)); | |
4408 SSLSocketDataProvider ssl_bad(ASYNC, ERR_CERT_AUTHORITY_INVALID); | |
4409 SSLSocketDataProvider ssl(ASYNC, OK); | |
4410 | |
4411 session_deps.socket_factory.AddSocketDataProvider(&ssl_bad_certificate); | |
4412 session_deps.socket_factory.AddSocketDataProvider(&data); | |
4413 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_bad); | |
4414 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
4415 | |
4416 TestCompletionCallback callback; | |
4417 | |
4418 for (int i = 0; i < 2; i++) { | |
4419 session_deps.socket_factory.ResetNextMockIndexes(); | |
4420 | |
4421 scoped_ptr<HttpTransaction> trans( | |
4422 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
4423 | |
4424 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
4425 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4426 | |
4427 rv = callback.WaitForResult(); | |
4428 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv); | |
4429 | |
4430 rv = trans->RestartIgnoringLastError(callback.callback()); | |
4431 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4432 | |
4433 rv = callback.WaitForResult(); | |
4434 EXPECT_EQ(OK, rv); | |
4435 | |
4436 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4437 | |
4438 ASSERT_TRUE(response != NULL); | |
4439 EXPECT_EQ(100, response->headers->GetContentLength()); | |
4440 } | |
4441 } | |
4442 | |
4443 | |
4444 // Test HTTPS connections to a site, going through an HTTPS proxy | |
4445 TEST_F(HttpNetworkTransactionTest, HTTPSViaHttpsProxy) { | |
4446 SessionDependencies session_deps(ProxyService::CreateFixed( | |
4447 "https://proxy:70")); | |
4448 | |
4449 HttpRequestInfo request; | |
4450 request.method = "GET"; | |
4451 request.url = GURL("https://www.google.com/"); | |
4452 request.load_flags = 0; | |
4453 | |
4454 MockWrite data_writes[] = { | |
4455 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
4456 "Host: www.google.com\r\n" | |
4457 "Proxy-Connection: keep-alive\r\n\r\n"), | |
4458 MockWrite("GET / HTTP/1.1\r\n" | |
4459 "Host: www.google.com\r\n" | |
4460 "Connection: keep-alive\r\n\r\n"), | |
4461 }; | |
4462 | |
4463 MockRead data_reads[] = { | |
4464 MockRead("HTTP/1.0 200 Connected\r\n\r\n"), | |
4465 MockRead("HTTP/1.1 200 OK\r\n"), | |
4466 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
4467 MockRead("Content-Length: 100\r\n\r\n"), | |
4468 MockRead(SYNCHRONOUS, OK), | |
4469 }; | |
4470 | |
4471 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
4472 data_writes, arraysize(data_writes)); | |
4473 SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy | |
4474 SSLSocketDataProvider tunnel_ssl(ASYNC, OK); // SSL through the tunnel | |
4475 | |
4476 session_deps.socket_factory.AddSocketDataProvider(&data); | |
4477 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl); | |
4478 session_deps.socket_factory.AddSSLSocketDataProvider(&tunnel_ssl); | |
4479 | |
4480 TestCompletionCallback callback; | |
4481 | |
4482 scoped_ptr<HttpTransaction> trans( | |
4483 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
4484 | |
4485 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
4486 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4487 | |
4488 rv = callback.WaitForResult(); | |
4489 EXPECT_EQ(OK, rv); | |
4490 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4491 | |
4492 ASSERT_TRUE(response != NULL); | |
4493 | |
4494 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
4495 EXPECT_EQ(200, response->headers->response_code()); | |
4496 EXPECT_EQ(100, response->headers->GetContentLength()); | |
4497 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
4498 } | |
4499 | |
4500 // Test an HTTPS Proxy's ability to redirect a CONNECT request | |
4501 TEST_F(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaHttpsProxy) { | |
4502 SessionDependencies session_deps( | |
4503 ProxyService::CreateFixed("https://proxy:70")); | |
4504 | |
4505 HttpRequestInfo request; | |
4506 request.method = "GET"; | |
4507 request.url = GURL("https://www.google.com/"); | |
4508 request.load_flags = 0; | |
4509 | |
4510 MockWrite data_writes[] = { | |
4511 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
4512 "Host: www.google.com\r\n" | |
4513 "Proxy-Connection: keep-alive\r\n\r\n"), | |
4514 }; | |
4515 | |
4516 MockRead data_reads[] = { | |
4517 MockRead("HTTP/1.1 302 Redirect\r\n"), | |
4518 MockRead("Location: http://login.example.com/\r\n"), | |
4519 MockRead("Content-Length: 0\r\n\r\n"), | |
4520 MockRead(SYNCHRONOUS, OK), | |
4521 }; | |
4522 | |
4523 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
4524 data_writes, arraysize(data_writes)); | |
4525 SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy | |
4526 | |
4527 session_deps.socket_factory.AddSocketDataProvider(&data); | |
4528 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl); | |
4529 | |
4530 TestCompletionCallback callback; | |
4531 | |
4532 scoped_ptr<HttpTransaction> trans( | |
4533 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
4534 | |
4535 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
4536 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4537 | |
4538 rv = callback.WaitForResult(); | |
4539 EXPECT_EQ(OK, rv); | |
4540 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4541 | |
4542 ASSERT_TRUE(response != NULL); | |
4543 | |
4544 EXPECT_EQ(302, response->headers->response_code()); | |
4545 std::string url; | |
4546 EXPECT_TRUE(response->headers->IsRedirect(&url)); | |
4547 EXPECT_EQ("http://login.example.com/", url); | |
4548 } | |
4549 | |
4550 // Test an HTTPS (SPDY) Proxy's ability to redirect a CONNECT request | |
4551 TEST_F(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaSpdyProxy) { | |
4552 SessionDependencies session_deps( | |
4553 ProxyService::CreateFixed("https://proxy:70")); | |
4554 | |
4555 HttpRequestInfo request; | |
4556 request.method = "GET"; | |
4557 request.url = GURL("https://www.google.com/"); | |
4558 request.load_flags = 0; | |
4559 | |
4560 scoped_ptr<spdy::SpdyFrame> conn(ConstructSpdyConnect(NULL, 0, 1)); | |
4561 scoped_ptr<spdy::SpdyFrame> goaway(ConstructSpdyRstStream(1, spdy::CANCEL)); | |
4562 MockWrite data_writes[] = { | |
4563 CreateMockWrite(*conn.get(), 0, SYNCHRONOUS), | |
4564 }; | |
4565 | |
4566 static const char* const kExtraHeaders[] = { | |
4567 "location", | |
4568 "http://login.example.com/", | |
4569 }; | |
4570 scoped_ptr<spdy::SpdyFrame> resp( | |
4571 ConstructSpdySynReplyError("302 Redirect", kExtraHeaders, | |
4572 arraysize(kExtraHeaders)/2, 1)); | |
4573 MockRead data_reads[] = { | |
4574 CreateMockRead(*resp.get(), 1, SYNCHRONOUS), | |
4575 MockRead(ASYNC, 0, 2), // EOF | |
4576 }; | |
4577 | |
4578 scoped_ptr<DelayedSocketData> data( | |
4579 new DelayedSocketData( | |
4580 1, // wait for one write to finish before reading. | |
4581 data_reads, arraysize(data_reads), | |
4582 data_writes, arraysize(data_writes))); | |
4583 SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy | |
4584 proxy_ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
4585 | |
4586 session_deps.socket_factory.AddSocketDataProvider(data.get()); | |
4587 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl); | |
4588 | |
4589 TestCompletionCallback callback; | |
4590 | |
4591 scoped_ptr<HttpTransaction> trans( | |
4592 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
4593 | |
4594 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
4595 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4596 | |
4597 rv = callback.WaitForResult(); | |
4598 EXPECT_EQ(OK, rv); | |
4599 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4600 | |
4601 ASSERT_TRUE(response != NULL); | |
4602 | |
4603 EXPECT_EQ(302, response->headers->response_code()); | |
4604 std::string url; | |
4605 EXPECT_TRUE(response->headers->IsRedirect(&url)); | |
4606 EXPECT_EQ("http://login.example.com/", url); | |
4607 } | |
4608 | |
4609 // Test an HTTPS Proxy's ability to provide a response to a CONNECT request | |
4610 TEST_F(HttpNetworkTransactionTest, ErrorResponseTofHttpsConnectViaHttpsProxy) { | |
4611 SessionDependencies session_deps( | |
4612 ProxyService::CreateFixed("https://proxy:70")); | |
4613 | |
4614 HttpRequestInfo request; | |
4615 request.method = "GET"; | |
4616 request.url = GURL("https://www.google.com/"); | |
4617 request.load_flags = 0; | |
4618 | |
4619 MockWrite data_writes[] = { | |
4620 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
4621 "Host: www.google.com\r\n" | |
4622 "Proxy-Connection: keep-alive\r\n\r\n"), | |
4623 }; | |
4624 | |
4625 MockRead data_reads[] = { | |
4626 MockRead("HTTP/1.1 404 Not Found\r\n"), | |
4627 MockRead("Content-Length: 23\r\n\r\n"), | |
4628 MockRead("The host does not exist"), | |
4629 MockRead(SYNCHRONOUS, OK), | |
4630 }; | |
4631 | |
4632 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
4633 data_writes, arraysize(data_writes)); | |
4634 SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy | |
4635 | |
4636 session_deps.socket_factory.AddSocketDataProvider(&data); | |
4637 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl); | |
4638 | |
4639 TestCompletionCallback callback; | |
4640 | |
4641 scoped_ptr<HttpTransaction> trans( | |
4642 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
4643 | |
4644 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
4645 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4646 | |
4647 rv = callback.WaitForResult(); | |
4648 EXPECT_EQ(OK, rv); | |
4649 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4650 | |
4651 ASSERT_TRUE(response != NULL); | |
4652 | |
4653 EXPECT_EQ(404, response->headers->response_code()); | |
4654 EXPECT_EQ(23, response->headers->GetContentLength()); | |
4655 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
4656 EXPECT_FALSE(response->ssl_info.is_valid()); | |
4657 | |
4658 std::string response_data; | |
4659 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
4660 EXPECT_EQ("The host does not exist", response_data); | |
4661 } | |
4662 | |
4663 // Test an HTTPS (SPDY) Proxy's ability to provide a response to a CONNECT | |
4664 // request | |
4665 TEST_F(HttpNetworkTransactionTest, ErrorResponseTofHttpsConnectViaSpdyProxy) { | |
4666 SessionDependencies session_deps( | |
4667 ProxyService::CreateFixed("https://proxy:70")); | |
4668 | |
4669 HttpRequestInfo request; | |
4670 request.method = "GET"; | |
4671 request.url = GURL("https://www.google.com/"); | |
4672 request.load_flags = 0; | |
4673 | |
4674 scoped_ptr<spdy::SpdyFrame> conn(ConstructSpdyConnect(NULL, 0, 1)); | |
4675 scoped_ptr<spdy::SpdyFrame> goaway(ConstructSpdyRstStream(1, spdy::CANCEL)); | |
4676 MockWrite data_writes[] = { | |
4677 CreateMockWrite(*conn.get(), 0, SYNCHRONOUS), | |
4678 }; | |
4679 | |
4680 static const char* const kExtraHeaders[] = { | |
4681 "location", | |
4682 "http://login.example.com/", | |
4683 }; | |
4684 scoped_ptr<spdy::SpdyFrame> resp( | |
4685 ConstructSpdySynReplyError("404 Not Found", kExtraHeaders, | |
4686 arraysize(kExtraHeaders)/2, 1)); | |
4687 scoped_ptr<spdy::SpdyFrame> body( | |
4688 ConstructSpdyBodyFrame(1, "The host does not exist", 23, true)); | |
4689 MockRead data_reads[] = { | |
4690 CreateMockRead(*resp.get(), 1, SYNCHRONOUS), | |
4691 CreateMockRead(*body.get(), 2, SYNCHRONOUS), | |
4692 MockRead(ASYNC, 0, 3), // EOF | |
4693 }; | |
4694 | |
4695 scoped_ptr<DelayedSocketData> data( | |
4696 new DelayedSocketData( | |
4697 1, // wait for one write to finish before reading. | |
4698 data_reads, arraysize(data_reads), | |
4699 data_writes, arraysize(data_writes))); | |
4700 SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy | |
4701 proxy_ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
4702 | |
4703 session_deps.socket_factory.AddSocketDataProvider(data.get()); | |
4704 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl); | |
4705 | |
4706 TestCompletionCallback callback; | |
4707 | |
4708 scoped_ptr<HttpTransaction> trans( | |
4709 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
4710 | |
4711 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
4712 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4713 | |
4714 rv = callback.WaitForResult(); | |
4715 EXPECT_EQ(OK, rv); | |
4716 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4717 | |
4718 ASSERT_TRUE(response != NULL); | |
4719 | |
4720 EXPECT_EQ(404, response->headers->response_code()); | |
4721 EXPECT_FALSE(response->ssl_info.is_valid()); | |
4722 | |
4723 std::string response_data; | |
4724 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
4725 EXPECT_EQ("The host does not exist", response_data); | |
4726 } | |
4727 | |
4728 // Test the request-challenge-retry sequence for basic auth, through | |
4729 // a SPDY proxy over a single SPDY session. | |
4730 TEST_F(HttpNetworkTransactionTest, BasicAuthSpdyProxy) { | |
4731 HttpRequestInfo request; | |
4732 request.method = "GET"; | |
4733 request.url = GURL("https://www.google.com/"); | |
4734 // when the no authentication data flag is set. | |
4735 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; | |
4736 | |
4737 // Configure against https proxy server "myproxy:70". | |
4738 SessionDependencies session_deps( | |
4739 ProxyService::CreateFixed("https://myproxy:70")); | |
4740 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
4741 session_deps.net_log = log.bound().net_log(); | |
4742 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
4743 | |
4744 // Since we have proxy, should try to establish tunnel. | |
4745 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyConnect(NULL, 0, 1)); | |
4746 scoped_ptr<spdy::SpdyFrame> rst(ConstructSpdyRstStream(1, spdy::CANCEL)); | |
4747 | |
4748 // After calling trans->RestartWithAuth(), this is the request we should | |
4749 // be issuing -- the final header line contains the credentials. | |
4750 const char* const kAuthCredentials[] = { | |
4751 "proxy-authorization", "Basic Zm9vOmJhcg==", | |
4752 }; | |
4753 scoped_ptr<spdy::SpdyFrame> connect2( | |
4754 ConstructSpdyConnect(kAuthCredentials, arraysize(kAuthCredentials)/2, 3)); | |
4755 // fetch https://www.google.com/ via HTTP | |
4756 const char get[] = "GET / HTTP/1.1\r\n" | |
4757 "Host: www.google.com\r\n" | |
4758 "Connection: keep-alive\r\n\r\n"; | |
4759 scoped_ptr<spdy::SpdyFrame> wrapped_get( | |
4760 ConstructSpdyBodyFrame(3, get, strlen(get), false)); | |
4761 | |
4762 MockWrite spdy_writes[] = { | |
4763 CreateMockWrite(*req, 0, ASYNC), | |
4764 CreateMockWrite(*rst, 2, ASYNC), | |
4765 CreateMockWrite(*connect2, 3), | |
4766 CreateMockWrite(*wrapped_get, 5) | |
4767 }; | |
4768 | |
4769 // The proxy responds to the connect with a 407, using a persistent | |
4770 // connection. | |
4771 const char* const kAuthChallenge[] = { | |
4772 "status", "407 Proxy Authentication Required", | |
4773 "version", "HTTP/1.1", | |
4774 "proxy-authenticate", "Basic realm=\"MyRealm1\"", | |
4775 }; | |
4776 | |
4777 scoped_ptr<spdy::SpdyFrame> conn_auth_resp( | |
4778 ConstructSpdyControlFrame(NULL, | |
4779 0, | |
4780 false, | |
4781 1, | |
4782 LOWEST, | |
4783 spdy::SYN_REPLY, | |
4784 spdy::CONTROL_FLAG_NONE, | |
4785 kAuthChallenge, | |
4786 arraysize(kAuthChallenge))); | |
4787 | |
4788 scoped_ptr<spdy::SpdyFrame> conn_resp(ConstructSpdyGetSynReply(NULL, 0, 3)); | |
4789 const char resp[] = "HTTP/1.1 200 OK\r\n" | |
4790 "Content-Length: 5\r\n\r\n"; | |
4791 | |
4792 scoped_ptr<spdy::SpdyFrame> wrapped_get_resp( | |
4793 ConstructSpdyBodyFrame(3, resp, strlen(resp), false)); | |
4794 scoped_ptr<spdy::SpdyFrame> wrapped_body( | |
4795 ConstructSpdyBodyFrame(3, "hello", 5, false)); | |
4796 MockRead spdy_reads[] = { | |
4797 CreateMockRead(*conn_auth_resp, 1, ASYNC), | |
4798 CreateMockRead(*conn_resp, 4, ASYNC), | |
4799 CreateMockRead(*wrapped_get_resp, 5, ASYNC), | |
4800 CreateMockRead(*wrapped_body, 6, ASYNC), | |
4801 MockRead(SYNCHRONOUS, ERR_IO_PENDING), | |
4802 }; | |
4803 | |
4804 scoped_ptr<OrderedSocketData> spdy_data( | |
4805 new OrderedSocketData( | |
4806 spdy_reads, arraysize(spdy_reads), | |
4807 spdy_writes, arraysize(spdy_writes))); | |
4808 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
4809 // Negotiate SPDY to the proxy | |
4810 SSLSocketDataProvider proxy(ASYNC, OK); | |
4811 proxy.SetNextProto(SSLClientSocket::kProtoSPDY2); | |
4812 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy); | |
4813 // Vanilla SSL to the server | |
4814 SSLSocketDataProvider server(ASYNC, OK); | |
4815 session_deps.socket_factory.AddSSLSocketDataProvider(&server); | |
4816 | |
4817 TestCompletionCallback callback1; | |
4818 | |
4819 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
4820 | |
4821 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
4822 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4823 | |
4824 rv = callback1.WaitForResult(); | |
4825 EXPECT_EQ(OK, rv); | |
4826 net::CapturingNetLog::EntryList entries; | |
4827 log.GetEntries(&entries); | |
4828 size_t pos = ExpectLogContainsSomewhere( | |
4829 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
4830 NetLog::PHASE_NONE); | |
4831 ExpectLogContainsSomewhere( | |
4832 entries, pos, | |
4833 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
4834 NetLog::PHASE_NONE); | |
4835 | |
4836 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4837 ASSERT_TRUE(response != NULL); | |
4838 ASSERT_FALSE(response->headers == NULL); | |
4839 EXPECT_EQ(407, response->headers->response_code()); | |
4840 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
4841 EXPECT_TRUE(response->auth_challenge.get() != NULL); | |
4842 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
4843 | |
4844 TestCompletionCallback callback2; | |
4845 | |
4846 rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar), | |
4847 callback2.callback()); | |
4848 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4849 | |
4850 rv = callback2.WaitForResult(); | |
4851 EXPECT_EQ(OK, rv); | |
4852 | |
4853 response = trans->GetResponseInfo(); | |
4854 ASSERT_TRUE(response != NULL); | |
4855 | |
4856 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
4857 EXPECT_EQ(200, response->headers->response_code()); | |
4858 EXPECT_EQ(5, response->headers->GetContentLength()); | |
4859 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
4860 | |
4861 // The password prompt info should not be set. | |
4862 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
4863 | |
4864 trans.reset(); | |
4865 session->CloseAllConnections(); | |
4866 } | |
4867 | |
4868 // Test HTTPS connections to a site with a bad certificate, going through an | |
4869 // HTTPS proxy | |
4870 TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificateViaHttpsProxy) { | |
4871 SessionDependencies session_deps(ProxyService::CreateFixed( | |
4872 "https://proxy:70")); | |
4873 | |
4874 HttpRequestInfo request; | |
4875 request.method = "GET"; | |
4876 request.url = GURL("https://www.google.com/"); | |
4877 request.load_flags = 0; | |
4878 | |
4879 // Attempt to fetch the URL from a server with a bad cert | |
4880 MockWrite bad_cert_writes[] = { | |
4881 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
4882 "Host: www.google.com\r\n" | |
4883 "Proxy-Connection: keep-alive\r\n\r\n"), | |
4884 }; | |
4885 | |
4886 MockRead bad_cert_reads[] = { | |
4887 MockRead("HTTP/1.0 200 Connected\r\n\r\n"), | |
4888 MockRead(SYNCHRONOUS, OK) | |
4889 }; | |
4890 | |
4891 // Attempt to fetch the URL with a good cert | |
4892 MockWrite good_data_writes[] = { | |
4893 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
4894 "Host: www.google.com\r\n" | |
4895 "Proxy-Connection: keep-alive\r\n\r\n"), | |
4896 MockWrite("GET / HTTP/1.1\r\n" | |
4897 "Host: www.google.com\r\n" | |
4898 "Connection: keep-alive\r\n\r\n"), | |
4899 }; | |
4900 | |
4901 MockRead good_cert_reads[] = { | |
4902 MockRead("HTTP/1.0 200 Connected\r\n\r\n"), | |
4903 MockRead("HTTP/1.0 200 OK\r\n"), | |
4904 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
4905 MockRead("Content-Length: 100\r\n\r\n"), | |
4906 MockRead(SYNCHRONOUS, OK), | |
4907 }; | |
4908 | |
4909 StaticSocketDataProvider ssl_bad_certificate( | |
4910 bad_cert_reads, arraysize(bad_cert_reads), | |
4911 bad_cert_writes, arraysize(bad_cert_writes)); | |
4912 StaticSocketDataProvider data(good_cert_reads, arraysize(good_cert_reads), | |
4913 good_data_writes, arraysize(good_data_writes)); | |
4914 SSLSocketDataProvider ssl_bad(ASYNC, ERR_CERT_AUTHORITY_INVALID); | |
4915 SSLSocketDataProvider ssl(ASYNC, OK); | |
4916 | |
4917 // SSL to the proxy, then CONNECT request, then SSL with bad certificate | |
4918 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
4919 session_deps.socket_factory.AddSocketDataProvider(&ssl_bad_certificate); | |
4920 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_bad); | |
4921 | |
4922 // SSL to the proxy, then CONNECT request, then valid SSL certificate | |
4923 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
4924 session_deps.socket_factory.AddSocketDataProvider(&data); | |
4925 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
4926 | |
4927 TestCompletionCallback callback; | |
4928 | |
4929 scoped_ptr<HttpTransaction> trans( | |
4930 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
4931 | |
4932 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
4933 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4934 | |
4935 rv = callback.WaitForResult(); | |
4936 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv); | |
4937 | |
4938 rv = trans->RestartIgnoringLastError(callback.callback()); | |
4939 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4940 | |
4941 rv = callback.WaitForResult(); | |
4942 EXPECT_EQ(OK, rv); | |
4943 | |
4944 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4945 | |
4946 ASSERT_TRUE(response != NULL); | |
4947 EXPECT_EQ(100, response->headers->GetContentLength()); | |
4948 } | |
4949 | |
4950 TEST_F(HttpNetworkTransactionTest, BuildRequest_UserAgent) { | |
4951 HttpRequestInfo request; | |
4952 request.method = "GET"; | |
4953 request.url = GURL("http://www.google.com/"); | |
4954 request.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, | |
4955 "Chromium Ultra Awesome X Edition"); | |
4956 | |
4957 SessionDependencies session_deps; | |
4958 scoped_ptr<HttpTransaction> trans( | |
4959 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
4960 | |
4961 MockWrite data_writes[] = { | |
4962 MockWrite("GET / HTTP/1.1\r\n" | |
4963 "Host: www.google.com\r\n" | |
4964 "Connection: keep-alive\r\n" | |
4965 "User-Agent: Chromium Ultra Awesome X Edition\r\n\r\n"), | |
4966 }; | |
4967 | |
4968 // Lastly, the server responds with the actual content. | |
4969 MockRead data_reads[] = { | |
4970 MockRead("HTTP/1.0 200 OK\r\n"), | |
4971 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
4972 MockRead("Content-Length: 100\r\n\r\n"), | |
4973 MockRead(SYNCHRONOUS, OK), | |
4974 }; | |
4975 | |
4976 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
4977 data_writes, arraysize(data_writes)); | |
4978 session_deps.socket_factory.AddSocketDataProvider(&data); | |
4979 | |
4980 TestCompletionCallback callback; | |
4981 | |
4982 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
4983 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4984 | |
4985 rv = callback.WaitForResult(); | |
4986 EXPECT_EQ(OK, rv); | |
4987 } | |
4988 | |
4989 TEST_F(HttpNetworkTransactionTest, BuildRequest_UserAgentOverTunnel) { | |
4990 HttpRequestInfo request; | |
4991 request.method = "GET"; | |
4992 request.url = GURL("https://www.google.com/"); | |
4993 request.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, | |
4994 "Chromium Ultra Awesome X Edition"); | |
4995 | |
4996 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
4997 scoped_ptr<HttpTransaction> trans( | |
4998 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
4999 | |
5000 MockWrite data_writes[] = { | |
5001 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
5002 "Host: www.google.com\r\n" | |
5003 "Proxy-Connection: keep-alive\r\n" | |
5004 "User-Agent: Chromium Ultra Awesome X Edition\r\n\r\n"), | |
5005 }; | |
5006 MockRead data_reads[] = { | |
5007 // Return an error, so the transaction stops here (this test isn't | |
5008 // interested in the rest). | |
5009 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
5010 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
5011 MockRead("Proxy-Connection: close\r\n\r\n"), | |
5012 }; | |
5013 | |
5014 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
5015 data_writes, arraysize(data_writes)); | |
5016 session_deps.socket_factory.AddSocketDataProvider(&data); | |
5017 | |
5018 TestCompletionCallback callback; | |
5019 | |
5020 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
5021 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5022 | |
5023 rv = callback.WaitForResult(); | |
5024 EXPECT_EQ(OK, rv); | |
5025 } | |
5026 | |
5027 TEST_F(HttpNetworkTransactionTest, BuildRequest_Referer) { | |
5028 HttpRequestInfo request; | |
5029 request.method = "GET"; | |
5030 request.url = GURL("http://www.google.com/"); | |
5031 request.load_flags = 0; | |
5032 request.extra_headers.SetHeader(HttpRequestHeaders::kReferer, | |
5033 "http://the.previous.site.com/"); | |
5034 | |
5035 SessionDependencies session_deps; | |
5036 scoped_ptr<HttpTransaction> trans( | |
5037 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
5038 | |
5039 MockWrite data_writes[] = { | |
5040 MockWrite("GET / HTTP/1.1\r\n" | |
5041 "Host: www.google.com\r\n" | |
5042 "Connection: keep-alive\r\n" | |
5043 "Referer: http://the.previous.site.com/\r\n\r\n"), | |
5044 }; | |
5045 | |
5046 // Lastly, the server responds with the actual content. | |
5047 MockRead data_reads[] = { | |
5048 MockRead("HTTP/1.0 200 OK\r\n"), | |
5049 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
5050 MockRead("Content-Length: 100\r\n\r\n"), | |
5051 MockRead(SYNCHRONOUS, OK), | |
5052 }; | |
5053 | |
5054 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
5055 data_writes, arraysize(data_writes)); | |
5056 session_deps.socket_factory.AddSocketDataProvider(&data); | |
5057 | |
5058 TestCompletionCallback callback; | |
5059 | |
5060 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
5061 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5062 | |
5063 rv = callback.WaitForResult(); | |
5064 EXPECT_EQ(OK, rv); | |
5065 } | |
5066 | |
5067 TEST_F(HttpNetworkTransactionTest, BuildRequest_PostContentLengthZero) { | |
5068 HttpRequestInfo request; | |
5069 request.method = "POST"; | |
5070 request.url = GURL("http://www.google.com/"); | |
5071 | |
5072 SessionDependencies session_deps; | |
5073 scoped_ptr<HttpTransaction> trans( | |
5074 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
5075 | |
5076 MockWrite data_writes[] = { | |
5077 MockWrite("POST / HTTP/1.1\r\n" | |
5078 "Host: www.google.com\r\n" | |
5079 "Connection: keep-alive\r\n" | |
5080 "Content-Length: 0\r\n\r\n"), | |
5081 }; | |
5082 | |
5083 // Lastly, the server responds with the actual content. | |
5084 MockRead data_reads[] = { | |
5085 MockRead("HTTP/1.0 200 OK\r\n"), | |
5086 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
5087 MockRead("Content-Length: 100\r\n\r\n"), | |
5088 MockRead(SYNCHRONOUS, OK), | |
5089 }; | |
5090 | |
5091 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
5092 data_writes, arraysize(data_writes)); | |
5093 session_deps.socket_factory.AddSocketDataProvider(&data); | |
5094 | |
5095 TestCompletionCallback callback; | |
5096 | |
5097 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
5098 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5099 | |
5100 rv = callback.WaitForResult(); | |
5101 EXPECT_EQ(OK, rv); | |
5102 } | |
5103 | |
5104 TEST_F(HttpNetworkTransactionTest, BuildRequest_PutContentLengthZero) { | |
5105 HttpRequestInfo request; | |
5106 request.method = "PUT"; | |
5107 request.url = GURL("http://www.google.com/"); | |
5108 | |
5109 SessionDependencies session_deps; | |
5110 scoped_ptr<HttpTransaction> trans( | |
5111 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
5112 | |
5113 MockWrite data_writes[] = { | |
5114 MockWrite("PUT / HTTP/1.1\r\n" | |
5115 "Host: www.google.com\r\n" | |
5116 "Connection: keep-alive\r\n" | |
5117 "Content-Length: 0\r\n\r\n"), | |
5118 }; | |
5119 | |
5120 // Lastly, the server responds with the actual content. | |
5121 MockRead data_reads[] = { | |
5122 MockRead("HTTP/1.0 200 OK\r\n"), | |
5123 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
5124 MockRead("Content-Length: 100\r\n\r\n"), | |
5125 MockRead(SYNCHRONOUS, OK), | |
5126 }; | |
5127 | |
5128 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
5129 data_writes, arraysize(data_writes)); | |
5130 session_deps.socket_factory.AddSocketDataProvider(&data); | |
5131 | |
5132 TestCompletionCallback callback; | |
5133 | |
5134 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
5135 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5136 | |
5137 rv = callback.WaitForResult(); | |
5138 EXPECT_EQ(OK, rv); | |
5139 } | |
5140 | |
5141 TEST_F(HttpNetworkTransactionTest, BuildRequest_HeadContentLengthZero) { | |
5142 HttpRequestInfo request; | |
5143 request.method = "HEAD"; | |
5144 request.url = GURL("http://www.google.com/"); | |
5145 | |
5146 SessionDependencies session_deps; | |
5147 scoped_ptr<HttpTransaction> trans( | |
5148 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
5149 | |
5150 MockWrite data_writes[] = { | |
5151 MockWrite("HEAD / HTTP/1.1\r\n" | |
5152 "Host: www.google.com\r\n" | |
5153 "Connection: keep-alive\r\n" | |
5154 "Content-Length: 0\r\n\r\n"), | |
5155 }; | |
5156 | |
5157 // Lastly, the server responds with the actual content. | |
5158 MockRead data_reads[] = { | |
5159 MockRead("HTTP/1.0 200 OK\r\n"), | |
5160 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
5161 MockRead("Content-Length: 100\r\n\r\n"), | |
5162 MockRead(SYNCHRONOUS, OK), | |
5163 }; | |
5164 | |
5165 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
5166 data_writes, arraysize(data_writes)); | |
5167 session_deps.socket_factory.AddSocketDataProvider(&data); | |
5168 | |
5169 TestCompletionCallback callback; | |
5170 | |
5171 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
5172 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5173 | |
5174 rv = callback.WaitForResult(); | |
5175 EXPECT_EQ(OK, rv); | |
5176 } | |
5177 | |
5178 TEST_F(HttpNetworkTransactionTest, BuildRequest_CacheControlNoCache) { | |
5179 HttpRequestInfo request; | |
5180 request.method = "GET"; | |
5181 request.url = GURL("http://www.google.com/"); | |
5182 request.load_flags = LOAD_BYPASS_CACHE; | |
5183 | |
5184 SessionDependencies session_deps; | |
5185 scoped_ptr<HttpTransaction> trans( | |
5186 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
5187 | |
5188 MockWrite data_writes[] = { | |
5189 MockWrite("GET / HTTP/1.1\r\n" | |
5190 "Host: www.google.com\r\n" | |
5191 "Connection: keep-alive\r\n" | |
5192 "Pragma: no-cache\r\n" | |
5193 "Cache-Control: no-cache\r\n\r\n"), | |
5194 }; | |
5195 | |
5196 // Lastly, the server responds with the actual content. | |
5197 MockRead data_reads[] = { | |
5198 MockRead("HTTP/1.0 200 OK\r\n"), | |
5199 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
5200 MockRead("Content-Length: 100\r\n\r\n"), | |
5201 MockRead(SYNCHRONOUS, OK), | |
5202 }; | |
5203 | |
5204 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
5205 data_writes, arraysize(data_writes)); | |
5206 session_deps.socket_factory.AddSocketDataProvider(&data); | |
5207 | |
5208 TestCompletionCallback callback; | |
5209 | |
5210 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
5211 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5212 | |
5213 rv = callback.WaitForResult(); | |
5214 EXPECT_EQ(OK, rv); | |
5215 } | |
5216 | |
5217 TEST_F(HttpNetworkTransactionTest, | |
5218 BuildRequest_CacheControlValidateCache) { | |
5219 HttpRequestInfo request; | |
5220 request.method = "GET"; | |
5221 request.url = GURL("http://www.google.com/"); | |
5222 request.load_flags = LOAD_VALIDATE_CACHE; | |
5223 | |
5224 SessionDependencies session_deps; | |
5225 scoped_ptr<HttpTransaction> trans( | |
5226 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
5227 | |
5228 MockWrite data_writes[] = { | |
5229 MockWrite("GET / HTTP/1.1\r\n" | |
5230 "Host: www.google.com\r\n" | |
5231 "Connection: keep-alive\r\n" | |
5232 "Cache-Control: max-age=0\r\n\r\n"), | |
5233 }; | |
5234 | |
5235 // Lastly, the server responds with the actual content. | |
5236 MockRead data_reads[] = { | |
5237 MockRead("HTTP/1.0 200 OK\r\n"), | |
5238 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
5239 MockRead("Content-Length: 100\r\n\r\n"), | |
5240 MockRead(SYNCHRONOUS, OK), | |
5241 }; | |
5242 | |
5243 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
5244 data_writes, arraysize(data_writes)); | |
5245 session_deps.socket_factory.AddSocketDataProvider(&data); | |
5246 | |
5247 TestCompletionCallback callback; | |
5248 | |
5249 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
5250 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5251 | |
5252 rv = callback.WaitForResult(); | |
5253 EXPECT_EQ(OK, rv); | |
5254 } | |
5255 | |
5256 TEST_F(HttpNetworkTransactionTest, BuildRequest_ExtraHeaders) { | |
5257 HttpRequestInfo request; | |
5258 request.method = "GET"; | |
5259 request.url = GURL("http://www.google.com/"); | |
5260 request.extra_headers.SetHeader("FooHeader", "Bar"); | |
5261 | |
5262 SessionDependencies session_deps; | |
5263 scoped_ptr<HttpTransaction> trans( | |
5264 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
5265 | |
5266 MockWrite data_writes[] = { | |
5267 MockWrite("GET / HTTP/1.1\r\n" | |
5268 "Host: www.google.com\r\n" | |
5269 "Connection: keep-alive\r\n" | |
5270 "FooHeader: Bar\r\n\r\n"), | |
5271 }; | |
5272 | |
5273 // Lastly, the server responds with the actual content. | |
5274 MockRead data_reads[] = { | |
5275 MockRead("HTTP/1.0 200 OK\r\n"), | |
5276 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
5277 MockRead("Content-Length: 100\r\n\r\n"), | |
5278 MockRead(SYNCHRONOUS, OK), | |
5279 }; | |
5280 | |
5281 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
5282 data_writes, arraysize(data_writes)); | |
5283 session_deps.socket_factory.AddSocketDataProvider(&data); | |
5284 | |
5285 TestCompletionCallback callback; | |
5286 | |
5287 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
5288 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5289 | |
5290 rv = callback.WaitForResult(); | |
5291 EXPECT_EQ(OK, rv); | |
5292 } | |
5293 | |
5294 TEST_F(HttpNetworkTransactionTest, BuildRequest_ExtraHeadersStripped) { | |
5295 HttpRequestInfo request; | |
5296 request.method = "GET"; | |
5297 request.url = GURL("http://www.google.com/"); | |
5298 request.extra_headers.SetHeader("referer", "www.foo.com"); | |
5299 request.extra_headers.SetHeader("hEllo", "Kitty"); | |
5300 request.extra_headers.SetHeader("FoO", "bar"); | |
5301 | |
5302 SessionDependencies session_deps; | |
5303 scoped_ptr<HttpTransaction> trans( | |
5304 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
5305 | |
5306 MockWrite data_writes[] = { | |
5307 MockWrite("GET / HTTP/1.1\r\n" | |
5308 "Host: www.google.com\r\n" | |
5309 "Connection: keep-alive\r\n" | |
5310 "referer: www.foo.com\r\n" | |
5311 "hEllo: Kitty\r\n" | |
5312 "FoO: bar\r\n\r\n"), | |
5313 }; | |
5314 | |
5315 // Lastly, the server responds with the actual content. | |
5316 MockRead data_reads[] = { | |
5317 MockRead("HTTP/1.0 200 OK\r\n"), | |
5318 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
5319 MockRead("Content-Length: 100\r\n\r\n"), | |
5320 MockRead(SYNCHRONOUS, OK), | |
5321 }; | |
5322 | |
5323 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
5324 data_writes, arraysize(data_writes)); | |
5325 session_deps.socket_factory.AddSocketDataProvider(&data); | |
5326 | |
5327 TestCompletionCallback callback; | |
5328 | |
5329 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
5330 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5331 | |
5332 rv = callback.WaitForResult(); | |
5333 EXPECT_EQ(OK, rv); | |
5334 } | |
5335 | |
5336 // http://crbug.com/112682 | |
5337 #if defined(OS_MACOSX) | |
5338 #define MAYBE_SOCKS4_HTTP_GET DISABLED_SOCKS4_HTTP_GET | |
5339 #else | |
5340 #define MAYBE_SOCKS4_HTTP_GET SOCKS4_HTTP_GET | |
5341 #endif | |
5342 | |
5343 TEST_F(HttpNetworkTransactionTest, MAYBE_SOCKS4_HTTP_GET) { | |
5344 HttpRequestInfo request; | |
5345 request.method = "GET"; | |
5346 request.url = GURL("http://www.google.com/"); | |
5347 request.load_flags = 0; | |
5348 | |
5349 SessionDependencies session_deps( | |
5350 ProxyService::CreateFixed("socks4://myproxy:1080")); | |
5351 | |
5352 scoped_ptr<HttpTransaction> trans( | |
5353 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
5354 | |
5355 char write_buffer[] = { 0x04, 0x01, 0x00, 0x50, 127, 0, 0, 1, 0 }; | |
5356 char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 }; | |
5357 | |
5358 MockWrite data_writes[] = { | |
5359 MockWrite(ASYNC, write_buffer, arraysize(write_buffer)), | |
5360 MockWrite("GET / HTTP/1.1\r\n" | |
5361 "Host: www.google.com\r\n" | |
5362 "Connection: keep-alive\r\n\r\n") | |
5363 }; | |
5364 | |
5365 MockRead data_reads[] = { | |
5366 MockRead(ASYNC, read_buffer, arraysize(read_buffer)), | |
5367 MockRead("HTTP/1.0 200 OK\r\n"), | |
5368 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), | |
5369 MockRead("Payload"), | |
5370 MockRead(SYNCHRONOUS, OK) | |
5371 }; | |
5372 | |
5373 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
5374 data_writes, arraysize(data_writes)); | |
5375 session_deps.socket_factory.AddSocketDataProvider(&data); | |
5376 | |
5377 TestCompletionCallback callback; | |
5378 | |
5379 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
5380 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5381 | |
5382 rv = callback.WaitForResult(); | |
5383 EXPECT_EQ(OK, rv); | |
5384 | |
5385 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
5386 ASSERT_TRUE(response != NULL); | |
5387 | |
5388 std::string response_text; | |
5389 rv = ReadTransaction(trans.get(), &response_text); | |
5390 EXPECT_EQ(OK, rv); | |
5391 EXPECT_EQ("Payload", response_text); | |
5392 } | |
5393 | |
5394 // http://crbug.com/112682 | |
5395 #if defined(OS_MACOSX) | |
5396 #define MAYBE_SOCKS4_SSL_GET DISABLED_SOCKS4_SSL_GET | |
5397 #else | |
5398 #define MAYBE_SOCKS4_SSL_GET SOCKS4_SSL_GET | |
5399 #endif | |
5400 | |
5401 TEST_F(HttpNetworkTransactionTest, MAYBE_SOCKS4_SSL_GET) { | |
5402 HttpRequestInfo request; | |
5403 request.method = "GET"; | |
5404 request.url = GURL("https://www.google.com/"); | |
5405 request.load_flags = 0; | |
5406 | |
5407 SessionDependencies session_deps( | |
5408 ProxyService::CreateFixed("socks4://myproxy:1080")); | |
5409 | |
5410 scoped_ptr<HttpTransaction> trans( | |
5411 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
5412 | |
5413 unsigned char write_buffer[] = { 0x04, 0x01, 0x01, 0xBB, 127, 0, 0, 1, 0 }; | |
5414 unsigned char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 }; | |
5415 | |
5416 MockWrite data_writes[] = { | |
5417 MockWrite(ASYNC, reinterpret_cast<char*>(write_buffer), | |
5418 arraysize(write_buffer)), | |
5419 MockWrite("GET / HTTP/1.1\r\n" | |
5420 "Host: www.google.com\r\n" | |
5421 "Connection: keep-alive\r\n\r\n") | |
5422 }; | |
5423 | |
5424 MockRead data_reads[] = { | |
5425 MockWrite(ASYNC, reinterpret_cast<char*>(read_buffer), | |
5426 arraysize(read_buffer)), | |
5427 MockRead("HTTP/1.0 200 OK\r\n"), | |
5428 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), | |
5429 MockRead("Payload"), | |
5430 MockRead(SYNCHRONOUS, OK) | |
5431 }; | |
5432 | |
5433 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
5434 data_writes, arraysize(data_writes)); | |
5435 session_deps.socket_factory.AddSocketDataProvider(&data); | |
5436 | |
5437 SSLSocketDataProvider ssl(ASYNC, OK); | |
5438 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
5439 | |
5440 TestCompletionCallback callback; | |
5441 | |
5442 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
5443 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5444 | |
5445 rv = callback.WaitForResult(); | |
5446 EXPECT_EQ(OK, rv); | |
5447 | |
5448 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
5449 ASSERT_TRUE(response != NULL); | |
5450 | |
5451 std::string response_text; | |
5452 rv = ReadTransaction(trans.get(), &response_text); | |
5453 EXPECT_EQ(OK, rv); | |
5454 EXPECT_EQ("Payload", response_text); | |
5455 } | |
5456 | |
5457 TEST_F(HttpNetworkTransactionTest, SOCKS5_HTTP_GET) { | |
5458 HttpRequestInfo request; | |
5459 request.method = "GET"; | |
5460 request.url = GURL("http://www.google.com/"); | |
5461 request.load_flags = 0; | |
5462 | |
5463 SessionDependencies session_deps( | |
5464 ProxyService::CreateFixed("socks5://myproxy:1080")); | |
5465 | |
5466 scoped_ptr<HttpTransaction> trans( | |
5467 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
5468 | |
5469 const char kSOCKS5GreetRequest[] = { 0x05, 0x01, 0x00 }; | |
5470 const char kSOCKS5GreetResponse[] = { 0x05, 0x00 }; | |
5471 const char kSOCKS5OkRequest[] = { | |
5472 0x05, // Version | |
5473 0x01, // Command (CONNECT) | |
5474 0x00, // Reserved. | |
5475 0x03, // Address type (DOMAINNAME). | |
5476 0x0E, // Length of domain (14) | |
5477 // Domain string: | |
5478 'w', 'w', 'w', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o', 'm', | |
5479 0x00, 0x50, // 16-bit port (80) | |
5480 }; | |
5481 const char kSOCKS5OkResponse[] = | |
5482 { 0x05, 0x00, 0x00, 0x01, 127, 0, 0, 1, 0x00, 0x50 }; | |
5483 | |
5484 MockWrite data_writes[] = { | |
5485 MockWrite(ASYNC, kSOCKS5GreetRequest, arraysize(kSOCKS5GreetRequest)), | |
5486 MockWrite(ASYNC, kSOCKS5OkRequest, arraysize(kSOCKS5OkRequest)), | |
5487 MockWrite("GET / HTTP/1.1\r\n" | |
5488 "Host: www.google.com\r\n" | |
5489 "Connection: keep-alive\r\n\r\n") | |
5490 }; | |
5491 | |
5492 MockRead data_reads[] = { | |
5493 MockWrite(ASYNC, kSOCKS5GreetResponse, arraysize(kSOCKS5GreetResponse)), | |
5494 MockWrite(ASYNC, kSOCKS5OkResponse, arraysize(kSOCKS5OkResponse)), | |
5495 MockRead("HTTP/1.0 200 OK\r\n"), | |
5496 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), | |
5497 MockRead("Payload"), | |
5498 MockRead(SYNCHRONOUS, OK) | |
5499 }; | |
5500 | |
5501 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
5502 data_writes, arraysize(data_writes)); | |
5503 session_deps.socket_factory.AddSocketDataProvider(&data); | |
5504 | |
5505 TestCompletionCallback callback; | |
5506 | |
5507 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
5508 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5509 | |
5510 rv = callback.WaitForResult(); | |
5511 EXPECT_EQ(OK, rv); | |
5512 | |
5513 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
5514 ASSERT_TRUE(response != NULL); | |
5515 | |
5516 std::string response_text; | |
5517 rv = ReadTransaction(trans.get(), &response_text); | |
5518 EXPECT_EQ(OK, rv); | |
5519 EXPECT_EQ("Payload", response_text); | |
5520 } | |
5521 | |
5522 TEST_F(HttpNetworkTransactionTest, SOCKS5_SSL_GET) { | |
5523 HttpRequestInfo request; | |
5524 request.method = "GET"; | |
5525 request.url = GURL("https://www.google.com/"); | |
5526 request.load_flags = 0; | |
5527 | |
5528 SessionDependencies session_deps( | |
5529 ProxyService::CreateFixed("socks5://myproxy:1080")); | |
5530 | |
5531 scoped_ptr<HttpTransaction> trans( | |
5532 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
5533 | |
5534 const char kSOCKS5GreetRequest[] = { 0x05, 0x01, 0x00 }; | |
5535 const char kSOCKS5GreetResponse[] = { 0x05, 0x00 }; | |
5536 const unsigned char kSOCKS5OkRequest[] = { | |
5537 0x05, // Version | |
5538 0x01, // Command (CONNECT) | |
5539 0x00, // Reserved. | |
5540 0x03, // Address type (DOMAINNAME). | |
5541 0x0E, // Length of domain (14) | |
5542 // Domain string: | |
5543 'w', 'w', 'w', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o', 'm', | |
5544 0x01, 0xBB, // 16-bit port (443) | |
5545 }; | |
5546 | |
5547 const char kSOCKS5OkResponse[] = | |
5548 { 0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0x00, 0x00 }; | |
5549 | |
5550 MockWrite data_writes[] = { | |
5551 MockWrite(ASYNC, kSOCKS5GreetRequest, arraysize(kSOCKS5GreetRequest)), | |
5552 MockWrite(ASYNC, reinterpret_cast<const char*>(kSOCKS5OkRequest), | |
5553 arraysize(kSOCKS5OkRequest)), | |
5554 MockWrite("GET / HTTP/1.1\r\n" | |
5555 "Host: www.google.com\r\n" | |
5556 "Connection: keep-alive\r\n\r\n") | |
5557 }; | |
5558 | |
5559 MockRead data_reads[] = { | |
5560 MockWrite(ASYNC, kSOCKS5GreetResponse, arraysize(kSOCKS5GreetResponse)), | |
5561 MockWrite(ASYNC, kSOCKS5OkResponse, arraysize(kSOCKS5OkResponse)), | |
5562 MockRead("HTTP/1.0 200 OK\r\n"), | |
5563 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), | |
5564 MockRead("Payload"), | |
5565 MockRead(SYNCHRONOUS, OK) | |
5566 }; | |
5567 | |
5568 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
5569 data_writes, arraysize(data_writes)); | |
5570 session_deps.socket_factory.AddSocketDataProvider(&data); | |
5571 | |
5572 SSLSocketDataProvider ssl(ASYNC, OK); | |
5573 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
5574 | |
5575 TestCompletionCallback callback; | |
5576 | |
5577 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
5578 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5579 | |
5580 rv = callback.WaitForResult(); | |
5581 EXPECT_EQ(OK, rv); | |
5582 | |
5583 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
5584 ASSERT_TRUE(response != NULL); | |
5585 | |
5586 std::string response_text; | |
5587 rv = ReadTransaction(trans.get(), &response_text); | |
5588 EXPECT_EQ(OK, rv); | |
5589 EXPECT_EQ("Payload", response_text); | |
5590 } | |
5591 | |
5592 // Tests that for connection endpoints the group names are correctly set. | |
5593 | |
5594 struct GroupNameTest { | |
5595 std::string proxy_server; | |
5596 std::string url; | |
5597 std::string expected_group_name; | |
5598 bool ssl; | |
5599 }; | |
5600 | |
5601 scoped_refptr<HttpNetworkSession> SetupSessionForGroupNameTests( | |
5602 SessionDependencies* session_deps) { | |
5603 scoped_refptr<HttpNetworkSession> session(CreateSession(session_deps)); | |
5604 | |
5605 HttpServerProperties* http_server_properties = | |
5606 session->http_server_properties(); | |
5607 http_server_properties->SetAlternateProtocol( | |
5608 HostPortPair("host.with.alternate", 80), 443, | |
5609 NPN_SPDY_21); | |
5610 | |
5611 return session; | |
5612 } | |
5613 | |
5614 int GroupNameTransactionHelper( | |
5615 const std::string& url, | |
5616 const scoped_refptr<HttpNetworkSession>& session) { | |
5617 HttpRequestInfo request; | |
5618 request.method = "GET"; | |
5619 request.url = GURL(url); | |
5620 request.load_flags = 0; | |
5621 | |
5622 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
5623 | |
5624 TestCompletionCallback callback; | |
5625 | |
5626 // We do not complete this request, the dtor will clean the transaction up. | |
5627 return trans->Start(&request, callback.callback(), BoundNetLog()); | |
5628 } | |
5629 | |
5630 TEST_F(HttpNetworkTransactionTest, GroupNameForDirectConnections) { | |
5631 const GroupNameTest tests[] = { | |
5632 { | |
5633 "", // unused | |
5634 "http://www.google.com/direct", | |
5635 "www.google.com:80", | |
5636 false, | |
5637 }, | |
5638 { | |
5639 "", // unused | |
5640 "http://[2001:1418:13:1::25]/direct", | |
5641 "[2001:1418:13:1::25]:80", | |
5642 false, | |
5643 }, | |
5644 | |
5645 // SSL Tests | |
5646 { | |
5647 "", // unused | |
5648 "https://www.google.com/direct_ssl", | |
5649 "ssl/www.google.com:443", | |
5650 true, | |
5651 }, | |
5652 { | |
5653 "", // unused | |
5654 "https://[2001:1418:13:1::25]/direct", | |
5655 "ssl/[2001:1418:13:1::25]:443", | |
5656 true, | |
5657 }, | |
5658 { | |
5659 "", // unused | |
5660 "http://host.with.alternate/direct", | |
5661 "ssl/host.with.alternate:443", | |
5662 true, | |
5663 }, | |
5664 }; | |
5665 | |
5666 HttpStreamFactory::set_use_alternate_protocols(true); | |
5667 | |
5668 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { | |
5669 SessionDependencies session_deps( | |
5670 ProxyService::CreateFixed(tests[i].proxy_server)); | |
5671 scoped_refptr<HttpNetworkSession> session( | |
5672 SetupSessionForGroupNameTests(&session_deps)); | |
5673 | |
5674 HttpNetworkSessionPeer peer(session); | |
5675 CaptureGroupNameTransportSocketPool* transport_conn_pool = | |
5676 new CaptureGroupNameTransportSocketPool(NULL, NULL); | |
5677 CaptureGroupNameSSLSocketPool* ssl_conn_pool = | |
5678 new CaptureGroupNameSSLSocketPool(NULL, NULL); | |
5679 MockClientSocketPoolManager* mock_pool_manager = | |
5680 new MockClientSocketPoolManager; | |
5681 mock_pool_manager->SetTransportSocketPool(transport_conn_pool); | |
5682 mock_pool_manager->SetSSLSocketPool(ssl_conn_pool); | |
5683 peer.SetClientSocketPoolManager(mock_pool_manager); | |
5684 | |
5685 EXPECT_EQ(ERR_IO_PENDING, | |
5686 GroupNameTransactionHelper(tests[i].url, session)); | |
5687 if (tests[i].ssl) | |
5688 EXPECT_EQ(tests[i].expected_group_name, | |
5689 ssl_conn_pool->last_group_name_received()); | |
5690 else | |
5691 EXPECT_EQ(tests[i].expected_group_name, | |
5692 transport_conn_pool->last_group_name_received()); | |
5693 } | |
5694 | |
5695 HttpStreamFactory::set_use_alternate_protocols(false); | |
5696 } | |
5697 | |
5698 TEST_F(HttpNetworkTransactionTest, GroupNameForHTTPProxyConnections) { | |
5699 const GroupNameTest tests[] = { | |
5700 { | |
5701 "http_proxy", | |
5702 "http://www.google.com/http_proxy_normal", | |
5703 "www.google.com:80", | |
5704 false, | |
5705 }, | |
5706 | |
5707 // SSL Tests | |
5708 { | |
5709 "http_proxy", | |
5710 "https://www.google.com/http_connect_ssl", | |
5711 "ssl/www.google.com:443", | |
5712 true, | |
5713 }, | |
5714 | |
5715 { | |
5716 "http_proxy", | |
5717 "http://host.with.alternate/direct", | |
5718 "ssl/host.with.alternate:443", | |
5719 true, | |
5720 }, | |
5721 }; | |
5722 | |
5723 HttpStreamFactory::set_use_alternate_protocols(true); | |
5724 | |
5725 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { | |
5726 SessionDependencies session_deps( | |
5727 ProxyService::CreateFixed(tests[i].proxy_server)); | |
5728 scoped_refptr<HttpNetworkSession> session( | |
5729 SetupSessionForGroupNameTests(&session_deps)); | |
5730 | |
5731 HttpNetworkSessionPeer peer(session); | |
5732 | |
5733 HostPortPair proxy_host("http_proxy", 80); | |
5734 CaptureGroupNameHttpProxySocketPool* http_proxy_pool = | |
5735 new CaptureGroupNameHttpProxySocketPool(NULL, NULL); | |
5736 CaptureGroupNameSSLSocketPool* ssl_conn_pool = | |
5737 new CaptureGroupNameSSLSocketPool(NULL, NULL); | |
5738 | |
5739 MockClientSocketPoolManager* mock_pool_manager = | |
5740 new MockClientSocketPoolManager; | |
5741 mock_pool_manager->SetSocketPoolForHTTPProxy(proxy_host, http_proxy_pool); | |
5742 mock_pool_manager->SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool); | |
5743 peer.SetClientSocketPoolManager(mock_pool_manager); | |
5744 | |
5745 EXPECT_EQ(ERR_IO_PENDING, | |
5746 GroupNameTransactionHelper(tests[i].url, session)); | |
5747 if (tests[i].ssl) | |
5748 EXPECT_EQ(tests[i].expected_group_name, | |
5749 ssl_conn_pool->last_group_name_received()); | |
5750 else | |
5751 EXPECT_EQ(tests[i].expected_group_name, | |
5752 http_proxy_pool->last_group_name_received()); | |
5753 } | |
5754 | |
5755 HttpStreamFactory::set_use_alternate_protocols(false); | |
5756 } | |
5757 | |
5758 TEST_F(HttpNetworkTransactionTest, GroupNameForSOCKSConnections) { | |
5759 const GroupNameTest tests[] = { | |
5760 { | |
5761 "socks4://socks_proxy:1080", | |
5762 "http://www.google.com/socks4_direct", | |
5763 "socks4/www.google.com:80", | |
5764 false, | |
5765 }, | |
5766 { | |
5767 "socks5://socks_proxy:1080", | |
5768 "http://www.google.com/socks5_direct", | |
5769 "socks5/www.google.com:80", | |
5770 false, | |
5771 }, | |
5772 | |
5773 // SSL Tests | |
5774 { | |
5775 "socks4://socks_proxy:1080", | |
5776 "https://www.google.com/socks4_ssl", | |
5777 "socks4/ssl/www.google.com:443", | |
5778 true, | |
5779 }, | |
5780 { | |
5781 "socks5://socks_proxy:1080", | |
5782 "https://www.google.com/socks5_ssl", | |
5783 "socks5/ssl/www.google.com:443", | |
5784 true, | |
5785 }, | |
5786 | |
5787 { | |
5788 "socks4://socks_proxy:1080", | |
5789 "http://host.with.alternate/direct", | |
5790 "socks4/ssl/host.with.alternate:443", | |
5791 true, | |
5792 }, | |
5793 }; | |
5794 | |
5795 HttpStreamFactory::set_use_alternate_protocols(true); | |
5796 | |
5797 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { | |
5798 SessionDependencies session_deps( | |
5799 ProxyService::CreateFixed(tests[i].proxy_server)); | |
5800 scoped_refptr<HttpNetworkSession> session( | |
5801 SetupSessionForGroupNameTests(&session_deps)); | |
5802 | |
5803 HttpNetworkSessionPeer peer(session); | |
5804 | |
5805 HostPortPair proxy_host("socks_proxy", 1080); | |
5806 CaptureGroupNameSOCKSSocketPool* socks_conn_pool = | |
5807 new CaptureGroupNameSOCKSSocketPool(NULL, NULL); | |
5808 CaptureGroupNameSSLSocketPool* ssl_conn_pool = | |
5809 new CaptureGroupNameSSLSocketPool(NULL, NULL); | |
5810 | |
5811 MockClientSocketPoolManager* mock_pool_manager = | |
5812 new MockClientSocketPoolManager; | |
5813 mock_pool_manager->SetSocketPoolForSOCKSProxy(proxy_host, socks_conn_pool); | |
5814 mock_pool_manager->SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool); | |
5815 peer.SetClientSocketPoolManager(mock_pool_manager); | |
5816 | |
5817 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
5818 | |
5819 EXPECT_EQ(ERR_IO_PENDING, | |
5820 GroupNameTransactionHelper(tests[i].url, session)); | |
5821 if (tests[i].ssl) | |
5822 EXPECT_EQ(tests[i].expected_group_name, | |
5823 ssl_conn_pool->last_group_name_received()); | |
5824 else | |
5825 EXPECT_EQ(tests[i].expected_group_name, | |
5826 socks_conn_pool->last_group_name_received()); | |
5827 } | |
5828 | |
5829 HttpStreamFactory::set_use_alternate_protocols(false); | |
5830 } | |
5831 | |
5832 TEST_F(HttpNetworkTransactionTest, ReconsiderProxyAfterFailedConnection) { | |
5833 HttpRequestInfo request; | |
5834 request.method = "GET"; | |
5835 request.url = GURL("http://www.google.com/"); | |
5836 | |
5837 SessionDependencies session_deps( | |
5838 ProxyService::CreateFixed("myproxy:70;foobar:80")); | |
5839 | |
5840 // This simulates failure resolving all hostnames; that means we will fail | |
5841 // connecting to both proxies (myproxy:70 and foobar:80). | |
5842 session_deps.host_resolver->rules()->AddSimulatedFailure("*"); | |
5843 | |
5844 scoped_ptr<HttpTransaction> trans( | |
5845 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
5846 | |
5847 TestCompletionCallback callback; | |
5848 | |
5849 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
5850 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5851 | |
5852 rv = callback.WaitForResult(); | |
5853 EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, rv); | |
5854 } | |
5855 | |
5856 // Base test to make sure that when the load flags for a request specify to | |
5857 // bypass the cache, the DNS cache is not used. | |
5858 void BypassHostCacheOnRefreshHelper(int load_flags) { | |
5859 // Issue a request, asking to bypass the cache(s). | |
5860 HttpRequestInfo request; | |
5861 request.method = "GET"; | |
5862 request.load_flags = load_flags; | |
5863 request.url = GURL("http://www.google.com/"); | |
5864 | |
5865 SessionDependencies session_deps; | |
5866 | |
5867 // Select a host resolver that does caching. | |
5868 session_deps.host_resolver.reset(new MockCachingHostResolver); | |
5869 | |
5870 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction( | |
5871 CreateSession(&session_deps))); | |
5872 | |
5873 // Warm up the host cache so it has an entry for "www.google.com". | |
5874 AddressList addrlist; | |
5875 TestCompletionCallback callback; | |
5876 int rv = session_deps.host_resolver->Resolve( | |
5877 HostResolver::RequestInfo(HostPortPair("www.google.com", 80)), &addrlist, | |
5878 callback.callback(), NULL, BoundNetLog()); | |
5879 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5880 rv = callback.WaitForResult(); | |
5881 EXPECT_EQ(OK, rv); | |
5882 | |
5883 // Verify that it was added to host cache, by doing a subsequent async lookup | |
5884 // and confirming it completes synchronously. | |
5885 rv = session_deps.host_resolver->Resolve( | |
5886 HostResolver::RequestInfo(HostPortPair("www.google.com", 80)), &addrlist, | |
5887 callback.callback(), NULL, BoundNetLog()); | |
5888 ASSERT_EQ(OK, rv); | |
5889 | |
5890 // Inject a failure the next time that "www.google.com" is resolved. This way | |
5891 // we can tell if the next lookup hit the cache, or the "network". | |
5892 // (cache --> success, "network" --> failure). | |
5893 session_deps.host_resolver->rules()->AddSimulatedFailure("www.google.com"); | |
5894 | |
5895 // Connect up a mock socket which will fail with ERR_UNEXPECTED during the | |
5896 // first read -- this won't be reached as the host resolution will fail first. | |
5897 MockRead data_reads[] = { MockRead(SYNCHRONOUS, ERR_UNEXPECTED) }; | |
5898 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
5899 session_deps.socket_factory.AddSocketDataProvider(&data); | |
5900 | |
5901 // Run the request. | |
5902 rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
5903 ASSERT_EQ(ERR_IO_PENDING, rv); | |
5904 rv = callback.WaitForResult(); | |
5905 | |
5906 // If we bypassed the cache, we would have gotten a failure while resolving | |
5907 // "www.google.com". | |
5908 EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv); | |
5909 } | |
5910 | |
5911 // There are multiple load flags that should trigger the host cache bypass. | |
5912 // Test each in isolation: | |
5913 TEST_F(HttpNetworkTransactionTest, BypassHostCacheOnRefresh1) { | |
5914 BypassHostCacheOnRefreshHelper(LOAD_BYPASS_CACHE); | |
5915 } | |
5916 | |
5917 TEST_F(HttpNetworkTransactionTest, BypassHostCacheOnRefresh2) { | |
5918 BypassHostCacheOnRefreshHelper(LOAD_VALIDATE_CACHE); | |
5919 } | |
5920 | |
5921 TEST_F(HttpNetworkTransactionTest, BypassHostCacheOnRefresh3) { | |
5922 BypassHostCacheOnRefreshHelper(LOAD_DISABLE_CACHE); | |
5923 } | |
5924 | |
5925 // Make sure we can handle an error when writing the request. | |
5926 TEST_F(HttpNetworkTransactionTest, RequestWriteError) { | |
5927 SessionDependencies session_deps; | |
5928 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
5929 | |
5930 HttpRequestInfo request; | |
5931 request.method = "GET"; | |
5932 request.url = GURL("http://www.foo.com/"); | |
5933 request.load_flags = 0; | |
5934 | |
5935 MockWrite write_failure[] = { | |
5936 MockWrite(ASYNC, ERR_CONNECTION_RESET), | |
5937 }; | |
5938 StaticSocketDataProvider data(NULL, 0, | |
5939 write_failure, arraysize(write_failure)); | |
5940 session_deps.socket_factory.AddSocketDataProvider(&data); | |
5941 | |
5942 TestCompletionCallback callback; | |
5943 | |
5944 scoped_ptr<HttpTransaction> trans( | |
5945 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
5946 | |
5947 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
5948 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5949 | |
5950 rv = callback.WaitForResult(); | |
5951 EXPECT_EQ(ERR_CONNECTION_RESET, rv); | |
5952 } | |
5953 | |
5954 // Check that a connection closed after the start of the headers finishes ok. | |
5955 TEST_F(HttpNetworkTransactionTest, ConnectionClosedAfterStartOfHeaders) { | |
5956 SessionDependencies session_deps; | |
5957 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
5958 | |
5959 HttpRequestInfo request; | |
5960 request.method = "GET"; | |
5961 request.url = GURL("http://www.foo.com/"); | |
5962 request.load_flags = 0; | |
5963 | |
5964 MockRead data_reads[] = { | |
5965 MockRead("HTTP/1."), | |
5966 MockRead(SYNCHRONOUS, OK), | |
5967 }; | |
5968 | |
5969 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
5970 session_deps.socket_factory.AddSocketDataProvider(&data); | |
5971 | |
5972 TestCompletionCallback callback; | |
5973 | |
5974 scoped_ptr<HttpTransaction> trans( | |
5975 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
5976 | |
5977 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
5978 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5979 | |
5980 rv = callback.WaitForResult(); | |
5981 EXPECT_EQ(OK, rv); | |
5982 | |
5983 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
5984 ASSERT_TRUE(response != NULL); | |
5985 | |
5986 EXPECT_TRUE(response->headers != NULL); | |
5987 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); | |
5988 | |
5989 std::string response_data; | |
5990 rv = ReadTransaction(trans.get(), &response_data); | |
5991 EXPECT_EQ(OK, rv); | |
5992 EXPECT_EQ("", response_data); | |
5993 } | |
5994 | |
5995 // Make sure that a dropped connection while draining the body for auth | |
5996 // restart does the right thing. | |
5997 TEST_F(HttpNetworkTransactionTest, DrainResetOK) { | |
5998 SessionDependencies session_deps; | |
5999 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
6000 | |
6001 HttpRequestInfo request; | |
6002 request.method = "GET"; | |
6003 request.url = GURL("http://www.google.com/"); | |
6004 request.load_flags = 0; | |
6005 | |
6006 MockWrite data_writes1[] = { | |
6007 MockWrite("GET / HTTP/1.1\r\n" | |
6008 "Host: www.google.com\r\n" | |
6009 "Connection: keep-alive\r\n\r\n"), | |
6010 }; | |
6011 | |
6012 MockRead data_reads1[] = { | |
6013 MockRead("HTTP/1.1 401 Unauthorized\r\n"), | |
6014 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
6015 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
6016 MockRead("Content-Length: 14\r\n\r\n"), | |
6017 MockRead("Unauth"), | |
6018 MockRead(ASYNC, ERR_CONNECTION_RESET), | |
6019 }; | |
6020 | |
6021 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
6022 data_writes1, arraysize(data_writes1)); | |
6023 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
6024 | |
6025 // After calling trans->RestartWithAuth(), this is the request we should | |
6026 // be issuing -- the final header line contains the credentials. | |
6027 MockWrite data_writes2[] = { | |
6028 MockWrite("GET / HTTP/1.1\r\n" | |
6029 "Host: www.google.com\r\n" | |
6030 "Connection: keep-alive\r\n" | |
6031 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
6032 }; | |
6033 | |
6034 // Lastly, the server responds with the actual content. | |
6035 MockRead data_reads2[] = { | |
6036 MockRead("HTTP/1.1 200 OK\r\n"), | |
6037 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
6038 MockRead("Content-Length: 100\r\n\r\n"), | |
6039 MockRead(SYNCHRONOUS, OK), | |
6040 }; | |
6041 | |
6042 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
6043 data_writes2, arraysize(data_writes2)); | |
6044 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
6045 | |
6046 TestCompletionCallback callback1; | |
6047 | |
6048 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
6049 | |
6050 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
6051 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6052 | |
6053 rv = callback1.WaitForResult(); | |
6054 EXPECT_EQ(OK, rv); | |
6055 | |
6056 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
6057 ASSERT_TRUE(response != NULL); | |
6058 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
6059 | |
6060 TestCompletionCallback callback2; | |
6061 | |
6062 rv = trans->RestartWithAuth( | |
6063 AuthCredentials(kFoo, kBar), callback2.callback()); | |
6064 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6065 | |
6066 rv = callback2.WaitForResult(); | |
6067 EXPECT_EQ(OK, rv); | |
6068 | |
6069 response = trans->GetResponseInfo(); | |
6070 ASSERT_TRUE(response != NULL); | |
6071 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
6072 EXPECT_EQ(100, response->headers->GetContentLength()); | |
6073 } | |
6074 | |
6075 // Test HTTPS connections going through a proxy that sends extra data. | |
6076 TEST_F(HttpNetworkTransactionTest, HTTPSViaProxyWithExtraData) { | |
6077 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
6078 | |
6079 HttpRequestInfo request; | |
6080 request.method = "GET"; | |
6081 request.url = GURL("https://www.google.com/"); | |
6082 request.load_flags = 0; | |
6083 | |
6084 MockRead proxy_reads[] = { | |
6085 MockRead("HTTP/1.0 200 Connected\r\n\r\nExtra data"), | |
6086 MockRead(SYNCHRONOUS, OK) | |
6087 }; | |
6088 | |
6089 StaticSocketDataProvider data(proxy_reads, arraysize(proxy_reads), NULL, 0); | |
6090 SSLSocketDataProvider ssl(ASYNC, OK); | |
6091 | |
6092 session_deps.socket_factory.AddSocketDataProvider(&data); | |
6093 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
6094 | |
6095 TestCompletionCallback callback; | |
6096 | |
6097 session_deps.socket_factory.ResetNextMockIndexes(); | |
6098 | |
6099 scoped_ptr<HttpTransaction> trans( | |
6100 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
6101 | |
6102 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
6103 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6104 | |
6105 rv = callback.WaitForResult(); | |
6106 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); | |
6107 } | |
6108 | |
6109 TEST_F(HttpNetworkTransactionTest, LargeContentLengthThenClose) { | |
6110 HttpRequestInfo request; | |
6111 request.method = "GET"; | |
6112 request.url = GURL("http://www.google.com/"); | |
6113 request.load_flags = 0; | |
6114 | |
6115 SessionDependencies session_deps; | |
6116 scoped_ptr<HttpTransaction> trans( | |
6117 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
6118 | |
6119 MockRead data_reads[] = { | |
6120 MockRead("HTTP/1.0 200 OK\r\nContent-Length:6719476739\r\n\r\n"), | |
6121 MockRead(SYNCHRONOUS, OK), | |
6122 }; | |
6123 | |
6124 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
6125 session_deps.socket_factory.AddSocketDataProvider(&data); | |
6126 | |
6127 TestCompletionCallback callback; | |
6128 | |
6129 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
6130 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6131 | |
6132 EXPECT_EQ(OK, callback.WaitForResult()); | |
6133 | |
6134 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
6135 ASSERT_TRUE(response != NULL); | |
6136 | |
6137 EXPECT_TRUE(response->headers != NULL); | |
6138 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); | |
6139 | |
6140 std::string response_data; | |
6141 rv = ReadTransaction(trans.get(), &response_data); | |
6142 EXPECT_EQ(ERR_CONNECTION_CLOSED, rv); | |
6143 } | |
6144 | |
6145 TEST_F(HttpNetworkTransactionTest, UploadFileSmallerThanLength) { | |
6146 HttpRequestInfo request; | |
6147 request.method = "POST"; | |
6148 request.url = GURL("http://www.google.com/upload"); | |
6149 request.upload_data = new UploadData; | |
6150 request.load_flags = 0; | |
6151 | |
6152 SessionDependencies session_deps; | |
6153 scoped_ptr<HttpTransaction> trans( | |
6154 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
6155 | |
6156 FilePath temp_file_path; | |
6157 ASSERT_TRUE(file_util::CreateTemporaryFile(&temp_file_path)); | |
6158 const uint64 kFakeSize = 100000; // file is actually blank | |
6159 | |
6160 std::vector<UploadData::Element> elements; | |
6161 UploadData::Element element; | |
6162 element.SetToFilePath(temp_file_path); | |
6163 element.SetContentLength(kFakeSize); | |
6164 elements.push_back(element); | |
6165 request.upload_data->SetElements(elements); | |
6166 EXPECT_EQ(kFakeSize, request.upload_data->GetContentLengthSync()); | |
6167 | |
6168 MockRead data_reads[] = { | |
6169 MockRead("HTTP/1.0 200 OK\r\n\r\n"), | |
6170 MockRead("hello world"), | |
6171 MockRead(SYNCHRONOUS, OK), | |
6172 }; | |
6173 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
6174 session_deps.socket_factory.AddSocketDataProvider(&data); | |
6175 | |
6176 TestCompletionCallback callback; | |
6177 | |
6178 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
6179 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6180 | |
6181 rv = callback.WaitForResult(); | |
6182 EXPECT_EQ(OK, rv); | |
6183 | |
6184 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
6185 ASSERT_TRUE(response != NULL); | |
6186 | |
6187 EXPECT_TRUE(response->headers != NULL); | |
6188 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); | |
6189 | |
6190 std::string response_data; | |
6191 rv = ReadTransaction(trans.get(), &response_data); | |
6192 EXPECT_EQ(OK, rv); | |
6193 EXPECT_EQ("hello world", response_data); | |
6194 | |
6195 file_util::Delete(temp_file_path, false); | |
6196 } | |
6197 | |
6198 TEST_F(HttpNetworkTransactionTest, UploadUnreadableFile) { | |
6199 HttpRequestInfo request; | |
6200 request.method = "POST"; | |
6201 request.url = GURL("http://www.google.com/upload"); | |
6202 request.upload_data = new UploadData; | |
6203 request.load_flags = 0; | |
6204 | |
6205 // If we try to upload an unreadable file, the network stack should report | |
6206 // the file size as zero and upload zero bytes for that file. | |
6207 SessionDependencies session_deps; | |
6208 scoped_ptr<HttpTransaction> trans( | |
6209 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
6210 | |
6211 FilePath temp_file; | |
6212 ASSERT_TRUE(file_util::CreateTemporaryFile(&temp_file)); | |
6213 std::string temp_file_content("Unreadable file."); | |
6214 ASSERT_TRUE(file_util::WriteFile(temp_file, temp_file_content.c_str(), | |
6215 temp_file_content.length())); | |
6216 ASSERT_TRUE(file_util::MakeFileUnreadable(temp_file)); | |
6217 | |
6218 std::vector<UploadData::Element> elements; | |
6219 UploadData::Element element; | |
6220 element.SetToFilePath(temp_file); | |
6221 elements.push_back(element); | |
6222 request.upload_data->SetElements(elements); | |
6223 | |
6224 MockRead data_reads[] = { | |
6225 MockRead("HTTP/1.0 200 OK\r\n\r\n"), | |
6226 MockRead(SYNCHRONOUS, OK), | |
6227 }; | |
6228 MockWrite data_writes[] = { | |
6229 MockWrite("POST /upload HTTP/1.1\r\n" | |
6230 "Host: www.google.com\r\n" | |
6231 "Connection: keep-alive\r\n" | |
6232 "Content-Length: 0\r\n\r\n"), | |
6233 MockWrite(SYNCHRONOUS, OK), | |
6234 }; | |
6235 StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes, | |
6236 arraysize(data_writes)); | |
6237 session_deps.socket_factory.AddSocketDataProvider(&data); | |
6238 | |
6239 TestCompletionCallback callback; | |
6240 | |
6241 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
6242 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6243 | |
6244 rv = callback.WaitForResult(); | |
6245 EXPECT_EQ(OK, rv); | |
6246 | |
6247 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
6248 ASSERT_TRUE(response != NULL); | |
6249 EXPECT_TRUE(response->headers != NULL); | |
6250 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); | |
6251 | |
6252 file_util::Delete(temp_file, false); | |
6253 } | |
6254 | |
6255 TEST_F(HttpNetworkTransactionTest, UnreadableUploadFileAfterAuthRestart) { | |
6256 HttpRequestInfo request; | |
6257 request.method = "POST"; | |
6258 request.url = GURL("http://www.google.com/upload"); | |
6259 request.upload_data = new UploadData; | |
6260 request.load_flags = 0; | |
6261 | |
6262 SessionDependencies session_deps; | |
6263 scoped_ptr<HttpTransaction> trans( | |
6264 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
6265 | |
6266 FilePath temp_file; | |
6267 ASSERT_TRUE(file_util::CreateTemporaryFile(&temp_file)); | |
6268 std::string temp_file_contents("Unreadable file."); | |
6269 std::string unreadable_contents(temp_file_contents.length(), '\0'); | |
6270 ASSERT_TRUE(file_util::WriteFile(temp_file, temp_file_contents.c_str(), | |
6271 temp_file_contents.length())); | |
6272 | |
6273 std::vector<UploadData::Element> elements; | |
6274 UploadData::Element element; | |
6275 element.SetToFilePath(temp_file); | |
6276 elements.push_back(element); | |
6277 request.upload_data->SetElements(elements); | |
6278 | |
6279 MockRead data_reads[] = { | |
6280 MockRead("HTTP/1.1 401 Unauthorized\r\n"), | |
6281 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
6282 MockRead("Content-Length: 0\r\n\r\n"), // No response body. | |
6283 | |
6284 MockRead("HTTP/1.1 200 OK\r\n"), | |
6285 MockRead("Content-Length: 0\r\n\r\n"), | |
6286 MockRead(SYNCHRONOUS, OK), | |
6287 }; | |
6288 MockWrite data_writes[] = { | |
6289 MockWrite("POST /upload HTTP/1.1\r\n" | |
6290 "Host: www.google.com\r\n" | |
6291 "Connection: keep-alive\r\n" | |
6292 "Content-Length: 16\r\n\r\n"), | |
6293 MockWrite(SYNCHRONOUS, temp_file_contents.c_str()), | |
6294 | |
6295 MockWrite("POST /upload HTTP/1.1\r\n" | |
6296 "Host: www.google.com\r\n" | |
6297 "Connection: keep-alive\r\n" | |
6298 "Content-Length: 16\r\n" | |
6299 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
6300 MockWrite(SYNCHRONOUS, unreadable_contents.c_str(), | |
6301 temp_file_contents.length()), | |
6302 MockWrite(SYNCHRONOUS, OK), | |
6303 }; | |
6304 StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes, | |
6305 arraysize(data_writes)); | |
6306 session_deps.socket_factory.AddSocketDataProvider(&data); | |
6307 | |
6308 TestCompletionCallback callback1; | |
6309 | |
6310 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
6311 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6312 | |
6313 rv = callback1.WaitForResult(); | |
6314 EXPECT_EQ(OK, rv); | |
6315 | |
6316 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
6317 ASSERT_TRUE(response != NULL); | |
6318 ASSERT_TRUE(response->headers != NULL); | |
6319 EXPECT_EQ("HTTP/1.1 401 Unauthorized", response->headers->GetStatusLine()); | |
6320 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
6321 | |
6322 // Now make the file unreadable and try again. | |
6323 ASSERT_TRUE(file_util::MakeFileUnreadable(temp_file)); | |
6324 | |
6325 TestCompletionCallback callback2; | |
6326 | |
6327 rv = trans->RestartWithAuth( | |
6328 AuthCredentials(kFoo, kBar), callback2.callback()); | |
6329 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6330 | |
6331 rv = callback2.WaitForResult(); | |
6332 EXPECT_EQ(OK, rv); | |
6333 | |
6334 response = trans->GetResponseInfo(); | |
6335 ASSERT_TRUE(response != NULL); | |
6336 EXPECT_TRUE(response->headers != NULL); | |
6337 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
6338 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
6339 | |
6340 file_util::Delete(temp_file, false); | |
6341 } | |
6342 | |
6343 // Tests that changes to Auth realms are treated like auth rejections. | |
6344 TEST_F(HttpNetworkTransactionTest, ChangeAuthRealms) { | |
6345 SessionDependencies session_deps; | |
6346 | |
6347 HttpRequestInfo request; | |
6348 request.method = "GET"; | |
6349 request.url = GURL("http://www.google.com/"); | |
6350 request.load_flags = 0; | |
6351 | |
6352 // First transaction will request a resource and receive a Basic challenge | |
6353 // with realm="first_realm". | |
6354 MockWrite data_writes1[] = { | |
6355 MockWrite("GET / HTTP/1.1\r\n" | |
6356 "Host: www.google.com\r\n" | |
6357 "Connection: keep-alive\r\n" | |
6358 "\r\n"), | |
6359 }; | |
6360 MockRead data_reads1[] = { | |
6361 MockRead("HTTP/1.1 401 Unauthorized\r\n" | |
6362 "WWW-Authenticate: Basic realm=\"first_realm\"\r\n" | |
6363 "\r\n"), | |
6364 }; | |
6365 | |
6366 // After calling trans->RestartWithAuth(), provide an Authentication header | |
6367 // for first_realm. The server will reject and provide a challenge with | |
6368 // second_realm. | |
6369 MockWrite data_writes2[] = { | |
6370 MockWrite("GET / HTTP/1.1\r\n" | |
6371 "Host: www.google.com\r\n" | |
6372 "Connection: keep-alive\r\n" | |
6373 "Authorization: Basic Zmlyc3Q6YmF6\r\n" | |
6374 "\r\n"), | |
6375 }; | |
6376 MockRead data_reads2[] = { | |
6377 MockRead("HTTP/1.1 401 Unauthorized\r\n" | |
6378 "WWW-Authenticate: Basic realm=\"second_realm\"\r\n" | |
6379 "\r\n"), | |
6380 }; | |
6381 | |
6382 // This again fails, and goes back to first_realm. Make sure that the | |
6383 // entry is removed from cache. | |
6384 MockWrite data_writes3[] = { | |
6385 MockWrite("GET / HTTP/1.1\r\n" | |
6386 "Host: www.google.com\r\n" | |
6387 "Connection: keep-alive\r\n" | |
6388 "Authorization: Basic c2Vjb25kOmZvdQ==\r\n" | |
6389 "\r\n"), | |
6390 }; | |
6391 MockRead data_reads3[] = { | |
6392 MockRead("HTTP/1.1 401 Unauthorized\r\n" | |
6393 "WWW-Authenticate: Basic realm=\"first_realm\"\r\n" | |
6394 "\r\n"), | |
6395 }; | |
6396 | |
6397 // Try one last time (with the correct password) and get the resource. | |
6398 MockWrite data_writes4[] = { | |
6399 MockWrite("GET / HTTP/1.1\r\n" | |
6400 "Host: www.google.com\r\n" | |
6401 "Connection: keep-alive\r\n" | |
6402 "Authorization: Basic Zmlyc3Q6YmFy\r\n" | |
6403 "\r\n"), | |
6404 }; | |
6405 MockRead data_reads4[] = { | |
6406 MockRead("HTTP/1.1 200 OK\r\n" | |
6407 "Content-Type: text/html; charset=iso-8859-1\r\n" | |
6408 "Content-Length: 5\r\n" | |
6409 "\r\n" | |
6410 "hello"), | |
6411 }; | |
6412 | |
6413 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
6414 data_writes1, arraysize(data_writes1)); | |
6415 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
6416 data_writes2, arraysize(data_writes2)); | |
6417 StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3), | |
6418 data_writes3, arraysize(data_writes3)); | |
6419 StaticSocketDataProvider data4(data_reads4, arraysize(data_reads4), | |
6420 data_writes4, arraysize(data_writes4)); | |
6421 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
6422 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
6423 session_deps.socket_factory.AddSocketDataProvider(&data3); | |
6424 session_deps.socket_factory.AddSocketDataProvider(&data4); | |
6425 | |
6426 TestCompletionCallback callback1; | |
6427 | |
6428 scoped_ptr<HttpTransaction> trans( | |
6429 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
6430 | |
6431 // Issue the first request with Authorize headers. There should be a | |
6432 // password prompt for first_realm waiting to be filled in after the | |
6433 // transaction completes. | |
6434 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
6435 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6436 rv = callback1.WaitForResult(); | |
6437 EXPECT_EQ(OK, rv); | |
6438 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
6439 ASSERT_TRUE(response != NULL); | |
6440 const AuthChallengeInfo* challenge = response->auth_challenge.get(); | |
6441 ASSERT_FALSE(challenge == NULL); | |
6442 EXPECT_FALSE(challenge->is_proxy); | |
6443 EXPECT_EQ("www.google.com:80", challenge->challenger.ToString()); | |
6444 EXPECT_EQ("first_realm", challenge->realm); | |
6445 EXPECT_EQ("basic", challenge->scheme); | |
6446 | |
6447 // Issue the second request with an incorrect password. There should be a | |
6448 // password prompt for second_realm waiting to be filled in after the | |
6449 // transaction completes. | |
6450 TestCompletionCallback callback2; | |
6451 rv = trans->RestartWithAuth( | |
6452 AuthCredentials(kFirst, kBaz), callback2.callback()); | |
6453 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6454 rv = callback2.WaitForResult(); | |
6455 EXPECT_EQ(OK, rv); | |
6456 response = trans->GetResponseInfo(); | |
6457 ASSERT_TRUE(response != NULL); | |
6458 challenge = response->auth_challenge.get(); | |
6459 ASSERT_FALSE(challenge == NULL); | |
6460 EXPECT_FALSE(challenge->is_proxy); | |
6461 EXPECT_EQ("www.google.com:80", challenge->challenger.ToString()); | |
6462 EXPECT_EQ("second_realm", challenge->realm); | |
6463 EXPECT_EQ("basic", challenge->scheme); | |
6464 | |
6465 // Issue the third request with another incorrect password. There should be | |
6466 // a password prompt for first_realm waiting to be filled in. If the password | |
6467 // prompt is not present, it indicates that the HttpAuthCacheEntry for | |
6468 // first_realm was not correctly removed. | |
6469 TestCompletionCallback callback3; | |
6470 rv = trans->RestartWithAuth( | |
6471 AuthCredentials(kSecond, kFou), callback3.callback()); | |
6472 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6473 rv = callback3.WaitForResult(); | |
6474 EXPECT_EQ(OK, rv); | |
6475 response = trans->GetResponseInfo(); | |
6476 ASSERT_TRUE(response != NULL); | |
6477 challenge = response->auth_challenge.get(); | |
6478 ASSERT_FALSE(challenge == NULL); | |
6479 EXPECT_FALSE(challenge->is_proxy); | |
6480 EXPECT_EQ("www.google.com:80", challenge->challenger.ToString()); | |
6481 EXPECT_EQ("first_realm", challenge->realm); | |
6482 EXPECT_EQ("basic", challenge->scheme); | |
6483 | |
6484 // Issue the fourth request with the correct password and username. | |
6485 TestCompletionCallback callback4; | |
6486 rv = trans->RestartWithAuth( | |
6487 AuthCredentials(kFirst, kBar), callback4.callback()); | |
6488 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6489 rv = callback4.WaitForResult(); | |
6490 EXPECT_EQ(OK, rv); | |
6491 response = trans->GetResponseInfo(); | |
6492 ASSERT_TRUE(response != NULL); | |
6493 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
6494 } | |
6495 | |
6496 TEST_F(HttpNetworkTransactionTest, HonorAlternateProtocolHeader) { | |
6497 HttpStreamFactory::set_use_alternate_protocols(true); | |
6498 HttpStreamFactory::SetNextProtos(SpdyNextProtos()); | |
6499 | |
6500 SessionDependencies session_deps; | |
6501 | |
6502 MockRead data_reads[] = { | |
6503 MockRead("HTTP/1.1 200 OK\r\n"), | |
6504 MockRead(kAlternateProtocolHttpHeader), | |
6505 MockRead("hello world"), | |
6506 MockRead(SYNCHRONOUS, OK), | |
6507 }; | |
6508 | |
6509 HttpRequestInfo request; | |
6510 request.method = "GET"; | |
6511 request.url = GURL("http://www.google.com/"); | |
6512 request.load_flags = 0; | |
6513 | |
6514 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
6515 | |
6516 session_deps.socket_factory.AddSocketDataProvider(&data); | |
6517 | |
6518 TestCompletionCallback callback; | |
6519 | |
6520 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
6521 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
6522 | |
6523 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
6524 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6525 | |
6526 HostPortPair http_host_port_pair("www.google.com", 80); | |
6527 const HttpServerProperties& http_server_properties = | |
6528 *session->http_server_properties(); | |
6529 EXPECT_FALSE( | |
6530 http_server_properties.HasAlternateProtocol(http_host_port_pair)); | |
6531 | |
6532 EXPECT_EQ(OK, callback.WaitForResult()); | |
6533 | |
6534 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
6535 ASSERT_TRUE(response != NULL); | |
6536 ASSERT_TRUE(response->headers != NULL); | |
6537 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
6538 EXPECT_FALSE(response->was_fetched_via_spdy); | |
6539 EXPECT_FALSE(response->was_npn_negotiated); | |
6540 | |
6541 std::string response_data; | |
6542 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
6543 EXPECT_EQ("hello world", response_data); | |
6544 | |
6545 ASSERT_TRUE(http_server_properties.HasAlternateProtocol(http_host_port_pair)); | |
6546 const PortAlternateProtocolPair alternate = | |
6547 http_server_properties.GetAlternateProtocol(http_host_port_pair); | |
6548 PortAlternateProtocolPair expected_alternate; | |
6549 expected_alternate.port = 443; | |
6550 expected_alternate.protocol = NPN_SPDY_21; | |
6551 EXPECT_TRUE(expected_alternate.Equals(alternate)); | |
6552 | |
6553 HttpStreamFactory::set_use_alternate_protocols(false); | |
6554 HttpStreamFactory::SetNextProtos(std::vector<std::string>()); | |
6555 } | |
6556 | |
6557 TEST_F(HttpNetworkTransactionTest, MarkBrokenAlternateProtocolAndFallback) { | |
6558 HttpStreamFactory::set_use_alternate_protocols(true); | |
6559 SessionDependencies session_deps; | |
6560 | |
6561 HttpRequestInfo request; | |
6562 request.method = "GET"; | |
6563 request.url = GURL("http://www.google.com/"); | |
6564 request.load_flags = 0; | |
6565 | |
6566 MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); | |
6567 StaticSocketDataProvider first_data; | |
6568 first_data.set_connect_data(mock_connect); | |
6569 session_deps.socket_factory.AddSocketDataProvider(&first_data); | |
6570 | |
6571 MockRead data_reads[] = { | |
6572 MockRead("HTTP/1.1 200 OK\r\n\r\n"), | |
6573 MockRead("hello world"), | |
6574 MockRead(ASYNC, OK), | |
6575 }; | |
6576 StaticSocketDataProvider second_data( | |
6577 data_reads, arraysize(data_reads), NULL, 0); | |
6578 session_deps.socket_factory.AddSocketDataProvider(&second_data); | |
6579 | |
6580 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
6581 | |
6582 HttpServerProperties* http_server_properties = | |
6583 session->http_server_properties(); | |
6584 // Port must be < 1024, or the header will be ignored (since initial port was | |
6585 // port 80 (another restricted port). | |
6586 http_server_properties->SetAlternateProtocol( | |
6587 HostPortPair::FromURL(request.url), | |
6588 666 /* port is ignored by MockConnect anyway */, | |
6589 NPN_SPDY_21); | |
6590 | |
6591 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
6592 TestCompletionCallback callback; | |
6593 | |
6594 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
6595 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6596 EXPECT_EQ(OK, callback.WaitForResult()); | |
6597 | |
6598 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
6599 ASSERT_TRUE(response != NULL); | |
6600 ASSERT_TRUE(response->headers != NULL); | |
6601 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
6602 | |
6603 std::string response_data; | |
6604 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
6605 EXPECT_EQ("hello world", response_data); | |
6606 | |
6607 ASSERT_TRUE(http_server_properties->HasAlternateProtocol( | |
6608 HostPortPair::FromURL(request.url))); | |
6609 const PortAlternateProtocolPair alternate = | |
6610 http_server_properties->GetAlternateProtocol( | |
6611 HostPortPair::FromURL(request.url)); | |
6612 EXPECT_EQ(ALTERNATE_PROTOCOL_BROKEN, alternate.protocol); | |
6613 HttpStreamFactory::set_use_alternate_protocols(false); | |
6614 } | |
6615 | |
6616 TEST_F(HttpNetworkTransactionTest, AlternateProtocolPortRestrictedBlocked) { | |
6617 // Ensure that we're not allowed to redirect traffic via an alternate | |
6618 // protocol to an unrestricted (port >= 1024) when the original traffic was | |
6619 // on a restricted port (port < 1024). Ensure that we can redirect in all | |
6620 // other cases. | |
6621 HttpStreamFactory::set_use_alternate_protocols(true); | |
6622 SessionDependencies session_deps; | |
6623 | |
6624 HttpRequestInfo restricted_port_request; | |
6625 restricted_port_request.method = "GET"; | |
6626 restricted_port_request.url = GURL("http://www.google.com:1023/"); | |
6627 restricted_port_request.load_flags = 0; | |
6628 | |
6629 MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); | |
6630 StaticSocketDataProvider first_data; | |
6631 first_data.set_connect_data(mock_connect); | |
6632 session_deps.socket_factory.AddSocketDataProvider(&first_data); | |
6633 | |
6634 MockRead data_reads[] = { | |
6635 MockRead("HTTP/1.1 200 OK\r\n\r\n"), | |
6636 MockRead("hello world"), | |
6637 MockRead(ASYNC, OK), | |
6638 }; | |
6639 StaticSocketDataProvider second_data( | |
6640 data_reads, arraysize(data_reads), NULL, 0); | |
6641 session_deps.socket_factory.AddSocketDataProvider(&second_data); | |
6642 | |
6643 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
6644 | |
6645 HttpServerProperties* http_server_properties = | |
6646 session->http_server_properties(); | |
6647 const int kUnrestrictedAlternatePort = 1024; | |
6648 http_server_properties->SetAlternateProtocol( | |
6649 HostPortPair::FromURL(restricted_port_request.url), | |
6650 kUnrestrictedAlternatePort, | |
6651 NPN_SPDY_21); | |
6652 | |
6653 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
6654 TestCompletionCallback callback; | |
6655 | |
6656 int rv = trans->Start( | |
6657 &restricted_port_request, callback.callback(), BoundNetLog()); | |
6658 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6659 // Invalid change to unrestricted port should fail. | |
6660 EXPECT_EQ(ERR_CONNECTION_REFUSED, callback.WaitForResult()); | |
6661 | |
6662 HttpStreamFactory::set_use_alternate_protocols(false); | |
6663 } | |
6664 | |
6665 TEST_F(HttpNetworkTransactionTest, AlternateProtocolPortRestrictedAllowed) { | |
6666 // Ensure that we're not allowed to redirect traffic via an alternate | |
6667 // protocol to an unrestricted (port >= 1024) when the original traffic was | |
6668 // on a restricted port (port < 1024). Ensure that we can redirect in all | |
6669 // other cases. | |
6670 HttpStreamFactory::set_use_alternate_protocols(true); | |
6671 SessionDependencies session_deps; | |
6672 | |
6673 HttpRequestInfo restricted_port_request; | |
6674 restricted_port_request.method = "GET"; | |
6675 restricted_port_request.url = GURL("http://www.google.com:1023/"); | |
6676 restricted_port_request.load_flags = 0; | |
6677 | |
6678 MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); | |
6679 StaticSocketDataProvider first_data; | |
6680 first_data.set_connect_data(mock_connect); | |
6681 session_deps.socket_factory.AddSocketDataProvider(&first_data); | |
6682 | |
6683 MockRead data_reads[] = { | |
6684 MockRead("HTTP/1.1 200 OK\r\n\r\n"), | |
6685 MockRead("hello world"), | |
6686 MockRead(ASYNC, OK), | |
6687 }; | |
6688 StaticSocketDataProvider second_data( | |
6689 data_reads, arraysize(data_reads), NULL, 0); | |
6690 session_deps.socket_factory.AddSocketDataProvider(&second_data); | |
6691 | |
6692 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
6693 | |
6694 HttpServerProperties* http_server_properties = | |
6695 session->http_server_properties(); | |
6696 const int kRestrictedAlternatePort = 80; | |
6697 http_server_properties->SetAlternateProtocol( | |
6698 HostPortPair::FromURL(restricted_port_request.url), | |
6699 kRestrictedAlternatePort, | |
6700 NPN_SPDY_21); | |
6701 | |
6702 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
6703 TestCompletionCallback callback; | |
6704 | |
6705 int rv = trans->Start( | |
6706 &restricted_port_request, callback.callback(), BoundNetLog()); | |
6707 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6708 // Valid change to restricted port should pass. | |
6709 EXPECT_EQ(OK, callback.WaitForResult()); | |
6710 | |
6711 HttpStreamFactory::set_use_alternate_protocols(false); | |
6712 } | |
6713 | |
6714 TEST_F(HttpNetworkTransactionTest, AlternateProtocolPortUnrestrictedAllowed1) { | |
6715 // Ensure that we're not allowed to redirect traffic via an alternate | |
6716 // protocol to an unrestricted (port >= 1024) when the original traffic was | |
6717 // on a restricted port (port < 1024). Ensure that we can redirect in all | |
6718 // other cases. | |
6719 HttpStreamFactory::set_use_alternate_protocols(true); | |
6720 SessionDependencies session_deps; | |
6721 | |
6722 HttpRequestInfo unrestricted_port_request; | |
6723 unrestricted_port_request.method = "GET"; | |
6724 unrestricted_port_request.url = GURL("http://www.google.com:1024/"); | |
6725 unrestricted_port_request.load_flags = 0; | |
6726 | |
6727 MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); | |
6728 StaticSocketDataProvider first_data; | |
6729 first_data.set_connect_data(mock_connect); | |
6730 session_deps.socket_factory.AddSocketDataProvider(&first_data); | |
6731 | |
6732 MockRead data_reads[] = { | |
6733 MockRead("HTTP/1.1 200 OK\r\n\r\n"), | |
6734 MockRead("hello world"), | |
6735 MockRead(ASYNC, OK), | |
6736 }; | |
6737 StaticSocketDataProvider second_data( | |
6738 data_reads, arraysize(data_reads), NULL, 0); | |
6739 session_deps.socket_factory.AddSocketDataProvider(&second_data); | |
6740 | |
6741 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
6742 | |
6743 HttpServerProperties* http_server_properties = | |
6744 session->http_server_properties(); | |
6745 const int kRestrictedAlternatePort = 80; | |
6746 http_server_properties->SetAlternateProtocol( | |
6747 HostPortPair::FromURL(unrestricted_port_request.url), | |
6748 kRestrictedAlternatePort, | |
6749 NPN_SPDY_21); | |
6750 | |
6751 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
6752 TestCompletionCallback callback; | |
6753 | |
6754 int rv = trans->Start( | |
6755 &unrestricted_port_request, callback.callback(), BoundNetLog()); | |
6756 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6757 // Valid change to restricted port should pass. | |
6758 EXPECT_EQ(OK, callback.WaitForResult()); | |
6759 | |
6760 HttpStreamFactory::set_use_alternate_protocols(false); | |
6761 } | |
6762 | |
6763 TEST_F(HttpNetworkTransactionTest, AlternateProtocolPortUnrestrictedAllowed2) { | |
6764 // Ensure that we're not allowed to redirect traffic via an alternate | |
6765 // protocol to an unrestricted (port >= 1024) when the original traffic was | |
6766 // on a restricted port (port < 1024). Ensure that we can redirect in all | |
6767 // other cases. | |
6768 HttpStreamFactory::set_use_alternate_protocols(true); | |
6769 SessionDependencies session_deps; | |
6770 | |
6771 HttpRequestInfo unrestricted_port_request; | |
6772 unrestricted_port_request.method = "GET"; | |
6773 unrestricted_port_request.url = GURL("http://www.google.com:1024/"); | |
6774 unrestricted_port_request.load_flags = 0; | |
6775 | |
6776 MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); | |
6777 StaticSocketDataProvider first_data; | |
6778 first_data.set_connect_data(mock_connect); | |
6779 session_deps.socket_factory.AddSocketDataProvider(&first_data); | |
6780 | |
6781 MockRead data_reads[] = { | |
6782 MockRead("HTTP/1.1 200 OK\r\n\r\n"), | |
6783 MockRead("hello world"), | |
6784 MockRead(ASYNC, OK), | |
6785 }; | |
6786 StaticSocketDataProvider second_data( | |
6787 data_reads, arraysize(data_reads), NULL, 0); | |
6788 session_deps.socket_factory.AddSocketDataProvider(&second_data); | |
6789 | |
6790 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
6791 | |
6792 HttpServerProperties* http_server_properties = | |
6793 session->http_server_properties(); | |
6794 const int kUnrestrictedAlternatePort = 1024; | |
6795 http_server_properties->SetAlternateProtocol( | |
6796 HostPortPair::FromURL(unrestricted_port_request.url), | |
6797 kUnrestrictedAlternatePort, | |
6798 NPN_SPDY_21); | |
6799 | |
6800 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
6801 TestCompletionCallback callback; | |
6802 | |
6803 int rv = trans->Start( | |
6804 &unrestricted_port_request, callback.callback(), BoundNetLog()); | |
6805 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6806 // Valid change to an unrestricted port should pass. | |
6807 EXPECT_EQ(OK, callback.WaitForResult()); | |
6808 | |
6809 HttpStreamFactory::set_use_alternate_protocols(false); | |
6810 } | |
6811 | |
6812 TEST_F(HttpNetworkTransactionTest, AlternateProtocolUnsafeBlocked) { | |
6813 // Ensure that we're not allowed to redirect traffic via an alternate | |
6814 // protocol to an unsafe port, and that we resume the second | |
6815 // HttpStreamFactoryImpl::Job once the alternate protocol request fails. | |
6816 HttpStreamFactory::set_use_alternate_protocols(true); | |
6817 SessionDependencies session_deps; | |
6818 | |
6819 HttpRequestInfo request; | |
6820 request.method = "GET"; | |
6821 request.url = GURL("http://www.google.com/"); | |
6822 request.load_flags = 0; | |
6823 | |
6824 // The alternate protocol request will error out before we attempt to connect, | |
6825 // so only the standard HTTP request will try to connect. | |
6826 MockRead data_reads[] = { | |
6827 MockRead("HTTP/1.1 200 OK\r\n\r\n"), | |
6828 MockRead("hello world"), | |
6829 MockRead(ASYNC, OK), | |
6830 }; | |
6831 StaticSocketDataProvider data( | |
6832 data_reads, arraysize(data_reads), NULL, 0); | |
6833 session_deps.socket_factory.AddSocketDataProvider(&data); | |
6834 | |
6835 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
6836 | |
6837 HttpServerProperties* http_server_properties = | |
6838 session->http_server_properties(); | |
6839 const int kUnsafePort = 7; | |
6840 http_server_properties->SetAlternateProtocol( | |
6841 HostPortPair::FromURL(request.url), | |
6842 kUnsafePort, | |
6843 NPN_SPDY_2); | |
6844 | |
6845 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
6846 TestCompletionCallback callback; | |
6847 | |
6848 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
6849 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6850 // The HTTP request should succeed. | |
6851 EXPECT_EQ(OK, callback.WaitForResult()); | |
6852 | |
6853 // Disable alternate protocol before the asserts. | |
6854 HttpStreamFactory::set_use_alternate_protocols(false); | |
6855 | |
6856 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
6857 ASSERT_TRUE(response != NULL); | |
6858 ASSERT_TRUE(response->headers != NULL); | |
6859 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
6860 | |
6861 std::string response_data; | |
6862 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
6863 EXPECT_EQ("hello world", response_data); | |
6864 } | |
6865 | |
6866 TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) { | |
6867 HttpStreamFactory::set_use_alternate_protocols(true); | |
6868 HttpStreamFactory::SetNextProtos(SpdyNextProtos()); | |
6869 SessionDependencies session_deps; | |
6870 | |
6871 HttpRequestInfo request; | |
6872 request.method = "GET"; | |
6873 request.url = GURL("http://www.google.com/"); | |
6874 request.load_flags = 0; | |
6875 | |
6876 MockRead data_reads[] = { | |
6877 MockRead("HTTP/1.1 200 OK\r\n"), | |
6878 MockRead(kAlternateProtocolHttpHeader), | |
6879 MockRead("hello world"), | |
6880 MockRead(ASYNC, OK), | |
6881 }; | |
6882 | |
6883 StaticSocketDataProvider first_transaction( | |
6884 data_reads, arraysize(data_reads), NULL, 0); | |
6885 session_deps.socket_factory.AddSocketDataProvider(&first_transaction); | |
6886 | |
6887 SSLSocketDataProvider ssl(ASYNC, OK); | |
6888 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
6889 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
6890 | |
6891 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
6892 MockWrite spdy_writes[] = { CreateMockWrite(*req) }; | |
6893 | |
6894 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
6895 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); | |
6896 MockRead spdy_reads[] = { | |
6897 CreateMockRead(*resp), | |
6898 CreateMockRead(*data), | |
6899 MockRead(ASYNC, 0, 0), | |
6900 }; | |
6901 | |
6902 scoped_ptr<DelayedSocketData> spdy_data( | |
6903 new DelayedSocketData( | |
6904 1, // wait for one write to finish before reading. | |
6905 spdy_reads, arraysize(spdy_reads), | |
6906 spdy_writes, arraysize(spdy_writes))); | |
6907 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
6908 | |
6909 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); | |
6910 StaticSocketDataProvider hanging_non_alternate_protocol_socket( | |
6911 NULL, 0, NULL, 0); | |
6912 hanging_non_alternate_protocol_socket.set_connect_data( | |
6913 never_finishing_connect); | |
6914 session_deps.socket_factory.AddSocketDataProvider( | |
6915 &hanging_non_alternate_protocol_socket); | |
6916 | |
6917 TestCompletionCallback callback; | |
6918 | |
6919 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
6920 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); | |
6921 | |
6922 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
6923 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6924 EXPECT_EQ(OK, callback.WaitForResult()); | |
6925 | |
6926 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
6927 ASSERT_TRUE(response != NULL); | |
6928 ASSERT_TRUE(response->headers != NULL); | |
6929 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
6930 | |
6931 std::string response_data; | |
6932 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
6933 EXPECT_EQ("hello world", response_data); | |
6934 | |
6935 trans.reset(new HttpNetworkTransaction(session)); | |
6936 | |
6937 rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
6938 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6939 EXPECT_EQ(OK, callback.WaitForResult()); | |
6940 | |
6941 response = trans->GetResponseInfo(); | |
6942 ASSERT_TRUE(response != NULL); | |
6943 ASSERT_TRUE(response->headers != NULL); | |
6944 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
6945 EXPECT_TRUE(response->was_fetched_via_spdy); | |
6946 EXPECT_TRUE(response->was_npn_negotiated); | |
6947 | |
6948 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
6949 EXPECT_EQ("hello!", response_data); | |
6950 | |
6951 HttpStreamFactory::SetNextProtos(std::vector<std::string>()); | |
6952 HttpStreamFactory::set_use_alternate_protocols(false); | |
6953 } | |
6954 | |
6955 TEST_F(HttpNetworkTransactionTest, AlternateProtocolWithSpdyLateBinding) { | |
6956 HttpStreamFactory::set_use_alternate_protocols(true); | |
6957 HttpStreamFactory::SetNextProtos(SpdyNextProtos()); | |
6958 SessionDependencies session_deps; | |
6959 | |
6960 HttpRequestInfo request; | |
6961 request.method = "GET"; | |
6962 request.url = GURL("http://www.google.com/"); | |
6963 request.load_flags = 0; | |
6964 | |
6965 MockRead data_reads[] = { | |
6966 MockRead("HTTP/1.1 200 OK\r\n"), | |
6967 MockRead(kAlternateProtocolHttpHeader), | |
6968 MockRead("hello world"), | |
6969 MockRead(ASYNC, OK), | |
6970 }; | |
6971 | |
6972 StaticSocketDataProvider first_transaction( | |
6973 data_reads, arraysize(data_reads), NULL, 0); | |
6974 // Socket 1 is the HTTP transaction with the Alternate-Protocol header. | |
6975 session_deps.socket_factory.AddSocketDataProvider(&first_transaction); | |
6976 | |
6977 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); | |
6978 StaticSocketDataProvider hanging_socket( | |
6979 NULL, 0, NULL, 0); | |
6980 hanging_socket.set_connect_data(never_finishing_connect); | |
6981 // Socket 2 and 3 are the hanging Alternate-Protocol and | |
6982 // non-Alternate-Protocol jobs from the 2nd transaction. | |
6983 session_deps.socket_factory.AddSocketDataProvider(&hanging_socket); | |
6984 session_deps.socket_factory.AddSocketDataProvider(&hanging_socket); | |
6985 | |
6986 SSLSocketDataProvider ssl(ASYNC, OK); | |
6987 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
6988 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
6989 | |
6990 scoped_ptr<spdy::SpdyFrame> req1(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
6991 scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST)); | |
6992 MockWrite spdy_writes[] = { | |
6993 CreateMockWrite(*req1), | |
6994 CreateMockWrite(*req2), | |
6995 }; | |
6996 scoped_ptr<spdy::SpdyFrame> resp1(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
6997 scoped_ptr<spdy::SpdyFrame> data1(ConstructSpdyBodyFrame(1, true)); | |
6998 scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3)); | |
6999 scoped_ptr<spdy::SpdyFrame> data2(ConstructSpdyBodyFrame(3, true)); | |
7000 MockRead spdy_reads[] = { | |
7001 CreateMockRead(*resp1), | |
7002 CreateMockRead(*data1), | |
7003 CreateMockRead(*resp2), | |
7004 CreateMockRead(*data2), | |
7005 MockRead(ASYNC, 0, 0), | |
7006 }; | |
7007 | |
7008 scoped_ptr<DelayedSocketData> spdy_data( | |
7009 new DelayedSocketData( | |
7010 2, // wait for writes to finish before reading. | |
7011 spdy_reads, arraysize(spdy_reads), | |
7012 spdy_writes, arraysize(spdy_writes))); | |
7013 // Socket 4 is the successful Alternate-Protocol for transaction 3. | |
7014 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
7015 | |
7016 // Socket 5 is the unsuccessful non-Alternate-Protocol for transaction 3. | |
7017 session_deps.socket_factory.AddSocketDataProvider(&hanging_socket); | |
7018 | |
7019 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
7020 TestCompletionCallback callback1; | |
7021 HttpNetworkTransaction trans1(session); | |
7022 | |
7023 int rv = trans1.Start(&request, callback1.callback(), BoundNetLog()); | |
7024 EXPECT_EQ(ERR_IO_PENDING, rv); | |
7025 EXPECT_EQ(OK, callback1.WaitForResult()); | |
7026 | |
7027 const HttpResponseInfo* response = trans1.GetResponseInfo(); | |
7028 ASSERT_TRUE(response != NULL); | |
7029 ASSERT_TRUE(response->headers != NULL); | |
7030 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
7031 | |
7032 std::string response_data; | |
7033 ASSERT_EQ(OK, ReadTransaction(&trans1, &response_data)); | |
7034 EXPECT_EQ("hello world", response_data); | |
7035 | |
7036 TestCompletionCallback callback2; | |
7037 HttpNetworkTransaction trans2(session); | |
7038 rv = trans2.Start(&request, callback2.callback(), BoundNetLog()); | |
7039 EXPECT_EQ(ERR_IO_PENDING, rv); | |
7040 | |
7041 TestCompletionCallback callback3; | |
7042 HttpNetworkTransaction trans3(session); | |
7043 rv = trans3.Start(&request, callback3.callback(), BoundNetLog()); | |
7044 EXPECT_EQ(ERR_IO_PENDING, rv); | |
7045 | |
7046 EXPECT_EQ(OK, callback2.WaitForResult()); | |
7047 EXPECT_EQ(OK, callback3.WaitForResult()); | |
7048 | |
7049 response = trans2.GetResponseInfo(); | |
7050 ASSERT_TRUE(response != NULL); | |
7051 ASSERT_TRUE(response->headers != NULL); | |
7052 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
7053 EXPECT_TRUE(response->was_fetched_via_spdy); | |
7054 EXPECT_TRUE(response->was_npn_negotiated); | |
7055 ASSERT_EQ(OK, ReadTransaction(&trans2, &response_data)); | |
7056 EXPECT_EQ("hello!", response_data); | |
7057 | |
7058 response = trans3.GetResponseInfo(); | |
7059 ASSERT_TRUE(response != NULL); | |
7060 ASSERT_TRUE(response->headers != NULL); | |
7061 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
7062 EXPECT_TRUE(response->was_fetched_via_spdy); | |
7063 EXPECT_TRUE(response->was_npn_negotiated); | |
7064 ASSERT_EQ(OK, ReadTransaction(&trans3, &response_data)); | |
7065 EXPECT_EQ("hello!", response_data); | |
7066 | |
7067 HttpStreamFactory::SetNextProtos(std::vector<std::string>()); | |
7068 HttpStreamFactory::set_use_alternate_protocols(false); | |
7069 } | |
7070 | |
7071 TEST_F(HttpNetworkTransactionTest, StallAlternateProtocolForNpnSpdy) { | |
7072 HttpStreamFactory::set_use_alternate_protocols(true); | |
7073 HttpStreamFactory::SetNextProtos(SpdyNextProtos()); | |
7074 SessionDependencies session_deps; | |
7075 | |
7076 HttpRequestInfo request; | |
7077 request.method = "GET"; | |
7078 request.url = GURL("http://www.google.com/"); | |
7079 request.load_flags = 0; | |
7080 | |
7081 MockRead data_reads[] = { | |
7082 MockRead("HTTP/1.1 200 OK\r\n"), | |
7083 MockRead(kAlternateProtocolHttpHeader), | |
7084 MockRead("hello world"), | |
7085 MockRead(ASYNC, OK), | |
7086 }; | |
7087 | |
7088 StaticSocketDataProvider first_transaction( | |
7089 data_reads, arraysize(data_reads), NULL, 0); | |
7090 session_deps.socket_factory.AddSocketDataProvider(&first_transaction); | |
7091 | |
7092 SSLSocketDataProvider ssl(ASYNC, OK); | |
7093 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
7094 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
7095 | |
7096 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); | |
7097 StaticSocketDataProvider hanging_alternate_protocol_socket( | |
7098 NULL, 0, NULL, 0); | |
7099 hanging_alternate_protocol_socket.set_connect_data( | |
7100 never_finishing_connect); | |
7101 session_deps.socket_factory.AddSocketDataProvider( | |
7102 &hanging_alternate_protocol_socket); | |
7103 | |
7104 // 2nd request is just a copy of the first one, over HTTP again. | |
7105 session_deps.socket_factory.AddSocketDataProvider(&first_transaction); | |
7106 | |
7107 TestCompletionCallback callback; | |
7108 | |
7109 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
7110 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); | |
7111 | |
7112 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
7113 EXPECT_EQ(ERR_IO_PENDING, rv); | |
7114 EXPECT_EQ(OK, callback.WaitForResult()); | |
7115 | |
7116 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
7117 ASSERT_TRUE(response != NULL); | |
7118 ASSERT_TRUE(response->headers != NULL); | |
7119 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
7120 | |
7121 std::string response_data; | |
7122 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
7123 EXPECT_EQ("hello world", response_data); | |
7124 | |
7125 trans.reset(new HttpNetworkTransaction(session)); | |
7126 | |
7127 rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
7128 EXPECT_EQ(ERR_IO_PENDING, rv); | |
7129 EXPECT_EQ(OK, callback.WaitForResult()); | |
7130 | |
7131 response = trans->GetResponseInfo(); | |
7132 ASSERT_TRUE(response != NULL); | |
7133 ASSERT_TRUE(response->headers != NULL); | |
7134 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
7135 EXPECT_FALSE(response->was_fetched_via_spdy); | |
7136 EXPECT_FALSE(response->was_npn_negotiated); | |
7137 | |
7138 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
7139 EXPECT_EQ("hello world", response_data); | |
7140 | |
7141 HttpStreamFactory::SetNextProtos(std::vector<std::string>()); | |
7142 HttpStreamFactory::set_use_alternate_protocols(false); | |
7143 } | |
7144 | |
7145 class CapturingProxyResolver : public ProxyResolver { | |
7146 public: | |
7147 CapturingProxyResolver() : ProxyResolver(false /* expects_pac_bytes */) {} | |
7148 virtual ~CapturingProxyResolver() {} | |
7149 | |
7150 virtual int GetProxyForURL(const GURL& url, | |
7151 ProxyInfo* results, | |
7152 const CompletionCallback& callback, | |
7153 RequestHandle* request, | |
7154 const BoundNetLog& net_log) { | |
7155 ProxyServer proxy_server(ProxyServer::SCHEME_HTTP, | |
7156 HostPortPair("myproxy", 80)); | |
7157 results->UseProxyServer(proxy_server); | |
7158 resolved_.push_back(url); | |
7159 return OK; | |
7160 } | |
7161 | |
7162 virtual void CancelRequest(RequestHandle request) { | |
7163 NOTREACHED(); | |
7164 } | |
7165 | |
7166 virtual LoadState GetLoadState(RequestHandle request) const OVERRIDE { | |
7167 NOTREACHED(); | |
7168 return LOAD_STATE_IDLE; | |
7169 } | |
7170 | |
7171 virtual LoadState GetLoadStateThreadSafe( | |
7172 RequestHandle request) const OVERRIDE { | |
7173 NOTREACHED(); | |
7174 return LOAD_STATE_IDLE; | |
7175 } | |
7176 | |
7177 virtual void CancelSetPacScript() { | |
7178 NOTREACHED(); | |
7179 } | |
7180 | |
7181 virtual int SetPacScript(const scoped_refptr<ProxyResolverScriptData>&, | |
7182 const CompletionCallback& /*callback*/) { | |
7183 return OK; | |
7184 } | |
7185 | |
7186 const std::vector<GURL>& resolved() const { return resolved_; } | |
7187 | |
7188 private: | |
7189 std::vector<GURL> resolved_; | |
7190 | |
7191 DISALLOW_COPY_AND_ASSIGN(CapturingProxyResolver); | |
7192 }; | |
7193 | |
7194 TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForTunneledNpnSpdy) { | |
7195 HttpStreamFactory::set_use_alternate_protocols(true); | |
7196 HttpStreamFactory::SetNextProtos(SpdyNextProtos()); | |
7197 | |
7198 ProxyConfig proxy_config; | |
7199 proxy_config.set_auto_detect(true); | |
7200 proxy_config.set_pac_url(GURL("http://fooproxyurl")); | |
7201 | |
7202 CapturingProxyResolver* capturing_proxy_resolver = | |
7203 new CapturingProxyResolver(); | |
7204 SessionDependencies session_deps(new ProxyService( | |
7205 new ProxyConfigServiceFixed(proxy_config), capturing_proxy_resolver, | |
7206 NULL)); | |
7207 | |
7208 HttpRequestInfo request; | |
7209 request.method = "GET"; | |
7210 request.url = GURL("http://www.google.com/"); | |
7211 request.load_flags = 0; | |
7212 | |
7213 MockRead data_reads[] = { | |
7214 MockRead("HTTP/1.1 200 OK\r\n"), | |
7215 MockRead(kAlternateProtocolHttpHeader), | |
7216 MockRead("hello world"), | |
7217 MockRead(ASYNC, OK), | |
7218 }; | |
7219 | |
7220 StaticSocketDataProvider first_transaction( | |
7221 data_reads, arraysize(data_reads), NULL, 0); | |
7222 session_deps.socket_factory.AddSocketDataProvider(&first_transaction); | |
7223 | |
7224 SSLSocketDataProvider ssl(ASYNC, OK); | |
7225 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
7226 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
7227 | |
7228 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
7229 MockWrite spdy_writes[] = { | |
7230 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
7231 "Host: www.google.com\r\n" | |
7232 "Proxy-Connection: keep-alive\r\n\r\n"), // 0 | |
7233 CreateMockWrite(*req) // 3 | |
7234 }; | |
7235 | |
7236 const char kCONNECTResponse[] = "HTTP/1.1 200 Connected\r\n\r\n"; | |
7237 | |
7238 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
7239 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); | |
7240 MockRead spdy_reads[] = { | |
7241 MockRead(ASYNC, kCONNECTResponse, arraysize(kCONNECTResponse) - 1, 1), // 1 | |
7242 CreateMockRead(*resp.get(), 4), // 2, 4 | |
7243 CreateMockRead(*data.get(), 4), // 5 | |
7244 MockRead(ASYNC, 0, 0, 4), // 6 | |
7245 }; | |
7246 | |
7247 scoped_ptr<OrderedSocketData> spdy_data( | |
7248 new OrderedSocketData( | |
7249 spdy_reads, arraysize(spdy_reads), | |
7250 spdy_writes, arraysize(spdy_writes))); | |
7251 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
7252 | |
7253 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); | |
7254 StaticSocketDataProvider hanging_non_alternate_protocol_socket( | |
7255 NULL, 0, NULL, 0); | |
7256 hanging_non_alternate_protocol_socket.set_connect_data( | |
7257 never_finishing_connect); | |
7258 session_deps.socket_factory.AddSocketDataProvider( | |
7259 &hanging_non_alternate_protocol_socket); | |
7260 | |
7261 TestCompletionCallback callback; | |
7262 | |
7263 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
7264 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); | |
7265 | |
7266 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
7267 EXPECT_EQ(ERR_IO_PENDING, rv); | |
7268 EXPECT_EQ(OK, callback.WaitForResult()); | |
7269 | |
7270 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
7271 ASSERT_TRUE(response != NULL); | |
7272 ASSERT_TRUE(response->headers != NULL); | |
7273 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
7274 EXPECT_FALSE(response->was_fetched_via_spdy); | |
7275 EXPECT_FALSE(response->was_npn_negotiated); | |
7276 | |
7277 std::string response_data; | |
7278 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
7279 EXPECT_EQ("hello world", response_data); | |
7280 | |
7281 trans.reset(new HttpNetworkTransaction(session)); | |
7282 | |
7283 rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
7284 EXPECT_EQ(ERR_IO_PENDING, rv); | |
7285 EXPECT_EQ(OK, callback.WaitForResult()); | |
7286 | |
7287 response = trans->GetResponseInfo(); | |
7288 ASSERT_TRUE(response != NULL); | |
7289 ASSERT_TRUE(response->headers != NULL); | |
7290 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
7291 EXPECT_TRUE(response->was_fetched_via_spdy); | |
7292 EXPECT_TRUE(response->was_npn_negotiated); | |
7293 | |
7294 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
7295 EXPECT_EQ("hello!", response_data); | |
7296 ASSERT_EQ(3u, capturing_proxy_resolver->resolved().size()); | |
7297 EXPECT_EQ("http://www.google.com/", | |
7298 capturing_proxy_resolver->resolved()[0].spec()); | |
7299 EXPECT_EQ("https://www.google.com/", | |
7300 capturing_proxy_resolver->resolved()[1].spec()); | |
7301 | |
7302 HttpStreamFactory::SetNextProtos(std::vector<std::string>()); | |
7303 HttpStreamFactory::set_use_alternate_protocols(false); | |
7304 } | |
7305 | |
7306 TEST_F(HttpNetworkTransactionTest, | |
7307 UseAlternateProtocolForNpnSpdyWithExistingSpdySession) { | |
7308 HttpStreamFactory::set_use_alternate_protocols(true); | |
7309 HttpStreamFactory::SetNextProtos(SpdyNextProtos()); | |
7310 SessionDependencies session_deps; | |
7311 | |
7312 HttpRequestInfo request; | |
7313 request.method = "GET"; | |
7314 request.url = GURL("http://www.google.com/"); | |
7315 request.load_flags = 0; | |
7316 | |
7317 MockRead data_reads[] = { | |
7318 MockRead("HTTP/1.1 200 OK\r\n"), | |
7319 MockRead(kAlternateProtocolHttpHeader), | |
7320 MockRead("hello world"), | |
7321 MockRead(ASYNC, OK), | |
7322 }; | |
7323 | |
7324 StaticSocketDataProvider first_transaction( | |
7325 data_reads, arraysize(data_reads), NULL, 0); | |
7326 session_deps.socket_factory.AddSocketDataProvider(&first_transaction); | |
7327 | |
7328 SSLSocketDataProvider ssl(ASYNC, OK); | |
7329 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
7330 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
7331 // Make sure we use ssl for spdy here. | |
7332 SpdySession::SetSSLMode(true); | |
7333 | |
7334 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
7335 MockWrite spdy_writes[] = { CreateMockWrite(*req) }; | |
7336 | |
7337 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
7338 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); | |
7339 MockRead spdy_reads[] = { | |
7340 CreateMockRead(*resp), | |
7341 CreateMockRead(*data), | |
7342 MockRead(ASYNC, 0, 0), | |
7343 }; | |
7344 | |
7345 scoped_ptr<DelayedSocketData> spdy_data( | |
7346 new DelayedSocketData( | |
7347 1, // wait for one write to finish before reading. | |
7348 spdy_reads, arraysize(spdy_reads), | |
7349 spdy_writes, arraysize(spdy_writes))); | |
7350 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
7351 | |
7352 TestCompletionCallback callback; | |
7353 | |
7354 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
7355 | |
7356 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); | |
7357 | |
7358 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
7359 EXPECT_EQ(ERR_IO_PENDING, rv); | |
7360 EXPECT_EQ(OK, callback.WaitForResult()); | |
7361 | |
7362 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
7363 ASSERT_TRUE(response != NULL); | |
7364 ASSERT_TRUE(response->headers != NULL); | |
7365 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
7366 | |
7367 std::string response_data; | |
7368 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
7369 EXPECT_EQ("hello world", response_data); | |
7370 | |
7371 // Set up an initial SpdySession in the pool to reuse. | |
7372 HostPortPair host_port_pair("www.google.com", 443); | |
7373 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct()); | |
7374 scoped_refptr<SpdySession> spdy_session = | |
7375 session->spdy_session_pool()->Get(pair, BoundNetLog()); | |
7376 scoped_refptr<TransportSocketParams> transport_params( | |
7377 new TransportSocketParams(host_port_pair, MEDIUM, false, false)); | |
7378 | |
7379 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); | |
7380 EXPECT_EQ(ERR_IO_PENDING, | |
7381 connection->Init(host_port_pair.ToString(), | |
7382 transport_params, | |
7383 LOWEST, | |
7384 callback.callback(), | |
7385 session->GetTransportSocketPool(), | |
7386 BoundNetLog())); | |
7387 EXPECT_EQ(OK, callback.WaitForResult()); | |
7388 | |
7389 SSLConfig ssl_config; | |
7390 session->ssl_config_service()->GetSSLConfig(&ssl_config); | |
7391 scoped_ptr<ClientSocketHandle> ssl_connection(new ClientSocketHandle); | |
7392 SSLClientSocketContext context; | |
7393 context.cert_verifier = session_deps.cert_verifier.get(); | |
7394 ssl_connection->set_socket(session_deps.socket_factory.CreateSSLClientSocket( | |
7395 connection.release(), HostPortPair("" , 443), ssl_config, | |
7396 NULL /* ssl_host_info */, context)); | |
7397 EXPECT_EQ(ERR_IO_PENDING, | |
7398 ssl_connection->socket()->Connect(callback.callback())); | |
7399 EXPECT_EQ(OK, callback.WaitForResult()); | |
7400 | |
7401 EXPECT_EQ(OK, spdy_session->InitializeWithSocket(ssl_connection.release(), | |
7402 true, OK)); | |
7403 | |
7404 trans.reset(new HttpNetworkTransaction(session)); | |
7405 | |
7406 rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
7407 EXPECT_EQ(ERR_IO_PENDING, rv); | |
7408 EXPECT_EQ(OK, callback.WaitForResult()); | |
7409 | |
7410 response = trans->GetResponseInfo(); | |
7411 ASSERT_TRUE(response != NULL); | |
7412 ASSERT_TRUE(response->headers != NULL); | |
7413 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
7414 EXPECT_TRUE(response->was_fetched_via_spdy); | |
7415 EXPECT_TRUE(response->was_npn_negotiated); | |
7416 | |
7417 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
7418 EXPECT_EQ("hello!", response_data); | |
7419 | |
7420 HttpStreamFactory::SetNextProtos(std::vector<std::string>()); | |
7421 HttpStreamFactory::set_use_alternate_protocols(false); | |
7422 } | |
7423 | |
7424 // GenerateAuthToken is a mighty big test. | |
7425 // It tests all permutation of GenerateAuthToken behavior: | |
7426 // - Synchronous and Asynchronous completion. | |
7427 // - OK or error on completion. | |
7428 // - Direct connection, non-authenticating proxy, and authenticating proxy. | |
7429 // - HTTP or HTTPS backend (to include proxy tunneling). | |
7430 // - Non-authenticating and authenticating backend. | |
7431 // | |
7432 // In all, there are 44 reasonable permuations (for example, if there are | |
7433 // problems generating an auth token for an authenticating proxy, we don't | |
7434 // need to test all permutations of the backend server). | |
7435 // | |
7436 // The test proceeds by going over each of the configuration cases, and | |
7437 // potentially running up to three rounds in each of the tests. The TestConfig | |
7438 // specifies both the configuration for the test as well as the expectations | |
7439 // for the results. | |
7440 TEST_F(HttpNetworkTransactionTest, GenerateAuthToken) { | |
7441 static const char kServer[] = "http://www.example.com"; | |
7442 static const char kSecureServer[] = "https://www.example.com"; | |
7443 static const char kProxy[] = "myproxy:70"; | |
7444 const int kAuthErr = ERR_INVALID_AUTH_CREDENTIALS; | |
7445 | |
7446 enum AuthTiming { | |
7447 AUTH_NONE, | |
7448 AUTH_SYNC, | |
7449 AUTH_ASYNC, | |
7450 }; | |
7451 | |
7452 const MockWrite kGet( | |
7453 "GET / HTTP/1.1\r\n" | |
7454 "Host: www.example.com\r\n" | |
7455 "Connection: keep-alive\r\n\r\n"); | |
7456 const MockWrite kGetProxy( | |
7457 "GET http://www.example.com/ HTTP/1.1\r\n" | |
7458 "Host: www.example.com\r\n" | |
7459 "Proxy-Connection: keep-alive\r\n\r\n"); | |
7460 const MockWrite kGetAuth( | |
7461 "GET / HTTP/1.1\r\n" | |
7462 "Host: www.example.com\r\n" | |
7463 "Connection: keep-alive\r\n" | |
7464 "Authorization: auth_token\r\n\r\n"); | |
7465 const MockWrite kGetProxyAuth( | |
7466 "GET http://www.example.com/ HTTP/1.1\r\n" | |
7467 "Host: www.example.com\r\n" | |
7468 "Proxy-Connection: keep-alive\r\n" | |
7469 "Proxy-Authorization: auth_token\r\n\r\n"); | |
7470 const MockWrite kGetAuthThroughProxy( | |
7471 "GET http://www.example.com/ HTTP/1.1\r\n" | |
7472 "Host: www.example.com\r\n" | |
7473 "Proxy-Connection: keep-alive\r\n" | |
7474 "Authorization: auth_token\r\n\r\n"); | |
7475 const MockWrite kGetAuthWithProxyAuth( | |
7476 "GET http://www.example.com/ HTTP/1.1\r\n" | |
7477 "Host: www.example.com\r\n" | |
7478 "Proxy-Connection: keep-alive\r\n" | |
7479 "Proxy-Authorization: auth_token\r\n" | |
7480 "Authorization: auth_token\r\n\r\n"); | |
7481 const MockWrite kConnect( | |
7482 "CONNECT www.example.com:443 HTTP/1.1\r\n" | |
7483 "Host: www.example.com\r\n" | |
7484 "Proxy-Connection: keep-alive\r\n\r\n"); | |
7485 const MockWrite kConnectProxyAuth( | |
7486 "CONNECT www.example.com:443 HTTP/1.1\r\n" | |
7487 "Host: www.example.com\r\n" | |
7488 "Proxy-Connection: keep-alive\r\n" | |
7489 "Proxy-Authorization: auth_token\r\n\r\n"); | |
7490 | |
7491 const MockRead kSuccess( | |
7492 "HTTP/1.1 200 OK\r\n" | |
7493 "Content-Type: text/html; charset=iso-8859-1\r\n" | |
7494 "Content-Length: 3\r\n\r\n" | |
7495 "Yes"); | |
7496 const MockRead kFailure( | |
7497 "Should not be called."); | |
7498 const MockRead kServerChallenge( | |
7499 "HTTP/1.1 401 Unauthorized\r\n" | |
7500 "WWW-Authenticate: Mock realm=server\r\n" | |
7501 "Content-Type: text/html; charset=iso-8859-1\r\n" | |
7502 "Content-Length: 14\r\n\r\n" | |
7503 "Unauthorized\r\n"); | |
7504 const MockRead kProxyChallenge( | |
7505 "HTTP/1.1 407 Unauthorized\r\n" | |
7506 "Proxy-Authenticate: Mock realm=proxy\r\n" | |
7507 "Proxy-Connection: close\r\n" | |
7508 "Content-Type: text/html; charset=iso-8859-1\r\n" | |
7509 "Content-Length: 14\r\n\r\n" | |
7510 "Unauthorized\r\n"); | |
7511 const MockRead kProxyConnected( | |
7512 "HTTP/1.1 200 Connection Established\r\n\r\n"); | |
7513 | |
7514 // NOTE(cbentzel): I wanted TestReadWriteRound to be a simple struct with | |
7515 // no constructors, but the C++ compiler on Windows warns about | |
7516 // unspecified data in compound literals. So, moved to using constructors, | |
7517 // and TestRound's created with the default constructor should not be used. | |
7518 struct TestRound { | |
7519 TestRound() | |
7520 : expected_rv(ERR_UNEXPECTED), | |
7521 extra_write(NULL), | |
7522 extra_read(NULL) { | |
7523 } | |
7524 TestRound(const MockWrite& write_arg, const MockRead& read_arg, | |
7525 int expected_rv_arg) | |
7526 : write(write_arg), | |
7527 read(read_arg), | |
7528 expected_rv(expected_rv_arg), | |
7529 extra_write(NULL), | |
7530 extra_read(NULL) { | |
7531 } | |
7532 TestRound(const MockWrite& write_arg, const MockRead& read_arg, | |
7533 int expected_rv_arg, const MockWrite* extra_write_arg, | |
7534 const MockWrite* extra_read_arg) | |
7535 : write(write_arg), | |
7536 read(read_arg), | |
7537 expected_rv(expected_rv_arg), | |
7538 extra_write(extra_write_arg), | |
7539 extra_read(extra_read_arg) { | |
7540 } | |
7541 MockWrite write; | |
7542 MockRead read; | |
7543 int expected_rv; | |
7544 const MockWrite* extra_write; | |
7545 const MockRead* extra_read; | |
7546 }; | |
7547 | |
7548 static const int kNoSSL = 500; | |
7549 | |
7550 struct TestConfig { | |
7551 const char* proxy_url; | |
7552 AuthTiming proxy_auth_timing; | |
7553 int proxy_auth_rv; | |
7554 const char* server_url; | |
7555 AuthTiming server_auth_timing; | |
7556 int server_auth_rv; | |
7557 int num_auth_rounds; | |
7558 int first_ssl_round; | |
7559 TestRound rounds[3]; | |
7560 } test_configs[] = { | |
7561 // Non-authenticating HTTP server with a direct connection. | |
7562 { NULL, AUTH_NONE, OK, kServer, AUTH_NONE, OK, 1, kNoSSL, | |
7563 { TestRound(kGet, kSuccess, OK)}}, | |
7564 // Authenticating HTTP server with a direct connection. | |
7565 { NULL, AUTH_NONE, OK, kServer, AUTH_SYNC, OK, 2, kNoSSL, | |
7566 { TestRound(kGet, kServerChallenge, OK), | |
7567 TestRound(kGetAuth, kSuccess, OK)}}, | |
7568 { NULL, AUTH_NONE, OK, kServer, AUTH_SYNC, kAuthErr, 2, kNoSSL, | |
7569 { TestRound(kGet, kServerChallenge, OK), | |
7570 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
7571 { NULL, AUTH_NONE, OK, kServer, AUTH_ASYNC, OK, 2, kNoSSL, | |
7572 { TestRound(kGet, kServerChallenge, OK), | |
7573 TestRound(kGetAuth, kSuccess, OK)}}, | |
7574 { NULL, AUTH_NONE, OK, kServer, AUTH_ASYNC, kAuthErr, 2, kNoSSL, | |
7575 { TestRound(kGet, kServerChallenge, OK), | |
7576 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
7577 // Non-authenticating HTTP server through a non-authenticating proxy. | |
7578 { kProxy, AUTH_NONE, OK, kServer, AUTH_NONE, OK, 1, kNoSSL, | |
7579 { TestRound(kGetProxy, kSuccess, OK)}}, | |
7580 // Authenticating HTTP server through a non-authenticating proxy. | |
7581 { kProxy, AUTH_NONE, OK, kServer, AUTH_SYNC, OK, 2, kNoSSL, | |
7582 { TestRound(kGetProxy, kServerChallenge, OK), | |
7583 TestRound(kGetAuthThroughProxy, kSuccess, OK)}}, | |
7584 { kProxy, AUTH_NONE, OK, kServer, AUTH_SYNC, kAuthErr, 2, kNoSSL, | |
7585 { TestRound(kGetProxy, kServerChallenge, OK), | |
7586 TestRound(kGetAuthThroughProxy, kFailure, kAuthErr)}}, | |
7587 { kProxy, AUTH_NONE, OK, kServer, AUTH_ASYNC, OK, 2, kNoSSL, | |
7588 { TestRound(kGetProxy, kServerChallenge, OK), | |
7589 TestRound(kGetAuthThroughProxy, kSuccess, OK)}}, | |
7590 { kProxy, AUTH_NONE, OK, kServer, AUTH_ASYNC, kAuthErr, 2, kNoSSL, | |
7591 { TestRound(kGetProxy, kServerChallenge, OK), | |
7592 TestRound(kGetAuthThroughProxy, kFailure, kAuthErr)}}, | |
7593 // Non-authenticating HTTP server through an authenticating proxy. | |
7594 { kProxy, AUTH_SYNC, OK, kServer, AUTH_NONE, OK, 2, kNoSSL, | |
7595 { TestRound(kGetProxy, kProxyChallenge, OK), | |
7596 TestRound(kGetProxyAuth, kSuccess, OK)}}, | |
7597 { kProxy, AUTH_SYNC, kAuthErr, kServer, AUTH_NONE, OK, 2, kNoSSL, | |
7598 { TestRound(kGetProxy, kProxyChallenge, OK), | |
7599 TestRound(kGetProxyAuth, kFailure, kAuthErr)}}, | |
7600 { kProxy, AUTH_ASYNC, OK, kServer, AUTH_NONE, OK, 2, kNoSSL, | |
7601 { TestRound(kGetProxy, kProxyChallenge, OK), | |
7602 TestRound(kGetProxyAuth, kSuccess, OK)}}, | |
7603 { kProxy, AUTH_ASYNC, kAuthErr, kServer, AUTH_NONE, OK, 2, kNoSSL, | |
7604 { TestRound(kGetProxy, kProxyChallenge, OK), | |
7605 TestRound(kGetProxyAuth, kFailure, kAuthErr)}}, | |
7606 // Authenticating HTTP server through an authenticating proxy. | |
7607 { kProxy, AUTH_SYNC, OK, kServer, AUTH_SYNC, OK, 3, kNoSSL, | |
7608 { TestRound(kGetProxy, kProxyChallenge, OK), | |
7609 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
7610 TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}}, | |
7611 { kProxy, AUTH_SYNC, OK, kServer, AUTH_SYNC, kAuthErr, 3, kNoSSL, | |
7612 { TestRound(kGetProxy, kProxyChallenge, OK), | |
7613 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
7614 TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}}, | |
7615 { kProxy, AUTH_ASYNC, OK, kServer, AUTH_SYNC, OK, 3, kNoSSL, | |
7616 { TestRound(kGetProxy, kProxyChallenge, OK), | |
7617 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
7618 TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}}, | |
7619 { kProxy, AUTH_ASYNC, OK, kServer, AUTH_SYNC, kAuthErr, 3, kNoSSL, | |
7620 { TestRound(kGetProxy, kProxyChallenge, OK), | |
7621 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
7622 TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}}, | |
7623 { kProxy, AUTH_SYNC, OK, kServer, AUTH_ASYNC, OK, 3, kNoSSL, | |
7624 { TestRound(kGetProxy, kProxyChallenge, OK), | |
7625 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
7626 TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}}, | |
7627 { kProxy, AUTH_SYNC, OK, kServer, AUTH_ASYNC, kAuthErr, 3, kNoSSL, | |
7628 { TestRound(kGetProxy, kProxyChallenge, OK), | |
7629 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
7630 TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}}, | |
7631 { kProxy, AUTH_ASYNC, OK, kServer, AUTH_ASYNC, OK, 3, kNoSSL, | |
7632 { TestRound(kGetProxy, kProxyChallenge, OK), | |
7633 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
7634 TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}}, | |
7635 { kProxy, AUTH_ASYNC, OK, kServer, AUTH_ASYNC, kAuthErr, 3, kNoSSL, | |
7636 { TestRound(kGetProxy, kProxyChallenge, OK), | |
7637 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
7638 TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}}, | |
7639 // Non-authenticating HTTPS server with a direct connection. | |
7640 { NULL, AUTH_NONE, OK, kSecureServer, AUTH_NONE, OK, 1, 0, | |
7641 { TestRound(kGet, kSuccess, OK)}}, | |
7642 // Authenticating HTTPS server with a direct connection. | |
7643 { NULL, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, OK, 2, 0, | |
7644 { TestRound(kGet, kServerChallenge, OK), | |
7645 TestRound(kGetAuth, kSuccess, OK)}}, | |
7646 { NULL, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, kAuthErr, 2, 0, | |
7647 { TestRound(kGet, kServerChallenge, OK), | |
7648 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
7649 { NULL, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, OK, 2, 0, | |
7650 { TestRound(kGet, kServerChallenge, OK), | |
7651 TestRound(kGetAuth, kSuccess, OK)}}, | |
7652 { NULL, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 2, 0, | |
7653 { TestRound(kGet, kServerChallenge, OK), | |
7654 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
7655 // Non-authenticating HTTPS server with a non-authenticating proxy. | |
7656 { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_NONE, OK, 1, 0, | |
7657 { TestRound(kConnect, kProxyConnected, OK, &kGet, &kSuccess)}}, | |
7658 // Authenticating HTTPS server through a non-authenticating proxy. | |
7659 { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, OK, 2, 0, | |
7660 { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge), | |
7661 TestRound(kGetAuth, kSuccess, OK)}}, | |
7662 { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, kAuthErr, 2, 0, | |
7663 { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge), | |
7664 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
7665 { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, OK, 2, 0, | |
7666 { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge), | |
7667 TestRound(kGetAuth, kSuccess, OK)}}, | |
7668 { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 2, 0, | |
7669 { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge), | |
7670 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
7671 // Non-Authenticating HTTPS server through an authenticating proxy. | |
7672 { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_NONE, OK, 2, 1, | |
7673 { TestRound(kConnect, kProxyChallenge, OK), | |
7674 TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet, &kSuccess)}}, | |
7675 { kProxy, AUTH_SYNC, kAuthErr, kSecureServer, AUTH_NONE, OK, 2, kNoSSL, | |
7676 { TestRound(kConnect, kProxyChallenge, OK), | |
7677 TestRound(kConnectProxyAuth, kFailure, kAuthErr)}}, | |
7678 { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_NONE, OK, 2, 1, | |
7679 { TestRound(kConnect, kProxyChallenge, OK), | |
7680 TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet, &kSuccess)}}, | |
7681 { kProxy, AUTH_ASYNC, kAuthErr, kSecureServer, AUTH_NONE, OK, 2, kNoSSL, | |
7682 { TestRound(kConnect, kProxyChallenge, OK), | |
7683 TestRound(kConnectProxyAuth, kFailure, kAuthErr)}}, | |
7684 // Authenticating HTTPS server through an authenticating proxy. | |
7685 { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_SYNC, OK, 3, 1, | |
7686 { TestRound(kConnect, kProxyChallenge, OK), | |
7687 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
7688 &kGet, &kServerChallenge), | |
7689 TestRound(kGetAuth, kSuccess, OK)}}, | |
7690 { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_SYNC, kAuthErr, 3, 1, | |
7691 { TestRound(kConnect, kProxyChallenge, OK), | |
7692 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
7693 &kGet, &kServerChallenge), | |
7694 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
7695 { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_SYNC, OK, 3, 1, | |
7696 { TestRound(kConnect, kProxyChallenge, OK), | |
7697 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
7698 &kGet, &kServerChallenge), | |
7699 TestRound(kGetAuth, kSuccess, OK)}}, | |
7700 { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_SYNC, kAuthErr, 3, 1, | |
7701 { TestRound(kConnect, kProxyChallenge, OK), | |
7702 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
7703 &kGet, &kServerChallenge), | |
7704 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
7705 { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_ASYNC, OK, 3, 1, | |
7706 { TestRound(kConnect, kProxyChallenge, OK), | |
7707 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
7708 &kGet, &kServerChallenge), | |
7709 TestRound(kGetAuth, kSuccess, OK)}}, | |
7710 { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 3, 1, | |
7711 { TestRound(kConnect, kProxyChallenge, OK), | |
7712 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
7713 &kGet, &kServerChallenge), | |
7714 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
7715 { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_ASYNC, OK, 3, 1, | |
7716 { TestRound(kConnect, kProxyChallenge, OK), | |
7717 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
7718 &kGet, &kServerChallenge), | |
7719 TestRound(kGetAuth, kSuccess, OK)}}, | |
7720 { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 3, 1, | |
7721 { TestRound(kConnect, kProxyChallenge, OK), | |
7722 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
7723 &kGet, &kServerChallenge), | |
7724 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
7725 }; | |
7726 | |
7727 SessionDependencies session_deps; | |
7728 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_configs); ++i) { | |
7729 HttpAuthHandlerMock::Factory* auth_factory( | |
7730 new HttpAuthHandlerMock::Factory()); | |
7731 session_deps.http_auth_handler_factory.reset(auth_factory); | |
7732 const TestConfig& test_config = test_configs[i]; | |
7733 | |
7734 // Set up authentication handlers as necessary. | |
7735 if (test_config.proxy_auth_timing != AUTH_NONE) { | |
7736 for (int n = 0; n < 2; n++) { | |
7737 HttpAuthHandlerMock* auth_handler(new HttpAuthHandlerMock()); | |
7738 std::string auth_challenge = "Mock realm=proxy"; | |
7739 GURL origin(test_config.proxy_url); | |
7740 HttpAuth::ChallengeTokenizer tokenizer(auth_challenge.begin(), | |
7741 auth_challenge.end()); | |
7742 auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_PROXY, | |
7743 origin, BoundNetLog()); | |
7744 auth_handler->SetGenerateExpectation( | |
7745 test_config.proxy_auth_timing == AUTH_ASYNC, | |
7746 test_config.proxy_auth_rv); | |
7747 auth_factory->AddMockHandler(auth_handler, HttpAuth::AUTH_PROXY); | |
7748 } | |
7749 } | |
7750 if (test_config.server_auth_timing != AUTH_NONE) { | |
7751 HttpAuthHandlerMock* auth_handler(new HttpAuthHandlerMock()); | |
7752 std::string auth_challenge = "Mock realm=server"; | |
7753 GURL origin(test_config.server_url); | |
7754 HttpAuth::ChallengeTokenizer tokenizer(auth_challenge.begin(), | |
7755 auth_challenge.end()); | |
7756 auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_SERVER, | |
7757 origin, BoundNetLog()); | |
7758 auth_handler->SetGenerateExpectation( | |
7759 test_config.server_auth_timing == AUTH_ASYNC, | |
7760 test_config.server_auth_rv); | |
7761 auth_factory->AddMockHandler(auth_handler, HttpAuth::AUTH_SERVER); | |
7762 } | |
7763 if (test_config.proxy_url) { | |
7764 session_deps.proxy_service.reset( | |
7765 ProxyService::CreateFixed(test_config.proxy_url)); | |
7766 } else { | |
7767 session_deps.proxy_service.reset(ProxyService::CreateDirect()); | |
7768 } | |
7769 | |
7770 HttpRequestInfo request; | |
7771 request.method = "GET"; | |
7772 request.url = GURL(test_config.server_url); | |
7773 request.load_flags = 0; | |
7774 | |
7775 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
7776 HttpNetworkTransaction trans(CreateSession(&session_deps)); | |
7777 | |
7778 for (int round = 0; round < test_config.num_auth_rounds; ++round) { | |
7779 const TestRound& read_write_round = test_config.rounds[round]; | |
7780 | |
7781 // Set up expected reads and writes. | |
7782 MockRead reads[2]; | |
7783 reads[0] = read_write_round.read; | |
7784 size_t length_reads = 1; | |
7785 if (read_write_round.extra_read) { | |
7786 reads[1] = *read_write_round.extra_read; | |
7787 length_reads = 2; | |
7788 } | |
7789 | |
7790 MockWrite writes[2]; | |
7791 writes[0] = read_write_round.write; | |
7792 size_t length_writes = 1; | |
7793 if (read_write_round.extra_write) { | |
7794 writes[1] = *read_write_round.extra_write; | |
7795 length_writes = 2; | |
7796 } | |
7797 StaticSocketDataProvider data_provider( | |
7798 reads, length_reads, writes, length_writes); | |
7799 session_deps.socket_factory.AddSocketDataProvider(&data_provider); | |
7800 | |
7801 // Add an SSL sequence if necessary. | |
7802 SSLSocketDataProvider ssl_socket_data_provider(SYNCHRONOUS, OK); | |
7803 if (round >= test_config.first_ssl_round) | |
7804 session_deps.socket_factory.AddSSLSocketDataProvider( | |
7805 &ssl_socket_data_provider); | |
7806 | |
7807 // Start or restart the transaction. | |
7808 TestCompletionCallback callback; | |
7809 int rv; | |
7810 if (round == 0) { | |
7811 rv = trans.Start(&request, callback.callback(), BoundNetLog()); | |
7812 } else { | |
7813 rv = trans.RestartWithAuth( | |
7814 AuthCredentials(kFoo, kBar), callback.callback()); | |
7815 } | |
7816 if (rv == ERR_IO_PENDING) | |
7817 rv = callback.WaitForResult(); | |
7818 | |
7819 // Compare results with expected data. | |
7820 EXPECT_EQ(read_write_round.expected_rv, rv); | |
7821 const HttpResponseInfo* response = trans.GetResponseInfo(); | |
7822 if (read_write_round.expected_rv == OK) { | |
7823 ASSERT_TRUE(response != NULL); | |
7824 } else { | |
7825 EXPECT_TRUE(response == NULL); | |
7826 EXPECT_EQ(round + 1, test_config.num_auth_rounds); | |
7827 continue; | |
7828 } | |
7829 if (round + 1 < test_config.num_auth_rounds) { | |
7830 EXPECT_FALSE(response->auth_challenge.get() == NULL); | |
7831 } else { | |
7832 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
7833 } | |
7834 } | |
7835 } | |
7836 } | |
7837 | |
7838 TEST_F(HttpNetworkTransactionTest, MultiRoundAuth) { | |
7839 // Do multi-round authentication and make sure it works correctly. | |
7840 SessionDependencies session_deps; | |
7841 HttpAuthHandlerMock::Factory* auth_factory( | |
7842 new HttpAuthHandlerMock::Factory()); | |
7843 session_deps.http_auth_handler_factory.reset(auth_factory); | |
7844 session_deps.proxy_service.reset(ProxyService::CreateDirect()); | |
7845 session_deps.host_resolver->rules()->AddRule("www.example.com", "10.0.0.1"); | |
7846 session_deps.host_resolver->set_synchronous_mode(true); | |
7847 | |
7848 HttpAuthHandlerMock* auth_handler(new HttpAuthHandlerMock()); | |
7849 auth_handler->set_connection_based(true); | |
7850 std::string auth_challenge = "Mock realm=server"; | |
7851 GURL origin("http://www.example.com"); | |
7852 HttpAuth::ChallengeTokenizer tokenizer(auth_challenge.begin(), | |
7853 auth_challenge.end()); | |
7854 auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_SERVER, | |
7855 origin, BoundNetLog()); | |
7856 auth_factory->AddMockHandler(auth_handler, HttpAuth::AUTH_SERVER); | |
7857 | |
7858 int rv = OK; | |
7859 const HttpResponseInfo* response = NULL; | |
7860 HttpRequestInfo request; | |
7861 request.method = "GET"; | |
7862 request.url = origin; | |
7863 request.load_flags = 0; | |
7864 | |
7865 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
7866 | |
7867 // Use a TCP Socket Pool with only one connection per group. This is used | |
7868 // to validate that the TCP socket is not released to the pool between | |
7869 // each round of multi-round authentication. | |
7870 HttpNetworkSessionPeer session_peer(session); | |
7871 ClientSocketPoolHistograms transport_pool_histograms("SmallTCP"); | |
7872 TransportClientSocketPool* transport_pool = new TransportClientSocketPool( | |
7873 50, // Max sockets for pool | |
7874 1, // Max sockets per group | |
7875 &transport_pool_histograms, | |
7876 session_deps.host_resolver.get(), | |
7877 &session_deps.socket_factory, | |
7878 session_deps.net_log); | |
7879 MockClientSocketPoolManager* mock_pool_manager = | |
7880 new MockClientSocketPoolManager; | |
7881 mock_pool_manager->SetTransportSocketPool(transport_pool); | |
7882 session_peer.SetClientSocketPoolManager(mock_pool_manager); | |
7883 | |
7884 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
7885 TestCompletionCallback callback; | |
7886 | |
7887 const MockWrite kGet( | |
7888 "GET / HTTP/1.1\r\n" | |
7889 "Host: www.example.com\r\n" | |
7890 "Connection: keep-alive\r\n\r\n"); | |
7891 const MockWrite kGetAuth( | |
7892 "GET / HTTP/1.1\r\n" | |
7893 "Host: www.example.com\r\n" | |
7894 "Connection: keep-alive\r\n" | |
7895 "Authorization: auth_token\r\n\r\n"); | |
7896 | |
7897 const MockRead kServerChallenge( | |
7898 "HTTP/1.1 401 Unauthorized\r\n" | |
7899 "WWW-Authenticate: Mock realm=server\r\n" | |
7900 "Content-Type: text/html; charset=iso-8859-1\r\n" | |
7901 "Content-Length: 14\r\n\r\n" | |
7902 "Unauthorized\r\n"); | |
7903 const MockRead kSuccess( | |
7904 "HTTP/1.1 200 OK\r\n" | |
7905 "Content-Type: text/html; charset=iso-8859-1\r\n" | |
7906 "Content-Length: 3\r\n\r\n" | |
7907 "Yes"); | |
7908 | |
7909 MockWrite writes[] = { | |
7910 // First round | |
7911 kGet, | |
7912 // Second round | |
7913 kGetAuth, | |
7914 // Third round | |
7915 kGetAuth, | |
7916 // Fourth round | |
7917 kGetAuth, | |
7918 // Competing request | |
7919 kGet, | |
7920 }; | |
7921 MockRead reads[] = { | |
7922 // First round | |
7923 kServerChallenge, | |
7924 // Second round | |
7925 kServerChallenge, | |
7926 // Third round | |
7927 kServerChallenge, | |
7928 // Fourth round | |
7929 kSuccess, | |
7930 // Competing response | |
7931 kSuccess, | |
7932 }; | |
7933 StaticSocketDataProvider data_provider(reads, arraysize(reads), | |
7934 writes, arraysize(writes)); | |
7935 session_deps.socket_factory.AddSocketDataProvider(&data_provider); | |
7936 | |
7937 const char* const kSocketGroup = "www.example.com:80"; | |
7938 | |
7939 // First round of authentication. | |
7940 auth_handler->SetGenerateExpectation(false, OK); | |
7941 rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
7942 if (rv == ERR_IO_PENDING) | |
7943 rv = callback.WaitForResult(); | |
7944 EXPECT_EQ(OK, rv); | |
7945 response = trans->GetResponseInfo(); | |
7946 ASSERT_TRUE(response != NULL); | |
7947 EXPECT_FALSE(response->auth_challenge.get() == NULL); | |
7948 EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); | |
7949 | |
7950 // In between rounds, another request comes in for the same domain. | |
7951 // It should not be able to grab the TCP socket that trans has already | |
7952 // claimed. | |
7953 scoped_ptr<HttpTransaction> trans_compete( | |
7954 new HttpNetworkTransaction(session)); | |
7955 TestCompletionCallback callback_compete; | |
7956 rv = trans_compete->Start( | |
7957 &request, callback_compete.callback(), BoundNetLog()); | |
7958 EXPECT_EQ(ERR_IO_PENDING, rv); | |
7959 // callback_compete.WaitForResult at this point would stall forever, | |
7960 // since the HttpNetworkTransaction does not release the request back to | |
7961 // the pool until after authentication completes. | |
7962 | |
7963 // Second round of authentication. | |
7964 auth_handler->SetGenerateExpectation(false, OK); | |
7965 rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar), callback.callback()); | |
7966 if (rv == ERR_IO_PENDING) | |
7967 rv = callback.WaitForResult(); | |
7968 EXPECT_EQ(OK, rv); | |
7969 response = trans->GetResponseInfo(); | |
7970 ASSERT_TRUE(response != NULL); | |
7971 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
7972 EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); | |
7973 | |
7974 // Third round of authentication. | |
7975 auth_handler->SetGenerateExpectation(false, OK); | |
7976 rv = trans->RestartWithAuth(AuthCredentials(), callback.callback()); | |
7977 if (rv == ERR_IO_PENDING) | |
7978 rv = callback.WaitForResult(); | |
7979 EXPECT_EQ(OK, rv); | |
7980 response = trans->GetResponseInfo(); | |
7981 ASSERT_TRUE(response != NULL); | |
7982 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
7983 EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); | |
7984 | |
7985 // Fourth round of authentication, which completes successfully. | |
7986 auth_handler->SetGenerateExpectation(false, OK); | |
7987 rv = trans->RestartWithAuth(AuthCredentials(), callback.callback()); | |
7988 if (rv == ERR_IO_PENDING) | |
7989 rv = callback.WaitForResult(); | |
7990 EXPECT_EQ(OK, rv); | |
7991 response = trans->GetResponseInfo(); | |
7992 ASSERT_TRUE(response != NULL); | |
7993 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
7994 EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); | |
7995 | |
7996 // Read the body since the fourth round was successful. This will also | |
7997 // release the socket back to the pool. | |
7998 scoped_refptr<IOBufferWithSize> io_buf(new IOBufferWithSize(50)); | |
7999 rv = trans->Read(io_buf, io_buf->size(), callback.callback()); | |
8000 if (rv == ERR_IO_PENDING) | |
8001 rv = callback.WaitForResult(); | |
8002 EXPECT_EQ(3, rv); | |
8003 rv = trans->Read(io_buf, io_buf->size(), callback.callback()); | |
8004 EXPECT_EQ(0, rv); | |
8005 // There are still 0 idle sockets, since the trans_compete transaction | |
8006 // will be handed it immediately after trans releases it to the group. | |
8007 EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); | |
8008 | |
8009 // The competing request can now finish. Wait for the headers and then | |
8010 // read the body. | |
8011 rv = callback_compete.WaitForResult(); | |
8012 EXPECT_EQ(OK, rv); | |
8013 rv = trans_compete->Read(io_buf, io_buf->size(), callback.callback()); | |
8014 if (rv == ERR_IO_PENDING) | |
8015 rv = callback.WaitForResult(); | |
8016 EXPECT_EQ(3, rv); | |
8017 rv = trans_compete->Read(io_buf, io_buf->size(), callback.callback()); | |
8018 EXPECT_EQ(0, rv); | |
8019 | |
8020 // Finally, the socket is released to the group. | |
8021 EXPECT_EQ(1, transport_pool->IdleSocketCountInGroup(kSocketGroup)); | |
8022 } | |
8023 | |
8024 class TLSDecompressionFailureSocketDataProvider : public SocketDataProvider { | |
8025 public: | |
8026 explicit TLSDecompressionFailureSocketDataProvider(bool fail_all) | |
8027 : fail_all_(fail_all) { | |
8028 } | |
8029 | |
8030 virtual MockRead GetNextRead() { | |
8031 if (fail_all_) | |
8032 return MockRead(SYNCHRONOUS, ERR_SSL_DECOMPRESSION_FAILURE_ALERT); | |
8033 | |
8034 return MockRead(SYNCHRONOUS, | |
8035 "HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nok.\r\n"); | |
8036 } | |
8037 | |
8038 virtual MockWriteResult OnWrite(const std::string& data) { | |
8039 return MockWriteResult(SYNCHRONOUS /* async */, data.size()); | |
8040 } | |
8041 | |
8042 void Reset() { | |
8043 } | |
8044 | |
8045 private: | |
8046 const bool fail_all_; | |
8047 }; | |
8048 | |
8049 // Test that we restart a connection when we see a decompression failure from | |
8050 // the peer during the handshake. (In the real world we'll restart with SSLv3 | |
8051 // and we won't offer DEFLATE in that case.) | |
8052 TEST_F(HttpNetworkTransactionTest, RestartAfterTLSDecompressionFailure) { | |
8053 HttpRequestInfo request; | |
8054 request.method = "GET"; | |
8055 request.url = GURL("https://tlsdecompressionfailure.example.com/"); | |
8056 request.load_flags = 0; | |
8057 | |
8058 SessionDependencies session_deps; | |
8059 TLSDecompressionFailureSocketDataProvider socket_data_provider1( | |
8060 false /* fail all reads */); | |
8061 TLSDecompressionFailureSocketDataProvider socket_data_provider2(false); | |
8062 SSLSocketDataProvider ssl_socket_data_provider1( | |
8063 SYNCHRONOUS, ERR_SSL_DECOMPRESSION_FAILURE_ALERT); | |
8064 SSLSocketDataProvider ssl_socket_data_provider2(SYNCHRONOUS, OK); | |
8065 session_deps.socket_factory.AddSocketDataProvider(&socket_data_provider1); | |
8066 session_deps.socket_factory.AddSocketDataProvider(&socket_data_provider2); | |
8067 session_deps.socket_factory.AddSSLSocketDataProvider( | |
8068 &ssl_socket_data_provider1); | |
8069 session_deps.socket_factory.AddSSLSocketDataProvider( | |
8070 &ssl_socket_data_provider2); | |
8071 | |
8072 // Work around http://crbug.com/37454 | |
8073 StaticSocketDataProvider bug37454_connection; | |
8074 bug37454_connection.set_connect_data(MockConnect(ASYNC, ERR_UNEXPECTED)); | |
8075 session_deps.socket_factory.AddSocketDataProvider(&bug37454_connection); | |
8076 | |
8077 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
8078 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
8079 TestCompletionCallback callback; | |
8080 | |
8081 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
8082 EXPECT_EQ(ERR_IO_PENDING, rv); | |
8083 EXPECT_EQ(OK, callback.WaitForResult()); | |
8084 | |
8085 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
8086 ASSERT_TRUE(response != NULL); | |
8087 ASSERT_TRUE(response->headers != NULL); | |
8088 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
8089 | |
8090 std::string response_data; | |
8091 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
8092 EXPECT_EQ("ok.", response_data); | |
8093 } | |
8094 | |
8095 // Test that we restart a connection if we get a decompression failure from the | |
8096 // peer while reading the first bytes from the connection. This occurs when the | |
8097 // peer cannot handle DEFLATE but we're using False Start, so we don't notice | |
8098 // in the handshake. | |
8099 TEST_F(HttpNetworkTransactionTest, | |
8100 RestartAfterTLSDecompressionFailureWithFalseStart) { | |
8101 HttpRequestInfo request; | |
8102 request.method = "GET"; | |
8103 request.url = GURL("https://tlsdecompressionfailure2.example.com/"); | |
8104 request.load_flags = 0; | |
8105 | |
8106 SessionDependencies session_deps; | |
8107 TLSDecompressionFailureSocketDataProvider socket_data_provider1( | |
8108 true /* fail all reads */); | |
8109 TLSDecompressionFailureSocketDataProvider socket_data_provider2(false); | |
8110 SSLSocketDataProvider ssl_socket_data_provider1(SYNCHRONOUS, OK); | |
8111 SSLSocketDataProvider ssl_socket_data_provider2(SYNCHRONOUS, OK); | |
8112 session_deps.socket_factory.AddSocketDataProvider(&socket_data_provider1); | |
8113 session_deps.socket_factory.AddSocketDataProvider(&socket_data_provider2); | |
8114 session_deps.socket_factory.AddSSLSocketDataProvider( | |
8115 &ssl_socket_data_provider1); | |
8116 session_deps.socket_factory.AddSSLSocketDataProvider( | |
8117 &ssl_socket_data_provider2); | |
8118 | |
8119 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
8120 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
8121 TestCompletionCallback callback; | |
8122 | |
8123 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
8124 EXPECT_EQ(ERR_IO_PENDING, rv); | |
8125 EXPECT_EQ(OK, callback.WaitForResult()); | |
8126 | |
8127 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
8128 ASSERT_TRUE(response != NULL); | |
8129 ASSERT_TRUE(response->headers != NULL); | |
8130 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
8131 | |
8132 std::string response_data; | |
8133 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
8134 EXPECT_EQ("ok.", response_data); | |
8135 } | |
8136 | |
8137 // This tests the case that a request is issued via http instead of spdy after | |
8138 // npn is negotiated. | |
8139 TEST_F(HttpNetworkTransactionTest, NpnWithHttpOverSSL) { | |
8140 HttpStreamFactory::set_use_alternate_protocols(true); | |
8141 HttpStreamFactory::SetNextProtos( | |
8142 MakeNextProtos("http/1.1", "http1.1", NULL)); | |
8143 SessionDependencies session_deps; | |
8144 HttpRequestInfo request; | |
8145 request.method = "GET"; | |
8146 request.url = GURL("https://www.google.com/"); | |
8147 request.load_flags = 0; | |
8148 | |
8149 MockWrite data_writes[] = { | |
8150 MockWrite("GET / HTTP/1.1\r\n" | |
8151 "Host: www.google.com\r\n" | |
8152 "Connection: keep-alive\r\n\r\n"), | |
8153 }; | |
8154 | |
8155 MockRead data_reads[] = { | |
8156 MockRead("HTTP/1.1 200 OK\r\n"), | |
8157 MockRead(kAlternateProtocolHttpHeader), | |
8158 MockRead("hello world"), | |
8159 MockRead(SYNCHRONOUS, OK), | |
8160 }; | |
8161 | |
8162 SSLSocketDataProvider ssl(ASYNC, OK); | |
8163 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated; | |
8164 ssl.next_proto = "http/1.1"; | |
8165 ssl.protocol_negotiated = SSLClientSocket::kProtoHTTP11; | |
8166 | |
8167 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
8168 | |
8169 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
8170 data_writes, arraysize(data_writes)); | |
8171 session_deps.socket_factory.AddSocketDataProvider(&data); | |
8172 | |
8173 TestCompletionCallback callback; | |
8174 | |
8175 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
8176 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
8177 | |
8178 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
8179 | |
8180 EXPECT_EQ(ERR_IO_PENDING, rv); | |
8181 EXPECT_EQ(OK, callback.WaitForResult()); | |
8182 | |
8183 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
8184 ASSERT_TRUE(response != NULL); | |
8185 ASSERT_TRUE(response->headers != NULL); | |
8186 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
8187 | |
8188 std::string response_data; | |
8189 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
8190 EXPECT_EQ("hello world", response_data); | |
8191 | |
8192 EXPECT_FALSE(response->was_fetched_via_spdy); | |
8193 EXPECT_TRUE(response->was_npn_negotiated); | |
8194 | |
8195 HttpStreamFactory::SetNextProtos(std::vector<std::string>()); | |
8196 HttpStreamFactory::set_use_alternate_protocols(false); | |
8197 } | |
8198 | |
8199 TEST_F(HttpNetworkTransactionTest, SpdyPostNPNServerHangup) { | |
8200 // Simulate the SSL handshake completing with an NPN negotiation | |
8201 // followed by an immediate server closing of the socket. | |
8202 // Fix crash: http://crbug.com/46369 | |
8203 HttpStreamFactory::set_use_alternate_protocols(true); | |
8204 HttpStreamFactory::SetNextProtos(SpdyNextProtos()); | |
8205 SessionDependencies session_deps; | |
8206 | |
8207 HttpRequestInfo request; | |
8208 request.method = "GET"; | |
8209 request.url = GURL("https://www.google.com/"); | |
8210 request.load_flags = 0; | |
8211 | |
8212 SSLSocketDataProvider ssl(ASYNC, OK); | |
8213 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
8214 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
8215 | |
8216 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
8217 MockWrite spdy_writes[] = { CreateMockWrite(*req) }; | |
8218 | |
8219 MockRead spdy_reads[] = { | |
8220 MockRead(SYNCHRONOUS, 0, 0) // Not async - return 0 immediately. | |
8221 }; | |
8222 | |
8223 scoped_ptr<DelayedSocketData> spdy_data( | |
8224 new DelayedSocketData( | |
8225 0, // don't wait in this case, immediate hangup. | |
8226 spdy_reads, arraysize(spdy_reads), | |
8227 spdy_writes, arraysize(spdy_writes))); | |
8228 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
8229 | |
8230 TestCompletionCallback callback; | |
8231 | |
8232 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
8233 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); | |
8234 | |
8235 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
8236 EXPECT_EQ(ERR_IO_PENDING, rv); | |
8237 EXPECT_EQ(ERR_CONNECTION_CLOSED, callback.WaitForResult()); | |
8238 | |
8239 HttpStreamFactory::SetNextProtos(std::vector<std::string>()); | |
8240 HttpStreamFactory::set_use_alternate_protocols(false); | |
8241 } | |
8242 | |
8243 TEST_F(HttpNetworkTransactionTest, SpdyAlternateProtocolThroughProxy) { | |
8244 // This test ensures that the URL passed into the proxy is upgraded | |
8245 // to https when doing an Alternate Protocol upgrade. | |
8246 HttpStreamFactory::set_use_alternate_protocols(true); | |
8247 HttpStreamFactory::SetNextProtos( | |
8248 MakeNextProtos( | |
8249 "http/1.1", "http1.1", "spdy/2.1", "spdy/2", "spdy", NULL)); | |
8250 | |
8251 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
8252 HttpAuthHandlerMock::Factory* auth_factory = | |
8253 new HttpAuthHandlerMock::Factory(); | |
8254 HttpAuthHandlerMock* auth_handler = new HttpAuthHandlerMock(); | |
8255 auth_factory->AddMockHandler(auth_handler, HttpAuth::AUTH_PROXY); | |
8256 auth_factory->set_do_init_from_challenge(true); | |
8257 session_deps.http_auth_handler_factory.reset(auth_factory); | |
8258 | |
8259 HttpRequestInfo request; | |
8260 request.method = "GET"; | |
8261 request.url = GURL("http://www.google.com"); | |
8262 request.load_flags = 0; | |
8263 | |
8264 // First round goes unauthenticated through the proxy. | |
8265 MockWrite data_writes_1[] = { | |
8266 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
8267 "Host: www.google.com\r\n" | |
8268 "Proxy-Connection: keep-alive\r\n" | |
8269 "\r\n"), | |
8270 }; | |
8271 MockRead data_reads_1[] = { | |
8272 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), | |
8273 MockRead("HTTP/1.1 200 OK\r\n" | |
8274 "Alternate-Protocol: 443:npn-spdy/2.1\r\n" | |
8275 "Proxy-Connection: close\r\n" | |
8276 "\r\n"), | |
8277 }; | |
8278 StaticSocketDataProvider data_1(data_reads_1, arraysize(data_reads_1), | |
8279 data_writes_1, arraysize(data_writes_1)); | |
8280 | |
8281 // Second round tries to tunnel to www.google.com due to the | |
8282 // Alternate-Protocol announcement in the first round. It fails due | |
8283 // to a proxy authentication challenge. | |
8284 // After the failure, a tunnel is established to www.google.com using | |
8285 // Proxy-Authorization headers. There is then a SPDY request round. | |
8286 // | |
8287 // NOTE: Despite the "Proxy-Connection: Close", these are done on the | |
8288 // same MockTCPClientSocket since the underlying HttpNetworkClientSocket | |
8289 // does a Disconnect and Connect on the same socket, rather than trying | |
8290 // to obtain a new one. | |
8291 // | |
8292 // NOTE: Originally, the proxy response to the second CONNECT request | |
8293 // simply returned another 407 so the unit test could skip the SSL connection | |
8294 // establishment and SPDY framing issues. Alas, the | |
8295 // retry-http-when-alternate-protocol fails logic kicks in, which was more | |
8296 // complicated to set up expectations for than the SPDY session. | |
8297 | |
8298 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
8299 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
8300 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); | |
8301 | |
8302 MockWrite data_writes_2[] = { | |
8303 // First connection attempt without Proxy-Authorization. | |
8304 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
8305 "Host: www.google.com\r\n" | |
8306 "Proxy-Connection: keep-alive\r\n" | |
8307 "\r\n"), | |
8308 | |
8309 // Second connection attempt with Proxy-Authorization. | |
8310 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
8311 "Host: www.google.com\r\n" | |
8312 "Proxy-Connection: keep-alive\r\n" | |
8313 "Proxy-Authorization: auth_token\r\n" | |
8314 "\r\n"), | |
8315 | |
8316 // SPDY request | |
8317 CreateMockWrite(*req), | |
8318 }; | |
8319 const char kRejectConnectResponse[] = ("HTTP/1.1 407 Unauthorized\r\n" | |
8320 "Proxy-Authenticate: Mock\r\n" | |
8321 "Proxy-Connection: close\r\n" | |
8322 "\r\n"); | |
8323 const char kAcceptConnectResponse[] = "HTTP/1.1 200 Connected\r\n\r\n"; | |
8324 MockRead data_reads_2[] = { | |
8325 // First connection attempt fails | |
8326 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ, 1), | |
8327 MockRead(ASYNC, kRejectConnectResponse, | |
8328 arraysize(kRejectConnectResponse) - 1, 1), | |
8329 | |
8330 // Second connection attempt passes | |
8331 MockRead(ASYNC, kAcceptConnectResponse, | |
8332 arraysize(kAcceptConnectResponse) -1, 4), | |
8333 | |
8334 // SPDY response | |
8335 CreateMockRead(*resp.get(), 6), | |
8336 CreateMockRead(*data.get(), 6), | |
8337 MockRead(ASYNC, 0, 0, 6), | |
8338 }; | |
8339 scoped_ptr<OrderedSocketData> data_2( | |
8340 new OrderedSocketData(data_reads_2, arraysize(data_reads_2), | |
8341 data_writes_2, arraysize(data_writes_2))); | |
8342 | |
8343 SSLSocketDataProvider ssl(ASYNC, OK); | |
8344 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
8345 | |
8346 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); | |
8347 StaticSocketDataProvider hanging_non_alternate_protocol_socket( | |
8348 NULL, 0, NULL, 0); | |
8349 hanging_non_alternate_protocol_socket.set_connect_data( | |
8350 never_finishing_connect); | |
8351 | |
8352 session_deps.socket_factory.AddSocketDataProvider(&data_1); | |
8353 session_deps.socket_factory.AddSocketDataProvider(data_2.get()); | |
8354 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
8355 session_deps.socket_factory.AddSocketDataProvider( | |
8356 &hanging_non_alternate_protocol_socket); | |
8357 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
8358 | |
8359 // First round should work and provide the Alternate-Protocol state. | |
8360 TestCompletionCallback callback_1; | |
8361 scoped_ptr<HttpTransaction> trans_1(new HttpNetworkTransaction(session)); | |
8362 int rv = trans_1->Start(&request, callback_1.callback(), BoundNetLog()); | |
8363 EXPECT_EQ(ERR_IO_PENDING, rv); | |
8364 EXPECT_EQ(OK, callback_1.WaitForResult()); | |
8365 | |
8366 // Second round should attempt a tunnel connect and get an auth challenge. | |
8367 TestCompletionCallback callback_2; | |
8368 scoped_ptr<HttpTransaction> trans_2(new HttpNetworkTransaction(session)); | |
8369 rv = trans_2->Start(&request, callback_2.callback(), BoundNetLog()); | |
8370 EXPECT_EQ(ERR_IO_PENDING, rv); | |
8371 EXPECT_EQ(OK, callback_2.WaitForResult()); | |
8372 const HttpResponseInfo* response = trans_2->GetResponseInfo(); | |
8373 ASSERT_TRUE(response != NULL); | |
8374 ASSERT_FALSE(response->auth_challenge.get() == NULL); | |
8375 | |
8376 // Restart with auth. Tunnel should work and response received. | |
8377 TestCompletionCallback callback_3; | |
8378 rv = trans_2->RestartWithAuth( | |
8379 AuthCredentials(kFoo, kBar), callback_3.callback()); | |
8380 EXPECT_EQ(ERR_IO_PENDING, rv); | |
8381 EXPECT_EQ(OK, callback_3.WaitForResult()); | |
8382 | |
8383 // After all that work, these two lines (or actually, just the scheme) are | |
8384 // what this test is all about. Make sure it happens correctly. | |
8385 const GURL& request_url = auth_handler->request_url(); | |
8386 EXPECT_EQ("https", request_url.scheme()); | |
8387 EXPECT_EQ("www.google.com", request_url.host()); | |
8388 | |
8389 HttpStreamFactory::SetNextProtos(std::vector<std::string>()); | |
8390 HttpStreamFactory::set_use_alternate_protocols(false); | |
8391 } | |
8392 | |
8393 // Test that if we cancel the transaction as the connection is completing, that | |
8394 // everything tears down correctly. | |
8395 TEST_F(HttpNetworkTransactionTest, SimpleCancel) { | |
8396 // Setup everything about the connection to complete synchronously, so that | |
8397 // after calling HttpNetworkTransaction::Start, the only thing we're waiting | |
8398 // for is the callback from the HttpStreamRequest. | |
8399 // Then cancel the transaction. | |
8400 // Verify that we don't crash. | |
8401 MockConnect mock_connect(SYNCHRONOUS, OK); | |
8402 MockRead data_reads[] = { | |
8403 MockRead(SYNCHRONOUS, "HTTP/1.0 200 OK\r\n\r\n"), | |
8404 MockRead(SYNCHRONOUS, "hello world"), | |
8405 MockRead(SYNCHRONOUS, OK), | |
8406 }; | |
8407 | |
8408 HttpRequestInfo request; | |
8409 request.method = "GET"; | |
8410 request.url = GURL("http://www.google.com/"); | |
8411 request.load_flags = 0; | |
8412 | |
8413 SessionDependencies session_deps; | |
8414 session_deps.host_resolver->set_synchronous_mode(true); | |
8415 scoped_ptr<HttpTransaction> trans( | |
8416 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
8417 | |
8418 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
8419 data.set_connect_data(mock_connect); | |
8420 session_deps.socket_factory.AddSocketDataProvider(&data); | |
8421 | |
8422 TestCompletionCallback callback; | |
8423 | |
8424 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
8425 int rv = trans->Start(&request, callback.callback(), log.bound()); | |
8426 EXPECT_EQ(ERR_IO_PENDING, rv); | |
8427 trans.reset(); // Cancel the transaction here. | |
8428 | |
8429 MessageLoop::current()->RunAllPending(); | |
8430 } | |
8431 | |
8432 // Test a basic GET request through a proxy. | |
8433 TEST_F(HttpNetworkTransactionTest, ProxyGet) { | |
8434 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
8435 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
8436 session_deps.net_log = log.bound().net_log(); | |
8437 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
8438 | |
8439 HttpRequestInfo request; | |
8440 request.method = "GET"; | |
8441 request.url = GURL("http://www.google.com/"); | |
8442 | |
8443 MockWrite data_writes1[] = { | |
8444 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
8445 "Host: www.google.com\r\n" | |
8446 "Proxy-Connection: keep-alive\r\n\r\n"), | |
8447 }; | |
8448 | |
8449 MockRead data_reads1[] = { | |
8450 MockRead("HTTP/1.1 200 OK\r\n"), | |
8451 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
8452 MockRead("Content-Length: 100\r\n\r\n"), | |
8453 MockRead(SYNCHRONOUS, OK), | |
8454 }; | |
8455 | |
8456 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
8457 data_writes1, arraysize(data_writes1)); | |
8458 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
8459 | |
8460 TestCompletionCallback callback1; | |
8461 | |
8462 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
8463 | |
8464 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
8465 EXPECT_EQ(ERR_IO_PENDING, rv); | |
8466 | |
8467 rv = callback1.WaitForResult(); | |
8468 EXPECT_EQ(OK, rv); | |
8469 | |
8470 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
8471 ASSERT_TRUE(response != NULL); | |
8472 | |
8473 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
8474 EXPECT_EQ(200, response->headers->response_code()); | |
8475 EXPECT_EQ(100, response->headers->GetContentLength()); | |
8476 EXPECT_TRUE(response->was_fetched_via_proxy); | |
8477 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
8478 } | |
8479 | |
8480 // Test a basic HTTPS GET request through a proxy. | |
8481 TEST_F(HttpNetworkTransactionTest, ProxyTunnelGet) { | |
8482 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
8483 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
8484 session_deps.net_log = log.bound().net_log(); | |
8485 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
8486 | |
8487 HttpRequestInfo request; | |
8488 request.method = "GET"; | |
8489 request.url = GURL("https://www.google.com/"); | |
8490 | |
8491 // Since we have proxy, should try to establish tunnel. | |
8492 MockWrite data_writes1[] = { | |
8493 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
8494 "Host: www.google.com\r\n" | |
8495 "Proxy-Connection: keep-alive\r\n\r\n"), | |
8496 | |
8497 MockWrite("GET / HTTP/1.1\r\n" | |
8498 "Host: www.google.com\r\n" | |
8499 "Connection: keep-alive\r\n\r\n"), | |
8500 }; | |
8501 | |
8502 MockRead data_reads1[] = { | |
8503 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), | |
8504 | |
8505 MockRead("HTTP/1.1 200 OK\r\n"), | |
8506 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
8507 MockRead("Content-Length: 100\r\n\r\n"), | |
8508 MockRead(SYNCHRONOUS, OK), | |
8509 }; | |
8510 | |
8511 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
8512 data_writes1, arraysize(data_writes1)); | |
8513 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
8514 SSLSocketDataProvider ssl(ASYNC, OK); | |
8515 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
8516 | |
8517 TestCompletionCallback callback1; | |
8518 | |
8519 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
8520 | |
8521 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
8522 EXPECT_EQ(ERR_IO_PENDING, rv); | |
8523 | |
8524 rv = callback1.WaitForResult(); | |
8525 EXPECT_EQ(OK, rv); | |
8526 net::CapturingNetLog::EntryList entries; | |
8527 log.GetEntries(&entries); | |
8528 size_t pos = ExpectLogContainsSomewhere( | |
8529 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
8530 NetLog::PHASE_NONE); | |
8531 ExpectLogContainsSomewhere( | |
8532 entries, pos, | |
8533 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
8534 NetLog::PHASE_NONE); | |
8535 | |
8536 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
8537 ASSERT_TRUE(response != NULL); | |
8538 | |
8539 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
8540 EXPECT_EQ(200, response->headers->response_code()); | |
8541 EXPECT_EQ(100, response->headers->GetContentLength()); | |
8542 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
8543 EXPECT_TRUE(response->was_fetched_via_proxy); | |
8544 } | |
8545 | |
8546 // Test a basic HTTPS GET request through a proxy, but the server hangs up | |
8547 // while establishing the tunnel. | |
8548 TEST_F(HttpNetworkTransactionTest, ProxyTunnelGetHangup) { | |
8549 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
8550 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
8551 session_deps.net_log = log.bound().net_log(); | |
8552 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
8553 | |
8554 HttpRequestInfo request; | |
8555 request.method = "GET"; | |
8556 request.url = GURL("https://www.google.com/"); | |
8557 | |
8558 // Since we have proxy, should try to establish tunnel. | |
8559 MockWrite data_writes1[] = { | |
8560 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
8561 "Host: www.google.com\r\n" | |
8562 "Proxy-Connection: keep-alive\r\n\r\n"), | |
8563 | |
8564 MockWrite("GET / HTTP/1.1\r\n" | |
8565 "Host: www.google.com\r\n" | |
8566 "Connection: keep-alive\r\n\r\n"), | |
8567 }; | |
8568 | |
8569 MockRead data_reads1[] = { | |
8570 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), | |
8571 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), | |
8572 MockRead(ASYNC, 0, 0), // EOF | |
8573 }; | |
8574 | |
8575 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
8576 data_writes1, arraysize(data_writes1)); | |
8577 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
8578 SSLSocketDataProvider ssl(ASYNC, OK); | |
8579 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
8580 | |
8581 TestCompletionCallback callback1; | |
8582 | |
8583 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
8584 | |
8585 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
8586 EXPECT_EQ(ERR_IO_PENDING, rv); | |
8587 | |
8588 rv = callback1.WaitForResult(); | |
8589 EXPECT_EQ(ERR_EMPTY_RESPONSE, rv); | |
8590 net::CapturingNetLog::EntryList entries; | |
8591 log.GetEntries(&entries); | |
8592 size_t pos = ExpectLogContainsSomewhere( | |
8593 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
8594 NetLog::PHASE_NONE); | |
8595 ExpectLogContainsSomewhere( | |
8596 entries, pos, | |
8597 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
8598 NetLog::PHASE_NONE); | |
8599 } | |
8600 | |
8601 // Test for crbug.com/55424. | |
8602 TEST_F(HttpNetworkTransactionTest, PreconnectWithExistingSpdySession) { | |
8603 SessionDependencies session_deps; | |
8604 | |
8605 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet( | |
8606 "https://www.google.com", false, 1, LOWEST)); | |
8607 MockWrite spdy_writes[] = { CreateMockWrite(*req) }; | |
8608 | |
8609 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
8610 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); | |
8611 MockRead spdy_reads[] = { | |
8612 CreateMockRead(*resp), | |
8613 CreateMockRead(*data), | |
8614 MockRead(ASYNC, 0, 0), | |
8615 }; | |
8616 | |
8617 scoped_ptr<DelayedSocketData> spdy_data( | |
8618 new DelayedSocketData( | |
8619 1, // wait for one write to finish before reading. | |
8620 spdy_reads, arraysize(spdy_reads), | |
8621 spdy_writes, arraysize(spdy_writes))); | |
8622 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
8623 | |
8624 SSLSocketDataProvider ssl(ASYNC, OK); | |
8625 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
8626 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
8627 | |
8628 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
8629 | |
8630 // Set up an initial SpdySession in the pool to reuse. | |
8631 HostPortPair host_port_pair("www.google.com", 443); | |
8632 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct()); | |
8633 scoped_refptr<SpdySession> spdy_session = | |
8634 session->spdy_session_pool()->Get(pair, BoundNetLog()); | |
8635 scoped_refptr<TransportSocketParams> transport_params( | |
8636 new TransportSocketParams(host_port_pair, MEDIUM, false, false)); | |
8637 TestCompletionCallback callback; | |
8638 | |
8639 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); | |
8640 EXPECT_EQ(ERR_IO_PENDING, | |
8641 connection->Init(host_port_pair.ToString(), transport_params, | |
8642 LOWEST, callback.callback(), | |
8643 session->GetTransportSocketPool(), BoundNetLog())); | |
8644 EXPECT_EQ(OK, callback.WaitForResult()); | |
8645 spdy_session->InitializeWithSocket(connection.release(), false, OK); | |
8646 | |
8647 HttpRequestInfo request; | |
8648 request.method = "GET"; | |
8649 request.url = GURL("https://www.google.com/"); | |
8650 request.load_flags = 0; | |
8651 | |
8652 // This is the important line that marks this as a preconnect. | |
8653 request.motivation = HttpRequestInfo::PRECONNECT_MOTIVATED; | |
8654 | |
8655 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); | |
8656 | |
8657 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
8658 EXPECT_EQ(ERR_IO_PENDING, rv); | |
8659 EXPECT_EQ(OK, callback.WaitForResult()); | |
8660 } | |
8661 | |
8662 // Given a net error, cause that error to be returned from the first Write() | |
8663 // call and verify that the HttpTransaction fails with that error. | |
8664 static void CheckErrorIsPassedBack(int error, IoMode mode) { | |
8665 net::HttpRequestInfo request_info; | |
8666 request_info.url = GURL("https://www.example.com/"); | |
8667 request_info.method = "GET"; | |
8668 request_info.load_flags = net::LOAD_NORMAL; | |
8669 | |
8670 SessionDependencies session_deps; | |
8671 | |
8672 SSLSocketDataProvider ssl_data(mode, OK); | |
8673 net::MockWrite data_writes[] = { | |
8674 net::MockWrite(mode, error), | |
8675 }; | |
8676 net::StaticSocketDataProvider data(NULL, 0, | |
8677 data_writes, arraysize(data_writes)); | |
8678 session_deps.socket_factory.AddSocketDataProvider(&data); | |
8679 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data); | |
8680 | |
8681 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
8682 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); | |
8683 | |
8684 TestCompletionCallback callback; | |
8685 int rv = trans->Start(&request_info, callback.callback(), net::BoundNetLog()); | |
8686 if (rv == net::ERR_IO_PENDING) | |
8687 rv = callback.WaitForResult(); | |
8688 ASSERT_EQ(error, rv); | |
8689 } | |
8690 | |
8691 TEST_F(HttpNetworkTransactionTest, SSLWriteCertError) { | |
8692 // Just check a grab bag of cert errors. | |
8693 static const int kErrors[] = { | |
8694 ERR_CERT_COMMON_NAME_INVALID, | |
8695 ERR_CERT_AUTHORITY_INVALID, | |
8696 ERR_CERT_DATE_INVALID, | |
8697 }; | |
8698 for (size_t i = 0; i < arraysize(kErrors); i++) { | |
8699 CheckErrorIsPassedBack(kErrors[i], ASYNC); | |
8700 CheckErrorIsPassedBack(kErrors[i], SYNCHRONOUS); | |
8701 } | |
8702 } | |
8703 | |
8704 // Ensure that a client certificate is removed from the SSL client auth | |
8705 // cache when: | |
8706 // 1) No proxy is involved. | |
8707 // 2) TLS False Start is disabled. | |
8708 // 3) The initial TLS handshake requests a client certificate. | |
8709 // 4) The client supplies an invalid/unacceptable certificate. | |
8710 TEST_F(HttpNetworkTransactionTest, ClientAuthCertCache_Direct_NoFalseStart) { | |
8711 net::HttpRequestInfo request_info; | |
8712 request_info.url = GURL("https://www.example.com/"); | |
8713 request_info.method = "GET"; | |
8714 request_info.load_flags = net::LOAD_NORMAL; | |
8715 | |
8716 SessionDependencies session_deps; | |
8717 | |
8718 scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo()); | |
8719 cert_request->host_and_port = "www.example.com:443"; | |
8720 | |
8721 // [ssl_]data1 contains the data for the first SSL handshake. When a | |
8722 // CertificateRequest is received for the first time, the handshake will | |
8723 // be aborted to allow the caller to provide a certificate. | |
8724 SSLSocketDataProvider ssl_data1(ASYNC, net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED); | |
8725 ssl_data1.cert_request_info = cert_request.get(); | |
8726 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data1); | |
8727 net::StaticSocketDataProvider data1(NULL, 0, NULL, 0); | |
8728 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
8729 | |
8730 // [ssl_]data2 contains the data for the second SSL handshake. When TLS | |
8731 // False Start is not being used, the result of the SSL handshake will be | |
8732 // returned as part of the SSLClientSocket::Connect() call. This test | |
8733 // matches the result of a server sending a handshake_failure alert, | |
8734 // rather than a Finished message, because it requires a client | |
8735 // certificate and none was supplied. | |
8736 SSLSocketDataProvider ssl_data2(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); | |
8737 ssl_data2.cert_request_info = cert_request.get(); | |
8738 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data2); | |
8739 net::StaticSocketDataProvider data2(NULL, 0, NULL, 0); | |
8740 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
8741 | |
8742 // [ssl_]data3 contains the data for the third SSL handshake. When a | |
8743 // connection to a server fails during an SSL handshake, | |
8744 // HttpNetworkTransaction will attempt to fallback to SSLv3 if the initial | |
8745 // connection was attempted with TLSv1. This is transparent to the caller | |
8746 // of the HttpNetworkTransaction. Because this test failure is due to | |
8747 // requiring a client certificate, this fallback handshake should also | |
8748 // fail. | |
8749 SSLSocketDataProvider ssl_data3(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); | |
8750 ssl_data3.cert_request_info = cert_request.get(); | |
8751 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data3); | |
8752 net::StaticSocketDataProvider data3(NULL, 0, NULL, 0); | |
8753 session_deps.socket_factory.AddSocketDataProvider(&data3); | |
8754 | |
8755 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
8756 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); | |
8757 | |
8758 // Begin the SSL handshake with the peer. This consumes ssl_data1. | |
8759 TestCompletionCallback callback; | |
8760 int rv = trans->Start(&request_info, callback.callback(), net::BoundNetLog()); | |
8761 ASSERT_EQ(net::ERR_IO_PENDING, rv); | |
8762 | |
8763 // Complete the SSL handshake, which should abort due to requiring a | |
8764 // client certificate. | |
8765 rv = callback.WaitForResult(); | |
8766 ASSERT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv); | |
8767 | |
8768 // Indicate that no certificate should be supplied. From the perspective | |
8769 // of SSLClientCertCache, NULL is just as meaningful as a real | |
8770 // certificate, so this is the same as supply a | |
8771 // legitimate-but-unacceptable certificate. | |
8772 rv = trans->RestartWithCertificate(NULL, callback.callback()); | |
8773 ASSERT_EQ(net::ERR_IO_PENDING, rv); | |
8774 | |
8775 // Ensure the certificate was added to the client auth cache before | |
8776 // allowing the connection to continue restarting. | |
8777 scoped_refptr<X509Certificate> client_cert; | |
8778 ASSERT_TRUE(session->ssl_client_auth_cache()->Lookup("www.example.com:443", | |
8779 &client_cert)); | |
8780 ASSERT_EQ(NULL, client_cert.get()); | |
8781 | |
8782 // Restart the handshake. This will consume ssl_data2, which fails, and | |
8783 // then consume ssl_data3, which should also fail. The result code is | |
8784 // checked against what ssl_data3 should return. | |
8785 rv = callback.WaitForResult(); | |
8786 ASSERT_EQ(net::ERR_SSL_PROTOCOL_ERROR, rv); | |
8787 | |
8788 // Ensure that the client certificate is removed from the cache on a | |
8789 // handshake failure. | |
8790 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("www.example.com:443", | |
8791 &client_cert)); | |
8792 } | |
8793 | |
8794 // Ensure that a client certificate is removed from the SSL client auth | |
8795 // cache when: | |
8796 // 1) No proxy is involved. | |
8797 // 2) TLS False Start is enabled. | |
8798 // 3) The initial TLS handshake requests a client certificate. | |
8799 // 4) The client supplies an invalid/unacceptable certificate. | |
8800 TEST_F(HttpNetworkTransactionTest, ClientAuthCertCache_Direct_FalseStart) { | |
8801 net::HttpRequestInfo request_info; | |
8802 request_info.url = GURL("https://www.example.com/"); | |
8803 request_info.method = "GET"; | |
8804 request_info.load_flags = net::LOAD_NORMAL; | |
8805 | |
8806 SessionDependencies session_deps; | |
8807 | |
8808 scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo()); | |
8809 cert_request->host_and_port = "www.example.com:443"; | |
8810 | |
8811 // When TLS False Start is used, SSLClientSocket::Connect() calls will | |
8812 // return successfully after reading up to the peer's Certificate message. | |
8813 // This is to allow the caller to call SSLClientSocket::Write(), which can | |
8814 // enqueue application data to be sent in the same packet as the | |
8815 // ChangeCipherSpec and Finished messages. | |
8816 // The actual handshake will be finished when SSLClientSocket::Read() is | |
8817 // called, which expects to process the peer's ChangeCipherSpec and | |
8818 // Finished messages. If there was an error negotiating with the peer, | |
8819 // such as due to the peer requiring a client certificate when none was | |
8820 // supplied, the alert sent by the peer won't be processed until Read() is | |
8821 // called. | |
8822 | |
8823 // Like the non-False Start case, when a client certificate is requested by | |
8824 // the peer, the handshake is aborted during the Connect() call. | |
8825 // [ssl_]data1 represents the initial SSL handshake with the peer. | |
8826 SSLSocketDataProvider ssl_data1(ASYNC, net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED); | |
8827 ssl_data1.cert_request_info = cert_request.get(); | |
8828 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data1); | |
8829 net::StaticSocketDataProvider data1(NULL, 0, NULL, 0); | |
8830 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
8831 | |
8832 // When a client certificate is supplied, Connect() will not be aborted | |
8833 // when the peer requests the certificate. Instead, the handshake will | |
8834 // artificially succeed, allowing the caller to write the HTTP request to | |
8835 // the socket. The handshake messages are not processed until Read() is | |
8836 // called, which then detects that the handshake was aborted, due to the | |
8837 // peer sending a handshake_failure because it requires a client | |
8838 // certificate. | |
8839 SSLSocketDataProvider ssl_data2(ASYNC, net::OK); | |
8840 ssl_data2.cert_request_info = cert_request.get(); | |
8841 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data2); | |
8842 net::MockRead data2_reads[] = { | |
8843 net::MockRead(ASYNC /* async */, net::ERR_SSL_PROTOCOL_ERROR), | |
8844 }; | |
8845 net::StaticSocketDataProvider data2( | |
8846 data2_reads, arraysize(data2_reads), NULL, 0); | |
8847 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
8848 | |
8849 // As described in ClientAuthCertCache_Direct_NoFalseStart, [ssl_]data3 is | |
8850 // the data for the SSL handshake once the TLSv1 connection falls back to | |
8851 // SSLv3. It has the same behaviour as [ssl_]data2. | |
8852 SSLSocketDataProvider ssl_data3(ASYNC, net::OK); | |
8853 ssl_data3.cert_request_info = cert_request.get(); | |
8854 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data3); | |
8855 net::StaticSocketDataProvider data3( | |
8856 data2_reads, arraysize(data2_reads), NULL, 0); | |
8857 session_deps.socket_factory.AddSocketDataProvider(&data3); | |
8858 | |
8859 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
8860 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); | |
8861 | |
8862 // Begin the initial SSL handshake. | |
8863 TestCompletionCallback callback; | |
8864 int rv = trans->Start(&request_info, callback.callback(), net::BoundNetLog()); | |
8865 ASSERT_EQ(net::ERR_IO_PENDING, rv); | |
8866 | |
8867 // Complete the SSL handshake, which should abort due to requiring a | |
8868 // client certificate. | |
8869 rv = callback.WaitForResult(); | |
8870 ASSERT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv); | |
8871 | |
8872 // Indicate that no certificate should be supplied. From the perspective | |
8873 // of SSLClientCertCache, NULL is just as meaningful as a real | |
8874 // certificate, so this is the same as supply a | |
8875 // legitimate-but-unacceptable certificate. | |
8876 rv = trans->RestartWithCertificate(NULL, callback.callback()); | |
8877 ASSERT_EQ(net::ERR_IO_PENDING, rv); | |
8878 | |
8879 // Ensure the certificate was added to the client auth cache before | |
8880 // allowing the connection to continue restarting. | |
8881 scoped_refptr<X509Certificate> client_cert; | |
8882 ASSERT_TRUE(session->ssl_client_auth_cache()->Lookup("www.example.com:443", | |
8883 &client_cert)); | |
8884 ASSERT_EQ(NULL, client_cert.get()); | |
8885 | |
8886 | |
8887 // Restart the handshake. This will consume ssl_data2, which fails, and | |
8888 // then consume ssl_data3, which should also fail. The result code is | |
8889 // checked against what ssl_data3 should return. | |
8890 rv = callback.WaitForResult(); | |
8891 ASSERT_EQ(net::ERR_SSL_PROTOCOL_ERROR, rv); | |
8892 | |
8893 // Ensure that the client certificate is removed from the cache on a | |
8894 // handshake failure. | |
8895 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("www.example.com:443", | |
8896 &client_cert)); | |
8897 } | |
8898 | |
8899 // Ensure that a client certificate is removed from the SSL client auth | |
8900 // cache when: | |
8901 // 1) An HTTPS proxy is involved. | |
8902 // 3) The HTTPS proxy requests a client certificate. | |
8903 // 4) The client supplies an invalid/unacceptable certificate for the | |
8904 // proxy. | |
8905 // The test is repeated twice, first for connecting to an HTTPS endpoint, | |
8906 // then for connecting to an HTTP endpoint. | |
8907 TEST_F(HttpNetworkTransactionTest, ClientAuthCertCache_Proxy_Fail) { | |
8908 SessionDependencies session_deps( | |
8909 ProxyService::CreateFixed("https://proxy:70")); | |
8910 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
8911 session_deps.net_log = log.bound().net_log(); | |
8912 | |
8913 scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo()); | |
8914 cert_request->host_and_port = "proxy:70"; | |
8915 | |
8916 // See ClientAuthCertCache_Direct_NoFalseStart for the explanation of | |
8917 // [ssl_]data[1-3]. Rather than represending the endpoint | |
8918 // (www.example.com:443), they represent failures with the HTTPS proxy | |
8919 // (proxy:70). | |
8920 SSLSocketDataProvider ssl_data1(ASYNC, net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED); | |
8921 ssl_data1.cert_request_info = cert_request.get(); | |
8922 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data1); | |
8923 net::StaticSocketDataProvider data1(NULL, 0, NULL, 0); | |
8924 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
8925 | |
8926 SSLSocketDataProvider ssl_data2(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); | |
8927 ssl_data2.cert_request_info = cert_request.get(); | |
8928 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data2); | |
8929 net::StaticSocketDataProvider data2(NULL, 0, NULL, 0); | |
8930 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
8931 | |
8932 SSLSocketDataProvider ssl_data3(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); | |
8933 ssl_data3.cert_request_info = cert_request.get(); | |
8934 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data3); | |
8935 net::StaticSocketDataProvider data3(NULL, 0, NULL, 0); | |
8936 session_deps.socket_factory.AddSocketDataProvider(&data3); | |
8937 | |
8938 net::HttpRequestInfo requests[2]; | |
8939 requests[0].url = GURL("https://www.example.com/"); | |
8940 requests[0].method = "GET"; | |
8941 requests[0].load_flags = net::LOAD_NORMAL; | |
8942 | |
8943 requests[1].url = GURL("http://www.example.com/"); | |
8944 requests[1].method = "GET"; | |
8945 requests[1].load_flags = net::LOAD_NORMAL; | |
8946 | |
8947 for (size_t i = 0; i < arraysize(requests); ++i) { | |
8948 session_deps.socket_factory.ResetNextMockIndexes(); | |
8949 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
8950 scoped_ptr<HttpNetworkTransaction> trans( | |
8951 new HttpNetworkTransaction(session)); | |
8952 | |
8953 // Begin the SSL handshake with the proxy. | |
8954 TestCompletionCallback callback; | |
8955 int rv = trans->Start( | |
8956 &requests[i], callback.callback(), net::BoundNetLog()); | |
8957 ASSERT_EQ(net::ERR_IO_PENDING, rv); | |
8958 | |
8959 // Complete the SSL handshake, which should abort due to requiring a | |
8960 // client certificate. | |
8961 rv = callback.WaitForResult(); | |
8962 ASSERT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv); | |
8963 | |
8964 // Indicate that no certificate should be supplied. From the perspective | |
8965 // of SSLClientCertCache, NULL is just as meaningful as a real | |
8966 // certificate, so this is the same as supply a | |
8967 // legitimate-but-unacceptable certificate. | |
8968 rv = trans->RestartWithCertificate(NULL, callback.callback()); | |
8969 ASSERT_EQ(net::ERR_IO_PENDING, rv); | |
8970 | |
8971 // Ensure the certificate was added to the client auth cache before | |
8972 // allowing the connection to continue restarting. | |
8973 scoped_refptr<X509Certificate> client_cert; | |
8974 ASSERT_TRUE(session->ssl_client_auth_cache()->Lookup("proxy:70", | |
8975 &client_cert)); | |
8976 ASSERT_EQ(NULL, client_cert.get()); | |
8977 // Ensure the certificate was NOT cached for the endpoint. This only | |
8978 // applies to HTTPS requests, but is fine to check for HTTP requests. | |
8979 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("www.example.com:443", | |
8980 &client_cert)); | |
8981 | |
8982 // Restart the handshake. This will consume ssl_data2, which fails, and | |
8983 // then consume ssl_data3, which should also fail. The result code is | |
8984 // checked against what ssl_data3 should return. | |
8985 rv = callback.WaitForResult(); | |
8986 ASSERT_EQ(net::ERR_PROXY_CONNECTION_FAILED, rv); | |
8987 | |
8988 // Now that the new handshake has failed, ensure that the client | |
8989 // certificate was removed from the client auth cache. | |
8990 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("proxy:70", | |
8991 &client_cert)); | |
8992 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("www.example.com:443", | |
8993 &client_cert)); | |
8994 } | |
8995 } | |
8996 | |
8997 void IPPoolingAddAlias(MockCachingHostResolver* host_resolver, | |
8998 SpdySessionPoolPeer* pool_peer, | |
8999 std::string host, | |
9000 int port, | |
9001 std::string iplist) { | |
9002 // Create a host resolver dependency that returns address |iplist| for | |
9003 // resolutions of |host|. | |
9004 host_resolver->rules()->AddIPLiteralRule(host, iplist, ""); | |
9005 | |
9006 // Setup a HostPortProxyPair. | |
9007 HostPortPair host_port_pair(host, port); | |
9008 HostPortProxyPair pair = HostPortProxyPair(host_port_pair, | |
9009 ProxyServer::Direct()); | |
9010 | |
9011 // Resolve the host and port. | |
9012 AddressList addresses; | |
9013 HostResolver::RequestInfo info(host_port_pair); | |
9014 TestCompletionCallback callback; | |
9015 int rv = host_resolver->Resolve(info, &addresses, callback.callback(), NULL, | |
9016 BoundNetLog()); | |
9017 if (rv == ERR_IO_PENDING) | |
9018 rv = callback.WaitForResult(); | |
9019 DCHECK_EQ(OK, rv); | |
9020 | |
9021 // Add the first address as an alias. It would have been better to call | |
9022 // MockClientSocket::GetPeerAddress but that returns 192.0.2.33 whereas | |
9023 // MockHostResolver returns 127.0.0.1 (MockHostResolverBase::Reset). So we use | |
9024 // the first address (127.0.0.1) returned by MockHostResolver as an alias for | |
9025 // the |pair|. | |
9026 const addrinfo* address = addresses.head(); | |
9027 pool_peer->AddAlias(address, pair); | |
9028 } | |
9029 | |
9030 TEST_F(HttpNetworkTransactionTest, UseIPConnectionPooling) { | |
9031 HttpStreamFactory::set_use_alternate_protocols(true); | |
9032 HttpStreamFactory::SetNextProtos(SpdyNextProtos()); | |
9033 | |
9034 // Set up a special HttpNetworkSession with a MockCachingHostResolver. | |
9035 SessionDependencies session_deps; | |
9036 MockCachingHostResolver host_resolver; | |
9037 net::HttpNetworkSession::Params params; | |
9038 params.client_socket_factory = &session_deps.socket_factory; | |
9039 params.host_resolver = &host_resolver; | |
9040 params.cert_verifier = session_deps.cert_verifier.get(); | |
9041 params.proxy_service = session_deps.proxy_service.get(); | |
9042 params.ssl_config_service = session_deps.ssl_config_service; | |
9043 params.http_auth_handler_factory = | |
9044 session_deps.http_auth_handler_factory.get(); | |
9045 params.http_server_properties = &session_deps.http_server_properties; | |
9046 params.net_log = session_deps.net_log; | |
9047 scoped_refptr<HttpNetworkSession> session(new HttpNetworkSession(params)); | |
9048 SpdySessionPoolPeer pool_peer(session->spdy_session_pool()); | |
9049 pool_peer.DisableDomainAuthenticationVerification(); | |
9050 | |
9051 SSLSocketDataProvider ssl(ASYNC, OK); | |
9052 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
9053 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
9054 | |
9055 scoped_ptr<spdy::SpdyFrame> host1_req(ConstructSpdyGet( | |
9056 "https://www.google.com", false, 1, LOWEST)); | |
9057 scoped_ptr<spdy::SpdyFrame> host2_req(ConstructSpdyGet( | |
9058 "https://www.gmail.com", false, 3, LOWEST)); | |
9059 MockWrite spdy_writes[] = { | |
9060 CreateMockWrite(*host1_req, 1), | |
9061 CreateMockWrite(*host2_req, 4), | |
9062 }; | |
9063 scoped_ptr<spdy::SpdyFrame> host1_resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
9064 scoped_ptr<spdy::SpdyFrame> host1_resp_body(ConstructSpdyBodyFrame(1, true)); | |
9065 scoped_ptr<spdy::SpdyFrame> host2_resp(ConstructSpdyGetSynReply(NULL, 0, 3)); | |
9066 scoped_ptr<spdy::SpdyFrame> host2_resp_body(ConstructSpdyBodyFrame(3, true)); | |
9067 MockRead spdy_reads[] = { | |
9068 CreateMockRead(*host1_resp, 2), | |
9069 CreateMockRead(*host1_resp_body, 3), | |
9070 CreateMockRead(*host2_resp, 5), | |
9071 CreateMockRead(*host2_resp_body, 6), | |
9072 MockRead(ASYNC, 0, 7), | |
9073 }; | |
9074 | |
9075 scoped_ptr<OrderedSocketData> spdy_data( | |
9076 new OrderedSocketData( | |
9077 spdy_reads, arraysize(spdy_reads), | |
9078 spdy_writes, arraysize(spdy_writes))); | |
9079 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
9080 | |
9081 TestCompletionCallback callback; | |
9082 HttpRequestInfo request1; | |
9083 request1.method = "GET"; | |
9084 request1.url = GURL("https://www.google.com/"); | |
9085 request1.load_flags = 0; | |
9086 HttpNetworkTransaction trans1(session); | |
9087 | |
9088 int rv = trans1.Start(&request1, callback.callback(), BoundNetLog()); | |
9089 EXPECT_EQ(ERR_IO_PENDING, rv); | |
9090 EXPECT_EQ(OK, callback.WaitForResult()); | |
9091 | |
9092 const HttpResponseInfo* response = trans1.GetResponseInfo(); | |
9093 ASSERT_TRUE(response != NULL); | |
9094 ASSERT_TRUE(response->headers != NULL); | |
9095 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
9096 | |
9097 std::string response_data; | |
9098 ASSERT_EQ(OK, ReadTransaction(&trans1, &response_data)); | |
9099 EXPECT_EQ("hello!", response_data); | |
9100 | |
9101 // Preload www.gmail.com into HostCache. | |
9102 HostPortPair host_port("www.gmail.com", 443); | |
9103 HostResolver::RequestInfo resolve_info(host_port); | |
9104 AddressList ignored; | |
9105 rv = host_resolver.Resolve(resolve_info, &ignored, callback.callback(), NULL, | |
9106 BoundNetLog()); | |
9107 EXPECT_EQ(ERR_IO_PENDING, rv); | |
9108 rv = callback.WaitForResult(); | |
9109 EXPECT_EQ(OK, rv); | |
9110 | |
9111 // MockHostResolver returns 127.0.0.1, port 443 for https://www.google.com/ | |
9112 // and https://www.gmail.com/. Add 127.0.0.1 as alias for host_port_pair: | |
9113 // (www.google.com, 443). | |
9114 IPPoolingAddAlias(&host_resolver, &pool_peer, "www.google.com", 443, | |
9115 "127.0.0.1"); | |
9116 | |
9117 HttpRequestInfo request2; | |
9118 request2.method = "GET"; | |
9119 request2.url = GURL("https://www.gmail.com/"); | |
9120 request2.load_flags = 0; | |
9121 HttpNetworkTransaction trans2(session); | |
9122 | |
9123 rv = trans2.Start(&request2, callback.callback(), BoundNetLog()); | |
9124 EXPECT_EQ(ERR_IO_PENDING, rv); | |
9125 EXPECT_EQ(OK, callback.WaitForResult()); | |
9126 | |
9127 response = trans2.GetResponseInfo(); | |
9128 ASSERT_TRUE(response != NULL); | |
9129 ASSERT_TRUE(response->headers != NULL); | |
9130 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
9131 EXPECT_TRUE(response->was_fetched_via_spdy); | |
9132 EXPECT_TRUE(response->was_npn_negotiated); | |
9133 ASSERT_EQ(OK, ReadTransaction(&trans2, &response_data)); | |
9134 EXPECT_EQ("hello!", response_data); | |
9135 | |
9136 HttpStreamFactory::SetNextProtos(std::vector<std::string>()); | |
9137 HttpStreamFactory::set_use_alternate_protocols(false); | |
9138 } | |
9139 | |
9140 class OneTimeCachingHostResolver : public net::HostResolver { | |
9141 public: | |
9142 explicit OneTimeCachingHostResolver(const HostPortPair& host_port) | |
9143 : host_port_(host_port) {} | |
9144 virtual ~OneTimeCachingHostResolver() {} | |
9145 | |
9146 RuleBasedHostResolverProc* rules() { return host_resolver_.rules(); } | |
9147 | |
9148 // HostResolver methods: | |
9149 virtual int Resolve(const RequestInfo& info, | |
9150 AddressList* addresses, | |
9151 const CompletionCallback& callback, | |
9152 RequestHandle* out_req, | |
9153 const BoundNetLog& net_log) OVERRIDE { | |
9154 return host_resolver_.Resolve( | |
9155 info, addresses, callback, out_req, net_log); | |
9156 } | |
9157 | |
9158 virtual int ResolveFromCache(const RequestInfo& info, | |
9159 AddressList* addresses, | |
9160 const BoundNetLog& net_log) OVERRIDE { | |
9161 int rv = host_resolver_.ResolveFromCache(info, addresses, net_log); | |
9162 if (rv == OK && info.host_port_pair().Equals(host_port_)) | |
9163 host_resolver_.GetHostCache()->clear(); | |
9164 return rv; | |
9165 } | |
9166 | |
9167 virtual void CancelRequest(RequestHandle req) OVERRIDE { | |
9168 host_resolver_.CancelRequest(req); | |
9169 } | |
9170 | |
9171 MockCachingHostResolver* GetMockHostResolver() { | |
9172 return &host_resolver_; | |
9173 } | |
9174 | |
9175 private: | |
9176 MockCachingHostResolver host_resolver_; | |
9177 const HostPortPair host_port_; | |
9178 }; | |
9179 | |
9180 TEST_F(HttpNetworkTransactionTest, | |
9181 UseIPConnectionPoolingWithHostCacheExpiration) { | |
9182 HttpStreamFactory::set_use_alternate_protocols(true); | |
9183 HttpStreamFactory::SetNextProtos(SpdyNextProtos()); | |
9184 | |
9185 // Set up a special HttpNetworkSession with a OneTimeCachingHostResolver. | |
9186 SessionDependencies session_deps; | |
9187 OneTimeCachingHostResolver host_resolver(HostPortPair("www.gmail.com", 443)); | |
9188 net::HttpNetworkSession::Params params; | |
9189 params.client_socket_factory = &session_deps.socket_factory; | |
9190 params.host_resolver = &host_resolver; | |
9191 params.cert_verifier = session_deps.cert_verifier.get(); | |
9192 params.proxy_service = session_deps.proxy_service.get(); | |
9193 params.ssl_config_service = session_deps.ssl_config_service; | |
9194 params.http_auth_handler_factory = | |
9195 session_deps.http_auth_handler_factory.get(); | |
9196 params.http_server_properties = &session_deps.http_server_properties; | |
9197 params.net_log = session_deps.net_log; | |
9198 scoped_refptr<HttpNetworkSession> session(new HttpNetworkSession(params)); | |
9199 SpdySessionPoolPeer pool_peer(session->spdy_session_pool()); | |
9200 pool_peer.DisableDomainAuthenticationVerification(); | |
9201 | |
9202 SSLSocketDataProvider ssl(ASYNC, OK); | |
9203 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
9204 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
9205 | |
9206 scoped_ptr<spdy::SpdyFrame> host1_req(ConstructSpdyGet( | |
9207 "https://www.google.com", false, 1, LOWEST)); | |
9208 scoped_ptr<spdy::SpdyFrame> host2_req(ConstructSpdyGet( | |
9209 "https://www.gmail.com", false, 3, LOWEST)); | |
9210 MockWrite spdy_writes[] = { | |
9211 CreateMockWrite(*host1_req, 1), | |
9212 CreateMockWrite(*host2_req, 4), | |
9213 }; | |
9214 scoped_ptr<spdy::SpdyFrame> host1_resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
9215 scoped_ptr<spdy::SpdyFrame> host1_resp_body(ConstructSpdyBodyFrame(1, true)); | |
9216 scoped_ptr<spdy::SpdyFrame> host2_resp(ConstructSpdyGetSynReply(NULL, 0, 3)); | |
9217 scoped_ptr<spdy::SpdyFrame> host2_resp_body(ConstructSpdyBodyFrame(3, true)); | |
9218 MockRead spdy_reads[] = { | |
9219 CreateMockRead(*host1_resp, 2), | |
9220 CreateMockRead(*host1_resp_body, 3), | |
9221 CreateMockRead(*host2_resp, 5), | |
9222 CreateMockRead(*host2_resp_body, 6), | |
9223 MockRead(ASYNC, 0, 7), | |
9224 }; | |
9225 | |
9226 scoped_ptr<OrderedSocketData> spdy_data( | |
9227 new OrderedSocketData( | |
9228 spdy_reads, arraysize(spdy_reads), | |
9229 spdy_writes, arraysize(spdy_writes))); | |
9230 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
9231 | |
9232 TestCompletionCallback callback; | |
9233 HttpRequestInfo request1; | |
9234 request1.method = "GET"; | |
9235 request1.url = GURL("https://www.google.com/"); | |
9236 request1.load_flags = 0; | |
9237 HttpNetworkTransaction trans1(session); | |
9238 | |
9239 int rv = trans1.Start(&request1, callback.callback(), BoundNetLog()); | |
9240 EXPECT_EQ(ERR_IO_PENDING, rv); | |
9241 EXPECT_EQ(OK, callback.WaitForResult()); | |
9242 | |
9243 const HttpResponseInfo* response = trans1.GetResponseInfo(); | |
9244 ASSERT_TRUE(response != NULL); | |
9245 ASSERT_TRUE(response->headers != NULL); | |
9246 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
9247 | |
9248 std::string response_data; | |
9249 ASSERT_EQ(OK, ReadTransaction(&trans1, &response_data)); | |
9250 EXPECT_EQ("hello!", response_data); | |
9251 | |
9252 // Preload cache entries into HostCache. | |
9253 HostResolver::RequestInfo resolve_info(HostPortPair("www.gmail.com", 443)); | |
9254 AddressList ignored; | |
9255 rv = host_resolver.Resolve(resolve_info, &ignored, callback.callback(), NULL, | |
9256 BoundNetLog()); | |
9257 EXPECT_EQ(ERR_IO_PENDING, rv); | |
9258 rv = callback.WaitForResult(); | |
9259 EXPECT_EQ(OK, rv); | |
9260 | |
9261 HttpRequestInfo request2; | |
9262 request2.method = "GET"; | |
9263 request2.url = GURL("https://www.gmail.com/"); | |
9264 request2.load_flags = 0; | |
9265 HttpNetworkTransaction trans2(session); | |
9266 | |
9267 // MockHostResolver returns 127.0.0.1, port 443 for https://www.google.com/ | |
9268 // and https://www.gmail.com/. Add 127.0.0.1 as alias for host_port_pair: | |
9269 // (www.google.com, 443). | |
9270 IPPoolingAddAlias(host_resolver.GetMockHostResolver(), &pool_peer, | |
9271 "www.google.com", 443, "127.0.0.1"); | |
9272 | |
9273 rv = trans2.Start(&request2, callback.callback(), BoundNetLog()); | |
9274 EXPECT_EQ(ERR_IO_PENDING, rv); | |
9275 EXPECT_EQ(OK, callback.WaitForResult()); | |
9276 | |
9277 response = trans2.GetResponseInfo(); | |
9278 ASSERT_TRUE(response != NULL); | |
9279 ASSERT_TRUE(response->headers != NULL); | |
9280 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
9281 EXPECT_TRUE(response->was_fetched_via_spdy); | |
9282 EXPECT_TRUE(response->was_npn_negotiated); | |
9283 ASSERT_EQ(OK, ReadTransaction(&trans2, &response_data)); | |
9284 EXPECT_EQ("hello!", response_data); | |
9285 | |
9286 HttpStreamFactory::SetNextProtos(std::vector<std::string>()); | |
9287 HttpStreamFactory::set_use_alternate_protocols(false); | |
9288 } | |
9289 | |
9290 TEST_F(HttpNetworkTransactionTest, ReadPipelineEvictionFallback) { | |
9291 MockRead data_reads1[] = { | |
9292 MockRead(SYNCHRONOUS, ERR_PIPELINE_EVICTION), | |
9293 }; | |
9294 MockRead data_reads2[] = { | |
9295 MockRead("HTTP/1.0 200 OK\r\n\r\n"), | |
9296 MockRead("hello world"), | |
9297 MockRead(SYNCHRONOUS, OK), | |
9298 }; | |
9299 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), NULL, 0); | |
9300 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), NULL, 0); | |
9301 StaticSocketDataProvider* data[] = { &data1, &data2 }; | |
9302 | |
9303 SimpleGetHelperResult out = SimpleGetHelperForData(data, arraysize(data)); | |
9304 | |
9305 EXPECT_EQ(OK, out.rv); | |
9306 EXPECT_EQ("HTTP/1.0 200 OK", out.status_line); | |
9307 EXPECT_EQ("hello world", out.response_data); | |
9308 } | |
9309 | |
9310 TEST_F(HttpNetworkTransactionTest, SendPipelineEvictionFallback) { | |
9311 MockWrite data_writes1[] = { | |
9312 MockWrite(SYNCHRONOUS, ERR_PIPELINE_EVICTION), | |
9313 }; | |
9314 MockWrite data_writes2[] = { | |
9315 MockWrite("GET / HTTP/1.1\r\n" | |
9316 "Host: www.google.com\r\n" | |
9317 "Connection: keep-alive\r\n\r\n"), | |
9318 }; | |
9319 MockRead data_reads2[] = { | |
9320 MockRead("HTTP/1.0 200 OK\r\n\r\n"), | |
9321 MockRead("hello world"), | |
9322 MockRead(SYNCHRONOUS, OK), | |
9323 }; | |
9324 StaticSocketDataProvider data1(NULL, 0, | |
9325 data_writes1, arraysize(data_writes1)); | |
9326 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
9327 data_writes2, arraysize(data_writes2)); | |
9328 StaticSocketDataProvider* data[] = { &data1, &data2 }; | |
9329 | |
9330 SimpleGetHelperResult out = SimpleGetHelperForData(data, arraysize(data)); | |
9331 | |
9332 EXPECT_EQ(OK, out.rv); | |
9333 EXPECT_EQ("HTTP/1.0 200 OK", out.status_line); | |
9334 EXPECT_EQ("hello world", out.response_data); | |
9335 } | |
9336 | |
9337 } // namespace net | |
OLD | NEW |