1 // Copyright (c) 2011 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 <vector>
9
10 #include "base/basictypes.h"
11 #include "base/compiler_specific.h"
12 #include "base/file_path.h"
13 #include "base/file_util.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/utf_string_conversions.h"
16 #include "net/base/auth.h"
17 #include "net/base/capturing_net_log.h"
18 #include "net/base/completion_callback.h"
19 #include "net/base/mock_host_resolver.h"
20 #include "net/base/net_log.h"
21 #include "net/base/net_log_unittest.h"
22 #include "net/base/request_priority.h"
23 #include "net/base/ssl_cert_request_info.h"
24 #include "net/base/ssl_config_service_defaults.h"
25 #include "net/base/ssl_info.h"
26 #include "net/base/test_completion_callback.h"
27 #include "net/base/upload_data.h"
28 #include "net/http/http_auth_handler_digest.h"
29 #include "net/http/http_auth_handler_mock.h"
30 #include "net/http/http_auth_handler_ntlm.h"
31 #include "net/http/http_basic_stream.h"
32 #include "net/http/http_net_log_params.h"
33 #include "net/http/http_network_session.h"
34 #include "net/http/http_network_session_peer.h"
35 #include "net/http/http_stream.h"
36 #include "net/http/http_stream_factory.h"
37 #include "net/http/http_transaction_unittest.h"
38 #include "net/proxy/proxy_config_service_fixed.h"
39 #include "net/proxy/proxy_resolver.h"
40 #include "net/proxy/proxy_service.h"
41 #include "net/socket/client_socket_factory.h"
42 #include "net/socket/socket_test_util.h"
43 #include "net/socket/ssl_client_socket.h"
44 #include "net/spdy/spdy_framer.h"
45 #include "net/spdy/spdy_session.h"
46 #include "net/spdy/spdy_session_pool.h"
47 #include "net/spdy/spdy_test_util.h"
48 #include "testing/gtest/include/gtest/gtest.h"
49 #include "testing/platform_test.h"
50
51 //-----------------------------------------------------------------------------
52
53 namespace {
54
55 const string16 kBar(ASCIIToUTF16("bar"));
56 const string16 kBar2(ASCIIToUTF16("bar2"));
57 const string16 kBar3(ASCIIToUTF16("bar3"));
58 const string16 kBaz(ASCIIToUTF16("baz"));
59 const string16 kFirst(ASCIIToUTF16("first"));
60 const string16 kFoo(ASCIIToUTF16("foo"));
61 const string16 kFoo2(ASCIIToUTF16("foo2"));
62 const string16 kFoo3(ASCIIToUTF16("foo3"));
63 const string16 kFou(ASCIIToUTF16("fou"));
64 const string16 kSecond(ASCIIToUTF16("second"));
65 const string16 kTestingNTLM(ASCIIToUTF16("testing-ntlm"));
66 const string16 kWrongPassword(ASCIIToUTF16("wrongpassword"));
67
68 } // namespace
69
70 namespace net {
71
72 // Helper to manage the lifetimes of the dependencies for a
73 // HttpNetworkTransaction.
74 struct SessionDependencies {
75 // Default set of dependencies -- "null" proxy service.
SessionDependenciesnet::SessionDependencies76 SessionDependencies()
77 : host_resolver(new MockHostResolver),
78 cert_verifier(new CertVerifier),
79 proxy_service(ProxyService::CreateDirect()),
80 ssl_config_service(new SSLConfigServiceDefaults),
81 http_auth_handler_factory(
82 HttpAuthHandlerFactory::CreateDefault(host_resolver.get())),
83 net_log(NULL) {}
84
85 // Custom proxy service dependency.
SessionDependenciesnet::SessionDependencies86 explicit SessionDependencies(ProxyService* proxy_service)
87 : host_resolver(new MockHostResolver),
88 cert_verifier(new CertVerifier),
89 proxy_service(proxy_service),
90 ssl_config_service(new SSLConfigServiceDefaults),
91 http_auth_handler_factory(
92 HttpAuthHandlerFactory::CreateDefault(host_resolver.get())),
93 net_log(NULL) {}
94
95 scoped_ptr<MockHostResolverBase> host_resolver;
96 scoped_ptr<CertVerifier> cert_verifier;
97 scoped_refptr<ProxyService> proxy_service;
98 scoped_refptr<SSLConfigService> ssl_config_service;
99 MockClientSocketFactory socket_factory;
100 scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory;
101 NetLog* net_log;
102 };
103
CreateSession(SessionDependencies * session_deps)104 HttpNetworkSession* CreateSession(SessionDependencies* session_deps) {
105 net::HttpNetworkSession::Params params;
106 params.client_socket_factory = &session_deps->socket_factory;
107 params.host_resolver = session_deps->host_resolver.get();
108 params.cert_verifier = session_deps->cert_verifier.get();
109 params.proxy_service = session_deps->proxy_service;
110 params.ssl_config_service = session_deps->ssl_config_service;
111 params.http_auth_handler_factory =
112 session_deps->http_auth_handler_factory.get();
113 params.net_log = session_deps->net_log;
114 return new HttpNetworkSession(params);
115 }
116
117 class HttpNetworkTransactionTest : public PlatformTest {
118 public:
SetUp()119 virtual void SetUp() {
120 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
121 MessageLoop::current()->RunAllPending();
122 spdy::SpdyFramer::set_enable_compression_default(false);
123 }
124
TearDown()125 virtual void TearDown() {
126 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
127 MessageLoop::current()->RunAllPending();
128 spdy::SpdyFramer::set_enable_compression_default(true);
129 // Empty the current queue.
130 MessageLoop::current()->RunAllPending();
131 PlatformTest::TearDown();
132 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
133 MessageLoop::current()->RunAllPending();
134 }
135
136 protected:
137 void KeepAliveConnectionResendRequestTest(const MockRead& read_failure);
138
139 struct SimpleGetHelperResult {
140 int rv;
141 std::string status_line;
142 std::string response_data;
143 };
144
SimpleGetHelper(MockRead data_reads[],size_t reads_count)145 SimpleGetHelperResult SimpleGetHelper(MockRead data_reads[],
146 size_t reads_count) {
147 SimpleGetHelperResult out;
148
149 HttpRequestInfo request;
150 request.method = "GET";
151 request.url = GURL("http://www.google.com/");
152 request.load_flags = 0;
153
154 SessionDependencies session_deps;
155 scoped_ptr<HttpTransaction> trans(
156 new HttpNetworkTransaction(CreateSession(&session_deps)));
157
158 StaticSocketDataProvider data(data_reads, reads_count, NULL, 0);
159 session_deps.socket_factory.AddSocketDataProvider(&data);
160
161 TestCompletionCallback callback;
162
163 CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
164 EXPECT_TRUE(log.bound().IsLoggingAllEvents());
165 int rv = trans->Start(&request, &callback, log.bound());
166 EXPECT_EQ(ERR_IO_PENDING, rv);
167
168 out.rv = callback.WaitForResult();
169 if (out.rv != OK)
170 return out;
171
172 const HttpResponseInfo* response = trans->GetResponseInfo();
173 EXPECT_TRUE(response != NULL);
174
175 EXPECT_TRUE(response->headers != NULL);
176 out.status_line = response->headers->GetStatusLine();
177
178 EXPECT_EQ("192.0.2.33", response->socket_address.host());
179 EXPECT_EQ(0, response->socket_address.port());
180
181 rv = ReadTransaction(trans.get(), &out.response_data);
182 EXPECT_EQ(OK, rv);
183
184 net::CapturingNetLog::EntryList entries;
185 log.GetEntries(&entries);
186 size_t pos = ExpectLogContainsSomewhere(
187 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS,
188 NetLog::PHASE_NONE);
189 ExpectLogContainsSomewhere(
190 entries, pos,
191 NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS,
192 NetLog::PHASE_NONE);
193
194 CapturingNetLog::Entry entry = entries[pos];
195 NetLogHttpRequestParameter* request_params =
196 static_cast<NetLogHttpRequestParameter*>(entry.extra_parameters.get());
197 EXPECT_EQ("GET / HTTP/1.1\r\n", request_params->GetLine());
198 EXPECT_EQ("Host: www.google.com\r\n"
199 "Connection: keep-alive\r\n\r\n",
200 request_params->GetHeaders().ToString());
201
202 return out;
203 }
204
205 void ConnectStatusHelperWithExpectedStatus(const MockRead& status,
206 int expected_status);
207
208 void ConnectStatusHelper(const MockRead& status);
209 };
210
211 // Fill |str| with a long header list that consumes >= |size| bytes.
FillLargeHeadersString(std::string * str,int size)212 void FillLargeHeadersString(std::string* str, int size) {
213 const char* row =
214 "SomeHeaderName: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n";
215 const int sizeof_row = strlen(row);
216 const int num_rows = static_cast<int>(
217 ceil(static_cast<float>(size) / sizeof_row));
218 const int sizeof_data = num_rows * sizeof_row;
219 DCHECK(sizeof_data >= size);
220 str->reserve(sizeof_data);
221
222 for (int i = 0; i < num_rows; ++i)
223 str->append(row, sizeof_row);
224 }
225
226 // Alternative functions that eliminate randomness and dependency on the local
227 // host name so that the generated NTLM messages are reproducible.
MockGenerateRandom1(uint8 * output,size_t n)228 void MockGenerateRandom1(uint8* output, size_t n) {
229 static const uint8 bytes[] = {
230 0x55, 0x29, 0x66, 0x26, 0x6b, 0x9c, 0x73, 0x54
231 };
232 static size_t current_byte = 0;
233 for (size_t i = 0; i < n; ++i) {
234 output[i] = bytes[current_byte++];
235 current_byte %= arraysize(bytes);
236 }
237 }
238
MockGenerateRandom2(uint8 * output,size_t n)239 void MockGenerateRandom2(uint8* output, size_t n) {
240 static const uint8 bytes[] = {
241 0x96, 0x79, 0x85, 0xe7, 0x49, 0x93, 0x70, 0xa1,
242 0x4e, 0xe7, 0x87, 0x45, 0x31, 0x5b, 0xd3, 0x1f
243 };
244 static size_t current_byte = 0;
245 for (size_t i = 0; i < n; ++i) {
246 output[i] = bytes[current_byte++];
247 current_byte %= arraysize(bytes);
248 }
249 }
250
MockGetHostName()251 std::string MockGetHostName() {
252 return "WTC-WIN7";
253 }
254
255 template<typename ParentPool>
256 class CaptureGroupNameSocketPool : public ParentPool {
257 public:
258 CaptureGroupNameSocketPool(HostResolver* host_resolver,
259 CertVerifier* cert_verifier);
260
last_group_name_received() const261 const std::string last_group_name_received() const {
262 return last_group_name_;
263 }
264
RequestSocket(const std::string & group_name,const void * socket_params,RequestPriority priority,ClientSocketHandle * handle,CompletionCallback * callback,const BoundNetLog & net_log)265 virtual int RequestSocket(const std::string& group_name,
266 const void* socket_params,
267 RequestPriority priority,
268 ClientSocketHandle* handle,
269 CompletionCallback* callback,
270 const BoundNetLog& net_log) {
271 last_group_name_ = group_name;
272 return ERR_IO_PENDING;
273 }
CancelRequest(const std::string & group_name,ClientSocketHandle * handle)274 virtual void CancelRequest(const std::string& group_name,
275 ClientSocketHandle* handle) {}
ReleaseSocket(const std::string & group_name,ClientSocket * socket,int id)276 virtual void ReleaseSocket(const std::string& group_name,
277 ClientSocket* socket,
278 int id) {}
CloseIdleSockets()279 virtual void CloseIdleSockets() {}
IdleSocketCount() const280 virtual int IdleSocketCount() const {
281 return 0;
282 }
IdleSocketCountInGroup(const std::string & group_name) const283 virtual int IdleSocketCountInGroup(const std::string& group_name) const {
284 return 0;
285 }
GetLoadState(const std::string & group_name,const ClientSocketHandle * handle) const286 virtual LoadState GetLoadState(const std::string& group_name,
287 const ClientSocketHandle* handle) const {
288 return LOAD_STATE_IDLE;
289 }
ConnectionTimeout() const290 virtual base::TimeDelta ConnectionTimeout() const {
291 return base::TimeDelta();
292 }
293
294 private:
295 std::string last_group_name_;
296 };
297
298 typedef CaptureGroupNameSocketPool<TransportClientSocketPool>
299 CaptureGroupNameTransportSocketPool;
300 typedef CaptureGroupNameSocketPool<HttpProxyClientSocketPool>
301 CaptureGroupNameHttpProxySocketPool;
302 typedef CaptureGroupNameSocketPool<SOCKSClientSocketPool>
303 CaptureGroupNameSOCKSSocketPool;
304 typedef CaptureGroupNameSocketPool<SSLClientSocketPool>
305 CaptureGroupNameSSLSocketPool;
306
307 template<typename ParentPool>
CaptureGroupNameSocketPool(HostResolver * host_resolver,CertVerifier *)308 CaptureGroupNameSocketPool<ParentPool>::CaptureGroupNameSocketPool(
309 HostResolver* host_resolver,
310 CertVerifier* /* cert_verifier */)
311 : ParentPool(0, 0, NULL, host_resolver, NULL, NULL) {}
312
313 template<>
CaptureGroupNameSocketPool(HostResolver * host_resolver,CertVerifier *)314 CaptureGroupNameHttpProxySocketPool::CaptureGroupNameSocketPool(
315 HostResolver* host_resolver,
316 CertVerifier* /* cert_verifier */)
317 : HttpProxyClientSocketPool(0, 0, NULL, host_resolver, NULL, NULL, NULL) {}
318
319 template<>
CaptureGroupNameSocketPool(HostResolver * host_resolver,CertVerifier * cert_verifier)320 CaptureGroupNameSSLSocketPool::CaptureGroupNameSocketPool(
321 HostResolver* host_resolver,
322 CertVerifier* cert_verifier)
323 : SSLClientSocketPool(0, 0, NULL, host_resolver, cert_verifier, NULL, NULL,
324 NULL, NULL, NULL, NULL, NULL, NULL, NULL) {}
325
326 //-----------------------------------------------------------------------------
327
328 // This is the expected list of advertised protocols from the browser's NPN
329 // list.
330 static const char kExpectedNPNString[] = "\x08http/1.1\x06spdy/2";
331
332 // This is the expected return from a current server advertising SPDY.
333 static const char kAlternateProtocolHttpHeader[] =
334 "Alternate-Protocol: 443:npn-spdy/2\r\n\r\n";
335
TEST_F(HttpNetworkTransactionTest,Basic)336 TEST_F(HttpNetworkTransactionTest, Basic) {
337 SessionDependencies session_deps;
338 scoped_ptr<HttpTransaction> trans(
339 new HttpNetworkTransaction(CreateSession(&session_deps)));
340 }
341
TEST_F(HttpNetworkTransactionTest,SimpleGET)342 TEST_F(HttpNetworkTransactionTest, SimpleGET) {
343 MockRead data_reads[] = {
344 MockRead("HTTP/1.0 200 OK\r\n\r\n"),
345 MockRead("hello world"),
346 MockRead(false, OK),
347 };
348 SimpleGetHelperResult out = SimpleGetHelper(data_reads,
349 arraysize(data_reads));
350 EXPECT_EQ(OK, out.rv);
351 EXPECT_EQ("HTTP/1.0 200 OK", out.status_line);
352 EXPECT_EQ("hello world", out.response_data);
353 }
354
355 // Response with no status line.
TEST_F(HttpNetworkTransactionTest,SimpleGETNoHeaders)356 TEST_F(HttpNetworkTransactionTest, SimpleGETNoHeaders) {
357 MockRead data_reads[] = {
358 MockRead("hello world"),
359 MockRead(false, OK),
360 };
361 SimpleGetHelperResult out = SimpleGetHelper(data_reads,
362 arraysize(data_reads));
363 EXPECT_EQ(OK, out.rv);
364 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
365 EXPECT_EQ("hello world", out.response_data);
366 }
367
368 // Allow up to 4 bytes of junk to precede status line.
TEST_F(HttpNetworkTransactionTest,StatusLineJunk2Bytes)369 TEST_F(HttpNetworkTransactionTest, StatusLineJunk2Bytes) {
370 MockRead data_reads[] = {
371 MockRead("xxxHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
372 MockRead(false, OK),
373 };
374 SimpleGetHelperResult out = SimpleGetHelper(data_reads,
375 arraysize(data_reads));
376 EXPECT_EQ(OK, out.rv);
377 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
378 EXPECT_EQ("DATA", out.response_data);
379 }
380
381 // Allow up to 4 bytes of junk to precede status line.
TEST_F(HttpNetworkTransactionTest,StatusLineJunk4Bytes)382 TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes) {
383 MockRead data_reads[] = {
384 MockRead("\n\nQJHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
385 MockRead(false, OK),
386 };
387 SimpleGetHelperResult out = SimpleGetHelper(data_reads,
388 arraysize(data_reads));
389 EXPECT_EQ(OK, out.rv);
390 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
391 EXPECT_EQ("DATA", out.response_data);
392 }
393
394 // Beyond 4 bytes of slop and it should fail to find a status line.
TEST_F(HttpNetworkTransactionTest,StatusLineJunk5Bytes)395 TEST_F(HttpNetworkTransactionTest, StatusLineJunk5Bytes) {
396 MockRead data_reads[] = {
397 MockRead("xxxxxHTTP/1.1 404 Not Found\nServer: blah"),
398 MockRead(false, OK),
399 };
400 SimpleGetHelperResult out = SimpleGetHelper(data_reads,
401 arraysize(data_reads));
402 EXPECT_EQ(OK, out.rv);
403 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
404 EXPECT_EQ("xxxxxHTTP/1.1 404 Not Found\nServer: blah", out.response_data);
405 }
406
407 // Same as StatusLineJunk4Bytes, except the read chunks are smaller.
TEST_F(HttpNetworkTransactionTest,StatusLineJunk4Bytes_Slow)408 TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes_Slow) {
409 MockRead data_reads[] = {
410 MockRead("\n"),
411 MockRead("\n"),
412 MockRead("Q"),
413 MockRead("J"),
414 MockRead("HTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
415 MockRead(false, OK),
416 };
417 SimpleGetHelperResult out = SimpleGetHelper(data_reads,
418 arraysize(data_reads));
419 EXPECT_EQ(OK, out.rv);
420 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
421 EXPECT_EQ("DATA", out.response_data);
422 }
423
424 // Close the connection before enough bytes to have a status line.
TEST_F(HttpNetworkTransactionTest,StatusLinePartial)425 TEST_F(HttpNetworkTransactionTest, StatusLinePartial) {
426 MockRead data_reads[] = {
427 MockRead("HTT"),
428 MockRead(false, OK),
429 };
430 SimpleGetHelperResult out = SimpleGetHelper(data_reads,
431 arraysize(data_reads));
432 EXPECT_EQ(OK, out.rv);
433 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
434 EXPECT_EQ("HTT", out.response_data);
435 }
436
437 // Simulate a 204 response, lacking a Content-Length header, sent over a
438 // persistent connection. The response should still terminate since a 204
439 // cannot have a response body.
TEST_F(HttpNetworkTransactionTest,StopsReading204)440 TEST_F(HttpNetworkTransactionTest, StopsReading204) {
441 MockRead data_reads[] = {
442 MockRead("HTTP/1.1 204 No Content\r\n\r\n"),
443 MockRead("junk"), // Should not be read!!
444 MockRead(false, OK),
445 };
446 SimpleGetHelperResult out = SimpleGetHelper(data_reads,
447 arraysize(data_reads));
448 EXPECT_EQ(OK, out.rv);
449 EXPECT_EQ("HTTP/1.1 204 No Content", out.status_line);
450 EXPECT_EQ("", out.response_data);
451 }
452
453 // A simple request using chunked encoding with some extra data after.
454 // (Like might be seen in a pipelined response.)
TEST_F(HttpNetworkTransactionTest,ChunkedEncoding)455 TEST_F(HttpNetworkTransactionTest, ChunkedEncoding) {
456 MockRead data_reads[] = {
457 MockRead("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"),
458 MockRead("5\r\nHello\r\n"),
459 MockRead("1\r\n"),
460 MockRead(" \r\n"),
461 MockRead("5\r\nworld\r\n"),
462 MockRead("0\r\n\r\nHTTP/1.1 200 OK\r\n"),
463 MockRead(false, OK),
464 };
465 SimpleGetHelperResult out = SimpleGetHelper(data_reads,
466 arraysize(data_reads));
467 EXPECT_EQ(OK, out.rv);
468 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
469 EXPECT_EQ("Hello world", out.response_data);
470 }
471
472 // Next tests deal with http://crbug.com/56344.
473
TEST_F(HttpNetworkTransactionTest,MultipleContentLengthHeadersNoTransferEncoding)474 TEST_F(HttpNetworkTransactionTest,
475 MultipleContentLengthHeadersNoTransferEncoding) {
476 MockRead data_reads[] = {
477 MockRead("HTTP/1.1 200 OK\r\n"),
478 MockRead("Content-Length: 10\r\n"),
479 MockRead("Content-Length: 5\r\n\r\n"),
480 };
481 SimpleGetHelperResult out = SimpleGetHelper(data_reads,
482 arraysize(data_reads));
483 EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH, out.rv);
484 }
485
TEST_F(HttpNetworkTransactionTest,DuplicateContentLengthHeadersNoTransferEncoding)486 TEST_F(HttpNetworkTransactionTest,
487 DuplicateContentLengthHeadersNoTransferEncoding) {
488 MockRead data_reads[] = {
489 MockRead("HTTP/1.1 200 OK\r\n"),
490 MockRead("Content-Length: 5\r\n"),
491 MockRead("Content-Length: 5\r\n\r\n"),
492 MockRead("Hello"),
493 };
494 SimpleGetHelperResult out = SimpleGetHelper(data_reads,
495 arraysize(data_reads));
496 EXPECT_EQ(OK, out.rv);
497 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
498 EXPECT_EQ("Hello", out.response_data);
499 }
500
TEST_F(HttpNetworkTransactionTest,ComplexContentLengthHeadersNoTransferEncoding)501 TEST_F(HttpNetworkTransactionTest,
502 ComplexContentLengthHeadersNoTransferEncoding) {
503 // More than 2 dupes.
504 {
505 MockRead data_reads[] = {
506 MockRead("HTTP/1.1 200 OK\r\n"),
507 MockRead("Content-Length: 5\r\n"),
508 MockRead("Content-Length: 5\r\n"),
509 MockRead("Content-Length: 5\r\n\r\n"),
510 MockRead("Hello"),
511 };
512 SimpleGetHelperResult out = SimpleGetHelper(data_reads,
513 arraysize(data_reads));
514 EXPECT_EQ(OK, out.rv);
515 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
516 EXPECT_EQ("Hello", out.response_data);
517 }
518 // HTTP/1.0
519 {
520 MockRead data_reads[] = {
521 MockRead("HTTP/1.0 200 OK\r\n"),
522 MockRead("Content-Length: 5\r\n"),
523 MockRead("Content-Length: 5\r\n"),
524 MockRead("Content-Length: 5\r\n\r\n"),
525 MockRead("Hello"),
526 };
527 SimpleGetHelperResult out = SimpleGetHelper(data_reads,
528 arraysize(data_reads));
529 EXPECT_EQ(OK, out.rv);
530 EXPECT_EQ("HTTP/1.0 200 OK", out.status_line);
531 EXPECT_EQ("Hello", out.response_data);
532 }
533 // 2 dupes and one mismatched.
534 {
535 MockRead data_reads[] = {
536 MockRead("HTTP/1.1 200 OK\r\n"),
537 MockRead("Content-Length: 10\r\n"),
538 MockRead("Content-Length: 10\r\n"),
539 MockRead("Content-Length: 5\r\n\r\n"),
540 };
541 SimpleGetHelperResult out = SimpleGetHelper(data_reads,
542 arraysize(data_reads));
543 EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH, out.rv);
544 }
545 }
546
TEST_F(HttpNetworkTransactionTest,MultipleContentLengthHeadersTransferEncoding)547 TEST_F(HttpNetworkTransactionTest,
548 MultipleContentLengthHeadersTransferEncoding) {
549 MockRead data_reads[] = {
550 MockRead("HTTP/1.1 200 OK\r\n"),
551 MockRead("Content-Length: 666\r\n"),
552 MockRead("Content-Length: 1337\r\n"),
553 MockRead("Transfer-Encoding: chunked\r\n\r\n"),
554 MockRead("5\r\nHello\r\n"),
555 MockRead("1\r\n"),
556 MockRead(" \r\n"),
557 MockRead("5\r\nworld\r\n"),
558 MockRead("0\r\n\r\nHTTP/1.1 200 OK\r\n"),
559 MockRead(false, OK),
560 };
561 SimpleGetHelperResult out = SimpleGetHelper(data_reads,
562 arraysize(data_reads));
563 EXPECT_EQ(OK, out.rv);
564 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
565 EXPECT_EQ("Hello world", out.response_data);
566 }
567
568 // Do a request using the HEAD method. Verify that we don't try to read the
569 // message body (since HEAD has none).
TEST_F(HttpNetworkTransactionTest,Head)570 TEST_F(HttpNetworkTransactionTest, Head) {
571 HttpRequestInfo request;
572 request.method = "HEAD";
573 request.url = GURL("http://www.google.com/");
574 request.load_flags = 0;
575
576 SessionDependencies session_deps;
577 scoped_ptr<HttpTransaction> trans(
578 new HttpNetworkTransaction(CreateSession(&session_deps)));
579
580 MockWrite data_writes1[] = {
581 MockWrite("HEAD / HTTP/1.1\r\n"
582 "Host: www.google.com\r\n"
583 "Connection: keep-alive\r\n"
584 "Content-Length: 0\r\n\r\n"),
585 };
586 MockRead data_reads1[] = {
587 MockRead("HTTP/1.1 404 Not Found\r\n"),
588 MockRead("Server: Blah\r\n"),
589 MockRead("Content-Length: 1234\r\n\r\n"),
590
591 // No response body because the test stops reading here.
592 MockRead(false, ERR_UNEXPECTED), // Should not be reached.
593 };
594
595 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
596 data_writes1, arraysize(data_writes1));
597 session_deps.socket_factory.AddSocketDataProvider(&data1);
598
599 TestCompletionCallback callback1;
600
601 int rv = trans->Start(&request, &callback1, BoundNetLog());
602 EXPECT_EQ(ERR_IO_PENDING, rv);
603
604 rv = callback1.WaitForResult();
605 EXPECT_EQ(OK, rv);
606
607 const HttpResponseInfo* response = trans->GetResponseInfo();
608 EXPECT_FALSE(response == NULL);
609
610 // Check that the headers got parsed.
611 EXPECT_TRUE(response->headers != NULL);
612 EXPECT_EQ(1234, response->headers->GetContentLength());
613 EXPECT_EQ("HTTP/1.1 404 Not Found", response->headers->GetStatusLine());
614
615 std::string server_header;
616 void* iter = NULL;
617 bool has_server_header = response->headers->EnumerateHeader(
618 &iter, "Server", &server_header);
619 EXPECT_TRUE(has_server_header);
620 EXPECT_EQ("Blah", server_header);
621
622 // Reading should give EOF right away, since there is no message body
623 // (despite non-zero content-length).
624 std::string response_data;
625 rv = ReadTransaction(trans.get(), &response_data);
626 EXPECT_EQ(OK, rv);
627 EXPECT_EQ("", response_data);
628 }
629
TEST_F(HttpNetworkTransactionTest,ReuseConnection)630 TEST_F(HttpNetworkTransactionTest, ReuseConnection) {
631 SessionDependencies session_deps;
632 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
633
634 MockRead data_reads[] = {
635 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
636 MockRead("hello"),
637 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
638 MockRead("world"),
639 MockRead(false, OK),
640 };
641 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
642 session_deps.socket_factory.AddSocketDataProvider(&data);
643
644 const char* const kExpectedResponseData[] = {
645 "hello", "world"
646 };
647
648 for (int i = 0; i < 2; ++i) {
649 HttpRequestInfo request;
650 request.method = "GET";
651 request.url = GURL("http://www.google.com/");
652 request.load_flags = 0;
653
654 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
655
656 TestCompletionCallback callback;
657
658 int rv = trans->Start(&request, &callback, BoundNetLog());
659 EXPECT_EQ(ERR_IO_PENDING, rv);
660
661 rv = callback.WaitForResult();
662 EXPECT_EQ(OK, rv);
663
664 const HttpResponseInfo* response = trans->GetResponseInfo();
665 EXPECT_TRUE(response != NULL);
666
667 EXPECT_TRUE(response->headers != NULL);
668 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
669
670 std::string response_data;
671 rv = ReadTransaction(trans.get(), &response_data);
672 EXPECT_EQ(OK, rv);
673 EXPECT_EQ(kExpectedResponseData[i], response_data);
674 }
675 }
676
TEST_F(HttpNetworkTransactionTest,Ignores100)677 TEST_F(HttpNetworkTransactionTest, Ignores100) {
678 HttpRequestInfo request;
679 request.method = "POST";
680 request.url = GURL("http://www.foo.com/");
681 request.upload_data = new UploadData;
682 request.upload_data->AppendBytes("foo", 3);
683 request.load_flags = 0;
684
685 SessionDependencies session_deps;
686 scoped_ptr<HttpTransaction> trans(
687 new HttpNetworkTransaction(CreateSession(&session_deps)));
688
689 MockRead data_reads[] = {
690 MockRead("HTTP/1.0 100 Continue\r\n\r\n"),
691 MockRead("HTTP/1.0 200 OK\r\n\r\n"),
692 MockRead("hello world"),
693 MockRead(false, OK),
694 };
695 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
696 session_deps.socket_factory.AddSocketDataProvider(&data);
697
698 TestCompletionCallback callback;
699
700 int rv = trans->Start(&request, &callback, BoundNetLog());
701 EXPECT_EQ(ERR_IO_PENDING, rv);
702
703 rv = callback.WaitForResult();
704 EXPECT_EQ(OK, rv);
705
706 const HttpResponseInfo* response = trans->GetResponseInfo();
707 EXPECT_TRUE(response != NULL);
708
709 EXPECT_TRUE(response->headers != NULL);
710 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine());
711
712 std::string response_data;
713 rv = ReadTransaction(trans.get(), &response_data);
714 EXPECT_EQ(OK, rv);
715 EXPECT_EQ("hello world", response_data);
716 }
717
718 // This test is almost the same as Ignores100 above, but the response contains
719 // a 102 instead of a 100. Also, instead of HTTP/1.0 the response is
720 // HTTP/1.1 and the two status headers are read in one read.
TEST_F(HttpNetworkTransactionTest,Ignores1xx)721 TEST_F(HttpNetworkTransactionTest, Ignores1xx) {
722 HttpRequestInfo request;
723 request.method = "GET";
724 request.url = GURL("http://www.foo.com/");
725 request.load_flags = 0;
726
727 SessionDependencies session_deps;
728 scoped_ptr<HttpTransaction> trans(
729 new HttpNetworkTransaction(CreateSession(&session_deps)));
730
731 MockRead data_reads[] = {
732 MockRead("HTTP/1.1 102 Unspecified status code\r\n\r\n"
733 "HTTP/1.1 200 OK\r\n\r\n"),
734 MockRead("hello world"),
735 MockRead(false, OK),
736 };
737 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
738 session_deps.socket_factory.AddSocketDataProvider(&data);
739
740 TestCompletionCallback callback;
741
742 int rv = trans->Start(&request, &callback, BoundNetLog());
743 EXPECT_EQ(ERR_IO_PENDING, rv);
744
745 rv = callback.WaitForResult();
746 EXPECT_EQ(OK, rv);
747
748 const HttpResponseInfo* response = trans->GetResponseInfo();
749 EXPECT_TRUE(response != NULL);
750
751 EXPECT_TRUE(response->headers != NULL);
752 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
753
754 std::string response_data;
755 rv = ReadTransaction(trans.get(), &response_data);
756 EXPECT_EQ(OK, rv);
757 EXPECT_EQ("hello world", response_data);
758 }
759
TEST_F(HttpNetworkTransactionTest,Incomplete100ThenEOF)760 TEST_F(HttpNetworkTransactionTest, Incomplete100ThenEOF) {
761 HttpRequestInfo request;
762 request.method = "POST";
763 request.url = GURL("http://www.foo.com/");
764 request.load_flags = 0;
765
766 SessionDependencies session_deps;
767 scoped_ptr<HttpTransaction> trans(
768 new HttpNetworkTransaction(CreateSession(&session_deps)));
769
770 MockRead data_reads[] = {
771 MockRead(false, "HTTP/1.0 100 Continue\r\n"),
772 MockRead(true, 0),
773 };
774 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
775 session_deps.socket_factory.AddSocketDataProvider(&data);
776
777 TestCompletionCallback callback;
778
779 int rv = trans->Start(&request, &callback, BoundNetLog());
780 EXPECT_EQ(ERR_IO_PENDING, rv);
781
782 rv = callback.WaitForResult();
783 EXPECT_EQ(OK, rv);
784
785 std::string response_data;
786 rv = ReadTransaction(trans.get(), &response_data);
787 EXPECT_EQ(OK, rv);
788 EXPECT_EQ("", response_data);
789 }
790
TEST_F(HttpNetworkTransactionTest,EmptyResponse)791 TEST_F(HttpNetworkTransactionTest, EmptyResponse) {
792 HttpRequestInfo request;
793 request.method = "POST";
794 request.url = GURL("http://www.foo.com/");
795 request.load_flags = 0;
796
797 SessionDependencies session_deps;
798 scoped_ptr<HttpTransaction> trans(
799 new HttpNetworkTransaction(CreateSession(&session_deps)));
800
801 MockRead data_reads[] = {
802 MockRead(true, 0),
803 };
804 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
805 session_deps.socket_factory.AddSocketDataProvider(&data);
806
807 TestCompletionCallback callback;
808
809 int rv = trans->Start(&request, &callback, BoundNetLog());
810 EXPECT_EQ(ERR_IO_PENDING, rv);
811
812 rv = callback.WaitForResult();
813 EXPECT_EQ(ERR_EMPTY_RESPONSE, rv);
814 }
815
816 // read_failure specifies a read failure that should cause the network
817 // transaction to resend the request.
KeepAliveConnectionResendRequestTest(const MockRead & read_failure)818 void HttpNetworkTransactionTest::KeepAliveConnectionResendRequestTest(
819 const MockRead& read_failure) {
820 HttpRequestInfo request;
821 request.method = "GET";
822 request.url = GURL("http://www.foo.com/");
823 request.load_flags = 0;
824
825 SessionDependencies session_deps;
826 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
827
828 MockRead data1_reads[] = {
829 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
830 MockRead("hello"),
831 read_failure, // Now, we reuse the connection and fail the first read.
832 };
833 StaticSocketDataProvider data1(data1_reads, arraysize(data1_reads), NULL, 0);
834 session_deps.socket_factory.AddSocketDataProvider(&data1);
835
836 MockRead data2_reads[] = {
837 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
838 MockRead("world"),
839 MockRead(true, OK),
840 };
841 StaticSocketDataProvider data2(data2_reads, arraysize(data2_reads), NULL, 0);
842 session_deps.socket_factory.AddSocketDataProvider(&data2);
843
844 const char* kExpectedResponseData[] = {
845 "hello", "world"
846 };
847
848 for (int i = 0; i < 2; ++i) {
849 TestCompletionCallback callback;
850
851 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
852
853 int rv = trans->Start(&request, &callback, BoundNetLog());
854 EXPECT_EQ(ERR_IO_PENDING, rv);
855
856 rv = callback.WaitForResult();
857 EXPECT_EQ(OK, rv);
858
859 const HttpResponseInfo* response = trans->GetResponseInfo();
860 EXPECT_TRUE(response != NULL);
861
862 EXPECT_TRUE(response->headers != NULL);
863 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
864
865 std::string response_data;
866 rv = ReadTransaction(trans.get(), &response_data);
867 EXPECT_EQ(OK, rv);
868 EXPECT_EQ(kExpectedResponseData[i], response_data);
869 }
870 }
871
TEST_F(HttpNetworkTransactionTest,KeepAliveConnectionReset)872 TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionReset) {
873 MockRead read_failure(true, ERR_CONNECTION_RESET);
874 KeepAliveConnectionResendRequestTest(read_failure);
875 }
876
TEST_F(HttpNetworkTransactionTest,KeepAliveConnectionEOF)877 TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionEOF) {
878 MockRead read_failure(false, OK); // EOF
879 KeepAliveConnectionResendRequestTest(read_failure);
880 }
881
TEST_F(HttpNetworkTransactionTest,NonKeepAliveConnectionReset)882 TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionReset) {
883 HttpRequestInfo request;
884 request.method = "GET";
885 request.url = GURL("http://www.google.com/");
886 request.load_flags = 0;
887
888 SessionDependencies session_deps;
889 scoped_ptr<HttpTransaction> trans(
890 new HttpNetworkTransaction(CreateSession(&session_deps)));
891
892 MockRead data_reads[] = {
893 MockRead(true, ERR_CONNECTION_RESET),
894 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used
895 MockRead("hello world"),
896 MockRead(false, OK),
897 };
898 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
899 session_deps.socket_factory.AddSocketDataProvider(&data);
900
901 TestCompletionCallback callback;
902
903 int rv = trans->Start(&request, &callback, BoundNetLog());
904 EXPECT_EQ(ERR_IO_PENDING, rv);
905
906 rv = callback.WaitForResult();
907 EXPECT_EQ(ERR_CONNECTION_RESET, rv);
908
909 const HttpResponseInfo* response = trans->GetResponseInfo();
910 EXPECT_TRUE(response == NULL);
911 }
912
913 // What do various browsers do when the server closes a non-keepalive
914 // connection without sending any response header or body?
915 //
916 // IE7: error page
917 // Safari 3.1.2 (Windows): error page
918 // Firefox 3.0.1: blank page
919 // Opera 9.52: after five attempts, blank page
920 // Us with WinHTTP: error page (ERR_INVALID_RESPONSE)
921 // Us: error page (EMPTY_RESPONSE)
TEST_F(HttpNetworkTransactionTest,NonKeepAliveConnectionEOF)922 TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionEOF) {
923 MockRead data_reads[] = {
924 MockRead(false, OK), // EOF
925 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used
926 MockRead("hello world"),
927 MockRead(false, OK),
928 };
929 SimpleGetHelperResult out = SimpleGetHelper(data_reads,
930 arraysize(data_reads));
931 EXPECT_EQ(ERR_EMPTY_RESPONSE, out.rv);
932 }
933
934 // Test that we correctly reuse a keep-alive connection after not explicitly
935 // reading the body.
TEST_F(HttpNetworkTransactionTest,KeepAliveAfterUnreadBody)936 TEST_F(HttpNetworkTransactionTest, KeepAliveAfterUnreadBody) {
937 HttpRequestInfo request;
938 request.method = "GET";
939 request.url = GURL("http://www.foo.com/");
940 request.load_flags = 0;
941
942 SessionDependencies session_deps;
943 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
944
945 // Note that because all these reads happen in the same
946 // StaticSocketDataProvider, it shows that the same socket is being reused for
947 // all transactions.
948 MockRead data1_reads[] = {
949 MockRead("HTTP/1.1 204 No Content\r\n\r\n"),
950 MockRead("HTTP/1.1 205 Reset Content\r\n\r\n"),
951 MockRead("HTTP/1.1 304 Not Modified\r\n\r\n"),
952 MockRead("HTTP/1.1 302 Found\r\n"
953 "Content-Length: 0\r\n\r\n"),
954 MockRead("HTTP/1.1 302 Found\r\n"
955 "Content-Length: 5\r\n\r\n"
956 "hello"),
957 MockRead("HTTP/1.1 301 Moved Permanently\r\n"
958 "Content-Length: 0\r\n\r\n"),
959 MockRead("HTTP/1.1 301 Moved Permanently\r\n"
960 "Content-Length: 5\r\n\r\n"
961 "hello"),
962 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
963 MockRead("hello"),
964 };
965 StaticSocketDataProvider data1(data1_reads, arraysize(data1_reads), NULL, 0);
966 session_deps.socket_factory.AddSocketDataProvider(&data1);
967
968 MockRead data2_reads[] = {
969 MockRead(false, ERR_UNEXPECTED), // Should not be reached.
970 };
971 StaticSocketDataProvider data2(data2_reads, arraysize(data2_reads), NULL, 0);
972 session_deps.socket_factory.AddSocketDataProvider(&data2);
973
974 const int kNumUnreadBodies = arraysize(data1_reads) - 2;
975 std::string response_lines[kNumUnreadBodies];
976
977 for (size_t i = 0; i < arraysize(data1_reads) - 2; ++i) {
978 TestCompletionCallback callback;
979
980 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
981
982 int rv = trans->Start(&request, &callback, BoundNetLog());
983 EXPECT_EQ(ERR_IO_PENDING, rv);
984
985 rv = callback.WaitForResult();
986 EXPECT_EQ(OK, rv);
987
988 const HttpResponseInfo* response = trans->GetResponseInfo();
989 ASSERT_TRUE(response != NULL);
990
991 ASSERT_TRUE(response->headers != NULL);
992 response_lines[i] = response->headers->GetStatusLine();
993
994 // We intentionally don't read the response bodies.
995 }
996
997 const char* const kStatusLines[] = {
998 "HTTP/1.1 204 No Content",
999 "HTTP/1.1 205 Reset Content",
1000 "HTTP/1.1 304 Not Modified",
1001 "HTTP/1.1 302 Found",
1002 "HTTP/1.1 302 Found",
1003 "HTTP/1.1 301 Moved Permanently",
1004 "HTTP/1.1 301 Moved Permanently",
1005 };
1006
1007 COMPILE_ASSERT(kNumUnreadBodies == arraysize(kStatusLines),
1008 forgot_to_update_kStatusLines);
1009
1010 for (int i = 0; i < kNumUnreadBodies; ++i)
1011 EXPECT_EQ(kStatusLines[i], response_lines[i]);
1012
1013 TestCompletionCallback callback;
1014 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
1015 int rv = trans->Start(&request, &callback, BoundNetLog());
1016 EXPECT_EQ(ERR_IO_PENDING, rv);
1017 rv = callback.WaitForResult();
1018 EXPECT_EQ(OK, rv);
1019 const HttpResponseInfo* response = trans->GetResponseInfo();
1020 ASSERT_TRUE(response != NULL);
1021 ASSERT_TRUE(response->headers != NULL);
1022 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
1023 std::string response_data;
1024 rv = ReadTransaction(trans.get(), &response_data);
1025 EXPECT_EQ(OK, rv);
1026 EXPECT_EQ("hello", response_data);
1027 }
1028
1029 // Test the request-challenge-retry sequence for basic auth.
1030 // (basic auth is the easiest to mock, because it has no randomness).
TEST_F(HttpNetworkTransactionTest,BasicAuth)1031 TEST_F(HttpNetworkTransactionTest, BasicAuth) {
1032 HttpRequestInfo request;
1033 request.method = "GET";
1034 request.url = GURL("http://www.google.com/");
1035 request.load_flags = 0;
1036
1037 SessionDependencies session_deps;
1038 scoped_ptr<HttpTransaction> trans(
1039 new HttpNetworkTransaction(CreateSession(&session_deps)));
1040
1041 MockWrite data_writes1[] = {
1042 MockWrite("GET / HTTP/1.1\r\n"
1043 "Host: www.google.com\r\n"
1044 "Connection: keep-alive\r\n\r\n"),
1045 };
1046
1047 MockRead data_reads1[] = {
1048 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
1049 // Give a couple authenticate options (only the middle one is actually
1050 // supported).
1051 MockRead("WWW-Authenticate: Basic invalid\r\n"), // Malformed.
1052 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1053 MockRead("WWW-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"),
1054 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1055 // Large content-length -- won't matter, as connection will be reset.
1056 MockRead("Content-Length: 10000\r\n\r\n"),
1057 MockRead(false, ERR_FAILED),
1058 };
1059
1060 // After calling trans->RestartWithAuth(), this is the request we should
1061 // be issuing -- the final header line contains the credentials.
1062 MockWrite data_writes2[] = {
1063 MockWrite("GET / HTTP/1.1\r\n"
1064 "Host: www.google.com\r\n"
1065 "Connection: keep-alive\r\n"
1066 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1067 };
1068
1069 // Lastly, the server responds with the actual content.
1070 MockRead data_reads2[] = {
1071 MockRead("HTTP/1.0 200 OK\r\n"),
1072 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1073 MockRead("Content-Length: 100\r\n\r\n"),
1074 MockRead(false, OK),
1075 };
1076
1077 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
1078 data_writes1, arraysize(data_writes1));
1079 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
1080 data_writes2, arraysize(data_writes2));
1081 session_deps.socket_factory.AddSocketDataProvider(&data1);
1082 session_deps.socket_factory.AddSocketDataProvider(&data2);
1083
1084 TestCompletionCallback callback1;
1085
1086 int rv = trans->Start(&request, &callback1, BoundNetLog());
1087 EXPECT_EQ(ERR_IO_PENDING, rv);
1088
1089 rv = callback1.WaitForResult();
1090 EXPECT_EQ(OK, rv);
1091
1092 const HttpResponseInfo* response = trans->GetResponseInfo();
1093 EXPECT_FALSE(response == NULL);
1094
1095 // The password prompt info should have been set in response->auth_challenge.
1096 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1097
1098 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
1099 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1100 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1101
1102 TestCompletionCallback callback2;
1103
1104 rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
1105 EXPECT_EQ(ERR_IO_PENDING, rv);
1106
1107 rv = callback2.WaitForResult();
1108 EXPECT_EQ(OK, rv);
1109
1110 response = trans->GetResponseInfo();
1111 EXPECT_FALSE(response == NULL);
1112 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1113 EXPECT_EQ(100, response->headers->GetContentLength());
1114 }
1115
TEST_F(HttpNetworkTransactionTest,DoNotSendAuth)1116 TEST_F(HttpNetworkTransactionTest, DoNotSendAuth) {
1117 HttpRequestInfo request;
1118 request.method = "GET";
1119 request.url = GURL("http://www.google.com/");
1120 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA;
1121
1122 SessionDependencies session_deps;
1123 scoped_ptr<HttpTransaction> trans(
1124 new HttpNetworkTransaction(CreateSession(&session_deps)));
1125
1126 MockWrite data_writes[] = {
1127 MockWrite("GET / HTTP/1.1\r\n"
1128 "Host: www.google.com\r\n"
1129 "Connection: keep-alive\r\n\r\n"),
1130 };
1131
1132 MockRead data_reads[] = {
1133 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
1134 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1135 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1136 // Large content-length -- won't matter, as connection will be reset.
1137 MockRead("Content-Length: 10000\r\n\r\n"),
1138 MockRead(false, ERR_FAILED),
1139 };
1140
1141 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
1142 data_writes, arraysize(data_writes));
1143 session_deps.socket_factory.AddSocketDataProvider(&data);
1144 TestCompletionCallback callback;
1145
1146 int rv = trans->Start(&request, &callback, BoundNetLog());
1147 EXPECT_EQ(ERR_IO_PENDING, rv);
1148
1149 rv = callback.WaitForResult();
1150 EXPECT_EQ(0, rv);
1151
1152 const HttpResponseInfo* response = trans->GetResponseInfo();
1153 ASSERT_FALSE(response == NULL);
1154 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1155 }
1156
1157 // Test the request-challenge-retry sequence for basic auth, over a keep-alive
1158 // connection.
TEST_F(HttpNetworkTransactionTest,BasicAuthKeepAlive)1159 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAlive) {
1160 HttpRequestInfo request;
1161 request.method = "GET";
1162 request.url = GURL("http://www.google.com/");
1163 request.load_flags = 0;
1164
1165 SessionDependencies session_deps;
1166 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
1167
1168 MockWrite data_writes1[] = {
1169 MockWrite("GET / HTTP/1.1\r\n"
1170 "Host: www.google.com\r\n"
1171 "Connection: keep-alive\r\n\r\n"),
1172
1173 // After calling trans->RestartWithAuth(), this is the request we should
1174 // be issuing -- the final header line contains the credentials.
1175 MockWrite("GET / HTTP/1.1\r\n"
1176 "Host: www.google.com\r\n"
1177 "Connection: keep-alive\r\n"
1178 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1179 };
1180
1181 MockRead data_reads1[] = {
1182 MockRead("HTTP/1.1 401 Unauthorized\r\n"),
1183 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1184 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1185 MockRead("Content-Length: 14\r\n\r\n"),
1186 MockRead("Unauthorized\r\n"),
1187
1188 // Lastly, the server responds with the actual content.
1189 MockRead("HTTP/1.1 200 OK\r\n"),
1190 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1191 MockRead("Content-Length: 5\r\n\r\n"),
1192 MockRead("Hello"),
1193 };
1194
1195 // If there is a regression where we disconnect a Keep-Alive
1196 // connection during an auth roundtrip, we'll end up reading this.
1197 MockRead data_reads2[] = {
1198 MockRead(false, ERR_FAILED),
1199 };
1200
1201 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
1202 data_writes1, arraysize(data_writes1));
1203 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
1204 NULL, 0);
1205 session_deps.socket_factory.AddSocketDataProvider(&data1);
1206 session_deps.socket_factory.AddSocketDataProvider(&data2);
1207
1208 TestCompletionCallback callback1;
1209
1210 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
1211 int rv = trans->Start(&request, &callback1, BoundNetLog());
1212 EXPECT_EQ(ERR_IO_PENDING, rv);
1213
1214 rv = callback1.WaitForResult();
1215 EXPECT_EQ(OK, rv);
1216
1217 const HttpResponseInfo* response = trans->GetResponseInfo();
1218 EXPECT_FALSE(response == NULL);
1219
1220 // The password prompt info should have been set in response->auth_challenge.
1221 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1222
1223 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
1224 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1225 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1226
1227 TestCompletionCallback callback2;
1228
1229 rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
1230 EXPECT_EQ(ERR_IO_PENDING, rv);
1231
1232 rv = callback2.WaitForResult();
1233 EXPECT_EQ(OK, rv);
1234
1235 response = trans->GetResponseInfo();
1236 ASSERT_FALSE(response == NULL);
1237 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1238 EXPECT_EQ(5, response->headers->GetContentLength());
1239 }
1240
1241 // Test the request-challenge-retry sequence for basic auth, over a keep-alive
1242 // connection and with no response body to drain.
TEST_F(HttpNetworkTransactionTest,BasicAuthKeepAliveNoBody)1243 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) {
1244 HttpRequestInfo request;
1245 request.method = "GET";
1246 request.url = GURL("http://www.google.com/");
1247 request.load_flags = 0;
1248
1249 SessionDependencies session_deps;
1250 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
1251
1252 MockWrite data_writes1[] = {
1253 MockWrite("GET / HTTP/1.1\r\n"
1254 "Host: www.google.com\r\n"
1255 "Connection: keep-alive\r\n\r\n"),
1256
1257 // After calling trans->RestartWithAuth(), this is the request we should
1258 // be issuing -- the final header line contains the credentials.
1259 MockWrite("GET / HTTP/1.1\r\n"
1260 "Host: www.google.com\r\n"
1261 "Connection: keep-alive\r\n"
1262 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1263 };
1264
1265 MockRead data_reads1[] = {
1266 MockRead("HTTP/1.1 401 Unauthorized\r\n"),
1267 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1268 MockRead("Content-Length: 0\r\n\r\n"), // No response body.
1269
1270 // Lastly, the server responds with the actual content.
1271 MockRead("HTTP/1.1 200 OK\r\n"),
1272 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1273 MockRead("Content-Length: 5\r\n\r\n"),
1274 MockRead("hello"),
1275 };
1276
1277 // An incorrect reconnect would cause this to be read.
1278 MockRead data_reads2[] = {
1279 MockRead(false, ERR_FAILED),
1280 };
1281
1282 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
1283 data_writes1, arraysize(data_writes1));
1284 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
1285 NULL, 0);
1286 session_deps.socket_factory.AddSocketDataProvider(&data1);
1287 session_deps.socket_factory.AddSocketDataProvider(&data2);
1288
1289 TestCompletionCallback callback1;
1290
1291 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
1292 int rv = trans->Start(&request, &callback1, BoundNetLog());
1293 EXPECT_EQ(ERR_IO_PENDING, rv);
1294
1295 rv = callback1.WaitForResult();
1296 EXPECT_EQ(OK, rv);
1297
1298 const HttpResponseInfo* response = trans->GetResponseInfo();
1299 EXPECT_FALSE(response == NULL);
1300
1301 // The password prompt info should have been set in response->auth_challenge.
1302 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1303
1304 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
1305 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1306 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1307
1308 TestCompletionCallback callback2;
1309
1310 rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
1311 EXPECT_EQ(ERR_IO_PENDING, rv);
1312
1313 rv = callback2.WaitForResult();
1314 EXPECT_EQ(OK, rv);
1315
1316 response = trans->GetResponseInfo();
1317 ASSERT_FALSE(response == NULL);
1318 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1319 EXPECT_EQ(5, response->headers->GetContentLength());
1320 }
1321
1322 // Test the request-challenge-retry sequence for basic auth, over a keep-alive
1323 // connection and with a large response body to drain.
TEST_F(HttpNetworkTransactionTest,BasicAuthKeepAliveLargeBody)1324 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) {
1325 HttpRequestInfo request;
1326 request.method = "GET";
1327 request.url = GURL("http://www.google.com/");
1328 request.load_flags = 0;
1329
1330 SessionDependencies session_deps;
1331 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
1332
1333 MockWrite data_writes1[] = {
1334 MockWrite("GET / HTTP/1.1\r\n"
1335 "Host: www.google.com\r\n"
1336 "Connection: keep-alive\r\n\r\n"),
1337
1338 // After calling trans->RestartWithAuth(), this is the request we should
1339 // be issuing -- the final header line contains the credentials.
1340 MockWrite("GET / HTTP/1.1\r\n"
1341 "Host: www.google.com\r\n"
1342 "Connection: keep-alive\r\n"
1343 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1344 };
1345
1346 // Respond with 5 kb of response body.
1347 std::string large_body_string("Unauthorized");
1348 large_body_string.append(5 * 1024, ' ');
1349 large_body_string.append("\r\n");
1350
1351 MockRead data_reads1[] = {
1352 MockRead("HTTP/1.1 401 Unauthorized\r\n"),
1353 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1354 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1355 // 5134 = 12 + 5 * 1024 + 2
1356 MockRead("Content-Length: 5134\r\n\r\n"),
1357 MockRead(true, large_body_string.data(), large_body_string.size()),
1358
1359 // Lastly, the server responds with the actual content.
1360 MockRead("HTTP/1.1 200 OK\r\n"),
1361 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1362 MockRead("Content-Length: 5\r\n\r\n"),
1363 MockRead("hello"),
1364 };
1365
1366 // An incorrect reconnect would cause this to be read.
1367 MockRead data_reads2[] = {
1368 MockRead(false, ERR_FAILED),
1369 };
1370
1371 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
1372 data_writes1, arraysize(data_writes1));
1373 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
1374 NULL, 0);
1375 session_deps.socket_factory.AddSocketDataProvider(&data1);
1376 session_deps.socket_factory.AddSocketDataProvider(&data2);
1377
1378 TestCompletionCallback callback1;
1379
1380 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
1381 int rv = trans->Start(&request, &callback1, BoundNetLog());
1382 EXPECT_EQ(ERR_IO_PENDING, rv);
1383
1384 rv = callback1.WaitForResult();
1385 EXPECT_EQ(OK, rv);
1386
1387 const HttpResponseInfo* response = trans->GetResponseInfo();
1388 EXPECT_FALSE(response == NULL);
1389
1390 // The password prompt info should have been set in response->auth_challenge.
1391 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1392
1393 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
1394 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1395 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1396
1397 TestCompletionCallback callback2;
1398
1399 rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
1400 EXPECT_EQ(ERR_IO_PENDING, rv);
1401
1402 rv = callback2.WaitForResult();
1403 EXPECT_EQ(OK, rv);
1404
1405 response = trans->GetResponseInfo();
1406 ASSERT_FALSE(response == NULL);
1407 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1408 EXPECT_EQ(5, response->headers->GetContentLength());
1409 }
1410
1411 // Test the request-challenge-retry sequence for basic auth, over a keep-alive
1412 // connection, but the server gets impatient and closes the connection.
TEST_F(HttpNetworkTransactionTest,BasicAuthKeepAliveImpatientServer)1413 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveImpatientServer) {
1414 HttpRequestInfo request;
1415 request.method = "GET";
1416 request.url = GURL("http://www.google.com/");
1417 request.load_flags = 0;
1418
1419 SessionDependencies session_deps;
1420 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
1421
1422 MockWrite data_writes1[] = {
1423 MockWrite("GET / HTTP/1.1\r\n"
1424 "Host: www.google.com\r\n"
1425 "Connection: keep-alive\r\n\r\n"),
1426 // This simulates the seemingly successful write to a closed connection
1427 // if the bug is not fixed.
1428 MockWrite("GET / HTTP/1.1\r\n"
1429 "Host: www.google.com\r\n"
1430 "Connection: keep-alive\r\n"
1431 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1432 };
1433
1434 MockRead data_reads1[] = {
1435 MockRead("HTTP/1.1 401 Unauthorized\r\n"),
1436 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1437 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1438 MockRead("Content-Length: 14\r\n\r\n"),
1439 // Tell MockTCPClientSocket to simulate the server closing the connection.
1440 MockRead(false, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
1441 MockRead("Unauthorized\r\n"),
1442 MockRead(false, OK), // The server closes the connection.
1443 };
1444
1445 // After calling trans->RestartWithAuth(), this is the request we should
1446 // be issuing -- the final header line contains the credentials.
1447 MockWrite data_writes2[] = {
1448 MockWrite("GET / HTTP/1.1\r\n"
1449 "Host: www.google.com\r\n"
1450 "Connection: keep-alive\r\n"
1451 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1452 };
1453
1454 // Lastly, the server responds with the actual content.
1455 MockRead data_reads2[] = {
1456 MockRead("HTTP/1.1 200 OK\r\n"),
1457 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1458 MockRead("Content-Length: 5\r\n\r\n"),
1459 MockRead("hello"),
1460 };
1461
1462 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
1463 data_writes1, arraysize(data_writes1));
1464 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
1465 data_writes2, arraysize(data_writes2));
1466 session_deps.socket_factory.AddSocketDataProvider(&data1);
1467 session_deps.socket_factory.AddSocketDataProvider(&data2);
1468
1469 TestCompletionCallback callback1;
1470
1471 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
1472 int rv = trans->Start(&request, &callback1, BoundNetLog());
1473 EXPECT_EQ(ERR_IO_PENDING, rv);
1474
1475 rv = callback1.WaitForResult();
1476 EXPECT_EQ(OK, rv);
1477
1478 const HttpResponseInfo* response = trans->GetResponseInfo();
1479 EXPECT_FALSE(response == NULL);
1480
1481 // The password prompt info should have been set in response->auth_challenge.
1482 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1483
1484 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
1485 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1486 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1487
1488 TestCompletionCallback callback2;
1489
1490 rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
1491 EXPECT_EQ(ERR_IO_PENDING, rv);
1492
1493 rv = callback2.WaitForResult();
1494 EXPECT_EQ(OK, rv);
1495
1496 response = trans->GetResponseInfo();
1497 ASSERT_FALSE(response == NULL);
1498 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1499 EXPECT_EQ(5, response->headers->GetContentLength());
1500 }
1501
1502 // Test the request-challenge-retry sequence for basic auth, over a connection
1503 // that requires a restart when setting up an SSL tunnel.
TEST_F(HttpNetworkTransactionTest,BasicAuthProxyNoKeepAlive)1504 TEST_F(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAlive) {
1505 HttpRequestInfo request;
1506 request.method = "GET";
1507 request.url = GURL("https://www.google.com/");
1508 // when the no authentication data flag is set.
1509 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA;
1510
1511 // Configure against proxy server "myproxy:70".
1512 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70"));
1513 CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
1514 session_deps.net_log = log.bound().net_log();
1515 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
1516
1517 // Since we have proxy, should try to establish tunnel.
1518 MockWrite data_writes1[] = {
1519 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
1520 "Host: www.google.com\r\n"
1521 "Proxy-Connection: keep-alive\r\n\r\n"),
1522
1523 // After calling trans->RestartWithAuth(), this is the request we should
1524 // be issuing -- the final header line contains the credentials.
1525 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
1526 "Host: www.google.com\r\n"
1527 "Proxy-Connection: keep-alive\r\n"
1528 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1529
1530 MockWrite("GET / HTTP/1.1\r\n"
1531 "Host: www.google.com\r\n"
1532 "Connection: keep-alive\r\n\r\n"),
1533 };
1534
1535 // The proxy responds to the connect with a 407, using a persistent
1536 // connection.
1537 MockRead data_reads1[] = {
1538 // No credentials.
1539 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
1540 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1541 MockRead("Proxy-Connection: close\r\n\r\n"),
1542
1543 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
1544
1545 MockRead("HTTP/1.1 200 OK\r\n"),
1546 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1547 MockRead("Content-Length: 5\r\n\r\n"),
1548 MockRead(false, "hello"),
1549 };
1550
1551 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
1552 data_writes1, arraysize(data_writes1));
1553 session_deps.socket_factory.AddSocketDataProvider(&data1);
1554 SSLSocketDataProvider ssl(true, OK);
1555 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
1556
1557 TestCompletionCallback callback1;
1558
1559 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
1560
1561 int rv = trans->Start(&request, &callback1, log.bound());
1562 EXPECT_EQ(ERR_IO_PENDING, rv);
1563
1564 rv = callback1.WaitForResult();
1565 EXPECT_EQ(OK, rv);
1566 net::CapturingNetLog::EntryList entries;
1567 log.GetEntries(&entries);
1568 size_t pos = ExpectLogContainsSomewhere(
1569 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
1570 NetLog::PHASE_NONE);
1571 ExpectLogContainsSomewhere(
1572 entries, pos,
1573 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
1574 NetLog::PHASE_NONE);
1575
1576 const HttpResponseInfo* response = trans->GetResponseInfo();
1577 ASSERT_FALSE(response == NULL);
1578
1579 EXPECT_EQ(407, response->headers->response_code());
1580 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
1581
1582 // The password prompt info should have been set in response->auth_challenge.
1583 ASSERT_FALSE(response->auth_challenge.get() == NULL);
1584
1585 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host_and_port);
1586 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1587 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1588
1589 TestCompletionCallback callback2;
1590
1591 rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
1592 EXPECT_EQ(ERR_IO_PENDING, rv);
1593
1594 rv = callback2.WaitForResult();
1595 EXPECT_EQ(OK, rv);
1596
1597 response = trans->GetResponseInfo();
1598 ASSERT_FALSE(response == NULL);
1599
1600 EXPECT_TRUE(response->headers->IsKeepAlive());
1601 EXPECT_EQ(200, response->headers->response_code());
1602 EXPECT_EQ(5, response->headers->GetContentLength());
1603 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
1604
1605 // The password prompt info should not be set.
1606 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1607
1608 trans.reset();
1609 session->CloseAllConnections();
1610 }
1611
1612 // Test the request-challenge-retry sequence for basic auth, over a keep-alive
1613 // proxy connection, when setting up an SSL tunnel.
TEST_F(HttpNetworkTransactionTest,BasicAuthProxyKeepAlive)1614 TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAlive) {
1615 HttpRequestInfo request;
1616 request.method = "GET";
1617 request.url = GURL("https://www.google.com/");
1618 // Ensure that proxy authentication is attempted even
1619 // when the no authentication data flag is set.
1620 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA;
1621
1622 // Configure against proxy server "myproxy:70".
1623 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70"));
1624 CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
1625 session_deps.net_log = log.bound().net_log();
1626 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
1627
1628 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
1629
1630 // Since we have proxy, should try to establish tunnel.
1631 MockWrite data_writes1[] = {
1632 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
1633 "Host: www.google.com\r\n"
1634 "Proxy-Connection: keep-alive\r\n\r\n"),
1635
1636 // After calling trans->RestartWithAuth(), this is the request we should
1637 // be issuing -- the final header line contains the credentials.
1638 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
1639 "Host: www.google.com\r\n"
1640 "Proxy-Connection: keep-alive\r\n"
1641 "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"),
1642 };
1643
1644 // The proxy responds to the connect with a 407, using a persistent
1645 // connection.
1646 MockRead data_reads1[] = {
1647 // No credentials.
1648 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
1649 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1650 MockRead("Content-Length: 10\r\n\r\n"),
1651 MockRead("0123456789"),
1652
1653 // Wrong credentials (wrong password).
1654 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
1655 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1656 MockRead("Content-Length: 10\r\n\r\n"),
1657 // No response body because the test stops reading here.
1658 MockRead(false, ERR_UNEXPECTED), // Should not be reached.
1659 };
1660
1661 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
1662 data_writes1, arraysize(data_writes1));
1663 session_deps.socket_factory.AddSocketDataProvider(&data1);
1664
1665 TestCompletionCallback callback1;
1666
1667 int rv = trans->Start(&request, &callback1, log.bound());
1668 EXPECT_EQ(ERR_IO_PENDING, rv);
1669
1670 rv = callback1.WaitForResult();
1671 EXPECT_EQ(OK, rv);
1672 net::CapturingNetLog::EntryList entries;
1673 log.GetEntries(&entries);
1674 size_t pos = ExpectLogContainsSomewhere(
1675 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
1676 NetLog::PHASE_NONE);
1677 ExpectLogContainsSomewhere(
1678 entries, pos,
1679 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
1680 NetLog::PHASE_NONE);
1681
1682 const HttpResponseInfo* response = trans->GetResponseInfo();
1683 EXPECT_FALSE(response == NULL);
1684
1685 EXPECT_TRUE(response->headers->IsKeepAlive());
1686 EXPECT_EQ(407, response->headers->response_code());
1687 EXPECT_EQ(10, response->headers->GetContentLength());
1688 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
1689
1690 // The password prompt info should have been set in response->auth_challenge.
1691 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1692
1693 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host_and_port);
1694 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1695 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1696
1697 TestCompletionCallback callback2;
1698
1699 // Wrong password (should be "bar").
1700 rv = trans->RestartWithAuth(kFoo, kBaz, &callback2);
1701 EXPECT_EQ(ERR_IO_PENDING, rv);
1702
1703 rv = callback2.WaitForResult();
1704 EXPECT_EQ(OK, rv);
1705
1706 response = trans->GetResponseInfo();
1707 EXPECT_FALSE(response == NULL);
1708
1709 EXPECT_TRUE(response->headers->IsKeepAlive());
1710 EXPECT_EQ(407, response->headers->response_code());
1711 EXPECT_EQ(10, response->headers->GetContentLength());
1712 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
1713
1714 // The password prompt info should have been set in response->auth_challenge.
1715 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1716
1717 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host_and_port);
1718 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1719 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1720
1721 // Flush the idle socket before the NetLog and HttpNetworkTransaction go
1722 // out of scope.
1723 session->CloseAllConnections();
1724 }
1725
1726 // Test that we don't read the response body when we fail to establish a tunnel,
1727 // even if the user cancels the proxy's auth attempt.
TEST_F(HttpNetworkTransactionTest,BasicAuthProxyCancelTunnel)1728 TEST_F(HttpNetworkTransactionTest, BasicAuthProxyCancelTunnel) {
1729 HttpRequestInfo request;
1730 request.method = "GET";
1731 request.url = GURL("https://www.google.com/");
1732 request.load_flags = 0;
1733
1734 // Configure against proxy server "myproxy:70".
1735 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70"));
1736
1737 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
1738
1739 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
1740
1741 // Since we have proxy, should try to establish tunnel.
1742 MockWrite data_writes[] = {
1743 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
1744 "Host: www.google.com\r\n"
1745 "Proxy-Connection: keep-alive\r\n\r\n"),
1746 };
1747
1748 // The proxy responds to the connect with a 407.
1749 MockRead data_reads[] = {
1750 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
1751 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1752 MockRead("Content-Length: 10\r\n\r\n"),
1753 MockRead(false, ERR_UNEXPECTED), // Should not be reached.
1754 };
1755
1756 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
1757 data_writes, arraysize(data_writes));
1758 session_deps.socket_factory.AddSocketDataProvider(&data);
1759
1760 TestCompletionCallback callback;
1761
1762 int rv = trans->Start(&request, &callback, BoundNetLog());
1763 EXPECT_EQ(ERR_IO_PENDING, rv);
1764
1765 rv = callback.WaitForResult();
1766 EXPECT_EQ(OK, rv);
1767
1768 const HttpResponseInfo* response = trans->GetResponseInfo();
1769 EXPECT_FALSE(response == NULL);
1770
1771 EXPECT_TRUE(response->headers->IsKeepAlive());
1772 EXPECT_EQ(407, response->headers->response_code());
1773 EXPECT_EQ(10, response->headers->GetContentLength());
1774 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
1775
1776 std::string response_data;
1777 rv = ReadTransaction(trans.get(), &response_data);
1778 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
1779
1780 // Flush the idle socket before the HttpNetworkTransaction goes out of scope.
1781 session->CloseAllConnections();
1782 }
1783
1784 // Test when a server (non-proxy) returns a 407 (proxy-authenticate).
1785 // The request should fail with ERR_UNEXPECTED_PROXY_AUTH.
TEST_F(HttpNetworkTransactionTest,UnexpectedProxyAuth)1786 TEST_F(HttpNetworkTransactionTest, UnexpectedProxyAuth) {
1787 HttpRequestInfo request;
1788 request.method = "GET";
1789 request.url = GURL("http://www.google.com/");
1790 request.load_flags = 0;
1791
1792 // We are using a DIRECT connection (i.e. no proxy) for this session.
1793 SessionDependencies session_deps;
1794 scoped_ptr<HttpTransaction> trans(
1795 new HttpNetworkTransaction(CreateSession(&session_deps)));
1796
1797 MockWrite data_writes1[] = {
1798 MockWrite("GET / HTTP/1.1\r\n"
1799 "Host: www.google.com\r\n"
1800 "Connection: keep-alive\r\n\r\n"),
1801 };
1802
1803 MockRead data_reads1[] = {
1804 MockRead("HTTP/1.0 407 Proxy Auth required\r\n"),
1805 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1806 // Large content-length -- won't matter, as connection will be reset.
1807 MockRead("Content-Length: 10000\r\n\r\n"),
1808 MockRead(false, ERR_FAILED),
1809 };
1810
1811 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
1812 data_writes1, arraysize(data_writes1));
1813 session_deps.socket_factory.AddSocketDataProvider(&data1);
1814
1815 TestCompletionCallback callback;
1816
1817 int rv = trans->Start(&request, &callback, BoundNetLog());
1818 EXPECT_EQ(ERR_IO_PENDING, rv);
1819
1820 rv = callback.WaitForResult();
1821 EXPECT_EQ(ERR_UNEXPECTED_PROXY_AUTH, rv);
1822 }
1823
1824 // Tests when an HTTPS server (non-proxy) returns a 407 (proxy-authentication)
1825 // through a non-authenticating proxy. The request should fail with
1826 // ERR_UNEXPECTED_PROXY_AUTH.
1827 // Note that it is impossible to detect if an HTTP server returns a 407 through
1828 // a non-authenticating proxy - there is nothing to indicate whether the
1829 // response came from the proxy or the server, so it is treated as if the proxy
1830 // issued the challenge.
TEST_F(HttpNetworkTransactionTest,HttpsServerRequestsProxyAuthThroughProxy)1831 TEST_F(HttpNetworkTransactionTest, HttpsServerRequestsProxyAuthThroughProxy) {
1832 HttpRequestInfo request;
1833 request.method = "GET";
1834 request.url = GURL("https://www.google.com/");
1835
1836 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70"));
1837 CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
1838 session_deps.net_log = log.bound().net_log();
1839 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
1840
1841 // Since we have proxy, should try to establish tunnel.
1842 MockWrite data_writes1[] = {
1843 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
1844 "Host: www.google.com\r\n"
1845 "Proxy-Connection: keep-alive\r\n\r\n"),
1846
1847 MockWrite("GET / HTTP/1.1\r\n"
1848 "Host: www.google.com\r\n"
1849 "Connection: keep-alive\r\n\r\n"),
1850 };
1851
1852 MockRead data_reads1[] = {
1853 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
1854
1855 MockRead("HTTP/1.1 407 Unauthorized\r\n"),
1856 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1857 MockRead("\r\n"),
1858 MockRead(false, OK),
1859 };
1860
1861 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
1862 data_writes1, arraysize(data_writes1));
1863 session_deps.socket_factory.AddSocketDataProvider(&data1);
1864 SSLSocketDataProvider ssl(true, OK);
1865 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
1866
1867 TestCompletionCallback callback1;
1868
1869 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
1870
1871 int rv = trans->Start(&request, &callback1, log.bound());
1872 EXPECT_EQ(ERR_IO_PENDING, rv);
1873
1874 rv = callback1.WaitForResult();
1875 EXPECT_EQ(ERR_UNEXPECTED_PROXY_AUTH, rv);
1876 net::CapturingNetLog::EntryList entries;
1877 log.GetEntries(&entries);
1878 size_t pos = ExpectLogContainsSomewhere(
1879 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
1880 NetLog::PHASE_NONE);
1881 ExpectLogContainsSomewhere(
1882 entries, pos,
1883 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
1884 NetLog::PHASE_NONE);
1885 }
1886
1887 // Test a simple get through an HTTPS Proxy.
TEST_F(HttpNetworkTransactionTest,HttpsProxyGet)1888 TEST_F(HttpNetworkTransactionTest, HttpsProxyGet) {
1889 HttpRequestInfo request;
1890 request.method = "GET";
1891 request.url = GURL("http://www.google.com/");
1892
1893 // Configure against https proxy server "proxy:70".
1894 SessionDependencies session_deps(ProxyService::CreateFixed("https://proxy:70"));
1895 CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
1896 session_deps.net_log = log.bound().net_log();
1897 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
1898
1899 // Since we have proxy, should use full url
1900 MockWrite data_writes1[] = {
1901 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
1902 "Host: www.google.com\r\n"
1903 "Proxy-Connection: keep-alive\r\n\r\n"),
1904 };
1905
1906 MockRead data_reads1[] = {
1907 MockRead("HTTP/1.1 200 OK\r\n"),
1908 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1909 MockRead("Content-Length: 100\r\n\r\n"),
1910 MockRead(false, OK),
1911 };
1912
1913 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
1914 data_writes1, arraysize(data_writes1));
1915 session_deps.socket_factory.AddSocketDataProvider(&data1);
1916 SSLSocketDataProvider ssl(true, OK);
1917 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
1918
1919 TestCompletionCallback callback1;
1920
1921 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
1922
1923 int rv = trans->Start(&request, &callback1, log.bound());
1924 EXPECT_EQ(ERR_IO_PENDING, rv);
1925
1926 rv = callback1.WaitForResult();
1927 EXPECT_EQ(OK, rv);
1928
1929 const HttpResponseInfo* response = trans->GetResponseInfo();
1930 ASSERT_FALSE(response == NULL);
1931
1932 EXPECT_TRUE(response->headers->IsKeepAlive());
1933 EXPECT_EQ(200, response->headers->response_code());
1934 EXPECT_EQ(100, response->headers->GetContentLength());
1935 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
1936
1937 // The password prompt info should not be set.
1938 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1939 }
1940
1941 // Test a SPDY get through an HTTPS Proxy.
TEST_F(HttpNetworkTransactionTest,HttpsProxySpdyGet)1942 TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyGet) {
1943 HttpRequestInfo request;
1944 request.method = "GET";
1945 request.url = GURL("http://www.google.com/");
1946 request.load_flags = 0;
1947
1948 // Configure against https proxy server "proxy:70".
1949 SessionDependencies session_deps(ProxyService::CreateFixed("https://proxy:70"));
1950 CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
1951 session_deps.net_log = log.bound().net_log();
1952 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
1953
1954 // fetch http://www.google.com/ via SPDY
1955 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST,
1956 false));
1957 MockWrite spdy_writes[] = { CreateMockWrite(*req) };
1958
1959 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
1960 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true));
1961 MockRead spdy_reads[] = {
1962 CreateMockRead(*resp),
1963 CreateMockRead(*data),
1964 MockRead(true, 0, 0),
1965 };
1966
1967 scoped_refptr<DelayedSocketData> spdy_data(
1968 new DelayedSocketData(
1969 1, // wait for one write to finish before reading.
1970 spdy_reads, arraysize(spdy_reads),
1971 spdy_writes, arraysize(spdy_writes)));
1972 session_deps.socket_factory.AddSocketDataProvider(spdy_data);
1973
1974 SSLSocketDataProvider ssl(true, OK);
1975 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
1976 ssl.next_proto = "spdy/2";
1977 ssl.was_npn_negotiated = true;
1978 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
1979
1980 TestCompletionCallback callback1;
1981
1982 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
1983
1984 int rv = trans->Start(&request, &callback1, log.bound());
1985 EXPECT_EQ(ERR_IO_PENDING, rv);
1986
1987 rv = callback1.WaitForResult();
1988 EXPECT_EQ(OK, rv);
1989
1990 const HttpResponseInfo* response = trans->GetResponseInfo();
1991 ASSERT_TRUE(response != NULL);
1992 ASSERT_TRUE(response->headers != NULL);
1993 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
1994
1995 std::string response_data;
1996 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
1997 EXPECT_EQ(net::kUploadData, response_data);
1998 }
1999
2000 // Test a SPDY get through an HTTPS Proxy.
TEST_F(HttpNetworkTransactionTest,HttpsProxySpdyGetWithProxyAuth)2001 TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyGetWithProxyAuth) {
2002 HttpRequestInfo request;
2003 request.method = "GET";
2004 request.url = GURL("http://www.google.com/");
2005 request.load_flags = 0;
2006
2007 // Configure against https proxy server "proxy:70".
2008 SessionDependencies session_deps(
2009 ProxyService::CreateFixed("https://proxy:70"));
2010 CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
2011 session_deps.net_log = log.bound().net_log();
2012 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
2013
2014 // The first request will be a bare GET, the second request will be a
2015 // GET with a Proxy-Authorization header.
2016 scoped_ptr<spdy::SpdyFrame> req_get(
2017 ConstructSpdyGet(NULL, 0, false, 1, LOWEST, false));
2018 const char* const kExtraAuthorizationHeaders[] = {
2019 "proxy-authorization",
2020 "Basic Zm9vOmJhcg==",
2021 };
2022 scoped_ptr<spdy::SpdyFrame> req_get_authorization(
2023 ConstructSpdyGet(
2024 kExtraAuthorizationHeaders, arraysize(kExtraAuthorizationHeaders)/2,
2025 false, 3, LOWEST, false));
2026 MockWrite spdy_writes[] = {
2027 CreateMockWrite(*req_get, 1),
2028 CreateMockWrite(*req_get_authorization, 4),
2029 };
2030
2031 // The first response is a 407 proxy authentication challenge, and the second
2032 // response will be a 200 response since the second request includes a valid
2033 // Authorization header.
2034 const char* const kExtraAuthenticationHeaders[] = {
2035 "Proxy-Authenticate",
2036 "Basic realm=\"MyRealm1\""
2037 };
2038 scoped_ptr<spdy::SpdyFrame> resp_authentication(
2039 ConstructSpdySynReplyError(
2040 "407 Proxy Authentication Required",
2041 kExtraAuthenticationHeaders, arraysize(kExtraAuthenticationHeaders)/2,
2042 1));
2043 scoped_ptr<spdy::SpdyFrame> body_authentication(
2044 ConstructSpdyBodyFrame(1, true));
2045 scoped_ptr<spdy::SpdyFrame> resp_data(ConstructSpdyGetSynReply(NULL, 0, 3));
2046 scoped_ptr<spdy::SpdyFrame> body_data(ConstructSpdyBodyFrame(3, true));
2047 MockRead spdy_reads[] = {
2048 CreateMockRead(*resp_authentication, 2),
2049 CreateMockRead(*body_authentication, 3),
2050 CreateMockRead(*resp_data, 5),
2051 CreateMockRead(*body_data, 6),
2052 MockRead(true, 0, 7),
2053 };
2054
2055 scoped_refptr<OrderedSocketData> data(
2056 new OrderedSocketData(spdy_reads, arraysize(spdy_reads),
2057 spdy_writes, arraysize(spdy_writes)));
2058 session_deps.socket_factory.AddSocketDataProvider(data);
2059
2060 SSLSocketDataProvider ssl(true, OK);
2061 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
2062 ssl.next_proto = "spdy/2";
2063 ssl.was_npn_negotiated = true;
2064 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
2065
2066 TestCompletionCallback callback1;
2067
2068 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
2069
2070 int rv = trans->Start(&request, &callback1, log.bound());
2071 EXPECT_EQ(ERR_IO_PENDING, rv);
2072
2073 rv = callback1.WaitForResult();
2074 EXPECT_EQ(OK, rv);
2075
2076 const HttpResponseInfo* const response = trans->GetResponseInfo();
2077
2078 ASSERT_TRUE(response != NULL);
2079 ASSERT_TRUE(response->headers != NULL);
2080 EXPECT_EQ(407, response->headers->response_code());
2081 EXPECT_TRUE(response->was_fetched_via_spdy);
2082
2083 // The password prompt info should have been set in response->auth_challenge.
2084 ASSERT_TRUE(response->auth_challenge.get() != NULL);
2085 EXPECT_TRUE(response->auth_challenge->is_proxy);
2086 EXPECT_EQ(L"proxy:70", response->auth_challenge->host_and_port);
2087 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
2088 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
2089
2090 TestCompletionCallback callback2;
2091
2092 rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
2093 EXPECT_EQ(ERR_IO_PENDING, rv);
2094
2095 rv = callback2.WaitForResult();
2096 EXPECT_EQ(OK, rv);
2097
2098 const HttpResponseInfo* const response_restart = trans->GetResponseInfo();
2099
2100 ASSERT_TRUE(response_restart != NULL);
2101 ASSERT_TRUE(response_restart->headers != NULL);
2102 EXPECT_EQ(200, response_restart->headers->response_code());
2103 // The password prompt info should not be set.
2104 EXPECT_TRUE(response_restart->auth_challenge.get() == NULL);
2105 }
2106
2107 // Test a SPDY CONNECT through an HTTPS Proxy to an HTTPS (non-SPDY) Server.
TEST_F(HttpNetworkTransactionTest,HttpsProxySpdyConnectHttps)2108 TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyConnectHttps) {
2109 HttpRequestInfo request;
2110 request.method = "GET";
2111 request.url = GURL("https://www.google.com/");
2112 request.load_flags = 0;
2113
2114 // Configure against https proxy server "proxy:70".
2115 SessionDependencies session_deps(ProxyService::CreateFixed("https://proxy:70"));
2116 CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
2117 session_deps.net_log = log.bound().net_log();
2118 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
2119
2120 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
2121
2122 // CONNECT to www.google.com:443 via SPDY
2123 scoped_ptr<spdy::SpdyFrame> connect(ConstructSpdyConnect(NULL, 0, 1));
2124 // fetch https://www.google.com/ via HTTP
2125
2126 const char get[] = "GET / HTTP/1.1\r\n"
2127 "Host: www.google.com\r\n"
2128 "Connection: keep-alive\r\n\r\n";
2129 scoped_ptr<spdy::SpdyFrame> wrapped_get(
2130 ConstructSpdyBodyFrame(1, get, strlen(get), false));
2131 MockWrite spdy_writes[] = {
2132 CreateMockWrite(*connect, 1),
2133 CreateMockWrite(*wrapped_get, 3)
2134 };
2135
2136 scoped_ptr<spdy::SpdyFrame> conn_resp(ConstructSpdyGetSynReply(NULL, 0, 1));
2137 const char resp[] = "HTTP/1.1 200 OK\r\n"
2138 "Content-Length: 10\r\n\r\n";
2139
2140 scoped_ptr<spdy::SpdyFrame> wrapped_get_resp(
2141 ConstructSpdyBodyFrame(1, resp, strlen(resp), false));
2142 scoped_ptr<spdy::SpdyFrame> wrapped_body(
2143 ConstructSpdyBodyFrame(1, "1234567890", 10, false));
2144 MockRead spdy_reads[] = {
2145 CreateMockRead(*conn_resp, 2, true),
2146 CreateMockRead(*wrapped_get_resp, 4, true),
2147 CreateMockRead(*wrapped_body, 5, true),
2148 CreateMockRead(*wrapped_body, 6, true),
2149 MockRead(true, 0, 7),
2150 };
2151
2152 scoped_refptr<OrderedSocketData> spdy_data(
2153 new OrderedSocketData(
2154 spdy_reads, arraysize(spdy_reads),
2155 spdy_writes, arraysize(spdy_writes)));
2156 session_deps.socket_factory.AddSocketDataProvider(spdy_data);
2157
2158 SSLSocketDataProvider ssl(true, OK);
2159 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
2160 ssl.next_proto = "spdy/2";
2161 ssl.was_npn_negotiated = true;
2162 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
2163 SSLSocketDataProvider ssl2(true, OK);
2164 ssl2.was_npn_negotiated = false;
2165 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2);
2166
2167 TestCompletionCallback callback1;
2168
2169 int rv = trans->Start(&request, &callback1, log.bound());
2170 EXPECT_EQ(ERR_IO_PENDING, rv);
2171
2172 rv = callback1.WaitForResult();
2173 EXPECT_EQ(OK, rv);
2174
2175 const HttpResponseInfo* response = trans->GetResponseInfo();
2176 ASSERT_TRUE(response != NULL);
2177 ASSERT_TRUE(response->headers != NULL);
2178 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
2179
2180 std::string response_data;
2181 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
2182 EXPECT_EQ("1234567890", response_data);
2183 }
2184
2185 // Test a SPDY CONNECT through an HTTPS Proxy to a SPDY server.
TEST_F(HttpNetworkTransactionTest,HttpsProxySpdyConnectSpdy)2186 TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyConnectSpdy) {
2187 HttpRequestInfo request;
2188 request.method = "GET";
2189 request.url = GURL("https://www.google.com/");
2190 request.load_flags = 0;
2191
2192 // Configure against https proxy server "proxy:70".
2193 SessionDependencies session_deps(ProxyService::CreateFixed("https://proxy:70"));
2194 CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
2195 session_deps.net_log = log.bound().net_log();
2196 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
2197
2198 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
2199
2200 // CONNECT to www.google.com:443 via SPDY
2201 scoped_ptr<spdy::SpdyFrame> connect(ConstructSpdyConnect(NULL, 0, 1));
2202 // fetch https://www.google.com/ via SPDY
2203 const char* const kMyUrl = "https://www.google.com/";
2204 scoped_ptr<spdy::SpdyFrame> get(ConstructSpdyGet(kMyUrl, false, 1, LOWEST));
2205 scoped_ptr<spdy::SpdyFrame> wrapped_get(ConstructWrappedSpdyFrame(get, 1));
2206 MockWrite spdy_writes[] = {
2207 CreateMockWrite(*connect, 1),
2208 CreateMockWrite(*wrapped_get, 3)
2209 };
2210
2211 scoped_ptr<spdy::SpdyFrame> conn_resp(ConstructSpdyGetSynReply(NULL, 0, 1));
2212 scoped_ptr<spdy::SpdyFrame> get_resp(ConstructSpdyGetSynReply(NULL, 0, 1));
2213 scoped_ptr<spdy::SpdyFrame> wrapped_get_resp(
2214 ConstructWrappedSpdyFrame(get_resp, 1));
2215 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
2216 scoped_ptr<spdy::SpdyFrame> wrapped_body(ConstructWrappedSpdyFrame(body, 1));
2217 MockRead spdy_reads[] = {
2218 CreateMockRead(*conn_resp, 2, true),
2219 CreateMockRead(*wrapped_get_resp, 4, true),
2220 CreateMockRead(*wrapped_body, 5, true),
2221 MockRead(true, 0, 1),
2222 };
2223
2224 scoped_refptr<OrderedSocketData> spdy_data(
2225 new OrderedSocketData(
2226 spdy_reads, arraysize(spdy_reads),
2227 spdy_writes, arraysize(spdy_writes)));
2228 session_deps.socket_factory.AddSocketDataProvider(spdy_data);
2229
2230 SSLSocketDataProvider ssl(true, OK);
2231 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
2232 ssl.next_proto = "spdy/2";
2233 ssl.was_npn_negotiated = true;
2234 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
2235 SSLSocketDataProvider ssl2(true, OK);
2236 ssl2.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
2237 ssl2.next_proto = "spdy/2";
2238 ssl2.was_npn_negotiated = true;
2239 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2);
2240
2241 TestCompletionCallback callback1;
2242
2243 int rv = trans->Start(&request, &callback1, log.bound());
2244 EXPECT_EQ(ERR_IO_PENDING, rv);
2245
2246 rv = callback1.WaitForResult();
2247 EXPECT_EQ(OK, rv);
2248
2249 const HttpResponseInfo* response = trans->GetResponseInfo();
2250 ASSERT_TRUE(response != NULL);
2251 ASSERT_TRUE(response->headers != NULL);
2252 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
2253
2254 std::string response_data;
2255 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
2256 EXPECT_EQ(net::kUploadData, response_data);
2257 }
2258
2259 // Test a SPDY CONNECT failure through an HTTPS Proxy.
TEST_F(HttpNetworkTransactionTest,HttpsProxySpdyConnectFailure)2260 TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyConnectFailure) {
2261 HttpRequestInfo request;
2262 request.method = "GET";
2263 request.url = GURL("https://www.google.com/");
2264 request.load_flags = 0;
2265
2266 // Configure against https proxy server "proxy:70".
2267 SessionDependencies session_deps(ProxyService::CreateFixed("https://proxy:70"));
2268 CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
2269 session_deps.net_log = log.bound().net_log();
2270 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
2271
2272 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
2273
2274 // CONNECT to www.google.com:443 via SPDY
2275 scoped_ptr<spdy::SpdyFrame> connect(ConstructSpdyConnect(NULL, 0, 1));
2276 scoped_ptr<spdy::SpdyFrame> get(ConstructSpdyRstStream(1, spdy::CANCEL));
2277
2278 MockWrite spdy_writes[] = {
2279 CreateMockWrite(*connect, 1),
2280 CreateMockWrite(*get, 3),
2281 };
2282
2283 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdySynReplyError(1));
2284 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true));
2285 MockRead spdy_reads[] = {
2286 CreateMockRead(*resp, 2, true),
2287 MockRead(true, 0, 4),
2288 };
2289
2290 scoped_refptr<OrderedSocketData> spdy_data(
2291 new OrderedSocketData(
2292 spdy_reads, arraysize(spdy_reads),
2293 spdy_writes, arraysize(spdy_writes)));
2294 session_deps.socket_factory.AddSocketDataProvider(spdy_data);
2295
2296 SSLSocketDataProvider ssl(true, OK);
2297 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
2298 ssl.next_proto = "spdy/2";
2299 ssl.was_npn_negotiated = true;
2300 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
2301 SSLSocketDataProvider ssl2(true, OK);
2302 ssl2.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
2303 ssl2.next_proto = "spdy/2";
2304 ssl2.was_npn_negotiated = true;
2305 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2);
2306
2307 TestCompletionCallback callback1;
2308
2309 int rv = trans->Start(&request, &callback1, log.bound());
2310 EXPECT_EQ(ERR_IO_PENDING, rv);
2311
2312 rv = callback1.WaitForResult();
2313 EXPECT_EQ(OK, rv);
2314
2315 const HttpResponseInfo* response = trans->GetResponseInfo();
2316 ASSERT_FALSE(response == NULL);
2317 EXPECT_EQ(500, response->headers->response_code());
2318 }
2319
2320 // Test the challenge-response-retry sequence through an HTTPS Proxy
TEST_F(HttpNetworkTransactionTest,HttpsProxyAuthRetry)2321 TEST_F(HttpNetworkTransactionTest, HttpsProxyAuthRetry) {
2322 HttpRequestInfo request;
2323 request.method = "GET";
2324 request.url = GURL("http://www.google.com/");
2325 // when the no authentication data flag is set.
2326 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA;
2327
2328 // Configure against https proxy server "proxy:70".
2329 SessionDependencies session_deps(ProxyService::CreateFixed("https://proxy:70"));
2330 CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
2331 session_deps.net_log = log.bound().net_log();
2332 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
2333
2334 // Since we have proxy, should use full url
2335 MockWrite data_writes1[] = {
2336 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
2337 "Host: www.google.com\r\n"
2338 "Proxy-Connection: keep-alive\r\n\r\n"),
2339
2340 // After calling trans->RestartWithAuth(), this is the request we should
2341 // be issuing -- the final header line contains the credentials.
2342 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
2343 "Host: www.google.com\r\n"
2344 "Proxy-Connection: keep-alive\r\n"
2345 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
2346 };
2347
2348 // The proxy responds to the GET with a 407, using a persistent
2349 // connection.
2350 MockRead data_reads1[] = {
2351 // No credentials.
2352 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
2353 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
2354 MockRead("Proxy-Connection: keep-alive\r\n"),
2355 MockRead("Content-Length: 0\r\n\r\n"),
2356
2357 MockRead("HTTP/1.1 200 OK\r\n"),
2358 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
2359 MockRead("Content-Length: 100\r\n\r\n"),
2360 MockRead(false, OK),
2361 };
2362
2363 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
2364 data_writes1, arraysize(data_writes1));
2365 session_deps.socket_factory.AddSocketDataProvider(&data1);
2366 SSLSocketDataProvider ssl(true, OK);
2367 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
2368
2369 TestCompletionCallback callback1;
2370
2371 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
2372
2373 int rv = trans->Start(&request, &callback1, log.bound());
2374 EXPECT_EQ(ERR_IO_PENDING, rv);
2375
2376 rv = callback1.WaitForResult();
2377 EXPECT_EQ(OK, rv);
2378
2379 const HttpResponseInfo* response = trans->GetResponseInfo();
2380 ASSERT_FALSE(response == NULL);
2381
2382 EXPECT_EQ(407, response->headers->response_code());
2383 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
2384
2385 // The password prompt info should have been set in response->auth_challenge.
2386 ASSERT_FALSE(response->auth_challenge.get() == NULL);
2387
2388 EXPECT_EQ(L"proxy:70", response->auth_challenge->host_and_port);
2389 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
2390 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
2391
2392 TestCompletionCallback callback2;
2393
2394 rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
2395 EXPECT_EQ(ERR_IO_PENDING, rv);
2396
2397 rv = callback2.WaitForResult();
2398 EXPECT_EQ(OK, rv);
2399
2400 response = trans->GetResponseInfo();
2401 ASSERT_FALSE(response == NULL);
2402
2403 EXPECT_TRUE(response->headers->IsKeepAlive());
2404 EXPECT_EQ(200, response->headers->response_code());
2405 EXPECT_EQ(100, response->headers->GetContentLength());
2406 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
2407
2408 // The password prompt info should not be set.
2409 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2410 }
2411
ConnectStatusHelperWithExpectedStatus(const MockRead & status,int expected_status)2412 void HttpNetworkTransactionTest::ConnectStatusHelperWithExpectedStatus(
2413 const MockRead& status, int expected_status) {
2414 HttpRequestInfo request;
2415 request.method = "GET";
2416 request.url = GURL("https://www.google.com/");
2417 request.load_flags = 0;
2418
2419 // Configure against proxy server "myproxy:70".
2420 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70"));
2421
2422 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
2423
2424 // Since we have proxy, should try to establish tunnel.
2425 MockWrite data_writes[] = {
2426 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
2427 "Host: www.google.com\r\n"
2428 "Proxy-Connection: keep-alive\r\n\r\n"),
2429 };
2430
2431 MockRead data_reads[] = {
2432 status,
2433 MockRead("Content-Length: 10\r\n\r\n"),
2434 // No response body because the test stops reading here.
2435 MockRead(false, ERR_UNEXPECTED), // Should not be reached.
2436 };
2437
2438 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
2439 data_writes, arraysize(data_writes));
2440 session_deps.socket_factory.AddSocketDataProvider(&data);
2441
2442 TestCompletionCallback callback;
2443
2444 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
2445
2446 int rv = trans->Start(&request, &callback, BoundNetLog());
2447 EXPECT_EQ(ERR_IO_PENDING, rv);
2448
2449 rv = callback.WaitForResult();
2450 EXPECT_EQ(expected_status, rv);
2451 }
2452
ConnectStatusHelper(const MockRead & status)2453 void HttpNetworkTransactionTest::ConnectStatusHelper(const MockRead& status) {
2454 ConnectStatusHelperWithExpectedStatus(
2455 status, ERR_TUNNEL_CONNECTION_FAILED);
2456 }
2457
TEST_F(HttpNetworkTransactionTest,ConnectStatus100)2458 TEST_F(HttpNetworkTransactionTest, ConnectStatus100) {
2459 ConnectStatusHelper(MockRead("HTTP/1.1 100 Continue\r\n"));
2460 }
2461
TEST_F(HttpNetworkTransactionTest,ConnectStatus101)2462 TEST_F(HttpNetworkTransactionTest, ConnectStatus101) {
2463 ConnectStatusHelper(MockRead("HTTP/1.1 101 Switching Protocols\r\n"));
2464 }
2465
TEST_F(HttpNetworkTransactionTest,ConnectStatus201)2466 TEST_F(HttpNetworkTransactionTest, ConnectStatus201) {
2467 ConnectStatusHelper(MockRead("HTTP/1.1 201 Created\r\n"));
2468 }
2469
TEST_F(HttpNetworkTransactionTest,ConnectStatus202)2470 TEST_F(HttpNetworkTransactionTest, ConnectStatus202) {
2471 ConnectStatusHelper(MockRead("HTTP/1.1 202 Accepted\r\n"));
2472 }
2473
TEST_F(HttpNetworkTransactionTest,ConnectStatus203)2474 TEST_F(HttpNetworkTransactionTest, ConnectStatus203) {
2475 ConnectStatusHelper(
2476 MockRead("HTTP/1.1 203 Non-Authoritative Information\r\n"));
2477 }
2478
TEST_F(HttpNetworkTransactionTest,ConnectStatus204)2479 TEST_F(HttpNetworkTransactionTest, ConnectStatus204) {
2480 ConnectStatusHelper(MockRead("HTTP/1.1 204 No Content\r\n"));
2481 }
2482
TEST_F(HttpNetworkTransactionTest,ConnectStatus205)2483 TEST_F(HttpNetworkTransactionTest, ConnectStatus205) {
2484 ConnectStatusHelper(MockRead("HTTP/1.1 205 Reset Content\r\n"));
2485 }
2486
TEST_F(HttpNetworkTransactionTest,ConnectStatus206)2487 TEST_F(HttpNetworkTransactionTest, ConnectStatus206) {
2488 ConnectStatusHelper(MockRead("HTTP/1.1 206 Partial Content\r\n"));
2489 }
2490
TEST_F(HttpNetworkTransactionTest,ConnectStatus300)2491 TEST_F(HttpNetworkTransactionTest, ConnectStatus300) {
2492 ConnectStatusHelper(MockRead("HTTP/1.1 300 Multiple Choices\r\n"));
2493 }
2494
TEST_F(HttpNetworkTransactionTest,ConnectStatus301)2495 TEST_F(HttpNetworkTransactionTest, ConnectStatus301) {
2496 ConnectStatusHelper(MockRead("HTTP/1.1 301 Moved Permanently\r\n"));
2497 }
2498
TEST_F(HttpNetworkTransactionTest,ConnectStatus302)2499 TEST_F(HttpNetworkTransactionTest, ConnectStatus302) {
2500 ConnectStatusHelper(MockRead("HTTP/1.1 302 Found\r\n"));
2501 }
2502
TEST_F(HttpNetworkTransactionTest,ConnectStatus303)2503 TEST_F(HttpNetworkTransactionTest, ConnectStatus303) {
2504 ConnectStatusHelper(MockRead("HTTP/1.1 303 See Other\r\n"));
2505 }
2506
TEST_F(HttpNetworkTransactionTest,ConnectStatus304)2507 TEST_F(HttpNetworkTransactionTest, ConnectStatus304) {
2508 ConnectStatusHelper(MockRead("HTTP/1.1 304 Not Modified\r\n"));
2509 }
2510
TEST_F(HttpNetworkTransactionTest,ConnectStatus305)2511 TEST_F(HttpNetworkTransactionTest, ConnectStatus305) {
2512 ConnectStatusHelper(MockRead("HTTP/1.1 305 Use Proxy\r\n"));
2513 }
2514
TEST_F(HttpNetworkTransactionTest,ConnectStatus306)2515 TEST_F(HttpNetworkTransactionTest, ConnectStatus306) {
2516 ConnectStatusHelper(MockRead("HTTP/1.1 306\r\n"));
2517 }
2518
TEST_F(HttpNetworkTransactionTest,ConnectStatus307)2519 TEST_F(HttpNetworkTransactionTest, ConnectStatus307) {
2520 ConnectStatusHelper(MockRead("HTTP/1.1 307 Temporary Redirect\r\n"));
2521 }
2522
TEST_F(HttpNetworkTransactionTest,ConnectStatus400)2523 TEST_F(HttpNetworkTransactionTest, ConnectStatus400) {
2524 ConnectStatusHelper(MockRead("HTTP/1.1 400 Bad Request\r\n"));
2525 }
2526
TEST_F(HttpNetworkTransactionTest,ConnectStatus401)2527 TEST_F(HttpNetworkTransactionTest, ConnectStatus401) {
2528 ConnectStatusHelper(MockRead("HTTP/1.1 401 Unauthorized\r\n"));
2529 }
2530
TEST_F(HttpNetworkTransactionTest,ConnectStatus402)2531 TEST_F(HttpNetworkTransactionTest, ConnectStatus402) {
2532 ConnectStatusHelper(MockRead("HTTP/1.1 402 Payment Required\r\n"));
2533 }
2534
TEST_F(HttpNetworkTransactionTest,ConnectStatus403)2535 TEST_F(HttpNetworkTransactionTest, ConnectStatus403) {
2536 ConnectStatusHelper(MockRead("HTTP/1.1 403 Forbidden\r\n"));
2537 }
2538
TEST_F(HttpNetworkTransactionTest,ConnectStatus404)2539 TEST_F(HttpNetworkTransactionTest, ConnectStatus404) {
2540 ConnectStatusHelper(MockRead("HTTP/1.1 404 Not Found\r\n"));
2541 }
2542
TEST_F(HttpNetworkTransactionTest,ConnectStatus405)2543 TEST_F(HttpNetworkTransactionTest, ConnectStatus405) {
2544 ConnectStatusHelper(MockRead("HTTP/1.1 405 Method Not Allowed\r\n"));
2545 }
2546
TEST_F(HttpNetworkTransactionTest,ConnectStatus406)2547 TEST_F(HttpNetworkTransactionTest, ConnectStatus406) {
2548 ConnectStatusHelper(MockRead("HTTP/1.1 406 Not Acceptable\r\n"));
2549 }
2550
TEST_F(HttpNetworkTransactionTest,ConnectStatus407)2551 TEST_F(HttpNetworkTransactionTest, ConnectStatus407) {
2552 ConnectStatusHelperWithExpectedStatus(
2553 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
2554 ERR_PROXY_AUTH_UNSUPPORTED);
2555 }
2556
TEST_F(HttpNetworkTransactionTest,ConnectStatus408)2557 TEST_F(HttpNetworkTransactionTest, ConnectStatus408) {
2558 ConnectStatusHelper(MockRead("HTTP/1.1 408 Request Timeout\r\n"));
2559 }
2560
TEST_F(HttpNetworkTransactionTest,ConnectStatus409)2561 TEST_F(HttpNetworkTransactionTest, ConnectStatus409) {
2562 ConnectStatusHelper(MockRead("HTTP/1.1 409 Conflict\r\n"));
2563 }
2564
TEST_F(HttpNetworkTransactionTest,ConnectStatus410)2565 TEST_F(HttpNetworkTransactionTest, ConnectStatus410) {
2566 ConnectStatusHelper(MockRead("HTTP/1.1 410 Gone\r\n"));
2567 }
2568
TEST_F(HttpNetworkTransactionTest,ConnectStatus411)2569 TEST_F(HttpNetworkTransactionTest, ConnectStatus411) {
2570 ConnectStatusHelper(MockRead("HTTP/1.1 411 Length Required\r\n"));
2571 }
2572
TEST_F(HttpNetworkTransactionTest,ConnectStatus412)2573 TEST_F(HttpNetworkTransactionTest, ConnectStatus412) {
2574 ConnectStatusHelper(MockRead("HTTP/1.1 412 Precondition Failed\r\n"));
2575 }
2576
TEST_F(HttpNetworkTransactionTest,ConnectStatus413)2577 TEST_F(HttpNetworkTransactionTest, ConnectStatus413) {
2578 ConnectStatusHelper(MockRead("HTTP/1.1 413 Request Entity Too Large\r\n"));
2579 }
2580
TEST_F(HttpNetworkTransactionTest,ConnectStatus414)2581 TEST_F(HttpNetworkTransactionTest, ConnectStatus414) {
2582 ConnectStatusHelper(MockRead("HTTP/1.1 414 Request-URI Too Long\r\n"));
2583 }
2584
TEST_F(HttpNetworkTransactionTest,ConnectStatus415)2585 TEST_F(HttpNetworkTransactionTest, ConnectStatus415) {
2586 ConnectStatusHelper(MockRead("HTTP/1.1 415 Unsupported Media Type\r\n"));
2587 }
2588
TEST_F(HttpNetworkTransactionTest,ConnectStatus416)2589 TEST_F(HttpNetworkTransactionTest, ConnectStatus416) {
2590 ConnectStatusHelper(
2591 MockRead("HTTP/1.1 416 Requested Range Not Satisfiable\r\n"));
2592 }
2593
TEST_F(HttpNetworkTransactionTest,ConnectStatus417)2594 TEST_F(HttpNetworkTransactionTest, ConnectStatus417) {
2595 ConnectStatusHelper(MockRead("HTTP/1.1 417 Expectation Failed\r\n"));
2596 }
2597
TEST_F(HttpNetworkTransactionTest,ConnectStatus500)2598 TEST_F(HttpNetworkTransactionTest, ConnectStatus500) {
2599 ConnectStatusHelper(MockRead("HTTP/1.1 500 Internal Server Error\r\n"));
2600 }
2601
TEST_F(HttpNetworkTransactionTest,ConnectStatus501)2602 TEST_F(HttpNetworkTransactionTest, ConnectStatus501) {
2603 ConnectStatusHelper(MockRead("HTTP/1.1 501 Not Implemented\r\n"));
2604 }
2605
TEST_F(HttpNetworkTransactionTest,ConnectStatus502)2606 TEST_F(HttpNetworkTransactionTest, ConnectStatus502) {
2607 ConnectStatusHelper(MockRead("HTTP/1.1 502 Bad Gateway\r\n"));
2608 }
2609
TEST_F(HttpNetworkTransactionTest,ConnectStatus503)2610 TEST_F(HttpNetworkTransactionTest, ConnectStatus503) {
2611 ConnectStatusHelper(MockRead("HTTP/1.1 503 Service Unavailable\r\n"));
2612 }
2613
TEST_F(HttpNetworkTransactionTest,ConnectStatus504)2614 TEST_F(HttpNetworkTransactionTest, ConnectStatus504) {
2615 ConnectStatusHelper(MockRead("HTTP/1.1 504 Gateway Timeout\r\n"));
2616 }
2617
TEST_F(HttpNetworkTransactionTest,ConnectStatus505)2618 TEST_F(HttpNetworkTransactionTest, ConnectStatus505) {
2619 ConnectStatusHelper(MockRead("HTTP/1.1 505 HTTP Version Not Supported\r\n"));
2620 }
2621
2622 // Test the flow when both the proxy server AND origin server require
2623 // authentication. Again, this uses basic auth for both since that is
2624 // the simplest to mock.
TEST_F(HttpNetworkTransactionTest,BasicAuthProxyThenServer)2625 TEST_F(HttpNetworkTransactionTest, BasicAuthProxyThenServer) {
2626 HttpRequestInfo request;
2627 request.method = "GET";
2628 request.url = GURL("http://www.google.com/");
2629 request.load_flags = 0;
2630
2631 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70"));
2632
2633 // Configure against proxy server "myproxy:70".
2634 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
2635 CreateSession(&session_deps)));
2636
2637 MockWrite data_writes1[] = {
2638 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
2639 "Host: www.google.com\r\n"
2640 "Proxy-Connection: keep-alive\r\n\r\n"),
2641 };
2642
2643 MockRead data_reads1[] = {
2644 MockRead("HTTP/1.0 407 Unauthorized\r\n"),
2645 // Give a couple authenticate options (only the middle one is actually
2646 // supported).
2647 MockRead("Proxy-Authenticate: Basic invalid\r\n"), // Malformed.
2648 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
2649 MockRead("Proxy-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"),
2650 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
2651 // Large content-length -- won't matter, as connection will be reset.
2652 MockRead("Content-Length: 10000\r\n\r\n"),
2653 MockRead(false, ERR_FAILED),
2654 };
2655
2656 // After calling trans->RestartWithAuth() the first time, this is the
2657 // request we should be issuing -- the final header line contains the
2658 // proxy's credentials.
2659 MockWrite data_writes2[] = {
2660 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
2661 "Host: www.google.com\r\n"
2662 "Proxy-Connection: keep-alive\r\n"
2663 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
2664 };
2665
2666 // Now the proxy server lets the request pass through to origin server.
2667 // The origin server responds with a 401.
2668 MockRead data_reads2[] = {
2669 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
2670 // Note: We are using the same realm-name as the proxy server. This is
2671 // completely valid, as realms are unique across hosts.
2672 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
2673 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
2674 MockRead("Content-Length: 2000\r\n\r\n"),
2675 MockRead(false, ERR_FAILED), // Won't be reached.
2676 };
2677
2678 // After calling trans->RestartWithAuth() the second time, we should send
2679 // the credentials for both the proxy and origin server.
2680 MockWrite data_writes3[] = {
2681 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
2682 "Host: www.google.com\r\n"
2683 "Proxy-Connection: keep-alive\r\n"
2684 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n"
2685 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"),
2686 };
2687
2688 // Lastly we get the desired content.
2689 MockRead data_reads3[] = {
2690 MockRead("HTTP/1.0 200 OK\r\n"),
2691 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
2692 MockRead("Content-Length: 100\r\n\r\n"),
2693 MockRead(false, OK),
2694 };
2695
2696 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
2697 data_writes1, arraysize(data_writes1));
2698 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
2699 data_writes2, arraysize(data_writes2));
2700 StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3),
2701 data_writes3, arraysize(data_writes3));
2702 session_deps.socket_factory.AddSocketDataProvider(&data1);
2703 session_deps.socket_factory.AddSocketDataProvider(&data2);
2704 session_deps.socket_factory.AddSocketDataProvider(&data3);
2705
2706 TestCompletionCallback callback1;
2707
2708 int rv = trans->Start(&request, &callback1, BoundNetLog());
2709 EXPECT_EQ(ERR_IO_PENDING, rv);
2710
2711 rv = callback1.WaitForResult();
2712 EXPECT_EQ(OK, rv);
2713
2714 const HttpResponseInfo* response = trans->GetResponseInfo();
2715 EXPECT_FALSE(response == NULL);
2716
2717 // The password prompt info should have been set in response->auth_challenge.
2718 EXPECT_FALSE(response->auth_challenge.get() == NULL);
2719
2720 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host_and_port);
2721 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
2722 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
2723
2724 TestCompletionCallback callback2;
2725
2726 rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
2727 EXPECT_EQ(ERR_IO_PENDING, rv);
2728
2729 rv = callback2.WaitForResult();
2730 EXPECT_EQ(OK, rv);
2731
2732 response = trans->GetResponseInfo();
2733 EXPECT_FALSE(response == NULL);
2734 EXPECT_FALSE(response->auth_challenge.get() == NULL);
2735
2736 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
2737 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
2738 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
2739
2740 TestCompletionCallback callback3;
2741
2742 rv = trans->RestartWithAuth(kFoo2, kBar2, &callback3);
2743 EXPECT_EQ(ERR_IO_PENDING, rv);
2744
2745 rv = callback3.WaitForResult();
2746 EXPECT_EQ(OK, rv);
2747
2748 response = trans->GetResponseInfo();
2749 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2750 EXPECT_EQ(100, response->headers->GetContentLength());
2751 }
2752
2753 // For the NTLM implementation using SSPI, we skip the NTLM tests since we
2754 // can't hook into its internals to cause it to generate predictable NTLM
2755 // authorization headers.
2756 #if defined(NTLM_PORTABLE)
2757 // The NTLM authentication unit tests were generated by capturing the HTTP
2758 // requests and responses using Fiddler 2 and inspecting the generated random
2759 // bytes in the debugger.
2760
2761 // Enter the correct password and authenticate successfully.
TEST_F(HttpNetworkTransactionTest,NTLMAuth1)2762 TEST_F(HttpNetworkTransactionTest, NTLMAuth1) {
2763 HttpRequestInfo request;
2764 request.method = "GET";
2765 request.url = GURL("http://172.22.68.17/kids/login.aspx");
2766 request.load_flags = 0;
2767
2768 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockGenerateRandom1,
2769 MockGetHostName);
2770 SessionDependencies session_deps;
2771 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
2772
2773 MockWrite data_writes1[] = {
2774 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
2775 "Host: 172.22.68.17\r\n"
2776 "Connection: keep-alive\r\n\r\n"),
2777 };
2778
2779 MockRead data_reads1[] = {
2780 MockRead("HTTP/1.1 401 Access Denied\r\n"),
2781 // Negotiate and NTLM are often requested together. However, we only want
2782 // to test NTLM. Since Negotiate is preferred over NTLM, we have to skip
2783 // the header that requests Negotiate for this test.
2784 MockRead("WWW-Authenticate: NTLM\r\n"),
2785 MockRead("Connection: close\r\n"),
2786 MockRead("Content-Length: 42\r\n"),
2787 MockRead("Content-Type: text/html\r\n\r\n"),
2788 // Missing content -- won't matter, as connection will be reset.
2789 MockRead(false, ERR_UNEXPECTED),
2790 };
2791
2792 MockWrite data_writes2[] = {
2793 // After restarting with a null identity, this is the
2794 // request we should be issuing -- the final header line contains a Type
2795 // 1 message.
2796 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
2797 "Host: 172.22.68.17\r\n"
2798 "Connection: keep-alive\r\n"
2799 "Authorization: NTLM "
2800 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"),
2801
2802 // After calling trans->RestartWithAuth(), we should send a Type 3 message
2803 // (the credentials for the origin server). The second request continues
2804 // on the same connection.
2805 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
2806 "Host: 172.22.68.17\r\n"
2807 "Connection: keep-alive\r\n"
2808 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA"
2809 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA"
2810 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBVKW"
2811 "Yma5xzVAAAAAAAAAAAAAAAAAAAAACH+gWcm+YsP9Tqb9zCR3WAeZZX"
2812 "ahlhx5I=\r\n\r\n"),
2813 };
2814
2815 MockRead data_reads2[] = {
2816 // The origin server responds with a Type 2 message.
2817 MockRead("HTTP/1.1 401 Access Denied\r\n"),
2818 MockRead("WWW-Authenticate: NTLM "
2819 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCjGpMpPGlYKkAAAAAAAAAALo"
2820 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE"
2821 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA"
2822 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy"
2823 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB"
2824 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw"
2825 "BtAAAAAAA=\r\n"),
2826 MockRead("Content-Length: 42\r\n"),
2827 MockRead("Content-Type: text/html\r\n\r\n"),
2828 MockRead("You are not authorized to view this page\r\n"),
2829
2830 // Lastly we get the desired content.
2831 MockRead("HTTP/1.1 200 OK\r\n"),
2832 MockRead("Content-Type: text/html; charset=utf-8\r\n"),
2833 MockRead("Content-Length: 13\r\n\r\n"),
2834 MockRead("Please Login\r\n"),
2835 MockRead(false, OK),
2836 };
2837
2838 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
2839 data_writes1, arraysize(data_writes1));
2840 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
2841 data_writes2, arraysize(data_writes2));
2842 session_deps.socket_factory.AddSocketDataProvider(&data1);
2843 session_deps.socket_factory.AddSocketDataProvider(&data2);
2844
2845 TestCompletionCallback callback1;
2846
2847 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
2848
2849 int rv = trans->Start(&request, &callback1, BoundNetLog());
2850 EXPECT_EQ(ERR_IO_PENDING, rv);
2851
2852 rv = callback1.WaitForResult();
2853 EXPECT_EQ(OK, rv);
2854
2855 EXPECT_FALSE(trans->IsReadyToRestartForAuth());
2856
2857 const HttpResponseInfo* response = trans->GetResponseInfo();
2858 ASSERT_TRUE(response != NULL);
2859
2860 // The password prompt info should have been set in
2861 // response->auth_challenge.
2862 ASSERT_FALSE(response->auth_challenge.get() == NULL);
2863
2864 EXPECT_EQ(L"172.22.68.17:80", response->auth_challenge->host_and_port);
2865 EXPECT_EQ(L"", response->auth_challenge->realm);
2866 EXPECT_EQ(L"ntlm", response->auth_challenge->scheme);
2867
2868 TestCompletionCallback callback2;
2869
2870 rv = trans->RestartWithAuth(kTestingNTLM, kTestingNTLM, &callback2);
2871 EXPECT_EQ(ERR_IO_PENDING, rv);
2872
2873 rv = callback2.WaitForResult();
2874 EXPECT_EQ(OK, rv);
2875
2876 EXPECT_TRUE(trans->IsReadyToRestartForAuth());
2877
2878 response = trans->GetResponseInfo();
2879 ASSERT_TRUE(response != NULL);
2880
2881 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2882
2883 TestCompletionCallback callback3;
2884
2885 rv = trans->RestartWithAuth(string16(), string16(), &callback3);
2886 EXPECT_EQ(ERR_IO_PENDING, rv);
2887
2888 rv = callback3.WaitForResult();
2889 EXPECT_EQ(OK, rv);
2890
2891 response = trans->GetResponseInfo();
2892 ASSERT_FALSE(response == NULL);
2893 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2894 EXPECT_EQ(13, response->headers->GetContentLength());
2895 }
2896
2897 // Enter a wrong password, and then the correct one.
TEST_F(HttpNetworkTransactionTest,NTLMAuth2)2898 TEST_F(HttpNetworkTransactionTest, NTLMAuth2) {
2899 HttpRequestInfo request;
2900 request.method = "GET";
2901 request.url = GURL("http://172.22.68.17/kids/login.aspx");
2902 request.load_flags = 0;
2903
2904 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockGenerateRandom2,
2905 MockGetHostName);
2906 SessionDependencies session_deps;
2907 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
2908
2909 MockWrite data_writes1[] = {
2910 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
2911 "Host: 172.22.68.17\r\n"
2912 "Connection: keep-alive\r\n\r\n"),
2913 };
2914
2915 MockRead data_reads1[] = {
2916 MockRead("HTTP/1.1 401 Access Denied\r\n"),
2917 // Negotiate and NTLM are often requested together. However, we only want
2918 // to test NTLM. Since Negotiate is preferred over NTLM, we have to skip
2919 // the header that requests Negotiate for this test.
2920 MockRead("WWW-Authenticate: NTLM\r\n"),
2921 MockRead("Connection: close\r\n"),
2922 MockRead("Content-Length: 42\r\n"),
2923 MockRead("Content-Type: text/html\r\n\r\n"),
2924 // Missing content -- won't matter, as connection will be reset.
2925 MockRead(false, ERR_UNEXPECTED),
2926 };
2927
2928 MockWrite data_writes2[] = {
2929 // After restarting with a null identity, this is the
2930 // request we should be issuing -- the final header line contains a Type
2931 // 1 message.
2932 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
2933 "Host: 172.22.68.17\r\n"
2934 "Connection: keep-alive\r\n"
2935 "Authorization: NTLM "
2936 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"),
2937
2938 // After calling trans->RestartWithAuth(), we should send a Type 3 message
2939 // (the credentials for the origin server). The second request continues
2940 // on the same connection.
2941 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
2942 "Host: 172.22.68.17\r\n"
2943 "Connection: keep-alive\r\n"
2944 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA"
2945 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA"
2946 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwCWeY"
2947 "XnSZNwoQAAAAAAAAAAAAAAAAAAAADLa34/phTTKzNTWdub+uyFleOj"
2948 "4Ww7b7E=\r\n\r\n"),
2949 };
2950
2951 MockRead data_reads2[] = {
2952 // The origin server responds with a Type 2 message.
2953 MockRead("HTTP/1.1 401 Access Denied\r\n"),
2954 MockRead("WWW-Authenticate: NTLM "
2955 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCbVWUZezVGpAAAAAAAAAAALo"
2956 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE"
2957 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA"
2958 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy"
2959 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB"
2960 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw"
2961 "BtAAAAAAA=\r\n"),
2962 MockRead("Content-Length: 42\r\n"),
2963 MockRead("Content-Type: text/html\r\n\r\n"),
2964 MockRead("You are not authorized to view this page\r\n"),
2965
2966 // Wrong password.
2967 MockRead("HTTP/1.1 401 Access Denied\r\n"),
2968 MockRead("WWW-Authenticate: NTLM\r\n"),
2969 MockRead("Connection: close\r\n"),
2970 MockRead("Content-Length: 42\r\n"),
2971 MockRead("Content-Type: text/html\r\n\r\n"),
2972 // Missing content -- won't matter, as connection will be reset.
2973 MockRead(false, ERR_UNEXPECTED),
2974 };
2975
2976 MockWrite data_writes3[] = {
2977 // After restarting with a null identity, this is the
2978 // request we should be issuing -- the final header line contains a Type
2979 // 1 message.
2980 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
2981 "Host: 172.22.68.17\r\n"
2982 "Connection: keep-alive\r\n"
2983 "Authorization: NTLM "
2984 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"),
2985
2986 // After calling trans->RestartWithAuth(), we should send a Type 3 message
2987 // (the credentials for the origin server). The second request continues
2988 // on the same connection.
2989 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
2990 "Host: 172.22.68.17\r\n"
2991 "Connection: keep-alive\r\n"
2992 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA"
2993 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA"
2994 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBO54"
2995 "dFMVvTHwAAAAAAAAAAAAAAAAAAAACS7sT6Uzw7L0L//WUqlIaVWpbI"
2996 "+4MUm7c=\r\n\r\n"),
2997 };
2998
2999 MockRead data_reads3[] = {
3000 // The origin server responds with a Type 2 message.
3001 MockRead("HTTP/1.1 401 Access Denied\r\n"),
3002 MockRead("WWW-Authenticate: NTLM "
3003 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCL24VN8dgOR8AAAAAAAAAALo"
3004 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE"
3005 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA"
3006 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy"
3007 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB"
3008 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw"
3009 "BtAAAAAAA=\r\n"),
3010 MockRead("Content-Length: 42\r\n"),
3011 MockRead("Content-Type: text/html\r\n\r\n"),
3012 MockRead("You are not authorized to view this page\r\n"),
3013
3014 // Lastly we get the desired content.
3015 MockRead("HTTP/1.1 200 OK\r\n"),
3016 MockRead("Content-Type: text/html; charset=utf-8\r\n"),
3017 MockRead("Content-Length: 13\r\n\r\n"),
3018 MockRead("Please Login\r\n"),
3019 MockRead(false, OK),
3020 };
3021
3022 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
3023 data_writes1, arraysize(data_writes1));
3024 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
3025 data_writes2, arraysize(data_writes2));
3026 StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3),
3027 data_writes3, arraysize(data_writes3));
3028 session_deps.socket_factory.AddSocketDataProvider(&data1);
3029 session_deps.socket_factory.AddSocketDataProvider(&data2);
3030 session_deps.socket_factory.AddSocketDataProvider(&data3);
3031
3032 TestCompletionCallback callback1;
3033
3034 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
3035
3036 int rv = trans->Start(&request, &callback1, BoundNetLog());
3037 EXPECT_EQ(ERR_IO_PENDING, rv);
3038
3039 rv = callback1.WaitForResult();
3040 EXPECT_EQ(OK, rv);
3041
3042 EXPECT_FALSE(trans->IsReadyToRestartForAuth());
3043
3044 const HttpResponseInfo* response = trans->GetResponseInfo();
3045 EXPECT_FALSE(response == NULL);
3046
3047 // The password prompt info should have been set in response->auth_challenge.
3048 EXPECT_FALSE(response->auth_challenge.get() == NULL);
3049
3050 EXPECT_EQ(L"172.22.68.17:80", response->auth_challenge->host_and_port);
3051 EXPECT_EQ(L"", response->auth_challenge->realm);
3052 EXPECT_EQ(L"ntlm", response->auth_challenge->scheme);
3053
3054 TestCompletionCallback callback2;
3055
3056 // Enter the wrong password.
3057 rv = trans->RestartWithAuth(kTestingNTLM, kWrongPassword, &callback2);
3058 EXPECT_EQ(ERR_IO_PENDING, rv);
3059
3060 rv = callback2.WaitForResult();
3061 EXPECT_EQ(OK, rv);
3062
3063 EXPECT_TRUE(trans->IsReadyToRestartForAuth());
3064 TestCompletionCallback callback3;
3065 rv = trans->RestartWithAuth(string16(), string16(), &callback3);
3066 EXPECT_EQ(ERR_IO_PENDING, rv);
3067 rv = callback3.WaitForResult();
3068 EXPECT_EQ(OK, rv);
3069 EXPECT_FALSE(trans->IsReadyToRestartForAuth());
3070
3071 response = trans->GetResponseInfo();
3072 ASSERT_TRUE(response != NULL);
3073
3074 // The password prompt info should have been set in response->auth_challenge.
3075 EXPECT_FALSE(response->auth_challenge.get() == NULL);
3076
3077 EXPECT_EQ(L"172.22.68.17:80", response->auth_challenge->host_and_port);
3078 EXPECT_EQ(L"", response->auth_challenge->realm);
3079 EXPECT_EQ(L"ntlm", response->auth_challenge->scheme);
3080
3081 TestCompletionCallback callback4;
3082
3083 // Now enter the right password.
3084 rv = trans->RestartWithAuth(kTestingNTLM, kTestingNTLM, &callback4);
3085 EXPECT_EQ(ERR_IO_PENDING, rv);
3086
3087 rv = callback4.WaitForResult();
3088 EXPECT_EQ(OK, rv);
3089
3090 EXPECT_TRUE(trans->IsReadyToRestartForAuth());
3091
3092 TestCompletionCallback callback5;
3093
3094 // One more roundtrip
3095 rv = trans->RestartWithAuth(string16(), string16(), &callback5);
3096 EXPECT_EQ(ERR_IO_PENDING, rv);
3097
3098 rv = callback5.WaitForResult();
3099 EXPECT_EQ(OK, rv);
3100
3101 response = trans->GetResponseInfo();
3102 EXPECT_TRUE(response->auth_challenge.get() == NULL);
3103 EXPECT_EQ(13, response->headers->GetContentLength());
3104 }
3105 #endif // NTLM_PORTABLE
3106
3107 // Test reading a server response which has only headers, and no body.
3108 // After some maximum number of bytes is consumed, the transaction should
3109 // fail with ERR_RESPONSE_HEADERS_TOO_BIG.
TEST_F(HttpNetworkTransactionTest,LargeHeadersNoBody)3110 TEST_F(HttpNetworkTransactionTest, LargeHeadersNoBody) {
3111 HttpRequestInfo request;
3112 request.method = "GET";
3113 request.url = GURL("http://www.google.com/");
3114 request.load_flags = 0;
3115
3116 SessionDependencies session_deps;
3117 scoped_ptr<HttpTransaction> trans(
3118 new HttpNetworkTransaction(CreateSession(&session_deps)));
3119
3120 // Respond with 300 kb of headers (we should fail after 256 kb).
3121 std::string large_headers_string;
3122 FillLargeHeadersString(&large_headers_string, 300 * 1024);
3123
3124 MockRead data_reads[] = {
3125 MockRead("HTTP/1.0 200 OK\r\n"),
3126 MockRead(true, large_headers_string.data(), large_headers_string.size()),
3127 MockRead("\r\nBODY"),
3128 MockRead(false, OK),
3129 };
3130 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
3131 session_deps.socket_factory.AddSocketDataProvider(&data);
3132
3133 TestCompletionCallback callback;
3134
3135 int rv = trans->Start(&request, &callback, BoundNetLog());
3136 EXPECT_EQ(ERR_IO_PENDING, rv);
3137
3138 rv = callback.WaitForResult();
3139 EXPECT_EQ(ERR_RESPONSE_HEADERS_TOO_BIG, rv);
3140
3141 const HttpResponseInfo* response = trans->GetResponseInfo();
3142 EXPECT_TRUE(response == NULL);
3143 }
3144
3145 // Make sure that we don't try to reuse a TCPClientSocket when failing to
3146 // establish tunnel.
3147 // http://code.google.com/p/chromium/issues/detail?id=3772
TEST_F(HttpNetworkTransactionTest,DontRecycleTransportSocketForSSLTunnel)3148 TEST_F(HttpNetworkTransactionTest, DontRecycleTransportSocketForSSLTunnel) {
3149 HttpRequestInfo request;
3150 request.method = "GET";
3151 request.url = GURL("https://www.google.com/");
3152 request.load_flags = 0;
3153
3154 // Configure against proxy server "myproxy:70".
3155 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70"));
3156
3157 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
3158
3159 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
3160
3161 // Since we have proxy, should try to establish tunnel.
3162 MockWrite data_writes1[] = {
3163 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
3164 "Host: www.google.com\r\n"
3165 "Proxy-Connection: keep-alive\r\n\r\n"),
3166 };
3167
3168 // The proxy responds to the connect with a 404, using a persistent
3169 // connection. Usually a proxy would return 501 (not implemented),
3170 // or 200 (tunnel established).
3171 MockRead data_reads1[] = {
3172 MockRead("HTTP/1.1 404 Not Found\r\n"),
3173 MockRead("Content-Length: 10\r\n\r\n"),
3174 MockRead(false, ERR_UNEXPECTED), // Should not be reached.
3175 };
3176
3177 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
3178 data_writes1, arraysize(data_writes1));
3179 session_deps.socket_factory.AddSocketDataProvider(&data1);
3180
3181 TestCompletionCallback callback1;
3182
3183 int rv = trans->Start(&request, &callback1, BoundNetLog());
3184 EXPECT_EQ(ERR_IO_PENDING, rv);
3185
3186 rv = callback1.WaitForResult();
3187 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
3188
3189 const HttpResponseInfo* response = trans->GetResponseInfo();
3190 EXPECT_TRUE(response == NULL);
3191
3192 // Empty the current queue. This is necessary because idle sockets are
3193 // added to the connection pool asynchronously with a PostTask.
3194 MessageLoop::current()->RunAllPending();
3195
3196 // We now check to make sure the TCPClientSocket was not added back to
3197 // the pool.
3198 EXPECT_EQ(0, session->transport_socket_pool()->IdleSocketCount());
3199 trans.reset();
3200 MessageLoop::current()->RunAllPending();
3201 // Make sure that the socket didn't get recycled after calling the destructor.
3202 EXPECT_EQ(0, session->transport_socket_pool()->IdleSocketCount());
3203 }
3204
3205 // Make sure that we recycle a socket after reading all of the response body.
TEST_F(HttpNetworkTransactionTest,RecycleSocket)3206 TEST_F(HttpNetworkTransactionTest, RecycleSocket) {
3207 HttpRequestInfo request;
3208 request.method = "GET";
3209 request.url = GURL("http://www.google.com/");
3210 request.load_flags = 0;
3211
3212 SessionDependencies session_deps;
3213 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
3214
3215 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
3216
3217 MockRead data_reads[] = {
3218 // A part of the response body is received with the response headers.
3219 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\nhel"),
3220 // The rest of the response body is received in two parts.
3221 MockRead("lo"),
3222 MockRead(" world"),
3223 MockRead("junk"), // Should not be read!!
3224 MockRead(false, OK),
3225 };
3226
3227 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
3228 session_deps.socket_factory.AddSocketDataProvider(&data);
3229
3230 TestCompletionCallback callback;
3231
3232 int rv = trans->Start(&request, &callback, BoundNetLog());
3233 EXPECT_EQ(ERR_IO_PENDING, rv);
3234
3235 rv = callback.WaitForResult();
3236 EXPECT_EQ(OK, rv);
3237
3238 const HttpResponseInfo* response = trans->GetResponseInfo();
3239 EXPECT_TRUE(response != NULL);
3240
3241 EXPECT_TRUE(response->headers != NULL);
3242 std::string status_line = response->headers->GetStatusLine();
3243 EXPECT_EQ("HTTP/1.1 200 OK", status_line);
3244
3245 EXPECT_EQ(0, session->transport_socket_pool()->IdleSocketCount());
3246
3247 std::string response_data;
3248 rv = ReadTransaction(trans.get(), &response_data);
3249 EXPECT_EQ(OK, rv);
3250 EXPECT_EQ("hello world", response_data);
3251
3252 // Empty the current queue. This is necessary because idle sockets are
3253 // added to the connection pool asynchronously with a PostTask.
3254 MessageLoop::current()->RunAllPending();
3255
3256 // We now check to make sure the socket was added back to the pool.
3257 EXPECT_EQ(1, session->transport_socket_pool()->IdleSocketCount());
3258 }
3259
3260 // Make sure that we recycle a SSL socket after reading all of the response
3261 // body.
TEST_F(HttpNetworkTransactionTest,RecycleSSLSocket)3262 TEST_F(HttpNetworkTransactionTest, RecycleSSLSocket) {
3263 SessionDependencies session_deps;
3264 HttpRequestInfo request;
3265 request.method = "GET";
3266 request.url = GURL("https://www.google.com/");
3267 request.load_flags = 0;
3268
3269 MockWrite data_writes[] = {
3270 MockWrite("GET / HTTP/1.1\r\n"
3271 "Host: www.google.com\r\n"
3272 "Connection: keep-alive\r\n\r\n"),
3273 };
3274
3275 MockRead data_reads[] = {
3276 MockRead("HTTP/1.1 200 OK\r\n"),
3277 MockRead("Content-Length: 11\r\n\r\n"),
3278 MockRead("hello world"),
3279 MockRead(false, OK),
3280 };
3281
3282 SSLSocketDataProvider ssl(true, OK);
3283 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
3284
3285 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
3286 data_writes, arraysize(data_writes));
3287 session_deps.socket_factory.AddSocketDataProvider(&data);
3288
3289 TestCompletionCallback callback;
3290
3291 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
3292 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
3293
3294 int rv = trans->Start(&request, &callback, BoundNetLog());
3295
3296 EXPECT_EQ(ERR_IO_PENDING, rv);
3297 EXPECT_EQ(OK, callback.WaitForResult());
3298
3299 const HttpResponseInfo* response = trans->GetResponseInfo();
3300 ASSERT_TRUE(response != NULL);
3301 ASSERT_TRUE(response->headers != NULL);
3302 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
3303
3304 EXPECT_EQ(0, session->transport_socket_pool()->IdleSocketCount());
3305
3306 std::string response_data;
3307 rv = ReadTransaction(trans.get(), &response_data);
3308 EXPECT_EQ(OK, rv);
3309 EXPECT_EQ("hello world", response_data);
3310
3311 // Empty the current queue. This is necessary because idle sockets are
3312 // added to the connection pool asynchronously with a PostTask.
3313 MessageLoop::current()->RunAllPending();
3314
3315 // We now check to make sure the socket was added back to the pool.
3316 EXPECT_EQ(1, session->ssl_socket_pool()->IdleSocketCount());
3317 }
3318
3319 // Grab a SSL socket, use it, and put it back into the pool. Then, reuse it
3320 // from the pool and make sure that we recover okay.
TEST_F(HttpNetworkTransactionTest,RecycleDeadSSLSocket)3321 TEST_F(HttpNetworkTransactionTest, RecycleDeadSSLSocket) {
3322 SessionDependencies session_deps;
3323 HttpRequestInfo request;
3324 request.method = "GET";
3325 request.url = GURL("https://www.google.com/");
3326 request.load_flags = 0;
3327
3328 MockWrite data_writes[] = {
3329 MockWrite("GET / HTTP/1.1\r\n"
3330 "Host: www.google.com\r\n"
3331 "Connection: keep-alive\r\n\r\n"),
3332 MockWrite("GET / HTTP/1.1\r\n"
3333 "Host: www.google.com\r\n"
3334 "Connection: keep-alive\r\n\r\n"),
3335 };
3336
3337 MockRead data_reads[] = {
3338 MockRead("HTTP/1.1 200 OK\r\n"),
3339 MockRead("Content-Length: 11\r\n\r\n"),
3340 MockRead(false, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
3341 MockRead("hello world"),
3342 MockRead(true, 0, 0) // EOF
3343 };
3344
3345 SSLSocketDataProvider ssl(true, OK);
3346 SSLSocketDataProvider ssl2(true, OK);
3347 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
3348 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2);
3349
3350 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
3351 data_writes, arraysize(data_writes));
3352 StaticSocketDataProvider data2(data_reads, arraysize(data_reads),
3353 data_writes, arraysize(data_writes));
3354 session_deps.socket_factory.AddSocketDataProvider(&data);
3355 session_deps.socket_factory.AddSocketDataProvider(&data2);
3356
3357 TestCompletionCallback callback;
3358
3359 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
3360 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
3361
3362 int rv = trans->Start(&request, &callback, BoundNetLog());
3363
3364 EXPECT_EQ(ERR_IO_PENDING, rv);
3365 EXPECT_EQ(OK, callback.WaitForResult());
3366
3367 const HttpResponseInfo* response = trans->GetResponseInfo();
3368 ASSERT_TRUE(response != NULL);
3369 ASSERT_TRUE(response->headers != NULL);
3370 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
3371
3372 EXPECT_EQ(0, session->transport_socket_pool()->IdleSocketCount());
3373
3374 std::string response_data;
3375 rv = ReadTransaction(trans.get(), &response_data);
3376 EXPECT_EQ(OK, rv);
3377 EXPECT_EQ("hello world", response_data);
3378
3379 // Empty the current queue. This is necessary because idle sockets are
3380 // added to the connection pool asynchronously with a PostTask.
3381 MessageLoop::current()->RunAllPending();
3382
3383 // We now check to make sure the socket was added back to the pool.
3384 EXPECT_EQ(1, session->ssl_socket_pool()->IdleSocketCount());
3385
3386 // Now start the second transaction, which should reuse the previous socket.
3387
3388 trans.reset(new HttpNetworkTransaction(session));
3389
3390 rv = trans->Start(&request, &callback, BoundNetLog());
3391
3392 EXPECT_EQ(ERR_IO_PENDING, rv);
3393 EXPECT_EQ(OK, callback.WaitForResult());
3394
3395 response = trans->GetResponseInfo();
3396 ASSERT_TRUE(response != NULL);
3397 ASSERT_TRUE(response->headers != NULL);
3398 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
3399
3400 EXPECT_EQ(0, session->transport_socket_pool()->IdleSocketCount());
3401
3402 rv = ReadTransaction(trans.get(), &response_data);
3403 EXPECT_EQ(OK, rv);
3404 EXPECT_EQ("hello world", response_data);
3405
3406 // Empty the current queue. This is necessary because idle sockets are
3407 // added to the connection pool asynchronously with a PostTask.
3408 MessageLoop::current()->RunAllPending();
3409
3410 // We now check to make sure the socket was added back to the pool.
3411 EXPECT_EQ(1, session->ssl_socket_pool()->IdleSocketCount());
3412 }
3413
3414 // Make sure that we recycle a socket after a zero-length response.
3415 // http://crbug.com/9880
TEST_F(HttpNetworkTransactionTest,RecycleSocketAfterZeroContentLength)3416 TEST_F(HttpNetworkTransactionTest, RecycleSocketAfterZeroContentLength) {
3417 HttpRequestInfo request;
3418 request.method = "GET";
3419 request.url = GURL("http://www.google.com/csi?v=3&s=web&action=&"
3420 "tran=undefined&ei=mAXcSeegAo-SMurloeUN&"
3421 "e=17259,18167,19592,19773,19981,20133,20173,20233&"
3422 "rt=prt.2642,ol.2649,xjs.2951");
3423 request.load_flags = 0;
3424
3425 SessionDependencies session_deps;
3426 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
3427
3428 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
3429
3430 MockRead data_reads[] = {
3431 MockRead("HTTP/1.1 204 No Content\r\n"
3432 "Content-Length: 0\r\n"
3433 "Content-Type: text/html\r\n\r\n"),
3434 MockRead("junk"), // Should not be read!!
3435 MockRead(false, OK),
3436 };
3437
3438 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
3439 session_deps.socket_factory.AddSocketDataProvider(&data);
3440
3441 TestCompletionCallback callback;
3442
3443 int rv = trans->Start(&request, &callback, BoundNetLog());
3444 EXPECT_EQ(ERR_IO_PENDING, rv);
3445
3446 rv = callback.WaitForResult();
3447 EXPECT_EQ(OK, rv);
3448
3449 const HttpResponseInfo* response = trans->GetResponseInfo();
3450 EXPECT_TRUE(response != NULL);
3451
3452 EXPECT_TRUE(response->headers != NULL);
3453 std::string status_line = response->headers->GetStatusLine();
3454 EXPECT_EQ("HTTP/1.1 204 No Content", status_line);
3455
3456 EXPECT_EQ(0, session->transport_socket_pool()->IdleSocketCount());
3457
3458 std::string response_data;
3459 rv = ReadTransaction(trans.get(), &response_data);
3460 EXPECT_EQ(OK, rv);
3461 EXPECT_EQ("", response_data);
3462
3463 // Empty the current queue. This is necessary because idle sockets are
3464 // added to the connection pool asynchronously with a PostTask.
3465 MessageLoop::current()->RunAllPending();
3466
3467 // We now check to make sure the socket was added back to the pool.
3468 EXPECT_EQ(1, session->transport_socket_pool()->IdleSocketCount());
3469 }
3470
TEST_F(HttpNetworkTransactionTest,ResendRequestOnWriteBodyError)3471 TEST_F(HttpNetworkTransactionTest, ResendRequestOnWriteBodyError) {
3472 HttpRequestInfo request[2];
3473 // Transaction 1: a GET request that succeeds. The socket is recycled
3474 // after use.
3475 request[0].method = "GET";
3476 request[0].url = GURL("http://www.google.com/");
3477 request[0].load_flags = 0;
3478 // Transaction 2: a POST request. Reuses the socket kept alive from
3479 // transaction 1. The first attempts fails when writing the POST data.
3480 // This causes the transaction to retry with a new socket. The second
3481 // attempt succeeds.
3482 request[1].method = "POST";
3483 request[1].url = GURL("http://www.google.com/login.cgi");
3484 request[1].upload_data = new UploadData;
3485 request[1].upload_data->AppendBytes("foo", 3);
3486 request[1].load_flags = 0;
3487
3488 SessionDependencies session_deps;
3489 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
3490
3491 // The first socket is used for transaction 1 and the first attempt of
3492 // transaction 2.
3493
3494 // The response of transaction 1.
3495 MockRead data_reads1[] = {
3496 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\n"),
3497 MockRead("hello world"),
3498 MockRead(false, OK),
3499 };
3500 // The mock write results of transaction 1 and the first attempt of
3501 // transaction 2.
3502 MockWrite data_writes1[] = {
3503 MockWrite(false, 64), // GET
3504 MockWrite(false, 93), // POST
3505 MockWrite(false, ERR_CONNECTION_ABORTED), // POST data
3506 };
3507 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
3508 data_writes1, arraysize(data_writes1));
3509
3510 // The second socket is used for the second attempt of transaction 2.
3511
3512 // The response of transaction 2.
3513 MockRead data_reads2[] = {
3514 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 7\r\n\r\n"),
3515 MockRead("welcome"),
3516 MockRead(false, OK),
3517 };
3518 // The mock write results of the second attempt of transaction 2.
3519 MockWrite data_writes2[] = {
3520 MockWrite(false, 93), // POST
3521 MockWrite(false, 3), // POST data
3522 };
3523 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
3524 data_writes2, arraysize(data_writes2));
3525
3526 session_deps.socket_factory.AddSocketDataProvider(&data1);
3527 session_deps.socket_factory.AddSocketDataProvider(&data2);
3528
3529 const char* kExpectedResponseData[] = {
3530 "hello world", "welcome"
3531 };
3532
3533 for (int i = 0; i < 2; ++i) {
3534 scoped_ptr<HttpTransaction> trans(
3535 new HttpNetworkTransaction(session));
3536
3537 TestCompletionCallback callback;
3538
3539 int rv = trans->Start(&request[i], &callback, BoundNetLog());
3540 EXPECT_EQ(ERR_IO_PENDING, rv);
3541
3542 rv = callback.WaitForResult();
3543 EXPECT_EQ(OK, rv);
3544
3545 const HttpResponseInfo* response = trans->GetResponseInfo();
3546 EXPECT_TRUE(response != NULL);
3547
3548 EXPECT_TRUE(response->headers != NULL);
3549 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
3550
3551 std::string response_data;
3552 rv = ReadTransaction(trans.get(), &response_data);
3553 EXPECT_EQ(OK, rv);
3554 EXPECT_EQ(kExpectedResponseData[i], response_data);
3555 }
3556 }
3557
3558 // Test the request-challenge-retry sequence for basic auth when there is
3559 // an identity in the URL. The request should be sent as normal, but when
3560 // it fails the identity from the URL is used to answer the challenge.
TEST_F(HttpNetworkTransactionTest,AuthIdentityInURL)3561 TEST_F(HttpNetworkTransactionTest, AuthIdentityInURL) {
3562 HttpRequestInfo request;
3563 request.method = "GET";
3564 // Note: the URL has a username:password in it.
3565 request.url = GURL("http://foo:b@r@www.google.com/");
3566
3567 SessionDependencies session_deps;
3568 scoped_ptr<HttpTransaction> trans(
3569 new HttpNetworkTransaction(CreateSession(&session_deps)));
3570
3571 // The password contains an escaped character -- for this test to pass it
3572 // will need to be unescaped by HttpNetworkTransaction.
3573 EXPECT_EQ("b%40r", request.url.password());
3574
3575 request.load_flags = LOAD_NORMAL;
3576
3577 MockWrite data_writes1[] = {
3578 MockWrite("GET / HTTP/1.1\r\n"
3579 "Host: www.google.com\r\n"
3580 "Connection: keep-alive\r\n\r\n"),
3581 };
3582
3583 MockRead data_reads1[] = {
3584 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
3585 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
3586 MockRead("Content-Length: 10\r\n\r\n"),
3587 MockRead(false, ERR_FAILED),
3588 };
3589
3590 // After the challenge above, the transaction will be restarted using the
3591 // identity from the url (foo, b@r) to answer the challenge.
3592 MockWrite data_writes2[] = {
3593 MockWrite("GET / HTTP/1.1\r\n"
3594 "Host: www.google.com\r\n"
3595 "Connection: keep-alive\r\n"
3596 "Authorization: Basic Zm9vOmJAcg==\r\n\r\n"),
3597 };
3598
3599 MockRead data_reads2[] = {
3600 MockRead("HTTP/1.0 200 OK\r\n"),
3601 MockRead("Content-Length: 100\r\n\r\n"),
3602 MockRead(false, OK),
3603 };
3604
3605 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
3606 data_writes1, arraysize(data_writes1));
3607 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
3608 data_writes2, arraysize(data_writes2));
3609 session_deps.socket_factory.AddSocketDataProvider(&data1);
3610 session_deps.socket_factory.AddSocketDataProvider(&data2);
3611
3612 TestCompletionCallback callback1;
3613
3614 int rv = trans->Start(&request, &callback1, BoundNetLog());
3615 EXPECT_EQ(ERR_IO_PENDING, rv);
3616
3617 rv = callback1.WaitForResult();
3618 EXPECT_EQ(OK, rv);
3619
3620 EXPECT_TRUE(trans->IsReadyToRestartForAuth());
3621 TestCompletionCallback callback2;
3622 rv = trans->RestartWithAuth(string16(), string16(), &callback2);
3623 EXPECT_EQ(ERR_IO_PENDING, rv);
3624 rv = callback2.WaitForResult();
3625 EXPECT_EQ(OK, rv);
3626 EXPECT_FALSE(trans->IsReadyToRestartForAuth());
3627
3628 const HttpResponseInfo* response = trans->GetResponseInfo();
3629 EXPECT_FALSE(response == NULL);
3630
3631 // There is no challenge info, since the identity in URL worked.
3632 EXPECT_TRUE(response->auth_challenge.get() == NULL);
3633
3634 EXPECT_EQ(100, response->headers->GetContentLength());
3635
3636 // Empty the current queue.
3637 MessageLoop::current()->RunAllPending();
3638 }
3639
3640 // Test the request-challenge-retry sequence for basic auth when there is
3641 // an incorrect identity in the URL. The identity from the URL should be used
3642 // only once.
TEST_F(HttpNetworkTransactionTest,WrongAuthIdentityInURL)3643 TEST_F(HttpNetworkTransactionTest, WrongAuthIdentityInURL) {
3644 HttpRequestInfo request;
3645 request.method = "GET";
3646 // Note: the URL has a username:password in it. The password "baz" is
3647 // wrong (should be "bar").
3648 request.url = GURL("http://foo:baz@www.google.com/");
3649
3650 request.load_flags = LOAD_NORMAL;
3651
3652 SessionDependencies session_deps;
3653 scoped_ptr<HttpTransaction> trans(
3654 new HttpNetworkTransaction(CreateSession(&session_deps)));
3655
3656 MockWrite data_writes1[] = {
3657 MockWrite("GET / HTTP/1.1\r\n"
3658 "Host: www.google.com\r\n"
3659 "Connection: keep-alive\r\n\r\n"),
3660 };
3661
3662 MockRead data_reads1[] = {
3663 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
3664 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
3665 MockRead("Content-Length: 10\r\n\r\n"),
3666 MockRead(false, ERR_FAILED),
3667 };
3668
3669 // After the challenge above, the transaction will be restarted using the
3670 // identity from the url (foo, baz) to answer the challenge.
3671 MockWrite data_writes2[] = {
3672 MockWrite("GET / HTTP/1.1\r\n"
3673 "Host: www.google.com\r\n"
3674 "Connection: keep-alive\r\n"
3675 "Authorization: Basic Zm9vOmJheg==\r\n\r\n"),
3676 };
3677
3678 MockRead data_reads2[] = {
3679 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
3680 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
3681 MockRead("Content-Length: 10\r\n\r\n"),
3682 MockRead(false, ERR_FAILED),
3683 };
3684
3685 // After the challenge above, the transaction will be restarted using the
3686 // identity supplied by the user (foo, bar) to answer the challenge.
3687 MockWrite data_writes3[] = {
3688 MockWrite("GET / HTTP/1.1\r\n"
3689 "Host: www.google.com\r\n"
3690 "Connection: keep-alive\r\n"
3691 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
3692 };
3693
3694 MockRead data_reads3[] = {
3695 MockRead("HTTP/1.0 200 OK\r\n"),
3696 MockRead("Content-Length: 100\r\n\r\n"),
3697 MockRead(false, OK),
3698 };
3699
3700 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
3701 data_writes1, arraysize(data_writes1));
3702 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
3703 data_writes2, arraysize(data_writes2));
3704 StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3),
3705 data_writes3, arraysize(data_writes3));
3706 session_deps.socket_factory.AddSocketDataProvider(&data1);
3707 session_deps.socket_factory.AddSocketDataProvider(&data2);
3708 session_deps.socket_factory.AddSocketDataProvider(&data3);
3709
3710 TestCompletionCallback callback1;
3711
3712 int rv = trans->Start(&request, &callback1, BoundNetLog());
3713 EXPECT_EQ(ERR_IO_PENDING, rv);
3714
3715 rv = callback1.WaitForResult();
3716 EXPECT_EQ(OK, rv);
3717
3718 EXPECT_TRUE(trans->IsReadyToRestartForAuth());
3719 TestCompletionCallback callback2;
3720 rv = trans->RestartWithAuth(string16(), string16(), &callback2);
3721 EXPECT_EQ(ERR_IO_PENDING, rv);
3722 rv = callback2.WaitForResult();
3723 EXPECT_EQ(OK, rv);
3724 EXPECT_FALSE(trans->IsReadyToRestartForAuth());
3725
3726 const HttpResponseInfo* response = trans->GetResponseInfo();
3727 EXPECT_FALSE(response == NULL);
3728 // The password prompt info should have been set in response->auth_challenge.
3729 EXPECT_FALSE(response->auth_challenge.get() == NULL);
3730
3731 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
3732 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
3733 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
3734
3735 TestCompletionCallback callback3;
3736 rv = trans->RestartWithAuth(kFoo, kBar, &callback3);
3737 EXPECT_EQ(ERR_IO_PENDING, rv);
3738 rv = callback3.WaitForResult();
3739 EXPECT_EQ(OK, rv);
3740 EXPECT_FALSE(trans->IsReadyToRestartForAuth());
3741
3742 response = trans->GetResponseInfo();
3743 EXPECT_FALSE(response == NULL);
3744
3745 // There is no challenge info, since the identity worked.
3746 EXPECT_TRUE(response->auth_challenge.get() == NULL);
3747
3748 EXPECT_EQ(100, response->headers->GetContentLength());
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.
TEST_F(HttpNetworkTransactionTest,BasicAuthCacheAndPreauth)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(false, 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(false, 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, 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 EXPECT_FALSE(response == NULL);
3813
3814 // The password prompt info should have been set in
3815 // response->auth_challenge.
3816 EXPECT_FALSE(response->auth_challenge.get() == NULL);
3817
3818 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
3819 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
3820 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
3821
3822 TestCompletionCallback callback2;
3823
3824 rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
3825 EXPECT_EQ(ERR_IO_PENDING, rv);
3826
3827 rv = callback2.WaitForResult();
3828 EXPECT_EQ(OK, rv);
3829
3830 response = trans->GetResponseInfo();
3831 EXPECT_FALSE(response == NULL);
3832 EXPECT_TRUE(response->auth_challenge.get() == NULL);
3833 EXPECT_EQ(100, response->headers->GetContentLength());
3834 }
3835
3836 // ------------------------------------------------------------------------
3837
3838 // Transaction 2: authenticate (foo2, bar2) on MyRealm2
3839 {
3840 HttpRequestInfo request;
3841 request.method = "GET";
3842 // Note that Transaction 1 was at /x/y/z, so this is in the same
3843 // protection space as MyRealm1.
3844 request.url = GURL("http://www.google.com/x/y/a/b");
3845 request.load_flags = 0;
3846
3847 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
3848
3849 MockWrite data_writes1[] = {
3850 MockWrite("GET /x/y/a/b HTTP/1.1\r\n"
3851 "Host: www.google.com\r\n"
3852 "Connection: keep-alive\r\n"
3853 // Send preemptive authorization for MyRealm1
3854 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
3855 };
3856
3857 // The server didn't like the preemptive authorization, and
3858 // challenges us for a different realm (MyRealm2).
3859 MockRead data_reads1[] = {
3860 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
3861 MockRead("WWW-Authenticate: Basic realm=\"MyRealm2\"\r\n"),
3862 MockRead("Content-Length: 10000\r\n\r\n"),
3863 MockRead(false, ERR_FAILED),
3864 };
3865
3866 // Resend with authorization for MyRealm2 (username=foo2, password=bar2)
3867 MockWrite data_writes2[] = {
3868 MockWrite("GET /x/y/a/b HTTP/1.1\r\n"
3869 "Host: www.google.com\r\n"
3870 "Connection: keep-alive\r\n"
3871 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"),
3872 };
3873
3874 // Sever accepts the authorization.
3875 MockRead data_reads2[] = {
3876 MockRead("HTTP/1.0 200 OK\r\n"),
3877 MockRead("Content-Length: 100\r\n\r\n"),
3878 MockRead(false, OK),
3879 };
3880
3881 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
3882 data_writes1, arraysize(data_writes1));
3883 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
3884 data_writes2, arraysize(data_writes2));
3885 session_deps.socket_factory.AddSocketDataProvider(&data1);
3886 session_deps.socket_factory.AddSocketDataProvider(&data2);
3887
3888 TestCompletionCallback callback1;
3889
3890 int rv = trans->Start(&request, &callback1, BoundNetLog());
3891 EXPECT_EQ(ERR_IO_PENDING, rv);
3892
3893 rv = callback1.WaitForResult();
3894 EXPECT_EQ(OK, rv);
3895
3896 const HttpResponseInfo* response = trans->GetResponseInfo();
3897 EXPECT_FALSE(response == NULL);
3898
3899 // The password prompt info should have been set in
3900 // response->auth_challenge.
3901 EXPECT_FALSE(response->auth_challenge.get() == NULL);
3902
3903 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
3904 EXPECT_EQ(L"MyRealm2", response->auth_challenge->realm);
3905 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
3906
3907 TestCompletionCallback callback2;
3908
3909 rv = trans->RestartWithAuth(kFoo2, kBar2, &callback2);
3910 EXPECT_EQ(ERR_IO_PENDING, rv);
3911
3912 rv = callback2.WaitForResult();
3913 EXPECT_EQ(OK, rv);
3914
3915 response = trans->GetResponseInfo();
3916 EXPECT_FALSE(response == NULL);
3917 EXPECT_TRUE(response->auth_challenge.get() == NULL);
3918 EXPECT_EQ(100, response->headers->GetContentLength());
3919 }
3920
3921 // ------------------------------------------------------------------------
3922
3923 // Transaction 3: Resend a request in MyRealm's protection space --
3924 // succeed with preemptive authorization.
3925 {
3926 HttpRequestInfo request;
3927 request.method = "GET";
3928 request.url = GURL("http://www.google.com/x/y/z2");
3929 request.load_flags = 0;
3930
3931 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
3932
3933 MockWrite data_writes1[] = {
3934 MockWrite("GET /x/y/z2 HTTP/1.1\r\n"
3935 "Host: www.google.com\r\n"
3936 "Connection: keep-alive\r\n"
3937 // The authorization for MyRealm1 gets sent preemptively
3938 // (since the url is in the same protection space)
3939 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
3940 };
3941
3942 // Sever accepts the preemptive authorization
3943 MockRead data_reads1[] = {
3944 MockRead("HTTP/1.0 200 OK\r\n"),
3945 MockRead("Content-Length: 100\r\n\r\n"),
3946 MockRead(false, OK),
3947 };
3948
3949 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
3950 data_writes1, arraysize(data_writes1));
3951 session_deps.socket_factory.AddSocketDataProvider(&data1);
3952
3953 TestCompletionCallback callback1;
3954
3955 int rv = trans->Start(&request, &callback1, BoundNetLog());
3956 EXPECT_EQ(ERR_IO_PENDING, rv);
3957
3958 rv = callback1.WaitForResult();
3959 EXPECT_EQ(OK, rv);
3960
3961 const HttpResponseInfo* response = trans->GetResponseInfo();
3962 EXPECT_FALSE(response == NULL);
3963
3964 EXPECT_TRUE(response->auth_challenge.get() == NULL);
3965 EXPECT_EQ(100, response->headers->GetContentLength());
3966 }
3967
3968 // ------------------------------------------------------------------------
3969
3970 // Transaction 4: request another URL in MyRealm (however the
3971 // url is not known to belong to the protection space, so no pre-auth).
3972 {
3973 HttpRequestInfo request;
3974 request.method = "GET";
3975 request.url = GURL("http://www.google.com/x/1");
3976 request.load_flags = 0;
3977
3978 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
3979
3980 MockWrite data_writes1[] = {
3981 MockWrite("GET /x/1 HTTP/1.1\r\n"
3982 "Host: www.google.com\r\n"
3983 "Connection: keep-alive\r\n\r\n"),
3984 };
3985
3986 MockRead data_reads1[] = {
3987 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
3988 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
3989 MockRead("Content-Length: 10000\r\n\r\n"),
3990 MockRead(false, ERR_FAILED),
3991 };
3992
3993 // Resend with authorization from MyRealm's cache.
3994 MockWrite data_writes2[] = {
3995 MockWrite("GET /x/1 HTTP/1.1\r\n"
3996 "Host: www.google.com\r\n"
3997 "Connection: keep-alive\r\n"
3998 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
3999 };
4000
4001 // Sever accepts the authorization.
4002 MockRead data_reads2[] = {
4003 MockRead("HTTP/1.0 200 OK\r\n"),
4004 MockRead("Content-Length: 100\r\n\r\n"),
4005 MockRead(false, OK),
4006 };
4007
4008 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
4009 data_writes1, arraysize(data_writes1));
4010 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
4011 data_writes2, arraysize(data_writes2));
4012 session_deps.socket_factory.AddSocketDataProvider(&data1);
4013 session_deps.socket_factory.AddSocketDataProvider(&data2);
4014
4015 TestCompletionCallback callback1;
4016
4017 int rv = trans->Start(&request, &callback1, BoundNetLog());
4018 EXPECT_EQ(ERR_IO_PENDING, rv);
4019
4020 rv = callback1.WaitForResult();
4021 EXPECT_EQ(OK, rv);
4022
4023 EXPECT_TRUE(trans->IsReadyToRestartForAuth());
4024 TestCompletionCallback callback2;
4025 rv = trans->RestartWithAuth(string16(), string16(), &callback2);
4026 EXPECT_EQ(ERR_IO_PENDING, rv);
4027 rv = callback2.WaitForResult();
4028 EXPECT_EQ(OK, rv);
4029 EXPECT_FALSE(trans->IsReadyToRestartForAuth());
4030
4031 const HttpResponseInfo* response = trans->GetResponseInfo();
4032 EXPECT_FALSE(response == NULL);
4033 EXPECT_TRUE(response->auth_challenge.get() == NULL);
4034 EXPECT_EQ(100, response->headers->GetContentLength());
4035 }
4036
4037 // ------------------------------------------------------------------------
4038
4039 // Transaction 5: request a URL in MyRealm, but the server rejects the
4040 // cached identity. Should invalidate and re-prompt.
4041 {
4042 HttpRequestInfo request;
4043 request.method = "GET";
4044 request.url = GURL("http://www.google.com/p/q/t");
4045 request.load_flags = 0;
4046
4047 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
4048
4049 MockWrite data_writes1[] = {
4050 MockWrite("GET /p/q/t HTTP/1.1\r\n"
4051 "Host: www.google.com\r\n"
4052 "Connection: keep-alive\r\n\r\n"),
4053 };
4054
4055 MockRead data_reads1[] = {
4056 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
4057 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
4058 MockRead("Content-Length: 10000\r\n\r\n"),
4059 MockRead(false, ERR_FAILED),
4060 };
4061
4062 // Resend with authorization from cache for MyRealm.
4063 MockWrite data_writes2[] = {
4064 MockWrite("GET /p/q/t HTTP/1.1\r\n"
4065 "Host: www.google.com\r\n"
4066 "Connection: keep-alive\r\n"
4067 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
4068 };
4069
4070 // Sever rejects the authorization.
4071 MockRead data_reads2[] = {
4072 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
4073 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
4074 MockRead("Content-Length: 10000\r\n\r\n"),
4075 MockRead(false, ERR_FAILED),
4076 };
4077
4078 // At this point we should prompt for new credentials for MyRealm.
4079 // Restart with username=foo3, password=foo4.
4080 MockWrite data_writes3[] = {
4081 MockWrite("GET /p/q/t HTTP/1.1\r\n"
4082 "Host: www.google.com\r\n"
4083 "Connection: keep-alive\r\n"
4084 "Authorization: Basic Zm9vMzpiYXIz\r\n\r\n"),
4085 };
4086
4087 // Sever accepts the authorization.
4088 MockRead data_reads3[] = {
4089 MockRead("HTTP/1.0 200 OK\r\n"),
4090 MockRead("Content-Length: 100\r\n\r\n"),
4091 MockRead(false, OK),
4092 };
4093
4094 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
4095 data_writes1, arraysize(data_writes1));
4096 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
4097 data_writes2, arraysize(data_writes2));
4098 StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3),
4099 data_writes3, arraysize(data_writes3));
4100 session_deps.socket_factory.AddSocketDataProvider(&data1);
4101 session_deps.socket_factory.AddSocketDataProvider(&data2);
4102 session_deps.socket_factory.AddSocketDataProvider(&data3);
4103
4104 TestCompletionCallback callback1;
4105
4106 int rv = trans->Start(&request, &callback1, BoundNetLog());
4107 EXPECT_EQ(ERR_IO_PENDING, rv);
4108
4109 rv = callback1.WaitForResult();
4110 EXPECT_EQ(OK, rv);
4111
4112 EXPECT_TRUE(trans->IsReadyToRestartForAuth());
4113 TestCompletionCallback callback2;
4114 rv = trans->RestartWithAuth(string16(), string16(), &callback2);
4115 EXPECT_EQ(ERR_IO_PENDING, rv);
4116 rv = callback2.WaitForResult();
4117 EXPECT_EQ(OK, rv);
4118 EXPECT_FALSE(trans->IsReadyToRestartForAuth());
4119
4120 const HttpResponseInfo* response = trans->GetResponseInfo();
4121 EXPECT_FALSE(response == NULL);
4122
4123 // The password prompt info should have been set in
4124 // response->auth_challenge.
4125 EXPECT_FALSE(response->auth_challenge.get() == NULL);
4126
4127 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
4128 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
4129 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
4130
4131 TestCompletionCallback callback3;
4132
4133 rv = trans->RestartWithAuth(kFoo3, kBar3, &callback3);
4134 EXPECT_EQ(ERR_IO_PENDING, rv);
4135
4136 rv = callback3.WaitForResult();
4137 EXPECT_EQ(OK, rv);
4138
4139 response = trans->GetResponseInfo();
4140 EXPECT_FALSE(response == NULL);
4141 EXPECT_TRUE(response->auth_challenge.get() == NULL);
4142 EXPECT_EQ(100, response->headers->GetContentLength());
4143 }
4144 }
4145
4146 // Tests that nonce count increments when multiple auth attempts
4147 // are started with the same nonce.
TEST_F(HttpNetworkTransactionTest,DigestPreAuthNonceCount)4148 TEST_F(HttpNetworkTransactionTest, DigestPreAuthNonceCount) {
4149 SessionDependencies session_deps;
4150 HttpAuthHandlerDigest::Factory* digest_factory =
4151 new HttpAuthHandlerDigest::Factory();
4152 HttpAuthHandlerDigest::FixedNonceGenerator* nonce_generator =
4153 new HttpAuthHandlerDigest::FixedNonceGenerator("0123456789abcdef");
4154 digest_factory->set_nonce_generator(nonce_generator);
4155 session_deps.http_auth_handler_factory.reset(digest_factory);
4156 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
4157
4158 // Transaction 1: authenticate (foo, bar) on MyRealm1
4159 {
4160 HttpRequestInfo request;
4161 request.method = "GET";
4162 request.url = GURL("http://www.google.com/x/y/z");
4163 request.load_flags = 0;
4164
4165 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
4166
4167 MockWrite data_writes1[] = {
4168 MockWrite("GET /x/y/z HTTP/1.1\r\n"
4169 "Host: www.google.com\r\n"
4170 "Connection: keep-alive\r\n\r\n"),
4171 };
4172
4173 MockRead data_reads1[] = {
4174 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
4175 MockRead("WWW-Authenticate: Digest realm=\"digestive\", nonce=\"OU812\", "
4176 "algorithm=MD5, qop=\"auth\"\r\n\r\n"),
4177 MockRead(false, OK),
4178 };
4179
4180 // Resend with authorization (username=foo, password=bar)
4181 MockWrite data_writes2[] = {
4182 MockWrite("GET /x/y/z HTTP/1.1\r\n"
4183 "Host: www.google.com\r\n"
4184 "Connection: keep-alive\r\n"
4185 "Authorization: Digest username=\"foo\", realm=\"digestive\", "
4186 "nonce=\"OU812\", uri=\"/x/y/z\", algorithm=MD5, "
4187 "response=\"03ffbcd30add722589c1de345d7a927f\", qop=auth, "
4188 "nc=00000001, cnonce=\"0123456789abcdef\"\r\n\r\n"),
4189 };
4190
4191 // Sever accepts the authorization.
4192 MockRead data_reads2[] = {
4193 MockRead("HTTP/1.0 200 OK\r\n"),
4194 MockRead(false, OK),
4195 };
4196
4197 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
4198 data_writes1, arraysize(data_writes1));
4199 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
4200 data_writes2, arraysize(data_writes2));
4201 session_deps.socket_factory.AddSocketDataProvider(&data1);
4202 session_deps.socket_factory.AddSocketDataProvider(&data2);
4203
4204 TestCompletionCallback callback1;
4205
4206 int rv = trans->Start(&request, &callback1, BoundNetLog());
4207 EXPECT_EQ(ERR_IO_PENDING, rv);
4208
4209 rv = callback1.WaitForResult();
4210 EXPECT_EQ(OK, rv);
4211
4212 const HttpResponseInfo* response = trans->GetResponseInfo();
4213 ASSERT_FALSE(response == NULL);
4214
4215 // The password prompt info should have been set in
4216 // response->auth_challenge.
4217 ASSERT_FALSE(response->auth_challenge.get() == NULL);
4218
4219 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
4220 EXPECT_EQ(L"digestive", response->auth_challenge->realm);
4221 EXPECT_EQ(L"digest", response->auth_challenge->scheme);
4222
4223 TestCompletionCallback callback2;
4224
4225 rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
4226 EXPECT_EQ(ERR_IO_PENDING, rv);
4227
4228 rv = callback2.WaitForResult();
4229 EXPECT_EQ(OK, rv);
4230
4231 response = trans->GetResponseInfo();
4232 ASSERT_FALSE(response == NULL);
4233 EXPECT_TRUE(response->auth_challenge.get() == NULL);
4234 }
4235
4236 // ------------------------------------------------------------------------
4237
4238 // Transaction 2: Request another resource in digestive's protection space.
4239 // This will preemptively add an Authorization header which should have an
4240 // "nc" value of 2 (as compared to 1 in the first use.
4241 {
4242 HttpRequestInfo request;
4243 request.method = "GET";
4244 // Note that Transaction 1 was at /x/y/z, so this is in the same
4245 // protection space as digest.
4246 request.url = GURL("http://www.google.com/x/y/a/b");
4247 request.load_flags = 0;
4248
4249 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
4250
4251 MockWrite data_writes1[] = {
4252 MockWrite("GET /x/y/a/b HTTP/1.1\r\n"
4253 "Host: www.google.com\r\n"
4254 "Connection: keep-alive\r\n"
4255 "Authorization: Digest username=\"foo\", realm=\"digestive\", "
4256 "nonce=\"OU812\", uri=\"/x/y/a/b\", algorithm=MD5, "
4257 "response=\"d6f9a2c07d1c5df7b89379dca1269b35\", qop=auth, "
4258 "nc=00000002, cnonce=\"0123456789abcdef\"\r\n\r\n"),
4259 };
4260
4261 // Sever accepts the authorization.
4262 MockRead data_reads1[] = {
4263 MockRead("HTTP/1.0 200 OK\r\n"),
4264 MockRead("Content-Length: 100\r\n\r\n"),
4265 MockRead(false, OK),
4266 };
4267
4268 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
4269 data_writes1, arraysize(data_writes1));
4270 session_deps.socket_factory.AddSocketDataProvider(&data1);
4271
4272 TestCompletionCallback callback1;
4273
4274 int rv = trans->Start(&request, &callback1, BoundNetLog());
4275 EXPECT_EQ(ERR_IO_PENDING, rv);
4276
4277 rv = callback1.WaitForResult();
4278 EXPECT_EQ(OK, rv);
4279
4280 const HttpResponseInfo* response = trans->GetResponseInfo();
4281 ASSERT_FALSE(response == NULL);
4282 EXPECT_TRUE(response->auth_challenge.get() == NULL);
4283 }
4284 }
4285
4286 // Test the ResetStateForRestart() private method.
TEST_F(HttpNetworkTransactionTest,ResetStateForRestart)4287 TEST_F(HttpNetworkTransactionTest, ResetStateForRestart) {
4288 // Create a transaction (the dependencies aren't important).
4289 SessionDependencies session_deps;
4290 scoped_ptr<HttpNetworkTransaction> trans(
4291 new HttpNetworkTransaction(CreateSession(&session_deps)));
4292
4293 // Setup some state (which we expect ResetStateForRestart() will clear).
4294 trans->read_buf_ = new IOBuffer(15);
4295 trans->read_buf_len_ = 15;
4296 trans->request_headers_.SetHeader("Authorization", "NTLM");
4297
4298 // Setup state in response_
4299 HttpResponseInfo* response = &trans->response_;
4300 response->auth_challenge = new AuthChallengeInfo();
4301 response->ssl_info.cert_status = -15;
4302 response->response_time = base::Time::Now();
4303 response->was_cached = true; // (Wouldn't ever actually be true...)
4304
4305 { // Setup state for response_.vary_data
4306 HttpRequestInfo request;
4307 std::string temp("HTTP/1.1 200 OK\nVary: foo, bar\n\n");
4308 std::replace(temp.begin(), temp.end(), '\n', '\0');
4309 scoped_refptr<HttpResponseHeaders> headers(new HttpResponseHeaders(temp));
4310 request.extra_headers.SetHeader("Foo", "1");
4311 request.extra_headers.SetHeader("bar", "23");
4312 EXPECT_TRUE(response->vary_data.Init(request, *headers));
4313 }
4314
4315 // Cause the above state to be reset.
4316 trans->ResetStateForRestart();
4317
4318 // Verify that the state that needed to be reset, has been reset.
4319 EXPECT_TRUE(trans->read_buf_.get() == NULL);
4320 EXPECT_EQ(0, trans->read_buf_len_);
4321 EXPECT_TRUE(trans->request_headers_.IsEmpty());
4322 EXPECT_TRUE(response->auth_challenge.get() == NULL);
4323 EXPECT_TRUE(response->headers.get() == NULL);
4324 EXPECT_FALSE(response->was_cached);
4325 EXPECT_EQ(0, response->ssl_info.cert_status);
4326 EXPECT_FALSE(response->vary_data.is_valid());
4327 }
4328
4329 // Test HTTPS connections to a site with a bad certificate
TEST_F(HttpNetworkTransactionTest,HTTPSBadCertificate)4330 TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificate) {
4331 HttpRequestInfo request;
4332 request.method = "GET";
4333 request.url = GURL("https://www.google.com/");
4334 request.load_flags = 0;
4335
4336 SessionDependencies session_deps;
4337 scoped_ptr<HttpTransaction> trans(
4338 new HttpNetworkTransaction(CreateSession(&session_deps)));
4339
4340 MockWrite data_writes[] = {
4341 MockWrite("GET / HTTP/1.1\r\n"
4342 "Host: www.google.com\r\n"
4343 "Connection: keep-alive\r\n\r\n"),
4344 };
4345
4346 MockRead data_reads[] = {
4347 MockRead("HTTP/1.0 200 OK\r\n"),
4348 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
4349 MockRead("Content-Length: 100\r\n\r\n"),
4350 MockRead(false, OK),
4351 };
4352
4353 StaticSocketDataProvider ssl_bad_certificate;
4354 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
4355 data_writes, arraysize(data_writes));
4356 SSLSocketDataProvider ssl_bad(true, ERR_CERT_AUTHORITY_INVALID);
4357 SSLSocketDataProvider ssl(true, OK);
4358
4359 session_deps.socket_factory.AddSocketDataProvider(&ssl_bad_certificate);
4360 session_deps.socket_factory.AddSocketDataProvider(&data);
4361 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_bad);
4362 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
4363
4364 TestCompletionCallback callback;
4365
4366 int rv = trans->Start(&request, &callback, BoundNetLog());
4367 EXPECT_EQ(ERR_IO_PENDING, rv);
4368
4369 rv = callback.WaitForResult();
4370 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv);
4371
4372 rv = trans->RestartIgnoringLastError(&callback);
4373 EXPECT_EQ(ERR_IO_PENDING, rv);
4374
4375 rv = callback.WaitForResult();
4376 EXPECT_EQ(OK, rv);
4377
4378 const HttpResponseInfo* response = trans->GetResponseInfo();
4379
4380 EXPECT_FALSE(response == NULL);
4381 EXPECT_EQ(100, response->headers->GetContentLength());
4382 }
4383
4384 // Test HTTPS connections to a site with a bad certificate, going through a
4385 // proxy
TEST_F(HttpNetworkTransactionTest,HTTPSBadCertificateViaProxy)4386 TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificateViaProxy) {
4387 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70"));
4388
4389 HttpRequestInfo request;
4390 request.method = "GET";
4391 request.url = GURL("https://www.google.com/");
4392 request.load_flags = 0;
4393
4394 MockWrite proxy_writes[] = {
4395 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
4396 "Host: www.google.com\r\n"
4397 "Proxy-Connection: keep-alive\r\n\r\n"),
4398 };
4399
4400 MockRead proxy_reads[] = {
4401 MockRead("HTTP/1.0 200 Connected\r\n\r\n"),
4402 MockRead(false, OK)
4403 };
4404
4405 MockWrite data_writes[] = {
4406 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
4407 "Host: www.google.com\r\n"
4408 "Proxy-Connection: keep-alive\r\n\r\n"),
4409 MockWrite("GET / HTTP/1.1\r\n"
4410 "Host: www.google.com\r\n"
4411 "Connection: keep-alive\r\n\r\n"),
4412 };
4413
4414 MockRead data_reads[] = {
4415 MockRead("HTTP/1.0 200 Connected\r\n\r\n"),
4416 MockRead("HTTP/1.0 200 OK\r\n"),
4417 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
4418 MockRead("Content-Length: 100\r\n\r\n"),
4419 MockRead(false, OK),
4420 };
4421
4422 StaticSocketDataProvider ssl_bad_certificate(
4423 proxy_reads, arraysize(proxy_reads),
4424 proxy_writes, arraysize(proxy_writes));
4425 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
4426 data_writes, arraysize(data_writes));
4427 SSLSocketDataProvider ssl_bad(true, ERR_CERT_AUTHORITY_INVALID);
4428 SSLSocketDataProvider ssl(true, OK);
4429
4430 session_deps.socket_factory.AddSocketDataProvider(&ssl_bad_certificate);
4431 session_deps.socket_factory.AddSocketDataProvider(&data);
4432 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_bad);
4433 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
4434
4435 TestCompletionCallback callback;
4436
4437 for (int i = 0; i < 2; i++) {
4438 session_deps.socket_factory.ResetNextMockIndexes();
4439
4440 scoped_ptr<HttpTransaction> trans(
4441 new HttpNetworkTransaction(CreateSession(&session_deps)));
4442
4443 int rv = trans->Start(&request, &callback, BoundNetLog());
4444 EXPECT_EQ(ERR_IO_PENDING, rv);
4445
4446 rv = callback.WaitForResult();
4447 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv);
4448
4449 rv = trans->RestartIgnoringLastError(&callback);
4450 EXPECT_EQ(ERR_IO_PENDING, rv);
4451
4452 rv = callback.WaitForResult();
4453 EXPECT_EQ(OK, rv);
4454
4455 const HttpResponseInfo* response = trans->GetResponseInfo();
4456
4457 EXPECT_FALSE(response == NULL);
4458 EXPECT_EQ(100, response->headers->GetContentLength());
4459 }
4460 }
4461
4462
4463 // Test HTTPS connections to a site, going through an HTTPS proxy
TEST_F(HttpNetworkTransactionTest,HTTPSViaHttpsProxy)4464 TEST_F(HttpNetworkTransactionTest, HTTPSViaHttpsProxy) {
4465 SessionDependencies session_deps(ProxyService::CreateFixed("https://proxy:70"));
4466
4467 HttpRequestInfo request;
4468 request.method = "GET";
4469 request.url = GURL("https://www.google.com/");
4470 request.load_flags = 0;
4471
4472 MockWrite data_writes[] = {
4473 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
4474 "Host: www.google.com\r\n"
4475 "Proxy-Connection: keep-alive\r\n\r\n"),
4476 MockWrite("GET / HTTP/1.1\r\n"
4477 "Host: www.google.com\r\n"
4478 "Connection: keep-alive\r\n\r\n"),
4479 };
4480
4481 MockRead data_reads[] = {
4482 MockRead("HTTP/1.0 200 Connected\r\n\r\n"),
4483 MockRead("HTTP/1.1 200 OK\r\n"),
4484 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
4485 MockRead("Content-Length: 100\r\n\r\n"),
4486 MockRead(false, OK),
4487 };
4488
4489 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
4490 data_writes, arraysize(data_writes));
4491 SSLSocketDataProvider proxy_ssl(true, OK); // SSL to the proxy
4492 SSLSocketDataProvider tunnel_ssl(true, OK); // SSL through the tunnel
4493
4494 session_deps.socket_factory.AddSocketDataProvider(&data);
4495 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl);
4496 session_deps.socket_factory.AddSSLSocketDataProvider(&tunnel_ssl);
4497
4498 TestCompletionCallback callback;
4499
4500 scoped_ptr<HttpTransaction> trans(
4501 new HttpNetworkTransaction(CreateSession(&session_deps)));
4502
4503 int rv = trans->Start(&request, &callback, BoundNetLog());
4504 EXPECT_EQ(ERR_IO_PENDING, rv);
4505
4506 rv = callback.WaitForResult();
4507 EXPECT_EQ(OK, rv);
4508 const HttpResponseInfo* response = trans->GetResponseInfo();
4509
4510 ASSERT_FALSE(response == NULL);
4511
4512 EXPECT_TRUE(response->headers->IsKeepAlive());
4513 EXPECT_EQ(200, response->headers->response_code());
4514 EXPECT_EQ(100, response->headers->GetContentLength());
4515 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
4516 }
4517
4518 // Test an HTTPS Proxy's ability to redirect a CONNECT request
TEST_F(HttpNetworkTransactionTest,RedirectOfHttpsConnectViaHttpsProxy)4519 TEST_F(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaHttpsProxy) {
4520 SessionDependencies session_deps(
4521 ProxyService::CreateFixed("https://proxy:70"));
4522
4523 HttpRequestInfo request;
4524 request.method = "GET";
4525 request.url = GURL("https://www.google.com/");
4526 request.load_flags = 0;
4527
4528 MockWrite data_writes[] = {
4529 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
4530 "Host: www.google.com\r\n"
4531 "Proxy-Connection: keep-alive\r\n\r\n"),
4532 };
4533
4534 MockRead data_reads[] = {
4535 MockRead("HTTP/1.1 302 Redirect\r\n"),
4536 MockRead("Location: http://login.example.com/\r\n"),
4537 MockRead("Content-Length: 0\r\n\r\n"),
4538 MockRead(false, OK),
4539 };
4540
4541 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
4542 data_writes, arraysize(data_writes));
4543 SSLSocketDataProvider proxy_ssl(true, OK); // SSL to the proxy
4544
4545 session_deps.socket_factory.AddSocketDataProvider(&data);
4546 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl);
4547
4548 TestCompletionCallback callback;
4549
4550 scoped_ptr<HttpTransaction> trans(
4551 new HttpNetworkTransaction(CreateSession(&session_deps)));
4552
4553 int rv = trans->Start(&request, &callback, BoundNetLog());
4554 EXPECT_EQ(ERR_IO_PENDING, rv);
4555
4556 rv = callback.WaitForResult();
4557 EXPECT_EQ(OK, rv);
4558 const HttpResponseInfo* response = trans->GetResponseInfo();
4559
4560 ASSERT_FALSE(response == NULL);
4561
4562 EXPECT_EQ(302, response->headers->response_code());
4563 std::string url;
4564 EXPECT_TRUE(response->headers->IsRedirect(&url));
4565 EXPECT_EQ("http://login.example.com/", url);
4566 }
4567
4568 // Test an HTTPS (SPDY) Proxy's ability to redirect a CONNECT request
TEST_F(HttpNetworkTransactionTest,RedirectOfHttpsConnectViaSpdyProxy)4569 TEST_F(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaSpdyProxy) {
4570 SessionDependencies session_deps(
4571 ProxyService::CreateFixed("https://proxy:70"));
4572
4573 HttpRequestInfo request;
4574 request.method = "GET";
4575 request.url = GURL("https://www.google.com/");
4576 request.load_flags = 0;
4577
4578 scoped_ptr<spdy::SpdyFrame> conn(ConstructSpdyConnect(NULL, 0, 1));
4579 scoped_ptr<spdy::SpdyFrame> goaway(ConstructSpdyRstStream(1, spdy::CANCEL));
4580 MockWrite data_writes[] = {
4581 CreateMockWrite(*conn.get(), 0, false),
4582 };
4583
4584 static const char* const kExtraHeaders[] = {
4585 "location",
4586 "http://login.example.com/",
4587 };
4588 scoped_ptr<spdy::SpdyFrame> resp(
4589 ConstructSpdySynReplyError("302 Redirect", kExtraHeaders,
4590 arraysize(kExtraHeaders)/2, 1));
4591 MockRead data_reads[] = {
4592 CreateMockRead(*resp.get(), 1, false),
4593 MockRead(true, 0, 2), // EOF
4594 };
4595
4596 scoped_refptr<DelayedSocketData> data(
4597 new DelayedSocketData(
4598 1, // wait for one write to finish before reading.
4599 data_reads, arraysize(data_reads),
4600 data_writes, arraysize(data_writes)));
4601 SSLSocketDataProvider proxy_ssl(true, OK); // SSL to the proxy
4602 proxy_ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
4603 proxy_ssl.next_proto = "spdy/2";
4604 proxy_ssl.was_npn_negotiated = true;
4605
4606 session_deps.socket_factory.AddSocketDataProvider(data.get());
4607 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl);
4608
4609 TestCompletionCallback callback;
4610
4611 scoped_ptr<HttpTransaction> trans(
4612 new HttpNetworkTransaction(CreateSession(&session_deps)));
4613
4614 int rv = trans->Start(&request, &callback, BoundNetLog());
4615 EXPECT_EQ(ERR_IO_PENDING, rv);
4616
4617 rv = callback.WaitForResult();
4618 EXPECT_EQ(OK, rv);
4619 const HttpResponseInfo* response = trans->GetResponseInfo();
4620
4621 ASSERT_FALSE(response == NULL);
4622
4623 EXPECT_EQ(302, response->headers->response_code());
4624 std::string url;
4625 EXPECT_TRUE(response->headers->IsRedirect(&url));
4626 EXPECT_EQ("http://login.example.com/", url);
4627 }
4628
4629 // Test an HTTPS Proxy's ability to provide a response to a CONNECT request
TEST_F(HttpNetworkTransactionTest,ErrorResponseTofHttpsConnectViaHttpsProxy)4630 TEST_F(HttpNetworkTransactionTest, ErrorResponseTofHttpsConnectViaHttpsProxy) {
4631 SessionDependencies session_deps(
4632 ProxyService::CreateFixed("https://proxy:70"));
4633
4634 HttpRequestInfo request;
4635 request.method = "GET";
4636 request.url = GURL("https://www.google.com/");
4637 request.load_flags = 0;
4638
4639 MockWrite data_writes[] = {
4640 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
4641 "Host: www.google.com\r\n"
4642 "Proxy-Connection: keep-alive\r\n\r\n"),
4643 };
4644
4645 MockRead data_reads[] = {
4646 MockRead("HTTP/1.1 404 Not Found\r\n"),
4647 MockRead("Content-Length: 23\r\n\r\n"),
4648 MockRead("The host does not exist"),
4649 MockRead(false, OK),
4650 };
4651
4652 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
4653 data_writes, arraysize(data_writes));
4654 SSLSocketDataProvider proxy_ssl(true, OK); // SSL to the proxy
4655
4656 session_deps.socket_factory.AddSocketDataProvider(&data);
4657 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl);
4658
4659 TestCompletionCallback callback;
4660
4661 scoped_ptr<HttpTransaction> trans(
4662 new HttpNetworkTransaction(CreateSession(&session_deps)));
4663
4664 int rv = trans->Start(&request, &callback, BoundNetLog());
4665 EXPECT_EQ(ERR_IO_PENDING, rv);
4666
4667 rv = callback.WaitForResult();
4668 EXPECT_EQ(OK, rv);
4669 const HttpResponseInfo* response = trans->GetResponseInfo();
4670
4671 ASSERT_FALSE(response == NULL);
4672
4673 EXPECT_EQ(404, response->headers->response_code());
4674 EXPECT_EQ(23, response->headers->GetContentLength());
4675 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
4676 EXPECT_FALSE(response->ssl_info.is_valid());
4677
4678 std::string response_data;
4679 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
4680 EXPECT_EQ("The host does not exist", response_data);
4681 }
4682
4683 // Test an HTTPS (SPDY) Proxy's ability to provide a response to a CONNECT
4684 // request
TEST_F(HttpNetworkTransactionTest,ErrorResponseTofHttpsConnectViaSpdyProxy)4685 TEST_F(HttpNetworkTransactionTest, ErrorResponseTofHttpsConnectViaSpdyProxy) {
4686 SessionDependencies session_deps(
4687 ProxyService::CreateFixed("https://proxy:70"));
4688
4689 HttpRequestInfo request;
4690 request.method = "GET";
4691 request.url = GURL("https://www.google.com/");
4692 request.load_flags = 0;
4693
4694 scoped_ptr<spdy::SpdyFrame> conn(ConstructSpdyConnect(NULL, 0, 1));
4695 scoped_ptr<spdy::SpdyFrame> goaway(ConstructSpdyRstStream(1, spdy::CANCEL));
4696 MockWrite data_writes[] = {
4697 CreateMockWrite(*conn.get(), 0, false),
4698 };
4699
4700 static const char* const kExtraHeaders[] = {
4701 "location",
4702 "http://login.example.com/",
4703 };
4704 scoped_ptr<spdy::SpdyFrame> resp(
4705 ConstructSpdySynReplyError("404 Not Found", kExtraHeaders,
4706 arraysize(kExtraHeaders)/2, 1));
4707 scoped_ptr<spdy::SpdyFrame> body(
4708 ConstructSpdyBodyFrame(1, "The host does not exist", 23, true));
4709 MockRead data_reads[] = {
4710 CreateMockRead(*resp.get(), 1, false),
4711 CreateMockRead(*body.get(), 2, false),
4712 MockRead(true, 0, 3), // EOF
4713 };
4714
4715 scoped_refptr<DelayedSocketData> data(
4716 new DelayedSocketData(
4717 1, // wait for one write to finish before reading.
4718 data_reads, arraysize(data_reads),
4719 data_writes, arraysize(data_writes)));
4720 SSLSocketDataProvider proxy_ssl(true, OK); // SSL to the proxy
4721 proxy_ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
4722 proxy_ssl.next_proto = "spdy/2";
4723 proxy_ssl.was_npn_negotiated = true;
4724
4725 session_deps.socket_factory.AddSocketDataProvider(data.get());
4726 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl);
4727
4728 TestCompletionCallback callback;
4729
4730 scoped_ptr<HttpTransaction> trans(
4731 new HttpNetworkTransaction(CreateSession(&session_deps)));
4732
4733 int rv = trans->Start(&request, &callback, BoundNetLog());
4734 EXPECT_EQ(ERR_IO_PENDING, rv);
4735
4736 rv = callback.WaitForResult();
4737 EXPECT_EQ(OK, rv);
4738 const HttpResponseInfo* response = trans->GetResponseInfo();
4739
4740 ASSERT_FALSE(response == NULL);
4741
4742 EXPECT_EQ(404, response->headers->response_code());
4743 EXPECT_FALSE(response->ssl_info.is_valid());
4744
4745 std::string response_data;
4746 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
4747 EXPECT_EQ("The host does not exist", response_data);
4748 }
4749
4750 // Test HTTPS connections to a site with a bad certificate, going through an
4751 // HTTPS proxy
TEST_F(HttpNetworkTransactionTest,HTTPSBadCertificateViaHttpsProxy)4752 TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificateViaHttpsProxy) {
4753 SessionDependencies session_deps(ProxyService::CreateFixed("https://proxy:70"));
4754
4755 HttpRequestInfo request;
4756 request.method = "GET";
4757 request.url = GURL("https://www.google.com/");
4758 request.load_flags = 0;
4759
4760 // Attempt to fetch the URL from a server with a bad cert
4761 MockWrite bad_cert_writes[] = {
4762 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
4763 "Host: www.google.com\r\n"
4764 "Proxy-Connection: keep-alive\r\n\r\n"),
4765 };
4766
4767 MockRead bad_cert_reads[] = {
4768 MockRead("HTTP/1.0 200 Connected\r\n\r\n"),
4769 MockRead(false, OK)
4770 };
4771
4772 // Attempt to fetch the URL with a good cert
4773 MockWrite good_data_writes[] = {
4774 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
4775 "Host: www.google.com\r\n"
4776 "Proxy-Connection: keep-alive\r\n\r\n"),
4777 MockWrite("GET / HTTP/1.1\r\n"
4778 "Host: www.google.com\r\n"
4779 "Connection: keep-alive\r\n\r\n"),
4780 };
4781
4782 MockRead good_cert_reads[] = {
4783 MockRead("HTTP/1.0 200 Connected\r\n\r\n"),
4784 MockRead("HTTP/1.0 200 OK\r\n"),
4785 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
4786 MockRead("Content-Length: 100\r\n\r\n"),
4787 MockRead(false, OK),
4788 };
4789
4790 StaticSocketDataProvider ssl_bad_certificate(
4791 bad_cert_reads, arraysize(bad_cert_reads),
4792 bad_cert_writes, arraysize(bad_cert_writes));
4793 StaticSocketDataProvider data(good_cert_reads, arraysize(good_cert_reads),
4794 good_data_writes, arraysize(good_data_writes));
4795 SSLSocketDataProvider ssl_bad(true, ERR_CERT_AUTHORITY_INVALID);
4796 SSLSocketDataProvider ssl(true, OK);
4797
4798 // SSL to the proxy, then CONNECT request, then SSL with bad certificate
4799 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
4800 session_deps.socket_factory.AddSocketDataProvider(&ssl_bad_certificate);
4801 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_bad);
4802
4803 // SSL to the proxy, then CONNECT request, then valid SSL certificate
4804 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
4805 session_deps.socket_factory.AddSocketDataProvider(&data);
4806 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
4807
4808 TestCompletionCallback callback;
4809
4810 scoped_ptr<HttpTransaction> trans(
4811 new HttpNetworkTransaction(CreateSession(&session_deps)));
4812
4813 int rv = trans->Start(&request, &callback, BoundNetLog());
4814 EXPECT_EQ(ERR_IO_PENDING, rv);
4815
4816 rv = callback.WaitForResult();
4817 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv);
4818
4819 rv = trans->RestartIgnoringLastError(&callback);
4820 EXPECT_EQ(ERR_IO_PENDING, rv);
4821
4822 rv = callback.WaitForResult();
4823 EXPECT_EQ(OK, rv);
4824
4825 const HttpResponseInfo* response = trans->GetResponseInfo();
4826
4827 EXPECT_FALSE(response == NULL);
4828 EXPECT_EQ(100, response->headers->GetContentLength());
4829 }
4830
TEST_F(HttpNetworkTransactionTest,BuildRequest_UserAgent)4831 TEST_F(HttpNetworkTransactionTest, BuildRequest_UserAgent) {
4832 HttpRequestInfo request;
4833 request.method = "GET";
4834 request.url = GURL("http://www.google.com/");
4835 request.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
4836 "Chromium Ultra Awesome X Edition");
4837
4838 SessionDependencies session_deps;
4839 scoped_ptr<HttpTransaction> trans(
4840 new HttpNetworkTransaction(CreateSession(&session_deps)));
4841
4842 MockWrite data_writes[] = {
4843 MockWrite("GET / HTTP/1.1\r\n"
4844 "Host: www.google.com\r\n"
4845 "Connection: keep-alive\r\n"
4846 "User-Agent: Chromium Ultra Awesome X Edition\r\n\r\n"),
4847 };
4848
4849 // Lastly, the server responds with the actual content.
4850 MockRead data_reads[] = {
4851 MockRead("HTTP/1.0 200 OK\r\n"),
4852 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
4853 MockRead("Content-Length: 100\r\n\r\n"),
4854 MockRead(false, OK),
4855 };
4856
4857 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
4858 data_writes, arraysize(data_writes));
4859 session_deps.socket_factory.AddSocketDataProvider(&data);
4860
4861 TestCompletionCallback callback;
4862
4863 int rv = trans->Start(&request, &callback, BoundNetLog());
4864 EXPECT_EQ(ERR_IO_PENDING, rv);
4865
4866 rv = callback.WaitForResult();
4867 EXPECT_EQ(OK, rv);
4868 }
4869
TEST_F(HttpNetworkTransactionTest,BuildRequest_UserAgentOverTunnel)4870 TEST_F(HttpNetworkTransactionTest, BuildRequest_UserAgentOverTunnel) {
4871 HttpRequestInfo request;
4872 request.method = "GET";
4873 request.url = GURL("https://www.google.com/");
4874 request.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
4875 "Chromium Ultra Awesome X Edition");
4876
4877 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70"));
4878 scoped_ptr<HttpTransaction> trans(
4879 new HttpNetworkTransaction(CreateSession(&session_deps)));
4880
4881 MockWrite data_writes[] = {
4882 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
4883 "Host: www.google.com\r\n"
4884 "Proxy-Connection: keep-alive\r\n"
4885 "User-Agent: Chromium Ultra Awesome X Edition\r\n\r\n"),
4886 };
4887 MockRead data_reads[] = {
4888 // Return an error, so the transaction stops here (this test isn't
4889 // interested in the rest).
4890 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
4891 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
4892 MockRead("Proxy-Connection: close\r\n\r\n"),
4893 };
4894
4895 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
4896 data_writes, arraysize(data_writes));
4897 session_deps.socket_factory.AddSocketDataProvider(&data);
4898
4899 TestCompletionCallback callback;
4900
4901 int rv = trans->Start(&request, &callback, BoundNetLog());
4902 EXPECT_EQ(ERR_IO_PENDING, rv);
4903
4904 rv = callback.WaitForResult();
4905 EXPECT_EQ(OK, rv);
4906 }
4907
TEST_F(HttpNetworkTransactionTest,BuildRequest_Referer)4908 TEST_F(HttpNetworkTransactionTest, BuildRequest_Referer) {
4909 HttpRequestInfo request;
4910 request.method = "GET";
4911 request.url = GURL("http://www.google.com/");
4912 request.load_flags = 0;
4913 request.referrer = GURL("http://the.previous.site.com/");
4914
4915 SessionDependencies session_deps;
4916 scoped_ptr<HttpTransaction> trans(
4917 new HttpNetworkTransaction(CreateSession(&session_deps)));
4918
4919 MockWrite data_writes[] = {
4920 MockWrite("GET / HTTP/1.1\r\n"
4921 "Host: www.google.com\r\n"
4922 "Connection: keep-alive\r\n"
4923 "Referer: http://the.previous.site.com/\r\n\r\n"),
4924 };
4925
4926 // Lastly, the server responds with the actual content.
4927 MockRead data_reads[] = {
4928 MockRead("HTTP/1.0 200 OK\r\n"),
4929 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
4930 MockRead("Content-Length: 100\r\n\r\n"),
4931 MockRead(false, OK),
4932 };
4933
4934 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
4935 data_writes, arraysize(data_writes));
4936 session_deps.socket_factory.AddSocketDataProvider(&data);
4937
4938 TestCompletionCallback callback;
4939
4940 int rv = trans->Start(&request, &callback, BoundNetLog());
4941 EXPECT_EQ(ERR_IO_PENDING, rv);
4942
4943 rv = callback.WaitForResult();
4944 EXPECT_EQ(OK, rv);
4945 }
4946
TEST_F(HttpNetworkTransactionTest,BuildRequest_PostContentLengthZero)4947 TEST_F(HttpNetworkTransactionTest, BuildRequest_PostContentLengthZero) {
4948 HttpRequestInfo request;
4949 request.method = "POST";
4950 request.url = GURL("http://www.google.com/");
4951
4952 SessionDependencies session_deps;
4953 scoped_ptr<HttpTransaction> trans(
4954 new HttpNetworkTransaction(CreateSession(&session_deps)));
4955
4956 MockWrite data_writes[] = {
4957 MockWrite("POST / HTTP/1.1\r\n"
4958 "Host: www.google.com\r\n"
4959 "Connection: keep-alive\r\n"
4960 "Content-Length: 0\r\n\r\n"),
4961 };
4962
4963 // Lastly, the server responds with the actual content.
4964 MockRead data_reads[] = {
4965 MockRead("HTTP/1.0 200 OK\r\n"),
4966 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
4967 MockRead("Content-Length: 100\r\n\r\n"),
4968 MockRead(false, OK),
4969 };
4970
4971 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
4972 data_writes, arraysize(data_writes));
4973 session_deps.socket_factory.AddSocketDataProvider(&data);
4974
4975 TestCompletionCallback callback;
4976
4977 int rv = trans->Start(&request, &callback, BoundNetLog());
4978 EXPECT_EQ(ERR_IO_PENDING, rv);
4979
4980 rv = callback.WaitForResult();
4981 EXPECT_EQ(OK, rv);
4982 }
4983
TEST_F(HttpNetworkTransactionTest,BuildRequest_PutContentLengthZero)4984 TEST_F(HttpNetworkTransactionTest, BuildRequest_PutContentLengthZero) {
4985 HttpRequestInfo request;
4986 request.method = "PUT";
4987 request.url = GURL("http://www.google.com/");
4988
4989 SessionDependencies session_deps;
4990 scoped_ptr<HttpTransaction> trans(
4991 new HttpNetworkTransaction(CreateSession(&session_deps)));
4992
4993 MockWrite data_writes[] = {
4994 MockWrite("PUT / HTTP/1.1\r\n"
4995 "Host: www.google.com\r\n"
4996 "Connection: keep-alive\r\n"
4997 "Content-Length: 0\r\n\r\n"),
4998 };
4999
5000 // Lastly, the server responds with the actual content.
5001 MockRead data_reads[] = {
5002 MockRead("HTTP/1.0 200 OK\r\n"),
5003 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
5004 MockRead("Content-Length: 100\r\n\r\n"),
5005 MockRead(false, OK),
5006 };
5007
5008 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
5009 data_writes, arraysize(data_writes));
5010 session_deps.socket_factory.AddSocketDataProvider(&data);
5011
5012 TestCompletionCallback callback;
5013
5014 int rv = trans->Start(&request, &callback, BoundNetLog());
5015 EXPECT_EQ(ERR_IO_PENDING, rv);
5016
5017 rv = callback.WaitForResult();
5018 EXPECT_EQ(OK, rv);
5019 }
5020
TEST_F(HttpNetworkTransactionTest,BuildRequest_HeadContentLengthZero)5021 TEST_F(HttpNetworkTransactionTest, BuildRequest_HeadContentLengthZero) {
5022 HttpRequestInfo request;
5023 request.method = "HEAD";
5024 request.url = GURL("http://www.google.com/");
5025
5026 SessionDependencies session_deps;
5027 scoped_ptr<HttpTransaction> trans(
5028 new HttpNetworkTransaction(CreateSession(&session_deps)));
5029
5030 MockWrite data_writes[] = {
5031 MockWrite("HEAD / HTTP/1.1\r\n"
5032 "Host: www.google.com\r\n"
5033 "Connection: keep-alive\r\n"
5034 "Content-Length: 0\r\n\r\n"),
5035 };
5036
5037 // Lastly, the server responds with the actual content.
5038 MockRead data_reads[] = {
5039 MockRead("HTTP/1.0 200 OK\r\n"),
5040 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
5041 MockRead("Content-Length: 100\r\n\r\n"),
5042 MockRead(false, OK),
5043 };
5044
5045 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
5046 data_writes, arraysize(data_writes));
5047 session_deps.socket_factory.AddSocketDataProvider(&data);
5048
5049 TestCompletionCallback callback;
5050
5051 int rv = trans->Start(&request, &callback, BoundNetLog());
5052 EXPECT_EQ(ERR_IO_PENDING, rv);
5053
5054 rv = callback.WaitForResult();
5055 EXPECT_EQ(OK, rv);
5056 }
5057
TEST_F(HttpNetworkTransactionTest,BuildRequest_CacheControlNoCache)5058 TEST_F(HttpNetworkTransactionTest, BuildRequest_CacheControlNoCache) {
5059 HttpRequestInfo request;
5060 request.method = "GET";
5061 request.url = GURL("http://www.google.com/");
5062 request.load_flags = LOAD_BYPASS_CACHE;
5063
5064 SessionDependencies session_deps;
5065 scoped_ptr<HttpTransaction> trans(
5066 new HttpNetworkTransaction(CreateSession(&session_deps)));
5067
5068 MockWrite data_writes[] = {
5069 MockWrite("GET / HTTP/1.1\r\n"
5070 "Host: www.google.com\r\n"
5071 "Connection: keep-alive\r\n"
5072 "Pragma: no-cache\r\n"
5073 "Cache-Control: no-cache\r\n\r\n"),
5074 };
5075
5076 // Lastly, the server responds with the actual content.
5077 MockRead data_reads[] = {
5078 MockRead("HTTP/1.0 200 OK\r\n"),
5079 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
5080 MockRead("Content-Length: 100\r\n\r\n"),
5081 MockRead(false, OK),
5082 };
5083
5084 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
5085 data_writes, arraysize(data_writes));
5086 session_deps.socket_factory.AddSocketDataProvider(&data);
5087
5088 TestCompletionCallback callback;
5089
5090 int rv = trans->Start(&request, &callback, BoundNetLog());
5091 EXPECT_EQ(ERR_IO_PENDING, rv);
5092
5093 rv = callback.WaitForResult();
5094 EXPECT_EQ(OK, rv);
5095 }
5096
TEST_F(HttpNetworkTransactionTest,BuildRequest_CacheControlValidateCache)5097 TEST_F(HttpNetworkTransactionTest,
5098 BuildRequest_CacheControlValidateCache) {
5099 HttpRequestInfo request;
5100 request.method = "GET";
5101 request.url = GURL("http://www.google.com/");
5102 request.load_flags = LOAD_VALIDATE_CACHE;
5103
5104 SessionDependencies session_deps;
5105 scoped_ptr<HttpTransaction> trans(
5106 new HttpNetworkTransaction(CreateSession(&session_deps)));
5107
5108 MockWrite data_writes[] = {
5109 MockWrite("GET / HTTP/1.1\r\n"
5110 "Host: www.google.com\r\n"
5111 "Connection: keep-alive\r\n"
5112 "Cache-Control: max-age=0\r\n\r\n"),
5113 };
5114
5115 // Lastly, the server responds with the actual content.
5116 MockRead data_reads[] = {
5117 MockRead("HTTP/1.0 200 OK\r\n"),
5118 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
5119 MockRead("Content-Length: 100\r\n\r\n"),
5120 MockRead(false, OK),
5121 };
5122
5123 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
5124 data_writes, arraysize(data_writes));
5125 session_deps.socket_factory.AddSocketDataProvider(&data);
5126
5127 TestCompletionCallback callback;
5128
5129 int rv = trans->Start(&request, &callback, BoundNetLog());
5130 EXPECT_EQ(ERR_IO_PENDING, rv);
5131
5132 rv = callback.WaitForResult();
5133 EXPECT_EQ(OK, rv);
5134 }
5135
TEST_F(HttpNetworkTransactionTest,BuildRequest_ExtraHeaders)5136 TEST_F(HttpNetworkTransactionTest, BuildRequest_ExtraHeaders) {
5137 HttpRequestInfo request;
5138 request.method = "GET";
5139 request.url = GURL("http://www.google.com/");
5140 request.extra_headers.SetHeader("FooHeader", "Bar");
5141
5142 SessionDependencies session_deps;
5143 scoped_ptr<HttpTransaction> trans(
5144 new HttpNetworkTransaction(CreateSession(&session_deps)));
5145
5146 MockWrite data_writes[] = {
5147 MockWrite("GET / HTTP/1.1\r\n"
5148 "Host: www.google.com\r\n"
5149 "Connection: keep-alive\r\n"
5150 "FooHeader: Bar\r\n\r\n"),
5151 };
5152
5153 // Lastly, the server responds with the actual content.
5154 MockRead data_reads[] = {
5155 MockRead("HTTP/1.0 200 OK\r\n"),
5156 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
5157 MockRead("Content-Length: 100\r\n\r\n"),
5158 MockRead(false, OK),
5159 };
5160
5161 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
5162 data_writes, arraysize(data_writes));
5163 session_deps.socket_factory.AddSocketDataProvider(&data);
5164
5165 TestCompletionCallback callback;
5166
5167 int rv = trans->Start(&request, &callback, BoundNetLog());
5168 EXPECT_EQ(ERR_IO_PENDING, rv);
5169
5170 rv = callback.WaitForResult();
5171 EXPECT_EQ(OK, rv);
5172 }
5173
TEST_F(HttpNetworkTransactionTest,BuildRequest_ExtraHeadersStripped)5174 TEST_F(HttpNetworkTransactionTest, BuildRequest_ExtraHeadersStripped) {
5175 HttpRequestInfo request;
5176 request.method = "GET";
5177 request.url = GURL("http://www.google.com/");
5178 request.extra_headers.SetHeader("referer", "www.foo.com");
5179 request.extra_headers.SetHeader("hEllo", "Kitty");
5180 request.extra_headers.SetHeader("FoO", "bar");
5181
5182 SessionDependencies session_deps;
5183 scoped_ptr<HttpTransaction> trans(
5184 new HttpNetworkTransaction(CreateSession(&session_deps)));
5185
5186 MockWrite data_writes[] = {
5187 MockWrite("GET / HTTP/1.1\r\n"
5188 "Host: www.google.com\r\n"
5189 "Connection: keep-alive\r\n"
5190 "hEllo: Kitty\r\n"
5191 "FoO: bar\r\n\r\n"),
5192 };
5193
5194 // Lastly, the server responds with the actual content.
5195 MockRead data_reads[] = {
5196 MockRead("HTTP/1.0 200 OK\r\n"),
5197 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
5198 MockRead("Content-Length: 100\r\n\r\n"),
5199 MockRead(false, OK),
5200 };
5201
5202 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
5203 data_writes, arraysize(data_writes));
5204 session_deps.socket_factory.AddSocketDataProvider(&data);
5205
5206 TestCompletionCallback callback;
5207
5208 int rv = trans->Start(&request, &callback, BoundNetLog());
5209 EXPECT_EQ(ERR_IO_PENDING, rv);
5210
5211 rv = callback.WaitForResult();
5212 EXPECT_EQ(OK, rv);
5213 }
5214
TEST_F(HttpNetworkTransactionTest,SOCKS4_HTTP_GET)5215 TEST_F(HttpNetworkTransactionTest, SOCKS4_HTTP_GET) {
5216 HttpRequestInfo request;
5217 request.method = "GET";
5218 request.url = GURL("http://www.google.com/");
5219 request.load_flags = 0;
5220
5221 SessionDependencies session_deps(
5222 ProxyService::CreateFixed("socks4://myproxy:1080"));
5223
5224 scoped_ptr<HttpTransaction> trans(
5225 new HttpNetworkTransaction(CreateSession(&session_deps)));
5226
5227 char write_buffer[] = { 0x04, 0x01, 0x00, 0x50, 127, 0, 0, 1, 0 };
5228 char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 };
5229
5230 MockWrite data_writes[] = {
5231 MockWrite(true, write_buffer, arraysize(write_buffer)),
5232 MockWrite("GET / HTTP/1.1\r\n"
5233 "Host: www.google.com\r\n"
5234 "Connection: keep-alive\r\n\r\n")
5235 };
5236
5237 MockRead data_reads[] = {
5238 MockRead(true, read_buffer, arraysize(read_buffer)),
5239 MockRead("HTTP/1.0 200 OK\r\n"),
5240 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"),
5241 MockRead("Payload"),
5242 MockRead(false, OK)
5243 };
5244
5245 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
5246 data_writes, arraysize(data_writes));
5247 session_deps.socket_factory.AddSocketDataProvider(&data);
5248
5249 TestCompletionCallback callback;
5250
5251 int rv = trans->Start(&request, &callback, BoundNetLog());
5252 EXPECT_EQ(ERR_IO_PENDING, rv);
5253
5254 rv = callback.WaitForResult();
5255 EXPECT_EQ(OK, rv);
5256
5257 const HttpResponseInfo* response = trans->GetResponseInfo();
5258 EXPECT_FALSE(response == NULL);
5259
5260 std::string response_text;
5261 rv = ReadTransaction(trans.get(), &response_text);
5262 EXPECT_EQ(OK, rv);
5263 EXPECT_EQ("Payload", response_text);
5264 }
5265
TEST_F(HttpNetworkTransactionTest,SOCKS4_SSL_GET)5266 TEST_F(HttpNetworkTransactionTest, SOCKS4_SSL_GET) {
5267 HttpRequestInfo request;
5268 request.method = "GET";
5269 request.url = GURL("https://www.google.com/");
5270 request.load_flags = 0;
5271
5272 SessionDependencies session_deps(
5273 ProxyService::CreateFixed("socks4://myproxy:1080"));
5274
5275 scoped_ptr<HttpTransaction> trans(
5276 new HttpNetworkTransaction(CreateSession(&session_deps)));
5277
5278 unsigned char write_buffer[] = { 0x04, 0x01, 0x01, 0xBB, 127, 0, 0, 1, 0 };
5279 unsigned char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 };
5280
5281 MockWrite data_writes[] = {
5282 MockWrite(true, reinterpret_cast<char*>(write_buffer),
5283 arraysize(write_buffer)),
5284 MockWrite("GET / HTTP/1.1\r\n"
5285 "Host: www.google.com\r\n"
5286 "Connection: keep-alive\r\n\r\n")
5287 };
5288
5289 MockRead data_reads[] = {
5290 MockWrite(true, reinterpret_cast<char*>(read_buffer),
5291 arraysize(read_buffer)),
5292 MockRead("HTTP/1.0 200 OK\r\n"),
5293 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"),
5294 MockRead("Payload"),
5295 MockRead(false, OK)
5296 };
5297
5298 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
5299 data_writes, arraysize(data_writes));
5300 session_deps.socket_factory.AddSocketDataProvider(&data);
5301
5302 SSLSocketDataProvider ssl(true, OK);
5303 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
5304
5305 TestCompletionCallback callback;
5306
5307 int rv = trans->Start(&request, &callback, BoundNetLog());
5308 EXPECT_EQ(ERR_IO_PENDING, rv);
5309
5310 rv = callback.WaitForResult();
5311 EXPECT_EQ(OK, rv);
5312
5313 const HttpResponseInfo* response = trans->GetResponseInfo();
5314 EXPECT_FALSE(response == NULL);
5315
5316 std::string response_text;
5317 rv = ReadTransaction(trans.get(), &response_text);
5318 EXPECT_EQ(OK, rv);
5319 EXPECT_EQ("Payload", response_text);
5320 }
5321
TEST_F(HttpNetworkTransactionTest,SOCKS5_HTTP_GET)5322 TEST_F(HttpNetworkTransactionTest, SOCKS5_HTTP_GET) {
5323 HttpRequestInfo request;
5324 request.method = "GET";
5325 request.url = GURL("http://www.google.com/");
5326 request.load_flags = 0;
5327
5328 SessionDependencies session_deps(
5329 ProxyService::CreateFixed("socks5://myproxy:1080"));
5330
5331 scoped_ptr<HttpTransaction> trans(
5332 new HttpNetworkTransaction(CreateSession(&session_deps)));
5333
5334 const char kSOCKS5GreetRequest[] = { 0x05, 0x01, 0x00 };
5335 const char kSOCKS5GreetResponse[] = { 0x05, 0x00 };
5336 const char kSOCKS5OkRequest[] = {
5337 0x05, // Version
5338 0x01, // Command (CONNECT)
5339 0x00, // Reserved.
5340 0x03, // Address type (DOMAINNAME).
5341 0x0E, // Length of domain (14)
5342 // Domain string:
5343 'w', 'w', 'w', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o', 'm',
5344 0x00, 0x50, // 16-bit port (80)
5345 };
5346 const char kSOCKS5OkResponse[] =
5347 { 0x05, 0x00, 0x00, 0x01, 127, 0, 0, 1, 0x00, 0x50 };
5348
5349 MockWrite data_writes[] = {
5350 MockWrite(true, kSOCKS5GreetRequest, arraysize(kSOCKS5GreetRequest)),
5351 MockWrite(true, kSOCKS5OkRequest, arraysize(kSOCKS5OkRequest)),
5352 MockWrite("GET / HTTP/1.1\r\n"
5353 "Host: www.google.com\r\n"
5354 "Connection: keep-alive\r\n\r\n")
5355 };
5356
5357 MockRead data_reads[] = {
5358 MockWrite(true, kSOCKS5GreetResponse, arraysize(kSOCKS5GreetResponse)),
5359 MockWrite(true, kSOCKS5OkResponse, arraysize(kSOCKS5OkResponse)),
5360 MockRead("HTTP/1.0 200 OK\r\n"),
5361 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"),
5362 MockRead("Payload"),
5363 MockRead(false, OK)
5364 };
5365
5366 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
5367 data_writes, arraysize(data_writes));
5368 session_deps.socket_factory.AddSocketDataProvider(&data);
5369
5370 TestCompletionCallback callback;
5371
5372 int rv = trans->Start(&request, &callback, BoundNetLog());
5373 EXPECT_EQ(ERR_IO_PENDING, rv);
5374
5375 rv = callback.WaitForResult();
5376 EXPECT_EQ(OK, rv);
5377
5378 const HttpResponseInfo* response = trans->GetResponseInfo();
5379 EXPECT_FALSE(response == NULL);
5380
5381 std::string response_text;
5382 rv = ReadTransaction(trans.get(), &response_text);
5383 EXPECT_EQ(OK, rv);
5384 EXPECT_EQ("Payload", response_text);
5385 }
5386
TEST_F(HttpNetworkTransactionTest,SOCKS5_SSL_GET)5387 TEST_F(HttpNetworkTransactionTest, SOCKS5_SSL_GET) {
5388 HttpRequestInfo request;
5389 request.method = "GET";
5390 request.url = GURL("https://www.google.com/");
5391 request.load_flags = 0;
5392
5393 SessionDependencies session_deps(
5394 ProxyService::CreateFixed("socks5://myproxy:1080"));
5395
5396 scoped_ptr<HttpTransaction> trans(
5397 new HttpNetworkTransaction(CreateSession(&session_deps)));
5398
5399 const char kSOCKS5GreetRequest[] = { 0x05, 0x01, 0x00 };
5400 const char kSOCKS5GreetResponse[] = { 0x05, 0x00 };
5401 const unsigned char kSOCKS5OkRequest[] = {
5402 0x05, // Version
5403 0x01, // Command (CONNECT)
5404 0x00, // Reserved.
5405 0x03, // Address type (DOMAINNAME).
5406 0x0E, // Length of domain (14)
5407 // Domain string:
5408 'w', 'w', 'w', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o', 'm',
5409 0x01, 0xBB, // 16-bit port (443)
5410 };
5411
5412 const char kSOCKS5OkResponse[] =
5413 { 0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0x00, 0x00 };
5414
5415 MockWrite data_writes[] = {
5416 MockWrite(true, kSOCKS5GreetRequest, arraysize(kSOCKS5GreetRequest)),
5417 MockWrite(true, reinterpret_cast<const char*>(kSOCKS5OkRequest),
5418 arraysize(kSOCKS5OkRequest)),
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(true, kSOCKS5GreetResponse, arraysize(kSOCKS5GreetResponse)),
5426 MockWrite(true, kSOCKS5OkResponse, arraysize(kSOCKS5OkResponse)),
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(false, 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(true, OK);
5438 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
5439
5440 TestCompletionCallback callback;
5441
5442 int rv = trans->Start(&request, &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 EXPECT_FALSE(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 // Tests that for connection endpoints the group names are correctly set.
5458
5459 struct GroupNameTest {
5460 std::string proxy_server;
5461 std::string url;
5462 std::string expected_group_name;
5463 bool ssl;
5464 };
5465
SetupSessionForGroupNameTests(SessionDependencies * session_deps)5466 scoped_refptr<HttpNetworkSession> SetupSessionForGroupNameTests(
5467 SessionDependencies* session_deps) {
5468 scoped_refptr<HttpNetworkSession> session(CreateSession(session_deps));
5469
5470 HttpAlternateProtocols* alternate_protocols =
5471 session->mutable_alternate_protocols();
5472 alternate_protocols->SetAlternateProtocolFor(
5473 HostPortPair("host.with.alternate", 80), 443,
5474 HttpAlternateProtocols::NPN_SPDY_2);
5475
5476 return session;
5477 }
5478
GroupNameTransactionHelper(const std::string & url,const scoped_refptr<HttpNetworkSession> & session)5479 int GroupNameTransactionHelper(
5480 const std::string& url,
5481 const scoped_refptr<HttpNetworkSession>& session) {
5482 HttpRequestInfo request;
5483 request.method = "GET";
5484 request.url = GURL(url);
5485 request.load_flags = 0;
5486
5487 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
5488
5489 TestCompletionCallback callback;
5490
5491 // We do not complete this request, the dtor will clean the transaction up.
5492 return trans->Start(&request, &callback, BoundNetLog());
5493 }
5494
TEST_F(HttpNetworkTransactionTest,GroupNameForDirectConnections)5495 TEST_F(HttpNetworkTransactionTest, GroupNameForDirectConnections) {
5496 const GroupNameTest tests[] = {
5497 {
5498 "", // unused
5499 "http://www.google.com/direct",
5500 "www.google.com:80",
5501 false,
5502 },
5503 {
5504 "", // unused
5505 "http://[2001:1418:13:1::25]/direct",
5506 "[2001:1418:13:1::25]:80",
5507 false,
5508 },
5509
5510 // SSL Tests
5511 {
5512 "", // unused
5513 "https://www.google.com/direct_ssl",
5514 "ssl/www.google.com:443",
5515 true,
5516 },
5517 {
5518 "", // unused
5519 "https://[2001:1418:13:1::25]/direct",
5520 "ssl/[2001:1418:13:1::25]:443",
5521 true,
5522 },
5523 {
5524 "", // unused
5525 "http://host.with.alternate/direct",
5526 "ssl/host.with.alternate:443",
5527 true,
5528 },
5529 };
5530
5531 HttpStreamFactory::set_use_alternate_protocols(true);
5532
5533 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
5534 SessionDependencies session_deps(
5535 ProxyService::CreateFixed(tests[i].proxy_server));
5536 scoped_refptr<HttpNetworkSession> session(
5537 SetupSessionForGroupNameTests(&session_deps));
5538
5539 HttpNetworkSessionPeer peer(session);
5540 CaptureGroupNameTransportSocketPool* transport_conn_pool =
5541 new CaptureGroupNameTransportSocketPool(NULL, NULL);
5542 peer.SetTransportSocketPool(transport_conn_pool);
5543 CaptureGroupNameSSLSocketPool* ssl_conn_pool =
5544 new CaptureGroupNameSSLSocketPool(NULL, NULL);
5545 peer.SetSSLSocketPool(ssl_conn_pool);
5546
5547 EXPECT_EQ(ERR_IO_PENDING,
5548 GroupNameTransactionHelper(tests[i].url, session));
5549 if (tests[i].ssl)
5550 EXPECT_EQ(tests[i].expected_group_name,
5551 ssl_conn_pool->last_group_name_received());
5552 else
5553 EXPECT_EQ(tests[i].expected_group_name,
5554 transport_conn_pool->last_group_name_received());
5555 }
5556
5557 HttpStreamFactory::set_use_alternate_protocols(false);
5558 }
5559
TEST_F(HttpNetworkTransactionTest,GroupNameForHTTPProxyConnections)5560 TEST_F(HttpNetworkTransactionTest, GroupNameForHTTPProxyConnections) {
5561 const GroupNameTest tests[] = {
5562 {
5563 "http_proxy",
5564 "http://www.google.com/http_proxy_normal",
5565 "www.google.com:80",
5566 false,
5567 },
5568
5569 // SSL Tests
5570 {
5571 "http_proxy",
5572 "https://www.google.com/http_connect_ssl",
5573 "ssl/www.google.com:443",
5574 true,
5575 },
5576
5577 {
5578 "http_proxy",
5579 "http://host.with.alternate/direct",
5580 "ssl/host.with.alternate:443",
5581 true,
5582 },
5583 };
5584
5585 HttpStreamFactory::set_use_alternate_protocols(true);
5586
5587 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
5588 SessionDependencies session_deps(
5589 ProxyService::CreateFixed(tests[i].proxy_server));
5590 scoped_refptr<HttpNetworkSession> session(
5591 SetupSessionForGroupNameTests(&session_deps));
5592
5593 HttpNetworkSessionPeer peer(session);
5594
5595 HostPortPair proxy_host("http_proxy", 80);
5596 CaptureGroupNameHttpProxySocketPool* http_proxy_pool =
5597 new CaptureGroupNameHttpProxySocketPool(NULL, NULL);
5598 peer.SetSocketPoolForHTTPProxy(proxy_host, http_proxy_pool);
5599 CaptureGroupNameSSLSocketPool* ssl_conn_pool =
5600 new CaptureGroupNameSSLSocketPool(NULL, NULL);
5601 peer.SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool);
5602
5603 EXPECT_EQ(ERR_IO_PENDING,
5604 GroupNameTransactionHelper(tests[i].url, session));
5605 if (tests[i].ssl)
5606 EXPECT_EQ(tests[i].expected_group_name,
5607 ssl_conn_pool->last_group_name_received());
5608 else
5609 EXPECT_EQ(tests[i].expected_group_name,
5610 http_proxy_pool->last_group_name_received());
5611 }
5612
5613 HttpStreamFactory::set_use_alternate_protocols(false);
5614 }
5615
TEST_F(HttpNetworkTransactionTest,GroupNameForSOCKSConnections)5616 TEST_F(HttpNetworkTransactionTest, GroupNameForSOCKSConnections) {
5617 const GroupNameTest tests[] = {
5618 {
5619 "socks4://socks_proxy:1080",
5620 "http://www.google.com/socks4_direct",
5621 "socks4/www.google.com:80",
5622 false,
5623 },
5624 {
5625 "socks5://socks_proxy:1080",
5626 "http://www.google.com/socks5_direct",
5627 "socks5/www.google.com:80",
5628 false,
5629 },
5630
5631 // SSL Tests
5632 {
5633 "socks4://socks_proxy:1080",
5634 "https://www.google.com/socks4_ssl",
5635 "socks4/ssl/www.google.com:443",
5636 true,
5637 },
5638 {
5639 "socks5://socks_proxy:1080",
5640 "https://www.google.com/socks5_ssl",
5641 "socks5/ssl/www.google.com:443",
5642 true,
5643 },
5644
5645 {
5646 "socks4://socks_proxy:1080",
5647 "http://host.with.alternate/direct",
5648 "socks4/ssl/host.with.alternate:443",
5649 true,
5650 },
5651 };
5652
5653 HttpStreamFactory::set_use_alternate_protocols(true);
5654
5655 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
5656 SessionDependencies session_deps(
5657 ProxyService::CreateFixed(tests[i].proxy_server));
5658 scoped_refptr<HttpNetworkSession> session(
5659 SetupSessionForGroupNameTests(&session_deps));
5660
5661 HttpNetworkSessionPeer peer(session);
5662
5663 HostPortPair proxy_host("socks_proxy", 1080);
5664 CaptureGroupNameSOCKSSocketPool* socks_conn_pool =
5665 new CaptureGroupNameSOCKSSocketPool(NULL, NULL);
5666 peer.SetSocketPoolForSOCKSProxy(proxy_host, socks_conn_pool);
5667 CaptureGroupNameSSLSocketPool* ssl_conn_pool =
5668 new CaptureGroupNameSSLSocketPool(NULL, NULL);
5669 peer.SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool);
5670
5671 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
5672
5673 EXPECT_EQ(ERR_IO_PENDING,
5674 GroupNameTransactionHelper(tests[i].url, session));
5675 if (tests[i].ssl)
5676 EXPECT_EQ(tests[i].expected_group_name,
5677 ssl_conn_pool->last_group_name_received());
5678 else
5679 EXPECT_EQ(tests[i].expected_group_name,
5680 socks_conn_pool->last_group_name_received());
5681 }
5682
5683 HttpStreamFactory::set_use_alternate_protocols(false);
5684 }
5685
TEST_F(HttpNetworkTransactionTest,ReconsiderProxyAfterFailedConnection)5686 TEST_F(HttpNetworkTransactionTest, ReconsiderProxyAfterFailedConnection) {
5687 HttpRequestInfo request;
5688 request.method = "GET";
5689 request.url = GURL("http://www.google.com/");
5690
5691 SessionDependencies session_deps(
5692 ProxyService::CreateFixed("myproxy:70;foobar:80"));
5693
5694 // This simulates failure resolving all hostnames; that means we will fail
5695 // connecting to both proxies (myproxy:70 and foobar:80).
5696 session_deps.host_resolver->rules()->AddSimulatedFailure("*");
5697
5698 scoped_ptr<HttpTransaction> trans(
5699 new HttpNetworkTransaction(CreateSession(&session_deps)));
5700
5701 TestCompletionCallback callback;
5702
5703 int rv = trans->Start(&request, &callback, BoundNetLog());
5704 EXPECT_EQ(ERR_IO_PENDING, rv);
5705
5706 rv = callback.WaitForResult();
5707 EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, rv);
5708 }
5709
5710 // Host resolution observer used by
5711 // HttpNetworkTransactionTest.ResolveMadeWithReferrer to check that host
5712 // resovle requests are issued with a referrer of |expected_referrer|.
5713 class ResolutionReferrerObserver : public HostResolver::Observer {
5714 public:
ResolutionReferrerObserver(const GURL & expected_referrer)5715 explicit ResolutionReferrerObserver(const GURL& expected_referrer)
5716 : expected_referrer_(expected_referrer),
5717 called_start_with_referrer_(false),
5718 called_finish_with_referrer_(false) {
5719 }
5720
OnStartResolution(int id,const HostResolver::RequestInfo & info)5721 virtual void OnStartResolution(int id,
5722 const HostResolver::RequestInfo& info) {
5723 if (info.referrer() == expected_referrer_)
5724 called_start_with_referrer_ = true;
5725 }
5726
OnFinishResolutionWithStatus(int id,bool was_resolved,const HostResolver::RequestInfo & info)5727 virtual void OnFinishResolutionWithStatus(
5728 int id, bool was_resolved, const HostResolver::RequestInfo& info ) {
5729 if (info.referrer() == expected_referrer_)
5730 called_finish_with_referrer_ = true;
5731 }
5732
OnCancelResolution(int id,const HostResolver::RequestInfo & info)5733 virtual void OnCancelResolution(int id,
5734 const HostResolver::RequestInfo& info ) {
5735 FAIL() << "Should not be cancelling any requests!";
5736 }
5737
did_complete_with_expected_referrer() const5738 bool did_complete_with_expected_referrer() const {
5739 return called_start_with_referrer_ && called_finish_with_referrer_;
5740 }
5741
5742 private:
5743 GURL expected_referrer_;
5744 bool called_start_with_referrer_;
5745 bool called_finish_with_referrer_;
5746
5747 DISALLOW_COPY_AND_ASSIGN(ResolutionReferrerObserver);
5748 };
5749
5750 // Make sure that when HostResolver::Resolve() is invoked, it passes through
5751 // the "referrer". This is depended on by the DNS prefetch observer.
TEST_F(HttpNetworkTransactionTest,ResolveMadeWithReferrer)5752 TEST_F(HttpNetworkTransactionTest, ResolveMadeWithReferrer) {
5753 GURL referrer = GURL("http://expected-referrer/");
5754 EXPECT_TRUE(referrer.is_valid());
5755 ResolutionReferrerObserver resolution_observer(referrer);
5756
5757 // Issue a request, containing an HTTP referrer.
5758 HttpRequestInfo request;
5759 request.method = "GET";
5760 request.referrer = referrer;
5761 request.url = GURL("http://www.google.com/");
5762
5763 SessionDependencies session_deps;
5764 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
5765 CreateSession(&session_deps)));
5766
5767 // Attach an observer to watch the host resolutions being made.
5768 session_deps.host_resolver->AddObserver(&resolution_observer);
5769
5770 // Connect up a mock socket which will fail when reading.
5771 MockRead data_reads[] = {
5772 MockRead(false, ERR_FAILED),
5773 };
5774 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
5775 session_deps.socket_factory.AddSocketDataProvider(&data);
5776
5777 // Run the request until it fails reading from the socket.
5778 TestCompletionCallback callback;
5779 int rv = trans->Start(&request, &callback, BoundNetLog());
5780 EXPECT_EQ(ERR_IO_PENDING, rv);
5781 rv = callback.WaitForResult();
5782 EXPECT_EQ(ERR_FAILED, rv);
5783
5784 // Check that the host resolution observer saw |referrer|.
5785 EXPECT_TRUE(resolution_observer.did_complete_with_expected_referrer());
5786 }
5787
5788 // Base test to make sure that when the load flags for a request specify to
5789 // bypass the cache, the DNS cache is not used.
BypassHostCacheOnRefreshHelper(int load_flags)5790 void BypassHostCacheOnRefreshHelper(int load_flags) {
5791 // Issue a request, asking to bypass the cache(s).
5792 HttpRequestInfo request;
5793 request.method = "GET";
5794 request.load_flags = load_flags;
5795 request.url = GURL("http://www.google.com/");
5796
5797 SessionDependencies session_deps;
5798
5799 // Select a host resolver that does caching.
5800 session_deps.host_resolver.reset(new MockCachingHostResolver);
5801
5802 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
5803 CreateSession(&session_deps)));
5804
5805 // Warm up the host cache so it has an entry for "www.google.com" (by doing
5806 // a synchronous lookup.)
5807 AddressList addrlist;
5808 int rv = session_deps.host_resolver->Resolve(
5809 HostResolver::RequestInfo(HostPortPair("www.google.com", 80)), &addrlist,
5810 NULL, NULL, BoundNetLog());
5811 EXPECT_EQ(OK, rv);
5812
5813 // Verify that it was added to host cache, by doing a subsequent async lookup
5814 // and confirming it completes synchronously.
5815 TestCompletionCallback resolve_callback;
5816 rv = session_deps.host_resolver->Resolve(
5817 HostResolver::RequestInfo(HostPortPair("www.google.com", 80)), &addrlist,
5818 &resolve_callback, NULL, BoundNetLog());
5819 ASSERT_EQ(OK, rv);
5820
5821 // Inject a failure the next time that "www.google.com" is resolved. This way
5822 // we can tell if the next lookup hit the cache, or the "network".
5823 // (cache --> success, "network" --> failure).
5824 session_deps.host_resolver->rules()->AddSimulatedFailure("www.google.com");
5825
5826 // Connect up a mock socket which will fail with ERR_UNEXPECTED during the
5827 // first read -- this won't be reached as the host resolution will fail first.
5828 MockRead data_reads[] = { MockRead(false, ERR_UNEXPECTED) };
5829 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
5830 session_deps.socket_factory.AddSocketDataProvider(&data);
5831
5832 // Run the request.
5833 TestCompletionCallback callback;
5834 rv = trans->Start(&request, &callback, BoundNetLog());
5835 ASSERT_EQ(ERR_IO_PENDING, rv);
5836 rv = callback.WaitForResult();
5837
5838 // If we bypassed the cache, we would have gotten a failure while resolving
5839 // "www.google.com".
5840 EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
5841 }
5842
5843 // There are multiple load flags that should trigger the host cache bypass.
5844 // Test each in isolation:
TEST_F(HttpNetworkTransactionTest,BypassHostCacheOnRefresh1)5845 TEST_F(HttpNetworkTransactionTest, BypassHostCacheOnRefresh1) {
5846 BypassHostCacheOnRefreshHelper(LOAD_BYPASS_CACHE);
5847 }
5848
TEST_F(HttpNetworkTransactionTest,BypassHostCacheOnRefresh2)5849 TEST_F(HttpNetworkTransactionTest, BypassHostCacheOnRefresh2) {
5850 BypassHostCacheOnRefreshHelper(LOAD_VALIDATE_CACHE);
5851 }
5852
TEST_F(HttpNetworkTransactionTest,BypassHostCacheOnRefresh3)5853 TEST_F(HttpNetworkTransactionTest, BypassHostCacheOnRefresh3) {
5854 BypassHostCacheOnRefreshHelper(LOAD_DISABLE_CACHE);
5855 }
5856
5857 // Make sure we can handle an error when writing the request.
TEST_F(HttpNetworkTransactionTest,RequestWriteError)5858 TEST_F(HttpNetworkTransactionTest, RequestWriteError) {
5859 SessionDependencies session_deps;
5860 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
5861
5862 HttpRequestInfo request;
5863 request.method = "GET";
5864 request.url = GURL("http://www.foo.com/");
5865 request.load_flags = 0;
5866
5867 MockWrite write_failure[] = {
5868 MockWrite(true, ERR_CONNECTION_RESET),
5869 };
5870 StaticSocketDataProvider data(NULL, 0,
5871 write_failure, arraysize(write_failure));
5872 session_deps.socket_factory.AddSocketDataProvider(&data);
5873
5874 TestCompletionCallback callback;
5875
5876 scoped_ptr<HttpTransaction> trans(
5877 new HttpNetworkTransaction(CreateSession(&session_deps)));
5878
5879 int rv = trans->Start(&request, &callback, BoundNetLog());
5880 EXPECT_EQ(ERR_IO_PENDING, rv);
5881
5882 rv = callback.WaitForResult();
5883 EXPECT_EQ(ERR_CONNECTION_RESET, rv);
5884 }
5885
5886 // Check that a connection closed after the start of the headers finishes ok.
TEST_F(HttpNetworkTransactionTest,ConnectionClosedAfterStartOfHeaders)5887 TEST_F(HttpNetworkTransactionTest, ConnectionClosedAfterStartOfHeaders) {
5888 SessionDependencies session_deps;
5889 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
5890
5891 HttpRequestInfo request;
5892 request.method = "GET";
5893 request.url = GURL("http://www.foo.com/");
5894 request.load_flags = 0;
5895
5896 MockRead data_reads[] = {
5897 MockRead("HTTP/1."),
5898 MockRead(false, OK),
5899 };
5900
5901 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
5902 session_deps.socket_factory.AddSocketDataProvider(&data);
5903
5904 TestCompletionCallback callback;
5905
5906 scoped_ptr<HttpTransaction> trans(
5907 new HttpNetworkTransaction(CreateSession(&session_deps)));
5908
5909 int rv = trans->Start(&request, &callback, BoundNetLog());
5910 EXPECT_EQ(ERR_IO_PENDING, rv);
5911
5912 rv = callback.WaitForResult();
5913 EXPECT_EQ(OK, rv);
5914
5915 const HttpResponseInfo* response = trans->GetResponseInfo();
5916 EXPECT_TRUE(response != NULL);
5917
5918 EXPECT_TRUE(response->headers != NULL);
5919 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine());
5920
5921 std::string response_data;
5922 rv = ReadTransaction(trans.get(), &response_data);
5923 EXPECT_EQ(OK, rv);
5924 EXPECT_EQ("", response_data);
5925 }
5926
5927 // Make sure that a dropped connection while draining the body for auth
5928 // restart does the right thing.
TEST_F(HttpNetworkTransactionTest,DrainResetOK)5929 TEST_F(HttpNetworkTransactionTest, DrainResetOK) {
5930 SessionDependencies session_deps;
5931 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
5932
5933 HttpRequestInfo request;
5934 request.method = "GET";
5935 request.url = GURL("http://www.google.com/");
5936 request.load_flags = 0;
5937
5938 MockWrite data_writes1[] = {
5939 MockWrite("GET / HTTP/1.1\r\n"
5940 "Host: www.google.com\r\n"
5941 "Connection: keep-alive\r\n\r\n"),
5942 };
5943
5944 MockRead data_reads1[] = {
5945 MockRead("HTTP/1.1 401 Unauthorized\r\n"),
5946 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
5947 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
5948 MockRead("Content-Length: 14\r\n\r\n"),
5949 MockRead("Unauth"),
5950 MockRead(true, ERR_CONNECTION_RESET),
5951 };
5952
5953 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
5954 data_writes1, arraysize(data_writes1));
5955 session_deps.socket_factory.AddSocketDataProvider(&data1);
5956
5957 // After calling trans->RestartWithAuth(), this is the request we should
5958 // be issuing -- the final header line contains the credentials.
5959 MockWrite data_writes2[] = {
5960 MockWrite("GET / HTTP/1.1\r\n"
5961 "Host: www.google.com\r\n"
5962 "Connection: keep-alive\r\n"
5963 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
5964 };
5965
5966 // Lastly, the server responds with the actual content.
5967 MockRead data_reads2[] = {
5968 MockRead("HTTP/1.1 200 OK\r\n"),
5969 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
5970 MockRead("Content-Length: 100\r\n\r\n"),
5971 MockRead(false, OK),
5972 };
5973
5974 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
5975 data_writes2, arraysize(data_writes2));
5976 session_deps.socket_factory.AddSocketDataProvider(&data2);
5977
5978 TestCompletionCallback callback1;
5979
5980 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
5981
5982 int rv = trans->Start(&request, &callback1, BoundNetLog());
5983 EXPECT_EQ(ERR_IO_PENDING, rv);
5984
5985 rv = callback1.WaitForResult();
5986 EXPECT_EQ(OK, rv);
5987
5988 const HttpResponseInfo* response = trans->GetResponseInfo();
5989 EXPECT_FALSE(response == NULL);
5990
5991 // The password prompt info should have been set in response->auth_challenge.
5992 EXPECT_FALSE(response->auth_challenge.get() == NULL);
5993
5994 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
5995 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
5996 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
5997
5998 TestCompletionCallback callback2;
5999
6000 rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
6001 EXPECT_EQ(ERR_IO_PENDING, rv);
6002
6003 rv = callback2.WaitForResult();
6004 EXPECT_EQ(OK, rv);
6005
6006 response = trans->GetResponseInfo();
6007 EXPECT_FALSE(response == NULL);
6008 EXPECT_TRUE(response->auth_challenge.get() == NULL);
6009 EXPECT_EQ(100, response->headers->GetContentLength());
6010 }
6011
6012 // Test HTTPS connections going through a proxy that sends extra data.
TEST_F(HttpNetworkTransactionTest,HTTPSViaProxyWithExtraData)6013 TEST_F(HttpNetworkTransactionTest, HTTPSViaProxyWithExtraData) {
6014 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70"));
6015
6016 HttpRequestInfo request;
6017 request.method = "GET";
6018 request.url = GURL("https://www.google.com/");
6019 request.load_flags = 0;
6020
6021 MockRead proxy_reads[] = {
6022 MockRead("HTTP/1.0 200 Connected\r\n\r\nExtra data"),
6023 MockRead(false, OK)
6024 };
6025
6026 StaticSocketDataProvider data(proxy_reads, arraysize(proxy_reads), NULL, 0);
6027 SSLSocketDataProvider ssl(true, OK);
6028
6029 session_deps.socket_factory.AddSocketDataProvider(&data);
6030 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
6031
6032 TestCompletionCallback callback;
6033
6034 session_deps.socket_factory.ResetNextMockIndexes();
6035
6036 scoped_ptr<HttpTransaction> trans(
6037 new HttpNetworkTransaction(CreateSession(&session_deps)));
6038
6039 int rv = trans->Start(&request, &callback, BoundNetLog());
6040 EXPECT_EQ(ERR_IO_PENDING, rv);
6041
6042 rv = callback.WaitForResult();
6043 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
6044 }
6045
TEST_F(HttpNetworkTransactionTest,LargeContentLengthThenClose)6046 TEST_F(HttpNetworkTransactionTest, LargeContentLengthThenClose) {
6047 HttpRequestInfo request;
6048 request.method = "GET";
6049 request.url = GURL("http://www.google.com/");
6050 request.load_flags = 0;
6051
6052 SessionDependencies session_deps;
6053 scoped_ptr<HttpTransaction> trans(
6054 new HttpNetworkTransaction(CreateSession(&session_deps)));
6055
6056 MockRead data_reads[] = {
6057 MockRead("HTTP/1.0 200 OK\r\nContent-Length:6719476739\r\n\r\n"),
6058 MockRead(false, OK),
6059 };
6060
6061 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
6062 session_deps.socket_factory.AddSocketDataProvider(&data);
6063
6064 TestCompletionCallback callback;
6065
6066 int rv = trans->Start(&request, &callback, BoundNetLog());
6067 EXPECT_EQ(ERR_IO_PENDING, rv);
6068
6069 EXPECT_EQ(OK, callback.WaitForResult());
6070
6071 const HttpResponseInfo* response = trans->GetResponseInfo();
6072 EXPECT_TRUE(response != NULL);
6073
6074 EXPECT_TRUE(response->headers != NULL);
6075 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine());
6076
6077 std::string response_data;
6078 rv = ReadTransaction(trans.get(), &response_data);
6079 EXPECT_EQ(ERR_CONNECTION_CLOSED, rv);
6080 }
6081
TEST_F(HttpNetworkTransactionTest,UploadFileSmallerThanLength)6082 TEST_F(HttpNetworkTransactionTest, UploadFileSmallerThanLength) {
6083 HttpRequestInfo request;
6084 request.method = "POST";
6085 request.url = GURL("http://www.google.com/upload");
6086 request.upload_data = new UploadData;
6087 request.load_flags = 0;
6088
6089 SessionDependencies session_deps;
6090 scoped_ptr<HttpTransaction> trans(
6091 new HttpNetworkTransaction(CreateSession(&session_deps)));
6092
6093 FilePath temp_file_path;
6094 ASSERT_TRUE(file_util::CreateTemporaryFile(&temp_file_path));
6095 const uint64 kFakeSize = 100000; // file is actually blank
6096
6097 std::vector<UploadData::Element> elements;
6098 UploadData::Element element;
6099 element.SetToFilePath(temp_file_path);
6100 element.SetContentLength(kFakeSize);
6101 elements.push_back(element);
6102 request.upload_data->SetElements(elements);
6103 EXPECT_EQ(kFakeSize, request.upload_data->GetContentLength());
6104
6105 MockRead data_reads[] = {
6106 MockRead("HTTP/1.0 200 OK\r\n\r\n"),
6107 MockRead("hello world"),
6108 MockRead(false, OK),
6109 };
6110 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
6111 session_deps.socket_factory.AddSocketDataProvider(&data);
6112
6113 TestCompletionCallback callback;
6114
6115 int rv = trans->Start(&request, &callback, BoundNetLog());
6116 EXPECT_EQ(ERR_IO_PENDING, rv);
6117
6118 rv = callback.WaitForResult();
6119 EXPECT_EQ(OK, rv);
6120
6121 const HttpResponseInfo* response = trans->GetResponseInfo();
6122 EXPECT_TRUE(response != NULL);
6123
6124 EXPECT_TRUE(response->headers != NULL);
6125 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine());
6126
6127 std::string response_data;
6128 rv = ReadTransaction(trans.get(), &response_data);
6129 EXPECT_EQ(OK, rv);
6130 EXPECT_EQ("hello world", response_data);
6131
6132 file_util::Delete(temp_file_path, false);
6133 }
6134
TEST_F(HttpNetworkTransactionTest,UploadUnreadableFile)6135 TEST_F(HttpNetworkTransactionTest, UploadUnreadableFile) {
6136 HttpRequestInfo request;
6137 request.method = "POST";
6138 request.url = GURL("http://www.google.com/upload");
6139 request.upload_data = new UploadData;
6140 request.load_flags = 0;
6141
6142 // If we try to upload an unreadable file, the network stack should report
6143 // the file size as zero and upload zero bytes for that file.
6144 SessionDependencies session_deps;
6145 scoped_ptr<HttpTransaction> trans(
6146 new HttpNetworkTransaction(CreateSession(&session_deps)));
6147
6148 FilePath temp_file;
6149 ASSERT_TRUE(file_util::CreateTemporaryFile(&temp_file));
6150 std::string temp_file_content("Unreadable file.");
6151 ASSERT_TRUE(file_util::WriteFile(temp_file, temp_file_content.c_str(),
6152 temp_file_content.length()));
6153 ASSERT_TRUE(file_util::MakeFileUnreadable(temp_file));
6154
6155 std::vector<UploadData::Element> elements;
6156 UploadData::Element element;
6157 element.SetToFilePath(temp_file);
6158 elements.push_back(element);
6159 request.upload_data->SetElements(elements);
6160
6161 MockRead data_reads[] = {
6162 MockRead("HTTP/1.0 200 OK\r\n\r\n"),
6163 MockRead(false, OK),
6164 };
6165 MockWrite data_writes[] = {
6166 MockWrite("POST /upload HTTP/1.1\r\n"
6167 "Host: www.google.com\r\n"
6168 "Connection: keep-alive\r\n"
6169 "Content-Length: 0\r\n\r\n"),
6170 MockWrite(false, OK),
6171 };
6172 StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes,
6173 arraysize(data_writes));
6174 session_deps.socket_factory.AddSocketDataProvider(&data);
6175
6176 TestCompletionCallback callback;
6177
6178 int rv = trans->Start(&request, &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 EXPECT_TRUE(response != NULL);
6186 EXPECT_TRUE(response->headers != NULL);
6187 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine());
6188
6189 file_util::Delete(temp_file, false);
6190 }
6191
TEST_F(HttpNetworkTransactionTest,UnreadableUploadFileAfterAuthRestart)6192 TEST_F(HttpNetworkTransactionTest, UnreadableUploadFileAfterAuthRestart) {
6193 HttpRequestInfo request;
6194 request.method = "POST";
6195 request.url = GURL("http://www.google.com/upload");
6196 request.upload_data = new UploadData;
6197 request.load_flags = 0;
6198
6199 SessionDependencies session_deps;
6200 scoped_ptr<HttpTransaction> trans(
6201 new HttpNetworkTransaction(CreateSession(&session_deps)));
6202
6203 FilePath temp_file;
6204 ASSERT_TRUE(file_util::CreateTemporaryFile(&temp_file));
6205 std::string temp_file_contents("Unreadable file.");
6206 std::string unreadable_contents(temp_file_contents.length(), '\0');
6207 ASSERT_TRUE(file_util::WriteFile(temp_file, temp_file_contents.c_str(),
6208 temp_file_contents.length()));
6209
6210 std::vector<UploadData::Element> elements;
6211 UploadData::Element element;
6212 element.SetToFilePath(temp_file);
6213 elements.push_back(element);
6214 request.upload_data->SetElements(elements);
6215
6216 MockRead data_reads[] = {
6217 MockRead("HTTP/1.1 401 Unauthorized\r\n"),
6218 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
6219 MockRead("Content-Length: 0\r\n\r\n"), // No response body.
6220
6221 MockRead("HTTP/1.1 200 OK\r\n"),
6222 MockRead("Content-Length: 0\r\n\r\n"),
6223 MockRead(false, OK),
6224 };
6225 MockWrite data_writes[] = {
6226 MockWrite("POST /upload HTTP/1.1\r\n"
6227 "Host: www.google.com\r\n"
6228 "Connection: keep-alive\r\n"
6229 "Content-Length: 16\r\n\r\n"),
6230 MockWrite(false, temp_file_contents.c_str()),
6231
6232 MockWrite("POST /upload HTTP/1.1\r\n"
6233 "Host: www.google.com\r\n"
6234 "Connection: keep-alive\r\n"
6235 "Content-Length: 16\r\n"
6236 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
6237 MockWrite(false, unreadable_contents.c_str(), temp_file_contents.length()),
6238 MockWrite(false, OK),
6239 };
6240 StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes,
6241 arraysize(data_writes));
6242 session_deps.socket_factory.AddSocketDataProvider(&data);
6243
6244 TestCompletionCallback callback1;
6245
6246 int rv = trans->Start(&request, &callback1, BoundNetLog());
6247 EXPECT_EQ(ERR_IO_PENDING, rv);
6248
6249 rv = callback1.WaitForResult();
6250 EXPECT_EQ(OK, rv);
6251
6252 const HttpResponseInfo* response = trans->GetResponseInfo();
6253 EXPECT_TRUE(response != NULL);
6254 EXPECT_TRUE(response->headers != NULL);
6255 EXPECT_EQ("HTTP/1.1 401 Unauthorized", response->headers->GetStatusLine());
6256
6257 // The password prompt info should have been set in response->auth_challenge.
6258 EXPECT_TRUE(response->auth_challenge.get() != NULL);
6259 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
6260 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
6261 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
6262
6263 // Now make the file unreadable and try again.
6264 ASSERT_TRUE(file_util::MakeFileUnreadable(temp_file));
6265
6266 TestCompletionCallback callback2;
6267
6268 rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
6269 EXPECT_EQ(ERR_IO_PENDING, rv);
6270
6271 rv = callback2.WaitForResult();
6272 EXPECT_EQ(OK, rv);
6273
6274 response = trans->GetResponseInfo();
6275 EXPECT_TRUE(response != NULL);
6276 EXPECT_TRUE(response->headers != NULL);
6277 EXPECT_TRUE(response->auth_challenge.get() == NULL);
6278 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
6279
6280 file_util::Delete(temp_file, false);
6281 }
6282
6283 // Tests that changes to Auth realms are treated like auth rejections.
TEST_F(HttpNetworkTransactionTest,ChangeAuthRealms)6284 TEST_F(HttpNetworkTransactionTest, ChangeAuthRealms) {
6285 SessionDependencies session_deps;
6286
6287 HttpRequestInfo request;
6288 request.method = "GET";
6289 request.url = GURL("http://www.google.com/");
6290 request.load_flags = 0;
6291
6292 // First transaction will request a resource and receive a Basic challenge
6293 // with realm="first_realm".
6294 MockWrite data_writes1[] = {
6295 MockWrite("GET / HTTP/1.1\r\n"
6296 "Host: www.google.com\r\n"
6297 "Connection: keep-alive\r\n"
6298 "\r\n"),
6299 };
6300 MockRead data_reads1[] = {
6301 MockRead("HTTP/1.1 401 Unauthorized\r\n"
6302 "WWW-Authenticate: Basic realm=\"first_realm\"\r\n"
6303 "\r\n"),
6304 };
6305
6306 // After calling trans->RestartWithAuth(), provide an Authentication header
6307 // for first_realm. The server will reject and provide a challenge with
6308 // second_realm.
6309 MockWrite data_writes2[] = {
6310 MockWrite("GET / HTTP/1.1\r\n"
6311 "Host: www.google.com\r\n"
6312 "Connection: keep-alive\r\n"
6313 "Authorization: Basic Zmlyc3Q6YmF6\r\n"
6314 "\r\n"),
6315 };
6316 MockRead data_reads2[] = {
6317 MockRead("HTTP/1.1 401 Unauthorized\r\n"
6318 "WWW-Authenticate: Basic realm=\"second_realm\"\r\n"
6319 "\r\n"),
6320 };
6321
6322 // This again fails, and goes back to first_realm. Make sure that the
6323 // entry is removed from cache.
6324 MockWrite data_writes3[] = {
6325 MockWrite("GET / HTTP/1.1\r\n"
6326 "Host: www.google.com\r\n"
6327 "Connection: keep-alive\r\n"
6328 "Authorization: Basic c2Vjb25kOmZvdQ==\r\n"
6329 "\r\n"),
6330 };
6331 MockRead data_reads3[] = {
6332 MockRead("HTTP/1.1 401 Unauthorized\r\n"
6333 "WWW-Authenticate: Basic realm=\"first_realm\"\r\n"
6334 "\r\n"),
6335 };
6336
6337 // Try one last time (with the correct password) and get the resource.
6338 MockWrite data_writes4[] = {
6339 MockWrite("GET / HTTP/1.1\r\n"
6340 "Host: www.google.com\r\n"
6341 "Connection: keep-alive\r\n"
6342 "Authorization: Basic Zmlyc3Q6YmFy\r\n"
6343 "\r\n"),
6344 };
6345 MockRead data_reads4[] = {
6346 MockRead("HTTP/1.1 200 OK\r\n"
6347 "Content-Type: text/html; charset=iso-8859-1\r\n"
6348 "Content-Length: 5\r\n"
6349 "\r\n"
6350 "hello"),
6351 };
6352
6353 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
6354 data_writes1, arraysize(data_writes1));
6355 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
6356 data_writes2, arraysize(data_writes2));
6357 StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3),
6358 data_writes3, arraysize(data_writes3));
6359 StaticSocketDataProvider data4(data_reads4, arraysize(data_reads4),
6360 data_writes4, arraysize(data_writes4));
6361 session_deps.socket_factory.AddSocketDataProvider(&data1);
6362 session_deps.socket_factory.AddSocketDataProvider(&data2);
6363 session_deps.socket_factory.AddSocketDataProvider(&data3);
6364 session_deps.socket_factory.AddSocketDataProvider(&data4);
6365
6366 TestCompletionCallback callback1;
6367
6368 scoped_ptr<HttpTransaction> trans(
6369 new HttpNetworkTransaction(CreateSession(&session_deps)));
6370
6371 // Issue the first request with Authorize headers. There should be a
6372 // password prompt for first_realm waiting to be filled in after the
6373 // transaction completes.
6374 int rv = trans->Start(&request, &callback1, BoundNetLog());
6375 EXPECT_EQ(ERR_IO_PENDING, rv);
6376 rv = callback1.WaitForResult();
6377 EXPECT_EQ(OK, rv);
6378 const HttpResponseInfo* response = trans->GetResponseInfo();
6379 ASSERT_FALSE(response == NULL);
6380 ASSERT_FALSE(response->auth_challenge.get() == NULL);
6381 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
6382 EXPECT_EQ(L"first_realm", response->auth_challenge->realm);
6383 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
6384
6385 // Issue the second request with an incorrect password. There should be a
6386 // password prompt for second_realm waiting to be filled in after the
6387 // transaction completes.
6388 TestCompletionCallback callback2;
6389 rv = trans->RestartWithAuth(kFirst, kBaz, &callback2);
6390 EXPECT_EQ(ERR_IO_PENDING, rv);
6391 rv = callback2.WaitForResult();
6392 EXPECT_EQ(OK, rv);
6393 response = trans->GetResponseInfo();
6394 ASSERT_FALSE(response == NULL);
6395 ASSERT_FALSE(response->auth_challenge.get() == NULL);
6396 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
6397 EXPECT_EQ(L"second_realm", response->auth_challenge->realm);
6398 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
6399
6400 // Issue the third request with another incorrect password. There should be
6401 // a password prompt for first_realm waiting to be filled in. If the password
6402 // prompt is not present, it indicates that the HttpAuthCacheEntry for
6403 // first_realm was not correctly removed.
6404 TestCompletionCallback callback3;
6405 rv = trans->RestartWithAuth(kSecond, kFou, &callback3);
6406 EXPECT_EQ(ERR_IO_PENDING, rv);
6407 rv = callback3.WaitForResult();
6408 EXPECT_EQ(OK, rv);
6409 response = trans->GetResponseInfo();
6410 ASSERT_FALSE(response == NULL);
6411 ASSERT_FALSE(response->auth_challenge.get() == NULL);
6412 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
6413 EXPECT_EQ(L"first_realm", response->auth_challenge->realm);
6414 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
6415
6416 // Issue the fourth request with the correct password and username.
6417 TestCompletionCallback callback4;
6418 rv = trans->RestartWithAuth(kFirst, kBar, &callback4);
6419 EXPECT_EQ(ERR_IO_PENDING, rv);
6420 rv = callback4.WaitForResult();
6421 EXPECT_EQ(OK, rv);
6422 response = trans->GetResponseInfo();
6423 ASSERT_FALSE(response == NULL);
6424 EXPECT_TRUE(response->auth_challenge.get() == NULL);
6425 }
6426
TEST_F(HttpNetworkTransactionTest,HonorAlternateProtocolHeader)6427 TEST_F(HttpNetworkTransactionTest, HonorAlternateProtocolHeader) {
6428 HttpStreamFactory::set_next_protos("needs_to_be_set_for_this_test");
6429 HttpStreamFactory::set_use_alternate_protocols(true);
6430
6431 SessionDependencies session_deps;
6432
6433 MockRead data_reads[] = {
6434 MockRead("HTTP/1.1 200 OK\r\n"),
6435 MockRead(kAlternateProtocolHttpHeader),
6436 MockRead("hello world"),
6437 MockRead(false, OK),
6438 };
6439
6440 HttpRequestInfo request;
6441 request.method = "GET";
6442 request.url = GURL("http://www.google.com/");
6443 request.load_flags = 0;
6444
6445 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
6446
6447 session_deps.socket_factory.AddSocketDataProvider(&data);
6448
6449 TestCompletionCallback callback;
6450
6451 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
6452 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
6453
6454 int rv = trans->Start(&request, &callback, BoundNetLog());
6455 EXPECT_EQ(ERR_IO_PENDING, rv);
6456
6457 HostPortPair http_host_port_pair("www.google.com", 80);
6458 const HttpAlternateProtocols& alternate_protocols =
6459 session->alternate_protocols();
6460 EXPECT_FALSE(
6461 alternate_protocols.HasAlternateProtocolFor(http_host_port_pair));
6462
6463 EXPECT_EQ(OK, callback.WaitForResult());
6464
6465 const HttpResponseInfo* response = trans->GetResponseInfo();
6466 ASSERT_TRUE(response != NULL);
6467 ASSERT_TRUE(response->headers != NULL);
6468 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
6469 EXPECT_FALSE(response->was_fetched_via_spdy);
6470 EXPECT_FALSE(response->was_npn_negotiated);
6471
6472 std::string response_data;
6473 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
6474 EXPECT_EQ("hello world", response_data);
6475
6476 ASSERT_TRUE(alternate_protocols.HasAlternateProtocolFor(http_host_port_pair));
6477 const HttpAlternateProtocols::PortProtocolPair alternate =
6478 alternate_protocols.GetAlternateProtocolFor(http_host_port_pair);
6479 HttpAlternateProtocols::PortProtocolPair expected_alternate;
6480 expected_alternate.port = 443;
6481 expected_alternate.protocol = HttpAlternateProtocols::NPN_SPDY_2;
6482 EXPECT_TRUE(expected_alternate.Equals(alternate));
6483
6484 HttpStreamFactory::set_use_alternate_protocols(false);
6485 HttpStreamFactory::set_next_protos("");
6486 }
6487
TEST_F(HttpNetworkTransactionTest,MarkBrokenAlternateProtocolAndFallback)6488 TEST_F(HttpNetworkTransactionTest, MarkBrokenAlternateProtocolAndFallback) {
6489 HttpStreamFactory::set_use_alternate_protocols(true);
6490 SessionDependencies session_deps;
6491
6492 HttpRequestInfo request;
6493 request.method = "GET";
6494 request.url = GURL("http://www.google.com/");
6495 request.load_flags = 0;
6496
6497 MockConnect mock_connect(true, ERR_CONNECTION_REFUSED);
6498 StaticSocketDataProvider first_data;
6499 first_data.set_connect_data(mock_connect);
6500 session_deps.socket_factory.AddSocketDataProvider(&first_data);
6501
6502 MockRead data_reads[] = {
6503 MockRead("HTTP/1.1 200 OK\r\n\r\n"),
6504 MockRead("hello world"),
6505 MockRead(true, OK),
6506 };
6507 StaticSocketDataProvider second_data(
6508 data_reads, arraysize(data_reads), NULL, 0);
6509 session_deps.socket_factory.AddSocketDataProvider(&second_data);
6510
6511 TestCompletionCallback callback;
6512
6513 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
6514
6515 HostPortPair http_host_port_pair("www.google.com", 80);
6516 HttpAlternateProtocols* alternate_protocols =
6517 session->mutable_alternate_protocols();
6518 alternate_protocols->SetAlternateProtocolFor(
6519 http_host_port_pair, 1234 /* port is ignored by MockConnect anyway */,
6520 HttpAlternateProtocols::NPN_SPDY_2);
6521
6522 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
6523
6524 int rv = trans->Start(&request, &callback, BoundNetLog());
6525 EXPECT_EQ(ERR_IO_PENDING, rv);
6526 EXPECT_EQ(OK, callback.WaitForResult());
6527
6528 const HttpResponseInfo* response = trans->GetResponseInfo();
6529 ASSERT_TRUE(response != NULL);
6530 ASSERT_TRUE(response->headers != NULL);
6531 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
6532
6533 std::string response_data;
6534 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
6535 EXPECT_EQ("hello world", response_data);
6536
6537 ASSERT_TRUE(
6538 alternate_protocols->HasAlternateProtocolFor(http_host_port_pair));
6539 const HttpAlternateProtocols::PortProtocolPair alternate =
6540 alternate_protocols->GetAlternateProtocolFor(http_host_port_pair);
6541 EXPECT_EQ(HttpAlternateProtocols::BROKEN, alternate.protocol);
6542 HttpStreamFactory::set_use_alternate_protocols(false);
6543 }
6544
TEST_F(HttpNetworkTransactionTest,UseAlternateProtocolForNpnSpdy)6545 TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) {
6546 HttpStreamFactory::set_use_alternate_protocols(true);
6547 HttpStreamFactory::set_next_protos(kExpectedNPNString);
6548 SessionDependencies session_deps;
6549
6550 HttpRequestInfo request;
6551 request.method = "GET";
6552 request.url = GURL("http://www.google.com/");
6553 request.load_flags = 0;
6554
6555 MockRead data_reads[] = {
6556 MockRead("HTTP/1.1 200 OK\r\n"),
6557 MockRead(kAlternateProtocolHttpHeader),
6558 MockRead("hello world"),
6559 MockRead(true, OK),
6560 };
6561
6562 StaticSocketDataProvider first_transaction(
6563 data_reads, arraysize(data_reads), NULL, 0);
6564 session_deps.socket_factory.AddSocketDataProvider(&first_transaction);
6565
6566 SSLSocketDataProvider ssl(true, OK);
6567 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
6568 ssl.next_proto = "spdy/2";
6569 ssl.was_npn_negotiated = true;
6570 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
6571
6572 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
6573 MockWrite spdy_writes[] = { CreateMockWrite(*req) };
6574
6575 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
6576 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true));
6577 MockRead spdy_reads[] = {
6578 CreateMockRead(*resp),
6579 CreateMockRead(*data),
6580 MockRead(true, 0, 0),
6581 };
6582
6583 scoped_refptr<DelayedSocketData> spdy_data(
6584 new DelayedSocketData(
6585 1, // wait for one write to finish before reading.
6586 spdy_reads, arraysize(spdy_reads),
6587 spdy_writes, arraysize(spdy_writes)));
6588 session_deps.socket_factory.AddSocketDataProvider(spdy_data);
6589
6590 MockConnect never_finishing_connect(false, ERR_IO_PENDING);
6591 StaticSocketDataProvider hanging_non_alternate_protocol_socket(
6592 NULL, 0, NULL, 0);
6593 hanging_non_alternate_protocol_socket.set_connect_data(
6594 never_finishing_connect);
6595 session_deps.socket_factory.AddSocketDataProvider(
6596 &hanging_non_alternate_protocol_socket);
6597
6598 TestCompletionCallback callback;
6599
6600 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
6601 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session));
6602
6603 int rv = trans->Start(&request, &callback, BoundNetLog());
6604 EXPECT_EQ(ERR_IO_PENDING, rv);
6605 EXPECT_EQ(OK, callback.WaitForResult());
6606
6607 const HttpResponseInfo* response = trans->GetResponseInfo();
6608 ASSERT_TRUE(response != NULL);
6609 ASSERT_TRUE(response->headers != NULL);
6610 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
6611
6612 std::string response_data;
6613 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
6614 EXPECT_EQ("hello world", response_data);
6615
6616 trans.reset(new HttpNetworkTransaction(session));
6617
6618 rv = trans->Start(&request, &callback, BoundNetLog());
6619 EXPECT_EQ(ERR_IO_PENDING, rv);
6620 EXPECT_EQ(OK, callback.WaitForResult());
6621
6622 response = trans->GetResponseInfo();
6623 ASSERT_TRUE(response != NULL);
6624 ASSERT_TRUE(response->headers != NULL);
6625 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
6626 EXPECT_TRUE(response->was_fetched_via_spdy);
6627 EXPECT_TRUE(response->was_npn_negotiated);
6628
6629 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
6630 EXPECT_EQ("hello!", response_data);
6631
6632 HttpStreamFactory::set_next_protos("");
6633 HttpStreamFactory::set_use_alternate_protocols(false);
6634 }
6635
TEST_F(HttpNetworkTransactionTest,AlternateProtocolWithSpdyLateBinding)6636 TEST_F(HttpNetworkTransactionTest, AlternateProtocolWithSpdyLateBinding) {
6637 HttpStreamFactory::set_use_alternate_protocols(true);
6638 HttpStreamFactory::set_next_protos(kExpectedNPNString);
6639 SessionDependencies session_deps;
6640
6641 HttpRequestInfo request;
6642 request.method = "GET";
6643 request.url = GURL("http://www.google.com/");
6644 request.load_flags = 0;
6645
6646 MockRead data_reads[] = {
6647 MockRead("HTTP/1.1 200 OK\r\n"),
6648 MockRead(kAlternateProtocolHttpHeader),
6649 MockRead("hello world"),
6650 MockRead(true, OK),
6651 };
6652
6653 StaticSocketDataProvider first_transaction(
6654 data_reads, arraysize(data_reads), NULL, 0);
6655 // Socket 1 is the HTTP transaction with the Alternate-Protocol header.
6656 session_deps.socket_factory.AddSocketDataProvider(&first_transaction);
6657
6658 MockConnect never_finishing_connect(false, ERR_IO_PENDING);
6659 StaticSocketDataProvider hanging_socket(
6660 NULL, 0, NULL, 0);
6661 hanging_socket.set_connect_data(never_finishing_connect);
6662 // Socket 2 and 3 are the hanging Alternate-Protocol and
6663 // non-Alternate-Protocol jobs from the 2nd transaction.
6664 session_deps.socket_factory.AddSocketDataProvider(&hanging_socket);
6665 session_deps.socket_factory.AddSocketDataProvider(&hanging_socket);
6666
6667 SSLSocketDataProvider ssl(true, OK);
6668 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
6669 ssl.next_proto = "spdy/2";
6670 ssl.was_npn_negotiated = true;
6671 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
6672
6673 scoped_ptr<spdy::SpdyFrame> req1(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
6674 scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST));
6675 MockWrite spdy_writes[] = {
6676 CreateMockWrite(*req1),
6677 CreateMockWrite(*req2),
6678 };
6679 scoped_ptr<spdy::SpdyFrame> resp1(ConstructSpdyGetSynReply(NULL, 0, 1));
6680 scoped_ptr<spdy::SpdyFrame> data1(ConstructSpdyBodyFrame(1, true));
6681 scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3));
6682 scoped_ptr<spdy::SpdyFrame> data2(ConstructSpdyBodyFrame(3, true));
6683 MockRead spdy_reads[] = {
6684 CreateMockRead(*resp1),
6685 CreateMockRead(*data1),
6686 CreateMockRead(*resp2),
6687 CreateMockRead(*data2),
6688 MockRead(true, 0, 0),
6689 };
6690
6691 scoped_refptr<DelayedSocketData> spdy_data(
6692 new DelayedSocketData(
6693 2, // wait for writes to finish before reading.
6694 spdy_reads, arraysize(spdy_reads),
6695 spdy_writes, arraysize(spdy_writes)));
6696 // Socket 4 is the successful Alternate-Protocol for transaction 3.
6697 session_deps.socket_factory.AddSocketDataProvider(spdy_data);
6698
6699 // Socket 5 is the unsuccessful non-Alternate-Protocol for transaction 3.
6700 session_deps.socket_factory.AddSocketDataProvider(&hanging_socket);
6701
6702 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
6703 TestCompletionCallback callback1;
6704 HttpNetworkTransaction trans1(session);
6705
6706 int rv = trans1.Start(&request, &callback1, BoundNetLog());
6707 EXPECT_EQ(ERR_IO_PENDING, rv);
6708 EXPECT_EQ(OK, callback1.WaitForResult());
6709
6710 const HttpResponseInfo* response = trans1.GetResponseInfo();
6711 ASSERT_TRUE(response != NULL);
6712 ASSERT_TRUE(response->headers != NULL);
6713 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
6714
6715 std::string response_data;
6716 ASSERT_EQ(OK, ReadTransaction(&trans1, &response_data));
6717 EXPECT_EQ("hello world", response_data);
6718
6719 TestCompletionCallback callback2;
6720 HttpNetworkTransaction trans2(session);
6721 rv = trans2.Start(&request, &callback2, BoundNetLog());
6722 EXPECT_EQ(ERR_IO_PENDING, rv);
6723
6724 TestCompletionCallback callback3;
6725 HttpNetworkTransaction trans3(session);
6726 rv = trans3.Start(&request, &callback3, BoundNetLog());
6727 EXPECT_EQ(ERR_IO_PENDING, rv);
6728
6729 EXPECT_EQ(OK, callback2.WaitForResult());
6730 EXPECT_EQ(OK, callback3.WaitForResult());
6731
6732 response = trans2.GetResponseInfo();
6733 ASSERT_TRUE(response != NULL);
6734 ASSERT_TRUE(response->headers != NULL);
6735 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
6736 EXPECT_TRUE(response->was_fetched_via_spdy);
6737 EXPECT_TRUE(response->was_npn_negotiated);
6738 ASSERT_EQ(OK, ReadTransaction(&trans2, &response_data));
6739 EXPECT_EQ("hello!", response_data);
6740
6741 response = trans3.GetResponseInfo();
6742 ASSERT_TRUE(response != NULL);
6743 ASSERT_TRUE(response->headers != NULL);
6744 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
6745 EXPECT_TRUE(response->was_fetched_via_spdy);
6746 EXPECT_TRUE(response->was_npn_negotiated);
6747 ASSERT_EQ(OK, ReadTransaction(&trans3, &response_data));
6748 EXPECT_EQ("hello!", response_data);
6749
6750 HttpStreamFactory::set_next_protos("");
6751 HttpStreamFactory::set_use_alternate_protocols(false);
6752 }
6753
TEST_F(HttpNetworkTransactionTest,StallAlternateProtocolForNpnSpdy)6754 TEST_F(HttpNetworkTransactionTest, StallAlternateProtocolForNpnSpdy) {
6755 HttpStreamFactory::set_use_alternate_protocols(true);
6756 HttpStreamFactory::set_next_protos(kExpectedNPNString);
6757 SessionDependencies session_deps;
6758
6759 HttpRequestInfo request;
6760 request.method = "GET";
6761 request.url = GURL("http://www.google.com/");
6762 request.load_flags = 0;
6763
6764 MockRead data_reads[] = {
6765 MockRead("HTTP/1.1 200 OK\r\n"),
6766 MockRead(kAlternateProtocolHttpHeader),
6767 MockRead("hello world"),
6768 MockRead(true, OK),
6769 };
6770
6771 StaticSocketDataProvider first_transaction(
6772 data_reads, arraysize(data_reads), NULL, 0);
6773 session_deps.socket_factory.AddSocketDataProvider(&first_transaction);
6774
6775 SSLSocketDataProvider ssl(true, OK);
6776 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
6777 ssl.next_proto = "spdy/2";
6778 ssl.was_npn_negotiated = true;
6779 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
6780
6781 MockConnect never_finishing_connect(false, ERR_IO_PENDING);
6782 StaticSocketDataProvider hanging_alternate_protocol_socket(
6783 NULL, 0, NULL, 0);
6784 hanging_alternate_protocol_socket.set_connect_data(
6785 never_finishing_connect);
6786 session_deps.socket_factory.AddSocketDataProvider(
6787 &hanging_alternate_protocol_socket);
6788
6789 // 2nd request is just a copy of the first one, over HTTP again.
6790 session_deps.socket_factory.AddSocketDataProvider(&first_transaction);
6791
6792 TestCompletionCallback callback;
6793
6794 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
6795 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session));
6796
6797 int rv = trans->Start(&request, &callback, BoundNetLog());
6798 EXPECT_EQ(ERR_IO_PENDING, rv);
6799 EXPECT_EQ(OK, callback.WaitForResult());
6800
6801 const HttpResponseInfo* response = trans->GetResponseInfo();
6802 ASSERT_TRUE(response != NULL);
6803 ASSERT_TRUE(response->headers != NULL);
6804 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
6805
6806 std::string response_data;
6807 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
6808 EXPECT_EQ("hello world", response_data);
6809
6810 trans.reset(new HttpNetworkTransaction(session));
6811
6812 rv = trans->Start(&request, &callback, BoundNetLog());
6813 EXPECT_EQ(ERR_IO_PENDING, rv);
6814 EXPECT_EQ(OK, callback.WaitForResult());
6815
6816 response = trans->GetResponseInfo();
6817 ASSERT_TRUE(response != NULL);
6818 ASSERT_TRUE(response->headers != NULL);
6819 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
6820 EXPECT_FALSE(response->was_fetched_via_spdy);
6821 EXPECT_FALSE(response->was_npn_negotiated);
6822
6823 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
6824 EXPECT_EQ("hello world", response_data);
6825
6826 HttpStreamFactory::set_next_protos("");
6827 HttpStreamFactory::set_use_alternate_protocols(false);
6828 }
6829
6830 class CapturingProxyResolver : public ProxyResolver {
6831 public:
CapturingProxyResolver()6832 CapturingProxyResolver() : ProxyResolver(false /* expects_pac_bytes */) {}
~CapturingProxyResolver()6833 virtual ~CapturingProxyResolver() {}
6834
GetProxyForURL(const GURL & url,ProxyInfo * results,CompletionCallback * callback,RequestHandle * request,const BoundNetLog & net_log)6835 virtual int GetProxyForURL(const GURL& url,
6836 ProxyInfo* results,
6837 CompletionCallback* callback,
6838 RequestHandle* request,
6839 const BoundNetLog& net_log) {
6840 ProxyServer proxy_server(ProxyServer::SCHEME_HTTP,
6841 HostPortPair("myproxy", 80));
6842 results->UseProxyServer(proxy_server);
6843 resolved_.push_back(url);
6844 return OK;
6845 }
6846
CancelRequest(RequestHandle request)6847 virtual void CancelRequest(RequestHandle request) {
6848 NOTREACHED();
6849 }
6850
CancelSetPacScript()6851 virtual void CancelSetPacScript() {
6852 NOTREACHED();
6853 }
6854
SetPacScript(const scoped_refptr<ProxyResolverScriptData> &,CompletionCallback *)6855 virtual int SetPacScript(const scoped_refptr<ProxyResolverScriptData>&,
6856 CompletionCallback* /*callback*/) {
6857 return OK;
6858 }
6859
resolved() const6860 const std::vector<GURL>& resolved() const { return resolved_; }
6861
6862 private:
6863 std::vector<GURL> resolved_;
6864
6865 DISALLOW_COPY_AND_ASSIGN(CapturingProxyResolver);
6866 };
6867
TEST_F(HttpNetworkTransactionTest,UseAlternateProtocolForTunneledNpnSpdy)6868 TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForTunneledNpnSpdy) {
6869 HttpStreamFactory::set_use_alternate_protocols(true);
6870 HttpStreamFactory::set_next_protos(kExpectedNPNString);
6871
6872 ProxyConfig proxy_config;
6873 proxy_config.set_auto_detect(true);
6874 proxy_config.set_pac_url(GURL("http://fooproxyurl"));
6875
6876 CapturingProxyResolver* capturing_proxy_resolver =
6877 new CapturingProxyResolver();
6878 SessionDependencies session_deps(new ProxyService(
6879 new ProxyConfigServiceFixed(proxy_config), capturing_proxy_resolver,
6880 NULL));
6881
6882 HttpRequestInfo request;
6883 request.method = "GET";
6884 request.url = GURL("http://www.google.com/");
6885 request.load_flags = 0;
6886
6887 MockRead data_reads[] = {
6888 MockRead("HTTP/1.1 200 OK\r\n"),
6889 MockRead(kAlternateProtocolHttpHeader),
6890 MockRead("hello world"),
6891 MockRead(true, OK),
6892 };
6893
6894 StaticSocketDataProvider first_transaction(
6895 data_reads, arraysize(data_reads), NULL, 0);
6896 session_deps.socket_factory.AddSocketDataProvider(&first_transaction);
6897
6898 SSLSocketDataProvider ssl(true, OK);
6899 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
6900 ssl.next_proto = "spdy/2";
6901 ssl.was_npn_negotiated = true;
6902 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
6903
6904 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
6905 MockWrite spdy_writes[] = {
6906 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
6907 "Host: www.google.com\r\n"
6908 "Proxy-Connection: keep-alive\r\n\r\n"), // 0
6909 CreateMockWrite(*req) // 3
6910 };
6911
6912 const char kCONNECTResponse[] = "HTTP/1.1 200 Connected\r\n\r\n";
6913
6914 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
6915 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true));
6916 MockRead spdy_reads[] = {
6917 MockRead(true, kCONNECTResponse, arraysize(kCONNECTResponse) - 1, 1), // 1
6918 CreateMockRead(*resp.get(), 4), // 2, 4
6919 CreateMockRead(*data.get(), 4), // 5
6920 MockRead(true, 0, 0, 4), // 6
6921 };
6922
6923 scoped_refptr<OrderedSocketData> spdy_data(
6924 new OrderedSocketData(
6925 spdy_reads, arraysize(spdy_reads),
6926 spdy_writes, arraysize(spdy_writes)));
6927 session_deps.socket_factory.AddSocketDataProvider(spdy_data);
6928
6929 MockConnect never_finishing_connect(false, ERR_IO_PENDING);
6930 StaticSocketDataProvider hanging_non_alternate_protocol_socket(
6931 NULL, 0, NULL, 0);
6932 hanging_non_alternate_protocol_socket.set_connect_data(
6933 never_finishing_connect);
6934 session_deps.socket_factory.AddSocketDataProvider(
6935 &hanging_non_alternate_protocol_socket);
6936
6937 TestCompletionCallback callback;
6938
6939 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
6940 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session));
6941
6942 int rv = trans->Start(&request, &callback, BoundNetLog());
6943 EXPECT_EQ(ERR_IO_PENDING, rv);
6944 EXPECT_EQ(OK, callback.WaitForResult());
6945
6946 const HttpResponseInfo* response = trans->GetResponseInfo();
6947 ASSERT_TRUE(response != NULL);
6948 ASSERT_TRUE(response->headers != NULL);
6949 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
6950 EXPECT_FALSE(response->was_fetched_via_spdy);
6951 EXPECT_FALSE(response->was_npn_negotiated);
6952
6953 std::string response_data;
6954 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
6955 EXPECT_EQ("hello world", response_data);
6956
6957 trans.reset(new HttpNetworkTransaction(session));
6958
6959 rv = trans->Start(&request, &callback, BoundNetLog());
6960 EXPECT_EQ(ERR_IO_PENDING, rv);
6961 EXPECT_EQ(OK, callback.WaitForResult());
6962
6963 response = trans->GetResponseInfo();
6964 ASSERT_TRUE(response != NULL);
6965 ASSERT_TRUE(response->headers != NULL);
6966 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
6967 EXPECT_TRUE(response->was_fetched_via_spdy);
6968 EXPECT_TRUE(response->was_npn_negotiated);
6969
6970 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
6971 EXPECT_EQ("hello!", response_data);
6972 ASSERT_EQ(3u, capturing_proxy_resolver->resolved().size());
6973 EXPECT_EQ("http://www.google.com/",
6974 capturing_proxy_resolver->resolved()[0].spec());
6975 EXPECT_EQ("https://www.google.com/",
6976 capturing_proxy_resolver->resolved()[1].spec());
6977
6978 HttpStreamFactory::set_next_protos("");
6979 HttpStreamFactory::set_use_alternate_protocols(false);
6980 }
6981
TEST_F(HttpNetworkTransactionTest,UseAlternateProtocolForNpnSpdyWithExistingSpdySession)6982 TEST_F(HttpNetworkTransactionTest,
6983 UseAlternateProtocolForNpnSpdyWithExistingSpdySession) {
6984 HttpStreamFactory::set_use_alternate_protocols(true);
6985 HttpStreamFactory::set_next_protos(kExpectedNPNString);
6986 SessionDependencies session_deps;
6987
6988 HttpRequestInfo request;
6989 request.method = "GET";
6990 request.url = GURL("http://www.google.com/");
6991 request.load_flags = 0;
6992
6993 MockRead data_reads[] = {
6994 MockRead("HTTP/1.1 200 OK\r\n"),
6995 MockRead(kAlternateProtocolHttpHeader),
6996 MockRead("hello world"),
6997 MockRead(true, OK),
6998 };
6999
7000 StaticSocketDataProvider first_transaction(
7001 data_reads, arraysize(data_reads), NULL, 0);
7002 session_deps.socket_factory.AddSocketDataProvider(&first_transaction);
7003
7004 SSLSocketDataProvider ssl(true, OK);
7005 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
7006 ssl.next_proto = "spdy/2";
7007 ssl.was_npn_negotiated = true;
7008 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
7009 // Make sure we use ssl for spdy here.
7010 SpdySession::SetSSLMode(true);
7011
7012 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
7013 MockWrite spdy_writes[] = { CreateMockWrite(*req) };
7014
7015 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
7016 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true));
7017 MockRead spdy_reads[] = {
7018 CreateMockRead(*resp),
7019 CreateMockRead(*data),
7020 MockRead(true, 0, 0),
7021 };
7022
7023 scoped_refptr<DelayedSocketData> spdy_data(
7024 new DelayedSocketData(
7025 1, // wait for one write to finish before reading.
7026 spdy_reads, arraysize(spdy_reads),
7027 spdy_writes, arraysize(spdy_writes)));
7028 session_deps.socket_factory.AddSocketDataProvider(spdy_data);
7029
7030 TestCompletionCallback callback;
7031
7032 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
7033
7034 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session));
7035
7036 int rv = trans->Start(&request, &callback, BoundNetLog());
7037 EXPECT_EQ(ERR_IO_PENDING, rv);
7038 EXPECT_EQ(OK, callback.WaitForResult());
7039
7040 const HttpResponseInfo* response = trans->GetResponseInfo();
7041 ASSERT_TRUE(response != NULL);
7042 ASSERT_TRUE(response->headers != NULL);
7043 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
7044
7045 std::string response_data;
7046 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
7047 EXPECT_EQ("hello world", response_data);
7048
7049 // Set up an initial SpdySession in the pool to reuse.
7050 HostPortPair host_port_pair("www.google.com", 443);
7051 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
7052 scoped_refptr<SpdySession> spdy_session =
7053 session->spdy_session_pool()->Get(pair, BoundNetLog());
7054 scoped_refptr<TransportSocketParams> transport_params(
7055 new TransportSocketParams(host_port_pair, MEDIUM, GURL(), false, false));
7056
7057 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
7058 EXPECT_EQ(ERR_IO_PENDING,
7059 connection->Init(host_port_pair.ToString(),
7060 transport_params,
7061 LOWEST,
7062 &callback,
7063 session->transport_socket_pool(),
7064 BoundNetLog()));
7065 EXPECT_EQ(OK, callback.WaitForResult());
7066
7067 SSLConfig ssl_config;
7068 session->ssl_config_service()->GetSSLConfig(&ssl_config);
7069 scoped_ptr<ClientSocketHandle> ssl_connection(new ClientSocketHandle);
7070 ssl_connection->set_socket(session_deps.socket_factory.CreateSSLClientSocket(
7071 connection.release(), HostPortPair("" , 443), ssl_config,
7072 NULL /* ssl_host_info */, session_deps.cert_verifier.get(), NULL));
7073 EXPECT_EQ(ERR_IO_PENDING, ssl_connection->socket()->Connect(&callback));
7074 EXPECT_EQ(OK, callback.WaitForResult());
7075
7076 EXPECT_EQ(OK, spdy_session->InitializeWithSocket(ssl_connection.release(),
7077 true, OK));
7078
7079 trans.reset(new HttpNetworkTransaction(session));
7080
7081 rv = trans->Start(&request, &callback, BoundNetLog());
7082 EXPECT_EQ(ERR_IO_PENDING, rv);
7083 EXPECT_EQ(OK, callback.WaitForResult());
7084
7085 response = trans->GetResponseInfo();
7086 ASSERT_TRUE(response != NULL);
7087 ASSERT_TRUE(response->headers != NULL);
7088 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
7089 EXPECT_TRUE(response->was_fetched_via_spdy);
7090 EXPECT_TRUE(response->was_npn_negotiated);
7091
7092 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
7093 EXPECT_EQ("hello!", response_data);
7094
7095 HttpStreamFactory::set_next_protos("");
7096 HttpStreamFactory::set_use_alternate_protocols(false);
7097 }
7098
7099 // GenerateAuthToken is a mighty big test.
7100 // It tests all permutation of GenerateAuthToken behavior:
7101 // - Synchronous and Asynchronous completion.
7102 // - OK or error on completion.
7103 // - Direct connection, non-authenticating proxy, and authenticating proxy.
7104 // - HTTP or HTTPS backend (to include proxy tunneling).
7105 // - Non-authenticating and authenticating backend.
7106 //
7107 // In all, there are 44 reasonable permuations (for example, if there are
7108 // problems generating an auth token for an authenticating proxy, we don't
7109 // need to test all permutations of the backend server).
7110 //
7111 // The test proceeds by going over each of the configuration cases, and
7112 // potentially running up to three rounds in each of the tests. The TestConfig
7113 // specifies both the configuration for the test as well as the expectations
7114 // for the results.
TEST_F(HttpNetworkTransactionTest,GenerateAuthToken)7115 TEST_F(HttpNetworkTransactionTest, GenerateAuthToken) {
7116 static const char kServer[] = "http://www.example.com";
7117 static const char kSecureServer[] = "https://www.example.com";
7118 static const char kProxy[] = "myproxy:70";
7119 const int kAuthErr = ERR_INVALID_AUTH_CREDENTIALS;
7120
7121 enum AuthTiming {
7122 AUTH_NONE,
7123 AUTH_SYNC,
7124 AUTH_ASYNC,
7125 };
7126
7127 const MockWrite kGet(
7128 "GET / HTTP/1.1\r\n"
7129 "Host: www.example.com\r\n"
7130 "Connection: keep-alive\r\n\r\n");
7131 const MockWrite kGetProxy(
7132 "GET http://www.example.com/ HTTP/1.1\r\n"
7133 "Host: www.example.com\r\n"
7134 "Proxy-Connection: keep-alive\r\n\r\n");
7135 const MockWrite kGetAuth(
7136 "GET / HTTP/1.1\r\n"
7137 "Host: www.example.com\r\n"
7138 "Connection: keep-alive\r\n"
7139 "Authorization: auth_token\r\n\r\n");
7140 const MockWrite kGetProxyAuth(
7141 "GET http://www.example.com/ HTTP/1.1\r\n"
7142 "Host: www.example.com\r\n"
7143 "Proxy-Connection: keep-alive\r\n"
7144 "Proxy-Authorization: auth_token\r\n\r\n");
7145 const MockWrite kGetAuthThroughProxy(
7146 "GET http://www.example.com/ HTTP/1.1\r\n"
7147 "Host: www.example.com\r\n"
7148 "Proxy-Connection: keep-alive\r\n"
7149 "Authorization: auth_token\r\n\r\n");
7150 const MockWrite kGetAuthWithProxyAuth(
7151 "GET http://www.example.com/ HTTP/1.1\r\n"
7152 "Host: www.example.com\r\n"
7153 "Proxy-Connection: keep-alive\r\n"
7154 "Proxy-Authorization: auth_token\r\n"
7155 "Authorization: auth_token\r\n\r\n");
7156 const MockWrite kConnect(
7157 "CONNECT www.example.com:443 HTTP/1.1\r\n"
7158 "Host: www.example.com\r\n"
7159 "Proxy-Connection: keep-alive\r\n\r\n");
7160 const MockWrite kConnectProxyAuth(
7161 "CONNECT www.example.com:443 HTTP/1.1\r\n"
7162 "Host: www.example.com\r\n"
7163 "Proxy-Connection: keep-alive\r\n"
7164 "Proxy-Authorization: auth_token\r\n\r\n");
7165
7166 const MockRead kSuccess(
7167 "HTTP/1.1 200 OK\r\n"
7168 "Content-Type: text/html; charset=iso-8859-1\r\n"
7169 "Content-Length: 3\r\n\r\n"
7170 "Yes");
7171 const MockRead kFailure(
7172 "Should not be called.");
7173 const MockRead kServerChallenge(
7174 "HTTP/1.1 401 Unauthorized\r\n"
7175 "WWW-Authenticate: Mock realm=server\r\n"
7176 "Content-Type: text/html; charset=iso-8859-1\r\n"
7177 "Content-Length: 14\r\n\r\n"
7178 "Unauthorized\r\n");
7179 const MockRead kProxyChallenge(
7180 "HTTP/1.1 407 Unauthorized\r\n"
7181 "Proxy-Authenticate: Mock realm=proxy\r\n"
7182 "Proxy-Connection: close\r\n"
7183 "Content-Type: text/html; charset=iso-8859-1\r\n"
7184 "Content-Length: 14\r\n\r\n"
7185 "Unauthorized\r\n");
7186 const MockRead kProxyConnected(
7187 "HTTP/1.1 200 Connection Established\r\n\r\n");
7188
7189 // NOTE(cbentzel): I wanted TestReadWriteRound to be a simple struct with
7190 // no constructors, but the C++ compiler on Windows warns about
7191 // unspecified data in compound literals. So, moved to using constructors,
7192 // and TestRound's created with the default constructor should not be used.
7193 struct TestRound {
7194 TestRound()
7195 : expected_rv(ERR_UNEXPECTED),
7196 extra_write(NULL),
7197 extra_read(NULL) {
7198 }
7199 TestRound(const MockWrite& write_arg, const MockRead& read_arg,
7200 int expected_rv_arg)
7201 : write(write_arg),
7202 read(read_arg),
7203 expected_rv(expected_rv_arg),
7204 extra_write(NULL),
7205 extra_read(NULL) {
7206 }
7207 TestRound(const MockWrite& write_arg, const MockRead& read_arg,
7208 int expected_rv_arg, const MockWrite* extra_write_arg,
7209 const MockWrite* extra_read_arg)
7210 : write(write_arg),
7211 read(read_arg),
7212 expected_rv(expected_rv_arg),
7213 extra_write(extra_write_arg),
7214 extra_read(extra_read_arg) {
7215 }
7216 MockWrite write;
7217 MockRead read;
7218 int expected_rv;
7219 const MockWrite* extra_write;
7220 const MockRead* extra_read;
7221 };
7222
7223 static const int kNoSSL = 500;
7224
7225 struct TestConfig {
7226 const char* proxy_url;
7227 AuthTiming proxy_auth_timing;
7228 int proxy_auth_rv;
7229 const char* server_url;
7230 AuthTiming server_auth_timing;
7231 int server_auth_rv;
7232 int num_auth_rounds;
7233 int first_ssl_round;
7234 TestRound rounds[3];
7235 } test_configs[] = {
7236 // Non-authenticating HTTP server with a direct connection.
7237 { NULL, AUTH_NONE, OK, kServer, AUTH_NONE, OK, 1, kNoSSL,
7238 { TestRound(kGet, kSuccess, OK)}},
7239 // Authenticating HTTP server with a direct connection.
7240 { NULL, AUTH_NONE, OK, kServer, AUTH_SYNC, OK, 2, kNoSSL,
7241 { TestRound(kGet, kServerChallenge, OK),
7242 TestRound(kGetAuth, kSuccess, OK)}},
7243 { NULL, AUTH_NONE, OK, kServer, AUTH_SYNC, kAuthErr, 2, kNoSSL,
7244 { TestRound(kGet, kServerChallenge, OK),
7245 TestRound(kGetAuth, kFailure, kAuthErr)}},
7246 { NULL, AUTH_NONE, OK, kServer, AUTH_ASYNC, OK, 2, kNoSSL,
7247 { TestRound(kGet, kServerChallenge, OK),
7248 TestRound(kGetAuth, kSuccess, OK)}},
7249 { NULL, AUTH_NONE, OK, kServer, AUTH_ASYNC, kAuthErr, 2, kNoSSL,
7250 { TestRound(kGet, kServerChallenge, OK),
7251 TestRound(kGetAuth, kFailure, kAuthErr)}},
7252 // Non-authenticating HTTP server through a non-authenticating proxy.
7253 { kProxy, AUTH_NONE, OK, kServer, AUTH_NONE, OK, 1, kNoSSL,
7254 { TestRound(kGetProxy, kSuccess, OK)}},
7255 // Authenticating HTTP server through a non-authenticating proxy.
7256 { kProxy, AUTH_NONE, OK, kServer, AUTH_SYNC, OK, 2, kNoSSL,
7257 { TestRound(kGetProxy, kServerChallenge, OK),
7258 TestRound(kGetAuthThroughProxy, kSuccess, OK)}},
7259 { kProxy, AUTH_NONE, OK, kServer, AUTH_SYNC, kAuthErr, 2, kNoSSL,
7260 { TestRound(kGetProxy, kServerChallenge, OK),
7261 TestRound(kGetAuthThroughProxy, kFailure, kAuthErr)}},
7262 { kProxy, AUTH_NONE, OK, kServer, AUTH_ASYNC, OK, 2, kNoSSL,
7263 { TestRound(kGetProxy, kServerChallenge, OK),
7264 TestRound(kGetAuthThroughProxy, kSuccess, OK)}},
7265 { kProxy, AUTH_NONE, OK, kServer, AUTH_ASYNC, kAuthErr, 2, kNoSSL,
7266 { TestRound(kGetProxy, kServerChallenge, OK),
7267 TestRound(kGetAuthThroughProxy, kFailure, kAuthErr)}},
7268 // Non-authenticating HTTP server through an authenticating proxy.
7269 { kProxy, AUTH_SYNC, OK, kServer, AUTH_NONE, OK, 2, kNoSSL,
7270 { TestRound(kGetProxy, kProxyChallenge, OK),
7271 TestRound(kGetProxyAuth, kSuccess, OK)}},
7272 { kProxy, AUTH_SYNC, kAuthErr, kServer, AUTH_NONE, OK, 2, kNoSSL,
7273 { TestRound(kGetProxy, kProxyChallenge, OK),
7274 TestRound(kGetProxyAuth, kFailure, kAuthErr)}},
7275 { kProxy, AUTH_ASYNC, OK, kServer, AUTH_NONE, OK, 2, kNoSSL,
7276 { TestRound(kGetProxy, kProxyChallenge, OK),
7277 TestRound(kGetProxyAuth, kSuccess, OK)}},
7278 { kProxy, AUTH_ASYNC, kAuthErr, kServer, AUTH_NONE, OK, 2, kNoSSL,
7279 { TestRound(kGetProxy, kProxyChallenge, OK),
7280 TestRound(kGetProxyAuth, kFailure, kAuthErr)}},
7281 // Authenticating HTTP server through an authenticating proxy.
7282 { kProxy, AUTH_SYNC, OK, kServer, AUTH_SYNC, OK, 3, kNoSSL,
7283 { TestRound(kGetProxy, kProxyChallenge, OK),
7284 TestRound(kGetProxyAuth, kServerChallenge, OK),
7285 TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}},
7286 { kProxy, AUTH_SYNC, OK, kServer, AUTH_SYNC, kAuthErr, 3, kNoSSL,
7287 { TestRound(kGetProxy, kProxyChallenge, OK),
7288 TestRound(kGetProxyAuth, kServerChallenge, OK),
7289 TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}},
7290 { kProxy, AUTH_ASYNC, OK, kServer, AUTH_SYNC, OK, 3, kNoSSL,
7291 { TestRound(kGetProxy, kProxyChallenge, OK),
7292 TestRound(kGetProxyAuth, kServerChallenge, OK),
7293 TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}},
7294 { kProxy, AUTH_ASYNC, OK, kServer, AUTH_SYNC, kAuthErr, 3, kNoSSL,
7295 { TestRound(kGetProxy, kProxyChallenge, OK),
7296 TestRound(kGetProxyAuth, kServerChallenge, OK),
7297 TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}},
7298 { kProxy, AUTH_SYNC, OK, kServer, AUTH_ASYNC, OK, 3, kNoSSL,
7299 { TestRound(kGetProxy, kProxyChallenge, OK),
7300 TestRound(kGetProxyAuth, kServerChallenge, OK),
7301 TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}},
7302 { kProxy, AUTH_SYNC, OK, kServer, AUTH_ASYNC, kAuthErr, 3, kNoSSL,
7303 { TestRound(kGetProxy, kProxyChallenge, OK),
7304 TestRound(kGetProxyAuth, kServerChallenge, OK),
7305 TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}},
7306 { kProxy, AUTH_ASYNC, OK, kServer, AUTH_ASYNC, OK, 3, kNoSSL,
7307 { TestRound(kGetProxy, kProxyChallenge, OK),
7308 TestRound(kGetProxyAuth, kServerChallenge, OK),
7309 TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}},
7310 { kProxy, AUTH_ASYNC, OK, kServer, AUTH_ASYNC, kAuthErr, 3, kNoSSL,
7311 { TestRound(kGetProxy, kProxyChallenge, OK),
7312 TestRound(kGetProxyAuth, kServerChallenge, OK),
7313 TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}},
7314 // Non-authenticating HTTPS server with a direct connection.
7315 { NULL, AUTH_NONE, OK, kSecureServer, AUTH_NONE, OK, 1, 0,
7316 { TestRound(kGet, kSuccess, OK)}},
7317 // Authenticating HTTPS server with a direct connection.
7318 { NULL, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, OK, 2, 0,
7319 { TestRound(kGet, kServerChallenge, OK),
7320 TestRound(kGetAuth, kSuccess, OK)}},
7321 { NULL, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, kAuthErr, 2, 0,
7322 { TestRound(kGet, kServerChallenge, OK),
7323 TestRound(kGetAuth, kFailure, kAuthErr)}},
7324 { NULL, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, OK, 2, 0,
7325 { TestRound(kGet, kServerChallenge, OK),
7326 TestRound(kGetAuth, kSuccess, OK)}},
7327 { NULL, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 2, 0,
7328 { TestRound(kGet, kServerChallenge, OK),
7329 TestRound(kGetAuth, kFailure, kAuthErr)}},
7330 // Non-authenticating HTTPS server with a non-authenticating proxy.
7331 { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_NONE, OK, 1, 0,
7332 { TestRound(kConnect, kProxyConnected, OK, &kGet, &kSuccess)}},
7333 // Authenticating HTTPS server through a non-authenticating proxy.
7334 { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, OK, 2, 0,
7335 { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge),
7336 TestRound(kGetAuth, kSuccess, OK)}},
7337 { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, kAuthErr, 2, 0,
7338 { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge),
7339 TestRound(kGetAuth, kFailure, kAuthErr)}},
7340 { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, OK, 2, 0,
7341 { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge),
7342 TestRound(kGetAuth, kSuccess, OK)}},
7343 { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 2, 0,
7344 { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge),
7345 TestRound(kGetAuth, kFailure, kAuthErr)}},
7346 // Non-Authenticating HTTPS server through an authenticating proxy.
7347 { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_NONE, OK, 2, 1,
7348 { TestRound(kConnect, kProxyChallenge, OK),
7349 TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet, &kSuccess)}},
7350 { kProxy, AUTH_SYNC, kAuthErr, kSecureServer, AUTH_NONE, OK, 2, kNoSSL,
7351 { TestRound(kConnect, kProxyChallenge, OK),
7352 TestRound(kConnectProxyAuth, kFailure, kAuthErr)}},
7353 { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_NONE, OK, 2, 1,
7354 { TestRound(kConnect, kProxyChallenge, OK),
7355 TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet, &kSuccess)}},
7356 { kProxy, AUTH_ASYNC, kAuthErr, kSecureServer, AUTH_NONE, OK, 2, kNoSSL,
7357 { TestRound(kConnect, kProxyChallenge, OK),
7358 TestRound(kConnectProxyAuth, kFailure, kAuthErr)}},
7359 // Authenticating HTTPS server through an authenticating proxy.
7360 { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_SYNC, OK, 3, 1,
7361 { TestRound(kConnect, kProxyChallenge, OK),
7362 TestRound(kConnectProxyAuth, kProxyConnected, OK,
7363 &kGet, &kServerChallenge),
7364 TestRound(kGetAuth, kSuccess, OK)}},
7365 { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_SYNC, kAuthErr, 3, 1,
7366 { TestRound(kConnect, kProxyChallenge, OK),
7367 TestRound(kConnectProxyAuth, kProxyConnected, OK,
7368 &kGet, &kServerChallenge),
7369 TestRound(kGetAuth, kFailure, kAuthErr)}},
7370 { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_SYNC, OK, 3, 1,
7371 { TestRound(kConnect, kProxyChallenge, OK),
7372 TestRound(kConnectProxyAuth, kProxyConnected, OK,
7373 &kGet, &kServerChallenge),
7374 TestRound(kGetAuth, kSuccess, OK)}},
7375 { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_SYNC, kAuthErr, 3, 1,
7376 { TestRound(kConnect, kProxyChallenge, OK),
7377 TestRound(kConnectProxyAuth, kProxyConnected, OK,
7378 &kGet, &kServerChallenge),
7379 TestRound(kGetAuth, kFailure, kAuthErr)}},
7380 { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_ASYNC, OK, 3, 1,
7381 { TestRound(kConnect, kProxyChallenge, OK),
7382 TestRound(kConnectProxyAuth, kProxyConnected, OK,
7383 &kGet, &kServerChallenge),
7384 TestRound(kGetAuth, kSuccess, OK)}},
7385 { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 3, 1,
7386 { TestRound(kConnect, kProxyChallenge, OK),
7387 TestRound(kConnectProxyAuth, kProxyConnected, OK,
7388 &kGet, &kServerChallenge),
7389 TestRound(kGetAuth, kFailure, kAuthErr)}},
7390 { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_ASYNC, OK, 3, 1,
7391 { TestRound(kConnect, kProxyChallenge, OK),
7392 TestRound(kConnectProxyAuth, kProxyConnected, OK,
7393 &kGet, &kServerChallenge),
7394 TestRound(kGetAuth, kSuccess, OK)}},
7395 { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 3, 1,
7396 { TestRound(kConnect, kProxyChallenge, OK),
7397 TestRound(kConnectProxyAuth, kProxyConnected, OK,
7398 &kGet, &kServerChallenge),
7399 TestRound(kGetAuth, kFailure, kAuthErr)}},
7400 };
7401
7402 SessionDependencies session_deps;
7403 HttpAuthHandlerMock::Factory* auth_factory(
7404 new HttpAuthHandlerMock::Factory());
7405 session_deps.http_auth_handler_factory.reset(auth_factory);
7406
7407 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_configs); ++i) {
7408 const TestConfig& test_config = test_configs[i];
7409
7410 // Set up authentication handlers as necessary.
7411 if (test_config.proxy_auth_timing != AUTH_NONE) {
7412 HttpAuthHandlerMock* auth_handler(new HttpAuthHandlerMock());
7413 std::string auth_challenge = "Mock realm=proxy";
7414 GURL origin(test_config.proxy_url);
7415 HttpAuth::ChallengeTokenizer tokenizer(auth_challenge.begin(),
7416 auth_challenge.end());
7417 auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_PROXY,
7418 origin, BoundNetLog());
7419 auth_handler->SetGenerateExpectation(
7420 test_config.proxy_auth_timing == AUTH_ASYNC,
7421 test_config.proxy_auth_rv);
7422 auth_factory->set_mock_handler(auth_handler, HttpAuth::AUTH_PROXY);
7423 }
7424 if (test_config.server_auth_timing != AUTH_NONE) {
7425 HttpAuthHandlerMock* auth_handler(new HttpAuthHandlerMock());
7426 std::string auth_challenge = "Mock realm=server";
7427 GURL origin(test_config.server_url);
7428 HttpAuth::ChallengeTokenizer tokenizer(auth_challenge.begin(),
7429 auth_challenge.end());
7430 auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_SERVER,
7431 origin, BoundNetLog());
7432 auth_handler->SetGenerateExpectation(
7433 test_config.server_auth_timing == AUTH_ASYNC,
7434 test_config.server_auth_rv);
7435 auth_factory->set_mock_handler(auth_handler, HttpAuth::AUTH_SERVER);
7436 }
7437 if (test_config.proxy_url) {
7438 session_deps.proxy_service =
7439 ProxyService::CreateFixed(test_config.proxy_url);
7440 } else {
7441 session_deps.proxy_service = ProxyService::CreateDirect();
7442 }
7443
7444 HttpRequestInfo request;
7445 request.method = "GET";
7446 request.url = GURL(test_config.server_url);
7447 request.load_flags = 0;
7448
7449 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
7450 HttpNetworkTransaction trans(CreateSession(&session_deps));
7451
7452 for (int round = 0; round < test_config.num_auth_rounds; ++round) {
7453 const TestRound& read_write_round = test_config.rounds[round];
7454
7455 // Set up expected reads and writes.
7456 MockRead reads[2];
7457 reads[0] = read_write_round.read;
7458 size_t length_reads = 1;
7459 if (read_write_round.extra_read) {
7460 reads[1] = *read_write_round.extra_read;
7461 length_reads = 2;
7462 }
7463
7464 MockWrite writes[2];
7465 writes[0] = read_write_round.write;
7466 size_t length_writes = 1;
7467 if (read_write_round.extra_write) {
7468 writes[1] = *read_write_round.extra_write;
7469 length_writes = 2;
7470 }
7471 StaticSocketDataProvider data_provider(
7472 reads, length_reads, writes, length_writes);
7473 session_deps.socket_factory.AddSocketDataProvider(&data_provider);
7474
7475 // Add an SSL sequence if necessary.
7476 SSLSocketDataProvider ssl_socket_data_provider(false, OK);
7477 if (round >= test_config.first_ssl_round)
7478 session_deps.socket_factory.AddSSLSocketDataProvider(
7479 &ssl_socket_data_provider);
7480
7481 // Start or restart the transaction.
7482 TestCompletionCallback callback;
7483 int rv;
7484 if (round == 0) {
7485 rv = trans.Start(&request, &callback, BoundNetLog());
7486 } else {
7487 rv = trans.RestartWithAuth(kFoo, kBar, &callback);
7488 }
7489 if (rv == ERR_IO_PENDING)
7490 rv = callback.WaitForResult();
7491
7492 // Compare results with expected data.
7493 EXPECT_EQ(read_write_round.expected_rv, rv);
7494 const HttpResponseInfo* response = trans.GetResponseInfo();
7495 if (read_write_round.expected_rv == OK) {
7496 EXPECT_FALSE(response == NULL);
7497 } else {
7498 EXPECT_TRUE(response == NULL);
7499 EXPECT_EQ(round + 1, test_config.num_auth_rounds);
7500 continue;
7501 }
7502 if (round + 1 < test_config.num_auth_rounds) {
7503 EXPECT_FALSE(response->auth_challenge.get() == NULL);
7504 } else {
7505 EXPECT_TRUE(response->auth_challenge.get() == NULL);
7506 }
7507 }
7508 }
7509 }
7510
TEST_F(HttpNetworkTransactionTest,MultiRoundAuth)7511 TEST_F(HttpNetworkTransactionTest, MultiRoundAuth) {
7512 // Do multi-round authentication and make sure it works correctly.
7513 SessionDependencies session_deps;
7514 HttpAuthHandlerMock::Factory* auth_factory(
7515 new HttpAuthHandlerMock::Factory());
7516 session_deps.http_auth_handler_factory.reset(auth_factory);
7517 session_deps.proxy_service = ProxyService::CreateDirect();
7518 session_deps.host_resolver->rules()->AddRule("www.example.com", "10.0.0.1");
7519 session_deps.host_resolver->set_synchronous_mode(true);
7520
7521 HttpAuthHandlerMock* auth_handler(new HttpAuthHandlerMock());
7522 auth_handler->set_connection_based(true);
7523 std::string auth_challenge = "Mock realm=server";
7524 GURL origin("http://www.example.com");
7525 HttpAuth::ChallengeTokenizer tokenizer(auth_challenge.begin(),
7526 auth_challenge.end());
7527 auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_SERVER,
7528 origin, BoundNetLog());
7529 auth_factory->set_mock_handler(auth_handler, HttpAuth::AUTH_SERVER);
7530
7531 int rv = OK;
7532 const HttpResponseInfo* response = NULL;
7533 HttpRequestInfo request;
7534 request.method = "GET";
7535 request.url = origin;
7536 request.load_flags = 0;
7537
7538 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
7539
7540 // Use a TCP Socket Pool with only one connection per group. This is used
7541 // to validate that the TCP socket is not released to the pool between
7542 // each round of multi-round authentication.
7543 HttpNetworkSessionPeer session_peer(session);
7544 ClientSocketPoolHistograms transport_pool_histograms("SmallTCP");
7545 TransportClientSocketPool* transport_pool = new TransportClientSocketPool(
7546 50, // Max sockets for pool
7547 1, // Max sockets per group
7548 &transport_pool_histograms,
7549 session_deps.host_resolver.get(),
7550 &session_deps.socket_factory,
7551 session_deps.net_log);
7552 session_peer.SetTransportSocketPool(transport_pool);
7553
7554 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
7555 TestCompletionCallback callback;
7556
7557 const MockWrite kGet(
7558 "GET / HTTP/1.1\r\n"
7559 "Host: www.example.com\r\n"
7560 "Connection: keep-alive\r\n\r\n");
7561 const MockWrite kGetAuth(
7562 "GET / HTTP/1.1\r\n"
7563 "Host: www.example.com\r\n"
7564 "Connection: keep-alive\r\n"
7565 "Authorization: auth_token\r\n\r\n");
7566
7567 const MockRead kServerChallenge(
7568 "HTTP/1.1 401 Unauthorized\r\n"
7569 "WWW-Authenticate: Mock realm=server\r\n"
7570 "Content-Type: text/html; charset=iso-8859-1\r\n"
7571 "Content-Length: 14\r\n\r\n"
7572 "Unauthorized\r\n");
7573 const MockRead kSuccess(
7574 "HTTP/1.1 200 OK\r\n"
7575 "Content-Type: text/html; charset=iso-8859-1\r\n"
7576 "Content-Length: 3\r\n\r\n"
7577 "Yes");
7578
7579 MockWrite writes[] = {
7580 // First round
7581 kGet,
7582 // Second round
7583 kGetAuth,
7584 // Third round
7585 kGetAuth,
7586 // Fourth round
7587 kGetAuth,
7588 // Competing request
7589 kGet,
7590 };
7591 MockRead reads[] = {
7592 // First round
7593 kServerChallenge,
7594 // Second round
7595 kServerChallenge,
7596 // Third round
7597 kServerChallenge,
7598 // Fourth round
7599 kSuccess,
7600 // Competing response
7601 kSuccess,
7602 };
7603 StaticSocketDataProvider data_provider(reads, arraysize(reads),
7604 writes, arraysize(writes));
7605 session_deps.socket_factory.AddSocketDataProvider(&data_provider);
7606
7607 const char* const kSocketGroup = "www.example.com:80";
7608
7609 // First round of authentication.
7610 auth_handler->SetGenerateExpectation(false, OK);
7611 rv = trans->Start(&request, &callback, BoundNetLog());
7612 if (rv == ERR_IO_PENDING)
7613 rv = callback.WaitForResult();
7614 EXPECT_EQ(OK, rv);
7615 response = trans->GetResponseInfo();
7616 ASSERT_FALSE(response == NULL);
7617 EXPECT_FALSE(response->auth_challenge.get() == NULL);
7618 EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup));
7619
7620 // In between rounds, another request comes in for the same domain.
7621 // It should not be able to grab the TCP socket that trans has already
7622 // claimed.
7623 scoped_ptr<HttpTransaction> trans_compete(
7624 new HttpNetworkTransaction(session));
7625 TestCompletionCallback callback_compete;
7626 rv = trans_compete->Start(&request, &callback_compete, BoundNetLog());
7627 EXPECT_EQ(ERR_IO_PENDING, rv);
7628 // callback_compete.WaitForResult at this point would stall forever,
7629 // since the HttpNetworkTransaction does not release the request back to
7630 // the pool until after authentication completes.
7631
7632 // Second round of authentication.
7633 auth_handler->SetGenerateExpectation(false, OK);
7634 rv = trans->RestartWithAuth(kFoo, kBar, &callback);
7635 if (rv == ERR_IO_PENDING)
7636 rv = callback.WaitForResult();
7637 EXPECT_EQ(OK, rv);
7638 response = trans->GetResponseInfo();
7639 ASSERT_FALSE(response == NULL);
7640 EXPECT_TRUE(response->auth_challenge.get() == NULL);
7641 EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup));
7642
7643 // Third round of authentication.
7644 auth_handler->SetGenerateExpectation(false, OK);
7645 rv = trans->RestartWithAuth(string16(), string16(), &callback);
7646 if (rv == ERR_IO_PENDING)
7647 rv = callback.WaitForResult();
7648 EXPECT_EQ(OK, rv);
7649 response = trans->GetResponseInfo();
7650 ASSERT_FALSE(response == NULL);
7651 EXPECT_TRUE(response->auth_challenge.get() == NULL);
7652 EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup));
7653
7654 // Fourth round of authentication, which completes successfully.
7655 auth_handler->SetGenerateExpectation(false, OK);
7656 rv = trans->RestartWithAuth(string16(), string16(), &callback);
7657 if (rv == ERR_IO_PENDING)
7658 rv = callback.WaitForResult();
7659 EXPECT_EQ(OK, rv);
7660 response = trans->GetResponseInfo();
7661 ASSERT_FALSE(response == NULL);
7662 EXPECT_TRUE(response->auth_challenge.get() == NULL);
7663 EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup));
7664
7665 // Read the body since the fourth round was successful. This will also
7666 // release the socket back to the pool.
7667 scoped_refptr<IOBufferWithSize> io_buf(new IOBufferWithSize(50));
7668 rv = trans->Read(io_buf, io_buf->size(), &callback);
7669 if (rv == ERR_IO_PENDING)
7670 rv = callback.WaitForResult();
7671 EXPECT_EQ(3, rv);
7672 rv = trans->Read(io_buf, io_buf->size(), &callback);
7673 EXPECT_EQ(0, rv);
7674 // There are still 0 idle sockets, since the trans_compete transaction
7675 // will be handed it immediately after trans releases it to the group.
7676 EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup));
7677
7678 // The competing request can now finish. Wait for the headers and then
7679 // read the body.
7680 rv = callback_compete.WaitForResult();
7681 EXPECT_EQ(OK, rv);
7682 rv = trans_compete->Read(io_buf, io_buf->size(), &callback);
7683 if (rv == ERR_IO_PENDING)
7684 rv = callback.WaitForResult();
7685 EXPECT_EQ(3, rv);
7686 rv = trans_compete->Read(io_buf, io_buf->size(), &callback);
7687 EXPECT_EQ(0, rv);
7688
7689 // Finally, the socket is released to the group.
7690 EXPECT_EQ(1, transport_pool->IdleSocketCountInGroup(kSocketGroup));
7691 }
7692
7693 class TLSDecompressionFailureSocketDataProvider : public SocketDataProvider {
7694 public:
TLSDecompressionFailureSocketDataProvider(bool fail_all)7695 explicit TLSDecompressionFailureSocketDataProvider(bool fail_all)
7696 : fail_all_(fail_all) {
7697 }
7698
GetNextRead()7699 virtual MockRead GetNextRead() {
7700 if (fail_all_)
7701 return MockRead(false /* async */, ERR_SSL_DECOMPRESSION_FAILURE_ALERT);
7702
7703 return MockRead(false /* async */,
7704 "HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nok.\r\n");
7705 }
7706
OnWrite(const std::string & data)7707 virtual MockWriteResult OnWrite(const std::string& data) {
7708 return MockWriteResult(false /* async */, data.size());
7709 }
7710
Reset()7711 void Reset() {
7712 }
7713
7714 private:
7715 const bool fail_all_;
7716 };
7717
7718 // Test that we restart a connection when we see a decompression failure from
7719 // the peer during the handshake. (In the real world we'll restart with SSLv3
7720 // and we won't offer DEFLATE in that case.)
TEST_F(HttpNetworkTransactionTest,RestartAfterTLSDecompressionFailure)7721 TEST_F(HttpNetworkTransactionTest, RestartAfterTLSDecompressionFailure) {
7722 HttpRequestInfo request;
7723 request.method = "GET";
7724 request.url = GURL("https://tlsdecompressionfailure.example.com/");
7725 request.load_flags = 0;
7726
7727 SessionDependencies session_deps;
7728 TLSDecompressionFailureSocketDataProvider socket_data_provider1(
7729 false /* fail all reads */);
7730 TLSDecompressionFailureSocketDataProvider socket_data_provider2(false);
7731 SSLSocketDataProvider ssl_socket_data_provider1(
7732 false, ERR_SSL_DECOMPRESSION_FAILURE_ALERT);
7733 SSLSocketDataProvider ssl_socket_data_provider2(false, OK);
7734 session_deps.socket_factory.AddSocketDataProvider(&socket_data_provider1);
7735 session_deps.socket_factory.AddSocketDataProvider(&socket_data_provider2);
7736 session_deps.socket_factory.AddSSLSocketDataProvider(
7737 &ssl_socket_data_provider1);
7738 session_deps.socket_factory.AddSSLSocketDataProvider(
7739 &ssl_socket_data_provider2);
7740
7741 // Work around http://crbug.com/37454
7742 StaticSocketDataProvider bug37454_connection;
7743 bug37454_connection.set_connect_data(MockConnect(true, ERR_UNEXPECTED));
7744 session_deps.socket_factory.AddSocketDataProvider(&bug37454_connection);
7745
7746 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
7747 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
7748 TestCompletionCallback callback;
7749
7750 int rv = trans->Start(&request, &callback, BoundNetLog());
7751 EXPECT_EQ(ERR_IO_PENDING, rv);
7752 EXPECT_EQ(OK, callback.WaitForResult());
7753
7754 const HttpResponseInfo* response = trans->GetResponseInfo();
7755 ASSERT_TRUE(response != NULL);
7756 ASSERT_TRUE(response->headers != NULL);
7757 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
7758
7759 std::string response_data;
7760 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
7761 EXPECT_EQ("ok.", response_data);
7762 }
7763
7764 // Test that we restart a connection if we get a decompression failure from the
7765 // peer while reading the first bytes from the connection. This occurs when the
7766 // peer cannot handle DEFLATE but we're using False Start, so we don't notice
7767 // in the handshake.
TEST_F(HttpNetworkTransactionTest,RestartAfterTLSDecompressionFailureWithFalseStart)7768 TEST_F(HttpNetworkTransactionTest,
7769 RestartAfterTLSDecompressionFailureWithFalseStart) {
7770 HttpRequestInfo request;
7771 request.method = "GET";
7772 request.url = GURL("https://tlsdecompressionfailure2.example.com/");
7773 request.load_flags = 0;
7774
7775 SessionDependencies session_deps;
7776 TLSDecompressionFailureSocketDataProvider socket_data_provider1(
7777 true /* fail all reads */);
7778 TLSDecompressionFailureSocketDataProvider socket_data_provider2(false);
7779 SSLSocketDataProvider ssl_socket_data_provider1(false, OK);
7780 SSLSocketDataProvider ssl_socket_data_provider2(false, OK);
7781 session_deps.socket_factory.AddSocketDataProvider(&socket_data_provider1);
7782 session_deps.socket_factory.AddSocketDataProvider(&socket_data_provider2);
7783 session_deps.socket_factory.AddSSLSocketDataProvider(
7784 &ssl_socket_data_provider1);
7785 session_deps.socket_factory.AddSSLSocketDataProvider(
7786 &ssl_socket_data_provider2);
7787
7788 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
7789 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
7790 TestCompletionCallback callback;
7791
7792 int rv = trans->Start(&request, &callback, BoundNetLog());
7793 EXPECT_EQ(ERR_IO_PENDING, rv);
7794 EXPECT_EQ(OK, callback.WaitForResult());
7795
7796 const HttpResponseInfo* response = trans->GetResponseInfo();
7797 ASSERT_TRUE(response != NULL);
7798 ASSERT_TRUE(response->headers != NULL);
7799 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
7800
7801 std::string response_data;
7802 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
7803 EXPECT_EQ("ok.", response_data);
7804 }
7805
7806 // This tests the case that a request is issued via http instead of spdy after
7807 // npn is negotiated.
TEST_F(HttpNetworkTransactionTest,NpnWithHttpOverSSL)7808 TEST_F(HttpNetworkTransactionTest, NpnWithHttpOverSSL) {
7809 HttpStreamFactory::set_use_alternate_protocols(true);
7810 HttpStreamFactory::set_next_protos("\x08http/1.1\x07http1.1");
7811 SessionDependencies session_deps;
7812 HttpRequestInfo request;
7813 request.method = "GET";
7814 request.url = GURL("https://www.google.com/");
7815 request.load_flags = 0;
7816
7817 MockWrite data_writes[] = {
7818 MockWrite("GET / HTTP/1.1\r\n"
7819 "Host: www.google.com\r\n"
7820 "Connection: keep-alive\r\n\r\n"),
7821 };
7822
7823 MockRead data_reads[] = {
7824 MockRead("HTTP/1.1 200 OK\r\n"),
7825 MockRead(kAlternateProtocolHttpHeader),
7826 MockRead("hello world"),
7827 MockRead(false, OK),
7828 };
7829
7830 SSLSocketDataProvider ssl(true, OK);
7831 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
7832 ssl.next_proto = "http/1.1";
7833
7834 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
7835
7836 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
7837 data_writes, arraysize(data_writes));
7838 session_deps.socket_factory.AddSocketDataProvider(&data);
7839
7840 TestCompletionCallback callback;
7841
7842 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
7843 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
7844
7845 int rv = trans->Start(&request, &callback, BoundNetLog());
7846
7847 EXPECT_EQ(ERR_IO_PENDING, rv);
7848 EXPECT_EQ(OK, callback.WaitForResult());
7849
7850 const HttpResponseInfo* response = trans->GetResponseInfo();
7851 ASSERT_TRUE(response != NULL);
7852 ASSERT_TRUE(response->headers != NULL);
7853 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
7854
7855 std::string response_data;
7856 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
7857 EXPECT_EQ("hello world", response_data);
7858
7859 EXPECT_FALSE(response->was_fetched_via_spdy);
7860 EXPECT_TRUE(response->was_npn_negotiated);
7861
7862 HttpStreamFactory::set_next_protos("");
7863 HttpStreamFactory::set_use_alternate_protocols(false);
7864 }
7865
TEST_F(HttpNetworkTransactionTest,SpdyPostNPNServerHangup)7866 TEST_F(HttpNetworkTransactionTest, SpdyPostNPNServerHangup) {
7867 // Simulate the SSL handshake completing with an NPN negotiation
7868 // followed by an immediate server closing of the socket.
7869 // Fix crash: http://crbug.com/46369
7870 HttpStreamFactory::set_use_alternate_protocols(true);
7871 HttpStreamFactory::set_next_protos(kExpectedNPNString);
7872 SessionDependencies session_deps;
7873
7874 HttpRequestInfo request;
7875 request.method = "GET";
7876 request.url = GURL("https://www.google.com/");
7877 request.load_flags = 0;
7878
7879 SSLSocketDataProvider ssl(true, OK);
7880 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
7881 ssl.next_proto = "spdy/2";
7882 ssl.was_npn_negotiated = true;
7883 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
7884
7885 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
7886 MockWrite spdy_writes[] = { CreateMockWrite(*req) };
7887
7888 MockRead spdy_reads[] = {
7889 MockRead(false, 0, 0) // Not async - return 0 immediately.
7890 };
7891
7892 scoped_refptr<DelayedSocketData> spdy_data(
7893 new DelayedSocketData(
7894 0, // don't wait in this case, immediate hangup.
7895 spdy_reads, arraysize(spdy_reads),
7896 spdy_writes, arraysize(spdy_writes)));
7897 session_deps.socket_factory.AddSocketDataProvider(spdy_data);
7898
7899 TestCompletionCallback callback;
7900
7901 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
7902 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session));
7903
7904 int rv = trans->Start(&request, &callback, BoundNetLog());
7905 EXPECT_EQ(ERR_IO_PENDING, rv);
7906 EXPECT_EQ(ERR_CONNECTION_CLOSED, callback.WaitForResult());
7907
7908 HttpStreamFactory::set_next_protos("");
7909 HttpStreamFactory::set_use_alternate_protocols(false);
7910 }
7911
TEST_F(HttpNetworkTransactionTest,SpdyAlternateProtocolThroughProxy)7912 TEST_F(HttpNetworkTransactionTest, SpdyAlternateProtocolThroughProxy) {
7913 // This test ensures that the URL passed into the proxy is upgraded
7914 // to https when doing an Alternate Protocol upgrade.
7915 HttpStreamFactory::set_use_alternate_protocols(true);
7916 HttpStreamFactory::set_next_protos(
7917 "\x08http/1.1\x07http1.1\x06spdy/2\x04spdy");
7918
7919 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70"));
7920 HttpAuthHandlerMock::Factory* auth_factory =
7921 new HttpAuthHandlerMock::Factory();
7922 HttpAuthHandlerMock* auth_handler = new HttpAuthHandlerMock();
7923 auth_factory->set_mock_handler(auth_handler, HttpAuth::AUTH_PROXY);
7924 auth_factory->set_do_init_from_challenge(true);
7925 session_deps.http_auth_handler_factory.reset(auth_factory);
7926
7927 HttpRequestInfo request;
7928 request.method = "GET";
7929 request.url = GURL("http://www.google.com");
7930 request.load_flags = 0;
7931
7932 // First round goes unauthenticated through the proxy.
7933 MockWrite data_writes_1[] = {
7934 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
7935 "Host: www.google.com\r\n"
7936 "Proxy-Connection: keep-alive\r\n"
7937 "\r\n"),
7938 };
7939 MockRead data_reads_1[] = {
7940 MockRead(false, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
7941 MockRead("HTTP/1.1 200 OK\r\n"
7942 "Alternate-Protocol: 443:npn-spdy/2\r\n"
7943 "Proxy-Connection: close\r\n"
7944 "\r\n"),
7945 };
7946 StaticSocketDataProvider data_1(data_reads_1, arraysize(data_reads_1),
7947 data_writes_1, arraysize(data_writes_1));
7948
7949 // Second round tries to tunnel to www.google.com due to the
7950 // Alternate-Protocol announcement in the first round. It fails due
7951 // to a proxy authentication challenge.
7952 // After the failure, a tunnel is established to www.google.com using
7953 // Proxy-Authorization headers. There is then a SPDY request round.
7954 //
7955 // NOTE: Despite the "Proxy-Connection: Close", these are done on the
7956 // same MockTCPClientSocket since the underlying HttpNetworkClientSocket
7957 // does a Disconnect and Connect on the same socket, rather than trying
7958 // to obtain a new one.
7959 //
7960 // NOTE: Originally, the proxy response to the second CONNECT request
7961 // simply returned another 407 so the unit test could skip the SSL connection
7962 // establishment and SPDY framing issues. Alas, the
7963 // retry-http-when-alternate-protocol fails logic kicks in, which was more
7964 // complicated to set up expectations for than the SPDY session.
7965
7966 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
7967 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
7968 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true));
7969
7970 MockWrite data_writes_2[] = {
7971 // First connection attempt without Proxy-Authorization.
7972 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
7973 "Host: www.google.com\r\n"
7974 "Proxy-Connection: keep-alive\r\n"
7975 "\r\n"),
7976
7977 // Second connection attempt with Proxy-Authorization.
7978 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
7979 "Host: www.google.com\r\n"
7980 "Proxy-Connection: keep-alive\r\n"
7981 "Proxy-Authorization: auth_token\r\n"
7982 "\r\n"),
7983
7984 // SPDY request
7985 CreateMockWrite(*req),
7986 };
7987 const char kRejectConnectResponse[] = ("HTTP/1.1 407 Unauthorized\r\n"
7988 "Proxy-Authenticate: Mock\r\n"
7989 "Proxy-Connection: close\r\n"
7990 "\r\n");
7991 const char kAcceptConnectResponse[] = "HTTP/1.1 200 Connected\r\n\r\n";
7992 MockRead data_reads_2[] = {
7993 // First connection attempt fails
7994 MockRead(false, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ, 1),
7995 MockRead(true, kRejectConnectResponse,
7996 arraysize(kRejectConnectResponse) - 1, 1),
7997
7998 // Second connection attempt passes
7999 MockRead(true, kAcceptConnectResponse,
8000 arraysize(kAcceptConnectResponse) -1, 4),
8001
8002 // SPDY response
8003 CreateMockRead(*resp.get(), 6),
8004 CreateMockRead(*data.get(), 6),
8005 MockRead(true, 0, 0, 6),
8006 };
8007 scoped_refptr<OrderedSocketData> data_2(
8008 new OrderedSocketData(data_reads_2, arraysize(data_reads_2),
8009 data_writes_2, arraysize(data_writes_2)));
8010
8011 SSLSocketDataProvider ssl(true, OK);
8012 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
8013 ssl.next_proto = "spdy/2";
8014 ssl.was_npn_negotiated = true;
8015
8016 MockConnect never_finishing_connect(false, ERR_IO_PENDING);
8017 StaticSocketDataProvider hanging_non_alternate_protocol_socket(
8018 NULL, 0, NULL, 0);
8019 hanging_non_alternate_protocol_socket.set_connect_data(
8020 never_finishing_connect);
8021
8022 session_deps.socket_factory.AddSocketDataProvider(&data_1);
8023 session_deps.socket_factory.AddSocketDataProvider(data_2.get());
8024 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
8025 session_deps.socket_factory.AddSocketDataProvider(
8026 &hanging_non_alternate_protocol_socket);
8027 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
8028
8029 // First round should work and provide the Alternate-Protocol state.
8030 TestCompletionCallback callback_1;
8031 scoped_ptr<HttpTransaction> trans_1(new HttpNetworkTransaction(session));
8032 int rv = trans_1->Start(&request, &callback_1, BoundNetLog());
8033 EXPECT_EQ(ERR_IO_PENDING, rv);
8034 EXPECT_EQ(OK, callback_1.WaitForResult());
8035
8036 // Second round should attempt a tunnel connect and get an auth challenge.
8037 TestCompletionCallback callback_2;
8038 scoped_ptr<HttpTransaction> trans_2(new HttpNetworkTransaction(session));
8039 rv = trans_2->Start(&request, &callback_2, BoundNetLog());
8040 EXPECT_EQ(ERR_IO_PENDING, rv);
8041 EXPECT_EQ(OK, callback_2.WaitForResult());
8042 const HttpResponseInfo* response = trans_2->GetResponseInfo();
8043 ASSERT_FALSE(response == NULL);
8044 ASSERT_FALSE(response->auth_challenge.get() == NULL);
8045
8046 // Restart with auth. Tunnel should work and response received.
8047 TestCompletionCallback callback_3;
8048 rv = trans_2->RestartWithAuth(kFoo, kBar, &callback_3);
8049 EXPECT_EQ(ERR_IO_PENDING, rv);
8050 EXPECT_EQ(OK, callback_3.WaitForResult());
8051
8052 // After all that work, these two lines (or actually, just the scheme) are
8053 // what this test is all about. Make sure it happens correctly.
8054 const GURL& request_url = auth_handler->request_url();
8055 EXPECT_EQ("https", request_url.scheme());
8056 EXPECT_EQ("www.google.com", request_url.host());
8057
8058 HttpStreamFactory::set_next_protos("");
8059 HttpStreamFactory::set_use_alternate_protocols(false);
8060 }
8061
8062 // Test that if we cancel the transaction as the connection is completing, that
8063 // everything tears down correctly.
TEST_F(HttpNetworkTransactionTest,SimpleCancel)8064 TEST_F(HttpNetworkTransactionTest, SimpleCancel) {
8065 // Setup everything about the connection to complete synchronously, so that
8066 // after calling HttpNetworkTransaction::Start, the only thing we're waiting
8067 // for is the callback from the HttpStreamRequest.
8068 // Then cancel the transaction.
8069 // Verify that we don't crash.
8070 MockConnect mock_connect(false, OK);
8071 MockRead data_reads[] = {
8072 MockRead(false, "HTTP/1.0 200 OK\r\n\r\n"),
8073 MockRead(false, "hello world"),
8074 MockRead(false, OK),
8075 };
8076
8077 HttpRequestInfo request;
8078 request.method = "GET";
8079 request.url = GURL("http://www.google.com/");
8080 request.load_flags = 0;
8081
8082 SessionDependencies session_deps;
8083 session_deps.host_resolver->set_synchronous_mode(true);
8084 scoped_ptr<HttpTransaction> trans(
8085 new HttpNetworkTransaction(CreateSession(&session_deps)));
8086
8087 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
8088 data.set_connect_data(mock_connect);
8089 session_deps.socket_factory.AddSocketDataProvider(&data);
8090
8091 TestCompletionCallback callback;
8092
8093 CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
8094 int rv = trans->Start(&request, &callback, log.bound());
8095 EXPECT_EQ(ERR_IO_PENDING, rv);
8096 trans.reset(); // Cancel the transaction here.
8097
8098 MessageLoop::current()->RunAllPending();
8099 }
8100
8101 // Test a basic GET request through a proxy.
TEST_F(HttpNetworkTransactionTest,ProxyGet)8102 TEST_F(HttpNetworkTransactionTest, ProxyGet) {
8103 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70"));
8104 CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
8105 session_deps.net_log = log.bound().net_log();
8106 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
8107
8108 HttpRequestInfo request;
8109 request.method = "GET";
8110 request.url = GURL("http://www.google.com/");
8111
8112 MockWrite data_writes1[] = {
8113 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
8114 "Host: www.google.com\r\n"
8115 "Proxy-Connection: keep-alive\r\n\r\n"),
8116 };
8117
8118 MockRead data_reads1[] = {
8119 MockRead("HTTP/1.1 200 OK\r\n"),
8120 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
8121 MockRead("Content-Length: 100\r\n\r\n"),
8122 MockRead(false, OK),
8123 };
8124
8125 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
8126 data_writes1, arraysize(data_writes1));
8127 session_deps.socket_factory.AddSocketDataProvider(&data1);
8128
8129 TestCompletionCallback callback1;
8130
8131 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
8132
8133 int rv = trans->Start(&request, &callback1, log.bound());
8134 EXPECT_EQ(ERR_IO_PENDING, rv);
8135
8136 rv = callback1.WaitForResult();
8137 EXPECT_EQ(OK, rv);
8138
8139 const HttpResponseInfo* response = trans->GetResponseInfo();
8140 ASSERT_FALSE(response == NULL);
8141
8142 EXPECT_TRUE(response->headers->IsKeepAlive());
8143 EXPECT_EQ(200, response->headers->response_code());
8144 EXPECT_EQ(100, response->headers->GetContentLength());
8145 EXPECT_TRUE(response->was_fetched_via_proxy);
8146 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
8147 }
8148
8149 // Test a basic HTTPS GET request through a proxy.
TEST_F(HttpNetworkTransactionTest,ProxyTunnelGet)8150 TEST_F(HttpNetworkTransactionTest, ProxyTunnelGet) {
8151 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70"));
8152 CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
8153 session_deps.net_log = log.bound().net_log();
8154 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
8155
8156 HttpRequestInfo request;
8157 request.method = "GET";
8158 request.url = GURL("https://www.google.com/");
8159
8160 // Since we have proxy, should try to establish tunnel.
8161 MockWrite data_writes1[] = {
8162 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
8163 "Host: www.google.com\r\n"
8164 "Proxy-Connection: keep-alive\r\n\r\n"),
8165
8166 MockWrite("GET / HTTP/1.1\r\n"
8167 "Host: www.google.com\r\n"
8168 "Connection: keep-alive\r\n\r\n"),
8169 };
8170
8171 MockRead data_reads1[] = {
8172 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
8173
8174 MockRead("HTTP/1.1 200 OK\r\n"),
8175 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
8176 MockRead("Content-Length: 100\r\n\r\n"),
8177 MockRead(false, OK),
8178 };
8179
8180 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
8181 data_writes1, arraysize(data_writes1));
8182 session_deps.socket_factory.AddSocketDataProvider(&data1);
8183 SSLSocketDataProvider ssl(true, OK);
8184 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
8185
8186 TestCompletionCallback callback1;
8187
8188 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
8189
8190 int rv = trans->Start(&request, &callback1, log.bound());
8191 EXPECT_EQ(ERR_IO_PENDING, rv);
8192
8193 rv = callback1.WaitForResult();
8194 EXPECT_EQ(OK, rv);
8195 net::CapturingNetLog::EntryList entries;
8196 log.GetEntries(&entries);
8197 size_t pos = ExpectLogContainsSomewhere(
8198 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
8199 NetLog::PHASE_NONE);
8200 ExpectLogContainsSomewhere(
8201 entries, pos,
8202 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
8203 NetLog::PHASE_NONE);
8204
8205 const HttpResponseInfo* response = trans->GetResponseInfo();
8206 ASSERT_FALSE(response == NULL);
8207
8208 EXPECT_TRUE(response->headers->IsKeepAlive());
8209 EXPECT_EQ(200, response->headers->response_code());
8210 EXPECT_EQ(100, response->headers->GetContentLength());
8211 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
8212 EXPECT_TRUE(response->was_fetched_via_proxy);
8213 }
8214
8215 // Test a basic HTTPS GET request through a proxy, but the server hangs up
8216 // while establishing the tunnel.
TEST_F(HttpNetworkTransactionTest,ProxyTunnelGetHangup)8217 TEST_F(HttpNetworkTransactionTest, ProxyTunnelGetHangup) {
8218 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70"));
8219 CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
8220 session_deps.net_log = log.bound().net_log();
8221 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
8222
8223 HttpRequestInfo request;
8224 request.method = "GET";
8225 request.url = GURL("https://www.google.com/");
8226
8227 // Since we have proxy, should try to establish tunnel.
8228 MockWrite data_writes1[] = {
8229 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
8230 "Host: www.google.com\r\n"
8231 "Proxy-Connection: keep-alive\r\n\r\n"),
8232
8233 MockWrite("GET / HTTP/1.1\r\n"
8234 "Host: www.google.com\r\n"
8235 "Connection: keep-alive\r\n\r\n"),
8236 };
8237
8238 MockRead data_reads1[] = {
8239 MockRead(false, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
8240 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
8241 MockRead(true, 0, 0), // EOF
8242 };
8243
8244 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
8245 data_writes1, arraysize(data_writes1));
8246 session_deps.socket_factory.AddSocketDataProvider(&data1);
8247 SSLSocketDataProvider ssl(true, OK);
8248 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
8249
8250 TestCompletionCallback callback1;
8251
8252 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
8253
8254 int rv = trans->Start(&request, &callback1, log.bound());
8255 EXPECT_EQ(ERR_IO_PENDING, rv);
8256
8257 rv = callback1.WaitForResult();
8258 EXPECT_EQ(ERR_EMPTY_RESPONSE, rv);
8259 net::CapturingNetLog::EntryList entries;
8260 log.GetEntries(&entries);
8261 size_t pos = ExpectLogContainsSomewhere(
8262 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
8263 NetLog::PHASE_NONE);
8264 ExpectLogContainsSomewhere(
8265 entries, pos,
8266 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
8267 NetLog::PHASE_NONE);
8268 }
8269
8270 // Test for crbug.com/55424.
TEST_F(HttpNetworkTransactionTest,PreconnectWithExistingSpdySession)8271 TEST_F(HttpNetworkTransactionTest, PreconnectWithExistingSpdySession) {
8272 SessionDependencies session_deps;
8273
8274 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(
8275 "https://www.google.com", false, 1, LOWEST));
8276 MockWrite spdy_writes[] = { CreateMockWrite(*req) };
8277
8278 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
8279 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true));
8280 MockRead spdy_reads[] = {
8281 CreateMockRead(*resp),
8282 CreateMockRead(*data),
8283 MockRead(true, 0, 0),
8284 };
8285
8286 scoped_refptr<DelayedSocketData> spdy_data(
8287 new DelayedSocketData(
8288 1, // wait for one write to finish before reading.
8289 spdy_reads, arraysize(spdy_reads),
8290 spdy_writes, arraysize(spdy_writes)));
8291 session_deps.socket_factory.AddSocketDataProvider(spdy_data);
8292
8293 SSLSocketDataProvider ssl(true, OK);
8294 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
8295 ssl.next_proto = "spdy/2";
8296 ssl.was_npn_negotiated = true;
8297 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
8298
8299 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
8300
8301 // Set up an initial SpdySession in the pool to reuse.
8302 HostPortPair host_port_pair("www.google.com", 443);
8303 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
8304 scoped_refptr<SpdySession> spdy_session =
8305 session->spdy_session_pool()->Get(pair, BoundNetLog());
8306 scoped_refptr<TransportSocketParams> transport_params(
8307 new TransportSocketParams(host_port_pair, MEDIUM, GURL(), false, false));
8308 TestCompletionCallback callback;
8309
8310 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
8311 EXPECT_EQ(ERR_IO_PENDING,
8312 connection->Init(host_port_pair.ToString(), transport_params,
8313 LOWEST, &callback,
8314 session->transport_socket_pool(), BoundNetLog()));
8315 EXPECT_EQ(OK, callback.WaitForResult());
8316 spdy_session->InitializeWithSocket(connection.release(), false, OK);
8317
8318 HttpRequestInfo request;
8319 request.method = "GET";
8320 request.url = GURL("https://www.google.com/");
8321 request.load_flags = 0;
8322
8323 // This is the important line that marks this as a preconnect.
8324 request.motivation = HttpRequestInfo::PRECONNECT_MOTIVATED;
8325
8326 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session));
8327
8328 int rv = trans->Start(&request, &callback, BoundNetLog());
8329 EXPECT_EQ(ERR_IO_PENDING, rv);
8330 EXPECT_EQ(OK, callback.WaitForResult());
8331 }
8332
8333 // Given a net error, cause that error to be returned from the first Write()
8334 // call and verify that the HttpTransaction fails with that error.
CheckErrorIsPassedBack(int error,bool async)8335 static void CheckErrorIsPassedBack(int error, bool async) {
8336 net::HttpRequestInfo request_info;
8337 request_info.url = GURL("https://www.example.com/");
8338 request_info.method = "GET";
8339 request_info.load_flags = net::LOAD_NORMAL;
8340
8341 SessionDependencies session_deps;
8342
8343 SSLSocketDataProvider ssl_data(async, OK);
8344 net::MockWrite data_writes[] = {
8345 net::MockWrite(async, error),
8346 };
8347 net::StaticSocketDataProvider data(NULL, 0,
8348 data_writes, arraysize(data_writes));
8349 session_deps.socket_factory.AddSocketDataProvider(&data);
8350 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data);
8351
8352 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
8353 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session));
8354
8355 TestCompletionCallback callback;
8356 int rv = trans->Start(&request_info, &callback, net::BoundNetLog());
8357 if (rv == net::ERR_IO_PENDING)
8358 rv = callback.WaitForResult();
8359 ASSERT_EQ(error, rv);
8360 }
8361
TEST_F(HttpNetworkTransactionTest,SSLWriteCertError)8362 TEST_F(HttpNetworkTransactionTest, SSLWriteCertError) {
8363 // Just check a grab bag of cert errors.
8364 static const int kErrors[] = {
8365 ERR_CERT_COMMON_NAME_INVALID,
8366 ERR_CERT_AUTHORITY_INVALID,
8367 ERR_CERT_DATE_INVALID,
8368 };
8369 for (size_t i = 0; i < arraysize(kErrors); i++) {
8370 CheckErrorIsPassedBack(kErrors[i], false /* not async */);
8371 CheckErrorIsPassedBack(kErrors[i], true /* async */);
8372 }
8373 }
8374
8375 // Ensure that a client certificate is removed from the SSL client auth
8376 // cache when:
8377 // 1) No proxy is involved.
8378 // 2) TLS False Start is disabled.
8379 // 3) The initial TLS handshake requests a client certificate.
8380 // 4) The client supplies an invalid/unacceptable certificate.
TEST_F(HttpNetworkTransactionTest,ClientAuthCertCache_Direct_NoFalseStart)8381 TEST_F(HttpNetworkTransactionTest, ClientAuthCertCache_Direct_NoFalseStart) {
8382 net::HttpRequestInfo request_info;
8383 request_info.url = GURL("https://www.example.com/");
8384 request_info.method = "GET";
8385 request_info.load_flags = net::LOAD_NORMAL;
8386
8387 SessionDependencies session_deps;
8388
8389 scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo());
8390 cert_request->host_and_port = "www.example.com:443";
8391
8392 // [ssl_]data1 contains the data for the first SSL handshake. When a
8393 // CertificateRequest is received for the first time, the handshake will
8394 // be aborted to allow the caller to provide a certificate.
8395 SSLSocketDataProvider ssl_data1(true /* async */,
8396 net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
8397 ssl_data1.cert_request_info = cert_request.get();
8398 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data1);
8399 net::StaticSocketDataProvider data1(NULL, 0, NULL, 0);
8400 session_deps.socket_factory.AddSocketDataProvider(&data1);
8401
8402 // [ssl_]data2 contains the data for the second SSL handshake. When TLS
8403 // False Start is not being used, the result of the SSL handshake will be
8404 // returned as part of the SSLClientSocket::Connect() call. This test
8405 // matches the result of a server sending a handshake_failure alert,
8406 // rather than a Finished message, because it requires a client
8407 // certificate and none was supplied.
8408 SSLSocketDataProvider ssl_data2(true /* async */,
8409 net::ERR_SSL_PROTOCOL_ERROR);
8410 ssl_data2.cert_request_info = cert_request.get();
8411 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data2);
8412 net::StaticSocketDataProvider data2(NULL, 0, NULL, 0);
8413 session_deps.socket_factory.AddSocketDataProvider(&data2);
8414
8415 // [ssl_]data3 contains the data for the third SSL handshake. When a
8416 // connection to a server fails during an SSL handshake,
8417 // HttpNetworkTransaction will attempt to fallback to SSLv3 if the initial
8418 // connection was attempted with TLSv1. This is transparent to the caller
8419 // of the HttpNetworkTransaction. Because this test failure is due to
8420 // requiring a client certificate, this fallback handshake should also
8421 // fail.
8422 SSLSocketDataProvider ssl_data3(true /* async */,
8423 net::ERR_SSL_PROTOCOL_ERROR);
8424 ssl_data3.cert_request_info = cert_request.get();
8425 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data3);
8426 net::StaticSocketDataProvider data3(NULL, 0, NULL, 0);
8427 session_deps.socket_factory.AddSocketDataProvider(&data3);
8428
8429 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
8430 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session));
8431
8432 // Begin the SSL handshake with the peer. This consumes ssl_data1.
8433 TestCompletionCallback callback;
8434 int rv = trans->Start(&request_info, &callback, net::BoundNetLog());
8435 ASSERT_EQ(net::ERR_IO_PENDING, rv);
8436
8437 // Complete the SSL handshake, which should abort due to requiring a
8438 // client certificate.
8439 rv = callback.WaitForResult();
8440 ASSERT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv);
8441
8442 // Indicate that no certificate should be supplied. From the perspective
8443 // of SSLClientCertCache, NULL is just as meaningful as a real
8444 // certificate, so this is the same as supply a
8445 // legitimate-but-unacceptable certificate.
8446 rv = trans->RestartWithCertificate(NULL, &callback);
8447 ASSERT_EQ(net::ERR_IO_PENDING, rv);
8448
8449 // Ensure the certificate was added to the client auth cache before
8450 // allowing the connection to continue restarting.
8451 scoped_refptr<X509Certificate> client_cert;
8452 ASSERT_TRUE(session->ssl_client_auth_cache()->Lookup("www.example.com:443",
8453 &client_cert));
8454 ASSERT_EQ(NULL, client_cert.get());
8455
8456 // Restart the handshake. This will consume ssl_data2, which fails, and
8457 // then consume ssl_data3, which should also fail. The result code is
8458 // checked against what ssl_data3 should return.
8459 rv = callback.WaitForResult();
8460 ASSERT_EQ(net::ERR_SSL_PROTOCOL_ERROR, rv);
8461
8462 // Ensure that the client certificate is removed from the cache on a
8463 // handshake failure.
8464 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("www.example.com:443",
8465 &client_cert));
8466 }
8467
8468 // Ensure that a client certificate is removed from the SSL client auth
8469 // cache when:
8470 // 1) No proxy is involved.
8471 // 2) TLS False Start is enabled.
8472 // 3) The initial TLS handshake requests a client certificate.
8473 // 4) The client supplies an invalid/unacceptable certificate.
TEST_F(HttpNetworkTransactionTest,ClientAuthCertCache_Direct_FalseStart)8474 TEST_F(HttpNetworkTransactionTest, ClientAuthCertCache_Direct_FalseStart) {
8475 net::HttpRequestInfo request_info;
8476 request_info.url = GURL("https://www.example.com/");
8477 request_info.method = "GET";
8478 request_info.load_flags = net::LOAD_NORMAL;
8479
8480 SessionDependencies session_deps;
8481
8482 scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo());
8483 cert_request->host_and_port = "www.example.com:443";
8484
8485 // When TLS False Start is used, SSLClientSocket::Connect() calls will
8486 // return successfully after reading up to the peer's Certificate message.
8487 // This is to allow the caller to call SSLClientSocket::Write(), which can
8488 // enqueue application data to be sent in the same packet as the
8489 // ChangeCipherSpec and Finished messages.
8490 // The actual handshake will be finished when SSLClientSocket::Read() is
8491 // called, which expects to process the peer's ChangeCipherSpec and
8492 // Finished messages. If there was an error negotiating with the peer,
8493 // such as due to the peer requiring a client certificate when none was
8494 // supplied, the alert sent by the peer won't be processed until Read() is
8495 // called.
8496
8497 // Like the non-False Start case, when a client certificate is requested by
8498 // the peer, the handshake is aborted during the Connect() call.
8499 // [ssl_]data1 represents the initial SSL handshake with the peer.
8500 SSLSocketDataProvider ssl_data1(true /* async */,
8501 net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
8502 ssl_data1.cert_request_info = cert_request.get();
8503 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data1);
8504 net::StaticSocketDataProvider data1(NULL, 0, NULL, 0);
8505 session_deps.socket_factory.AddSocketDataProvider(&data1);
8506
8507 // When a client certificate is supplied, Connect() will not be aborted
8508 // when the peer requests the certificate. Instead, the handshake will
8509 // artificially succeed, allowing the caller to write the HTTP request to
8510 // the socket. The handshake messages are not processed until Read() is
8511 // called, which then detects that the handshake was aborted, due to the
8512 // peer sending a handshake_failure because it requires a client
8513 // certificate.
8514 SSLSocketDataProvider ssl_data2(true /* async */, net::OK);
8515 ssl_data2.cert_request_info = cert_request.get();
8516 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data2);
8517 net::MockRead data2_reads[] = {
8518 net::MockRead(true /* async */, net::ERR_SSL_PROTOCOL_ERROR),
8519 };
8520 net::StaticSocketDataProvider data2(
8521 data2_reads, arraysize(data2_reads), NULL, 0);
8522 session_deps.socket_factory.AddSocketDataProvider(&data2);
8523
8524 // As described in ClientAuthCertCache_Direct_NoFalseStart, [ssl_]data3 is
8525 // the data for the SSL handshake once the TLSv1 connection falls back to
8526 // SSLv3. It has the same behaviour as [ssl_]data2.
8527 SSLSocketDataProvider ssl_data3(true /* async */, net::OK);
8528 ssl_data3.cert_request_info = cert_request.get();
8529 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data3);
8530 net::StaticSocketDataProvider data3(
8531 data2_reads, arraysize(data2_reads), NULL, 0);
8532 session_deps.socket_factory.AddSocketDataProvider(&data3);
8533
8534 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
8535 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session));
8536
8537 // Begin the initial SSL handshake.
8538 TestCompletionCallback callback;
8539 int rv = trans->Start(&request_info, &callback, net::BoundNetLog());
8540 ASSERT_EQ(net::ERR_IO_PENDING, rv);
8541
8542 // Complete the SSL handshake, which should abort due to requiring a
8543 // client certificate.
8544 rv = callback.WaitForResult();
8545 ASSERT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv);
8546
8547 // Indicate that no certificate should be supplied. From the perspective
8548 // of SSLClientCertCache, NULL is just as meaningful as a real
8549 // certificate, so this is the same as supply a
8550 // legitimate-but-unacceptable certificate.
8551 rv = trans->RestartWithCertificate(NULL, &callback);
8552 ASSERT_EQ(net::ERR_IO_PENDING, rv);
8553
8554 // Ensure the certificate was added to the client auth cache before
8555 // allowing the connection to continue restarting.
8556 scoped_refptr<X509Certificate> client_cert;
8557 ASSERT_TRUE(session->ssl_client_auth_cache()->Lookup("www.example.com:443",
8558 &client_cert));
8559 ASSERT_EQ(NULL, client_cert.get());
8560
8561
8562 // Restart the handshake. This will consume ssl_data2, which fails, and
8563 // then consume ssl_data3, which should also fail. The result code is
8564 // checked against what ssl_data3 should return.
8565 rv = callback.WaitForResult();
8566 ASSERT_EQ(net::ERR_SSL_PROTOCOL_ERROR, rv);
8567
8568 // Ensure that the client certificate is removed from the cache on a
8569 // handshake failure.
8570 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("www.example.com:443",
8571 &client_cert));
8572 }
8573
8574 // Ensure that a client certificate is removed from the SSL client auth
8575 // cache when:
8576 // 1) An HTTPS proxy is involved.
8577 // 3) The HTTPS proxy requests a client certificate.
8578 // 4) The client supplies an invalid/unacceptable certificate for the
8579 // proxy.
8580 // The test is repeated twice, first for connecting to an HTTPS endpoint,
8581 // then for connecting to an HTTP endpoint.
TEST_F(HttpNetworkTransactionTest,ClientAuthCertCache_Proxy_Fail)8582 TEST_F(HttpNetworkTransactionTest, ClientAuthCertCache_Proxy_Fail) {
8583 SessionDependencies session_deps(
8584 ProxyService::CreateFixed("https://proxy:70"));
8585 CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
8586 session_deps.net_log = log.bound().net_log();
8587
8588 scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo());
8589 cert_request->host_and_port = "proxy:70";
8590
8591 // See ClientAuthCertCache_Direct_NoFalseStart for the explanation of
8592 // [ssl_]data[1-3]. Rather than represending the endpoint
8593 // (www.example.com:443), they represent failures with the HTTPS proxy
8594 // (proxy:70).
8595 SSLSocketDataProvider ssl_data1(true /* async */,
8596 net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
8597 ssl_data1.cert_request_info = cert_request.get();
8598 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data1);
8599 net::StaticSocketDataProvider data1(NULL, 0, NULL, 0);
8600 session_deps.socket_factory.AddSocketDataProvider(&data1);
8601
8602 SSLSocketDataProvider ssl_data2(true /* async */,
8603 net::ERR_SSL_PROTOCOL_ERROR);
8604 ssl_data2.cert_request_info = cert_request.get();
8605 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data2);
8606 net::StaticSocketDataProvider data2(NULL, 0, NULL, 0);
8607 session_deps.socket_factory.AddSocketDataProvider(&data2);
8608
8609 SSLSocketDataProvider ssl_data3(true /* async */,
8610 net::ERR_SSL_PROTOCOL_ERROR);
8611 ssl_data3.cert_request_info = cert_request.get();
8612 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data3);
8613 net::StaticSocketDataProvider data3(NULL, 0, NULL, 0);
8614 session_deps.socket_factory.AddSocketDataProvider(&data3);
8615
8616 net::HttpRequestInfo requests[2];
8617 requests[0].url = GURL("https://www.example.com/");
8618 requests[0].method = "GET";
8619 requests[0].load_flags = net::LOAD_NORMAL;
8620
8621 requests[1].url = GURL("http://www.example.com/");
8622 requests[1].method = "GET";
8623 requests[1].load_flags = net::LOAD_NORMAL;
8624
8625 for (size_t i = 0; i < arraysize(requests); ++i) {
8626 session_deps.socket_factory.ResetNextMockIndexes();
8627 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
8628 scoped_ptr<HttpNetworkTransaction> trans(
8629 new HttpNetworkTransaction(session));
8630
8631 // Begin the SSL handshake with the proxy.
8632 TestCompletionCallback callback;
8633 int rv = trans->Start(&requests[i], &callback, net::BoundNetLog());
8634 ASSERT_EQ(net::ERR_IO_PENDING, rv);
8635
8636 // Complete the SSL handshake, which should abort due to requiring a
8637 // client certificate.
8638 rv = callback.WaitForResult();
8639 ASSERT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv);
8640
8641 // Indicate that no certificate should be supplied. From the perspective
8642 // of SSLClientCertCache, NULL is just as meaningful as a real
8643 // certificate, so this is the same as supply a
8644 // legitimate-but-unacceptable certificate.
8645 rv = trans->RestartWithCertificate(NULL, &callback);
8646 ASSERT_EQ(net::ERR_IO_PENDING, rv);
8647
8648 // Ensure the certificate was added to the client auth cache before
8649 // allowing the connection to continue restarting.
8650 scoped_refptr<X509Certificate> client_cert;
8651 ASSERT_TRUE(session->ssl_client_auth_cache()->Lookup("proxy:70",
8652 &client_cert));
8653 ASSERT_EQ(NULL, client_cert.get());
8654 // Ensure the certificate was NOT cached for the endpoint. This only
8655 // applies to HTTPS requests, but is fine to check for HTTP requests.
8656 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("www.example.com:443",
8657 &client_cert));
8658
8659 // Restart the handshake. This will consume ssl_data2, which fails, and
8660 // then consume ssl_data3, which should also fail. The result code is
8661 // checked against what ssl_data3 should return.
8662 rv = callback.WaitForResult();
8663 ASSERT_EQ(net::ERR_PROXY_CONNECTION_FAILED, rv);
8664
8665 // Now that the new handshake has failed, ensure that the client
8666 // certificate was removed from the client auth cache.
8667 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("proxy:70",
8668 &client_cert));
8669 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("www.example.com:443",
8670 &client_cert));
8671 }
8672 }
8673
8674 } // namespace net
8675