blob: 5ceeb39553d927958e45f074ed790d3d2903873d [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]038e9a32008-10-08 22:40:161063// Test the flow when both the proxy server AND origin server require
1064// authentication. Again, this uses basic auth for both since that is
1065// the simplest to mock.
1066TEST_F(HttpNetworkTransactionTest, BasicAuthProxyThenServer) {
[email protected]51fff29d2008-12-19 22:17:531067 scoped_ptr<net::ProxyService> proxy_service(
1068 CreateFixedProxyService("myproxy:70"));
[email protected]db8f44c2008-12-13 04:52:011069
[email protected]038e9a32008-10-08 22:40:161070 // Configure against proxy server "myproxy:70".
[email protected]af4876d2008-10-21 23:10:571071 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
[email protected]51fff29d2008-12-19 22:17:531072 CreateSession(proxy_service.get()),
[email protected]db8f44c2008-12-13 04:52:011073 &mock_socket_factory));
[email protected]038e9a32008-10-08 22:40:161074
1075 net::HttpRequestInfo request;
1076 request.method = "GET";
1077 request.url = GURL("http://www.google.com/");
1078 request.load_flags = 0;
1079
[email protected]f9ee6b52008-11-08 06:46:231080 MockWrite data_writes1[] = {
1081 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
1082 "Host: www.google.com\r\n"
1083 "Proxy-Connection: keep-alive\r\n\r\n"),
1084 };
1085
[email protected]038e9a32008-10-08 22:40:161086 MockRead data_reads1[] = {
1087 MockRead("HTTP/1.0 407 Unauthorized\r\n"),
1088 // Give a couple authenticate options (only the middle one is actually
1089 // supported).
[email protected]aaead502008-10-15 00:20:111090 MockRead("Proxy-Authenticate: Basic\r\n"), // Malformed
[email protected]038e9a32008-10-08 22:40:161091 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1092 MockRead("Proxy-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"),
1093 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1094 // Large content-length -- won't matter, as connection will be reset.
1095 MockRead("Content-Length: 10000\r\n\r\n"),
1096 MockRead(false, net::ERR_FAILED),
1097 };
1098
1099 // After calling trans->RestartWithAuth() the first time, this is the
1100 // request we should be issuing -- the final header line contains the
1101 // proxy's credentials.
1102 MockWrite data_writes2[] = {
1103 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
1104 "Host: www.google.com\r\n"
1105 "Proxy-Connection: keep-alive\r\n"
1106 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1107 };
1108
1109 // Now the proxy server lets the request pass through to origin server.
1110 // The origin server responds with a 401.
1111 MockRead data_reads2[] = {
1112 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
1113 // Note: We are using the same realm-name as the proxy server. This is
1114 // completely valid, as realms are unique across hosts.
1115 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1116 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1117 MockRead("Content-Length: 2000\r\n\r\n"),
[email protected]aaead502008-10-15 00:20:111118 MockRead(false, net::ERR_FAILED), // Won't be reached.
[email protected]038e9a32008-10-08 22:40:161119 };
1120
1121 // After calling trans->RestartWithAuth() the second time, we should send
1122 // the credentials for both the proxy and origin server.
1123 MockWrite data_writes3[] = {
1124 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
1125 "Host: www.google.com\r\n"
1126 "Proxy-Connection: keep-alive\r\n"
1127 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n"
1128 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"),
1129 };
1130
1131 // Lastly we get the desired content.
1132 MockRead data_reads3[] = {
1133 MockRead("HTTP/1.0 200 OK\r\n"),
1134 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1135 MockRead("Content-Length: 100\r\n\r\n"),
1136 MockRead(false, net::OK),
1137 };
1138
1139 MockSocket data1;
1140 data1.reads = data_reads1;
[email protected]f9ee6b52008-11-08 06:46:231141 data1.writes = data_writes1;
[email protected]038e9a32008-10-08 22:40:161142 MockSocket data2;
1143 data2.reads = data_reads2;
1144 data2.writes = data_writes2;
1145 MockSocket data3;
1146 data3.reads = data_reads3;
1147 data3.writes = data_writes3;
1148 mock_sockets[0] = &data1;
1149 mock_sockets[1] = &data2;
1150 mock_sockets[2] = &data3;
1151 mock_sockets[3] = NULL;
1152
1153 TestCompletionCallback callback1;
1154
1155 int rv = trans->Start(&request, &callback1);
1156 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1157
1158 rv = callback1.WaitForResult();
1159 EXPECT_EQ(net::OK, rv);
1160
1161 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1162 EXPECT_FALSE(response == NULL);
1163
1164 // The password prompt info should have been set in response->auth_challenge.
1165 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1166
1167 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host);
1168 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1169 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1170
1171 TestCompletionCallback callback2;
1172
1173 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
1174 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1175
1176 rv = callback2.WaitForResult();
1177 EXPECT_EQ(net::OK, rv);
1178
1179 response = trans->GetResponseInfo();
1180 EXPECT_FALSE(response == NULL);
1181 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1182
1183 // TODO(eroman): this should really include the effective port (80)
1184 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
1185 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1186 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1187
1188 TestCompletionCallback callback3;
1189
1190 rv = trans->RestartWithAuth(L"foo2", L"bar2", &callback3);
1191 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1192
1193 rv = callback3.WaitForResult();
1194 EXPECT_EQ(net::OK, rv);
1195
1196 response = trans->GetResponseInfo();
1197 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1198 EXPECT_EQ(100, response->headers->GetContentLength());
[email protected]038e9a32008-10-08 22:40:161199}
[email protected]4ddaf2502008-10-23 18:26:191200
1201// Test reading a server response which has only headers, and no body.
1202// After some maximum number of bytes is consumed, the transaction should
1203// fail with ERR_RESPONSE_HEADERS_TOO_BIG.
1204TEST_F(HttpNetworkTransactionTest, LargeHeadersNoBody) {
[email protected]db8f44c2008-12-13 04:52:011205 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
[email protected]4ddaf2502008-10-23 18:26:191206 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
[email protected]db8f44c2008-12-13 04:52:011207 CreateSession(proxy_service.get()), &mock_socket_factory));
[email protected]4ddaf2502008-10-23 18:26:191208
1209 net::HttpRequestInfo request;
1210 request.method = "GET";
1211 request.url = GURL("http://www.google.com/");
1212 request.load_flags = 0;
1213
1214 // Respond with 50 kb of headers (we should fail after 32 kb).
[email protected]15a5ccf82008-10-23 19:57:431215 std::string large_headers_string;
1216 FillLargeHeadersString(&large_headers_string, 50 * 1024);
[email protected]4ddaf2502008-10-23 18:26:191217
1218 MockRead data_reads[] = {
1219 MockRead("HTTP/1.0 200 OK\r\n"),
[email protected]15a5ccf82008-10-23 19:57:431220 MockRead(true, large_headers_string.data(), large_headers_string.size()),
[email protected]4ddaf2502008-10-23 18:26:191221 MockRead("\r\nBODY"),
1222 MockRead(false, net::OK),
1223 };
1224 MockSocket data;
1225 data.reads = data_reads;
1226 mock_sockets[0] = &data;
1227 mock_sockets[1] = NULL;
1228
1229 TestCompletionCallback callback;
1230
1231 int rv = trans->Start(&request, &callback);
1232 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1233
1234 rv = callback.WaitForResult();
1235 EXPECT_EQ(net::ERR_RESPONSE_HEADERS_TOO_BIG, rv);
1236
1237 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1238 EXPECT_TRUE(response == NULL);
1239}
[email protected]f4e426b2008-11-05 00:24:491240
1241// Make sure that we don't try to reuse a TCPClientSocket when failing to
1242// establish tunnel.
1243// http://code.google.com/p/chromium/issues/detail?id=3772
1244TEST_F(HttpNetworkTransactionTest, DontRecycleTCPSocketForSSLTunnel) {
1245 // Configure against proxy server "myproxy:70".
[email protected]51fff29d2008-12-19 22:17:531246 scoped_ptr<net::ProxyService> proxy_service(
1247 CreateFixedProxyService("myproxy:70"));
[email protected]db8f44c2008-12-13 04:52:011248
[email protected]f4e426b2008-11-05 00:24:491249 scoped_refptr<net::HttpNetworkSession> session(
[email protected]51fff29d2008-12-19 22:17:531250 CreateSession(proxy_service.get()));
[email protected]f4e426b2008-11-05 00:24:491251
1252 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1253 session.get(), &mock_socket_factory));
1254
1255 net::HttpRequestInfo request;
1256 request.method = "GET";
1257 request.url = GURL("https://www.google.com/");
1258 request.load_flags = 0;
1259
1260 // Since we have proxy, should try to establish tunnel.
1261 MockWrite data_writes1[] = {
1262 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
1263 "Host: www.google.com\r\n\r\n"),
1264 };
1265
[email protected]77848d12008-11-14 00:00:221266 // The proxy responds to the connect with a 404, using a persistent
[email protected]f4e426b2008-11-05 00:24:491267 // connection. Usually a proxy would return 501 (not implemented),
1268 // or 200 (tunnel established).
1269 MockRead data_reads1[] = {
1270 MockRead("HTTP/1.1 404 Not Found\r\n"),
1271 MockRead("Content-Length: 10\r\n\r\n"),
1272 MockRead("0123456789"),
[email protected]77848d12008-11-14 00:00:221273 MockRead(false, net::ERR_UNEXPECTED), // Should not be reached.
[email protected]f4e426b2008-11-05 00:24:491274 };
1275
1276 MockSocket data1;
1277 data1.writes = data_writes1;
1278 data1.reads = data_reads1;
1279 mock_sockets[0] = &data1;
1280 mock_sockets[1] = NULL;
1281
1282 TestCompletionCallback callback1;
1283
1284 int rv = trans->Start(&request, &callback1);
1285 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1286
1287 rv = callback1.WaitForResult();
1288 EXPECT_EQ(net::OK, rv);
1289
1290 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1291 EXPECT_FALSE(response == NULL);
1292
1293 EXPECT_TRUE(response->headers->IsKeepAlive());
1294 EXPECT_EQ(404, response->headers->response_code());
1295 EXPECT_EQ(10, response->headers->GetContentLength());
1296 EXPECT_TRUE(net::HttpVersion(1, 1) == response->headers->GetHttpVersion());
[email protected]77848d12008-11-14 00:00:221297
[email protected]f4e426b2008-11-05 00:24:491298 std::string response_data;
1299 rv = ReadTransaction(trans.get(), &response_data);
1300 EXPECT_STREQ("0123456789", response_data.c_str());
1301
1302 // We now check to make sure the TCPClientSocket was not added back to
1303 // the pool.
1304 EXPECT_EQ(0, session->connection_pool()->idle_socket_count());
1305 trans.reset();
1306 // Make sure that the socket didn't get recycled after calling the destructor.
1307 EXPECT_EQ(0, session->connection_pool()->idle_socket_count());
1308}
[email protected]372d34a2008-11-05 21:30:511309
1310TEST_F(HttpNetworkTransactionTest, ResendRequestOnWriteBodyError) {
1311 net::HttpRequestInfo request[2];
1312 // Transaction 1: a GET request that succeeds. The socket is recycled
1313 // after use.
1314 request[0].method = "GET";
1315 request[0].url = GURL("http://www.google.com/");
1316 request[0].load_flags = 0;
1317 // Transaction 2: a POST request. Reuses the socket kept alive from
1318 // transaction 1. The first attempts fails when writing the POST data.
1319 // This causes the transaction to retry with a new socket. The second
1320 // attempt succeeds.
1321 request[1].method = "POST";
1322 request[1].url = GURL("http://www.google.com/login.cgi");
1323 request[1].upload_data = new net::UploadData;
1324 request[1].upload_data->AppendBytes("foo", 3);
1325 request[1].load_flags = 0;
1326
[email protected]db8f44c2008-12-13 04:52:011327 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
1328 scoped_refptr<net::HttpNetworkSession> session =
1329 CreateSession(proxy_service.get());
[email protected]372d34a2008-11-05 21:30:511330
1331 // The first socket is used for transaction 1 and the first attempt of
1332 // transaction 2.
1333
1334 // The response of transaction 1.
1335 MockRead data_reads1[] = {
1336 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\n"),
1337 MockRead("hello world"),
1338 MockRead(false, net::OK),
1339 };
1340 // The mock write results of transaction 1 and the first attempt of
1341 // transaction 2.
1342 MockWrite data_writes1[] = {
1343 MockWrite(false, 64), // GET
1344 MockWrite(false, 93), // POST
1345 MockWrite(false, net::ERR_CONNECTION_ABORTED), // POST data
1346 };
1347 MockSocket data1;
1348 data1.reads = data_reads1;
1349 data1.writes = data_writes1;
1350
1351 // The second socket is used for the second attempt of transaction 2.
1352
1353 // The response of transaction 2.
1354 MockRead data_reads2[] = {
1355 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 7\r\n\r\n"),
1356 MockRead("welcome"),
1357 MockRead(false, net::OK),
1358 };
1359 // The mock write results of the second attempt of transaction 2.
1360 MockWrite data_writes2[] = {
1361 MockWrite(false, 93), // POST
1362 MockWrite(false, 3), // POST data
1363 };
1364 MockSocket data2;
1365 data2.reads = data_reads2;
1366 data2.writes = data_writes2;
1367
1368 mock_sockets[0] = &data1;
1369 mock_sockets[1] = &data2;
1370 mock_sockets[2] = NULL;
1371
1372 const char* kExpectedResponseData[] = {
1373 "hello world", "welcome"
1374 };
1375
1376 for (int i = 0; i < 2; ++i) {
1377 scoped_ptr<net::HttpTransaction> trans(
1378 new net::HttpNetworkTransaction(session, &mock_socket_factory));
1379
1380 TestCompletionCallback callback;
1381
1382 int rv = trans->Start(&request[i], &callback);
1383 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1384
1385 rv = callback.WaitForResult();
1386 EXPECT_EQ(net::OK, rv);
1387
1388 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1389 EXPECT_TRUE(response != NULL);
1390
1391 EXPECT_TRUE(response->headers != NULL);
1392 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
1393
1394 std::string response_data;
1395 rv = ReadTransaction(trans.get(), &response_data);
1396 EXPECT_EQ(net::OK, rv);
1397 EXPECT_EQ(kExpectedResponseData[i], response_data);
1398 }
1399}
[email protected]f9ee6b52008-11-08 06:46:231400
1401// Test the request-challenge-retry sequence for basic auth when there is
1402// an identity in the URL. The request should be sent as normal, but when
1403// it fails the identity from the URL is used to answer the challenge.
1404TEST_F(HttpNetworkTransactionTest, AuthIdentityInUrl) {
[email protected]db8f44c2008-12-13 04:52:011405 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
[email protected]f9ee6b52008-11-08 06:46:231406 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
[email protected]db8f44c2008-12-13 04:52:011407 CreateSession(proxy_service.get()), &mock_socket_factory));
[email protected]f9ee6b52008-11-08 06:46:231408
1409 net::HttpRequestInfo request;
1410 request.method = "GET";
1411 // Note: the URL has a username:password in it.
1412 request.url = GURL("http://foo:[email protected]/");
1413 request.load_flags = 0;
1414
1415 MockWrite data_writes1[] = {
1416 MockWrite("GET / HTTP/1.1\r\n"
1417 "Host: www.google.com\r\n"
1418 "Connection: keep-alive\r\n\r\n"),
1419 };
1420
1421 MockRead data_reads1[] = {
1422 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
1423 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1424 MockRead("Content-Length: 10\r\n\r\n"),
1425 MockRead(false, net::ERR_FAILED),
1426 };
1427
1428 // After the challenge above, the transaction will be restarted using the
1429 // identity from the url (foo, bar) to answer the challenge.
1430 MockWrite data_writes2[] = {
1431 MockWrite("GET / HTTP/1.1\r\n"
1432 "Host: www.google.com\r\n"
1433 "Connection: keep-alive\r\n"
1434 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1435 };
1436
1437 MockRead data_reads2[] = {
1438 MockRead("HTTP/1.0 200 OK\r\n"),
1439 MockRead("Content-Length: 100\r\n\r\n"),
1440 MockRead(false, net::OK),
1441 };
1442
1443 MockSocket data1;
1444 data1.reads = data_reads1;
1445 data1.writes = data_writes1;
1446 MockSocket data2;
1447 data2.reads = data_reads2;
1448 data2.writes = data_writes2;
1449 mock_sockets[0] = &data1;
1450 mock_sockets[1] = &data2;
1451 mock_sockets[2] = NULL;
1452
1453 TestCompletionCallback callback1;
1454
1455 int rv = trans->Start(&request, &callback1);
1456 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1457
1458 rv = callback1.WaitForResult();
1459 EXPECT_EQ(net::OK, rv);
1460
1461 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1462 EXPECT_FALSE(response == NULL);
1463
1464 // There is no challenge info, since the identity in URL worked.
1465 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1466
1467 EXPECT_EQ(100, response->headers->GetContentLength());
1468
1469 // Empty the current queue.
1470 MessageLoop::current()->RunAllPending();
1471}
1472
1473// Test that previously tried username/passwords for a realm get re-used.
1474TEST_F(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
[email protected]db8f44c2008-12-13 04:52:011475 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
1476 scoped_refptr<net::HttpNetworkSession> session =
1477 CreateSession(proxy_service.get());
[email protected]f9ee6b52008-11-08 06:46:231478
1479 // Transaction 1: authenticate (foo, bar) on MyRealm1
1480 {
1481 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1482 session, &mock_socket_factory));
1483
1484 net::HttpRequestInfo request;
1485 request.method = "GET";
1486 request.url = GURL("http://www.google.com/x/y/z");
1487 request.load_flags = 0;
1488
1489 MockWrite data_writes1[] = {
1490 MockWrite("GET /x/y/z HTTP/1.1\r\n"
1491 "Host: www.google.com\r\n"
1492 "Connection: keep-alive\r\n\r\n"),
1493 };
1494
1495 MockRead data_reads1[] = {
1496 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
1497 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1498 MockRead("Content-Length: 10000\r\n\r\n"),
1499 MockRead(false, net::ERR_FAILED),
1500 };
1501
1502 // Resend with authorization (username=foo, password=bar)
1503 MockWrite data_writes2[] = {
1504 MockWrite("GET /x/y/z HTTP/1.1\r\n"
1505 "Host: www.google.com\r\n"
1506 "Connection: keep-alive\r\n"
1507 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1508 };
1509
1510 // Sever accepts the authorization.
1511 MockRead data_reads2[] = {
1512 MockRead("HTTP/1.0 200 OK\r\n"),
1513 MockRead("Content-Length: 100\r\n\r\n"),
1514 MockRead(false, net::OK),
1515 };
1516
1517 MockSocket data1;
1518 data1.reads = data_reads1;
1519 data1.writes = data_writes1;
1520 MockSocket data2;
1521 data2.reads = data_reads2;
1522 data2.writes = data_writes2;
1523 mock_sockets_index = 0;
1524 mock_sockets[0] = &data1;
1525 mock_sockets[1] = &data2;
1526 mock_sockets[2] = NULL;
1527
1528 TestCompletionCallback callback1;
1529
1530 int rv = trans->Start(&request, &callback1);
1531 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1532
1533 rv = callback1.WaitForResult();
1534 EXPECT_EQ(net::OK, rv);
1535
1536 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1537 EXPECT_FALSE(response == NULL);
1538
1539 // The password prompt info should have been set in
1540 // response->auth_challenge.
1541 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1542
1543 // TODO(eroman): this should really include the effective port (80)
1544 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
1545 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1546 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1547
1548 TestCompletionCallback callback2;
1549
1550 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
1551 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1552
1553 rv = callback2.WaitForResult();
1554 EXPECT_EQ(net::OK, rv);
1555
1556 response = trans->GetResponseInfo();
1557 EXPECT_FALSE(response == NULL);
1558 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1559 EXPECT_EQ(100, response->headers->GetContentLength());
1560 }
1561
1562 // ------------------------------------------------------------------------
1563
1564 // Transaction 2: authenticate (foo2, bar2) on MyRealm2
1565 {
1566 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1567 session, &mock_socket_factory));
1568
1569 net::HttpRequestInfo request;
1570 request.method = "GET";
1571 // Note that Transaction 1 was at /x/y/z, so this is in the same
1572 // protection space as MyRealm1.
1573 request.url = GURL("http://www.google.com/x/y/a/b");
1574 request.load_flags = 0;
1575
1576 MockWrite data_writes1[] = {
1577 MockWrite("GET /x/y/a/b HTTP/1.1\r\n"
1578 "Host: www.google.com\r\n"
1579 "Connection: keep-alive\r\n"
1580 // Send preemptive authorization for MyRealm1
1581 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1582 };
1583
1584 // The server didn't like the preemptive authorization, and
1585 // challenges us for a different realm (MyRealm2).
1586 MockRead data_reads1[] = {
1587 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
1588 MockRead("WWW-Authenticate: Basic realm=\"MyRealm2\"\r\n"),
1589 MockRead("Content-Length: 10000\r\n\r\n"),
1590 MockRead(false, net::ERR_FAILED),
1591 };
1592
1593 // Resend with authorization for MyRealm2 (username=foo2, password=bar2)
1594 MockWrite data_writes2[] = {
1595 MockWrite("GET /x/y/a/b HTTP/1.1\r\n"
1596 "Host: www.google.com\r\n"
1597 "Connection: keep-alive\r\n"
1598 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"),
1599 };
1600
1601 // Sever accepts the authorization.
1602 MockRead data_reads2[] = {
1603 MockRead("HTTP/1.0 200 OK\r\n"),
1604 MockRead("Content-Length: 100\r\n\r\n"),
1605 MockRead(false, net::OK),
1606 };
1607
1608 MockSocket data1;
1609 data1.reads = data_reads1;
1610 data1.writes = data_writes1;
1611 MockSocket data2;
1612 data2.reads = data_reads2;
1613 data2.writes = data_writes2;
1614 mock_sockets_index = 0;
1615 mock_sockets[0] = &data1;
1616 mock_sockets[1] = &data2;
1617 mock_sockets[2] = NULL;
1618
1619 TestCompletionCallback callback1;
1620
1621 int rv = trans->Start(&request, &callback1);
1622 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1623
1624 rv = callback1.WaitForResult();
1625 EXPECT_EQ(net::OK, rv);
1626
1627 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1628 EXPECT_FALSE(response == NULL);
1629
1630 // The password prompt info should have been set in
1631 // response->auth_challenge.
1632 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1633
1634 // TODO(eroman): this should really include the effective port (80)
1635 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
1636 EXPECT_EQ(L"MyRealm2", response->auth_challenge->realm);
1637 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1638
1639 TestCompletionCallback callback2;
1640
1641 rv = trans->RestartWithAuth(L"foo2", L"bar2", &callback2);
1642 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1643
1644 rv = callback2.WaitForResult();
1645 EXPECT_EQ(net::OK, rv);
1646
1647 response = trans->GetResponseInfo();
1648 EXPECT_FALSE(response == NULL);
1649 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1650 EXPECT_EQ(100, response->headers->GetContentLength());
1651 }
1652
1653 // ------------------------------------------------------------------------
1654
1655 // Transaction 3: Resend a request in MyRealm's protection space --
1656 // succeed with preemptive authorization.
1657 {
1658 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1659 session, &mock_socket_factory));
1660
1661 net::HttpRequestInfo request;
1662 request.method = "GET";
1663 request.url = GURL("http://www.google.com/x/y/z2");
1664 request.load_flags = 0;
1665
1666 MockWrite data_writes1[] = {
1667 MockWrite("GET /x/y/z2 HTTP/1.1\r\n"
1668 "Host: www.google.com\r\n"
1669 "Connection: keep-alive\r\n"
1670 // The authorization for MyRealm1 gets sent preemptively
1671 // (since the url is in the same protection space)
1672 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1673 };
1674
1675 // Sever accepts the preemptive authorization
1676 MockRead data_reads1[] = {
1677 MockRead("HTTP/1.0 200 OK\r\n"),
1678 MockRead("Content-Length: 100\r\n\r\n"),
1679 MockRead(false, net::OK),
1680 };
1681
1682 MockSocket data1;
1683 data1.reads = data_reads1;
1684 data1.writes = data_writes1;
1685 mock_sockets_index = 0;
1686 mock_sockets[0] = &data1;
1687 mock_sockets[1] = NULL;
1688
1689 TestCompletionCallback callback1;
1690
1691 int rv = trans->Start(&request, &callback1);
1692 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1693
1694 rv = callback1.WaitForResult();
1695 EXPECT_EQ(net::OK, rv);
1696
1697 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1698 EXPECT_FALSE(response == NULL);
1699
1700 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1701 EXPECT_EQ(100, response->headers->GetContentLength());
1702 }
1703
1704 // ------------------------------------------------------------------------
1705
1706 // Transaction 4: request another URL in MyRealm (however the
1707 // url is not known to belong to the protection space, so no pre-auth).
1708 {
1709 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1710 session, &mock_socket_factory));
1711
1712 net::HttpRequestInfo request;
1713 request.method = "GET";
1714 request.url = GURL("http://www.google.com/x/1");
1715 request.load_flags = 0;
1716
1717 MockWrite data_writes1[] = {
1718 MockWrite("GET /x/1 HTTP/1.1\r\n"
1719 "Host: www.google.com\r\n"
1720 "Connection: keep-alive\r\n\r\n"),
1721 };
1722
1723 MockRead data_reads1[] = {
1724 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
1725 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1726 MockRead("Content-Length: 10000\r\n\r\n"),
1727 MockRead(false, net::ERR_FAILED),
1728 };
1729
1730 // Resend with authorization from MyRealm's cache.
1731 MockWrite data_writes2[] = {
1732 MockWrite("GET /x/1 HTTP/1.1\r\n"
1733 "Host: www.google.com\r\n"
1734 "Connection: keep-alive\r\n"
1735 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1736 };
1737
1738 // Sever accepts the authorization.
1739 MockRead data_reads2[] = {
1740 MockRead("HTTP/1.0 200 OK\r\n"),
1741 MockRead("Content-Length: 100\r\n\r\n"),
1742 MockRead(false, net::OK),
1743 };
1744
1745 MockSocket data1;
1746 data1.reads = data_reads1;
1747 data1.writes = data_writes1;
1748 MockSocket data2;
1749 data2.reads = data_reads2;
1750 data2.writes = data_writes2;
1751 mock_sockets_index = 0;
1752 mock_sockets[0] = &data1;
1753 mock_sockets[1] = &data2;
1754 mock_sockets[2] = NULL;
1755
1756 TestCompletionCallback callback1;
1757
1758 int rv = trans->Start(&request, &callback1);
1759 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1760
1761 rv = callback1.WaitForResult();
1762 EXPECT_EQ(net::OK, rv);
1763
1764 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1765 EXPECT_FALSE(response == NULL);
1766 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1767 EXPECT_EQ(100, response->headers->GetContentLength());
1768 }
1769
1770 // ------------------------------------------------------------------------
1771
1772 // Transaction 5: request a URL in MyRealm, but the server rejects the
1773 // cached identity. Should invalidate and re-prompt.
1774 {
1775 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1776 session, &mock_socket_factory));
1777
1778 net::HttpRequestInfo request;
1779 request.method = "GET";
1780 request.url = GURL("http://www.google.com/p/q/t");
1781 request.load_flags = 0;
1782
1783 MockWrite data_writes1[] = {
1784 MockWrite("GET /p/q/t HTTP/1.1\r\n"
1785 "Host: www.google.com\r\n"
1786 "Connection: keep-alive\r\n\r\n"),
1787 };
1788
1789 MockRead data_reads1[] = {
1790 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
1791 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1792 MockRead("Content-Length: 10000\r\n\r\n"),
1793 MockRead(false, net::ERR_FAILED),
1794 };
1795
1796 // Resend with authorization from cache for MyRealm.
1797 MockWrite data_writes2[] = {
1798 MockWrite("GET /p/q/t HTTP/1.1\r\n"
1799 "Host: www.google.com\r\n"
1800 "Connection: keep-alive\r\n"
1801 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1802 };
1803
1804 // Sever rejects the authorization.
1805 MockRead data_reads2[] = {
1806 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
1807 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1808 MockRead("Content-Length: 10000\r\n\r\n"),
1809 MockRead(false, net::ERR_FAILED),
1810 };
1811
1812 // At this point we should prompt for new credentials for MyRealm.
1813 // Restart with username=foo3, password=foo4.
1814 MockWrite data_writes3[] = {
1815 MockWrite("GET /p/q/t HTTP/1.1\r\n"
1816 "Host: www.google.com\r\n"
1817 "Connection: keep-alive\r\n"
1818 "Authorization: Basic Zm9vMzpiYXIz\r\n\r\n"),
1819 };
1820
1821 // Sever accepts the authorization.
1822 MockRead data_reads3[] = {
1823 MockRead("HTTP/1.0 200 OK\r\n"),
1824 MockRead("Content-Length: 100\r\n\r\n"),
1825 MockRead(false, net::OK),
1826 };
1827
1828 MockSocket data1;
1829 data1.reads = data_reads1;
1830 data1.writes = data_writes1;
1831 MockSocket data2;
1832 data2.reads = data_reads2;
1833 data2.writes = data_writes2;
1834 MockSocket data3;
1835 data3.reads = data_reads3;
1836 data3.writes = data_writes3;
1837 mock_sockets_index = 0;
1838 mock_sockets[0] = &data1;
1839 mock_sockets[1] = &data2;
1840 mock_sockets[2] = &data3;
1841 mock_sockets[3] = NULL;
1842
1843 TestCompletionCallback callback1;
1844
1845 int rv = trans->Start(&request, &callback1);
1846 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1847
1848 rv = callback1.WaitForResult();
1849 EXPECT_EQ(net::OK, rv);
1850
1851 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1852 EXPECT_FALSE(response == NULL);
1853
1854 // The password prompt info should have been set in
1855 // response->auth_challenge.
1856 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1857
1858 // TODO(eroman): this should really include the effective port (80)
1859 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
1860 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1861 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1862
1863 TestCompletionCallback callback2;
1864
1865 rv = trans->RestartWithAuth(L"foo3", L"bar3", &callback2);
1866 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1867
1868 rv = callback2.WaitForResult();
1869 EXPECT_EQ(net::OK, rv);
1870
1871 response = trans->GetResponseInfo();
1872 EXPECT_FALSE(response == NULL);
1873 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1874 EXPECT_EQ(100, response->headers->GetContentLength());
1875 }
1876}