blob: 87f2636a0e6dfe9d0684353f243afa0ff437ea80 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 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.
initial.commit586acc5fe2008-07-26 22:42:524
[email protected]77848d12008-11-14 00:00:225#include <math.h> // ceil
6
[email protected]68bf9152008-09-25 19:47:307#include "base/compiler_specific.h"
initial.commit586acc5fe2008-07-26 22:42:528#include "net/base/client_socket_factory.h"
9#include "net/base/test_completion_callback.h"
10#include "net/base/upload_data.h"
11#include "net/http/http_network_session.h"
12#include "net/http/http_network_transaction.h"
13#include "net/http/http_transaction_unittest.h"
[email protected]51fff29d2008-12-19 22:17:5314#include "net/proxy/proxy_config_service_fixed.h"
initial.commit586acc5fe2008-07-26 22:42:5215#include "testing/gtest/include/gtest/gtest.h"
[email protected]23887f04f2008-12-02 19:20:1516#include "testing/platform_test.h"
initial.commit586acc5fe2008-07-26 22:42:5217
18//-----------------------------------------------------------------------------
19
initial.commit586acc5fe2008-07-26 22:42:5220
21struct MockConnect {
[email protected]217e6022008-09-29 18:18:3522 // Asynchronous connection success.
23 MockConnect() : async(true), result(net::OK) { }
[email protected]038e9a32008-10-08 22:40:1624
25 bool async;
26 int result;
initial.commit586acc5fe2008-07-26 22:42:5227};
28
29struct MockRead {
[email protected]217e6022008-09-29 18:18:3530 // Read failure (no data).
31 MockRead(bool async, int result) : async(async) , result(result), data(NULL),
32 data_len(0) { }
33
34 // Asynchronous read success (inferred data length).
[email protected]372d34a2008-11-05 21:30:5135 explicit MockRead(const char* data) : async(true), result(0), data(data),
[email protected]b5462e02008-09-29 18:32:1936 data_len(strlen(data)) { }
[email protected]217e6022008-09-29 18:18:3537
38 // Read success (inferred data length).
[email protected]b5462e02008-09-29 18:32:1939 MockRead(bool async, const char* data) : async(async), result(0), data(data),
40 data_len(strlen(data)) { }
[email protected]217e6022008-09-29 18:18:3541
42 // Read success.
43 MockRead(bool async, const char* data, int data_len) : async(async),
[email protected]b5462e02008-09-29 18:32:1944 result(0), data(data), data_len(data_len) { }
[email protected]217e6022008-09-29 18:18:3545
initial.commit586acc5fe2008-07-26 22:42:5246 bool async;
[email protected]217e6022008-09-29 18:18:3547 int result;
initial.commit586acc5fe2008-07-26 22:42:5248 const char* data;
[email protected]217e6022008-09-29 18:18:3549 int data_len;
initial.commit586acc5fe2008-07-26 22:42:5250};
51
[email protected]038e9a32008-10-08 22:40:1652// MockWrite uses the same member fields as MockRead, but with different
53// meanings. The expected input to MockTCPClientSocket::Write() is given
54// by {data, data_len}, and the return value of Write() is controlled by
55// {async, result}.
56typedef MockRead MockWrite;
57
initial.commit586acc5fe2008-07-26 22:42:5258struct MockSocket {
[email protected]038e9a32008-10-08 22:40:1659 MockSocket() : reads(NULL), writes(NULL) { }
[email protected]217e6022008-09-29 18:18:3560
initial.commit586acc5fe2008-07-26 22:42:5261 MockConnect connect;
[email protected]217e6022008-09-29 18:18:3562 MockRead* reads;
[email protected]038e9a32008-10-08 22:40:1663 MockWrite* writes;
initial.commit586acc5fe2008-07-26 22:42:5264};
65
66// Holds an array of MockSocket elements. As MockTCPClientSocket objects get
67// instantiated, they take their data from the i'th element of this array.
68//
69// Tests should assign the first N entries of mock_sockets to point to valid
70// MockSocket objects. The first unused entry should be NULL'd.
71//
72MockSocket* mock_sockets[10];
73
74// Index of the next mock_sockets element to use.
75int mock_sockets_index;
76
77class MockTCPClientSocket : public net::ClientSocket {
78 public:
[email protected]372d34a2008-11-05 21:30:5179 explicit MockTCPClientSocket(const net::AddressList& addresses)
initial.commit586acc5fe2008-07-26 22:42:5280 : data_(mock_sockets[mock_sockets_index++]),
[email protected]68bf9152008-09-25 19:47:3081 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
initial.commit586acc5fe2008-07-26 22:42:5282 callback_(NULL),
83 read_index_(0),
84 read_offset_(0),
[email protected]038e9a32008-10-08 22:40:1685 write_index_(0),
initial.commit586acc5fe2008-07-26 22:42:5286 connected_(false) {
87 DCHECK(data_) << "overran mock_sockets array";
88 }
89 // ClientSocket methods:
90 virtual int Connect(net::CompletionCallback* callback) {
91 DCHECK(!callback_);
92 if (connected_)
93 return net::OK;
94 connected_ = true;
95 if (data_->connect.async) {
96 RunCallbackAsync(callback, data_->connect.result);
97 return net::ERR_IO_PENDING;
98 }
99 return data_->connect.result;
100 }
101 virtual int ReconnectIgnoringLastError(net::CompletionCallback* callback) {
102 NOTREACHED();
103 return net::ERR_FAILED;
104 }
105 virtual void Disconnect() {
106 connected_ = false;
107 callback_ = NULL;
108 }
109 virtual bool IsConnected() const {
110 return connected_;
111 }
[email protected]b2197852009-02-19 23:27:33112 virtual bool IsConnectedAndIdle() const {
113 return connected_;
114 }
initial.commit586acc5fe2008-07-26 22:42:52115 // Socket methods:
116 virtual int Read(char* buf, int buf_len, net::CompletionCallback* callback) {
117 DCHECK(!callback_);
118 MockRead& r = data_->reads[read_index_];
[email protected]038e9a32008-10-08 22:40:16119 int result = r.result;
initial.commit586acc5fe2008-07-26 22:42:52120 if (r.data) {
initial.commit586acc5fe2008-07-26 22:42:52121 if (r.data_len - read_offset_ > 0) {
122 result = std::min(buf_len, r.data_len - read_offset_);
123 memcpy(buf, r.data + read_offset_, result);
124 read_offset_ += result;
125 if (read_offset_ == r.data_len) {
126 read_index_++;
127 read_offset_ = 0;
128 }
129 } else {
130 result = 0; // EOF
131 }
initial.commit586acc5fe2008-07-26 22:42:52132 }
133 if (r.async) {
134 RunCallbackAsync(callback, result);
135 return net::ERR_IO_PENDING;
136 }
137 return result;
138 }
139 virtual int Write(const char* buf, int buf_len,
140 net::CompletionCallback* callback) {
[email protected]372d34a2008-11-05 21:30:51141 DCHECK(buf);
142 DCHECK(buf_len > 0);
initial.commit586acc5fe2008-07-26 22:42:52143 DCHECK(!callback_);
[email protected]038e9a32008-10-08 22:40:16144 // Not using mock writes; succeed synchronously.
145 if (!data_->writes)
146 return buf_len;
[email protected]aaead502008-10-15 00:20:11147
[email protected]038e9a32008-10-08 22:40:16148 // Check that what we are writing matches the expectation.
149 // Then give the mocked return value.
[email protected]372d34a2008-11-05 21:30:51150 MockWrite& w = data_->writes[write_index_++];
[email protected]038e9a32008-10-08 22:40:16151 int result = w.result;
152 if (w.data) {
153 std::string expected_data(w.data, w.data_len);
154 std::string actual_data(buf, buf_len);
155 EXPECT_EQ(expected_data, actual_data);
156 if (expected_data != actual_data)
157 return net::ERR_UNEXPECTED;
158 if (result == net::OK)
159 result = w.data_len;
160 }
161 if (w.async) {
162 RunCallbackAsync(callback, result);
163 return net::ERR_IO_PENDING;
164 }
165 return result;
initial.commit586acc5fe2008-07-26 22:42:52166 }
167 private:
168 void RunCallbackAsync(net::CompletionCallback* callback, int result) {
169 callback_ = callback;
170 MessageLoop::current()->PostTask(FROM_HERE,
171 method_factory_.NewRunnableMethod(
172 &MockTCPClientSocket::RunCallback, result));
173 }
174 void RunCallback(int result) {
175 net::CompletionCallback* c = callback_;
176 callback_ = NULL;
177 if (c)
178 c->Run(result);
179 }
180 MockSocket* data_;
181 ScopedRunnableMethodFactory<MockTCPClientSocket> method_factory_;
182 net::CompletionCallback* callback_;
183 int read_index_;
184 int read_offset_;
[email protected]038e9a32008-10-08 22:40:16185 int write_index_;
initial.commit586acc5fe2008-07-26 22:42:52186 bool connected_;
187};
188
189class MockClientSocketFactory : public net::ClientSocketFactory {
190 public:
191 virtual net::ClientSocket* CreateTCPClientSocket(
192 const net::AddressList& addresses) {
193 return new MockTCPClientSocket(addresses);
194 }
[email protected]aaead502008-10-15 00:20:11195 virtual net::SSLClientSocket* CreateSSLClientSocket(
initial.commit586acc5fe2008-07-26 22:42:52196 net::ClientSocket* transport_socket,
[email protected]c5949a32008-10-08 17:28:23197 const std::string& hostname,
[email protected]aaead502008-10-15 00:20:11198 const net::SSLConfig& ssl_config) {
initial.commit586acc5fe2008-07-26 22:42:52199 return NULL;
200 }
201};
202
203MockClientSocketFactory mock_socket_factory;
204
[email protected]db8f44c2008-12-13 04:52:01205// Create a proxy service which fails on all requests (falls back to direct).
206net::ProxyService* CreateNullProxyService() {
[email protected]51fff29d2008-12-19 22:17:53207 return net::ProxyService::CreateNull();
initial.commit586acc5fe2008-07-26 22:42:52208}
209
[email protected]51fff29d2008-12-19 22:17:53210net::ProxyService* CreateFixedProxyService(const std::string& proxy) {
211 net::ProxyInfo proxy_info;
212 proxy_info.UseNamedProxy(proxy);
[email protected]d1ec59082009-02-11 02:48:15213 return net::ProxyService::Create(&proxy_info);
[email protected]51fff29d2008-12-19 22:17:53214}
215
216
[email protected]db8f44c2008-12-13 04:52:01217net::HttpNetworkSession* CreateSession(net::ProxyService* proxy_service) {
218 return new net::HttpNetworkSession(proxy_service);
[email protected]e8d536192008-10-17 22:21:14219}
220
[email protected]89836e22008-09-25 20:33:42221class HttpNetworkTransactionTest : public PlatformTest {
initial.commit586acc5fe2008-07-26 22:42:52222 public:
223 virtual void SetUp() {
[email protected]89836e22008-09-25 20:33:42224 PlatformTest::SetUp();
initial.commit586acc5fe2008-07-26 22:42:52225 mock_sockets[0] = NULL;
226 mock_sockets_index = 0;
227 }
[email protected]3d2a59b2008-09-26 19:44:25228
[email protected]0e75a732008-10-16 20:36:09229 virtual void TearDown() {
230 // Empty the current queue.
231 MessageLoop::current()->RunAllPending();
232 PlatformTest::TearDown();
233 }
234
[email protected]3d2a59b2008-09-26 19:44:25235 protected:
236 void KeepAliveConnectionResendRequestTest(const MockRead& read_failure);
initial.commit586acc5fe2008-07-26 22:42:52237};
238
[email protected]231d5a32008-09-13 00:45:27239struct SimpleGetHelperResult {
[email protected]aecfbf22008-10-16 02:02:47240 int rv;
[email protected]231d5a32008-09-13 00:45:27241 std::string status_line;
242 std::string response_data;
243};
initial.commit586acc5fe2008-07-26 22:42:52244
[email protected]231d5a32008-09-13 00:45:27245SimpleGetHelperResult SimpleGetHelper(MockRead data_reads[]) {
246 SimpleGetHelperResult out;
initial.commit586acc5fe2008-07-26 22:42:52247
[email protected]db8f44c2008-12-13 04:52:01248 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
[email protected]af4876d2008-10-21 23:10:57249 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
[email protected]db8f44c2008-12-13 04:52:01250 CreateSession(proxy_service.get()), &mock_socket_factory));
initial.commit586acc5fe2008-07-26 22:42:52251
252 net::HttpRequestInfo request;
253 request.method = "GET";
254 request.url = GURL("http://www.google.com/");
255 request.load_flags = 0;
256
initial.commit586acc5fe2008-07-26 22:42:52257 MockSocket data;
initial.commit586acc5fe2008-07-26 22:42:52258 data.reads = data_reads;
259 mock_sockets[0] = &data;
260 mock_sockets[1] = NULL;
261
262 TestCompletionCallback callback;
263
264 int rv = trans->Start(&request, &callback);
265 EXPECT_EQ(net::ERR_IO_PENDING, rv);
266
[email protected]aecfbf22008-10-16 02:02:47267 out.rv = callback.WaitForResult();
[email protected]af4876d2008-10-21 23:10:57268 if (out.rv != net::OK)
[email protected]aecfbf22008-10-16 02:02:47269 return out;
initial.commit586acc5fe2008-07-26 22:42:52270
271 const net::HttpResponseInfo* response = trans->GetResponseInfo();
272 EXPECT_TRUE(response != NULL);
273
274 EXPECT_TRUE(response->headers != NULL);
[email protected]231d5a32008-09-13 00:45:27275 out.status_line = response->headers->GetStatusLine();
initial.commit586acc5fe2008-07-26 22:42:52276
[email protected]af4876d2008-10-21 23:10:57277 rv = ReadTransaction(trans.get(), &out.response_data);
initial.commit586acc5fe2008-07-26 22:42:52278 EXPECT_EQ(net::OK, rv);
initial.commit586acc5fe2008-07-26 22:42:52279
[email protected]231d5a32008-09-13 00:45:27280 return out;
281}
282
[email protected]15a5ccf82008-10-23 19:57:43283// Fill |str| with a long header list that consumes >= |size| bytes.
284void FillLargeHeadersString(std::string* str, int size) {
[email protected]4ddaf2502008-10-23 18:26:19285 const char* row =
286 "SomeHeaderName: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n";
287 const int sizeof_row = strlen(row);
288 const int num_rows = static_cast<int>(
289 ceil(static_cast<float>(size) / sizeof_row));
290 const int sizeof_data = num_rows * sizeof_row;
291 DCHECK(sizeof_data >= size);
[email protected]15a5ccf82008-10-23 19:57:43292 str->reserve(sizeof_data);
[email protected]372d34a2008-11-05 21:30:51293
[email protected]4ddaf2502008-10-23 18:26:19294 for (int i = 0; i < num_rows; ++i)
[email protected]15a5ccf82008-10-23 19:57:43295 str->append(row, sizeof_row);
[email protected]4ddaf2502008-10-23 18:26:19296}
297
[email protected]231d5a32008-09-13 00:45:27298//-----------------------------------------------------------------------------
299
300TEST_F(HttpNetworkTransactionTest, Basic) {
[email protected]db8f44c2008-12-13 04:52:01301 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
[email protected]af4876d2008-10-21 23:10:57302 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
[email protected]db8f44c2008-12-13 04:52:01303 CreateSession(proxy_service.get()), &mock_socket_factory));
[email protected]231d5a32008-09-13 00:45:27304}
305
306TEST_F(HttpNetworkTransactionTest, SimpleGET) {
307 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35308 MockRead("HTTP/1.0 200 OK\r\n\r\n"),
309 MockRead("hello world"),
310 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27311 };
[email protected]231d5a32008-09-13 00:45:27312 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47313 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27314 EXPECT_EQ("HTTP/1.0 200 OK", out.status_line);
315 EXPECT_EQ("hello world", out.response_data);
316}
317
318// Response with no status line.
319TEST_F(HttpNetworkTransactionTest, SimpleGETNoHeaders) {
320 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35321 MockRead("hello world"),
322 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27323 };
[email protected]231d5a32008-09-13 00:45:27324 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47325 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27326 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
327 EXPECT_EQ("hello world", out.response_data);
328}
329
330// Allow up to 4 bytes of junk to precede status line.
331TEST_F(HttpNetworkTransactionTest, StatusLineJunk2Bytes) {
332 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35333 MockRead("xxxHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
334 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27335 };
336 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47337 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27338 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
339 EXPECT_EQ("DATA", out.response_data);
340}
341
342// Allow up to 4 bytes of junk to precede status line.
343TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes) {
344 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35345 MockRead("\n\nQJHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
346 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27347 };
348 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47349 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27350 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
351 EXPECT_EQ("DATA", out.response_data);
352}
353
354// Beyond 4 bytes of slop and it should fail to find a status line.
355TEST_F(HttpNetworkTransactionTest, StatusLineJunk5Bytes) {
356 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35357 MockRead("xxxxxHTTP/1.1 404 Not Found\nServer: blah"),
358 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27359 };
360 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47361 EXPECT_EQ(net::OK, out.rv);
[email protected]3d2a59b2008-09-26 19:44:25362 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
363 EXPECT_EQ("xxxxxHTTP/1.1 404 Not Found\nServer: blah", out.response_data);
[email protected]231d5a32008-09-13 00:45:27364}
365
366// Same as StatusLineJunk4Bytes, except the read chunks are smaller.
367TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes_Slow) {
368 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35369 MockRead("\n"),
370 MockRead("\n"),
371 MockRead("Q"),
372 MockRead("J"),
373 MockRead("HTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
374 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27375 };
376 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47377 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27378 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
379 EXPECT_EQ("DATA", out.response_data);
380}
381
382// Close the connection before enough bytes to have a status line.
383TEST_F(HttpNetworkTransactionTest, StatusLinePartial) {
384 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35385 MockRead("HTT"),
386 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27387 };
388 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47389 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27390 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
391 EXPECT_EQ("HTT", out.response_data);
initial.commit586acc5fe2008-07-26 22:42:52392}
393
[email protected]f9d44aa2008-09-23 23:57:17394// Simulate a 204 response, lacking a Content-Length header, sent over a
395// persistent connection. The response should still terminate since a 204
396// cannot have a response body.
397TEST_F(HttpNetworkTransactionTest, StopsReading204) {
398 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35399 MockRead("HTTP/1.1 204 No Content\r\n\r\n"),
400 MockRead("junk"), // Should not be read!!
401 MockRead(false, net::OK),
[email protected]f9d44aa2008-09-23 23:57:17402 };
403 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47404 EXPECT_EQ(net::OK, out.rv);
[email protected]f9d44aa2008-09-23 23:57:17405 EXPECT_EQ("HTTP/1.1 204 No Content", out.status_line);
406 EXPECT_EQ("", out.response_data);
407}
408
initial.commit586acc5fe2008-07-26 22:42:52409TEST_F(HttpNetworkTransactionTest, ReuseConnection) {
[email protected]db8f44c2008-12-13 04:52:01410 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
411 scoped_refptr<net::HttpNetworkSession> session =
412 CreateSession(proxy_service.get());
initial.commit586acc5fe2008-07-26 22:42:52413
414 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35415 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
416 MockRead("hello"),
417 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
418 MockRead("world"),
419 MockRead(false, net::OK),
initial.commit586acc5fe2008-07-26 22:42:52420 };
421 MockSocket data;
initial.commit586acc5fe2008-07-26 22:42:52422 data.reads = data_reads;
423 mock_sockets[0] = &data;
424 mock_sockets[1] = NULL;
425
426 const char* kExpectedResponseData[] = {
427 "hello", "world"
428 };
429
430 for (int i = 0; i < 2; ++i) {
[email protected]af4876d2008-10-21 23:10:57431 scoped_ptr<net::HttpTransaction> trans(
432 new net::HttpNetworkTransaction(session, &mock_socket_factory));
initial.commit586acc5fe2008-07-26 22:42:52433
434 net::HttpRequestInfo request;
435 request.method = "GET";
436 request.url = GURL("http://www.google.com/");
437 request.load_flags = 0;
438
439 TestCompletionCallback callback;
440
441 int rv = trans->Start(&request, &callback);
442 EXPECT_EQ(net::ERR_IO_PENDING, rv);
443
444 rv = callback.WaitForResult();
445 EXPECT_EQ(net::OK, rv);
446
447 const net::HttpResponseInfo* response = trans->GetResponseInfo();
448 EXPECT_TRUE(response != NULL);
449
450 EXPECT_TRUE(response->headers != NULL);
[email protected]3d2a59b2008-09-26 19:44:25451 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
initial.commit586acc5fe2008-07-26 22:42:52452
453 std::string response_data;
[email protected]af4876d2008-10-21 23:10:57454 rv = ReadTransaction(trans.get(), &response_data);
initial.commit586acc5fe2008-07-26 22:42:52455 EXPECT_EQ(net::OK, rv);
[email protected]3d2a59b2008-09-26 19:44:25456 EXPECT_EQ(kExpectedResponseData[i], response_data);
initial.commit586acc5fe2008-07-26 22:42:52457 }
458}
459
460TEST_F(HttpNetworkTransactionTest, Ignores100) {
[email protected]db8f44c2008-12-13 04:52:01461 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
[email protected]af4876d2008-10-21 23:10:57462 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
[email protected]db8f44c2008-12-13 04:52:01463 CreateSession(proxy_service.get()), &mock_socket_factory));
initial.commit586acc5fe2008-07-26 22:42:52464
465 net::HttpRequestInfo request;
466 request.method = "POST";
467 request.url = GURL("http://www.foo.com/");
468 request.upload_data = new net::UploadData;
469 request.upload_data->AppendBytes("foo", 3);
470 request.load_flags = 0;
471
472 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35473 MockRead("HTTP/1.0 100 Continue\r\n\r\n"),
474 MockRead("HTTP/1.0 200 OK\r\n\r\n"),
475 MockRead("hello world"),
476 MockRead(false, net::OK),
initial.commit586acc5fe2008-07-26 22:42:52477 };
478 MockSocket data;
initial.commit586acc5fe2008-07-26 22:42:52479 data.reads = data_reads;
480 mock_sockets[0] = &data;
481 mock_sockets[1] = NULL;
482
483 TestCompletionCallback callback;
484
485 int rv = trans->Start(&request, &callback);
486 EXPECT_EQ(net::ERR_IO_PENDING, rv);
487
488 rv = callback.WaitForResult();
489 EXPECT_EQ(net::OK, rv);
490
491 const net::HttpResponseInfo* response = trans->GetResponseInfo();
492 EXPECT_TRUE(response != NULL);
493
494 EXPECT_TRUE(response->headers != NULL);
[email protected]3d2a59b2008-09-26 19:44:25495 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine());
initial.commit586acc5fe2008-07-26 22:42:52496
497 std::string response_data;
[email protected]af4876d2008-10-21 23:10:57498 rv = ReadTransaction(trans.get(), &response_data);
initial.commit586acc5fe2008-07-26 22:42:52499 EXPECT_EQ(net::OK, rv);
[email protected]3d2a59b2008-09-26 19:44:25500 EXPECT_EQ("hello world", response_data);
initial.commit586acc5fe2008-07-26 22:42:52501}
502
[email protected]3d2a59b2008-09-26 19:44:25503// read_failure specifies a read failure that should cause the network
504// transaction to resend the request.
505void HttpNetworkTransactionTest::KeepAliveConnectionResendRequestTest(
506 const MockRead& read_failure) {
[email protected]db8f44c2008-12-13 04:52:01507 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
508 scoped_refptr<net::HttpNetworkSession> session =
509 CreateSession(proxy_service.get());
initial.commit586acc5fe2008-07-26 22:42:52510
511 net::HttpRequestInfo request;
512 request.method = "GET";
513 request.url = GURL("http://www.foo.com/");
514 request.load_flags = 0;
515
516 MockRead data1_reads[] = {
[email protected]217e6022008-09-29 18:18:35517 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
518 MockRead("hello"),
[email protected]3d2a59b2008-09-26 19:44:25519 read_failure, // Now, we reuse the connection and fail the first read.
initial.commit586acc5fe2008-07-26 22:42:52520 };
521 MockSocket data1;
initial.commit586acc5fe2008-07-26 22:42:52522 data1.reads = data1_reads;
523 mock_sockets[0] = &data1;
524
525 MockRead data2_reads[] = {
[email protected]217e6022008-09-29 18:18:35526 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
527 MockRead("world"),
528 MockRead(true, net::OK),
initial.commit586acc5fe2008-07-26 22:42:52529 };
530 MockSocket data2;
initial.commit586acc5fe2008-07-26 22:42:52531 data2.reads = data2_reads;
532 mock_sockets[1] = &data2;
533
534 const char* kExpectedResponseData[] = {
535 "hello", "world"
536 };
537
538 for (int i = 0; i < 2; ++i) {
539 TestCompletionCallback callback;
540
[email protected]af4876d2008-10-21 23:10:57541 scoped_ptr<net::HttpTransaction> trans(
542 new net::HttpNetworkTransaction(session, &mock_socket_factory));
initial.commit586acc5fe2008-07-26 22:42:52543
544 int rv = trans->Start(&request, &callback);
545 EXPECT_EQ(net::ERR_IO_PENDING, rv);
546
547 rv = callback.WaitForResult();
548 EXPECT_EQ(net::OK, rv);
549
550 const net::HttpResponseInfo* response = trans->GetResponseInfo();
551 EXPECT_TRUE(response != NULL);
552
553 EXPECT_TRUE(response->headers != NULL);
[email protected]3d2a59b2008-09-26 19:44:25554 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
initial.commit586acc5fe2008-07-26 22:42:52555
556 std::string response_data;
[email protected]af4876d2008-10-21 23:10:57557 rv = ReadTransaction(trans.get(), &response_data);
initial.commit586acc5fe2008-07-26 22:42:52558 EXPECT_EQ(net::OK, rv);
[email protected]3d2a59b2008-09-26 19:44:25559 EXPECT_EQ(kExpectedResponseData[i], response_data);
initial.commit586acc5fe2008-07-26 22:42:52560 }
561}
[email protected]3d2a59b2008-09-26 19:44:25562
563TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionReset) {
[email protected]217e6022008-09-29 18:18:35564 MockRead read_failure(true, net::ERR_CONNECTION_RESET);
[email protected]3d2a59b2008-09-26 19:44:25565 KeepAliveConnectionResendRequestTest(read_failure);
566}
567
568TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionEOF) {
[email protected]217e6022008-09-29 18:18:35569 MockRead read_failure(false, net::OK); // EOF
[email protected]3d2a59b2008-09-26 19:44:25570 KeepAliveConnectionResendRequestTest(read_failure);
571}
572
573TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionReset) {
[email protected]db8f44c2008-12-13 04:52:01574 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
[email protected]af4876d2008-10-21 23:10:57575 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
[email protected]db8f44c2008-12-13 04:52:01576 CreateSession(proxy_service.get()), &mock_socket_factory));
[email protected]3d2a59b2008-09-26 19:44:25577
578 net::HttpRequestInfo request;
579 request.method = "GET";
580 request.url = GURL("http://www.google.com/");
581 request.load_flags = 0;
582
583 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35584 MockRead(true, net::ERR_CONNECTION_RESET),
585 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used
586 MockRead("hello world"),
587 MockRead(false, net::OK),
[email protected]3d2a59b2008-09-26 19:44:25588 };
589 MockSocket data;
[email protected]3d2a59b2008-09-26 19:44:25590 data.reads = data_reads;
591 mock_sockets[0] = &data;
592 mock_sockets[1] = NULL;
593
594 TestCompletionCallback callback;
595
596 int rv = trans->Start(&request, &callback);
597 EXPECT_EQ(net::ERR_IO_PENDING, rv);
598
599 rv = callback.WaitForResult();
600 EXPECT_EQ(net::ERR_CONNECTION_RESET, rv);
601
602 const net::HttpResponseInfo* response = trans->GetResponseInfo();
603 EXPECT_TRUE(response == NULL);
[email protected]3d2a59b2008-09-26 19:44:25604}
605
606// What do various browsers do when the server closes a non-keepalive
607// connection without sending any response header or body?
608//
609// IE7: error page
610// Safari 3.1.2 (Windows): error page
611// Firefox 3.0.1: blank page
612// Opera 9.52: after five attempts, blank page
613// Us with WinHTTP: error page (net::ERR_INVALID_RESPONSE)
[email protected]aecfbf22008-10-16 02:02:47614// Us: error page (net::EMPTY_RESPONSE)
[email protected]3d2a59b2008-09-26 19:44:25615TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionEOF) {
616 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35617 MockRead(false, net::OK), // EOF
618 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used
619 MockRead("hello world"),
620 MockRead(false, net::OK),
[email protected]3d2a59b2008-09-26 19:44:25621 };
622 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]0e75a732008-10-16 20:36:09623 EXPECT_EQ(net::ERR_EMPTY_RESPONSE, out.rv);
[email protected]3d2a59b2008-09-26 19:44:25624}
[email protected]038e9a32008-10-08 22:40:16625
626// Test the request-challenge-retry sequence for basic auth.
627// (basic auth is the easiest to mock, because it has no randomness).
628TEST_F(HttpNetworkTransactionTest, BasicAuth) {
[email protected]db8f44c2008-12-13 04:52:01629 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
[email protected]af4876d2008-10-21 23:10:57630 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
[email protected]db8f44c2008-12-13 04:52:01631 CreateSession(proxy_service.get()), &mock_socket_factory));
[email protected]038e9a32008-10-08 22:40:16632
633 net::HttpRequestInfo request;
634 request.method = "GET";
635 request.url = GURL("http://www.google.com/");
636 request.load_flags = 0;
637
[email protected]f9ee6b52008-11-08 06:46:23638 MockWrite data_writes1[] = {
639 MockWrite("GET / HTTP/1.1\r\n"
640 "Host: www.google.com\r\n"
641 "Connection: keep-alive\r\n\r\n"),
642 };
643
[email protected]038e9a32008-10-08 22:40:16644 MockRead data_reads1[] = {
645 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
646 // Give a couple authenticate options (only the middle one is actually
647 // supported).
[email protected]aaead502008-10-15 00:20:11648 MockRead("WWW-Authenticate: Basic\r\n"), // Malformed
[email protected]038e9a32008-10-08 22:40:16649 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
650 MockRead("WWW-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"),
651 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
652 // Large content-length -- won't matter, as connection will be reset.
653 MockRead("Content-Length: 10000\r\n\r\n"),
654 MockRead(false, net::ERR_FAILED),
655 };
656
657 // After calling trans->RestartWithAuth(), this is the request we should
658 // be issuing -- the final header line contains the credentials.
659 MockWrite data_writes2[] = {
660 MockWrite("GET / HTTP/1.1\r\n"
661 "Host: www.google.com\r\n"
662 "Connection: keep-alive\r\n"
663 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
664 };
665
666 // Lastly, the server responds with the actual content.
667 MockRead data_reads2[] = {
668 MockRead("HTTP/1.0 200 OK\r\n"),
669 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
670 MockRead("Content-Length: 100\r\n\r\n"),
671 MockRead(false, net::OK),
672 };
673
674 MockSocket data1;
675 data1.reads = data_reads1;
[email protected]f9ee6b52008-11-08 06:46:23676 data1.writes = data_writes1;
[email protected]038e9a32008-10-08 22:40:16677 MockSocket data2;
678 data2.reads = data_reads2;
679 data2.writes = data_writes2;
680 mock_sockets[0] = &data1;
681 mock_sockets[1] = &data2;
682 mock_sockets[2] = NULL;
683
684 TestCompletionCallback callback1;
685
686 int rv = trans->Start(&request, &callback1);
687 EXPECT_EQ(net::ERR_IO_PENDING, rv);
688
689 rv = callback1.WaitForResult();
690 EXPECT_EQ(net::OK, rv);
691
692 const net::HttpResponseInfo* response = trans->GetResponseInfo();
693 EXPECT_FALSE(response == NULL);
694
695 // The password prompt info should have been set in response->auth_challenge.
696 EXPECT_FALSE(response->auth_challenge.get() == NULL);
697
698 // TODO(eroman): this should really include the effective port (80)
699 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
700 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
701 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
702
703 TestCompletionCallback callback2;
704
705 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
706 EXPECT_EQ(net::ERR_IO_PENDING, rv);
707
708 rv = callback2.WaitForResult();
709 EXPECT_EQ(net::OK, rv);
710
711 response = trans->GetResponseInfo();
712 EXPECT_FALSE(response == NULL);
713 EXPECT_TRUE(response->auth_challenge.get() == NULL);
714 EXPECT_EQ(100, response->headers->GetContentLength());
[email protected]038e9a32008-10-08 22:40:16715}
716
[email protected]2d2697f92009-02-18 21:00:32717// Test the request-challenge-retry sequence for basic auth, over a keep-alive
718// connection.
719TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAlive) {
720 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
721 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
722 CreateSession(proxy_service.get()), &mock_socket_factory));
723
724 net::HttpRequestInfo request;
725 request.method = "GET";
726 request.url = GURL("http://www.google.com/");
727 request.load_flags = 0;
728
729 MockWrite data_writes1[] = {
730 MockWrite("GET / HTTP/1.1\r\n"
731 "Host: www.google.com\r\n"
732 "Connection: keep-alive\r\n\r\n"),
733
734 // After calling trans->RestartWithAuth(), this is the request we should
735 // be issuing -- the final header line contains the credentials.
736 MockWrite("GET / HTTP/1.1\r\n"
737 "Host: www.google.com\r\n"
738 "Connection: keep-alive\r\n"
739 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
740 };
741
742 MockRead data_reads1[] = {
743 MockRead("HTTP/1.1 401 Unauthorized\r\n"),
744 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
745 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
746 MockRead("Content-Length: 14\r\n\r\n"),
747 MockRead("Unauthorized\r\n"),
748
749 // Lastly, the server responds with the actual content.
750 MockRead("HTTP/1.1 200 OK\r\n"),
751 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
752 MockRead("Content-Length: 100\r\n\r\n"),
753 MockRead(false, net::OK),
754 };
755
756 MockSocket data1;
757 data1.reads = data_reads1;
758 data1.writes = data_writes1;
759 mock_sockets[0] = &data1;
760 mock_sockets[1] = NULL;
761
762 TestCompletionCallback callback1;
763
764 int rv = trans->Start(&request, &callback1);
765 EXPECT_EQ(net::ERR_IO_PENDING, rv);
766
767 rv = callback1.WaitForResult();
768 EXPECT_EQ(net::OK, rv);
769
770 const net::HttpResponseInfo* response = trans->GetResponseInfo();
771 EXPECT_FALSE(response == NULL);
772
773 // The password prompt info should have been set in response->auth_challenge.
774 EXPECT_FALSE(response->auth_challenge.get() == NULL);
775
776 // TODO(eroman): this should really include the effective port (80)
777 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
778 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
779 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
780
781 TestCompletionCallback callback2;
782
783 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
784 EXPECT_EQ(net::ERR_IO_PENDING, rv);
785
786 rv = callback2.WaitForResult();
787 EXPECT_EQ(net::OK, rv);
788
789 response = trans->GetResponseInfo();
790 EXPECT_FALSE(response == NULL);
791 EXPECT_TRUE(response->auth_challenge.get() == NULL);
792 EXPECT_EQ(100, response->headers->GetContentLength());
793}
794
795// Test the request-challenge-retry sequence for basic auth, over a keep-alive
796// connection and with no response body to drain.
797TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) {
798 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
799 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
800 CreateSession(proxy_service.get()), &mock_socket_factory));
801
802 net::HttpRequestInfo request;
803 request.method = "GET";
804 request.url = GURL("http://www.google.com/");
805 request.load_flags = 0;
806
807 MockWrite data_writes1[] = {
808 MockWrite("GET / HTTP/1.1\r\n"
809 "Host: www.google.com\r\n"
810 "Connection: keep-alive\r\n\r\n"),
811
812 // After calling trans->RestartWithAuth(), this is the request we should
813 // be issuing -- the final header line contains the credentials.
814 MockWrite("GET / HTTP/1.1\r\n"
815 "Host: www.google.com\r\n"
816 "Connection: keep-alive\r\n"
817 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
818 };
819
820 // Respond with 5 kb of response body.
821 std::string large_body_string("Unauthorized");
822 large_body_string.append(5 * 1024, ' ');
823 large_body_string.append("\r\n");
824
825 MockRead data_reads1[] = {
826 MockRead("HTTP/1.1 401 Unauthorized\r\n"),
827 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
828 MockRead("Content-Length: 0\r\n\r\n"),
829
830 // Lastly, the server responds with the actual content.
831 MockRead("HTTP/1.1 200 OK\r\n"),
832 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
833 MockRead("Content-Length: 100\r\n\r\n"),
834 MockRead(false, net::OK),
835 };
836
837 MockSocket data1;
838 data1.reads = data_reads1;
839 data1.writes = data_writes1;
840 mock_sockets[0] = &data1;
841 mock_sockets[1] = NULL;
842
843 TestCompletionCallback callback1;
844
845 int rv = trans->Start(&request, &callback1);
846 EXPECT_EQ(net::ERR_IO_PENDING, rv);
847
848 rv = callback1.WaitForResult();
849 EXPECT_EQ(net::OK, rv);
850
851 const net::HttpResponseInfo* response = trans->GetResponseInfo();
852 EXPECT_FALSE(response == NULL);
853
854 // The password prompt info should have been set in response->auth_challenge.
855 EXPECT_FALSE(response->auth_challenge.get() == NULL);
856
857 // TODO(eroman): this should really include the effective port (80)
858 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
859 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
860 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
861
862 TestCompletionCallback callback2;
863
864 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
865 EXPECT_EQ(net::ERR_IO_PENDING, rv);
866
867 rv = callback2.WaitForResult();
868 EXPECT_EQ(net::OK, rv);
869
870 response = trans->GetResponseInfo();
871 EXPECT_FALSE(response == NULL);
872 EXPECT_TRUE(response->auth_challenge.get() == NULL);
873 EXPECT_EQ(100, response->headers->GetContentLength());
874}
875
876// Test the request-challenge-retry sequence for basic auth, over a keep-alive
877// connection and with a large response body to drain.
878TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) {
879 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
880 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
881 CreateSession(proxy_service.get()), &mock_socket_factory));
882
883 net::HttpRequestInfo request;
884 request.method = "GET";
885 request.url = GURL("http://www.google.com/");
886 request.load_flags = 0;
887
888 MockWrite data_writes1[] = {
889 MockWrite("GET / HTTP/1.1\r\n"
890 "Host: www.google.com\r\n"
891 "Connection: keep-alive\r\n\r\n"),
892
893 // After calling trans->RestartWithAuth(), this is the request we should
894 // be issuing -- the final header line contains the credentials.
895 MockWrite("GET / HTTP/1.1\r\n"
896 "Host: www.google.com\r\n"
897 "Connection: keep-alive\r\n"
898 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
899 };
900
901 // Respond with 5 kb of response body.
902 std::string large_body_string("Unauthorized");
903 large_body_string.append(5 * 1024, ' ');
904 large_body_string.append("\r\n");
905
906 MockRead data_reads1[] = {
907 MockRead("HTTP/1.1 401 Unauthorized\r\n"),
908 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
909 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
910 // 5134 = 12 + 5 * 1024 + 2
911 MockRead("Content-Length: 5134\r\n\r\n"),
912 MockRead(true, large_body_string.data(), large_body_string.size()),
913
914 // Lastly, the server responds with the actual content.
915 MockRead("HTTP/1.1 200 OK\r\n"),
916 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
917 MockRead("Content-Length: 100\r\n\r\n"),
918 MockRead(false, net::OK),
919 };
920
921 MockSocket data1;
922 data1.reads = data_reads1;
923 data1.writes = data_writes1;
924 mock_sockets[0] = &data1;
925 mock_sockets[1] = NULL;
926
927 TestCompletionCallback callback1;
928
929 int rv = trans->Start(&request, &callback1);
930 EXPECT_EQ(net::ERR_IO_PENDING, rv);
931
932 rv = callback1.WaitForResult();
933 EXPECT_EQ(net::OK, rv);
934
935 const net::HttpResponseInfo* response = trans->GetResponseInfo();
936 EXPECT_FALSE(response == NULL);
937
938 // The password prompt info should have been set in response->auth_challenge.
939 EXPECT_FALSE(response->auth_challenge.get() == NULL);
940
941 // TODO(eroman): this should really include the effective port (80)
942 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
943 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
944 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
945
946 TestCompletionCallback callback2;
947
948 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
949 EXPECT_EQ(net::ERR_IO_PENDING, rv);
950
951 rv = callback2.WaitForResult();
952 EXPECT_EQ(net::OK, rv);
953
954 response = trans->GetResponseInfo();
955 EXPECT_FALSE(response == NULL);
956 EXPECT_TRUE(response->auth_challenge.get() == NULL);
957 EXPECT_EQ(100, response->headers->GetContentLength());
958}
959
960// Test the request-challenge-retry sequence for basic auth, over a keep-alive
961// proxy connection, when setting up an SSL tunnel.
962TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAlive) {
963 // Configure against proxy server "myproxy:70".
964 scoped_ptr<net::ProxyService> proxy_service(
965 CreateFixedProxyService("myproxy:70"));
966
967 scoped_refptr<net::HttpNetworkSession> session(
968 CreateSession(proxy_service.get()));
969
970 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
971 session.get(), &mock_socket_factory));
972
973 net::HttpRequestInfo request;
974 request.method = "GET";
975 request.url = GURL("https://www.google.com/");
976 request.load_flags = 0;
977
978 // Since we have proxy, should try to establish tunnel.
979 MockWrite data_writes1[] = {
980 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
981 "Host: www.google.com\r\n\r\n"),
982
983 // After calling trans->RestartWithAuth(), this is the request we should
984 // be issuing -- the final header line contains the credentials.
985 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
986 "Host: www.google.com\r\n"
987 "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"),
988 };
989
990 // The proxy responds to the connect with a 407, using a persistent
991 // connection.
992 MockRead data_reads1[] = {
993 // No credentials.
994 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
995 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
996 MockRead("Content-Length: 10\r\n\r\n"),
997 MockRead("0123456789"),
998
999 // Wrong credentials (wrong password).
1000 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
1001 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1002 MockRead("Content-Length: 10\r\n\r\n"),
1003 // No response body because the test stops reading here.
1004 MockRead(false, net::ERR_UNEXPECTED), // Should not be reached.
1005 };
1006
1007 MockSocket data1;
1008 data1.writes = data_writes1;
1009 data1.reads = data_reads1;
1010 mock_sockets[0] = &data1;
1011 mock_sockets[1] = NULL;
1012
1013 TestCompletionCallback callback1;
1014
1015 int rv = trans->Start(&request, &callback1);
1016 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1017
1018 rv = callback1.WaitForResult();
1019 EXPECT_EQ(net::OK, rv);
1020
1021 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1022 EXPECT_FALSE(response == NULL);
1023
1024 EXPECT_TRUE(response->headers->IsKeepAlive());
1025 EXPECT_EQ(407, response->headers->response_code());
1026 EXPECT_EQ(10, response->headers->GetContentLength());
1027 EXPECT_TRUE(net::HttpVersion(1, 1) == response->headers->GetHttpVersion());
1028
1029 // The password prompt info should have been set in response->auth_challenge.
1030 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1031
1032 // TODO(eroman): this should really include the effective port (80)
1033 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host);
1034 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1035 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1036
1037 TestCompletionCallback callback2;
1038
1039 // Wrong password (should be "bar").
1040 rv = trans->RestartWithAuth(L"foo", L"baz", &callback2);
1041 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1042
1043 rv = callback2.WaitForResult();
1044 EXPECT_EQ(net::OK, rv);
1045
1046 response = trans->GetResponseInfo();
1047 EXPECT_FALSE(response == NULL);
1048
1049 EXPECT_TRUE(response->headers->IsKeepAlive());
1050 EXPECT_EQ(407, response->headers->response_code());
1051 EXPECT_EQ(10, response->headers->GetContentLength());
1052 EXPECT_TRUE(net::HttpVersion(1, 1) == response->headers->GetHttpVersion());
1053
1054 // The password prompt info should have been set in response->auth_challenge.
1055 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1056
1057 // TODO(eroman): this should really include the effective port (80)
1058 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host);
1059 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1060 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1061}
1062
[email protected]c744cf22009-02-27 07:28:081063static void ConnectStatusHelperWithExpectedStatus(
1064 const MockRead& status, int expected_status) {
1065 // Configure against proxy server "myproxy:70".
1066 scoped_ptr<net::ProxyService> proxy_service(
1067 CreateFixedProxyService("myproxy:70"));
1068
1069 scoped_refptr<net::HttpNetworkSession> session(
1070 CreateSession(proxy_service.get()));
1071
1072 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1073 session.get(), &mock_socket_factory));
1074
1075 net::HttpRequestInfo request;
1076 request.method = "GET";
1077 request.url = GURL("https://www.google.com/");
1078 request.load_flags = 0;
1079
1080 // Since we have proxy, should try to establish tunnel.
1081 MockWrite data_writes[] = {
1082 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
1083 "Host: www.google.com\r\n\r\n"),
1084 };
1085
1086 MockRead data_reads[] = {
1087 status,
1088 MockRead("Content-Length: 10\r\n\r\n"),
1089 // No response body because the test stops reading here.
1090 MockRead(false, net::ERR_UNEXPECTED), // Should not be reached.
1091 };
1092
1093 MockSocket data;
1094 data.writes = data_writes;
1095 data.reads = data_reads;
1096 mock_sockets[0] = &data;
1097 mock_sockets[1] = NULL;
1098
1099 TestCompletionCallback callback;
1100
1101 int rv = trans->Start(&request, &callback);
1102 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1103
1104 rv = callback.WaitForResult();
1105 EXPECT_EQ(expected_status, rv);
1106}
1107
1108static void ConnectStatusHelper(const MockRead& status) {
1109 ConnectStatusHelperWithExpectedStatus(
1110 status, net::ERR_TUNNEL_CONNECTION_FAILED);
1111}
1112
1113TEST_F(HttpNetworkTransactionTest, ConnectStatus100) {
1114 ConnectStatusHelper(MockRead("HTTP/1.1 100 Continue\r\n"));
1115}
1116
1117TEST_F(HttpNetworkTransactionTest, ConnectStatus101) {
1118 ConnectStatusHelper(MockRead("HTTP/1.1 101 Switching Protocols\r\n"));
1119}
1120
1121TEST_F(HttpNetworkTransactionTest, ConnectStatus201) {
1122 ConnectStatusHelper(MockRead("HTTP/1.1 201 Created\r\n"));
1123}
1124
1125TEST_F(HttpNetworkTransactionTest, ConnectStatus202) {
1126 ConnectStatusHelper(MockRead("HTTP/1.1 202 Accepted\r\n"));
1127}
1128
1129TEST_F(HttpNetworkTransactionTest, ConnectStatus203) {
1130 ConnectStatusHelper(
1131 MockRead("HTTP/1.1 203 Non-Authoritative Information\r\n"));
1132}
1133
1134TEST_F(HttpNetworkTransactionTest, ConnectStatus204) {
1135 ConnectStatusHelper(MockRead("HTTP/1.1 204 No Content\r\n"));
1136}
1137
1138TEST_F(HttpNetworkTransactionTest, ConnectStatus205) {
1139 ConnectStatusHelper(MockRead("HTTP/1.1 205 Reset Content\r\n"));
1140}
1141
1142TEST_F(HttpNetworkTransactionTest, ConnectStatus206) {
1143 ConnectStatusHelper(MockRead("HTTP/1.1 206 Partial Content\r\n"));
1144}
1145
1146TEST_F(HttpNetworkTransactionTest, ConnectStatus300) {
1147 ConnectStatusHelper(MockRead("HTTP/1.1 300 Multiple Choices\r\n"));
1148}
1149
1150TEST_F(HttpNetworkTransactionTest, ConnectStatus301) {
1151 ConnectStatusHelper(MockRead("HTTP/1.1 301 Moved Permanently\r\n"));
1152}
1153
1154TEST_F(HttpNetworkTransactionTest, ConnectStatus302) {
1155 ConnectStatusHelper(MockRead("HTTP/1.1 302 Found\r\n"));
1156}
1157
1158TEST_F(HttpNetworkTransactionTest, ConnectStatus303) {
1159 ConnectStatusHelper(MockRead("HTTP/1.1 303 See Other\r\n"));
1160}
1161
1162TEST_F(HttpNetworkTransactionTest, ConnectStatus304) {
1163 ConnectStatusHelper(MockRead("HTTP/1.1 304 Not Modified\r\n"));
1164}
1165
1166TEST_F(HttpNetworkTransactionTest, ConnectStatus305) {
1167 ConnectStatusHelper(MockRead("HTTP/1.1 305 Use Proxy\r\n"));
1168}
1169
1170TEST_F(HttpNetworkTransactionTest, ConnectStatus306) {
1171 ConnectStatusHelper(MockRead("HTTP/1.1 306\r\n"));
1172}
1173
1174TEST_F(HttpNetworkTransactionTest, ConnectStatus307) {
1175 ConnectStatusHelper(MockRead("HTTP/1.1 307 Temporary Redirect\r\n"));
1176}
1177
1178TEST_F(HttpNetworkTransactionTest, ConnectStatus400) {
1179 ConnectStatusHelper(MockRead("HTTP/1.1 400 Bad Request\r\n"));
1180}
1181
1182TEST_F(HttpNetworkTransactionTest, ConnectStatus401) {
1183 ConnectStatusHelper(MockRead("HTTP/1.1 401 Unauthorized\r\n"));
1184}
1185
1186TEST_F(HttpNetworkTransactionTest, ConnectStatus402) {
1187 ConnectStatusHelper(MockRead("HTTP/1.1 402 Payment Required\r\n"));
1188}
1189
1190TEST_F(HttpNetworkTransactionTest, ConnectStatus403) {
1191 ConnectStatusHelper(MockRead("HTTP/1.1 403 Forbidden\r\n"));
1192}
1193
1194TEST_F(HttpNetworkTransactionTest, ConnectStatus404) {
1195 ConnectStatusHelper(MockRead("HTTP/1.1 404 Not Found\r\n"));
1196}
1197
1198TEST_F(HttpNetworkTransactionTest, ConnectStatus405) {
1199 ConnectStatusHelper(MockRead("HTTP/1.1 405 Method Not Allowed\r\n"));
1200}
1201
1202TEST_F(HttpNetworkTransactionTest, ConnectStatus406) {
1203 ConnectStatusHelper(MockRead("HTTP/1.1 406 Not Acceptable\r\n"));
1204}
1205
1206TEST_F(HttpNetworkTransactionTest, ConnectStatus407) {
1207 ConnectStatusHelperWithExpectedStatus(
1208 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
1209 net::ERR_PROXY_AUTH_REQUESTED);
1210}
1211
1212TEST_F(HttpNetworkTransactionTest, ConnectStatus408) {
1213 ConnectStatusHelper(MockRead("HTTP/1.1 408 Request Timeout\r\n"));
1214}
1215
1216TEST_F(HttpNetworkTransactionTest, ConnectStatus409) {
1217 ConnectStatusHelper(MockRead("HTTP/1.1 409 Conflict\r\n"));
1218}
1219
1220TEST_F(HttpNetworkTransactionTest, ConnectStatus410) {
1221 ConnectStatusHelper(MockRead("HTTP/1.1 410 Gone\r\n"));
1222}
1223
1224TEST_F(HttpNetworkTransactionTest, ConnectStatus411) {
1225 ConnectStatusHelper(MockRead("HTTP/1.1 411 Length Required\r\n"));
1226}
1227
1228TEST_F(HttpNetworkTransactionTest, ConnectStatus412) {
1229 ConnectStatusHelper(MockRead("HTTP/1.1 412 Precondition Failed\r\n"));
1230}
1231
1232TEST_F(HttpNetworkTransactionTest, ConnectStatus413) {
1233 ConnectStatusHelper(MockRead("HTTP/1.1 413 Request Entity Too Large\r\n"));
1234}
1235
1236TEST_F(HttpNetworkTransactionTest, ConnectStatus414) {
1237 ConnectStatusHelper(MockRead("HTTP/1.1 414 Request-URI Too Long\r\n"));
1238}
1239
1240TEST_F(HttpNetworkTransactionTest, ConnectStatus415) {
1241 ConnectStatusHelper(MockRead("HTTP/1.1 415 Unsupported Media Type\r\n"));
1242}
1243
1244TEST_F(HttpNetworkTransactionTest, ConnectStatus416) {
1245 ConnectStatusHelper(
1246 MockRead("HTTP/1.1 416 Requested Range Not Satisfiable\r\n"));
1247}
1248
1249TEST_F(HttpNetworkTransactionTest, ConnectStatus417) {
1250 ConnectStatusHelper(MockRead("HTTP/1.1 417 Expectation Failed\r\n"));
1251}
1252
1253TEST_F(HttpNetworkTransactionTest, ConnectStatus500) {
1254 ConnectStatusHelper(MockRead("HTTP/1.1 500 Internal Server Error\r\n"));
1255}
1256
1257TEST_F(HttpNetworkTransactionTest, ConnectStatus501) {
1258 ConnectStatusHelper(MockRead("HTTP/1.1 501 Not Implemented\r\n"));
1259}
1260
1261TEST_F(HttpNetworkTransactionTest, ConnectStatus502) {
1262 ConnectStatusHelper(MockRead("HTTP/1.1 502 Bad Gateway\r\n"));
1263}
1264
1265TEST_F(HttpNetworkTransactionTest, ConnectStatus503) {
1266 ConnectStatusHelper(MockRead("HTTP/1.1 503 Service Unavailable\r\n"));
1267}
1268
1269TEST_F(HttpNetworkTransactionTest, ConnectStatus504) {
1270 ConnectStatusHelper(MockRead("HTTP/1.1 504 Gateway Timeout\r\n"));
1271}
1272
1273TEST_F(HttpNetworkTransactionTest, ConnectStatus505) {
1274 ConnectStatusHelper(MockRead("HTTP/1.1 505 HTTP Version Not Supported\r\n"));
1275}
1276
[email protected]038e9a32008-10-08 22:40:161277// Test the flow when both the proxy server AND origin server require
1278// authentication. Again, this uses basic auth for both since that is
1279// the simplest to mock.
1280TEST_F(HttpNetworkTransactionTest, BasicAuthProxyThenServer) {
[email protected]51fff29d2008-12-19 22:17:531281 scoped_ptr<net::ProxyService> proxy_service(
1282 CreateFixedProxyService("myproxy:70"));
[email protected]db8f44c2008-12-13 04:52:011283
[email protected]038e9a32008-10-08 22:40:161284 // Configure against proxy server "myproxy:70".
[email protected]af4876d2008-10-21 23:10:571285 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
[email protected]51fff29d2008-12-19 22:17:531286 CreateSession(proxy_service.get()),
[email protected]db8f44c2008-12-13 04:52:011287 &mock_socket_factory));
[email protected]038e9a32008-10-08 22:40:161288
1289 net::HttpRequestInfo request;
1290 request.method = "GET";
1291 request.url = GURL("http://www.google.com/");
1292 request.load_flags = 0;
1293
[email protected]f9ee6b52008-11-08 06:46:231294 MockWrite data_writes1[] = {
1295 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
1296 "Host: www.google.com\r\n"
1297 "Proxy-Connection: keep-alive\r\n\r\n"),
1298 };
1299
[email protected]038e9a32008-10-08 22:40:161300 MockRead data_reads1[] = {
1301 MockRead("HTTP/1.0 407 Unauthorized\r\n"),
1302 // Give a couple authenticate options (only the middle one is actually
1303 // supported).
[email protected]aaead502008-10-15 00:20:111304 MockRead("Proxy-Authenticate: Basic\r\n"), // Malformed
[email protected]038e9a32008-10-08 22:40:161305 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1306 MockRead("Proxy-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"),
1307 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1308 // Large content-length -- won't matter, as connection will be reset.
1309 MockRead("Content-Length: 10000\r\n\r\n"),
1310 MockRead(false, net::ERR_FAILED),
1311 };
1312
1313 // After calling trans->RestartWithAuth() the first time, this is the
1314 // request we should be issuing -- the final header line contains the
1315 // proxy's credentials.
1316 MockWrite data_writes2[] = {
1317 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
1318 "Host: www.google.com\r\n"
1319 "Proxy-Connection: keep-alive\r\n"
1320 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1321 };
1322
1323 // Now the proxy server lets the request pass through to origin server.
1324 // The origin server responds with a 401.
1325 MockRead data_reads2[] = {
1326 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
1327 // Note: We are using the same realm-name as the proxy server. This is
1328 // completely valid, as realms are unique across hosts.
1329 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1330 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1331 MockRead("Content-Length: 2000\r\n\r\n"),
[email protected]aaead502008-10-15 00:20:111332 MockRead(false, net::ERR_FAILED), // Won't be reached.
[email protected]038e9a32008-10-08 22:40:161333 };
1334
1335 // After calling trans->RestartWithAuth() the second time, we should send
1336 // the credentials for both the proxy and origin server.
1337 MockWrite data_writes3[] = {
1338 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
1339 "Host: www.google.com\r\n"
1340 "Proxy-Connection: keep-alive\r\n"
1341 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n"
1342 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"),
1343 };
1344
1345 // Lastly we get the desired content.
1346 MockRead data_reads3[] = {
1347 MockRead("HTTP/1.0 200 OK\r\n"),
1348 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1349 MockRead("Content-Length: 100\r\n\r\n"),
1350 MockRead(false, net::OK),
1351 };
1352
1353 MockSocket data1;
1354 data1.reads = data_reads1;
[email protected]f9ee6b52008-11-08 06:46:231355 data1.writes = data_writes1;
[email protected]038e9a32008-10-08 22:40:161356 MockSocket data2;
1357 data2.reads = data_reads2;
1358 data2.writes = data_writes2;
1359 MockSocket data3;
1360 data3.reads = data_reads3;
1361 data3.writes = data_writes3;
1362 mock_sockets[0] = &data1;
1363 mock_sockets[1] = &data2;
1364 mock_sockets[2] = &data3;
1365 mock_sockets[3] = NULL;
1366
1367 TestCompletionCallback callback1;
1368
1369 int rv = trans->Start(&request, &callback1);
1370 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1371
1372 rv = callback1.WaitForResult();
1373 EXPECT_EQ(net::OK, rv);
1374
1375 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1376 EXPECT_FALSE(response == NULL);
1377
1378 // The password prompt info should have been set in response->auth_challenge.
1379 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1380
1381 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host);
1382 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1383 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1384
1385 TestCompletionCallback callback2;
1386
1387 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
1388 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1389
1390 rv = callback2.WaitForResult();
1391 EXPECT_EQ(net::OK, rv);
1392
1393 response = trans->GetResponseInfo();
1394 EXPECT_FALSE(response == NULL);
1395 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1396
1397 // TODO(eroman): this should really include the effective port (80)
1398 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
1399 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1400 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1401
1402 TestCompletionCallback callback3;
1403
1404 rv = trans->RestartWithAuth(L"foo2", L"bar2", &callback3);
1405 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1406
1407 rv = callback3.WaitForResult();
1408 EXPECT_EQ(net::OK, rv);
1409
1410 response = trans->GetResponseInfo();
1411 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1412 EXPECT_EQ(100, response->headers->GetContentLength());
[email protected]038e9a32008-10-08 22:40:161413}
[email protected]4ddaf2502008-10-23 18:26:191414
1415// Test reading a server response which has only headers, and no body.
1416// After some maximum number of bytes is consumed, the transaction should
1417// fail with ERR_RESPONSE_HEADERS_TOO_BIG.
1418TEST_F(HttpNetworkTransactionTest, LargeHeadersNoBody) {
[email protected]db8f44c2008-12-13 04:52:011419 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
[email protected]4ddaf2502008-10-23 18:26:191420 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
[email protected]db8f44c2008-12-13 04:52:011421 CreateSession(proxy_service.get()), &mock_socket_factory));
[email protected]4ddaf2502008-10-23 18:26:191422
1423 net::HttpRequestInfo request;
1424 request.method = "GET";
1425 request.url = GURL("http://www.google.com/");
1426 request.load_flags = 0;
1427
1428 // Respond with 50 kb of headers (we should fail after 32 kb).
[email protected]15a5ccf82008-10-23 19:57:431429 std::string large_headers_string;
1430 FillLargeHeadersString(&large_headers_string, 50 * 1024);
[email protected]4ddaf2502008-10-23 18:26:191431
1432 MockRead data_reads[] = {
1433 MockRead("HTTP/1.0 200 OK\r\n"),
[email protected]15a5ccf82008-10-23 19:57:431434 MockRead(true, large_headers_string.data(), large_headers_string.size()),
[email protected]4ddaf2502008-10-23 18:26:191435 MockRead("\r\nBODY"),
1436 MockRead(false, net::OK),
1437 };
1438 MockSocket data;
1439 data.reads = data_reads;
1440 mock_sockets[0] = &data;
1441 mock_sockets[1] = NULL;
1442
1443 TestCompletionCallback callback;
1444
1445 int rv = trans->Start(&request, &callback);
1446 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1447
1448 rv = callback.WaitForResult();
1449 EXPECT_EQ(net::ERR_RESPONSE_HEADERS_TOO_BIG, rv);
1450
1451 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1452 EXPECT_TRUE(response == NULL);
1453}
[email protected]f4e426b2008-11-05 00:24:491454
1455// Make sure that we don't try to reuse a TCPClientSocket when failing to
1456// establish tunnel.
1457// http://code.google.com/p/chromium/issues/detail?id=3772
1458TEST_F(HttpNetworkTransactionTest, DontRecycleTCPSocketForSSLTunnel) {
1459 // Configure against proxy server "myproxy:70".
[email protected]51fff29d2008-12-19 22:17:531460 scoped_ptr<net::ProxyService> proxy_service(
1461 CreateFixedProxyService("myproxy:70"));
[email protected]db8f44c2008-12-13 04:52:011462
[email protected]f4e426b2008-11-05 00:24:491463 scoped_refptr<net::HttpNetworkSession> session(
[email protected]51fff29d2008-12-19 22:17:531464 CreateSession(proxy_service.get()));
[email protected]f4e426b2008-11-05 00:24:491465
1466 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1467 session.get(), &mock_socket_factory));
1468
1469 net::HttpRequestInfo request;
1470 request.method = "GET";
1471 request.url = GURL("https://www.google.com/");
1472 request.load_flags = 0;
1473
1474 // Since we have proxy, should try to establish tunnel.
1475 MockWrite data_writes1[] = {
1476 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
1477 "Host: www.google.com\r\n\r\n"),
1478 };
1479
[email protected]77848d12008-11-14 00:00:221480 // The proxy responds to the connect with a 404, using a persistent
[email protected]f4e426b2008-11-05 00:24:491481 // connection. Usually a proxy would return 501 (not implemented),
1482 // or 200 (tunnel established).
1483 MockRead data_reads1[] = {
1484 MockRead("HTTP/1.1 404 Not Found\r\n"),
1485 MockRead("Content-Length: 10\r\n\r\n"),
[email protected]77848d12008-11-14 00:00:221486 MockRead(false, net::ERR_UNEXPECTED), // Should not be reached.
[email protected]f4e426b2008-11-05 00:24:491487 };
1488
1489 MockSocket data1;
1490 data1.writes = data_writes1;
1491 data1.reads = data_reads1;
1492 mock_sockets[0] = &data1;
1493 mock_sockets[1] = NULL;
1494
1495 TestCompletionCallback callback1;
1496
1497 int rv = trans->Start(&request, &callback1);
1498 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1499
1500 rv = callback1.WaitForResult();
[email protected]c744cf22009-02-27 07:28:081501 EXPECT_EQ(net::ERR_TUNNEL_CONNECTION_FAILED, rv);
[email protected]f4e426b2008-11-05 00:24:491502
1503 const net::HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]c744cf22009-02-27 07:28:081504 EXPECT_TRUE(response == NULL);
[email protected]f4e426b2008-11-05 00:24:491505
1506 // We now check to make sure the TCPClientSocket was not added back to
1507 // the pool.
1508 EXPECT_EQ(0, session->connection_pool()->idle_socket_count());
1509 trans.reset();
1510 // Make sure that the socket didn't get recycled after calling the destructor.
1511 EXPECT_EQ(0, session->connection_pool()->idle_socket_count());
1512}
[email protected]372d34a2008-11-05 21:30:511513
1514TEST_F(HttpNetworkTransactionTest, ResendRequestOnWriteBodyError) {
1515 net::HttpRequestInfo request[2];
1516 // Transaction 1: a GET request that succeeds. The socket is recycled
1517 // after use.
1518 request[0].method = "GET";
1519 request[0].url = GURL("http://www.google.com/");
1520 request[0].load_flags = 0;
1521 // Transaction 2: a POST request. Reuses the socket kept alive from
1522 // transaction 1. The first attempts fails when writing the POST data.
1523 // This causes the transaction to retry with a new socket. The second
1524 // attempt succeeds.
1525 request[1].method = "POST";
1526 request[1].url = GURL("http://www.google.com/login.cgi");
1527 request[1].upload_data = new net::UploadData;
1528 request[1].upload_data->AppendBytes("foo", 3);
1529 request[1].load_flags = 0;
1530
[email protected]db8f44c2008-12-13 04:52:011531 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
1532 scoped_refptr<net::HttpNetworkSession> session =
1533 CreateSession(proxy_service.get());
[email protected]372d34a2008-11-05 21:30:511534
1535 // The first socket is used for transaction 1 and the first attempt of
1536 // transaction 2.
1537
1538 // The response of transaction 1.
1539 MockRead data_reads1[] = {
1540 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\n"),
1541 MockRead("hello world"),
1542 MockRead(false, net::OK),
1543 };
1544 // The mock write results of transaction 1 and the first attempt of
1545 // transaction 2.
1546 MockWrite data_writes1[] = {
1547 MockWrite(false, 64), // GET
1548 MockWrite(false, 93), // POST
1549 MockWrite(false, net::ERR_CONNECTION_ABORTED), // POST data
1550 };
1551 MockSocket data1;
1552 data1.reads = data_reads1;
1553 data1.writes = data_writes1;
1554
1555 // The second socket is used for the second attempt of transaction 2.
1556
1557 // The response of transaction 2.
1558 MockRead data_reads2[] = {
1559 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 7\r\n\r\n"),
1560 MockRead("welcome"),
1561 MockRead(false, net::OK),
1562 };
1563 // The mock write results of the second attempt of transaction 2.
1564 MockWrite data_writes2[] = {
1565 MockWrite(false, 93), // POST
1566 MockWrite(false, 3), // POST data
1567 };
1568 MockSocket data2;
1569 data2.reads = data_reads2;
1570 data2.writes = data_writes2;
1571
1572 mock_sockets[0] = &data1;
1573 mock_sockets[1] = &data2;
1574 mock_sockets[2] = NULL;
1575
1576 const char* kExpectedResponseData[] = {
1577 "hello world", "welcome"
1578 };
1579
1580 for (int i = 0; i < 2; ++i) {
1581 scoped_ptr<net::HttpTransaction> trans(
1582 new net::HttpNetworkTransaction(session, &mock_socket_factory));
1583
1584 TestCompletionCallback callback;
1585
1586 int rv = trans->Start(&request[i], &callback);
1587 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1588
1589 rv = callback.WaitForResult();
1590 EXPECT_EQ(net::OK, rv);
1591
1592 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1593 EXPECT_TRUE(response != NULL);
1594
1595 EXPECT_TRUE(response->headers != NULL);
1596 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
1597
1598 std::string response_data;
1599 rv = ReadTransaction(trans.get(), &response_data);
1600 EXPECT_EQ(net::OK, rv);
1601 EXPECT_EQ(kExpectedResponseData[i], response_data);
1602 }
1603}
[email protected]f9ee6b52008-11-08 06:46:231604
1605// Test the request-challenge-retry sequence for basic auth when there is
1606// an identity in the URL. The request should be sent as normal, but when
1607// it fails the identity from the URL is used to answer the challenge.
1608TEST_F(HttpNetworkTransactionTest, AuthIdentityInUrl) {
[email protected]db8f44c2008-12-13 04:52:011609 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
[email protected]f9ee6b52008-11-08 06:46:231610 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
[email protected]db8f44c2008-12-13 04:52:011611 CreateSession(proxy_service.get()), &mock_socket_factory));
[email protected]f9ee6b52008-11-08 06:46:231612
1613 net::HttpRequestInfo request;
1614 request.method = "GET";
1615 // Note: the URL has a username:password in it.
1616 request.url = GURL("http://foo:[email protected]/");
1617 request.load_flags = 0;
1618
1619 MockWrite data_writes1[] = {
1620 MockWrite("GET / HTTP/1.1\r\n"
1621 "Host: www.google.com\r\n"
1622 "Connection: keep-alive\r\n\r\n"),
1623 };
1624
1625 MockRead data_reads1[] = {
1626 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
1627 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1628 MockRead("Content-Length: 10\r\n\r\n"),
1629 MockRead(false, net::ERR_FAILED),
1630 };
1631
1632 // After the challenge above, the transaction will be restarted using the
1633 // identity from the url (foo, bar) to answer the challenge.
1634 MockWrite data_writes2[] = {
1635 MockWrite("GET / HTTP/1.1\r\n"
1636 "Host: www.google.com\r\n"
1637 "Connection: keep-alive\r\n"
1638 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1639 };
1640
1641 MockRead data_reads2[] = {
1642 MockRead("HTTP/1.0 200 OK\r\n"),
1643 MockRead("Content-Length: 100\r\n\r\n"),
1644 MockRead(false, net::OK),
1645 };
1646
1647 MockSocket data1;
1648 data1.reads = data_reads1;
1649 data1.writes = data_writes1;
1650 MockSocket data2;
1651 data2.reads = data_reads2;
1652 data2.writes = data_writes2;
1653 mock_sockets[0] = &data1;
1654 mock_sockets[1] = &data2;
1655 mock_sockets[2] = NULL;
1656
1657 TestCompletionCallback callback1;
1658
1659 int rv = trans->Start(&request, &callback1);
1660 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1661
1662 rv = callback1.WaitForResult();
1663 EXPECT_EQ(net::OK, rv);
1664
1665 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1666 EXPECT_FALSE(response == NULL);
1667
1668 // There is no challenge info, since the identity in URL worked.
1669 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1670
1671 EXPECT_EQ(100, response->headers->GetContentLength());
1672
1673 // Empty the current queue.
1674 MessageLoop::current()->RunAllPending();
1675}
1676
1677// Test that previously tried username/passwords for a realm get re-used.
1678TEST_F(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
[email protected]db8f44c2008-12-13 04:52:011679 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
1680 scoped_refptr<net::HttpNetworkSession> session =
1681 CreateSession(proxy_service.get());
[email protected]f9ee6b52008-11-08 06:46:231682
1683 // Transaction 1: authenticate (foo, bar) on MyRealm1
1684 {
1685 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1686 session, &mock_socket_factory));
1687
1688 net::HttpRequestInfo request;
1689 request.method = "GET";
1690 request.url = GURL("http://www.google.com/x/y/z");
1691 request.load_flags = 0;
1692
1693 MockWrite data_writes1[] = {
1694 MockWrite("GET /x/y/z HTTP/1.1\r\n"
1695 "Host: www.google.com\r\n"
1696 "Connection: keep-alive\r\n\r\n"),
1697 };
1698
1699 MockRead data_reads1[] = {
1700 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
1701 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1702 MockRead("Content-Length: 10000\r\n\r\n"),
1703 MockRead(false, net::ERR_FAILED),
1704 };
1705
1706 // Resend with authorization (username=foo, password=bar)
1707 MockWrite data_writes2[] = {
1708 MockWrite("GET /x/y/z HTTP/1.1\r\n"
1709 "Host: www.google.com\r\n"
1710 "Connection: keep-alive\r\n"
1711 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1712 };
1713
1714 // Sever accepts the authorization.
1715 MockRead data_reads2[] = {
1716 MockRead("HTTP/1.0 200 OK\r\n"),
1717 MockRead("Content-Length: 100\r\n\r\n"),
1718 MockRead(false, net::OK),
1719 };
1720
1721 MockSocket data1;
1722 data1.reads = data_reads1;
1723 data1.writes = data_writes1;
1724 MockSocket data2;
1725 data2.reads = data_reads2;
1726 data2.writes = data_writes2;
1727 mock_sockets_index = 0;
1728 mock_sockets[0] = &data1;
1729 mock_sockets[1] = &data2;
1730 mock_sockets[2] = NULL;
1731
1732 TestCompletionCallback callback1;
1733
1734 int rv = trans->Start(&request, &callback1);
1735 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1736
1737 rv = callback1.WaitForResult();
1738 EXPECT_EQ(net::OK, rv);
1739
1740 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1741 EXPECT_FALSE(response == NULL);
1742
1743 // The password prompt info should have been set in
1744 // response->auth_challenge.
1745 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1746
1747 // TODO(eroman): this should really include the effective port (80)
1748 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
1749 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1750 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1751
1752 TestCompletionCallback callback2;
1753
1754 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
1755 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1756
1757 rv = callback2.WaitForResult();
1758 EXPECT_EQ(net::OK, rv);
1759
1760 response = trans->GetResponseInfo();
1761 EXPECT_FALSE(response == NULL);
1762 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1763 EXPECT_EQ(100, response->headers->GetContentLength());
1764 }
1765
1766 // ------------------------------------------------------------------------
1767
1768 // Transaction 2: authenticate (foo2, bar2) on MyRealm2
1769 {
1770 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1771 session, &mock_socket_factory));
1772
1773 net::HttpRequestInfo request;
1774 request.method = "GET";
1775 // Note that Transaction 1 was at /x/y/z, so this is in the same
1776 // protection space as MyRealm1.
1777 request.url = GURL("http://www.google.com/x/y/a/b");
1778 request.load_flags = 0;
1779
1780 MockWrite data_writes1[] = {
1781 MockWrite("GET /x/y/a/b HTTP/1.1\r\n"
1782 "Host: www.google.com\r\n"
1783 "Connection: keep-alive\r\n"
1784 // Send preemptive authorization for MyRealm1
1785 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1786 };
1787
1788 // The server didn't like the preemptive authorization, and
1789 // challenges us for a different realm (MyRealm2).
1790 MockRead data_reads1[] = {
1791 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
1792 MockRead("WWW-Authenticate: Basic realm=\"MyRealm2\"\r\n"),
1793 MockRead("Content-Length: 10000\r\n\r\n"),
1794 MockRead(false, net::ERR_FAILED),
1795 };
1796
1797 // Resend with authorization for MyRealm2 (username=foo2, password=bar2)
1798 MockWrite data_writes2[] = {
1799 MockWrite("GET /x/y/a/b HTTP/1.1\r\n"
1800 "Host: www.google.com\r\n"
1801 "Connection: keep-alive\r\n"
1802 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"),
1803 };
1804
1805 // Sever accepts the authorization.
1806 MockRead data_reads2[] = {
1807 MockRead("HTTP/1.0 200 OK\r\n"),
1808 MockRead("Content-Length: 100\r\n\r\n"),
1809 MockRead(false, net::OK),
1810 };
1811
1812 MockSocket data1;
1813 data1.reads = data_reads1;
1814 data1.writes = data_writes1;
1815 MockSocket data2;
1816 data2.reads = data_reads2;
1817 data2.writes = data_writes2;
1818 mock_sockets_index = 0;
1819 mock_sockets[0] = &data1;
1820 mock_sockets[1] = &data2;
1821 mock_sockets[2] = NULL;
1822
1823 TestCompletionCallback callback1;
1824
1825 int rv = trans->Start(&request, &callback1);
1826 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1827
1828 rv = callback1.WaitForResult();
1829 EXPECT_EQ(net::OK, rv);
1830
1831 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1832 EXPECT_FALSE(response == NULL);
1833
1834 // The password prompt info should have been set in
1835 // response->auth_challenge.
1836 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1837
1838 // TODO(eroman): this should really include the effective port (80)
1839 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
1840 EXPECT_EQ(L"MyRealm2", response->auth_challenge->realm);
1841 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1842
1843 TestCompletionCallback callback2;
1844
1845 rv = trans->RestartWithAuth(L"foo2", L"bar2", &callback2);
1846 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1847
1848 rv = callback2.WaitForResult();
1849 EXPECT_EQ(net::OK, rv);
1850
1851 response = trans->GetResponseInfo();
1852 EXPECT_FALSE(response == NULL);
1853 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1854 EXPECT_EQ(100, response->headers->GetContentLength());
1855 }
1856
1857 // ------------------------------------------------------------------------
1858
1859 // Transaction 3: Resend a request in MyRealm's protection space --
1860 // succeed with preemptive authorization.
1861 {
1862 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1863 session, &mock_socket_factory));
1864
1865 net::HttpRequestInfo request;
1866 request.method = "GET";
1867 request.url = GURL("http://www.google.com/x/y/z2");
1868 request.load_flags = 0;
1869
1870 MockWrite data_writes1[] = {
1871 MockWrite("GET /x/y/z2 HTTP/1.1\r\n"
1872 "Host: www.google.com\r\n"
1873 "Connection: keep-alive\r\n"
1874 // The authorization for MyRealm1 gets sent preemptively
1875 // (since the url is in the same protection space)
1876 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1877 };
1878
1879 // Sever accepts the preemptive authorization
1880 MockRead data_reads1[] = {
1881 MockRead("HTTP/1.0 200 OK\r\n"),
1882 MockRead("Content-Length: 100\r\n\r\n"),
1883 MockRead(false, net::OK),
1884 };
1885
1886 MockSocket data1;
1887 data1.reads = data_reads1;
1888 data1.writes = data_writes1;
1889 mock_sockets_index = 0;
1890 mock_sockets[0] = &data1;
1891 mock_sockets[1] = NULL;
1892
1893 TestCompletionCallback callback1;
1894
1895 int rv = trans->Start(&request, &callback1);
1896 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1897
1898 rv = callback1.WaitForResult();
1899 EXPECT_EQ(net::OK, rv);
1900
1901 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1902 EXPECT_FALSE(response == NULL);
1903
1904 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1905 EXPECT_EQ(100, response->headers->GetContentLength());
1906 }
1907
1908 // ------------------------------------------------------------------------
1909
1910 // Transaction 4: request another URL in MyRealm (however the
1911 // url is not known to belong to the protection space, so no pre-auth).
1912 {
1913 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1914 session, &mock_socket_factory));
1915
1916 net::HttpRequestInfo request;
1917 request.method = "GET";
1918 request.url = GURL("http://www.google.com/x/1");
1919 request.load_flags = 0;
1920
1921 MockWrite data_writes1[] = {
1922 MockWrite("GET /x/1 HTTP/1.1\r\n"
1923 "Host: www.google.com\r\n"
1924 "Connection: keep-alive\r\n\r\n"),
1925 };
1926
1927 MockRead data_reads1[] = {
1928 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
1929 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1930 MockRead("Content-Length: 10000\r\n\r\n"),
1931 MockRead(false, net::ERR_FAILED),
1932 };
1933
1934 // Resend with authorization from MyRealm's cache.
1935 MockWrite data_writes2[] = {
1936 MockWrite("GET /x/1 HTTP/1.1\r\n"
1937 "Host: www.google.com\r\n"
1938 "Connection: keep-alive\r\n"
1939 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1940 };
1941
1942 // Sever accepts the authorization.
1943 MockRead data_reads2[] = {
1944 MockRead("HTTP/1.0 200 OK\r\n"),
1945 MockRead("Content-Length: 100\r\n\r\n"),
1946 MockRead(false, net::OK),
1947 };
1948
1949 MockSocket data1;
1950 data1.reads = data_reads1;
1951 data1.writes = data_writes1;
1952 MockSocket data2;
1953 data2.reads = data_reads2;
1954 data2.writes = data_writes2;
1955 mock_sockets_index = 0;
1956 mock_sockets[0] = &data1;
1957 mock_sockets[1] = &data2;
1958 mock_sockets[2] = NULL;
1959
1960 TestCompletionCallback callback1;
1961
1962 int rv = trans->Start(&request, &callback1);
1963 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1964
1965 rv = callback1.WaitForResult();
1966 EXPECT_EQ(net::OK, rv);
1967
1968 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1969 EXPECT_FALSE(response == NULL);
1970 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1971 EXPECT_EQ(100, response->headers->GetContentLength());
1972 }
1973
1974 // ------------------------------------------------------------------------
1975
1976 // Transaction 5: request a URL in MyRealm, but the server rejects the
1977 // cached identity. Should invalidate and re-prompt.
1978 {
1979 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1980 session, &mock_socket_factory));
1981
1982 net::HttpRequestInfo request;
1983 request.method = "GET";
1984 request.url = GURL("http://www.google.com/p/q/t");
1985 request.load_flags = 0;
1986
1987 MockWrite data_writes1[] = {
1988 MockWrite("GET /p/q/t HTTP/1.1\r\n"
1989 "Host: www.google.com\r\n"
1990 "Connection: keep-alive\r\n\r\n"),
1991 };
1992
1993 MockRead data_reads1[] = {
1994 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
1995 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1996 MockRead("Content-Length: 10000\r\n\r\n"),
1997 MockRead(false, net::ERR_FAILED),
1998 };
1999
2000 // Resend with authorization from cache for MyRealm.
2001 MockWrite data_writes2[] = {
2002 MockWrite("GET /p/q/t HTTP/1.1\r\n"
2003 "Host: www.google.com\r\n"
2004 "Connection: keep-alive\r\n"
2005 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
2006 };
2007
2008 // Sever rejects the authorization.
2009 MockRead data_reads2[] = {
2010 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
2011 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
2012 MockRead("Content-Length: 10000\r\n\r\n"),
2013 MockRead(false, net::ERR_FAILED),
2014 };
2015
2016 // At this point we should prompt for new credentials for MyRealm.
2017 // Restart with username=foo3, password=foo4.
2018 MockWrite data_writes3[] = {
2019 MockWrite("GET /p/q/t HTTP/1.1\r\n"
2020 "Host: www.google.com\r\n"
2021 "Connection: keep-alive\r\n"
2022 "Authorization: Basic Zm9vMzpiYXIz\r\n\r\n"),
2023 };
2024
2025 // Sever accepts the authorization.
2026 MockRead data_reads3[] = {
2027 MockRead("HTTP/1.0 200 OK\r\n"),
2028 MockRead("Content-Length: 100\r\n\r\n"),
2029 MockRead(false, net::OK),
2030 };
2031
2032 MockSocket data1;
2033 data1.reads = data_reads1;
2034 data1.writes = data_writes1;
2035 MockSocket data2;
2036 data2.reads = data_reads2;
2037 data2.writes = data_writes2;
2038 MockSocket data3;
2039 data3.reads = data_reads3;
2040 data3.writes = data_writes3;
2041 mock_sockets_index = 0;
2042 mock_sockets[0] = &data1;
2043 mock_sockets[1] = &data2;
2044 mock_sockets[2] = &data3;
2045 mock_sockets[3] = NULL;
2046
2047 TestCompletionCallback callback1;
2048
2049 int rv = trans->Start(&request, &callback1);
2050 EXPECT_EQ(net::ERR_IO_PENDING, rv);
2051
2052 rv = callback1.WaitForResult();
2053 EXPECT_EQ(net::OK, rv);
2054
2055 const net::HttpResponseInfo* response = trans->GetResponseInfo();
2056 EXPECT_FALSE(response == NULL);
2057
2058 // The password prompt info should have been set in
2059 // response->auth_challenge.
2060 EXPECT_FALSE(response->auth_challenge.get() == NULL);
2061
2062 // TODO(eroman): this should really include the effective port (80)
2063 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
2064 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
2065 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
2066
2067 TestCompletionCallback callback2;
2068
2069 rv = trans->RestartWithAuth(L"foo3", L"bar3", &callback2);
2070 EXPECT_EQ(net::ERR_IO_PENDING, rv);
2071
2072 rv = callback2.WaitForResult();
2073 EXPECT_EQ(net::OK, rv);
2074
2075 response = trans->GetResponseInfo();
2076 EXPECT_FALSE(response == NULL);
2077 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2078 EXPECT_EQ(100, response->headers->GetContentLength());
2079 }
2080}