1 // Copyright (c) 2009 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 <math.h> // ceil
6
7 #include "base/compiler_specific.h"
8 #include "net/base/completion_callback.h"
9 #include "net/base/mock_host_resolver.h"
10 #include "net/base/request_priority.h"
11 #include "net/base/ssl_config_service_defaults.h"
12 #include "net/base/ssl_info.h"
13 #include "net/base/test_completion_callback.h"
14 #include "net/base/upload_data.h"
15 #include "net/flip/flip_session_pool.h"
16 #include "net/http/http_auth_handler_ntlm.h"
17 #include "net/http/http_basic_stream.h"
18 #include "net/http/http_network_session.h"
19 #include "net/http/http_network_transaction.h"
20 #include "net/http/http_stream.h"
21 #include "net/http/http_transaction_unittest.h"
22 #include "net/proxy/proxy_config_service_fixed.h"
23 #include "net/socket/client_socket_factory.h"
24 #include "net/socket/socket_test_util.h"
25 #include "net/socket/ssl_client_socket.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27 #include "testing/platform_test.h"
28
29 //-----------------------------------------------------------------------------
30
31 // TODO(eroman): Add a regression test for http://crbug.com/32316 -- when the
32 // proxy service returns an error, we should fallback to DIRECT instead of
33 // failing with ERR_NO_SUPPORTED_PROXIES.
34
35 namespace net {
36
37 // Create a proxy service which fails on all requests (falls back to direct).
CreateNullProxyService()38 ProxyService* CreateNullProxyService() {
39 return ProxyService::CreateNull();
40 }
41
42 // Helper to manage the lifetimes of the dependencies for a
43 // HttpNetworkTransaction.
44 class SessionDependencies {
45 public:
46 // Default set of dependencies -- "null" proxy service.
SessionDependencies()47 SessionDependencies()
48 : host_resolver(new MockHostResolver),
49 proxy_service(CreateNullProxyService()),
50 ssl_config_service(new SSLConfigServiceDefaults),
51 flip_session_pool(new FlipSessionPool) {}
52
53 // Custom proxy service dependency.
SessionDependencies(ProxyService * proxy_service)54 explicit SessionDependencies(ProxyService* proxy_service)
55 : host_resolver(new MockHostResolver),
56 proxy_service(proxy_service),
57 ssl_config_service(new SSLConfigServiceDefaults),
58 flip_session_pool(new FlipSessionPool) {}
59
60 scoped_refptr<MockHostResolverBase> host_resolver;
61 scoped_refptr<ProxyService> proxy_service;
62 scoped_refptr<SSLConfigService> ssl_config_service;
63 MockClientSocketFactory socket_factory;
64 scoped_refptr<FlipSessionPool> flip_session_pool;
65 };
66
CreateFixedProxyService(const std::string & proxy)67 ProxyService* CreateFixedProxyService(const std::string& proxy) {
68 net::ProxyConfig proxy_config;
69 proxy_config.proxy_rules.ParseFromString(proxy);
70 return ProxyService::CreateFixed(proxy_config);
71 }
72
73
CreateSession(SessionDependencies * session_deps)74 HttpNetworkSession* CreateSession(SessionDependencies* session_deps) {
75 return new HttpNetworkSession(NULL,
76 session_deps->host_resolver,
77 session_deps->proxy_service,
78 &session_deps->socket_factory,
79 session_deps->ssl_config_service,
80 session_deps->flip_session_pool);
81 }
82
83 class HttpNetworkTransactionTest : public PlatformTest {
84 public:
TearDown()85 virtual void TearDown() {
86 // Empty the current queue.
87 MessageLoop::current()->RunAllPending();
88 PlatformTest::TearDown();
89 }
90
91 protected:
92 void KeepAliveConnectionResendRequestTest(const MockRead& read_failure);
93
94 struct SimpleGetHelperResult {
95 int rv;
96 std::string status_line;
97 std::string response_data;
98 };
99
SimpleGetHelper(MockRead data_reads[])100 SimpleGetHelperResult SimpleGetHelper(MockRead data_reads[]) {
101 SimpleGetHelperResult out;
102
103 SessionDependencies session_deps;
104 scoped_ptr<HttpTransaction> trans(
105 new HttpNetworkTransaction(CreateSession(&session_deps)));
106
107 HttpRequestInfo request;
108 request.method = "GET";
109 request.url = GURL("http://www.google.com/");
110 request.load_flags = 0;
111
112 StaticSocketDataProvider data(data_reads, NULL);
113 session_deps.socket_factory.AddSocketDataProvider(&data);
114
115 TestCompletionCallback callback;
116
117 int rv = trans->Start(&request, &callback, NULL);
118 EXPECT_EQ(ERR_IO_PENDING, rv);
119
120 out.rv = callback.WaitForResult();
121 if (out.rv != OK)
122 return out;
123
124 const HttpResponseInfo* response = trans->GetResponseInfo();
125 EXPECT_TRUE(response != NULL);
126
127 EXPECT_TRUE(response->headers != NULL);
128 out.status_line = response->headers->GetStatusLine();
129
130 rv = ReadTransaction(trans.get(), &out.response_data);
131 EXPECT_EQ(OK, rv);
132
133 return out;
134 }
135
136 void ConnectStatusHelperWithExpectedStatus(const MockRead& status,
137 int expected_status);
138
139 void ConnectStatusHelper(const MockRead& status);
140 };
141
142 // Fill |str| with a long header list that consumes >= |size| bytes.
FillLargeHeadersString(std::string * str,int size)143 void FillLargeHeadersString(std::string* str, int size) {
144 const char* row =
145 "SomeHeaderName: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n";
146 const int sizeof_row = strlen(row);
147 const int num_rows = static_cast<int>(
148 ceil(static_cast<float>(size) / sizeof_row));
149 const int sizeof_data = num_rows * sizeof_row;
150 DCHECK(sizeof_data >= size);
151 str->reserve(sizeof_data);
152
153 for (int i = 0; i < num_rows; ++i)
154 str->append(row, sizeof_row);
155 }
156
157 // Alternative functions that eliminate randomness and dependency on the local
158 // host name so that the generated NTLM messages are reproducible.
MockGenerateRandom1(uint8 * output,size_t n)159 void MockGenerateRandom1(uint8* output, size_t n) {
160 static const uint8 bytes[] = {
161 0x55, 0x29, 0x66, 0x26, 0x6b, 0x9c, 0x73, 0x54
162 };
163 static size_t current_byte = 0;
164 for (size_t i = 0; i < n; ++i) {
165 output[i] = bytes[current_byte++];
166 current_byte %= arraysize(bytes);
167 }
168 }
169
MockGenerateRandom2(uint8 * output,size_t n)170 void MockGenerateRandom2(uint8* output, size_t n) {
171 static const uint8 bytes[] = {
172 0x96, 0x79, 0x85, 0xe7, 0x49, 0x93, 0x70, 0xa1,
173 0x4e, 0xe7, 0x87, 0x45, 0x31, 0x5b, 0xd3, 0x1f
174 };
175 static size_t current_byte = 0;
176 for (size_t i = 0; i < n; ++i) {
177 output[i] = bytes[current_byte++];
178 current_byte %= arraysize(bytes);
179 }
180 }
181
MockGetHostName()182 std::string MockGetHostName() {
183 return "WTC-WIN7";
184 }
185
186 class CaptureGroupNameSocketPool : public TCPClientSocketPool {
187 public:
CaptureGroupNameSocketPool()188 CaptureGroupNameSocketPool() : TCPClientSocketPool(0, 0, NULL, NULL, NULL) {}
last_group_name_received() const189 const std::string last_group_name_received() const {
190 return last_group_name_;
191 }
192
RequestSocket(const std::string & group_name,const void * socket_params,RequestPriority priority,ClientSocketHandle * handle,CompletionCallback * callback,LoadLog * load_log)193 virtual int RequestSocket(const std::string& group_name,
194 const void* socket_params,
195 RequestPriority priority,
196 ClientSocketHandle* handle,
197 CompletionCallback* callback,
198 LoadLog* load_log) {
199 last_group_name_ = group_name;
200 return ERR_IO_PENDING;
201 }
CancelRequest(const std::string & group_name,const ClientSocketHandle * handle)202 virtual void CancelRequest(const std::string& group_name,
203 const ClientSocketHandle* handle) { }
ReleaseSocket(const std::string & group_name,ClientSocket * socket)204 virtual void ReleaseSocket(const std::string& group_name,
205 ClientSocket* socket) {}
CloseIdleSockets()206 virtual void CloseIdleSockets() {}
GetHostResolver() const207 virtual HostResolver* GetHostResolver() const {
208 return NULL;
209 }
IdleSocketCount() const210 virtual int IdleSocketCount() const {
211 return 0;
212 }
IdleSocketCountInGroup(const std::string & group_name) const213 virtual int IdleSocketCountInGroup(const std::string& group_name) const {
214 return 0;
215 }
GetLoadState(const std::string & group_name,const ClientSocketHandle * handle) const216 virtual LoadState GetLoadState(const std::string& group_name,
217 const ClientSocketHandle* handle) const {
218 return LOAD_STATE_IDLE;
219 }
220
221 private:
222 std::string last_group_name_;
223 };
224
225 //-----------------------------------------------------------------------------
226
TEST_F(HttpNetworkTransactionTest,Basic)227 TEST_F(HttpNetworkTransactionTest, Basic) {
228 SessionDependencies session_deps;
229 scoped_ptr<HttpTransaction> trans(
230 new HttpNetworkTransaction(CreateSession(&session_deps)));
231 }
232
TEST_F(HttpNetworkTransactionTest,SimpleGET)233 TEST_F(HttpNetworkTransactionTest, SimpleGET) {
234 MockRead data_reads[] = {
235 MockRead("HTTP/1.0 200 OK\r\n\r\n"),
236 MockRead("hello world"),
237 MockRead(false, OK),
238 };
239 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
240 EXPECT_EQ(OK, out.rv);
241 EXPECT_EQ("HTTP/1.0 200 OK", out.status_line);
242 EXPECT_EQ("hello world", out.response_data);
243 }
244
245 // Response with no status line.
TEST_F(HttpNetworkTransactionTest,SimpleGETNoHeaders)246 TEST_F(HttpNetworkTransactionTest, SimpleGETNoHeaders) {
247 MockRead data_reads[] = {
248 MockRead("hello world"),
249 MockRead(false, OK),
250 };
251 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
252 EXPECT_EQ(OK, out.rv);
253 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
254 EXPECT_EQ("hello world", out.response_data);
255 }
256
257 // Allow up to 4 bytes of junk to precede status line.
TEST_F(HttpNetworkTransactionTest,StatusLineJunk2Bytes)258 TEST_F(HttpNetworkTransactionTest, StatusLineJunk2Bytes) {
259 MockRead data_reads[] = {
260 MockRead("xxxHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
261 MockRead(false, OK),
262 };
263 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
264 EXPECT_EQ(OK, out.rv);
265 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
266 EXPECT_EQ("DATA", out.response_data);
267 }
268
269 // Allow up to 4 bytes of junk to precede status line.
TEST_F(HttpNetworkTransactionTest,StatusLineJunk4Bytes)270 TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes) {
271 MockRead data_reads[] = {
272 MockRead("\n\nQJHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
273 MockRead(false, OK),
274 };
275 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
276 EXPECT_EQ(OK, out.rv);
277 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
278 EXPECT_EQ("DATA", out.response_data);
279 }
280
281 // Beyond 4 bytes of slop and it should fail to find a status line.
TEST_F(HttpNetworkTransactionTest,StatusLineJunk5Bytes)282 TEST_F(HttpNetworkTransactionTest, StatusLineJunk5Bytes) {
283 MockRead data_reads[] = {
284 MockRead("xxxxxHTTP/1.1 404 Not Found\nServer: blah"),
285 MockRead(false, OK),
286 };
287 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
288 EXPECT_EQ(OK, out.rv);
289 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
290 EXPECT_EQ("xxxxxHTTP/1.1 404 Not Found\nServer: blah", out.response_data);
291 }
292
293 // Same as StatusLineJunk4Bytes, except the read chunks are smaller.
TEST_F(HttpNetworkTransactionTest,StatusLineJunk4Bytes_Slow)294 TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes_Slow) {
295 MockRead data_reads[] = {
296 MockRead("\n"),
297 MockRead("\n"),
298 MockRead("Q"),
299 MockRead("J"),
300 MockRead("HTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
301 MockRead(false, OK),
302 };
303 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
304 EXPECT_EQ(OK, out.rv);
305 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
306 EXPECT_EQ("DATA", out.response_data);
307 }
308
309 // Close the connection before enough bytes to have a status line.
TEST_F(HttpNetworkTransactionTest,StatusLinePartial)310 TEST_F(HttpNetworkTransactionTest, StatusLinePartial) {
311 MockRead data_reads[] = {
312 MockRead("HTT"),
313 MockRead(false, OK),
314 };
315 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
316 EXPECT_EQ(OK, out.rv);
317 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
318 EXPECT_EQ("HTT", out.response_data);
319 }
320
321 // Simulate a 204 response, lacking a Content-Length header, sent over a
322 // persistent connection. The response should still terminate since a 204
323 // cannot have a response body.
TEST_F(HttpNetworkTransactionTest,StopsReading204)324 TEST_F(HttpNetworkTransactionTest, StopsReading204) {
325 MockRead data_reads[] = {
326 MockRead("HTTP/1.1 204 No Content\r\n\r\n"),
327 MockRead("junk"), // Should not be read!!
328 MockRead(false, OK),
329 };
330 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
331 EXPECT_EQ(OK, out.rv);
332 EXPECT_EQ("HTTP/1.1 204 No Content", out.status_line);
333 EXPECT_EQ("", out.response_data);
334 }
335
336 // A simple request using chunked encoding with some extra data after.
337 // (Like might be seen in a pipelined response.)
TEST_F(HttpNetworkTransactionTest,ChunkedEncoding)338 TEST_F(HttpNetworkTransactionTest, ChunkedEncoding) {
339 MockRead data_reads[] = {
340 MockRead("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"),
341 MockRead("5\r\nHello\r\n"),
342 MockRead("1\r\n"),
343 MockRead(" \r\n"),
344 MockRead("5\r\nworld\r\n"),
345 MockRead("0\r\n\r\nHTTP/1.1 200 OK\r\n"),
346 MockRead(false, OK),
347 };
348 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
349 EXPECT_EQ(OK, out.rv);
350 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
351 EXPECT_EQ("Hello world", out.response_data);
352 }
353
354 // Do a request using the HEAD method. Verify that we don't try to read the
355 // message body (since HEAD has none).
TEST_F(HttpNetworkTransactionTest,Head)356 TEST_F(HttpNetworkTransactionTest, Head) {
357 SessionDependencies session_deps;
358 scoped_ptr<HttpTransaction> trans(
359 new HttpNetworkTransaction(CreateSession(&session_deps)));
360
361 HttpRequestInfo request;
362 request.method = "HEAD";
363 request.url = GURL("http://www.google.com/");
364 request.load_flags = 0;
365
366 MockWrite data_writes1[] = {
367 MockWrite("HEAD / HTTP/1.1\r\n"
368 "Host: www.google.com\r\n"
369 "Connection: keep-alive\r\n"
370 "Content-Length: 0\r\n\r\n"),
371 };
372 MockRead data_reads1[] = {
373 MockRead("HTTP/1.1 404 Not Found\r\n"),
374 MockRead("Server: Blah\r\n"),
375 MockRead("Content-Length: 1234\r\n\r\n"),
376
377 // No response body because the test stops reading here.
378 MockRead(false, ERR_UNEXPECTED), // Should not be reached.
379 };
380
381 StaticSocketDataProvider data1(data_reads1, data_writes1);
382 session_deps.socket_factory.AddSocketDataProvider(&data1);
383
384 TestCompletionCallback callback1;
385
386 int rv = trans->Start(&request, &callback1, NULL);
387 EXPECT_EQ(ERR_IO_PENDING, rv);
388
389 rv = callback1.WaitForResult();
390 EXPECT_EQ(OK, rv);
391
392 const HttpResponseInfo* response = trans->GetResponseInfo();
393 EXPECT_FALSE(response == NULL);
394
395 // Check that the headers got parsed.
396 EXPECT_TRUE(response->headers != NULL);
397 EXPECT_EQ(1234, response->headers->GetContentLength());
398 EXPECT_EQ("HTTP/1.1 404 Not Found", response->headers->GetStatusLine());
399
400 std::string server_header;
401 void* iter = NULL;
402 bool has_server_header = response->headers->EnumerateHeader(
403 &iter, "Server", &server_header);
404 EXPECT_TRUE(has_server_header);
405 EXPECT_EQ("Blah", server_header);
406
407 // Reading should give EOF right away, since there is no message body
408 // (despite non-zero content-length).
409 std::string response_data;
410 rv = ReadTransaction(trans.get(), &response_data);
411 EXPECT_EQ(OK, rv);
412 EXPECT_EQ("", response_data);
413 }
414
TEST_F(HttpNetworkTransactionTest,ReuseConnection)415 TEST_F(HttpNetworkTransactionTest, ReuseConnection) {
416 SessionDependencies session_deps;
417 scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps);
418
419 MockRead data_reads[] = {
420 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
421 MockRead("hello"),
422 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
423 MockRead("world"),
424 MockRead(false, OK),
425 };
426 StaticSocketDataProvider data(data_reads, NULL);
427 session_deps.socket_factory.AddSocketDataProvider(&data);
428
429 const char* kExpectedResponseData[] = {
430 "hello", "world"
431 };
432
433 for (int i = 0; i < 2; ++i) {
434 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
435
436 HttpRequestInfo request;
437 request.method = "GET";
438 request.url = GURL("http://www.google.com/");
439 request.load_flags = 0;
440
441 TestCompletionCallback callback;
442
443 int rv = trans->Start(&request, &callback, NULL);
444 EXPECT_EQ(ERR_IO_PENDING, rv);
445
446 rv = callback.WaitForResult();
447 EXPECT_EQ(OK, rv);
448
449 const HttpResponseInfo* response = trans->GetResponseInfo();
450 EXPECT_TRUE(response != NULL);
451
452 EXPECT_TRUE(response->headers != NULL);
453 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
454
455 std::string response_data;
456 rv = ReadTransaction(trans.get(), &response_data);
457 EXPECT_EQ(OK, rv);
458 EXPECT_EQ(kExpectedResponseData[i], response_data);
459 }
460 }
461
TEST_F(HttpNetworkTransactionTest,Ignores100)462 TEST_F(HttpNetworkTransactionTest, Ignores100) {
463 SessionDependencies session_deps;
464 scoped_ptr<HttpTransaction> trans(
465 new HttpNetworkTransaction(CreateSession(&session_deps)));
466
467 HttpRequestInfo request;
468 request.method = "POST";
469 request.url = GURL("http://www.foo.com/");
470 request.upload_data = new UploadData;
471 request.upload_data->AppendBytes("foo", 3);
472 request.load_flags = 0;
473
474 MockRead data_reads[] = {
475 MockRead("HTTP/1.0 100 Continue\r\n\r\n"),
476 MockRead("HTTP/1.0 200 OK\r\n\r\n"),
477 MockRead("hello world"),
478 MockRead(false, OK),
479 };
480 StaticSocketDataProvider data(data_reads, NULL);
481 session_deps.socket_factory.AddSocketDataProvider(&data);
482
483 TestCompletionCallback callback;
484
485 int rv = trans->Start(&request, &callback, NULL);
486 EXPECT_EQ(ERR_IO_PENDING, rv);
487
488 rv = callback.WaitForResult();
489 EXPECT_EQ(OK, rv);
490
491 const HttpResponseInfo* response = trans->GetResponseInfo();
492 EXPECT_TRUE(response != NULL);
493
494 EXPECT_TRUE(response->headers != NULL);
495 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine());
496
497 std::string response_data;
498 rv = ReadTransaction(trans.get(), &response_data);
499 EXPECT_EQ(OK, rv);
500 EXPECT_EQ("hello world", response_data);
501 }
502
503 // This test is almost the same as Ignores100 above, but the response contains
504 // a 102 instead of a 100. Also, instead of HTTP/1.0 the response is
505 // HTTP/1.1 and the two status headers are read in one read.
TEST_F(HttpNetworkTransactionTest,Ignores1xx)506 TEST_F(HttpNetworkTransactionTest, Ignores1xx) {
507 SessionDependencies session_deps;
508 scoped_ptr<HttpTransaction> trans(
509 new HttpNetworkTransaction(CreateSession(&session_deps)));
510
511 HttpRequestInfo request;
512 request.method = "GET";
513 request.url = GURL("http://www.foo.com/");
514 request.load_flags = 0;
515
516 MockRead data_reads[] = {
517 MockRead("HTTP/1.1 102 Unspecified status code\r\n\r\n"
518 "HTTP/1.1 200 OK\r\n\r\n"),
519 MockRead("hello world"),
520 MockRead(false, OK),
521 };
522 StaticSocketDataProvider data(data_reads, NULL);
523 session_deps.socket_factory.AddSocketDataProvider(&data);
524
525 TestCompletionCallback callback;
526
527 int rv = trans->Start(&request, &callback, NULL);
528 EXPECT_EQ(ERR_IO_PENDING, rv);
529
530 rv = callback.WaitForResult();
531 EXPECT_EQ(OK, rv);
532
533 const HttpResponseInfo* response = trans->GetResponseInfo();
534 EXPECT_TRUE(response != NULL);
535
536 EXPECT_TRUE(response->headers != NULL);
537 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
538
539 std::string response_data;
540 rv = ReadTransaction(trans.get(), &response_data);
541 EXPECT_EQ(OK, rv);
542 EXPECT_EQ("hello world", response_data);
543 }
544
TEST_F(HttpNetworkTransactionTest,Incomplete100ThenEOF)545 TEST_F(HttpNetworkTransactionTest, Incomplete100ThenEOF) {
546 SessionDependencies session_deps;
547 scoped_ptr<HttpTransaction> trans(
548 new HttpNetworkTransaction(CreateSession(&session_deps)));
549
550 HttpRequestInfo request;
551 request.method = "POST";
552 request.url = GURL("http://www.foo.com/");
553 request.load_flags = 0;
554
555 MockRead data_reads[] = {
556 MockRead(false, "HTTP/1.0 100 Continue\r\n"),
557 MockRead(true, 0),
558 };
559 StaticSocketDataProvider data(data_reads, NULL);
560 session_deps.socket_factory.AddSocketDataProvider(&data);
561
562 TestCompletionCallback callback;
563
564 int rv = trans->Start(&request, &callback, NULL);
565 EXPECT_EQ(ERR_IO_PENDING, rv);
566
567 rv = callback.WaitForResult();
568 EXPECT_EQ(OK, rv);
569
570 std::string response_data;
571 rv = ReadTransaction(trans.get(), &response_data);
572 EXPECT_EQ(OK, rv);
573 EXPECT_EQ("", response_data);
574 }
575
TEST_F(HttpNetworkTransactionTest,EmptyResponse)576 TEST_F(HttpNetworkTransactionTest, EmptyResponse) {
577 SessionDependencies session_deps;
578 scoped_ptr<HttpTransaction> trans(
579 new HttpNetworkTransaction(CreateSession(&session_deps)));
580
581 HttpRequestInfo request;
582 request.method = "POST";
583 request.url = GURL("http://www.foo.com/");
584 request.load_flags = 0;
585
586 MockRead data_reads[] = {
587 MockRead(true, 0),
588 };
589 StaticSocketDataProvider data(data_reads, NULL);
590 session_deps.socket_factory.AddSocketDataProvider(&data);
591
592 TestCompletionCallback callback;
593
594 int rv = trans->Start(&request, &callback, NULL);
595 EXPECT_EQ(ERR_IO_PENDING, rv);
596
597 rv = callback.WaitForResult();
598 EXPECT_EQ(ERR_EMPTY_RESPONSE, rv);
599 }
600
601 // read_failure specifies a read failure that should cause the network
602 // transaction to resend the request.
KeepAliveConnectionResendRequestTest(const MockRead & read_failure)603 void HttpNetworkTransactionTest::KeepAliveConnectionResendRequestTest(
604 const MockRead& read_failure) {
605 SessionDependencies session_deps;
606 scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps);
607
608 HttpRequestInfo request;
609 request.method = "GET";
610 request.url = GURL("http://www.foo.com/");
611 request.load_flags = 0;
612
613 MockRead data1_reads[] = {
614 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
615 MockRead("hello"),
616 read_failure, // Now, we reuse the connection and fail the first read.
617 };
618 StaticSocketDataProvider data1(data1_reads, NULL);
619 session_deps.socket_factory.AddSocketDataProvider(&data1);
620
621 MockRead data2_reads[] = {
622 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
623 MockRead("world"),
624 MockRead(true, OK),
625 };
626 StaticSocketDataProvider data2(data2_reads, NULL);
627 session_deps.socket_factory.AddSocketDataProvider(&data2);
628
629 const char* kExpectedResponseData[] = {
630 "hello", "world"
631 };
632
633 for (int i = 0; i < 2; ++i) {
634 TestCompletionCallback callback;
635
636 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
637
638 int rv = trans->Start(&request, &callback, NULL);
639 EXPECT_EQ(ERR_IO_PENDING, rv);
640
641 rv = callback.WaitForResult();
642 EXPECT_EQ(OK, rv);
643
644 const HttpResponseInfo* response = trans->GetResponseInfo();
645 EXPECT_TRUE(response != NULL);
646
647 EXPECT_TRUE(response->headers != NULL);
648 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
649
650 std::string response_data;
651 rv = ReadTransaction(trans.get(), &response_data);
652 EXPECT_EQ(OK, rv);
653 EXPECT_EQ(kExpectedResponseData[i], response_data);
654 }
655 }
656
TEST_F(HttpNetworkTransactionTest,KeepAliveConnectionReset)657 TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionReset) {
658 MockRead read_failure(true, ERR_CONNECTION_RESET);
659 KeepAliveConnectionResendRequestTest(read_failure);
660 }
661
TEST_F(HttpNetworkTransactionTest,KeepAliveConnectionEOF)662 TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionEOF) {
663 MockRead read_failure(false, OK); // EOF
664 KeepAliveConnectionResendRequestTest(read_failure);
665 }
666
TEST_F(HttpNetworkTransactionTest,NonKeepAliveConnectionReset)667 TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionReset) {
668 SessionDependencies session_deps;
669 scoped_ptr<HttpTransaction> trans(
670 new HttpNetworkTransaction(CreateSession(&session_deps)));
671
672 HttpRequestInfo request;
673 request.method = "GET";
674 request.url = GURL("http://www.google.com/");
675 request.load_flags = 0;
676
677 MockRead data_reads[] = {
678 MockRead(true, ERR_CONNECTION_RESET),
679 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used
680 MockRead("hello world"),
681 MockRead(false, OK),
682 };
683 StaticSocketDataProvider data(data_reads, NULL);
684 session_deps.socket_factory.AddSocketDataProvider(&data);
685
686 TestCompletionCallback callback;
687
688 int rv = trans->Start(&request, &callback, NULL);
689 EXPECT_EQ(ERR_IO_PENDING, rv);
690
691 rv = callback.WaitForResult();
692 EXPECT_EQ(ERR_CONNECTION_RESET, rv);
693
694 const HttpResponseInfo* response = trans->GetResponseInfo();
695 EXPECT_TRUE(response == NULL);
696 }
697
698 // What do various browsers do when the server closes a non-keepalive
699 // connection without sending any response header or body?
700 //
701 // IE7: error page
702 // Safari 3.1.2 (Windows): error page
703 // Firefox 3.0.1: blank page
704 // Opera 9.52: after five attempts, blank page
705 // Us with WinHTTP: error page (ERR_INVALID_RESPONSE)
706 // Us: error page (EMPTY_RESPONSE)
TEST_F(HttpNetworkTransactionTest,NonKeepAliveConnectionEOF)707 TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionEOF) {
708 MockRead data_reads[] = {
709 MockRead(false, OK), // EOF
710 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used
711 MockRead("hello world"),
712 MockRead(false, OK),
713 };
714 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
715 EXPECT_EQ(ERR_EMPTY_RESPONSE, out.rv);
716 }
717
718 // Test the request-challenge-retry sequence for basic auth.
719 // (basic auth is the easiest to mock, because it has no randomness).
TEST_F(HttpNetworkTransactionTest,BasicAuth)720 TEST_F(HttpNetworkTransactionTest, BasicAuth) {
721 SessionDependencies session_deps;
722 scoped_ptr<HttpTransaction> trans(
723 new HttpNetworkTransaction(CreateSession(&session_deps)));
724
725 HttpRequestInfo request;
726 request.method = "GET";
727 request.url = GURL("http://www.google.com/");
728 request.load_flags = 0;
729
730 MockWrite data_writes1[] = {
731 MockWrite("GET / HTTP/1.1\r\n"
732 "Host: www.google.com\r\n"
733 "Connection: keep-alive\r\n\r\n"),
734 };
735
736 MockRead data_reads1[] = {
737 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
738 // Give a couple authenticate options (only the middle one is actually
739 // supported).
740 MockRead("WWW-Authenticate: Basic invalid\r\n"), // Malformed.
741 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
742 MockRead("WWW-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"),
743 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
744 // Large content-length -- won't matter, as connection will be reset.
745 MockRead("Content-Length: 10000\r\n\r\n"),
746 MockRead(false, ERR_FAILED),
747 };
748
749 // After calling trans->RestartWithAuth(), this is the request we should
750 // be issuing -- the final header line contains the credentials.
751 MockWrite data_writes2[] = {
752 MockWrite("GET / HTTP/1.1\r\n"
753 "Host: www.google.com\r\n"
754 "Connection: keep-alive\r\n"
755 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
756 };
757
758 // Lastly, the server responds with the actual content.
759 MockRead data_reads2[] = {
760 MockRead("HTTP/1.0 200 OK\r\n"),
761 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
762 MockRead("Content-Length: 100\r\n\r\n"),
763 MockRead(false, OK),
764 };
765
766 StaticSocketDataProvider data1(data_reads1, data_writes1);
767 StaticSocketDataProvider data2(data_reads2, data_writes2);
768 session_deps.socket_factory.AddSocketDataProvider(&data1);
769 session_deps.socket_factory.AddSocketDataProvider(&data2);
770
771 TestCompletionCallback callback1;
772
773 int rv = trans->Start(&request, &callback1, NULL);
774 EXPECT_EQ(ERR_IO_PENDING, rv);
775
776 rv = callback1.WaitForResult();
777 EXPECT_EQ(OK, rv);
778
779 const HttpResponseInfo* response = trans->GetResponseInfo();
780 EXPECT_FALSE(response == NULL);
781
782 // The password prompt info should have been set in response->auth_challenge.
783 EXPECT_FALSE(response->auth_challenge.get() == NULL);
784
785 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
786 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
787 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
788
789 TestCompletionCallback callback2;
790
791 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
792 EXPECT_EQ(ERR_IO_PENDING, rv);
793
794 rv = callback2.WaitForResult();
795 EXPECT_EQ(OK, rv);
796
797 response = trans->GetResponseInfo();
798 EXPECT_FALSE(response == NULL);
799 EXPECT_TRUE(response->auth_challenge.get() == NULL);
800 EXPECT_EQ(100, response->headers->GetContentLength());
801 }
802
TEST_F(HttpNetworkTransactionTest,DoNotSendAuth)803 TEST_F(HttpNetworkTransactionTest, DoNotSendAuth) {
804 SessionDependencies session_deps;
805 scoped_ptr<HttpTransaction> trans(
806 new HttpNetworkTransaction(CreateSession(&session_deps)));
807
808 HttpRequestInfo request;
809 request.method = "GET";
810 request.url = GURL("http://www.google.com/");
811 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA;
812
813 MockWrite data_writes[] = {
814 MockWrite("GET / HTTP/1.1\r\n"
815 "Host: www.google.com\r\n"
816 "Connection: keep-alive\r\n\r\n"),
817 };
818
819 MockRead data_reads[] = {
820 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
821 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
822 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
823 // Large content-length -- won't matter, as connection will be reset.
824 MockRead("Content-Length: 10000\r\n\r\n"),
825 MockRead(false, ERR_FAILED),
826 };
827
828 StaticSocketDataProvider data(data_reads, data_writes);
829 session_deps.socket_factory.AddSocketDataProvider(&data);
830 TestCompletionCallback callback;
831
832 int rv = trans->Start(&request, &callback, NULL);
833 EXPECT_EQ(ERR_IO_PENDING, rv);
834
835 rv = callback.WaitForResult();
836 EXPECT_EQ(0, rv);
837
838 const HttpResponseInfo* response = trans->GetResponseInfo();
839 ASSERT_FALSE(response == NULL);
840 EXPECT_TRUE(response->auth_challenge.get() == NULL);
841 }
842
843 // Test the request-challenge-retry sequence for basic auth, over a keep-alive
844 // connection.
TEST_F(HttpNetworkTransactionTest,BasicAuthKeepAlive)845 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAlive) {
846 SessionDependencies session_deps;
847 scoped_ptr<HttpTransaction> trans(
848 new HttpNetworkTransaction(CreateSession(&session_deps)));
849
850 HttpRequestInfo request;
851 request.method = "GET";
852 request.url = GURL("http://www.google.com/");
853 request.load_flags = 0;
854
855 MockWrite data_writes1[] = {
856 MockWrite("GET / HTTP/1.1\r\n"
857 "Host: www.google.com\r\n"
858 "Connection: keep-alive\r\n\r\n"),
859
860 // After calling trans->RestartWithAuth(), this is the request we should
861 // be issuing -- the final header line contains the credentials.
862 MockWrite("GET / HTTP/1.1\r\n"
863 "Host: www.google.com\r\n"
864 "Connection: keep-alive\r\n"
865 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
866 };
867
868 MockRead data_reads1[] = {
869 MockRead("HTTP/1.1 401 Unauthorized\r\n"),
870 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
871 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
872 MockRead("Content-Length: 14\r\n\r\n"),
873 MockRead("Unauthorized\r\n"),
874
875 // Lastly, the server responds with the actual content.
876 MockRead("HTTP/1.1 200 OK\r\n"),
877 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
878 MockRead("Content-Length: 100\r\n\r\n"),
879 MockRead(false, OK),
880 };
881
882 StaticSocketDataProvider data1(data_reads1, data_writes1);
883 session_deps.socket_factory.AddSocketDataProvider(&data1);
884
885 TestCompletionCallback callback1;
886
887 int rv = trans->Start(&request, &callback1, NULL);
888 EXPECT_EQ(ERR_IO_PENDING, rv);
889
890 rv = callback1.WaitForResult();
891 EXPECT_EQ(OK, rv);
892
893 const HttpResponseInfo* response = trans->GetResponseInfo();
894 EXPECT_FALSE(response == NULL);
895
896 // The password prompt info should have been set in response->auth_challenge.
897 EXPECT_FALSE(response->auth_challenge.get() == NULL);
898
899 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
900 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
901 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
902
903 TestCompletionCallback callback2;
904
905 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
906 EXPECT_EQ(ERR_IO_PENDING, rv);
907
908 rv = callback2.WaitForResult();
909 EXPECT_EQ(OK, rv);
910
911 response = trans->GetResponseInfo();
912 EXPECT_FALSE(response == NULL);
913 EXPECT_TRUE(response->auth_challenge.get() == NULL);
914 EXPECT_EQ(100, response->headers->GetContentLength());
915 }
916
917 // Test the request-challenge-retry sequence for basic auth, over a keep-alive
918 // connection and with no response body to drain.
TEST_F(HttpNetworkTransactionTest,BasicAuthKeepAliveNoBody)919 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) {
920 SessionDependencies session_deps;
921 scoped_ptr<HttpTransaction> trans(
922 new HttpNetworkTransaction(CreateSession(&session_deps)));
923
924 HttpRequestInfo request;
925 request.method = "GET";
926 request.url = GURL("http://www.google.com/");
927 request.load_flags = 0;
928
929 MockWrite data_writes1[] = {
930 MockWrite("GET / HTTP/1.1\r\n"
931 "Host: www.google.com\r\n"
932 "Connection: keep-alive\r\n\r\n"),
933
934 // After calling trans->RestartWithAuth(), this is the request we should
935 // be issuing -- the final header line contains the credentials.
936 MockWrite("GET / HTTP/1.1\r\n"
937 "Host: www.google.com\r\n"
938 "Connection: keep-alive\r\n"
939 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
940 };
941
942 MockRead data_reads1[] = {
943 MockRead("HTTP/1.1 401 Unauthorized\r\n"),
944 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
945 MockRead("Content-Length: 0\r\n\r\n"), // No response body.
946
947 // Lastly, the server responds with the actual content.
948 MockRead("HTTP/1.1 200 OK\r\n"),
949 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
950 MockRead("Content-Length: 100\r\n\r\n"),
951 MockRead(false, OK),
952 };
953
954 StaticSocketDataProvider data1(data_reads1, data_writes1);
955 session_deps.socket_factory.AddSocketDataProvider(&data1);
956
957 TestCompletionCallback callback1;
958
959 int rv = trans->Start(&request, &callback1, NULL);
960 EXPECT_EQ(ERR_IO_PENDING, rv);
961
962 rv = callback1.WaitForResult();
963 EXPECT_EQ(OK, rv);
964
965 const HttpResponseInfo* response = trans->GetResponseInfo();
966 EXPECT_FALSE(response == NULL);
967
968 // The password prompt info should have been set in response->auth_challenge.
969 EXPECT_FALSE(response->auth_challenge.get() == NULL);
970
971 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
972 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
973 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
974
975 TestCompletionCallback callback2;
976
977 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
978 EXPECT_EQ(ERR_IO_PENDING, rv);
979
980 rv = callback2.WaitForResult();
981 EXPECT_EQ(OK, rv);
982
983 response = trans->GetResponseInfo();
984 EXPECT_FALSE(response == NULL);
985 EXPECT_TRUE(response->auth_challenge.get() == NULL);
986 EXPECT_EQ(100, response->headers->GetContentLength());
987 }
988
989 // Test the request-challenge-retry sequence for basic auth, over a keep-alive
990 // connection and with a large response body to drain.
TEST_F(HttpNetworkTransactionTest,BasicAuthKeepAliveLargeBody)991 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) {
992 SessionDependencies session_deps;
993 scoped_ptr<HttpTransaction> trans(
994 new HttpNetworkTransaction(CreateSession(&session_deps)));
995
996 HttpRequestInfo request;
997 request.method = "GET";
998 request.url = GURL("http://www.google.com/");
999 request.load_flags = 0;
1000
1001 MockWrite data_writes1[] = {
1002 MockWrite("GET / HTTP/1.1\r\n"
1003 "Host: www.google.com\r\n"
1004 "Connection: keep-alive\r\n\r\n"),
1005
1006 // After calling trans->RestartWithAuth(), this is the request we should
1007 // be issuing -- the final header line contains the credentials.
1008 MockWrite("GET / HTTP/1.1\r\n"
1009 "Host: www.google.com\r\n"
1010 "Connection: keep-alive\r\n"
1011 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1012 };
1013
1014 // Respond with 5 kb of response body.
1015 std::string large_body_string("Unauthorized");
1016 large_body_string.append(5 * 1024, ' ');
1017 large_body_string.append("\r\n");
1018
1019 MockRead data_reads1[] = {
1020 MockRead("HTTP/1.1 401 Unauthorized\r\n"),
1021 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1022 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1023 // 5134 = 12 + 5 * 1024 + 2
1024 MockRead("Content-Length: 5134\r\n\r\n"),
1025 MockRead(true, large_body_string.data(), large_body_string.size()),
1026
1027 // Lastly, the server responds with the actual content.
1028 MockRead("HTTP/1.1 200 OK\r\n"),
1029 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1030 MockRead("Content-Length: 100\r\n\r\n"),
1031 MockRead(false, OK),
1032 };
1033
1034 StaticSocketDataProvider data1(data_reads1, data_writes1);
1035 session_deps.socket_factory.AddSocketDataProvider(&data1);
1036
1037 TestCompletionCallback callback1;
1038
1039 int rv = trans->Start(&request, &callback1, NULL);
1040 EXPECT_EQ(ERR_IO_PENDING, rv);
1041
1042 rv = callback1.WaitForResult();
1043 EXPECT_EQ(OK, rv);
1044
1045 const HttpResponseInfo* response = trans->GetResponseInfo();
1046 EXPECT_FALSE(response == NULL);
1047
1048 // The password prompt info should have been set in response->auth_challenge.
1049 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1050
1051 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
1052 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1053 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1054
1055 TestCompletionCallback callback2;
1056
1057 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
1058 EXPECT_EQ(ERR_IO_PENDING, rv);
1059
1060 rv = callback2.WaitForResult();
1061 EXPECT_EQ(OK, rv);
1062
1063 response = trans->GetResponseInfo();
1064 EXPECT_FALSE(response == NULL);
1065 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1066 EXPECT_EQ(100, response->headers->GetContentLength());
1067 }
1068
1069 // Test the request-challenge-retry sequence for basic auth, over a keep-alive
1070 // connection, but the server gets impatient and closes the connection.
TEST_F(HttpNetworkTransactionTest,BasicAuthKeepAliveImpatientServer)1071 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveImpatientServer) {
1072 SessionDependencies session_deps;
1073 scoped_ptr<HttpTransaction> trans(
1074 new HttpNetworkTransaction(CreateSession(&session_deps)));
1075
1076 HttpRequestInfo request;
1077 request.method = "GET";
1078 request.url = GURL("http://www.google.com/");
1079 request.load_flags = 0;
1080
1081 MockWrite data_writes1[] = {
1082 MockWrite("GET / HTTP/1.1\r\n"
1083 "Host: www.google.com\r\n"
1084 "Connection: keep-alive\r\n\r\n"),
1085 // This simulates the seemingly successful write to a closed connection
1086 // if the bug is not fixed.
1087 MockWrite("GET / HTTP/1.1\r\n"
1088 "Host: www.google.com\r\n"
1089 "Connection: keep-alive\r\n"
1090 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1091 };
1092
1093 MockRead data_reads1[] = {
1094 MockRead("HTTP/1.1 401 Unauthorized\r\n"),
1095 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1096 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1097 MockRead("Content-Length: 14\r\n\r\n"),
1098 // Tell MockTCPClientSocket to simulate the server closing the connection.
1099 MockRead(false, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
1100 MockRead("Unauthorized\r\n"),
1101 MockRead(false, OK), // The server closes the connection.
1102 };
1103
1104 // After calling trans->RestartWithAuth(), this is the request we should
1105 // be issuing -- the final header line contains the credentials.
1106 MockWrite data_writes2[] = {
1107 MockWrite("GET / HTTP/1.1\r\n"
1108 "Host: www.google.com\r\n"
1109 "Connection: keep-alive\r\n"
1110 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1111 };
1112
1113 // Lastly, the server responds with the actual content.
1114 MockRead data_reads2[] = {
1115 MockRead("HTTP/1.1 200 OK\r\n"),
1116 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1117 MockRead("Content-Length: 100\r\n\r\n"),
1118 MockRead(false, OK),
1119 };
1120
1121 StaticSocketDataProvider data1(data_reads1, data_writes1);
1122 StaticSocketDataProvider data2(data_reads2, data_writes2);
1123 session_deps.socket_factory.AddSocketDataProvider(&data1);
1124 session_deps.socket_factory.AddSocketDataProvider(&data2);
1125
1126 TestCompletionCallback callback1;
1127
1128 int rv = trans->Start(&request, &callback1, NULL);
1129 EXPECT_EQ(ERR_IO_PENDING, rv);
1130
1131 rv = callback1.WaitForResult();
1132 EXPECT_EQ(OK, rv);
1133
1134 const HttpResponseInfo* response = trans->GetResponseInfo();
1135 EXPECT_FALSE(response == NULL);
1136
1137 // The password prompt info should have been set in response->auth_challenge.
1138 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1139
1140 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
1141 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1142 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1143
1144 TestCompletionCallback callback2;
1145
1146 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
1147 EXPECT_EQ(ERR_IO_PENDING, rv);
1148
1149 rv = callback2.WaitForResult();
1150 EXPECT_EQ(OK, rv);
1151
1152 response = trans->GetResponseInfo();
1153 ASSERT_FALSE(response == NULL);
1154 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1155 EXPECT_EQ(100, response->headers->GetContentLength());
1156 }
1157
1158 // Test the request-challenge-retry sequence for basic auth, over a keep-alive
1159 // proxy connection, when setting up an SSL tunnel.
TEST_F(HttpNetworkTransactionTest,BasicAuthProxyKeepAlive)1160 TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAlive) {
1161 // Configure against proxy server "myproxy:70".
1162 SessionDependencies session_deps(CreateFixedProxyService("myproxy:70"));
1163 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
1164
1165 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
1166
1167 HttpRequestInfo request;
1168 request.method = "GET";
1169 request.url = GURL("https://www.google.com/");
1170 // Ensure that proxy authentication is attempted even
1171 // when the no authentication data flag is set.
1172 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA;
1173
1174 // Since we have proxy, should try to establish tunnel.
1175 MockWrite data_writes1[] = {
1176 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
1177 "Host: www.google.com\r\n"
1178 "Proxy-Connection: keep-alive\r\n\r\n"),
1179
1180 // After calling trans->RestartWithAuth(), this is the request we should
1181 // be issuing -- the final header line contains the credentials.
1182 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
1183 "Host: www.google.com\r\n"
1184 "Proxy-Connection: keep-alive\r\n"
1185 "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"),
1186 };
1187
1188 // The proxy responds to the connect with a 407, using a persistent
1189 // connection.
1190 MockRead data_reads1[] = {
1191 // No credentials.
1192 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
1193 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1194 MockRead("Content-Length: 10\r\n\r\n"),
1195 MockRead("0123456789"),
1196
1197 // Wrong credentials (wrong password).
1198 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
1199 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1200 MockRead("Content-Length: 10\r\n\r\n"),
1201 // No response body because the test stops reading here.
1202 MockRead(false, ERR_UNEXPECTED), // Should not be reached.
1203 };
1204
1205 StaticSocketDataProvider data1(data_reads1, data_writes1);
1206 session_deps.socket_factory.AddSocketDataProvider(&data1);
1207
1208 TestCompletionCallback callback1;
1209
1210 int rv = trans->Start(&request, &callback1, NULL);
1211 EXPECT_EQ(ERR_IO_PENDING, rv);
1212
1213 rv = callback1.WaitForResult();
1214 EXPECT_EQ(OK, rv);
1215
1216 const HttpResponseInfo* response = trans->GetResponseInfo();
1217 EXPECT_FALSE(response == NULL);
1218
1219 EXPECT_TRUE(response->headers->IsKeepAlive());
1220 EXPECT_EQ(407, response->headers->response_code());
1221 EXPECT_EQ(10, response->headers->GetContentLength());
1222 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
1223
1224 // The password prompt info should have been set in response->auth_challenge.
1225 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1226
1227 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host_and_port);
1228 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1229 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1230
1231 TestCompletionCallback callback2;
1232
1233 // Wrong password (should be "bar").
1234 rv = trans->RestartWithAuth(L"foo", L"baz", &callback2);
1235 EXPECT_EQ(ERR_IO_PENDING, rv);
1236
1237 rv = callback2.WaitForResult();
1238 EXPECT_EQ(OK, rv);
1239
1240 response = trans->GetResponseInfo();
1241 EXPECT_FALSE(response == NULL);
1242
1243 EXPECT_TRUE(response->headers->IsKeepAlive());
1244 EXPECT_EQ(407, response->headers->response_code());
1245 EXPECT_EQ(10, response->headers->GetContentLength());
1246 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
1247
1248 // The password prompt info should have been set in response->auth_challenge.
1249 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1250
1251 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host_and_port);
1252 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1253 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1254 }
1255
1256 // Test that we don't read the response body when we fail to establish a tunnel,
1257 // even if the user cancels the proxy's auth attempt.
TEST_F(HttpNetworkTransactionTest,BasicAuthProxyCancelTunnel)1258 TEST_F(HttpNetworkTransactionTest, BasicAuthProxyCancelTunnel) {
1259 // Configure against proxy server "myproxy:70".
1260 SessionDependencies session_deps(CreateFixedProxyService("myproxy:70"));
1261
1262 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
1263
1264 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
1265
1266 HttpRequestInfo request;
1267 request.method = "GET";
1268 request.url = GURL("https://www.google.com/");
1269 request.load_flags = 0;
1270
1271 // Since we have proxy, should try to establish tunnel.
1272 MockWrite data_writes[] = {
1273 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
1274 "Host: www.google.com\r\n"
1275 "Proxy-Connection: keep-alive\r\n\r\n"),
1276 };
1277
1278 // The proxy responds to the connect with a 407.
1279 MockRead data_reads[] = {
1280 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
1281 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1282 MockRead("Content-Length: 10\r\n\r\n"),
1283 MockRead(false, ERR_UNEXPECTED), // Should not be reached.
1284 };
1285
1286 StaticSocketDataProvider data(data_reads, data_writes);
1287 session_deps.socket_factory.AddSocketDataProvider(&data);
1288
1289 TestCompletionCallback callback;
1290
1291 int rv = trans->Start(&request, &callback, NULL);
1292 EXPECT_EQ(ERR_IO_PENDING, rv);
1293
1294 rv = callback.WaitForResult();
1295 EXPECT_EQ(OK, rv);
1296
1297 const HttpResponseInfo* response = trans->GetResponseInfo();
1298 EXPECT_FALSE(response == NULL);
1299
1300 EXPECT_TRUE(response->headers->IsKeepAlive());
1301 EXPECT_EQ(407, response->headers->response_code());
1302 EXPECT_EQ(10, response->headers->GetContentLength());
1303 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
1304
1305 std::string response_data;
1306 rv = ReadTransaction(trans.get(), &response_data);
1307 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
1308 }
1309
ConnectStatusHelperWithExpectedStatus(const MockRead & status,int expected_status)1310 void HttpNetworkTransactionTest::ConnectStatusHelperWithExpectedStatus(
1311 const MockRead& status, int expected_status) {
1312 // Configure against proxy server "myproxy:70".
1313 SessionDependencies session_deps(CreateFixedProxyService("myproxy:70"));
1314
1315 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
1316
1317 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
1318
1319 HttpRequestInfo request;
1320 request.method = "GET";
1321 request.url = GURL("https://www.google.com/");
1322 request.load_flags = 0;
1323
1324 // Since we have proxy, should try to establish tunnel.
1325 MockWrite data_writes[] = {
1326 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
1327 "Host: www.google.com\r\n"
1328 "Proxy-Connection: keep-alive\r\n\r\n"),
1329 };
1330
1331 MockRead data_reads[] = {
1332 status,
1333 MockRead("Content-Length: 10\r\n\r\n"),
1334 // No response body because the test stops reading here.
1335 MockRead(false, ERR_UNEXPECTED), // Should not be reached.
1336 };
1337
1338 StaticSocketDataProvider data(data_reads, data_writes);
1339 session_deps.socket_factory.AddSocketDataProvider(&data);
1340
1341 TestCompletionCallback callback;
1342
1343 int rv = trans->Start(&request, &callback, NULL);
1344 EXPECT_EQ(ERR_IO_PENDING, rv);
1345
1346 rv = callback.WaitForResult();
1347 EXPECT_EQ(expected_status, rv);
1348 }
1349
ConnectStatusHelper(const MockRead & status)1350 void HttpNetworkTransactionTest::ConnectStatusHelper(const MockRead& status) {
1351 ConnectStatusHelperWithExpectedStatus(
1352 status, ERR_TUNNEL_CONNECTION_FAILED);
1353 }
1354
TEST_F(HttpNetworkTransactionTest,ConnectStatus100)1355 TEST_F(HttpNetworkTransactionTest, ConnectStatus100) {
1356 ConnectStatusHelper(MockRead("HTTP/1.1 100 Continue\r\n"));
1357 }
1358
TEST_F(HttpNetworkTransactionTest,ConnectStatus101)1359 TEST_F(HttpNetworkTransactionTest, ConnectStatus101) {
1360 ConnectStatusHelper(MockRead("HTTP/1.1 101 Switching Protocols\r\n"));
1361 }
1362
TEST_F(HttpNetworkTransactionTest,ConnectStatus201)1363 TEST_F(HttpNetworkTransactionTest, ConnectStatus201) {
1364 ConnectStatusHelper(MockRead("HTTP/1.1 201 Created\r\n"));
1365 }
1366
TEST_F(HttpNetworkTransactionTest,ConnectStatus202)1367 TEST_F(HttpNetworkTransactionTest, ConnectStatus202) {
1368 ConnectStatusHelper(MockRead("HTTP/1.1 202 Accepted\r\n"));
1369 }
1370
TEST_F(HttpNetworkTransactionTest,ConnectStatus203)1371 TEST_F(HttpNetworkTransactionTest, ConnectStatus203) {
1372 ConnectStatusHelper(
1373 MockRead("HTTP/1.1 203 Non-Authoritative Information\r\n"));
1374 }
1375
TEST_F(HttpNetworkTransactionTest,ConnectStatus204)1376 TEST_F(HttpNetworkTransactionTest, ConnectStatus204) {
1377 ConnectStatusHelper(MockRead("HTTP/1.1 204 No Content\r\n"));
1378 }
1379
TEST_F(HttpNetworkTransactionTest,ConnectStatus205)1380 TEST_F(HttpNetworkTransactionTest, ConnectStatus205) {
1381 ConnectStatusHelper(MockRead("HTTP/1.1 205 Reset Content\r\n"));
1382 }
1383
TEST_F(HttpNetworkTransactionTest,ConnectStatus206)1384 TEST_F(HttpNetworkTransactionTest, ConnectStatus206) {
1385 ConnectStatusHelper(MockRead("HTTP/1.1 206 Partial Content\r\n"));
1386 }
1387
TEST_F(HttpNetworkTransactionTest,ConnectStatus300)1388 TEST_F(HttpNetworkTransactionTest, ConnectStatus300) {
1389 ConnectStatusHelper(MockRead("HTTP/1.1 300 Multiple Choices\r\n"));
1390 }
1391
TEST_F(HttpNetworkTransactionTest,ConnectStatus301)1392 TEST_F(HttpNetworkTransactionTest, ConnectStatus301) {
1393 ConnectStatusHelper(MockRead("HTTP/1.1 301 Moved Permanently\r\n"));
1394 }
1395
TEST_F(HttpNetworkTransactionTest,ConnectStatus302)1396 TEST_F(HttpNetworkTransactionTest, ConnectStatus302) {
1397 ConnectStatusHelper(MockRead("HTTP/1.1 302 Found\r\n"));
1398 }
1399
TEST_F(HttpNetworkTransactionTest,ConnectStatus303)1400 TEST_F(HttpNetworkTransactionTest, ConnectStatus303) {
1401 ConnectStatusHelper(MockRead("HTTP/1.1 303 See Other\r\n"));
1402 }
1403
TEST_F(HttpNetworkTransactionTest,ConnectStatus304)1404 TEST_F(HttpNetworkTransactionTest, ConnectStatus304) {
1405 ConnectStatusHelper(MockRead("HTTP/1.1 304 Not Modified\r\n"));
1406 }
1407
TEST_F(HttpNetworkTransactionTest,ConnectStatus305)1408 TEST_F(HttpNetworkTransactionTest, ConnectStatus305) {
1409 ConnectStatusHelper(MockRead("HTTP/1.1 305 Use Proxy\r\n"));
1410 }
1411
TEST_F(HttpNetworkTransactionTest,ConnectStatus306)1412 TEST_F(HttpNetworkTransactionTest, ConnectStatus306) {
1413 ConnectStatusHelper(MockRead("HTTP/1.1 306\r\n"));
1414 }
1415
TEST_F(HttpNetworkTransactionTest,ConnectStatus307)1416 TEST_F(HttpNetworkTransactionTest, ConnectStatus307) {
1417 ConnectStatusHelper(MockRead("HTTP/1.1 307 Temporary Redirect\r\n"));
1418 }
1419
TEST_F(HttpNetworkTransactionTest,ConnectStatus400)1420 TEST_F(HttpNetworkTransactionTest, ConnectStatus400) {
1421 ConnectStatusHelper(MockRead("HTTP/1.1 400 Bad Request\r\n"));
1422 }
1423
TEST_F(HttpNetworkTransactionTest,ConnectStatus401)1424 TEST_F(HttpNetworkTransactionTest, ConnectStatus401) {
1425 ConnectStatusHelper(MockRead("HTTP/1.1 401 Unauthorized\r\n"));
1426 }
1427
TEST_F(HttpNetworkTransactionTest,ConnectStatus402)1428 TEST_F(HttpNetworkTransactionTest, ConnectStatus402) {
1429 ConnectStatusHelper(MockRead("HTTP/1.1 402 Payment Required\r\n"));
1430 }
1431
TEST_F(HttpNetworkTransactionTest,ConnectStatus403)1432 TEST_F(HttpNetworkTransactionTest, ConnectStatus403) {
1433 ConnectStatusHelper(MockRead("HTTP/1.1 403 Forbidden\r\n"));
1434 }
1435
TEST_F(HttpNetworkTransactionTest,ConnectStatus404)1436 TEST_F(HttpNetworkTransactionTest, ConnectStatus404) {
1437 ConnectStatusHelper(MockRead("HTTP/1.1 404 Not Found\r\n"));
1438 }
1439
TEST_F(HttpNetworkTransactionTest,ConnectStatus405)1440 TEST_F(HttpNetworkTransactionTest, ConnectStatus405) {
1441 ConnectStatusHelper(MockRead("HTTP/1.1 405 Method Not Allowed\r\n"));
1442 }
1443
TEST_F(HttpNetworkTransactionTest,ConnectStatus406)1444 TEST_F(HttpNetworkTransactionTest, ConnectStatus406) {
1445 ConnectStatusHelper(MockRead("HTTP/1.1 406 Not Acceptable\r\n"));
1446 }
1447
TEST_F(HttpNetworkTransactionTest,ConnectStatus407)1448 TEST_F(HttpNetworkTransactionTest, ConnectStatus407) {
1449 ConnectStatusHelperWithExpectedStatus(
1450 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
1451 ERR_PROXY_AUTH_REQUESTED);
1452 }
1453
TEST_F(HttpNetworkTransactionTest,ConnectStatus408)1454 TEST_F(HttpNetworkTransactionTest, ConnectStatus408) {
1455 ConnectStatusHelper(MockRead("HTTP/1.1 408 Request Timeout\r\n"));
1456 }
1457
TEST_F(HttpNetworkTransactionTest,ConnectStatus409)1458 TEST_F(HttpNetworkTransactionTest, ConnectStatus409) {
1459 ConnectStatusHelper(MockRead("HTTP/1.1 409 Conflict\r\n"));
1460 }
1461
TEST_F(HttpNetworkTransactionTest,ConnectStatus410)1462 TEST_F(HttpNetworkTransactionTest, ConnectStatus410) {
1463 ConnectStatusHelper(MockRead("HTTP/1.1 410 Gone\r\n"));
1464 }
1465
TEST_F(HttpNetworkTransactionTest,ConnectStatus411)1466 TEST_F(HttpNetworkTransactionTest, ConnectStatus411) {
1467 ConnectStatusHelper(MockRead("HTTP/1.1 411 Length Required\r\n"));
1468 }
1469
TEST_F(HttpNetworkTransactionTest,ConnectStatus412)1470 TEST_F(HttpNetworkTransactionTest, ConnectStatus412) {
1471 ConnectStatusHelper(MockRead("HTTP/1.1 412 Precondition Failed\r\n"));
1472 }
1473
TEST_F(HttpNetworkTransactionTest,ConnectStatus413)1474 TEST_F(HttpNetworkTransactionTest, ConnectStatus413) {
1475 ConnectStatusHelper(MockRead("HTTP/1.1 413 Request Entity Too Large\r\n"));
1476 }
1477
TEST_F(HttpNetworkTransactionTest,ConnectStatus414)1478 TEST_F(HttpNetworkTransactionTest, ConnectStatus414) {
1479 ConnectStatusHelper(MockRead("HTTP/1.1 414 Request-URI Too Long\r\n"));
1480 }
1481
TEST_F(HttpNetworkTransactionTest,ConnectStatus415)1482 TEST_F(HttpNetworkTransactionTest, ConnectStatus415) {
1483 ConnectStatusHelper(MockRead("HTTP/1.1 415 Unsupported Media Type\r\n"));
1484 }
1485
TEST_F(HttpNetworkTransactionTest,ConnectStatus416)1486 TEST_F(HttpNetworkTransactionTest, ConnectStatus416) {
1487 ConnectStatusHelper(
1488 MockRead("HTTP/1.1 416 Requested Range Not Satisfiable\r\n"));
1489 }
1490
TEST_F(HttpNetworkTransactionTest,ConnectStatus417)1491 TEST_F(HttpNetworkTransactionTest, ConnectStatus417) {
1492 ConnectStatusHelper(MockRead("HTTP/1.1 417 Expectation Failed\r\n"));
1493 }
1494
TEST_F(HttpNetworkTransactionTest,ConnectStatus500)1495 TEST_F(HttpNetworkTransactionTest, ConnectStatus500) {
1496 ConnectStatusHelper(MockRead("HTTP/1.1 500 Internal Server Error\r\n"));
1497 }
1498
TEST_F(HttpNetworkTransactionTest,ConnectStatus501)1499 TEST_F(HttpNetworkTransactionTest, ConnectStatus501) {
1500 ConnectStatusHelper(MockRead("HTTP/1.1 501 Not Implemented\r\n"));
1501 }
1502
TEST_F(HttpNetworkTransactionTest,ConnectStatus502)1503 TEST_F(HttpNetworkTransactionTest, ConnectStatus502) {
1504 ConnectStatusHelper(MockRead("HTTP/1.1 502 Bad Gateway\r\n"));
1505 }
1506
TEST_F(HttpNetworkTransactionTest,ConnectStatus503)1507 TEST_F(HttpNetworkTransactionTest, ConnectStatus503) {
1508 ConnectStatusHelper(MockRead("HTTP/1.1 503 Service Unavailable\r\n"));
1509 }
1510
TEST_F(HttpNetworkTransactionTest,ConnectStatus504)1511 TEST_F(HttpNetworkTransactionTest, ConnectStatus504) {
1512 ConnectStatusHelper(MockRead("HTTP/1.1 504 Gateway Timeout\r\n"));
1513 }
1514
TEST_F(HttpNetworkTransactionTest,ConnectStatus505)1515 TEST_F(HttpNetworkTransactionTest, ConnectStatus505) {
1516 ConnectStatusHelper(MockRead("HTTP/1.1 505 HTTP Version Not Supported\r\n"));
1517 }
1518
1519 // Test the flow when both the proxy server AND origin server require
1520 // authentication. Again, this uses basic auth for both since that is
1521 // the simplest to mock.
TEST_F(HttpNetworkTransactionTest,BasicAuthProxyThenServer)1522 TEST_F(HttpNetworkTransactionTest, BasicAuthProxyThenServer) {
1523 SessionDependencies session_deps(CreateFixedProxyService("myproxy:70"));
1524
1525 // Configure against proxy server "myproxy:70".
1526 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
1527 CreateSession(&session_deps)));
1528
1529 HttpRequestInfo request;
1530 request.method = "GET";
1531 request.url = GURL("http://www.google.com/");
1532 request.load_flags = 0;
1533
1534 MockWrite data_writes1[] = {
1535 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
1536 "Host: www.google.com\r\n"
1537 "Proxy-Connection: keep-alive\r\n\r\n"),
1538 };
1539
1540 MockRead data_reads1[] = {
1541 MockRead("HTTP/1.0 407 Unauthorized\r\n"),
1542 // Give a couple authenticate options (only the middle one is actually
1543 // supported).
1544 MockRead("Proxy-Authenticate: Basic invalid\r\n"), // Malformed.
1545 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1546 MockRead("Proxy-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"),
1547 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1548 // Large content-length -- won't matter, as connection will be reset.
1549 MockRead("Content-Length: 10000\r\n\r\n"),
1550 MockRead(false, ERR_FAILED),
1551 };
1552
1553 // After calling trans->RestartWithAuth() the first time, this is the
1554 // request we should be issuing -- the final header line contains the
1555 // proxy's credentials.
1556 MockWrite data_writes2[] = {
1557 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
1558 "Host: www.google.com\r\n"
1559 "Proxy-Connection: keep-alive\r\n"
1560 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1561 };
1562
1563 // Now the proxy server lets the request pass through to origin server.
1564 // The origin server responds with a 401.
1565 MockRead data_reads2[] = {
1566 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
1567 // Note: We are using the same realm-name as the proxy server. This is
1568 // completely valid, as realms are unique across hosts.
1569 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1570 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1571 MockRead("Content-Length: 2000\r\n\r\n"),
1572 MockRead(false, ERR_FAILED), // Won't be reached.
1573 };
1574
1575 // After calling trans->RestartWithAuth() the second time, we should send
1576 // the credentials for both the proxy and origin server.
1577 MockWrite data_writes3[] = {
1578 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
1579 "Host: www.google.com\r\n"
1580 "Proxy-Connection: keep-alive\r\n"
1581 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n"
1582 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"),
1583 };
1584
1585 // Lastly we get the desired content.
1586 MockRead data_reads3[] = {
1587 MockRead("HTTP/1.0 200 OK\r\n"),
1588 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1589 MockRead("Content-Length: 100\r\n\r\n"),
1590 MockRead(false, OK),
1591 };
1592
1593 StaticSocketDataProvider data1(data_reads1, data_writes1);
1594 StaticSocketDataProvider data2(data_reads2, data_writes2);
1595 StaticSocketDataProvider data3(data_reads3, data_writes3);
1596 session_deps.socket_factory.AddSocketDataProvider(&data1);
1597 session_deps.socket_factory.AddSocketDataProvider(&data2);
1598 session_deps.socket_factory.AddSocketDataProvider(&data3);
1599
1600 TestCompletionCallback callback1;
1601
1602 int rv = trans->Start(&request, &callback1, NULL);
1603 EXPECT_EQ(ERR_IO_PENDING, rv);
1604
1605 rv = callback1.WaitForResult();
1606 EXPECT_EQ(OK, rv);
1607
1608 const HttpResponseInfo* response = trans->GetResponseInfo();
1609 EXPECT_FALSE(response == NULL);
1610
1611 // The password prompt info should have been set in response->auth_challenge.
1612 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1613
1614 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host_and_port);
1615 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1616 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1617
1618 TestCompletionCallback callback2;
1619
1620 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
1621 EXPECT_EQ(ERR_IO_PENDING, rv);
1622
1623 rv = callback2.WaitForResult();
1624 EXPECT_EQ(OK, rv);
1625
1626 response = trans->GetResponseInfo();
1627 EXPECT_FALSE(response == NULL);
1628 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1629
1630 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
1631 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1632 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1633
1634 TestCompletionCallback callback3;
1635
1636 rv = trans->RestartWithAuth(L"foo2", L"bar2", &callback3);
1637 EXPECT_EQ(ERR_IO_PENDING, rv);
1638
1639 rv = callback3.WaitForResult();
1640 EXPECT_EQ(OK, rv);
1641
1642 response = trans->GetResponseInfo();
1643 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1644 EXPECT_EQ(100, response->headers->GetContentLength());
1645 }
1646
1647 // For the NTLM implementation using SSPI, we skip the NTLM tests since we
1648 // can't hook into its internals to cause it to generate predictable NTLM
1649 // authorization headers.
1650 #if defined(NTLM_PORTABLE)
1651 // The NTLM authentication unit tests were generated by capturing the HTTP
1652 // requests and responses using Fiddler 2 and inspecting the generated random
1653 // bytes in the debugger.
1654
1655 // Enter the correct password and authenticate successfully.
TEST_F(HttpNetworkTransactionTest,NTLMAuth1)1656 TEST_F(HttpNetworkTransactionTest, NTLMAuth1) {
1657 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockGenerateRandom1,
1658 MockGetHostName);
1659 SessionDependencies session_deps;
1660 scoped_ptr<HttpTransaction> trans(
1661 new HttpNetworkTransaction(CreateSession(&session_deps)));
1662
1663 HttpRequestInfo request;
1664 request.method = "GET";
1665 request.url = GURL("http://172.22.68.17/kids/login.aspx");
1666 request.load_flags = 0;
1667
1668 MockWrite data_writes1[] = {
1669 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1670 "Host: 172.22.68.17\r\n"
1671 "Connection: keep-alive\r\n\r\n"),
1672 };
1673
1674 MockRead data_reads1[] = {
1675 MockRead("HTTP/1.1 401 Access Denied\r\n"),
1676 // Negotiate and NTLM are often requested together. We only support NTLM.
1677 MockRead("WWW-Authenticate: Negotiate\r\n"),
1678 MockRead("WWW-Authenticate: NTLM\r\n"),
1679 MockRead("Connection: close\r\n"),
1680 MockRead("Content-Length: 42\r\n"),
1681 MockRead("Content-Type: text/html\r\n\r\n"),
1682 // Missing content -- won't matter, as connection will be reset.
1683 MockRead(false, ERR_UNEXPECTED),
1684 };
1685
1686 MockWrite data_writes2[] = {
1687 // After restarting with a null identity, this is the
1688 // request we should be issuing -- the final header line contains a Type
1689 // 1 message.
1690 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1691 "Host: 172.22.68.17\r\n"
1692 "Connection: keep-alive\r\n"
1693 "Authorization: NTLM "
1694 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"),
1695
1696 // After calling trans->RestartWithAuth(), we should send a Type 3 message
1697 // (the credentials for the origin server). The second request continues
1698 // on the same connection.
1699 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1700 "Host: 172.22.68.17\r\n"
1701 "Connection: keep-alive\r\n"
1702 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA"
1703 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA"
1704 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBVKW"
1705 "Yma5xzVAAAAAAAAAAAAAAAAAAAAACH+gWcm+YsP9Tqb9zCR3WAeZZX"
1706 "ahlhx5I=\r\n\r\n"),
1707 };
1708
1709 MockRead data_reads2[] = {
1710 // The origin server responds with a Type 2 message.
1711 MockRead("HTTP/1.1 401 Access Denied\r\n"),
1712 MockRead("WWW-Authenticate: NTLM "
1713 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCjGpMpPGlYKkAAAAAAAAAALo"
1714 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE"
1715 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA"
1716 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy"
1717 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB"
1718 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw"
1719 "BtAAAAAAA=\r\n"),
1720 MockRead("Content-Length: 42\r\n"),
1721 MockRead("Content-Type: text/html\r\n\r\n"),
1722 MockRead("You are not authorized to view this page\r\n"),
1723
1724 // Lastly we get the desired content.
1725 MockRead("HTTP/1.1 200 OK\r\n"),
1726 MockRead("Content-Type: text/html; charset=utf-8\r\n"),
1727 MockRead("Content-Length: 13\r\n\r\n"),
1728 MockRead("Please Login\r\n"),
1729 MockRead(false, OK),
1730 };
1731
1732 StaticSocketDataProvider data1(data_reads1, data_writes1);
1733 StaticSocketDataProvider data2(data_reads2, data_writes2);
1734 session_deps.socket_factory.AddSocketDataProvider(&data1);
1735 session_deps.socket_factory.AddSocketDataProvider(&data2);
1736
1737 TestCompletionCallback callback1;
1738
1739 int rv = trans->Start(&request, &callback1, NULL);
1740 EXPECT_EQ(ERR_IO_PENDING, rv);
1741
1742 rv = callback1.WaitForResult();
1743 EXPECT_EQ(OK, rv);
1744
1745 EXPECT_TRUE(trans->IsReadyToRestartForAuth());
1746 TestCompletionCallback callback2;
1747 rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback2);
1748 EXPECT_EQ(ERR_IO_PENDING, rv);
1749 rv = callback2.WaitForResult();
1750 EXPECT_EQ(OK, rv);
1751 EXPECT_FALSE(trans->IsReadyToRestartForAuth());
1752
1753 const HttpResponseInfo* response = trans->GetResponseInfo();
1754 EXPECT_FALSE(response == NULL);
1755
1756 // The password prompt info should have been set in response->auth_challenge.
1757 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1758
1759 EXPECT_EQ(L"172.22.68.17:80", response->auth_challenge->host_and_port);
1760 EXPECT_EQ(L"", response->auth_challenge->realm);
1761 EXPECT_EQ(L"ntlm", response->auth_challenge->scheme);
1762
1763 TestCompletionCallback callback3;
1764
1765 rv = trans->RestartWithAuth(L"testing-ntlm", L"testing-ntlm", &callback3);
1766 EXPECT_EQ(ERR_IO_PENDING, rv);
1767
1768 rv = callback3.WaitForResult();
1769 EXPECT_EQ(OK, rv);
1770
1771 response = trans->GetResponseInfo();
1772 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1773 EXPECT_EQ(13, response->headers->GetContentLength());
1774 }
1775
1776 // Enter a wrong password, and then the correct one.
TEST_F(HttpNetworkTransactionTest,NTLMAuth2)1777 TEST_F(HttpNetworkTransactionTest, NTLMAuth2) {
1778 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockGenerateRandom2,
1779 MockGetHostName);
1780 SessionDependencies session_deps;
1781 scoped_ptr<HttpTransaction> trans(
1782 new HttpNetworkTransaction(CreateSession(&session_deps)));
1783
1784 HttpRequestInfo request;
1785 request.method = "GET";
1786 request.url = GURL("http://172.22.68.17/kids/login.aspx");
1787 request.load_flags = 0;
1788
1789 MockWrite data_writes1[] = {
1790 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1791 "Host: 172.22.68.17\r\n"
1792 "Connection: keep-alive\r\n\r\n"),
1793 };
1794
1795 MockRead data_reads1[] = {
1796 MockRead("HTTP/1.1 401 Access Denied\r\n"),
1797 // Negotiate and NTLM are often requested together. We only support NTLM.
1798 MockRead("WWW-Authenticate: Negotiate\r\n"),
1799 MockRead("WWW-Authenticate: NTLM\r\n"),
1800 MockRead("Connection: close\r\n"),
1801 MockRead("Content-Length: 42\r\n"),
1802 MockRead("Content-Type: text/html\r\n\r\n"),
1803 // Missing content -- won't matter, as connection will be reset.
1804 MockRead(false, ERR_UNEXPECTED),
1805 };
1806
1807 MockWrite data_writes2[] = {
1808 // After restarting with a null identity, this is the
1809 // request we should be issuing -- the final header line contains a Type
1810 // 1 message.
1811 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1812 "Host: 172.22.68.17\r\n"
1813 "Connection: keep-alive\r\n"
1814 "Authorization: NTLM "
1815 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"),
1816
1817 // After calling trans->RestartWithAuth(), we should send a Type 3 message
1818 // (the credentials for the origin server). The second request continues
1819 // on the same connection.
1820 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1821 "Host: 172.22.68.17\r\n"
1822 "Connection: keep-alive\r\n"
1823 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA"
1824 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA"
1825 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwCWeY"
1826 "XnSZNwoQAAAAAAAAAAAAAAAAAAAADLa34/phTTKzNTWdub+uyFleOj"
1827 "4Ww7b7E=\r\n\r\n"),
1828 };
1829
1830 MockRead data_reads2[] = {
1831 // The origin server responds with a Type 2 message.
1832 MockRead("HTTP/1.1 401 Access Denied\r\n"),
1833 MockRead("WWW-Authenticate: NTLM "
1834 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCbVWUZezVGpAAAAAAAAAAALo"
1835 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE"
1836 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA"
1837 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy"
1838 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB"
1839 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw"
1840 "BtAAAAAAA=\r\n"),
1841 MockRead("Content-Length: 42\r\n"),
1842 MockRead("Content-Type: text/html\r\n\r\n"),
1843 MockRead("You are not authorized to view this page\r\n"),
1844
1845 // Wrong password.
1846 MockRead("HTTP/1.1 401 Access Denied\r\n"),
1847 MockRead("WWW-Authenticate: Negotiate\r\n"),
1848 MockRead("WWW-Authenticate: NTLM\r\n"),
1849 MockRead("Connection: close\r\n"),
1850 MockRead("Content-Length: 42\r\n"),
1851 MockRead("Content-Type: text/html\r\n\r\n"),
1852 // Missing content -- won't matter, as connection will be reset.
1853 MockRead(false, ERR_UNEXPECTED),
1854 };
1855
1856 MockWrite data_writes3[] = {
1857 // After restarting with a null identity, this is the
1858 // request we should be issuing -- the final header line contains a Type
1859 // 1 message.
1860 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1861 "Host: 172.22.68.17\r\n"
1862 "Connection: keep-alive\r\n"
1863 "Authorization: NTLM "
1864 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"),
1865
1866 // After calling trans->RestartWithAuth(), we should send a Type 3 message
1867 // (the credentials for the origin server). The second request continues
1868 // on the same connection.
1869 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1870 "Host: 172.22.68.17\r\n"
1871 "Connection: keep-alive\r\n"
1872 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA"
1873 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA"
1874 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBO54"
1875 "dFMVvTHwAAAAAAAAAAAAAAAAAAAACS7sT6Uzw7L0L//WUqlIaVWpbI"
1876 "+4MUm7c=\r\n\r\n"),
1877 };
1878
1879 MockRead data_reads3[] = {
1880 // The origin server responds with a Type 2 message.
1881 MockRead("HTTP/1.1 401 Access Denied\r\n"),
1882 MockRead("WWW-Authenticate: NTLM "
1883 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCL24VN8dgOR8AAAAAAAAAALo"
1884 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE"
1885 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA"
1886 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy"
1887 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB"
1888 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw"
1889 "BtAAAAAAA=\r\n"),
1890 MockRead("Content-Length: 42\r\n"),
1891 MockRead("Content-Type: text/html\r\n\r\n"),
1892 MockRead("You are not authorized to view this page\r\n"),
1893
1894 // Lastly we get the desired content.
1895 MockRead("HTTP/1.1 200 OK\r\n"),
1896 MockRead("Content-Type: text/html; charset=utf-8\r\n"),
1897 MockRead("Content-Length: 13\r\n\r\n"),
1898 MockRead("Please Login\r\n"),
1899 MockRead(false, OK),
1900 };
1901
1902 StaticSocketDataProvider data1(data_reads1, data_writes1);
1903 StaticSocketDataProvider data2(data_reads2, data_writes2);
1904 StaticSocketDataProvider data3(data_reads3, data_writes3);
1905 session_deps.socket_factory.AddSocketDataProvider(&data1);
1906 session_deps.socket_factory.AddSocketDataProvider(&data2);
1907 session_deps.socket_factory.AddSocketDataProvider(&data3);
1908
1909 TestCompletionCallback callback1;
1910
1911 int rv = trans->Start(&request, &callback1, NULL);
1912 EXPECT_EQ(ERR_IO_PENDING, rv);
1913
1914 rv = callback1.WaitForResult();
1915 EXPECT_EQ(OK, rv);
1916
1917 EXPECT_TRUE(trans->IsReadyToRestartForAuth());
1918 TestCompletionCallback callback2;
1919 rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback2);
1920 EXPECT_EQ(ERR_IO_PENDING, rv);
1921 rv = callback2.WaitForResult();
1922 EXPECT_EQ(OK, rv);
1923 EXPECT_FALSE(trans->IsReadyToRestartForAuth());
1924
1925 const HttpResponseInfo* response = trans->GetResponseInfo();
1926 EXPECT_FALSE(response == NULL);
1927
1928 // The password prompt info should have been set in response->auth_challenge.
1929 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1930
1931 EXPECT_EQ(L"172.22.68.17:80", response->auth_challenge->host_and_port);
1932 EXPECT_EQ(L"", response->auth_challenge->realm);
1933 EXPECT_EQ(L"ntlm", response->auth_challenge->scheme);
1934
1935 TestCompletionCallback callback3;
1936
1937 // Enter the wrong password.
1938 rv = trans->RestartWithAuth(L"testing-ntlm", L"wrongpassword", &callback3);
1939 EXPECT_EQ(ERR_IO_PENDING, rv);
1940
1941 rv = callback3.WaitForResult();
1942 EXPECT_EQ(OK, rv);
1943
1944 EXPECT_TRUE(trans->IsReadyToRestartForAuth());
1945 TestCompletionCallback callback4;
1946 rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback4);
1947 EXPECT_EQ(ERR_IO_PENDING, rv);
1948 rv = callback4.WaitForResult();
1949 EXPECT_EQ(OK, rv);
1950 EXPECT_FALSE(trans->IsReadyToRestartForAuth());
1951
1952 response = trans->GetResponseInfo();
1953 EXPECT_FALSE(response == NULL);
1954
1955 // The password prompt info should have been set in response->auth_challenge.
1956 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1957
1958 EXPECT_EQ(L"172.22.68.17:80", response->auth_challenge->host_and_port);
1959 EXPECT_EQ(L"", response->auth_challenge->realm);
1960 EXPECT_EQ(L"ntlm", response->auth_challenge->scheme);
1961
1962 TestCompletionCallback callback5;
1963
1964 // Now enter the right password.
1965 rv = trans->RestartWithAuth(L"testing-ntlm", L"testing-ntlm", &callback5);
1966 EXPECT_EQ(ERR_IO_PENDING, rv);
1967
1968 rv = callback5.WaitForResult();
1969 EXPECT_EQ(OK, rv);
1970
1971 response = trans->GetResponseInfo();
1972 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1973 EXPECT_EQ(13, response->headers->GetContentLength());
1974 }
1975 #endif // NTLM_PORTABLE
1976
1977 // Test reading a server response which has only headers, and no body.
1978 // After some maximum number of bytes is consumed, the transaction should
1979 // fail with ERR_RESPONSE_HEADERS_TOO_BIG.
TEST_F(HttpNetworkTransactionTest,LargeHeadersNoBody)1980 TEST_F(HttpNetworkTransactionTest, LargeHeadersNoBody) {
1981 SessionDependencies session_deps;
1982 scoped_ptr<HttpTransaction> trans(
1983 new HttpNetworkTransaction(CreateSession(&session_deps)));
1984
1985 HttpRequestInfo request;
1986 request.method = "GET";
1987 request.url = GURL("http://www.google.com/");
1988 request.load_flags = 0;
1989
1990 // Respond with 300 kb of headers (we should fail after 256 kb).
1991 std::string large_headers_string;
1992 FillLargeHeadersString(&large_headers_string, 300 * 1024);
1993
1994 MockRead data_reads[] = {
1995 MockRead("HTTP/1.0 200 OK\r\n"),
1996 MockRead(true, large_headers_string.data(), large_headers_string.size()),
1997 MockRead("\r\nBODY"),
1998 MockRead(false, OK),
1999 };
2000 StaticSocketDataProvider data(data_reads, NULL);
2001 session_deps.socket_factory.AddSocketDataProvider(&data);
2002
2003 TestCompletionCallback callback;
2004
2005 int rv = trans->Start(&request, &callback, NULL);
2006 EXPECT_EQ(ERR_IO_PENDING, rv);
2007
2008 rv = callback.WaitForResult();
2009 EXPECT_EQ(ERR_RESPONSE_HEADERS_TOO_BIG, rv);
2010
2011 const HttpResponseInfo* response = trans->GetResponseInfo();
2012 EXPECT_TRUE(response == NULL);
2013 }
2014
2015 // Make sure that we don't try to reuse a TCPClientSocket when failing to
2016 // establish tunnel.
2017 // http://code.google.com/p/chromium/issues/detail?id=3772
TEST_F(HttpNetworkTransactionTest,DontRecycleTCPSocketForSSLTunnel)2018 TEST_F(HttpNetworkTransactionTest, DontRecycleTCPSocketForSSLTunnel) {
2019 // Configure against proxy server "myproxy:70".
2020 SessionDependencies session_deps(CreateFixedProxyService("myproxy:70"));
2021
2022 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
2023
2024 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
2025
2026 HttpRequestInfo request;
2027 request.method = "GET";
2028 request.url = GURL("https://www.google.com/");
2029 request.load_flags = 0;
2030
2031 // Since we have proxy, should try to establish tunnel.
2032 MockWrite data_writes1[] = {
2033 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
2034 "Host: www.google.com\r\n"
2035 "Proxy-Connection: keep-alive\r\n\r\n"),
2036 };
2037
2038 // The proxy responds to the connect with a 404, using a persistent
2039 // connection. Usually a proxy would return 501 (not implemented),
2040 // or 200 (tunnel established).
2041 MockRead data_reads1[] = {
2042 MockRead("HTTP/1.1 404 Not Found\r\n"),
2043 MockRead("Content-Length: 10\r\n\r\n"),
2044 MockRead(false, ERR_UNEXPECTED), // Should not be reached.
2045 };
2046
2047 StaticSocketDataProvider data1(data_reads1, data_writes1);
2048 session_deps.socket_factory.AddSocketDataProvider(&data1);
2049
2050 TestCompletionCallback callback1;
2051
2052 int rv = trans->Start(&request, &callback1, NULL);
2053 EXPECT_EQ(ERR_IO_PENDING, rv);
2054
2055 rv = callback1.WaitForResult();
2056 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
2057
2058 const HttpResponseInfo* response = trans->GetResponseInfo();
2059 EXPECT_TRUE(response == NULL);
2060
2061 // Empty the current queue. This is necessary because idle sockets are
2062 // added to the connection pool asynchronously with a PostTask.
2063 MessageLoop::current()->RunAllPending();
2064
2065 // We now check to make sure the TCPClientSocket was not added back to
2066 // the pool.
2067 EXPECT_EQ(0, session->tcp_socket_pool()->IdleSocketCount());
2068 trans.reset();
2069 MessageLoop::current()->RunAllPending();
2070 // Make sure that the socket didn't get recycled after calling the destructor.
2071 EXPECT_EQ(0, session->tcp_socket_pool()->IdleSocketCount());
2072 }
2073
2074 // Make sure that we recycle a socket after reading all of the response body.
TEST_F(HttpNetworkTransactionTest,RecycleSocket)2075 TEST_F(HttpNetworkTransactionTest, RecycleSocket) {
2076 SessionDependencies session_deps;
2077 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
2078
2079 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
2080
2081 HttpRequestInfo request;
2082 request.method = "GET";
2083 request.url = GURL("http://www.google.com/");
2084 request.load_flags = 0;
2085
2086 MockRead data_reads[] = {
2087 // A part of the response body is received with the response headers.
2088 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\nhel"),
2089 // The rest of the response body is received in two parts.
2090 MockRead("lo"),
2091 MockRead(" world"),
2092 MockRead("junk"), // Should not be read!!
2093 MockRead(false, OK),
2094 };
2095
2096 StaticSocketDataProvider data(data_reads, NULL);
2097 session_deps.socket_factory.AddSocketDataProvider(&data);
2098
2099 TestCompletionCallback callback;
2100
2101 int rv = trans->Start(&request, &callback, NULL);
2102 EXPECT_EQ(ERR_IO_PENDING, rv);
2103
2104 rv = callback.WaitForResult();
2105 EXPECT_EQ(OK, rv);
2106
2107 const HttpResponseInfo* response = trans->GetResponseInfo();
2108 EXPECT_TRUE(response != NULL);
2109
2110 EXPECT_TRUE(response->headers != NULL);
2111 std::string status_line = response->headers->GetStatusLine();
2112 EXPECT_EQ("HTTP/1.1 200 OK", status_line);
2113
2114 EXPECT_EQ(0, session->tcp_socket_pool()->IdleSocketCount());
2115
2116 std::string response_data;
2117 rv = ReadTransaction(trans.get(), &response_data);
2118 EXPECT_EQ(OK, rv);
2119 EXPECT_EQ("hello world", response_data);
2120
2121 // Empty the current queue. This is necessary because idle sockets are
2122 // added to the connection pool asynchronously with a PostTask.
2123 MessageLoop::current()->RunAllPending();
2124
2125 // We now check to make sure the socket was added back to the pool.
2126 EXPECT_EQ(1, session->tcp_socket_pool()->IdleSocketCount());
2127 }
2128
2129 // Make sure that we recycle a socket after a zero-length response.
2130 // http://crbug.com/9880
TEST_F(HttpNetworkTransactionTest,RecycleSocketAfterZeroContentLength)2131 TEST_F(HttpNetworkTransactionTest, RecycleSocketAfterZeroContentLength) {
2132 SessionDependencies session_deps;
2133 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
2134
2135 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
2136
2137 HttpRequestInfo request;
2138 request.method = "GET";
2139 request.url = GURL("http://www.google.com/csi?v=3&s=web&action=&"
2140 "tran=undefined&ei=mAXcSeegAo-SMurloeUN&"
2141 "e=17259,18167,19592,19773,19981,20133,20173,20233&"
2142 "rt=prt.2642,ol.2649,xjs.2951");
2143 request.load_flags = 0;
2144
2145 MockRead data_reads[] = {
2146 MockRead("HTTP/1.1 204 No Content\r\n"
2147 "Content-Length: 0\r\n"
2148 "Content-Type: text/html\r\n\r\n"),
2149 MockRead("junk"), // Should not be read!!
2150 MockRead(false, OK),
2151 };
2152
2153 StaticSocketDataProvider data(data_reads, NULL);
2154 session_deps.socket_factory.AddSocketDataProvider(&data);
2155
2156 TestCompletionCallback callback;
2157
2158 int rv = trans->Start(&request, &callback, NULL);
2159 EXPECT_EQ(ERR_IO_PENDING, rv);
2160
2161 rv = callback.WaitForResult();
2162 EXPECT_EQ(OK, rv);
2163
2164 const HttpResponseInfo* response = trans->GetResponseInfo();
2165 EXPECT_TRUE(response != NULL);
2166
2167 EXPECT_TRUE(response->headers != NULL);
2168 std::string status_line = response->headers->GetStatusLine();
2169 EXPECT_EQ("HTTP/1.1 204 No Content", status_line);
2170
2171 EXPECT_EQ(0, session->tcp_socket_pool()->IdleSocketCount());
2172
2173 std::string response_data;
2174 rv = ReadTransaction(trans.get(), &response_data);
2175 EXPECT_EQ(OK, rv);
2176 EXPECT_EQ("", response_data);
2177
2178 // Empty the current queue. This is necessary because idle sockets are
2179 // added to the connection pool asynchronously with a PostTask.
2180 MessageLoop::current()->RunAllPending();
2181
2182 // We now check to make sure the socket was added back to the pool.
2183 EXPECT_EQ(1, session->tcp_socket_pool()->IdleSocketCount());
2184 }
2185
TEST_F(HttpNetworkTransactionTest,ResendRequestOnWriteBodyError)2186 TEST_F(HttpNetworkTransactionTest, ResendRequestOnWriteBodyError) {
2187 HttpRequestInfo request[2];
2188 // Transaction 1: a GET request that succeeds. The socket is recycled
2189 // after use.
2190 request[0].method = "GET";
2191 request[0].url = GURL("http://www.google.com/");
2192 request[0].load_flags = 0;
2193 // Transaction 2: a POST request. Reuses the socket kept alive from
2194 // transaction 1. The first attempts fails when writing the POST data.
2195 // This causes the transaction to retry with a new socket. The second
2196 // attempt succeeds.
2197 request[1].method = "POST";
2198 request[1].url = GURL("http://www.google.com/login.cgi");
2199 request[1].upload_data = new UploadData;
2200 request[1].upload_data->AppendBytes("foo", 3);
2201 request[1].load_flags = 0;
2202
2203 SessionDependencies session_deps;
2204 scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps);
2205
2206 // The first socket is used for transaction 1 and the first attempt of
2207 // transaction 2.
2208
2209 // The response of transaction 1.
2210 MockRead data_reads1[] = {
2211 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\n"),
2212 MockRead("hello world"),
2213 MockRead(false, OK),
2214 };
2215 // The mock write results of transaction 1 and the first attempt of
2216 // transaction 2.
2217 MockWrite data_writes1[] = {
2218 MockWrite(false, 64), // GET
2219 MockWrite(false, 93), // POST
2220 MockWrite(false, ERR_CONNECTION_ABORTED), // POST data
2221 };
2222 StaticSocketDataProvider data1(data_reads1, data_writes1);
2223
2224 // The second socket is used for the second attempt of transaction 2.
2225
2226 // The response of transaction 2.
2227 MockRead data_reads2[] = {
2228 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 7\r\n\r\n"),
2229 MockRead("welcome"),
2230 MockRead(false, OK),
2231 };
2232 // The mock write results of the second attempt of transaction 2.
2233 MockWrite data_writes2[] = {
2234 MockWrite(false, 93), // POST
2235 MockWrite(false, 3), // POST data
2236 };
2237 StaticSocketDataProvider data2(data_reads2, data_writes2);
2238
2239 session_deps.socket_factory.AddSocketDataProvider(&data1);
2240 session_deps.socket_factory.AddSocketDataProvider(&data2);
2241
2242 const char* kExpectedResponseData[] = {
2243 "hello world", "welcome"
2244 };
2245
2246 for (int i = 0; i < 2; ++i) {
2247 scoped_ptr<HttpTransaction> trans(
2248 new HttpNetworkTransaction(session));
2249
2250 TestCompletionCallback callback;
2251
2252 int rv = trans->Start(&request[i], &callback, NULL);
2253 EXPECT_EQ(ERR_IO_PENDING, rv);
2254
2255 rv = callback.WaitForResult();
2256 EXPECT_EQ(OK, rv);
2257
2258 const HttpResponseInfo* response = trans->GetResponseInfo();
2259 EXPECT_TRUE(response != NULL);
2260
2261 EXPECT_TRUE(response->headers != NULL);
2262 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
2263
2264 std::string response_data;
2265 rv = ReadTransaction(trans.get(), &response_data);
2266 EXPECT_EQ(OK, rv);
2267 EXPECT_EQ(kExpectedResponseData[i], response_data);
2268 }
2269 }
2270
2271 // Test the request-challenge-retry sequence for basic auth when there is
2272 // an identity in the URL. The request should be sent as normal, but when
2273 // it fails the identity from the URL is used to answer the challenge.
TEST_F(HttpNetworkTransactionTest,AuthIdentityInURL)2274 TEST_F(HttpNetworkTransactionTest, AuthIdentityInURL) {
2275 SessionDependencies session_deps;
2276 scoped_ptr<HttpTransaction> trans(
2277 new HttpNetworkTransaction(CreateSession(&session_deps)));
2278
2279 HttpRequestInfo request;
2280 request.method = "GET";
2281 // Note: the URL has a username:password in it.
2282 request.url = GURL("http://foo:b@r@www.google.com/");
2283
2284 // The password contains an escaped character -- for this test to pass it
2285 // will need to be unescaped by HttpNetworkTransaction.
2286 EXPECT_EQ("b%40r", request.url.password());
2287
2288 request.load_flags = LOAD_NORMAL;
2289
2290 MockWrite data_writes1[] = {
2291 MockWrite("GET / HTTP/1.1\r\n"
2292 "Host: www.google.com\r\n"
2293 "Connection: keep-alive\r\n\r\n"),
2294 };
2295
2296 MockRead data_reads1[] = {
2297 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
2298 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
2299 MockRead("Content-Length: 10\r\n\r\n"),
2300 MockRead(false, ERR_FAILED),
2301 };
2302
2303 // After the challenge above, the transaction will be restarted using the
2304 // identity from the url (foo, b@r) to answer the challenge.
2305 MockWrite data_writes2[] = {
2306 MockWrite("GET / HTTP/1.1\r\n"
2307 "Host: www.google.com\r\n"
2308 "Connection: keep-alive\r\n"
2309 "Authorization: Basic Zm9vOmJAcg==\r\n\r\n"),
2310 };
2311
2312 MockRead data_reads2[] = {
2313 MockRead("HTTP/1.0 200 OK\r\n"),
2314 MockRead("Content-Length: 100\r\n\r\n"),
2315 MockRead(false, OK),
2316 };
2317
2318 StaticSocketDataProvider data1(data_reads1, data_writes1);
2319 StaticSocketDataProvider data2(data_reads2, data_writes2);
2320 session_deps.socket_factory.AddSocketDataProvider(&data1);
2321 session_deps.socket_factory.AddSocketDataProvider(&data2);
2322
2323 TestCompletionCallback callback1;
2324
2325 int rv = trans->Start(&request, &callback1, NULL);
2326 EXPECT_EQ(ERR_IO_PENDING, rv);
2327
2328 rv = callback1.WaitForResult();
2329 EXPECT_EQ(OK, rv);
2330
2331 EXPECT_TRUE(trans->IsReadyToRestartForAuth());
2332 TestCompletionCallback callback2;
2333 rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback2);
2334 EXPECT_EQ(ERR_IO_PENDING, rv);
2335 rv = callback2.WaitForResult();
2336 EXPECT_EQ(OK, rv);
2337 EXPECT_FALSE(trans->IsReadyToRestartForAuth());
2338
2339 const HttpResponseInfo* response = trans->GetResponseInfo();
2340 EXPECT_FALSE(response == NULL);
2341
2342 // There is no challenge info, since the identity in URL worked.
2343 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2344
2345 EXPECT_EQ(100, response->headers->GetContentLength());
2346
2347 // Empty the current queue.
2348 MessageLoop::current()->RunAllPending();
2349 }
2350
2351 // Test the request-challenge-retry sequence for basic auth when there is
2352 // an incorrect identity in the URL. The identity from the URL should be used
2353 // only once.
TEST_F(HttpNetworkTransactionTest,WrongAuthIdentityInURL)2354 TEST_F(HttpNetworkTransactionTest, WrongAuthIdentityInURL) {
2355 SessionDependencies session_deps;
2356 scoped_ptr<HttpTransaction> trans(
2357 new HttpNetworkTransaction(CreateSession(&session_deps)));
2358
2359 HttpRequestInfo request;
2360 request.method = "GET";
2361 // Note: the URL has a username:password in it. The password "baz" is
2362 // wrong (should be "bar").
2363 request.url = GURL("http://foo:baz@www.google.com/");
2364
2365 request.load_flags = LOAD_NORMAL;
2366
2367 MockWrite data_writes1[] = {
2368 MockWrite("GET / HTTP/1.1\r\n"
2369 "Host: www.google.com\r\n"
2370 "Connection: keep-alive\r\n\r\n"),
2371 };
2372
2373 MockRead data_reads1[] = {
2374 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
2375 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
2376 MockRead("Content-Length: 10\r\n\r\n"),
2377 MockRead(false, ERR_FAILED),
2378 };
2379
2380 // After the challenge above, the transaction will be restarted using the
2381 // identity from the url (foo, baz) to answer the challenge.
2382 MockWrite data_writes2[] = {
2383 MockWrite("GET / HTTP/1.1\r\n"
2384 "Host: www.google.com\r\n"
2385 "Connection: keep-alive\r\n"
2386 "Authorization: Basic Zm9vOmJheg==\r\n\r\n"),
2387 };
2388
2389 MockRead data_reads2[] = {
2390 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
2391 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
2392 MockRead("Content-Length: 10\r\n\r\n"),
2393 MockRead(false, ERR_FAILED),
2394 };
2395
2396 // After the challenge above, the transaction will be restarted using the
2397 // identity supplied by the user (foo, bar) to answer the challenge.
2398 MockWrite data_writes3[] = {
2399 MockWrite("GET / HTTP/1.1\r\n"
2400 "Host: www.google.com\r\n"
2401 "Connection: keep-alive\r\n"
2402 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
2403 };
2404
2405 MockRead data_reads3[] = {
2406 MockRead("HTTP/1.0 200 OK\r\n"),
2407 MockRead("Content-Length: 100\r\n\r\n"),
2408 MockRead(false, OK),
2409 };
2410
2411 StaticSocketDataProvider data1(data_reads1, data_writes1);
2412 StaticSocketDataProvider data2(data_reads2, data_writes2);
2413 StaticSocketDataProvider data3(data_reads3, data_writes3);
2414 session_deps.socket_factory.AddSocketDataProvider(&data1);
2415 session_deps.socket_factory.AddSocketDataProvider(&data2);
2416 session_deps.socket_factory.AddSocketDataProvider(&data3);
2417
2418 TestCompletionCallback callback1;
2419
2420 int rv = trans->Start(&request, &callback1, NULL);
2421 EXPECT_EQ(ERR_IO_PENDING, rv);
2422
2423 rv = callback1.WaitForResult();
2424 EXPECT_EQ(OK, rv);
2425
2426 EXPECT_TRUE(trans->IsReadyToRestartForAuth());
2427 TestCompletionCallback callback2;
2428 rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback2);
2429 EXPECT_EQ(ERR_IO_PENDING, rv);
2430 rv = callback2.WaitForResult();
2431 EXPECT_EQ(OK, rv);
2432 EXPECT_FALSE(trans->IsReadyToRestartForAuth());
2433
2434 const HttpResponseInfo* response = trans->GetResponseInfo();
2435 EXPECT_FALSE(response == NULL);
2436 // The password prompt info should have been set in response->auth_challenge.
2437 EXPECT_FALSE(response->auth_challenge.get() == NULL);
2438
2439 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
2440 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
2441 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
2442
2443 TestCompletionCallback callback3;
2444 rv = trans->RestartWithAuth(L"foo", L"bar", &callback3);
2445 EXPECT_EQ(ERR_IO_PENDING, rv);
2446 rv = callback3.WaitForResult();
2447 EXPECT_EQ(OK, rv);
2448 EXPECT_FALSE(trans->IsReadyToRestartForAuth());
2449
2450 response = trans->GetResponseInfo();
2451 EXPECT_FALSE(response == NULL);
2452
2453 // There is no challenge info, since the identity worked.
2454 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2455
2456 EXPECT_EQ(100, response->headers->GetContentLength());
2457
2458 // Empty the current queue.
2459 MessageLoop::current()->RunAllPending();
2460 }
2461
2462 // Test that previously tried username/passwords for a realm get re-used.
TEST_F(HttpNetworkTransactionTest,BasicAuthCacheAndPreauth)2463 TEST_F(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
2464 SessionDependencies session_deps;
2465 scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps);
2466
2467 // Transaction 1: authenticate (foo, bar) on MyRealm1
2468 {
2469 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
2470
2471 HttpRequestInfo request;
2472 request.method = "GET";
2473 request.url = GURL("http://www.google.com/x/y/z");
2474 request.load_flags = 0;
2475
2476 MockWrite data_writes1[] = {
2477 MockWrite("GET /x/y/z HTTP/1.1\r\n"
2478 "Host: www.google.com\r\n"
2479 "Connection: keep-alive\r\n\r\n"),
2480 };
2481
2482 MockRead data_reads1[] = {
2483 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
2484 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
2485 MockRead("Content-Length: 10000\r\n\r\n"),
2486 MockRead(false, ERR_FAILED),
2487 };
2488
2489 // Resend with authorization (username=foo, password=bar)
2490 MockWrite data_writes2[] = {
2491 MockWrite("GET /x/y/z HTTP/1.1\r\n"
2492 "Host: www.google.com\r\n"
2493 "Connection: keep-alive\r\n"
2494 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
2495 };
2496
2497 // Sever accepts the authorization.
2498 MockRead data_reads2[] = {
2499 MockRead("HTTP/1.0 200 OK\r\n"),
2500 MockRead("Content-Length: 100\r\n\r\n"),
2501 MockRead(false, OK),
2502 };
2503
2504 StaticSocketDataProvider data1(data_reads1, data_writes1);
2505 StaticSocketDataProvider data2(data_reads2, data_writes2);
2506 session_deps.socket_factory.AddSocketDataProvider(&data1);
2507 session_deps.socket_factory.AddSocketDataProvider(&data2);
2508
2509 TestCompletionCallback callback1;
2510
2511 int rv = trans->Start(&request, &callback1, NULL);
2512 EXPECT_EQ(ERR_IO_PENDING, rv);
2513
2514 rv = callback1.WaitForResult();
2515 EXPECT_EQ(OK, rv);
2516
2517 const HttpResponseInfo* response = trans->GetResponseInfo();
2518 EXPECT_FALSE(response == NULL);
2519
2520 // The password prompt info should have been set in
2521 // response->auth_challenge.
2522 EXPECT_FALSE(response->auth_challenge.get() == NULL);
2523
2524 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
2525 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
2526 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
2527
2528 TestCompletionCallback callback2;
2529
2530 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
2531 EXPECT_EQ(ERR_IO_PENDING, rv);
2532
2533 rv = callback2.WaitForResult();
2534 EXPECT_EQ(OK, rv);
2535
2536 response = trans->GetResponseInfo();
2537 EXPECT_FALSE(response == NULL);
2538 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2539 EXPECT_EQ(100, response->headers->GetContentLength());
2540 }
2541
2542 // ------------------------------------------------------------------------
2543
2544 // Transaction 2: authenticate (foo2, bar2) on MyRealm2
2545 {
2546 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
2547
2548 HttpRequestInfo request;
2549 request.method = "GET";
2550 // Note that Transaction 1 was at /x/y/z, so this is in the same
2551 // protection space as MyRealm1.
2552 request.url = GURL("http://www.google.com/x/y/a/b");
2553 request.load_flags = 0;
2554
2555 MockWrite data_writes1[] = {
2556 MockWrite("GET /x/y/a/b HTTP/1.1\r\n"
2557 "Host: www.google.com\r\n"
2558 "Connection: keep-alive\r\n"
2559 // Send preemptive authorization for MyRealm1
2560 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
2561 };
2562
2563 // The server didn't like the preemptive authorization, and
2564 // challenges us for a different realm (MyRealm2).
2565 MockRead data_reads1[] = {
2566 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
2567 MockRead("WWW-Authenticate: Basic realm=\"MyRealm2\"\r\n"),
2568 MockRead("Content-Length: 10000\r\n\r\n"),
2569 MockRead(false, ERR_FAILED),
2570 };
2571
2572 // Resend with authorization for MyRealm2 (username=foo2, password=bar2)
2573 MockWrite data_writes2[] = {
2574 MockWrite("GET /x/y/a/b HTTP/1.1\r\n"
2575 "Host: www.google.com\r\n"
2576 "Connection: keep-alive\r\n"
2577 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"),
2578 };
2579
2580 // Sever accepts the authorization.
2581 MockRead data_reads2[] = {
2582 MockRead("HTTP/1.0 200 OK\r\n"),
2583 MockRead("Content-Length: 100\r\n\r\n"),
2584 MockRead(false, OK),
2585 };
2586
2587 StaticSocketDataProvider data1(data_reads1, data_writes1);
2588 StaticSocketDataProvider data2(data_reads2, data_writes2);
2589 session_deps.socket_factory.AddSocketDataProvider(&data1);
2590 session_deps.socket_factory.AddSocketDataProvider(&data2);
2591
2592 TestCompletionCallback callback1;
2593
2594 int rv = trans->Start(&request, &callback1, NULL);
2595 EXPECT_EQ(ERR_IO_PENDING, rv);
2596
2597 rv = callback1.WaitForResult();
2598 EXPECT_EQ(OK, rv);
2599
2600 const HttpResponseInfo* response = trans->GetResponseInfo();
2601 EXPECT_FALSE(response == NULL);
2602
2603 // The password prompt info should have been set in
2604 // response->auth_challenge.
2605 EXPECT_FALSE(response->auth_challenge.get() == NULL);
2606
2607 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
2608 EXPECT_EQ(L"MyRealm2", response->auth_challenge->realm);
2609 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
2610
2611 TestCompletionCallback callback2;
2612
2613 rv = trans->RestartWithAuth(L"foo2", L"bar2", &callback2);
2614 EXPECT_EQ(ERR_IO_PENDING, rv);
2615
2616 rv = callback2.WaitForResult();
2617 EXPECT_EQ(OK, rv);
2618
2619 response = trans->GetResponseInfo();
2620 EXPECT_FALSE(response == NULL);
2621 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2622 EXPECT_EQ(100, response->headers->GetContentLength());
2623 }
2624
2625 // ------------------------------------------------------------------------
2626
2627 // Transaction 3: Resend a request in MyRealm's protection space --
2628 // succeed with preemptive authorization.
2629 {
2630 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
2631
2632 HttpRequestInfo request;
2633 request.method = "GET";
2634 request.url = GURL("http://www.google.com/x/y/z2");
2635 request.load_flags = 0;
2636
2637 MockWrite data_writes1[] = {
2638 MockWrite("GET /x/y/z2 HTTP/1.1\r\n"
2639 "Host: www.google.com\r\n"
2640 "Connection: keep-alive\r\n"
2641 // The authorization for MyRealm1 gets sent preemptively
2642 // (since the url is in the same protection space)
2643 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
2644 };
2645
2646 // Sever accepts the preemptive authorization
2647 MockRead data_reads1[] = {
2648 MockRead("HTTP/1.0 200 OK\r\n"),
2649 MockRead("Content-Length: 100\r\n\r\n"),
2650 MockRead(false, OK),
2651 };
2652
2653 StaticSocketDataProvider data1(data_reads1, data_writes1);
2654 session_deps.socket_factory.AddSocketDataProvider(&data1);
2655
2656 TestCompletionCallback callback1;
2657
2658 int rv = trans->Start(&request, &callback1, NULL);
2659 EXPECT_EQ(ERR_IO_PENDING, rv);
2660
2661 rv = callback1.WaitForResult();
2662 EXPECT_EQ(OK, rv);
2663
2664 const HttpResponseInfo* response = trans->GetResponseInfo();
2665 EXPECT_FALSE(response == NULL);
2666
2667 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2668 EXPECT_EQ(100, response->headers->GetContentLength());
2669 }
2670
2671 // ------------------------------------------------------------------------
2672
2673 // Transaction 4: request another URL in MyRealm (however the
2674 // url is not known to belong to the protection space, so no pre-auth).
2675 {
2676 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
2677
2678 HttpRequestInfo request;
2679 request.method = "GET";
2680 request.url = GURL("http://www.google.com/x/1");
2681 request.load_flags = 0;
2682
2683 MockWrite data_writes1[] = {
2684 MockWrite("GET /x/1 HTTP/1.1\r\n"
2685 "Host: www.google.com\r\n"
2686 "Connection: keep-alive\r\n\r\n"),
2687 };
2688
2689 MockRead data_reads1[] = {
2690 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
2691 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
2692 MockRead("Content-Length: 10000\r\n\r\n"),
2693 MockRead(false, ERR_FAILED),
2694 };
2695
2696 // Resend with authorization from MyRealm's cache.
2697 MockWrite data_writes2[] = {
2698 MockWrite("GET /x/1 HTTP/1.1\r\n"
2699 "Host: www.google.com\r\n"
2700 "Connection: keep-alive\r\n"
2701 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
2702 };
2703
2704 // Sever accepts the authorization.
2705 MockRead data_reads2[] = {
2706 MockRead("HTTP/1.0 200 OK\r\n"),
2707 MockRead("Content-Length: 100\r\n\r\n"),
2708 MockRead(false, OK),
2709 };
2710
2711 StaticSocketDataProvider data1(data_reads1, data_writes1);
2712 StaticSocketDataProvider data2(data_reads2, data_writes2);
2713 session_deps.socket_factory.AddSocketDataProvider(&data1);
2714 session_deps.socket_factory.AddSocketDataProvider(&data2);
2715
2716 TestCompletionCallback callback1;
2717
2718 int rv = trans->Start(&request, &callback1, NULL);
2719 EXPECT_EQ(ERR_IO_PENDING, rv);
2720
2721 rv = callback1.WaitForResult();
2722 EXPECT_EQ(OK, rv);
2723
2724 EXPECT_TRUE(trans->IsReadyToRestartForAuth());
2725 TestCompletionCallback callback2;
2726 rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback2);
2727 EXPECT_EQ(ERR_IO_PENDING, rv);
2728 rv = callback2.WaitForResult();
2729 EXPECT_EQ(OK, rv);
2730 EXPECT_FALSE(trans->IsReadyToRestartForAuth());
2731
2732 const HttpResponseInfo* response = trans->GetResponseInfo();
2733 EXPECT_FALSE(response == NULL);
2734 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2735 EXPECT_EQ(100, response->headers->GetContentLength());
2736 }
2737
2738 // ------------------------------------------------------------------------
2739
2740 // Transaction 5: request a URL in MyRealm, but the server rejects the
2741 // cached identity. Should invalidate and re-prompt.
2742 {
2743 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
2744
2745 HttpRequestInfo request;
2746 request.method = "GET";
2747 request.url = GURL("http://www.google.com/p/q/t");
2748 request.load_flags = 0;
2749
2750 MockWrite data_writes1[] = {
2751 MockWrite("GET /p/q/t HTTP/1.1\r\n"
2752 "Host: www.google.com\r\n"
2753 "Connection: keep-alive\r\n\r\n"),
2754 };
2755
2756 MockRead data_reads1[] = {
2757 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
2758 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
2759 MockRead("Content-Length: 10000\r\n\r\n"),
2760 MockRead(false, ERR_FAILED),
2761 };
2762
2763 // Resend with authorization from cache for MyRealm.
2764 MockWrite data_writes2[] = {
2765 MockWrite("GET /p/q/t HTTP/1.1\r\n"
2766 "Host: www.google.com\r\n"
2767 "Connection: keep-alive\r\n"
2768 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
2769 };
2770
2771 // Sever rejects the authorization.
2772 MockRead data_reads2[] = {
2773 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
2774 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
2775 MockRead("Content-Length: 10000\r\n\r\n"),
2776 MockRead(false, ERR_FAILED),
2777 };
2778
2779 // At this point we should prompt for new credentials for MyRealm.
2780 // Restart with username=foo3, password=foo4.
2781 MockWrite data_writes3[] = {
2782 MockWrite("GET /p/q/t HTTP/1.1\r\n"
2783 "Host: www.google.com\r\n"
2784 "Connection: keep-alive\r\n"
2785 "Authorization: Basic Zm9vMzpiYXIz\r\n\r\n"),
2786 };
2787
2788 // Sever accepts the authorization.
2789 MockRead data_reads3[] = {
2790 MockRead("HTTP/1.0 200 OK\r\n"),
2791 MockRead("Content-Length: 100\r\n\r\n"),
2792 MockRead(false, OK),
2793 };
2794
2795 StaticSocketDataProvider data1(data_reads1, data_writes1);
2796 StaticSocketDataProvider data2(data_reads2, data_writes2);
2797 StaticSocketDataProvider data3(data_reads3, data_writes3);
2798 session_deps.socket_factory.AddSocketDataProvider(&data1);
2799 session_deps.socket_factory.AddSocketDataProvider(&data2);
2800 session_deps.socket_factory.AddSocketDataProvider(&data3);
2801
2802 TestCompletionCallback callback1;
2803
2804 int rv = trans->Start(&request, &callback1, NULL);
2805 EXPECT_EQ(ERR_IO_PENDING, rv);
2806
2807 rv = callback1.WaitForResult();
2808 EXPECT_EQ(OK, rv);
2809
2810 EXPECT_TRUE(trans->IsReadyToRestartForAuth());
2811 TestCompletionCallback callback2;
2812 rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback2);
2813 EXPECT_EQ(ERR_IO_PENDING, rv);
2814 rv = callback2.WaitForResult();
2815 EXPECT_EQ(OK, rv);
2816 EXPECT_FALSE(trans->IsReadyToRestartForAuth());
2817
2818 const HttpResponseInfo* response = trans->GetResponseInfo();
2819 EXPECT_FALSE(response == NULL);
2820
2821 // The password prompt info should have been set in
2822 // response->auth_challenge.
2823 EXPECT_FALSE(response->auth_challenge.get() == NULL);
2824
2825 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
2826 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
2827 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
2828
2829 TestCompletionCallback callback3;
2830
2831 rv = trans->RestartWithAuth(L"foo3", L"bar3", &callback3);
2832 EXPECT_EQ(ERR_IO_PENDING, rv);
2833
2834 rv = callback3.WaitForResult();
2835 EXPECT_EQ(OK, rv);
2836
2837 response = trans->GetResponseInfo();
2838 EXPECT_FALSE(response == NULL);
2839 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2840 EXPECT_EQ(100, response->headers->GetContentLength());
2841 }
2842 }
2843
2844 // Test the ResetStateForRestart() private method.
TEST_F(HttpNetworkTransactionTest,ResetStateForRestart)2845 TEST_F(HttpNetworkTransactionTest, ResetStateForRestart) {
2846 // Create a transaction (the dependencies aren't important).
2847 SessionDependencies session_deps;
2848 scoped_ptr<HttpNetworkTransaction> trans(
2849 new HttpNetworkTransaction(CreateSession(&session_deps)));
2850
2851 // Setup some state (which we expect ResetStateForRestart() will clear).
2852 trans->read_buf_ = new IOBuffer(15);
2853 trans->read_buf_len_ = 15;
2854 trans->request_headers_ = "Authorization: NTLM";
2855
2856 // Setup state in response_
2857 HttpResponseInfo* response = &trans->response_;
2858 response->auth_challenge = new AuthChallengeInfo();
2859 response->ssl_info.cert_status = -15;
2860 response->response_time = base::Time::Now();
2861 response->was_cached = true; // (Wouldn't ever actually be true...)
2862
2863 { // Setup state for response_.vary_data
2864 HttpRequestInfo request;
2865 std::string temp("HTTP/1.1 200 OK\nVary: foo, bar\n\n");
2866 std::replace(temp.begin(), temp.end(), '\n', '\0');
2867 scoped_refptr<HttpResponseHeaders> headers = new HttpResponseHeaders(temp);
2868 request.extra_headers = "Foo: 1\nbar: 23";
2869 EXPECT_TRUE(response->vary_data.Init(request, *headers));
2870 }
2871
2872 // Cause the above state to be reset.
2873 trans->ResetStateForRestart();
2874
2875 // Verify that the state that needed to be reset, has been reset.
2876 EXPECT_TRUE(trans->read_buf_.get() == NULL);
2877 EXPECT_EQ(0, trans->read_buf_len_);
2878 EXPECT_EQ(0U, trans->request_headers_.size());
2879 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2880 EXPECT_TRUE(response->headers.get() == NULL);
2881 EXPECT_EQ(false, response->was_cached);
2882 EXPECT_EQ(0, response->ssl_info.cert_status);
2883 EXPECT_FALSE(response->vary_data.is_valid());
2884 }
2885
2886 // Test HTTPS connections to a site with a bad certificate
TEST_F(HttpNetworkTransactionTest,HTTPSBadCertificate)2887 TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificate) {
2888 SessionDependencies session_deps;
2889 scoped_ptr<HttpTransaction> trans(
2890 new HttpNetworkTransaction(CreateSession(&session_deps)));
2891
2892 HttpRequestInfo request;
2893 request.method = "GET";
2894 request.url = GURL("https://www.google.com/");
2895 request.load_flags = 0;
2896
2897 MockWrite data_writes[] = {
2898 MockWrite("GET / HTTP/1.1\r\n"
2899 "Host: www.google.com\r\n"
2900 "Connection: keep-alive\r\n\r\n"),
2901 };
2902
2903 MockRead data_reads[] = {
2904 MockRead("HTTP/1.0 200 OK\r\n"),
2905 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
2906 MockRead("Content-Length: 100\r\n\r\n"),
2907 MockRead(false, OK),
2908 };
2909
2910 StaticSocketDataProvider ssl_bad_certificate;
2911 StaticSocketDataProvider data(data_reads, data_writes);
2912 SSLSocketDataProvider ssl_bad(true, ERR_CERT_AUTHORITY_INVALID);
2913 SSLSocketDataProvider ssl(true, OK);
2914
2915 session_deps.socket_factory.AddSocketDataProvider(&ssl_bad_certificate);
2916 session_deps.socket_factory.AddSocketDataProvider(&data);
2917 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_bad);
2918 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
2919
2920 TestCompletionCallback callback;
2921
2922 int rv = trans->Start(&request, &callback, NULL);
2923 EXPECT_EQ(ERR_IO_PENDING, rv);
2924
2925 rv = callback.WaitForResult();
2926 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv);
2927
2928 rv = trans->RestartIgnoringLastError(&callback);
2929 EXPECT_EQ(ERR_IO_PENDING, rv);
2930
2931 rv = callback.WaitForResult();
2932 EXPECT_EQ(OK, rv);
2933
2934 const HttpResponseInfo* response = trans->GetResponseInfo();
2935
2936 EXPECT_FALSE(response == NULL);
2937 EXPECT_EQ(100, response->headers->GetContentLength());
2938 }
2939
2940 // Test HTTPS connections to a site with a bad certificate, going through a
2941 // proxy
TEST_F(HttpNetworkTransactionTest,HTTPSBadCertificateViaProxy)2942 TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificateViaProxy) {
2943 SessionDependencies session_deps(CreateFixedProxyService("myproxy:70"));
2944
2945 HttpRequestInfo request;
2946 request.method = "GET";
2947 request.url = GURL("https://www.google.com/");
2948 request.load_flags = 0;
2949
2950 MockWrite proxy_writes[] = {
2951 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
2952 "Host: www.google.com\r\n"
2953 "Proxy-Connection: keep-alive\r\n\r\n"),
2954 };
2955
2956 MockRead proxy_reads[] = {
2957 MockRead("HTTP/1.0 200 Connected\r\n\r\n"),
2958 MockRead(false, OK)
2959 };
2960
2961 MockWrite data_writes[] = {
2962 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
2963 "Host: www.google.com\r\n"
2964 "Proxy-Connection: keep-alive\r\n\r\n"),
2965 MockWrite("GET / HTTP/1.1\r\n"
2966 "Host: www.google.com\r\n"
2967 "Connection: keep-alive\r\n\r\n"),
2968 };
2969
2970 MockRead data_reads[] = {
2971 MockRead("HTTP/1.0 200 Connected\r\n\r\n"),
2972 MockRead("HTTP/1.0 200 OK\r\n"),
2973 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
2974 MockRead("Content-Length: 100\r\n\r\n"),
2975 MockRead(false, OK),
2976 };
2977
2978 StaticSocketDataProvider ssl_bad_certificate(proxy_reads, proxy_writes);
2979 StaticSocketDataProvider data(data_reads, data_writes);
2980 SSLSocketDataProvider ssl_bad(true, ERR_CERT_AUTHORITY_INVALID);
2981 SSLSocketDataProvider ssl(true, OK);
2982
2983 session_deps.socket_factory.AddSocketDataProvider(&ssl_bad_certificate);
2984 session_deps.socket_factory.AddSocketDataProvider(&data);
2985 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_bad);
2986 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
2987
2988 TestCompletionCallback callback;
2989
2990 for (int i = 0; i < 2; i++) {
2991 session_deps.socket_factory.ResetNextMockIndexes();
2992
2993 scoped_ptr<HttpTransaction> trans(
2994 new HttpNetworkTransaction(CreateSession(&session_deps)));
2995
2996 int rv = trans->Start(&request, &callback, NULL);
2997 EXPECT_EQ(ERR_IO_PENDING, rv);
2998
2999 rv = callback.WaitForResult();
3000 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv);
3001
3002 rv = trans->RestartIgnoringLastError(&callback);
3003 EXPECT_EQ(ERR_IO_PENDING, rv);
3004
3005 rv = callback.WaitForResult();
3006 EXPECT_EQ(OK, rv);
3007
3008 const HttpResponseInfo* response = trans->GetResponseInfo();
3009
3010 EXPECT_FALSE(response == NULL);
3011 EXPECT_EQ(100, response->headers->GetContentLength());
3012 }
3013 }
3014
TEST_F(HttpNetworkTransactionTest,BuildRequest_UserAgent)3015 TEST_F(HttpNetworkTransactionTest, BuildRequest_UserAgent) {
3016 SessionDependencies session_deps;
3017 scoped_ptr<HttpTransaction> trans(
3018 new HttpNetworkTransaction(CreateSession(&session_deps)));
3019
3020 HttpRequestInfo request;
3021 request.method = "GET";
3022 request.url = GURL("http://www.google.com/");
3023 request.user_agent = "Chromium Ultra Awesome X Edition";
3024
3025 MockWrite data_writes[] = {
3026 MockWrite("GET / HTTP/1.1\r\n"
3027 "Host: www.google.com\r\n"
3028 "Connection: keep-alive\r\n"
3029 "User-Agent: Chromium Ultra Awesome X Edition\r\n\r\n"),
3030 };
3031
3032 // Lastly, the server responds with the actual content.
3033 MockRead data_reads[] = {
3034 MockRead("HTTP/1.0 200 OK\r\n"),
3035 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
3036 MockRead("Content-Length: 100\r\n\r\n"),
3037 MockRead(false, OK),
3038 };
3039
3040 StaticSocketDataProvider data(data_reads, data_writes);
3041 session_deps.socket_factory.AddSocketDataProvider(&data);
3042
3043 TestCompletionCallback callback;
3044
3045 int rv = trans->Start(&request, &callback, NULL);
3046 EXPECT_EQ(ERR_IO_PENDING, rv);
3047
3048 rv = callback.WaitForResult();
3049 EXPECT_EQ(OK, rv);
3050 }
3051
TEST_F(HttpNetworkTransactionTest,BuildRequest_Referer)3052 TEST_F(HttpNetworkTransactionTest, BuildRequest_Referer) {
3053 SessionDependencies session_deps;
3054 scoped_ptr<HttpTransaction> trans(
3055 new HttpNetworkTransaction(CreateSession(&session_deps)));
3056
3057 HttpRequestInfo request;
3058 request.method = "GET";
3059 request.url = GURL("http://www.google.com/");
3060 request.load_flags = 0;
3061 request.referrer = GURL("http://the.previous.site.com/");
3062
3063 MockWrite data_writes[] = {
3064 MockWrite("GET / HTTP/1.1\r\n"
3065 "Host: www.google.com\r\n"
3066 "Connection: keep-alive\r\n"
3067 "Referer: http://the.previous.site.com/\r\n\r\n"),
3068 };
3069
3070 // Lastly, the server responds with the actual content.
3071 MockRead data_reads[] = {
3072 MockRead("HTTP/1.0 200 OK\r\n"),
3073 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
3074 MockRead("Content-Length: 100\r\n\r\n"),
3075 MockRead(false, OK),
3076 };
3077
3078 StaticSocketDataProvider data(data_reads, data_writes);
3079 session_deps.socket_factory.AddSocketDataProvider(&data);
3080
3081 TestCompletionCallback callback;
3082
3083 int rv = trans->Start(&request, &callback, NULL);
3084 EXPECT_EQ(ERR_IO_PENDING, rv);
3085
3086 rv = callback.WaitForResult();
3087 EXPECT_EQ(OK, rv);
3088 }
3089
TEST_F(HttpNetworkTransactionTest,BuildRequest_PostContentLengthZero)3090 TEST_F(HttpNetworkTransactionTest, BuildRequest_PostContentLengthZero) {
3091 SessionDependencies session_deps;
3092 scoped_ptr<HttpTransaction> trans(
3093 new HttpNetworkTransaction(CreateSession(&session_deps)));
3094
3095 HttpRequestInfo request;
3096 request.method = "POST";
3097 request.url = GURL("http://www.google.com/");
3098
3099 MockWrite data_writes[] = {
3100 MockWrite("POST / HTTP/1.1\r\n"
3101 "Host: www.google.com\r\n"
3102 "Connection: keep-alive\r\n"
3103 "Content-Length: 0\r\n\r\n"),
3104 };
3105
3106 // Lastly, the server responds with the actual content.
3107 MockRead data_reads[] = {
3108 MockRead("HTTP/1.0 200 OK\r\n"),
3109 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
3110 MockRead("Content-Length: 100\r\n\r\n"),
3111 MockRead(false, OK),
3112 };
3113
3114 StaticSocketDataProvider data(data_reads, data_writes);
3115 session_deps.socket_factory.AddSocketDataProvider(&data);
3116
3117 TestCompletionCallback callback;
3118
3119 int rv = trans->Start(&request, &callback, NULL);
3120 EXPECT_EQ(ERR_IO_PENDING, rv);
3121
3122 rv = callback.WaitForResult();
3123 EXPECT_EQ(OK, rv);
3124 }
3125
TEST_F(HttpNetworkTransactionTest,BuildRequest_PutContentLengthZero)3126 TEST_F(HttpNetworkTransactionTest, BuildRequest_PutContentLengthZero) {
3127 SessionDependencies session_deps;
3128 scoped_ptr<HttpTransaction> trans(
3129 new HttpNetworkTransaction(CreateSession(&session_deps)));
3130
3131 HttpRequestInfo request;
3132 request.method = "PUT";
3133 request.url = GURL("http://www.google.com/");
3134
3135 MockWrite data_writes[] = {
3136 MockWrite("PUT / HTTP/1.1\r\n"
3137 "Host: www.google.com\r\n"
3138 "Connection: keep-alive\r\n"
3139 "Content-Length: 0\r\n\r\n"),
3140 };
3141
3142 // Lastly, the server responds with the actual content.
3143 MockRead data_reads[] = {
3144 MockRead("HTTP/1.0 200 OK\r\n"),
3145 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
3146 MockRead("Content-Length: 100\r\n\r\n"),
3147 MockRead(false, OK),
3148 };
3149
3150 StaticSocketDataProvider data(data_reads, data_writes);
3151 session_deps.socket_factory.AddSocketDataProvider(&data);
3152
3153 TestCompletionCallback callback;
3154
3155 int rv = trans->Start(&request, &callback, NULL);
3156 EXPECT_EQ(ERR_IO_PENDING, rv);
3157
3158 rv = callback.WaitForResult();
3159 EXPECT_EQ(OK, rv);
3160 }
3161
TEST_F(HttpNetworkTransactionTest,BuildRequest_HeadContentLengthZero)3162 TEST_F(HttpNetworkTransactionTest, BuildRequest_HeadContentLengthZero) {
3163 SessionDependencies session_deps;
3164 scoped_ptr<HttpTransaction> trans(
3165 new HttpNetworkTransaction(CreateSession(&session_deps)));
3166
3167 HttpRequestInfo request;
3168 request.method = "HEAD";
3169 request.url = GURL("http://www.google.com/");
3170
3171 MockWrite data_writes[] = {
3172 MockWrite("HEAD / HTTP/1.1\r\n"
3173 "Host: www.google.com\r\n"
3174 "Connection: keep-alive\r\n"
3175 "Content-Length: 0\r\n\r\n"),
3176 };
3177
3178 // Lastly, the server responds with the actual content.
3179 MockRead data_reads[] = {
3180 MockRead("HTTP/1.0 200 OK\r\n"),
3181 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
3182 MockRead("Content-Length: 100\r\n\r\n"),
3183 MockRead(false, OK),
3184 };
3185
3186 StaticSocketDataProvider data(data_reads, data_writes);
3187 session_deps.socket_factory.AddSocketDataProvider(&data);
3188
3189 TestCompletionCallback callback;
3190
3191 int rv = trans->Start(&request, &callback, NULL);
3192 EXPECT_EQ(ERR_IO_PENDING, rv);
3193
3194 rv = callback.WaitForResult();
3195 EXPECT_EQ(OK, rv);
3196 }
3197
TEST_F(HttpNetworkTransactionTest,BuildRequest_CacheControlNoCache)3198 TEST_F(HttpNetworkTransactionTest, BuildRequest_CacheControlNoCache) {
3199 SessionDependencies session_deps;
3200 scoped_ptr<HttpTransaction> trans(
3201 new HttpNetworkTransaction(CreateSession(&session_deps)));
3202
3203 HttpRequestInfo request;
3204 request.method = "GET";
3205 request.url = GURL("http://www.google.com/");
3206 request.load_flags = LOAD_BYPASS_CACHE;
3207
3208 MockWrite data_writes[] = {
3209 MockWrite("GET / HTTP/1.1\r\n"
3210 "Host: www.google.com\r\n"
3211 "Connection: keep-alive\r\n"
3212 "Pragma: no-cache\r\n"
3213 "Cache-Control: no-cache\r\n\r\n"),
3214 };
3215
3216 // Lastly, the server responds with the actual content.
3217 MockRead data_reads[] = {
3218 MockRead("HTTP/1.0 200 OK\r\n"),
3219 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
3220 MockRead("Content-Length: 100\r\n\r\n"),
3221 MockRead(false, OK),
3222 };
3223
3224 StaticSocketDataProvider data(data_reads, data_writes);
3225 session_deps.socket_factory.AddSocketDataProvider(&data);
3226
3227 TestCompletionCallback callback;
3228
3229 int rv = trans->Start(&request, &callback, NULL);
3230 EXPECT_EQ(ERR_IO_PENDING, rv);
3231
3232 rv = callback.WaitForResult();
3233 EXPECT_EQ(OK, rv);
3234 }
3235
TEST_F(HttpNetworkTransactionTest,BuildRequest_CacheControlValidateCache)3236 TEST_F(HttpNetworkTransactionTest,
3237 BuildRequest_CacheControlValidateCache) {
3238 SessionDependencies session_deps;
3239 scoped_ptr<HttpTransaction> trans(
3240 new HttpNetworkTransaction(CreateSession(&session_deps)));
3241
3242 HttpRequestInfo request;
3243 request.method = "GET";
3244 request.url = GURL("http://www.google.com/");
3245 request.load_flags = LOAD_VALIDATE_CACHE;
3246
3247 MockWrite data_writes[] = {
3248 MockWrite("GET / HTTP/1.1\r\n"
3249 "Host: www.google.com\r\n"
3250 "Connection: keep-alive\r\n"
3251 "Cache-Control: max-age=0\r\n\r\n"),
3252 };
3253
3254 // Lastly, the server responds with the actual content.
3255 MockRead data_reads[] = {
3256 MockRead("HTTP/1.0 200 OK\r\n"),
3257 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
3258 MockRead("Content-Length: 100\r\n\r\n"),
3259 MockRead(false, OK),
3260 };
3261
3262 StaticSocketDataProvider data(data_reads, data_writes);
3263 session_deps.socket_factory.AddSocketDataProvider(&data);
3264
3265 TestCompletionCallback callback;
3266
3267 int rv = trans->Start(&request, &callback, NULL);
3268 EXPECT_EQ(ERR_IO_PENDING, rv);
3269
3270 rv = callback.WaitForResult();
3271 EXPECT_EQ(OK, rv);
3272 }
3273
TEST_F(HttpNetworkTransactionTest,BuildRequest_ExtraHeaders)3274 TEST_F(HttpNetworkTransactionTest, BuildRequest_ExtraHeaders) {
3275 SessionDependencies session_deps;
3276 scoped_ptr<HttpTransaction> trans(
3277 new HttpNetworkTransaction(CreateSession(&session_deps)));
3278
3279 HttpRequestInfo request;
3280 request.method = "GET";
3281 request.url = GURL("http://www.google.com/");
3282 request.extra_headers = "FooHeader: Bar\r\n";
3283
3284 MockWrite data_writes[] = {
3285 MockWrite("GET / HTTP/1.1\r\n"
3286 "Host: www.google.com\r\n"
3287 "Connection: keep-alive\r\n"
3288 "FooHeader: Bar\r\n\r\n"),
3289 };
3290
3291 // Lastly, the server responds with the actual content.
3292 MockRead data_reads[] = {
3293 MockRead("HTTP/1.0 200 OK\r\n"),
3294 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
3295 MockRead("Content-Length: 100\r\n\r\n"),
3296 MockRead(false, OK),
3297 };
3298
3299 StaticSocketDataProvider data(data_reads, data_writes);
3300 session_deps.socket_factory.AddSocketDataProvider(&data);
3301
3302 TestCompletionCallback callback;
3303
3304 int rv = trans->Start(&request, &callback, NULL);
3305 EXPECT_EQ(ERR_IO_PENDING, rv);
3306
3307 rv = callback.WaitForResult();
3308 EXPECT_EQ(OK, rv);
3309 }
3310
TEST_F(HttpNetworkTransactionTest,SOCKS4_HTTP_GET)3311 TEST_F(HttpNetworkTransactionTest, SOCKS4_HTTP_GET) {
3312 SessionDependencies session_deps(
3313 CreateFixedProxyService("socks4://myproxy:1080"));
3314
3315 scoped_ptr<HttpTransaction> trans(
3316 new HttpNetworkTransaction(CreateSession(&session_deps)));
3317
3318 HttpRequestInfo request;
3319 request.method = "GET";
3320 request.url = GURL("http://www.google.com/");
3321 request.load_flags = 0;
3322
3323 char write_buffer[] = { 0x04, 0x01, 0x00, 0x50, 127, 0, 0, 1, 0 };
3324 char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 };
3325
3326 MockWrite data_writes[] = {
3327 MockWrite(true, write_buffer, arraysize(write_buffer)),
3328 MockWrite("GET / HTTP/1.1\r\n"
3329 "Host: www.google.com\r\n"
3330 "Connection: keep-alive\r\n\r\n")
3331 };
3332
3333 MockRead data_reads[] = {
3334 MockRead(true, read_buffer, arraysize(read_buffer)),
3335 MockRead("HTTP/1.0 200 OK\r\n"),
3336 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"),
3337 MockRead("Payload"),
3338 MockRead(false, OK)
3339 };
3340
3341 StaticSocketDataProvider data(data_reads, data_writes);
3342 session_deps.socket_factory.AddSocketDataProvider(&data);
3343
3344 TestCompletionCallback callback;
3345
3346 int rv = trans->Start(&request, &callback, NULL);
3347 EXPECT_EQ(ERR_IO_PENDING, rv);
3348
3349 rv = callback.WaitForResult();
3350 EXPECT_EQ(OK, rv);
3351
3352 const HttpResponseInfo* response = trans->GetResponseInfo();
3353 EXPECT_FALSE(response == NULL);
3354
3355 std::string response_text;
3356 rv = ReadTransaction(trans.get(), &response_text);
3357 EXPECT_EQ(OK, rv);
3358 EXPECT_EQ("Payload", response_text);
3359 }
3360
TEST_F(HttpNetworkTransactionTest,SOCKS4_SSL_GET)3361 TEST_F(HttpNetworkTransactionTest, SOCKS4_SSL_GET) {
3362 SessionDependencies session_deps(
3363 CreateFixedProxyService("socks4://myproxy:1080"));
3364
3365 scoped_ptr<HttpTransaction> trans(
3366 new HttpNetworkTransaction(CreateSession(&session_deps)));
3367
3368 HttpRequestInfo request;
3369 request.method = "GET";
3370 request.url = GURL("https://www.google.com/");
3371 request.load_flags = 0;
3372
3373 unsigned char write_buffer[] = { 0x04, 0x01, 0x01, 0xBB, 127, 0, 0, 1, 0 };
3374 unsigned char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 };
3375
3376 MockWrite data_writes[] = {
3377 MockWrite(true, reinterpret_cast<char*>(write_buffer),
3378 arraysize(write_buffer)),
3379 MockWrite("GET / HTTP/1.1\r\n"
3380 "Host: www.google.com\r\n"
3381 "Connection: keep-alive\r\n\r\n")
3382 };
3383
3384 MockRead data_reads[] = {
3385 MockWrite(true, reinterpret_cast<char*>(read_buffer),
3386 arraysize(read_buffer)),
3387 MockRead("HTTP/1.0 200 OK\r\n"),
3388 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"),
3389 MockRead("Payload"),
3390 MockRead(false, OK)
3391 };
3392
3393 StaticSocketDataProvider data(data_reads, data_writes);
3394 session_deps.socket_factory.AddSocketDataProvider(&data);
3395
3396 SSLSocketDataProvider ssl(true, OK);
3397 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
3398
3399 TestCompletionCallback callback;
3400
3401 int rv = trans->Start(&request, &callback, NULL);
3402 EXPECT_EQ(ERR_IO_PENDING, rv);
3403
3404 rv = callback.WaitForResult();
3405 EXPECT_EQ(OK, rv);
3406
3407 const HttpResponseInfo* response = trans->GetResponseInfo();
3408 EXPECT_FALSE(response == NULL);
3409
3410 std::string response_text;
3411 rv = ReadTransaction(trans.get(), &response_text);
3412 EXPECT_EQ(OK, rv);
3413 EXPECT_EQ("Payload", response_text);
3414 }
3415
TEST_F(HttpNetworkTransactionTest,SOCKS5_HTTP_GET)3416 TEST_F(HttpNetworkTransactionTest, SOCKS5_HTTP_GET) {
3417 SessionDependencies session_deps(
3418 CreateFixedProxyService("socks5://myproxy:1080"));
3419
3420 scoped_ptr<HttpTransaction> trans(
3421 new HttpNetworkTransaction(CreateSession(&session_deps)));
3422
3423 HttpRequestInfo request;
3424 request.method = "GET";
3425 request.url = GURL("http://www.google.com/");
3426 request.load_flags = 0;
3427
3428 const char kSOCKS5GreetRequest[] = { 0x05, 0x01, 0x00 };
3429 const char kSOCKS5GreetResponse[] = { 0x05, 0x00 };
3430 const char kSOCKS5OkRequest[] = {
3431 0x05, // Version
3432 0x01, // Command (CONNECT)
3433 0x00, // Reserved.
3434 0x03, // Address type (DOMAINNAME).
3435 0x0E, // Length of domain (14)
3436 // Domain string:
3437 'w', 'w', 'w', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o', 'm',
3438 0x00, 0x50, // 16-bit port (80)
3439 };
3440 const char kSOCKS5OkResponse[] =
3441 { 0x05, 0x00, 0x00, 0x01, 127, 0, 0, 1, 0x00, 0x50 };
3442
3443 MockWrite data_writes[] = {
3444 MockWrite(true, kSOCKS5GreetRequest, arraysize(kSOCKS5GreetRequest)),
3445 MockWrite(true, kSOCKS5OkRequest, arraysize(kSOCKS5OkRequest)),
3446 MockWrite("GET / HTTP/1.1\r\n"
3447 "Host: www.google.com\r\n"
3448 "Connection: keep-alive\r\n\r\n")
3449 };
3450
3451 MockRead data_reads[] = {
3452 MockWrite(true, kSOCKS5GreetResponse, arraysize(kSOCKS5GreetResponse)),
3453 MockWrite(true, kSOCKS5OkResponse, arraysize(kSOCKS5OkResponse)),
3454 MockRead("HTTP/1.0 200 OK\r\n"),
3455 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"),
3456 MockRead("Payload"),
3457 MockRead(false, OK)
3458 };
3459
3460 StaticSocketDataProvider data(data_reads, data_writes);
3461 session_deps.socket_factory.AddSocketDataProvider(&data);
3462
3463 TestCompletionCallback callback;
3464
3465 int rv = trans->Start(&request, &callback, NULL);
3466 EXPECT_EQ(ERR_IO_PENDING, rv);
3467
3468 rv = callback.WaitForResult();
3469 EXPECT_EQ(OK, rv);
3470
3471 const HttpResponseInfo* response = trans->GetResponseInfo();
3472 EXPECT_FALSE(response == NULL);
3473
3474 std::string response_text;
3475 rv = ReadTransaction(trans.get(), &response_text);
3476 EXPECT_EQ(OK, rv);
3477 EXPECT_EQ("Payload", response_text);
3478 }
3479
TEST_F(HttpNetworkTransactionTest,SOCKS5_SSL_GET)3480 TEST_F(HttpNetworkTransactionTest, SOCKS5_SSL_GET) {
3481 SessionDependencies session_deps(
3482 CreateFixedProxyService("socks5://myproxy:1080"));
3483
3484 scoped_ptr<HttpTransaction> trans(
3485 new HttpNetworkTransaction(CreateSession(&session_deps)));
3486
3487 HttpRequestInfo request;
3488 request.method = "GET";
3489 request.url = GURL("https://www.google.com/");
3490 request.load_flags = 0;
3491
3492 const char kSOCKS5GreetRequest[] = { 0x05, 0x01, 0x00 };
3493 const char kSOCKS5GreetResponse[] = { 0x05, 0x00 };
3494 const unsigned char kSOCKS5OkRequest[] = {
3495 0x05, // Version
3496 0x01, // Command (CONNECT)
3497 0x00, // Reserved.
3498 0x03, // Address type (DOMAINNAME).
3499 0x0E, // Length of domain (14)
3500 // Domain string:
3501 'w', 'w', 'w', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o', 'm',
3502 0x01, 0xBB, // 16-bit port (443)
3503 };
3504
3505 const char kSOCKS5OkResponse[] =
3506 { 0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0x00, 0x00 };
3507
3508 MockWrite data_writes[] = {
3509 MockWrite(true, kSOCKS5GreetRequest, arraysize(kSOCKS5GreetRequest)),
3510 MockWrite(true, reinterpret_cast<const char*>(kSOCKS5OkRequest),
3511 arraysize(kSOCKS5OkRequest)),
3512 MockWrite("GET / HTTP/1.1\r\n"
3513 "Host: www.google.com\r\n"
3514 "Connection: keep-alive\r\n\r\n")
3515 };
3516
3517 MockRead data_reads[] = {
3518 MockWrite(true, kSOCKS5GreetResponse, arraysize(kSOCKS5GreetResponse)),
3519 MockWrite(true, kSOCKS5OkResponse, arraysize(kSOCKS5OkResponse)),
3520 MockRead("HTTP/1.0 200 OK\r\n"),
3521 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"),
3522 MockRead("Payload"),
3523 MockRead(false, OK)
3524 };
3525
3526 StaticSocketDataProvider data(data_reads, data_writes);
3527 session_deps.socket_factory.AddSocketDataProvider(&data);
3528
3529 SSLSocketDataProvider ssl(true, OK);
3530 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
3531
3532 TestCompletionCallback callback;
3533
3534 int rv = trans->Start(&request, &callback, NULL);
3535 EXPECT_EQ(ERR_IO_PENDING, rv);
3536
3537 rv = callback.WaitForResult();
3538 EXPECT_EQ(OK, rv);
3539
3540 const HttpResponseInfo* response = trans->GetResponseInfo();
3541 EXPECT_FALSE(response == NULL);
3542
3543 std::string response_text;
3544 rv = ReadTransaction(trans.get(), &response_text);
3545 EXPECT_EQ(OK, rv);
3546 EXPECT_EQ("Payload", response_text);
3547 }
3548
3549 // Tests that for connection endpoints the group names are correctly set.
TEST_F(HttpNetworkTransactionTest,GroupNameForProxyConnections)3550 TEST_F(HttpNetworkTransactionTest, GroupNameForProxyConnections) {
3551 const struct {
3552 const std::string proxy_server;
3553 const std::string url;
3554 const std::string expected_group_name;
3555 } tests[] = {
3556 {
3557 "", // no proxy (direct)
3558 "http://www.google.com/direct",
3559 "http://www.google.com/",
3560 },
3561 {
3562 "http_proxy",
3563 "http://www.google.com/http_proxy_normal",
3564 "proxy/http_proxy:80/",
3565 },
3566 {
3567 "socks4://socks_proxy:1080",
3568 "http://www.google.com/socks4_direct",
3569 "proxy/socks4://socks_proxy:1080/http://www.google.com/",
3570 },
3571
3572 // SSL Tests
3573 {
3574 "",
3575 "https://www.google.com/direct_ssl",
3576 "https://www.google.com/",
3577 },
3578 {
3579 "http_proxy",
3580 "https://www.google.com/http_connect_ssl",
3581 "proxy/http_proxy:80/https://www.google.com/",
3582 },
3583 {
3584 "socks4://socks_proxy:1080",
3585 "https://www.google.com/socks4_ssl",
3586 "proxy/socks4://socks_proxy:1080/https://www.google.com/",
3587 },
3588 };
3589
3590 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
3591 SessionDependencies session_deps(
3592 CreateFixedProxyService(tests[i].proxy_server));
3593
3594 scoped_refptr<CaptureGroupNameSocketPool> conn_pool(
3595 new CaptureGroupNameSocketPool());
3596
3597 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
3598 session->tcp_socket_pool_ = conn_pool.get();
3599
3600 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
3601
3602 HttpRequestInfo request;
3603 request.method = "GET";
3604 request.url = GURL(tests[i].url);
3605 request.load_flags = 0;
3606
3607 TestCompletionCallback callback;
3608
3609 // We do not complete this request, the dtor will clean the transaction up.
3610 EXPECT_EQ(ERR_IO_PENDING, trans->Start(&request, &callback, NULL));
3611 EXPECT_EQ(tests[i].expected_group_name,
3612 conn_pool->last_group_name_received());
3613 }
3614 }
3615
TEST_F(HttpNetworkTransactionTest,ReconsiderProxyAfterFailedConnection)3616 TEST_F(HttpNetworkTransactionTest, ReconsiderProxyAfterFailedConnection) {
3617 SessionDependencies session_deps(
3618 CreateFixedProxyService("myproxy:70;foobar:80"));
3619
3620 // This simulates failure resolving all hostnames; that means we will fail
3621 // connecting to both proxies (myproxy:70 and foobar:80).
3622 session_deps.host_resolver->rules()->AddSimulatedFailure("*");
3623
3624 scoped_ptr<HttpTransaction> trans(
3625 new HttpNetworkTransaction(CreateSession(&session_deps)));
3626
3627 HttpRequestInfo request;
3628 request.method = "GET";
3629 request.url = GURL("http://www.google.com/");
3630
3631 TestCompletionCallback callback;
3632
3633 int rv = trans->Start(&request, &callback, NULL);
3634 EXPECT_EQ(ERR_IO_PENDING, rv);
3635
3636 rv = callback.WaitForResult();
3637 EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
3638 }
3639
3640 // Host resolution observer used by
3641 // HttpNetworkTransactionTest.ResolveMadeWithReferrer to check that host
3642 // resovle requests are issued with a referrer of |expected_referrer|.
3643 class ResolutionReferrerObserver : public HostResolver::Observer {
3644 public:
ResolutionReferrerObserver(const GURL & expected_referrer)3645 explicit ResolutionReferrerObserver(const GURL& expected_referrer)
3646 : expected_referrer_(expected_referrer),
3647 called_start_with_referrer_(false),
3648 called_finish_with_referrer_(false) {
3649 }
3650
OnStartResolution(int id,const HostResolver::RequestInfo & info)3651 virtual void OnStartResolution(int id,
3652 const HostResolver::RequestInfo& info) {
3653 if (info.referrer() == expected_referrer_)
3654 called_start_with_referrer_ = true;
3655 }
3656
OnFinishResolutionWithStatus(int id,bool was_resolved,const HostResolver::RequestInfo & info)3657 virtual void OnFinishResolutionWithStatus(
3658 int id, bool was_resolved, const HostResolver::RequestInfo& info ) {
3659 if (info.referrer() == expected_referrer_)
3660 called_finish_with_referrer_ = true;
3661 }
3662
OnCancelResolution(int id,const HostResolver::RequestInfo & info)3663 virtual void OnCancelResolution(int id,
3664 const HostResolver::RequestInfo& info ) {
3665 FAIL() << "Should not be cancelling any requests!";
3666 }
3667
did_complete_with_expected_referrer() const3668 bool did_complete_with_expected_referrer() const {
3669 return called_start_with_referrer_ && called_finish_with_referrer_;
3670 }
3671
3672 private:
3673 GURL expected_referrer_;
3674 bool called_start_with_referrer_;
3675 bool called_finish_with_referrer_;
3676
3677 DISALLOW_COPY_AND_ASSIGN(ResolutionReferrerObserver);
3678 };
3679
3680 // Make sure that when HostResolver::Resolve() is invoked, it passes through
3681 // the "referrer". This is depended on by the DNS prefetch observer.
TEST_F(HttpNetworkTransactionTest,ResolveMadeWithReferrer)3682 TEST_F(HttpNetworkTransactionTest, ResolveMadeWithReferrer) {
3683 GURL referrer = GURL("http://expected-referrer/");
3684 EXPECT_TRUE(referrer.is_valid());
3685 ResolutionReferrerObserver resolution_observer(referrer);
3686
3687 SessionDependencies session_deps;
3688 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
3689 CreateSession(&session_deps)));
3690
3691 // Attach an observer to watch the host resolutions being made.
3692 session_deps.host_resolver->AddObserver(&resolution_observer);
3693
3694 // Connect up a mock socket which will fail when reading.
3695 MockRead data_reads[] = {
3696 MockRead(false, ERR_FAILED),
3697 };
3698 StaticSocketDataProvider data(data_reads, NULL);
3699 session_deps.socket_factory.AddSocketDataProvider(&data);
3700
3701 // Issue a request, containing an HTTP referrer.
3702 HttpRequestInfo request;
3703 request.method = "GET";
3704 request.referrer = referrer;
3705 request.url = GURL("http://www.google.com/");
3706
3707 // Run the request until it fails reading from the socket.
3708 TestCompletionCallback callback;
3709 int rv = trans->Start(&request, &callback, NULL);
3710 EXPECT_EQ(ERR_IO_PENDING, rv);
3711 rv = callback.WaitForResult();
3712 EXPECT_EQ(ERR_FAILED, rv);
3713
3714 // Check that the host resolution observer saw |referrer|.
3715 EXPECT_TRUE(resolution_observer.did_complete_with_expected_referrer());
3716 }
3717
3718 // Make sure that when the load flags contain LOAD_BYPASS_CACHE, the resolver's
3719 // host cache is bypassed.
TEST_F(HttpNetworkTransactionTest,BypassHostCacheOnRefresh)3720 TEST_F(HttpNetworkTransactionTest, BypassHostCacheOnRefresh) {
3721 SessionDependencies session_deps;
3722
3723 // Select a host resolver that does caching.
3724 session_deps.host_resolver = new MockCachingHostResolver;
3725
3726 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
3727 CreateSession(&session_deps)));
3728
3729 // Warm up the host cache so it has an entry for "www.google.com" (by doing
3730 // a synchronous lookup.)
3731 AddressList addrlist;
3732 int rv = session_deps.host_resolver->Resolve(
3733 HostResolver::RequestInfo("www.google.com", 80), &addrlist,
3734 NULL, NULL, NULL);
3735 EXPECT_EQ(OK, rv);
3736
3737 // Verify that it was added to host cache, by doing a subsequent async lookup
3738 // and confirming it completes synchronously.
3739 TestCompletionCallback resolve_callback;
3740 rv = session_deps.host_resolver->Resolve(
3741 HostResolver::RequestInfo("www.google.com", 80), &addrlist,
3742 &resolve_callback, NULL, NULL);
3743 ASSERT_EQ(OK, rv);
3744
3745 // Inject a failure the next time that "www.google.com" is resolved. This way
3746 // we can tell if the next lookup hit the cache, or the "network".
3747 // (cache --> success, "network" --> failure).
3748 session_deps.host_resolver->rules()->AddSimulatedFailure("www.google.com");
3749
3750 // Connect up a mock socket which will fail with ERR_UNEXPECTED during the
3751 // first read -- this won't be reached as the host resolution will fail first.
3752 MockRead data_reads[] = { MockRead(false, ERR_UNEXPECTED) };
3753 StaticSocketDataProvider data(data_reads, NULL);
3754 session_deps.socket_factory.AddSocketDataProvider(&data);
3755
3756 // Issue a request, asking to bypass the cache(s).
3757 HttpRequestInfo request;
3758 request.method = "GET";
3759 request.load_flags = LOAD_BYPASS_CACHE;
3760 request.url = GURL("http://www.google.com/");
3761
3762 // Run the request.
3763 TestCompletionCallback callback;
3764 rv = trans->Start(&request, &callback, NULL);
3765 ASSERT_EQ(ERR_IO_PENDING, rv);
3766 rv = callback.WaitForResult();
3767
3768 // If we bypassed the cache, we would have gotten a failure while resolving
3769 // "www.google.com".
3770 EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
3771 }
3772
3773 // Make sure we can handle an error when writing the request.
TEST_F(HttpNetworkTransactionTest,RequestWriteError)3774 TEST_F(HttpNetworkTransactionTest, RequestWriteError) {
3775 SessionDependencies session_deps;
3776 scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps);
3777
3778 HttpRequestInfo request;
3779 request.method = "GET";
3780 request.url = GURL("http://www.foo.com/");
3781 request.load_flags = 0;
3782
3783 MockWrite write_failure[] = {
3784 MockWrite(true, ERR_CONNECTION_RESET),
3785 };
3786 StaticSocketDataProvider data(NULL, write_failure);
3787 session_deps.socket_factory.AddSocketDataProvider(&data);
3788
3789 TestCompletionCallback callback;
3790
3791 scoped_ptr<HttpTransaction> trans(
3792 new HttpNetworkTransaction(CreateSession(&session_deps)));
3793
3794 int rv = trans->Start(&request, &callback, NULL);
3795 EXPECT_EQ(ERR_IO_PENDING, rv);
3796
3797 rv = callback.WaitForResult();
3798 EXPECT_EQ(ERR_CONNECTION_RESET, rv);
3799 }
3800
3801 // Check that a connection closed after the start of the headers finishes ok.
TEST_F(HttpNetworkTransactionTest,ConnectionClosedAfterStartOfHeaders)3802 TEST_F(HttpNetworkTransactionTest, ConnectionClosedAfterStartOfHeaders) {
3803 SessionDependencies session_deps;
3804 scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps);
3805
3806 HttpRequestInfo request;
3807 request.method = "GET";
3808 request.url = GURL("http://www.foo.com/");
3809 request.load_flags = 0;
3810
3811 MockRead data_reads[] = {
3812 MockRead("HTTP/1."),
3813 MockRead(false, OK),
3814 };
3815
3816 StaticSocketDataProvider data(data_reads, NULL);
3817 session_deps.socket_factory.AddSocketDataProvider(&data);
3818
3819 TestCompletionCallback callback;
3820
3821 scoped_ptr<HttpTransaction> trans(
3822 new HttpNetworkTransaction(CreateSession(&session_deps)));
3823
3824 int rv = trans->Start(&request, &callback, NULL);
3825 EXPECT_EQ(ERR_IO_PENDING, rv);
3826
3827 rv = callback.WaitForResult();
3828 EXPECT_EQ(OK, rv);
3829
3830 const HttpResponseInfo* response = trans->GetResponseInfo();
3831 EXPECT_TRUE(response != NULL);
3832
3833 EXPECT_TRUE(response->headers != NULL);
3834 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine());
3835
3836 std::string response_data;
3837 rv = ReadTransaction(trans.get(), &response_data);
3838 EXPECT_EQ(OK, rv);
3839 EXPECT_EQ("", response_data);
3840 }
3841
3842 // Make sure that a dropped connection while draining the body for auth
3843 // restart does the right thing.
TEST_F(HttpNetworkTransactionTest,DrainResetOK)3844 TEST_F(HttpNetworkTransactionTest, DrainResetOK) {
3845 SessionDependencies session_deps;
3846 scoped_ptr<HttpTransaction> trans(
3847 new HttpNetworkTransaction(CreateSession(&session_deps)));
3848
3849 HttpRequestInfo request;
3850 request.method = "GET";
3851 request.url = GURL("http://www.google.com/");
3852 request.load_flags = 0;
3853
3854 MockWrite data_writes1[] = {
3855 MockWrite("GET / HTTP/1.1\r\n"
3856 "Host: www.google.com\r\n"
3857 "Connection: keep-alive\r\n\r\n"),
3858 };
3859
3860 MockRead data_reads1[] = {
3861 MockRead("HTTP/1.1 401 Unauthorized\r\n"),
3862 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
3863 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
3864 MockRead("Content-Length: 14\r\n\r\n"),
3865 MockRead("Unauth"),
3866 MockRead(true, ERR_CONNECTION_RESET),
3867 };
3868
3869 StaticSocketDataProvider data1(data_reads1, data_writes1);
3870 session_deps.socket_factory.AddSocketDataProvider(&data1);
3871
3872 // After calling trans->RestartWithAuth(), this is the request we should
3873 // be issuing -- the final header line contains the credentials.
3874 MockWrite data_writes2[] = {
3875 MockWrite("GET / HTTP/1.1\r\n"
3876 "Host: www.google.com\r\n"
3877 "Connection: keep-alive\r\n"
3878 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
3879 };
3880
3881 // Lastly, the server responds with the actual content.
3882 MockRead data_reads2[] = {
3883 MockRead("HTTP/1.1 200 OK\r\n"),
3884 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
3885 MockRead("Content-Length: 100\r\n\r\n"),
3886 MockRead(false, OK),
3887 };
3888
3889 StaticSocketDataProvider data2(data_reads2, data_writes2);
3890 session_deps.socket_factory.AddSocketDataProvider(&data2);
3891
3892 TestCompletionCallback callback1;
3893
3894 int rv = trans->Start(&request, &callback1, NULL);
3895 EXPECT_EQ(ERR_IO_PENDING, rv);
3896
3897 rv = callback1.WaitForResult();
3898 EXPECT_EQ(OK, rv);
3899
3900 const HttpResponseInfo* response = trans->GetResponseInfo();
3901 EXPECT_FALSE(response == NULL);
3902
3903 // The password prompt info should have been set in response->auth_challenge.
3904 EXPECT_FALSE(response->auth_challenge.get() == NULL);
3905
3906 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
3907 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
3908 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
3909
3910 TestCompletionCallback callback2;
3911
3912 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
3913 EXPECT_EQ(ERR_IO_PENDING, rv);
3914
3915 rv = callback2.WaitForResult();
3916 EXPECT_EQ(OK, rv);
3917
3918 response = trans->GetResponseInfo();
3919 EXPECT_FALSE(response == NULL);
3920 EXPECT_TRUE(response->auth_challenge.get() == NULL);
3921 EXPECT_EQ(100, response->headers->GetContentLength());
3922 }
3923
3924 // Test HTTPS connections going through a proxy that sends extra data.
TEST_F(HttpNetworkTransactionTest,HTTPSViaProxyWithExtraData)3925 TEST_F(HttpNetworkTransactionTest, HTTPSViaProxyWithExtraData) {
3926 SessionDependencies session_deps(CreateFixedProxyService("myproxy:70"));
3927
3928 HttpRequestInfo request;
3929 request.method = "GET";
3930 request.url = GURL("https://www.google.com/");
3931 request.load_flags = 0;
3932
3933 MockRead proxy_reads[] = {
3934 MockRead("HTTP/1.0 200 Connected\r\n\r\nExtra data"),
3935 MockRead(false, OK)
3936 };
3937
3938 StaticSocketDataProvider data(proxy_reads, NULL);
3939 SSLSocketDataProvider ssl(true, OK);
3940
3941 session_deps.socket_factory.AddSocketDataProvider(&data);
3942 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
3943
3944 TestCompletionCallback callback;
3945
3946 session_deps.socket_factory.ResetNextMockIndexes();
3947
3948 scoped_ptr<HttpTransaction> trans(
3949 new HttpNetworkTransaction(CreateSession(&session_deps)));
3950
3951 int rv = trans->Start(&request, &callback, NULL);
3952 EXPECT_EQ(ERR_IO_PENDING, rv);
3953
3954 rv = callback.WaitForResult();
3955 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
3956 }
3957
TEST_F(HttpNetworkTransactionTest,LargeContentLengthThenClose)3958 TEST_F(HttpNetworkTransactionTest, LargeContentLengthThenClose) {
3959 MockRead data_reads[] = {
3960 MockRead("HTTP/1.0 200 OK\r\nContent-Length:6719476739\r\n\r\n"),
3961 MockRead(false, OK),
3962 };
3963 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
3964 EXPECT_EQ(OK, out.rv);
3965 EXPECT_EQ("HTTP/1.0 200 OK", out.status_line);
3966 EXPECT_EQ("", out.response_data);
3967 }
3968
3969 } // namespace net
3970