blob: fde12f4fd57d0e7635df58af1d7fc58fbb0ecd46 [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"
8#include "base/platform_test.h"
initial.commit586acc5fe2008-07-26 22:42:529#include "net/base/client_socket_factory.h"
10#include "net/base/test_completion_callback.h"
11#include "net/base/upload_data.h"
12#include "net/http/http_network_session.h"
13#include "net/http/http_network_transaction.h"
14#include "net/http/http_transaction_unittest.h"
[email protected]038e9a32008-10-08 22:40:1615#include "net/proxy/proxy_resolver_fixed.h"
[email protected]e8d536192008-10-17 22:21:1416#include "net/proxy/proxy_resolver_null.h"
initial.commit586acc5fe2008-07-26 22:42:5217#include "testing/gtest/include/gtest/gtest.h"
18
19//-----------------------------------------------------------------------------
20
initial.commit586acc5fe2008-07-26 22:42:5221
22struct MockConnect {
[email protected]217e6022008-09-29 18:18:3523 // Asynchronous connection success.
24 MockConnect() : async(true), result(net::OK) { }
[email protected]038e9a32008-10-08 22:40:1625
26 bool async;
27 int result;
initial.commit586acc5fe2008-07-26 22:42:5228};
29
30struct MockRead {
[email protected]217e6022008-09-29 18:18:3531 // Read failure (no data).
32 MockRead(bool async, int result) : async(async) , result(result), data(NULL),
33 data_len(0) { }
34
35 // Asynchronous read success (inferred data length).
[email protected]372d34a2008-11-05 21:30:5136 explicit MockRead(const char* data) : async(true), result(0), data(data),
[email protected]b5462e02008-09-29 18:32:1937 data_len(strlen(data)) { }
[email protected]217e6022008-09-29 18:18:3538
39 // Read success (inferred data length).
[email protected]b5462e02008-09-29 18:32:1940 MockRead(bool async, const char* data) : async(async), result(0), data(data),
41 data_len(strlen(data)) { }
[email protected]217e6022008-09-29 18:18:3542
43 // Read success.
44 MockRead(bool async, const char* data, int data_len) : async(async),
[email protected]b5462e02008-09-29 18:32:1945 result(0), data(data), data_len(data_len) { }
[email protected]217e6022008-09-29 18:18:3546
initial.commit586acc5fe2008-07-26 22:42:5247 bool async;
[email protected]217e6022008-09-29 18:18:3548 int result;
initial.commit586acc5fe2008-07-26 22:42:5249 const char* data;
[email protected]217e6022008-09-29 18:18:3550 int data_len;
initial.commit586acc5fe2008-07-26 22:42:5251};
52
[email protected]038e9a32008-10-08 22:40:1653// MockWrite uses the same member fields as MockRead, but with different
54// meanings. The expected input to MockTCPClientSocket::Write() is given
55// by {data, data_len}, and the return value of Write() is controlled by
56// {async, result}.
57typedef MockRead MockWrite;
58
initial.commit586acc5fe2008-07-26 22:42:5259struct MockSocket {
[email protected]038e9a32008-10-08 22:40:1660 MockSocket() : reads(NULL), writes(NULL) { }
[email protected]217e6022008-09-29 18:18:3561
initial.commit586acc5fe2008-07-26 22:42:5262 MockConnect connect;
[email protected]217e6022008-09-29 18:18:3563 MockRead* reads;
[email protected]038e9a32008-10-08 22:40:1664 MockWrite* writes;
initial.commit586acc5fe2008-07-26 22:42:5265};
66
67// Holds an array of MockSocket elements. As MockTCPClientSocket objects get
68// instantiated, they take their data from the i'th element of this array.
69//
70// Tests should assign the first N entries of mock_sockets to point to valid
71// MockSocket objects. The first unused entry should be NULL'd.
72//
73MockSocket* mock_sockets[10];
74
75// Index of the next mock_sockets element to use.
76int mock_sockets_index;
77
78class MockTCPClientSocket : public net::ClientSocket {
79 public:
[email protected]372d34a2008-11-05 21:30:5180 explicit MockTCPClientSocket(const net::AddressList& addresses)
initial.commit586acc5fe2008-07-26 22:42:5281 : data_(mock_sockets[mock_sockets_index++]),
[email protected]68bf9152008-09-25 19:47:3082 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
initial.commit586acc5fe2008-07-26 22:42:5283 callback_(NULL),
84 read_index_(0),
85 read_offset_(0),
[email protected]038e9a32008-10-08 22:40:1686 write_index_(0),
initial.commit586acc5fe2008-07-26 22:42:5287 connected_(false) {
88 DCHECK(data_) << "overran mock_sockets array";
89 }
90 // ClientSocket methods:
91 virtual int Connect(net::CompletionCallback* callback) {
92 DCHECK(!callback_);
93 if (connected_)
94 return net::OK;
95 connected_ = true;
96 if (data_->connect.async) {
97 RunCallbackAsync(callback, data_->connect.result);
98 return net::ERR_IO_PENDING;
99 }
100 return data_->connect.result;
101 }
102 virtual int ReconnectIgnoringLastError(net::CompletionCallback* callback) {
103 NOTREACHED();
104 return net::ERR_FAILED;
105 }
106 virtual void Disconnect() {
107 connected_ = false;
108 callback_ = NULL;
109 }
110 virtual bool IsConnected() const {
111 return connected_;
112 }
113 // Socket methods:
114 virtual int Read(char* buf, int buf_len, net::CompletionCallback* callback) {
115 DCHECK(!callback_);
116 MockRead& r = data_->reads[read_index_];
[email protected]038e9a32008-10-08 22:40:16117 int result = r.result;
initial.commit586acc5fe2008-07-26 22:42:52118 if (r.data) {
initial.commit586acc5fe2008-07-26 22:42:52119 if (r.data_len - read_offset_ > 0) {
120 result = std::min(buf_len, r.data_len - read_offset_);
121 memcpy(buf, r.data + read_offset_, result);
122 read_offset_ += result;
123 if (read_offset_ == r.data_len) {
124 read_index_++;
125 read_offset_ = 0;
126 }
127 } else {
128 result = 0; // EOF
129 }
initial.commit586acc5fe2008-07-26 22:42:52130 }
131 if (r.async) {
132 RunCallbackAsync(callback, result);
133 return net::ERR_IO_PENDING;
134 }
135 return result;
136 }
137 virtual int Write(const char* buf, int buf_len,
138 net::CompletionCallback* callback) {
[email protected]372d34a2008-11-05 21:30:51139 DCHECK(buf);
140 DCHECK(buf_len > 0);
initial.commit586acc5fe2008-07-26 22:42:52141 DCHECK(!callback_);
[email protected]038e9a32008-10-08 22:40:16142 // Not using mock writes; succeed synchronously.
143 if (!data_->writes)
144 return buf_len;
[email protected]aaead502008-10-15 00:20:11145
[email protected]038e9a32008-10-08 22:40:16146 // Check that what we are writing matches the expectation.
147 // Then give the mocked return value.
[email protected]372d34a2008-11-05 21:30:51148 MockWrite& w = data_->writes[write_index_++];
[email protected]038e9a32008-10-08 22:40:16149 int result = w.result;
150 if (w.data) {
151 std::string expected_data(w.data, w.data_len);
152 std::string actual_data(buf, buf_len);
153 EXPECT_EQ(expected_data, actual_data);
154 if (expected_data != actual_data)
155 return net::ERR_UNEXPECTED;
156 if (result == net::OK)
157 result = w.data_len;
158 }
159 if (w.async) {
160 RunCallbackAsync(callback, result);
161 return net::ERR_IO_PENDING;
162 }
163 return result;
initial.commit586acc5fe2008-07-26 22:42:52164 }
165 private:
166 void RunCallbackAsync(net::CompletionCallback* callback, int result) {
167 callback_ = callback;
168 MessageLoop::current()->PostTask(FROM_HERE,
169 method_factory_.NewRunnableMethod(
170 &MockTCPClientSocket::RunCallback, result));
171 }
172 void RunCallback(int result) {
173 net::CompletionCallback* c = callback_;
174 callback_ = NULL;
175 if (c)
176 c->Run(result);
177 }
178 MockSocket* data_;
179 ScopedRunnableMethodFactory<MockTCPClientSocket> method_factory_;
180 net::CompletionCallback* callback_;
181 int read_index_;
182 int read_offset_;
[email protected]038e9a32008-10-08 22:40:16183 int write_index_;
initial.commit586acc5fe2008-07-26 22:42:52184 bool connected_;
185};
186
187class MockClientSocketFactory : public net::ClientSocketFactory {
188 public:
189 virtual net::ClientSocket* CreateTCPClientSocket(
190 const net::AddressList& addresses) {
191 return new MockTCPClientSocket(addresses);
192 }
[email protected]aaead502008-10-15 00:20:11193 virtual net::SSLClientSocket* CreateSSLClientSocket(
initial.commit586acc5fe2008-07-26 22:42:52194 net::ClientSocket* transport_socket,
[email protected]c5949a32008-10-08 17:28:23195 const std::string& hostname,
[email protected]aaead502008-10-15 00:20:11196 const net::SSLConfig& ssl_config) {
initial.commit586acc5fe2008-07-26 22:42:52197 return NULL;
198 }
199};
200
201MockClientSocketFactory mock_socket_factory;
202
[email protected]e8d536192008-10-17 22:21:14203net::HttpNetworkSession* CreateSession(net::ProxyResolver* proxy_resolver) {
204 if (!proxy_resolver) {
205 proxy_resolver = new net::ProxyResolverNull();
initial.commit586acc5fe2008-07-26 22:42:52206 }
[email protected]038e9a32008-10-08 22:40:16207 return new net::HttpNetworkSession(proxy_resolver);
initial.commit586acc5fe2008-07-26 22:42:52208}
209
[email protected]e8d536192008-10-17 22:21:14210net::HttpNetworkSession* CreateSession() {
211 return CreateSession(NULL);
212}
213
[email protected]89836e22008-09-25 20:33:42214class HttpNetworkTransactionTest : public PlatformTest {
initial.commit586acc5fe2008-07-26 22:42:52215 public:
216 virtual void SetUp() {
[email protected]89836e22008-09-25 20:33:42217 PlatformTest::SetUp();
initial.commit586acc5fe2008-07-26 22:42:52218 mock_sockets[0] = NULL;
219 mock_sockets_index = 0;
220 }
[email protected]3d2a59b2008-09-26 19:44:25221
[email protected]0e75a732008-10-16 20:36:09222 virtual void TearDown() {
223 // Empty the current queue.
224 MessageLoop::current()->RunAllPending();
225 PlatformTest::TearDown();
226 }
227
[email protected]3d2a59b2008-09-26 19:44:25228 protected:
229 void KeepAliveConnectionResendRequestTest(const MockRead& read_failure);
initial.commit586acc5fe2008-07-26 22:42:52230};
231
[email protected]231d5a32008-09-13 00:45:27232struct SimpleGetHelperResult {
[email protected]aecfbf22008-10-16 02:02:47233 int rv;
[email protected]231d5a32008-09-13 00:45:27234 std::string status_line;
235 std::string response_data;
236};
initial.commit586acc5fe2008-07-26 22:42:52237
[email protected]231d5a32008-09-13 00:45:27238SimpleGetHelperResult SimpleGetHelper(MockRead data_reads[]) {
239 SimpleGetHelperResult out;
initial.commit586acc5fe2008-07-26 22:42:52240
[email protected]af4876d2008-10-21 23:10:57241 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
242 CreateSession(), &mock_socket_factory));
initial.commit586acc5fe2008-07-26 22:42:52243
244 net::HttpRequestInfo request;
245 request.method = "GET";
246 request.url = GURL("http://www.google.com/");
247 request.load_flags = 0;
248
initial.commit586acc5fe2008-07-26 22:42:52249 MockSocket data;
initial.commit586acc5fe2008-07-26 22:42:52250 data.reads = data_reads;
251 mock_sockets[0] = &data;
252 mock_sockets[1] = NULL;
253
254 TestCompletionCallback callback;
255
256 int rv = trans->Start(&request, &callback);
257 EXPECT_EQ(net::ERR_IO_PENDING, rv);
258
[email protected]aecfbf22008-10-16 02:02:47259 out.rv = callback.WaitForResult();
[email protected]af4876d2008-10-21 23:10:57260 if (out.rv != net::OK)
[email protected]aecfbf22008-10-16 02:02:47261 return out;
initial.commit586acc5fe2008-07-26 22:42:52262
263 const net::HttpResponseInfo* response = trans->GetResponseInfo();
264 EXPECT_TRUE(response != NULL);
265
266 EXPECT_TRUE(response->headers != NULL);
[email protected]231d5a32008-09-13 00:45:27267 out.status_line = response->headers->GetStatusLine();
initial.commit586acc5fe2008-07-26 22:42:52268
[email protected]af4876d2008-10-21 23:10:57269 rv = ReadTransaction(trans.get(), &out.response_data);
initial.commit586acc5fe2008-07-26 22:42:52270 EXPECT_EQ(net::OK, rv);
initial.commit586acc5fe2008-07-26 22:42:52271
[email protected]231d5a32008-09-13 00:45:27272 return out;
273}
274
[email protected]15a5ccf82008-10-23 19:57:43275// Fill |str| with a long header list that consumes >= |size| bytes.
276void FillLargeHeadersString(std::string* str, int size) {
[email protected]4ddaf2502008-10-23 18:26:19277 const char* row =
278 "SomeHeaderName: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n";
279 const int sizeof_row = strlen(row);
280 const int num_rows = static_cast<int>(
281 ceil(static_cast<float>(size) / sizeof_row));
282 const int sizeof_data = num_rows * sizeof_row;
283 DCHECK(sizeof_data >= size);
[email protected]15a5ccf82008-10-23 19:57:43284 str->reserve(sizeof_data);
[email protected]372d34a2008-11-05 21:30:51285
[email protected]4ddaf2502008-10-23 18:26:19286 for (int i = 0; i < num_rows; ++i)
[email protected]15a5ccf82008-10-23 19:57:43287 str->append(row, sizeof_row);
[email protected]4ddaf2502008-10-23 18:26:19288}
289
[email protected]231d5a32008-09-13 00:45:27290//-----------------------------------------------------------------------------
291
292TEST_F(HttpNetworkTransactionTest, Basic) {
[email protected]af4876d2008-10-21 23:10:57293 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
294 CreateSession(), &mock_socket_factory));
[email protected]231d5a32008-09-13 00:45:27295}
296
297TEST_F(HttpNetworkTransactionTest, SimpleGET) {
298 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35299 MockRead("HTTP/1.0 200 OK\r\n\r\n"),
300 MockRead("hello world"),
301 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27302 };
[email protected]231d5a32008-09-13 00:45:27303 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47304 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27305 EXPECT_EQ("HTTP/1.0 200 OK", out.status_line);
306 EXPECT_EQ("hello world", out.response_data);
307}
308
309// Response with no status line.
310TEST_F(HttpNetworkTransactionTest, SimpleGETNoHeaders) {
311 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35312 MockRead("hello world"),
313 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27314 };
[email protected]231d5a32008-09-13 00:45:27315 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47316 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27317 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
318 EXPECT_EQ("hello world", out.response_data);
319}
320
321// Allow up to 4 bytes of junk to precede status line.
322TEST_F(HttpNetworkTransactionTest, StatusLineJunk2Bytes) {
323 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35324 MockRead("xxxHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
325 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27326 };
327 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47328 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27329 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
330 EXPECT_EQ("DATA", out.response_data);
331}
332
333// Allow up to 4 bytes of junk to precede status line.
334TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes) {
335 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35336 MockRead("\n\nQJHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
337 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27338 };
339 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47340 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27341 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
342 EXPECT_EQ("DATA", out.response_data);
343}
344
345// Beyond 4 bytes of slop and it should fail to find a status line.
346TEST_F(HttpNetworkTransactionTest, StatusLineJunk5Bytes) {
347 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35348 MockRead("xxxxxHTTP/1.1 404 Not Found\nServer: blah"),
349 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27350 };
351 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47352 EXPECT_EQ(net::OK, out.rv);
[email protected]3d2a59b2008-09-26 19:44:25353 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
354 EXPECT_EQ("xxxxxHTTP/1.1 404 Not Found\nServer: blah", out.response_data);
[email protected]231d5a32008-09-13 00:45:27355}
356
357// Same as StatusLineJunk4Bytes, except the read chunks are smaller.
358TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes_Slow) {
359 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35360 MockRead("\n"),
361 MockRead("\n"),
362 MockRead("Q"),
363 MockRead("J"),
364 MockRead("HTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
365 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27366 };
367 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47368 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27369 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
370 EXPECT_EQ("DATA", out.response_data);
371}
372
373// Close the connection before enough bytes to have a status line.
374TEST_F(HttpNetworkTransactionTest, StatusLinePartial) {
375 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35376 MockRead("HTT"),
377 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27378 };
379 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47380 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27381 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
382 EXPECT_EQ("HTT", out.response_data);
initial.commit586acc5fe2008-07-26 22:42:52383}
384
[email protected]f9d44aa2008-09-23 23:57:17385// Simulate a 204 response, lacking a Content-Length header, sent over a
386// persistent connection. The response should still terminate since a 204
387// cannot have a response body.
388TEST_F(HttpNetworkTransactionTest, StopsReading204) {
389 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35390 MockRead("HTTP/1.1 204 No Content\r\n\r\n"),
391 MockRead("junk"), // Should not be read!!
392 MockRead(false, net::OK),
[email protected]f9d44aa2008-09-23 23:57:17393 };
394 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47395 EXPECT_EQ(net::OK, out.rv);
[email protected]f9d44aa2008-09-23 23:57:17396 EXPECT_EQ("HTTP/1.1 204 No Content", out.status_line);
397 EXPECT_EQ("", out.response_data);
398}
399
initial.commit586acc5fe2008-07-26 22:42:52400TEST_F(HttpNetworkTransactionTest, ReuseConnection) {
401 scoped_refptr<net::HttpNetworkSession> session = CreateSession();
402
403 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35404 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
405 MockRead("hello"),
406 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
407 MockRead("world"),
408 MockRead(false, net::OK),
initial.commit586acc5fe2008-07-26 22:42:52409 };
410 MockSocket data;
initial.commit586acc5fe2008-07-26 22:42:52411 data.reads = data_reads;
412 mock_sockets[0] = &data;
413 mock_sockets[1] = NULL;
414
415 const char* kExpectedResponseData[] = {
416 "hello", "world"
417 };
418
419 for (int i = 0; i < 2; ++i) {
[email protected]af4876d2008-10-21 23:10:57420 scoped_ptr<net::HttpTransaction> trans(
421 new net::HttpNetworkTransaction(session, &mock_socket_factory));
initial.commit586acc5fe2008-07-26 22:42:52422
423 net::HttpRequestInfo request;
424 request.method = "GET";
425 request.url = GURL("http://www.google.com/");
426 request.load_flags = 0;
427
428 TestCompletionCallback callback;
429
430 int rv = trans->Start(&request, &callback);
431 EXPECT_EQ(net::ERR_IO_PENDING, rv);
432
433 rv = callback.WaitForResult();
434 EXPECT_EQ(net::OK, rv);
435
436 const net::HttpResponseInfo* response = trans->GetResponseInfo();
437 EXPECT_TRUE(response != NULL);
438
439 EXPECT_TRUE(response->headers != NULL);
[email protected]3d2a59b2008-09-26 19:44:25440 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
initial.commit586acc5fe2008-07-26 22:42:52441
442 std::string response_data;
[email protected]af4876d2008-10-21 23:10:57443 rv = ReadTransaction(trans.get(), &response_data);
initial.commit586acc5fe2008-07-26 22:42:52444 EXPECT_EQ(net::OK, rv);
[email protected]3d2a59b2008-09-26 19:44:25445 EXPECT_EQ(kExpectedResponseData[i], response_data);
initial.commit586acc5fe2008-07-26 22:42:52446 }
447}
448
449TEST_F(HttpNetworkTransactionTest, Ignores100) {
[email protected]af4876d2008-10-21 23:10:57450 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
451 CreateSession(), &mock_socket_factory));
initial.commit586acc5fe2008-07-26 22:42:52452
453 net::HttpRequestInfo request;
454 request.method = "POST";
455 request.url = GURL("http://www.foo.com/");
456 request.upload_data = new net::UploadData;
457 request.upload_data->AppendBytes("foo", 3);
458 request.load_flags = 0;
459
460 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35461 MockRead("HTTP/1.0 100 Continue\r\n\r\n"),
462 MockRead("HTTP/1.0 200 OK\r\n\r\n"),
463 MockRead("hello world"),
464 MockRead(false, net::OK),
initial.commit586acc5fe2008-07-26 22:42:52465 };
466 MockSocket data;
initial.commit586acc5fe2008-07-26 22:42:52467 data.reads = data_reads;
468 mock_sockets[0] = &data;
469 mock_sockets[1] = NULL;
470
471 TestCompletionCallback callback;
472
473 int rv = trans->Start(&request, &callback);
474 EXPECT_EQ(net::ERR_IO_PENDING, rv);
475
476 rv = callback.WaitForResult();
477 EXPECT_EQ(net::OK, rv);
478
479 const net::HttpResponseInfo* response = trans->GetResponseInfo();
480 EXPECT_TRUE(response != NULL);
481
482 EXPECT_TRUE(response->headers != NULL);
[email protected]3d2a59b2008-09-26 19:44:25483 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine());
initial.commit586acc5fe2008-07-26 22:42:52484
485 std::string response_data;
[email protected]af4876d2008-10-21 23:10:57486 rv = ReadTransaction(trans.get(), &response_data);
initial.commit586acc5fe2008-07-26 22:42:52487 EXPECT_EQ(net::OK, rv);
[email protected]3d2a59b2008-09-26 19:44:25488 EXPECT_EQ("hello world", response_data);
initial.commit586acc5fe2008-07-26 22:42:52489}
490
[email protected]3d2a59b2008-09-26 19:44:25491// read_failure specifies a read failure that should cause the network
492// transaction to resend the request.
493void HttpNetworkTransactionTest::KeepAliveConnectionResendRequestTest(
494 const MockRead& read_failure) {
initial.commit586acc5fe2008-07-26 22:42:52495 scoped_refptr<net::HttpNetworkSession> session = CreateSession();
496
497 net::HttpRequestInfo request;
498 request.method = "GET";
499 request.url = GURL("http://www.foo.com/");
500 request.load_flags = 0;
501
502 MockRead data1_reads[] = {
[email protected]217e6022008-09-29 18:18:35503 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
504 MockRead("hello"),
[email protected]3d2a59b2008-09-26 19:44:25505 read_failure, // Now, we reuse the connection and fail the first read.
initial.commit586acc5fe2008-07-26 22:42:52506 };
507 MockSocket data1;
initial.commit586acc5fe2008-07-26 22:42:52508 data1.reads = data1_reads;
509 mock_sockets[0] = &data1;
510
511 MockRead data2_reads[] = {
[email protected]217e6022008-09-29 18:18:35512 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
513 MockRead("world"),
514 MockRead(true, net::OK),
initial.commit586acc5fe2008-07-26 22:42:52515 };
516 MockSocket data2;
initial.commit586acc5fe2008-07-26 22:42:52517 data2.reads = data2_reads;
518 mock_sockets[1] = &data2;
519
520 const char* kExpectedResponseData[] = {
521 "hello", "world"
522 };
523
524 for (int i = 0; i < 2; ++i) {
525 TestCompletionCallback callback;
526
[email protected]af4876d2008-10-21 23:10:57527 scoped_ptr<net::HttpTransaction> trans(
528 new net::HttpNetworkTransaction(session, &mock_socket_factory));
initial.commit586acc5fe2008-07-26 22:42:52529
530 int rv = trans->Start(&request, &callback);
531 EXPECT_EQ(net::ERR_IO_PENDING, rv);
532
533 rv = callback.WaitForResult();
534 EXPECT_EQ(net::OK, rv);
535
536 const net::HttpResponseInfo* response = trans->GetResponseInfo();
537 EXPECT_TRUE(response != NULL);
538
539 EXPECT_TRUE(response->headers != NULL);
[email protected]3d2a59b2008-09-26 19:44:25540 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
initial.commit586acc5fe2008-07-26 22:42:52541
542 std::string response_data;
[email protected]af4876d2008-10-21 23:10:57543 rv = ReadTransaction(trans.get(), &response_data);
initial.commit586acc5fe2008-07-26 22:42:52544 EXPECT_EQ(net::OK, rv);
[email protected]3d2a59b2008-09-26 19:44:25545 EXPECT_EQ(kExpectedResponseData[i], response_data);
initial.commit586acc5fe2008-07-26 22:42:52546 }
547}
[email protected]3d2a59b2008-09-26 19:44:25548
549TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionReset) {
[email protected]217e6022008-09-29 18:18:35550 MockRead read_failure(true, net::ERR_CONNECTION_RESET);
[email protected]3d2a59b2008-09-26 19:44:25551 KeepAliveConnectionResendRequestTest(read_failure);
552}
553
554TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionEOF) {
[email protected]217e6022008-09-29 18:18:35555 MockRead read_failure(false, net::OK); // EOF
[email protected]3d2a59b2008-09-26 19:44:25556 KeepAliveConnectionResendRequestTest(read_failure);
557}
558
559TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionReset) {
[email protected]af4876d2008-10-21 23:10:57560 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
561 CreateSession(), &mock_socket_factory));
[email protected]3d2a59b2008-09-26 19:44:25562
563 net::HttpRequestInfo request;
564 request.method = "GET";
565 request.url = GURL("http://www.google.com/");
566 request.load_flags = 0;
567
568 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35569 MockRead(true, net::ERR_CONNECTION_RESET),
570 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used
571 MockRead("hello world"),
572 MockRead(false, net::OK),
[email protected]3d2a59b2008-09-26 19:44:25573 };
574 MockSocket data;
[email protected]3d2a59b2008-09-26 19:44:25575 data.reads = data_reads;
576 mock_sockets[0] = &data;
577 mock_sockets[1] = NULL;
578
579 TestCompletionCallback callback;
580
581 int rv = trans->Start(&request, &callback);
582 EXPECT_EQ(net::ERR_IO_PENDING, rv);
583
584 rv = callback.WaitForResult();
585 EXPECT_EQ(net::ERR_CONNECTION_RESET, rv);
586
587 const net::HttpResponseInfo* response = trans->GetResponseInfo();
588 EXPECT_TRUE(response == NULL);
[email protected]3d2a59b2008-09-26 19:44:25589}
590
591// What do various browsers do when the server closes a non-keepalive
592// connection without sending any response header or body?
593//
594// IE7: error page
595// Safari 3.1.2 (Windows): error page
596// Firefox 3.0.1: blank page
597// Opera 9.52: after five attempts, blank page
598// Us with WinHTTP: error page (net::ERR_INVALID_RESPONSE)
[email protected]aecfbf22008-10-16 02:02:47599// Us: error page (net::EMPTY_RESPONSE)
[email protected]3d2a59b2008-09-26 19:44:25600TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionEOF) {
601 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35602 MockRead(false, net::OK), // EOF
603 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used
604 MockRead("hello world"),
605 MockRead(false, net::OK),
[email protected]3d2a59b2008-09-26 19:44:25606 };
607 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]0e75a732008-10-16 20:36:09608 EXPECT_EQ(net::ERR_EMPTY_RESPONSE, out.rv);
[email protected]3d2a59b2008-09-26 19:44:25609}
[email protected]038e9a32008-10-08 22:40:16610
611// Test the request-challenge-retry sequence for basic auth.
612// (basic auth is the easiest to mock, because it has no randomness).
613TEST_F(HttpNetworkTransactionTest, BasicAuth) {
[email protected]af4876d2008-10-21 23:10:57614 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
615 CreateSession(), &mock_socket_factory));
[email protected]038e9a32008-10-08 22:40:16616
617 net::HttpRequestInfo request;
618 request.method = "GET";
619 request.url = GURL("http://www.google.com/");
620 request.load_flags = 0;
621
[email protected]f9ee6b52008-11-08 06:46:23622 MockWrite data_writes1[] = {
623 MockWrite("GET / HTTP/1.1\r\n"
624 "Host: www.google.com\r\n"
625 "Connection: keep-alive\r\n\r\n"),
626 };
627
[email protected]038e9a32008-10-08 22:40:16628 MockRead data_reads1[] = {
629 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
630 // Give a couple authenticate options (only the middle one is actually
631 // supported).
[email protected]aaead502008-10-15 00:20:11632 MockRead("WWW-Authenticate: Basic\r\n"), // Malformed
[email protected]038e9a32008-10-08 22:40:16633 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
634 MockRead("WWW-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"),
635 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
636 // Large content-length -- won't matter, as connection will be reset.
637 MockRead("Content-Length: 10000\r\n\r\n"),
638 MockRead(false, net::ERR_FAILED),
639 };
640
641 // After calling trans->RestartWithAuth(), this is the request we should
642 // be issuing -- the final header line contains the credentials.
643 MockWrite data_writes2[] = {
644 MockWrite("GET / HTTP/1.1\r\n"
645 "Host: www.google.com\r\n"
646 "Connection: keep-alive\r\n"
647 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
648 };
649
650 // Lastly, the server responds with the actual content.
651 MockRead data_reads2[] = {
652 MockRead("HTTP/1.0 200 OK\r\n"),
653 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
654 MockRead("Content-Length: 100\r\n\r\n"),
655 MockRead(false, net::OK),
656 };
657
658 MockSocket data1;
659 data1.reads = data_reads1;
[email protected]f9ee6b52008-11-08 06:46:23660 data1.writes = data_writes1;
[email protected]038e9a32008-10-08 22:40:16661 MockSocket data2;
662 data2.reads = data_reads2;
663 data2.writes = data_writes2;
664 mock_sockets[0] = &data1;
665 mock_sockets[1] = &data2;
666 mock_sockets[2] = NULL;
667
668 TestCompletionCallback callback1;
669
670 int rv = trans->Start(&request, &callback1);
671 EXPECT_EQ(net::ERR_IO_PENDING, rv);
672
673 rv = callback1.WaitForResult();
674 EXPECT_EQ(net::OK, rv);
675
676 const net::HttpResponseInfo* response = trans->GetResponseInfo();
677 EXPECT_FALSE(response == NULL);
678
679 // The password prompt info should have been set in response->auth_challenge.
680 EXPECT_FALSE(response->auth_challenge.get() == NULL);
681
682 // TODO(eroman): this should really include the effective port (80)
683 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
684 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
685 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
686
687 TestCompletionCallback callback2;
688
689 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
690 EXPECT_EQ(net::ERR_IO_PENDING, rv);
691
692 rv = callback2.WaitForResult();
693 EXPECT_EQ(net::OK, rv);
694
695 response = trans->GetResponseInfo();
696 EXPECT_FALSE(response == NULL);
697 EXPECT_TRUE(response->auth_challenge.get() == NULL);
698 EXPECT_EQ(100, response->headers->GetContentLength());
[email protected]038e9a32008-10-08 22:40:16699}
700
701// Test the flow when both the proxy server AND origin server require
702// authentication. Again, this uses basic auth for both since that is
703// the simplest to mock.
704TEST_F(HttpNetworkTransactionTest, BasicAuthProxyThenServer) {
705 net::ProxyInfo proxy_info;
706 proxy_info.UseNamedProxy("myproxy:70");
707
708 // Configure against proxy server "myproxy:70".
[email protected]af4876d2008-10-21 23:10:57709 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
[email protected]038e9a32008-10-08 22:40:16710 CreateSession(new net::ProxyResolverFixed(proxy_info)),
[email protected]af4876d2008-10-21 23:10:57711 &mock_socket_factory));
[email protected]038e9a32008-10-08 22:40:16712
713 net::HttpRequestInfo request;
714 request.method = "GET";
715 request.url = GURL("http://www.google.com/");
716 request.load_flags = 0;
717
[email protected]f9ee6b52008-11-08 06:46:23718 MockWrite data_writes1[] = {
719 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
720 "Host: www.google.com\r\n"
721 "Proxy-Connection: keep-alive\r\n\r\n"),
722 };
723
[email protected]038e9a32008-10-08 22:40:16724 MockRead data_reads1[] = {
725 MockRead("HTTP/1.0 407 Unauthorized\r\n"),
726 // Give a couple authenticate options (only the middle one is actually
727 // supported).
[email protected]aaead502008-10-15 00:20:11728 MockRead("Proxy-Authenticate: Basic\r\n"), // Malformed
[email protected]038e9a32008-10-08 22:40:16729 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
730 MockRead("Proxy-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"),
731 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
732 // Large content-length -- won't matter, as connection will be reset.
733 MockRead("Content-Length: 10000\r\n\r\n"),
734 MockRead(false, net::ERR_FAILED),
735 };
736
737 // After calling trans->RestartWithAuth() the first time, this is the
738 // request we should be issuing -- the final header line contains the
739 // proxy's credentials.
740 MockWrite data_writes2[] = {
741 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
742 "Host: www.google.com\r\n"
743 "Proxy-Connection: keep-alive\r\n"
744 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
745 };
746
747 // Now the proxy server lets the request pass through to origin server.
748 // The origin server responds with a 401.
749 MockRead data_reads2[] = {
750 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
751 // Note: We are using the same realm-name as the proxy server. This is
752 // completely valid, as realms are unique across hosts.
753 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
754 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
755 MockRead("Content-Length: 2000\r\n\r\n"),
[email protected]aaead502008-10-15 00:20:11756 MockRead(false, net::ERR_FAILED), // Won't be reached.
[email protected]038e9a32008-10-08 22:40:16757 };
758
759 // After calling trans->RestartWithAuth() the second time, we should send
760 // the credentials for both the proxy and origin server.
761 MockWrite data_writes3[] = {
762 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
763 "Host: www.google.com\r\n"
764 "Proxy-Connection: keep-alive\r\n"
765 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n"
766 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"),
767 };
768
769 // Lastly we get the desired content.
770 MockRead data_reads3[] = {
771 MockRead("HTTP/1.0 200 OK\r\n"),
772 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
773 MockRead("Content-Length: 100\r\n\r\n"),
774 MockRead(false, net::OK),
775 };
776
777 MockSocket data1;
778 data1.reads = data_reads1;
[email protected]f9ee6b52008-11-08 06:46:23779 data1.writes = data_writes1;
[email protected]038e9a32008-10-08 22:40:16780 MockSocket data2;
781 data2.reads = data_reads2;
782 data2.writes = data_writes2;
783 MockSocket data3;
784 data3.reads = data_reads3;
785 data3.writes = data_writes3;
786 mock_sockets[0] = &data1;
787 mock_sockets[1] = &data2;
788 mock_sockets[2] = &data3;
789 mock_sockets[3] = NULL;
790
791 TestCompletionCallback callback1;
792
793 int rv = trans->Start(&request, &callback1);
794 EXPECT_EQ(net::ERR_IO_PENDING, rv);
795
796 rv = callback1.WaitForResult();
797 EXPECT_EQ(net::OK, rv);
798
799 const net::HttpResponseInfo* response = trans->GetResponseInfo();
800 EXPECT_FALSE(response == NULL);
801
802 // The password prompt info should have been set in response->auth_challenge.
803 EXPECT_FALSE(response->auth_challenge.get() == NULL);
804
805 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host);
806 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
807 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
808
809 TestCompletionCallback callback2;
810
811 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
812 EXPECT_EQ(net::ERR_IO_PENDING, rv);
813
814 rv = callback2.WaitForResult();
815 EXPECT_EQ(net::OK, rv);
816
817 response = trans->GetResponseInfo();
818 EXPECT_FALSE(response == NULL);
819 EXPECT_FALSE(response->auth_challenge.get() == NULL);
820
821 // TODO(eroman): this should really include the effective port (80)
822 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
823 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
824 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
825
826 TestCompletionCallback callback3;
827
828 rv = trans->RestartWithAuth(L"foo2", L"bar2", &callback3);
829 EXPECT_EQ(net::ERR_IO_PENDING, rv);
830
831 rv = callback3.WaitForResult();
832 EXPECT_EQ(net::OK, rv);
833
834 response = trans->GetResponseInfo();
835 EXPECT_TRUE(response->auth_challenge.get() == NULL);
836 EXPECT_EQ(100, response->headers->GetContentLength());
[email protected]038e9a32008-10-08 22:40:16837}
[email protected]4ddaf2502008-10-23 18:26:19838
839// Test reading a server response which has only headers, and no body.
840// After some maximum number of bytes is consumed, the transaction should
841// fail with ERR_RESPONSE_HEADERS_TOO_BIG.
842TEST_F(HttpNetworkTransactionTest, LargeHeadersNoBody) {
843 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
844 CreateSession(), &mock_socket_factory));
845
846 net::HttpRequestInfo request;
847 request.method = "GET";
848 request.url = GURL("http://www.google.com/");
849 request.load_flags = 0;
850
851 // Respond with 50 kb of headers (we should fail after 32 kb).
[email protected]15a5ccf82008-10-23 19:57:43852 std::string large_headers_string;
853 FillLargeHeadersString(&large_headers_string, 50 * 1024);
[email protected]4ddaf2502008-10-23 18:26:19854
855 MockRead data_reads[] = {
856 MockRead("HTTP/1.0 200 OK\r\n"),
[email protected]15a5ccf82008-10-23 19:57:43857 MockRead(true, large_headers_string.data(), large_headers_string.size()),
[email protected]4ddaf2502008-10-23 18:26:19858 MockRead("\r\nBODY"),
859 MockRead(false, net::OK),
860 };
861 MockSocket data;
862 data.reads = data_reads;
863 mock_sockets[0] = &data;
864 mock_sockets[1] = NULL;
865
866 TestCompletionCallback callback;
867
868 int rv = trans->Start(&request, &callback);
869 EXPECT_EQ(net::ERR_IO_PENDING, rv);
870
871 rv = callback.WaitForResult();
872 EXPECT_EQ(net::ERR_RESPONSE_HEADERS_TOO_BIG, rv);
873
874 const net::HttpResponseInfo* response = trans->GetResponseInfo();
875 EXPECT_TRUE(response == NULL);
876}
[email protected]f4e426b2008-11-05 00:24:49877
878// Make sure that we don't try to reuse a TCPClientSocket when failing to
879// establish tunnel.
880// http://code.google.com/p/chromium/issues/detail?id=3772
881TEST_F(HttpNetworkTransactionTest, DontRecycleTCPSocketForSSLTunnel) {
882 // Configure against proxy server "myproxy:70".
883 net::ProxyInfo proxy_info;
884 proxy_info.UseNamedProxy("myproxy:70");
885
886 scoped_refptr<net::HttpNetworkSession> session(
887 CreateSession(new net::ProxyResolverFixed(proxy_info)));
888
889 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
890 session.get(), &mock_socket_factory));
891
892 net::HttpRequestInfo request;
893 request.method = "GET";
894 request.url = GURL("https://www.google.com/");
895 request.load_flags = 0;
896
897 // Since we have proxy, should try to establish tunnel.
898 MockWrite data_writes1[] = {
899 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
900 "Host: www.google.com\r\n\r\n"),
901 };
902
[email protected]77848d12008-11-14 00:00:22903 // The proxy responds to the connect with a 404, using a persistent
[email protected]f4e426b2008-11-05 00:24:49904 // connection. Usually a proxy would return 501 (not implemented),
905 // or 200 (tunnel established).
906 MockRead data_reads1[] = {
907 MockRead("HTTP/1.1 404 Not Found\r\n"),
908 MockRead("Content-Length: 10\r\n\r\n"),
909 MockRead("0123456789"),
[email protected]77848d12008-11-14 00:00:22910 MockRead(false, net::ERR_UNEXPECTED), // Should not be reached.
[email protected]f4e426b2008-11-05 00:24:49911 };
912
913 MockSocket data1;
914 data1.writes = data_writes1;
915 data1.reads = data_reads1;
916 mock_sockets[0] = &data1;
917 mock_sockets[1] = NULL;
918
919 TestCompletionCallback callback1;
920
921 int rv = trans->Start(&request, &callback1);
922 EXPECT_EQ(net::ERR_IO_PENDING, rv);
923
924 rv = callback1.WaitForResult();
925 EXPECT_EQ(net::OK, rv);
926
927 const net::HttpResponseInfo* response = trans->GetResponseInfo();
928 EXPECT_FALSE(response == NULL);
929
930 EXPECT_TRUE(response->headers->IsKeepAlive());
931 EXPECT_EQ(404, response->headers->response_code());
932 EXPECT_EQ(10, response->headers->GetContentLength());
933 EXPECT_TRUE(net::HttpVersion(1, 1) == response->headers->GetHttpVersion());
[email protected]77848d12008-11-14 00:00:22934
[email protected]f4e426b2008-11-05 00:24:49935 std::string response_data;
936 rv = ReadTransaction(trans.get(), &response_data);
937 EXPECT_STREQ("0123456789", response_data.c_str());
938
939 // We now check to make sure the TCPClientSocket was not added back to
940 // the pool.
941 EXPECT_EQ(0, session->connection_pool()->idle_socket_count());
942 trans.reset();
943 // Make sure that the socket didn't get recycled after calling the destructor.
944 EXPECT_EQ(0, session->connection_pool()->idle_socket_count());
945}
[email protected]372d34a2008-11-05 21:30:51946
947TEST_F(HttpNetworkTransactionTest, ResendRequestOnWriteBodyError) {
948 net::HttpRequestInfo request[2];
949 // Transaction 1: a GET request that succeeds. The socket is recycled
950 // after use.
951 request[0].method = "GET";
952 request[0].url = GURL("http://www.google.com/");
953 request[0].load_flags = 0;
954 // Transaction 2: a POST request. Reuses the socket kept alive from
955 // transaction 1. The first attempts fails when writing the POST data.
956 // This causes the transaction to retry with a new socket. The second
957 // attempt succeeds.
958 request[1].method = "POST";
959 request[1].url = GURL("http://www.google.com/login.cgi");
960 request[1].upload_data = new net::UploadData;
961 request[1].upload_data->AppendBytes("foo", 3);
962 request[1].load_flags = 0;
963
964 scoped_refptr<net::HttpNetworkSession> session = CreateSession();
965
966 // The first socket is used for transaction 1 and the first attempt of
967 // transaction 2.
968
969 // The response of transaction 1.
970 MockRead data_reads1[] = {
971 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\n"),
972 MockRead("hello world"),
973 MockRead(false, net::OK),
974 };
975 // The mock write results of transaction 1 and the first attempt of
976 // transaction 2.
977 MockWrite data_writes1[] = {
978 MockWrite(false, 64), // GET
979 MockWrite(false, 93), // POST
980 MockWrite(false, net::ERR_CONNECTION_ABORTED), // POST data
981 };
982 MockSocket data1;
983 data1.reads = data_reads1;
984 data1.writes = data_writes1;
985
986 // The second socket is used for the second attempt of transaction 2.
987
988 // The response of transaction 2.
989 MockRead data_reads2[] = {
990 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 7\r\n\r\n"),
991 MockRead("welcome"),
992 MockRead(false, net::OK),
993 };
994 // The mock write results of the second attempt of transaction 2.
995 MockWrite data_writes2[] = {
996 MockWrite(false, 93), // POST
997 MockWrite(false, 3), // POST data
998 };
999 MockSocket data2;
1000 data2.reads = data_reads2;
1001 data2.writes = data_writes2;
1002
1003 mock_sockets[0] = &data1;
1004 mock_sockets[1] = &data2;
1005 mock_sockets[2] = NULL;
1006
1007 const char* kExpectedResponseData[] = {
1008 "hello world", "welcome"
1009 };
1010
1011 for (int i = 0; i < 2; ++i) {
1012 scoped_ptr<net::HttpTransaction> trans(
1013 new net::HttpNetworkTransaction(session, &mock_socket_factory));
1014
1015 TestCompletionCallback callback;
1016
1017 int rv = trans->Start(&request[i], &callback);
1018 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1019
1020 rv = callback.WaitForResult();
1021 EXPECT_EQ(net::OK, rv);
1022
1023 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1024 EXPECT_TRUE(response != NULL);
1025
1026 EXPECT_TRUE(response->headers != NULL);
1027 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
1028
1029 std::string response_data;
1030 rv = ReadTransaction(trans.get(), &response_data);
1031 EXPECT_EQ(net::OK, rv);
1032 EXPECT_EQ(kExpectedResponseData[i], response_data);
1033 }
1034}
[email protected]f9ee6b52008-11-08 06:46:231035
1036// Test the request-challenge-retry sequence for basic auth when there is
1037// an identity in the URL. The request should be sent as normal, but when
1038// it fails the identity from the URL is used to answer the challenge.
1039TEST_F(HttpNetworkTransactionTest, AuthIdentityInUrl) {
1040 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1041 CreateSession(), &mock_socket_factory));
1042
1043 net::HttpRequestInfo request;
1044 request.method = "GET";
1045 // Note: the URL has a username:password in it.
1046 request.url = GURL("http://foo:[email protected]/");
1047 request.load_flags = 0;
1048
1049 MockWrite data_writes1[] = {
1050 MockWrite("GET / HTTP/1.1\r\n"
1051 "Host: www.google.com\r\n"
1052 "Connection: keep-alive\r\n\r\n"),
1053 };
1054
1055 MockRead data_reads1[] = {
1056 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
1057 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1058 MockRead("Content-Length: 10\r\n\r\n"),
1059 MockRead(false, net::ERR_FAILED),
1060 };
1061
1062 // After the challenge above, the transaction will be restarted using the
1063 // identity from the url (foo, bar) to answer the challenge.
1064 MockWrite data_writes2[] = {
1065 MockWrite("GET / HTTP/1.1\r\n"
1066 "Host: www.google.com\r\n"
1067 "Connection: keep-alive\r\n"
1068 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1069 };
1070
1071 MockRead data_reads2[] = {
1072 MockRead("HTTP/1.0 200 OK\r\n"),
1073 MockRead("Content-Length: 100\r\n\r\n"),
1074 MockRead(false, net::OK),
1075 };
1076
1077 MockSocket data1;
1078 data1.reads = data_reads1;
1079 data1.writes = data_writes1;
1080 MockSocket data2;
1081 data2.reads = data_reads2;
1082 data2.writes = data_writes2;
1083 mock_sockets[0] = &data1;
1084 mock_sockets[1] = &data2;
1085 mock_sockets[2] = NULL;
1086
1087 TestCompletionCallback callback1;
1088
1089 int rv = trans->Start(&request, &callback1);
1090 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1091
1092 rv = callback1.WaitForResult();
1093 EXPECT_EQ(net::OK, rv);
1094
1095 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1096 EXPECT_FALSE(response == NULL);
1097
1098 // There is no challenge info, since the identity in URL worked.
1099 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1100
1101 EXPECT_EQ(100, response->headers->GetContentLength());
1102
1103 // Empty the current queue.
1104 MessageLoop::current()->RunAllPending();
1105}
1106
1107// Test that previously tried username/passwords for a realm get re-used.
1108TEST_F(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
1109 scoped_refptr<net::HttpNetworkSession> session = CreateSession();
1110
1111 // Transaction 1: authenticate (foo, bar) on MyRealm1
1112 {
1113 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1114 session, &mock_socket_factory));
1115
1116 net::HttpRequestInfo request;
1117 request.method = "GET";
1118 request.url = GURL("http://www.google.com/x/y/z");
1119 request.load_flags = 0;
1120
1121 MockWrite data_writes1[] = {
1122 MockWrite("GET /x/y/z HTTP/1.1\r\n"
1123 "Host: www.google.com\r\n"
1124 "Connection: keep-alive\r\n\r\n"),
1125 };
1126
1127 MockRead data_reads1[] = {
1128 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
1129 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1130 MockRead("Content-Length: 10000\r\n\r\n"),
1131 MockRead(false, net::ERR_FAILED),
1132 };
1133
1134 // Resend with authorization (username=foo, password=bar)
1135 MockWrite data_writes2[] = {
1136 MockWrite("GET /x/y/z HTTP/1.1\r\n"
1137 "Host: www.google.com\r\n"
1138 "Connection: keep-alive\r\n"
1139 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1140 };
1141
1142 // Sever accepts the authorization.
1143 MockRead data_reads2[] = {
1144 MockRead("HTTP/1.0 200 OK\r\n"),
1145 MockRead("Content-Length: 100\r\n\r\n"),
1146 MockRead(false, net::OK),
1147 };
1148
1149 MockSocket data1;
1150 data1.reads = data_reads1;
1151 data1.writes = data_writes1;
1152 MockSocket data2;
1153 data2.reads = data_reads2;
1154 data2.writes = data_writes2;
1155 mock_sockets_index = 0;
1156 mock_sockets[0] = &data1;
1157 mock_sockets[1] = &data2;
1158 mock_sockets[2] = NULL;
1159
1160 TestCompletionCallback callback1;
1161
1162 int rv = trans->Start(&request, &callback1);
1163 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1164
1165 rv = callback1.WaitForResult();
1166 EXPECT_EQ(net::OK, rv);
1167
1168 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1169 EXPECT_FALSE(response == NULL);
1170
1171 // The password prompt info should have been set in
1172 // response->auth_challenge.
1173 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1174
1175 // TODO(eroman): this should really include the effective port (80)
1176 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
1177 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1178 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1179
1180 TestCompletionCallback callback2;
1181
1182 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
1183 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1184
1185 rv = callback2.WaitForResult();
1186 EXPECT_EQ(net::OK, rv);
1187
1188 response = trans->GetResponseInfo();
1189 EXPECT_FALSE(response == NULL);
1190 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1191 EXPECT_EQ(100, response->headers->GetContentLength());
1192 }
1193
1194 // ------------------------------------------------------------------------
1195
1196 // Transaction 2: authenticate (foo2, bar2) on MyRealm2
1197 {
1198 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1199 session, &mock_socket_factory));
1200
1201 net::HttpRequestInfo request;
1202 request.method = "GET";
1203 // Note that Transaction 1 was at /x/y/z, so this is in the same
1204 // protection space as MyRealm1.
1205 request.url = GURL("http://www.google.com/x/y/a/b");
1206 request.load_flags = 0;
1207
1208 MockWrite data_writes1[] = {
1209 MockWrite("GET /x/y/a/b HTTP/1.1\r\n"
1210 "Host: www.google.com\r\n"
1211 "Connection: keep-alive\r\n"
1212 // Send preemptive authorization for MyRealm1
1213 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1214 };
1215
1216 // The server didn't like the preemptive authorization, and
1217 // challenges us for a different realm (MyRealm2).
1218 MockRead data_reads1[] = {
1219 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
1220 MockRead("WWW-Authenticate: Basic realm=\"MyRealm2\"\r\n"),
1221 MockRead("Content-Length: 10000\r\n\r\n"),
1222 MockRead(false, net::ERR_FAILED),
1223 };
1224
1225 // Resend with authorization for MyRealm2 (username=foo2, password=bar2)
1226 MockWrite data_writes2[] = {
1227 MockWrite("GET /x/y/a/b HTTP/1.1\r\n"
1228 "Host: www.google.com\r\n"
1229 "Connection: keep-alive\r\n"
1230 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"),
1231 };
1232
1233 // Sever accepts the authorization.
1234 MockRead data_reads2[] = {
1235 MockRead("HTTP/1.0 200 OK\r\n"),
1236 MockRead("Content-Length: 100\r\n\r\n"),
1237 MockRead(false, net::OK),
1238 };
1239
1240 MockSocket data1;
1241 data1.reads = data_reads1;
1242 data1.writes = data_writes1;
1243 MockSocket data2;
1244 data2.reads = data_reads2;
1245 data2.writes = data_writes2;
1246 mock_sockets_index = 0;
1247 mock_sockets[0] = &data1;
1248 mock_sockets[1] = &data2;
1249 mock_sockets[2] = NULL;
1250
1251 TestCompletionCallback callback1;
1252
1253 int rv = trans->Start(&request, &callback1);
1254 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1255
1256 rv = callback1.WaitForResult();
1257 EXPECT_EQ(net::OK, rv);
1258
1259 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1260 EXPECT_FALSE(response == NULL);
1261
1262 // The password prompt info should have been set in
1263 // response->auth_challenge.
1264 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1265
1266 // TODO(eroman): this should really include the effective port (80)
1267 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
1268 EXPECT_EQ(L"MyRealm2", response->auth_challenge->realm);
1269 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1270
1271 TestCompletionCallback callback2;
1272
1273 rv = trans->RestartWithAuth(L"foo2", L"bar2", &callback2);
1274 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1275
1276 rv = callback2.WaitForResult();
1277 EXPECT_EQ(net::OK, rv);
1278
1279 response = trans->GetResponseInfo();
1280 EXPECT_FALSE(response == NULL);
1281 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1282 EXPECT_EQ(100, response->headers->GetContentLength());
1283 }
1284
1285 // ------------------------------------------------------------------------
1286
1287 // Transaction 3: Resend a request in MyRealm's protection space --
1288 // succeed with preemptive authorization.
1289 {
1290 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1291 session, &mock_socket_factory));
1292
1293 net::HttpRequestInfo request;
1294 request.method = "GET";
1295 request.url = GURL("http://www.google.com/x/y/z2");
1296 request.load_flags = 0;
1297
1298 MockWrite data_writes1[] = {
1299 MockWrite("GET /x/y/z2 HTTP/1.1\r\n"
1300 "Host: www.google.com\r\n"
1301 "Connection: keep-alive\r\n"
1302 // The authorization for MyRealm1 gets sent preemptively
1303 // (since the url is in the same protection space)
1304 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1305 };
1306
1307 // Sever accepts the preemptive authorization
1308 MockRead data_reads1[] = {
1309 MockRead("HTTP/1.0 200 OK\r\n"),
1310 MockRead("Content-Length: 100\r\n\r\n"),
1311 MockRead(false, net::OK),
1312 };
1313
1314 MockSocket data1;
1315 data1.reads = data_reads1;
1316 data1.writes = data_writes1;
1317 mock_sockets_index = 0;
1318 mock_sockets[0] = &data1;
1319 mock_sockets[1] = NULL;
1320
1321 TestCompletionCallback callback1;
1322
1323 int rv = trans->Start(&request, &callback1);
1324 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1325
1326 rv = callback1.WaitForResult();
1327 EXPECT_EQ(net::OK, rv);
1328
1329 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1330 EXPECT_FALSE(response == NULL);
1331
1332 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1333 EXPECT_EQ(100, response->headers->GetContentLength());
1334 }
1335
1336 // ------------------------------------------------------------------------
1337
1338 // Transaction 4: request another URL in MyRealm (however the
1339 // url is not known to belong to the protection space, so no pre-auth).
1340 {
1341 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1342 session, &mock_socket_factory));
1343
1344 net::HttpRequestInfo request;
1345 request.method = "GET";
1346 request.url = GURL("http://www.google.com/x/1");
1347 request.load_flags = 0;
1348
1349 MockWrite data_writes1[] = {
1350 MockWrite("GET /x/1 HTTP/1.1\r\n"
1351 "Host: www.google.com\r\n"
1352 "Connection: keep-alive\r\n\r\n"),
1353 };
1354
1355 MockRead data_reads1[] = {
1356 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
1357 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1358 MockRead("Content-Length: 10000\r\n\r\n"),
1359 MockRead(false, net::ERR_FAILED),
1360 };
1361
1362 // Resend with authorization from MyRealm's cache.
1363 MockWrite data_writes2[] = {
1364 MockWrite("GET /x/1 HTTP/1.1\r\n"
1365 "Host: www.google.com\r\n"
1366 "Connection: keep-alive\r\n"
1367 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1368 };
1369
1370 // Sever accepts the authorization.
1371 MockRead data_reads2[] = {
1372 MockRead("HTTP/1.0 200 OK\r\n"),
1373 MockRead("Content-Length: 100\r\n\r\n"),
1374 MockRead(false, net::OK),
1375 };
1376
1377 MockSocket data1;
1378 data1.reads = data_reads1;
1379 data1.writes = data_writes1;
1380 MockSocket data2;
1381 data2.reads = data_reads2;
1382 data2.writes = data_writes2;
1383 mock_sockets_index = 0;
1384 mock_sockets[0] = &data1;
1385 mock_sockets[1] = &data2;
1386 mock_sockets[2] = NULL;
1387
1388 TestCompletionCallback callback1;
1389
1390 int rv = trans->Start(&request, &callback1);
1391 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1392
1393 rv = callback1.WaitForResult();
1394 EXPECT_EQ(net::OK, rv);
1395
1396 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1397 EXPECT_FALSE(response == NULL);
1398 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1399 EXPECT_EQ(100, response->headers->GetContentLength());
1400 }
1401
1402 // ------------------------------------------------------------------------
1403
1404 // Transaction 5: request a URL in MyRealm, but the server rejects the
1405 // cached identity. Should invalidate and re-prompt.
1406 {
1407 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1408 session, &mock_socket_factory));
1409
1410 net::HttpRequestInfo request;
1411 request.method = "GET";
1412 request.url = GURL("http://www.google.com/p/q/t");
1413 request.load_flags = 0;
1414
1415 MockWrite data_writes1[] = {
1416 MockWrite("GET /p/q/t 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: 10000\r\n\r\n"),
1425 MockRead(false, net::ERR_FAILED),
1426 };
1427
1428 // Resend with authorization from cache for MyRealm.
1429 MockWrite data_writes2[] = {
1430 MockWrite("GET /p/q/t HTTP/1.1\r\n"
1431 "Host: www.google.com\r\n"
1432 "Connection: keep-alive\r\n"
1433 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1434 };
1435
1436 // Sever rejects the authorization.
1437 MockRead data_reads2[] = {
1438 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
1439 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1440 MockRead("Content-Length: 10000\r\n\r\n"),
1441 MockRead(false, net::ERR_FAILED),
1442 };
1443
1444 // At this point we should prompt for new credentials for MyRealm.
1445 // Restart with username=foo3, password=foo4.
1446 MockWrite data_writes3[] = {
1447 MockWrite("GET /p/q/t HTTP/1.1\r\n"
1448 "Host: www.google.com\r\n"
1449 "Connection: keep-alive\r\n"
1450 "Authorization: Basic Zm9vMzpiYXIz\r\n\r\n"),
1451 };
1452
1453 // Sever accepts the authorization.
1454 MockRead data_reads3[] = {
1455 MockRead("HTTP/1.0 200 OK\r\n"),
1456 MockRead("Content-Length: 100\r\n\r\n"),
1457 MockRead(false, net::OK),
1458 };
1459
1460 MockSocket data1;
1461 data1.reads = data_reads1;
1462 data1.writes = data_writes1;
1463 MockSocket data2;
1464 data2.reads = data_reads2;
1465 data2.writes = data_writes2;
1466 MockSocket data3;
1467 data3.reads = data_reads3;
1468 data3.writes = data_writes3;
1469 mock_sockets_index = 0;
1470 mock_sockets[0] = &data1;
1471 mock_sockets[1] = &data2;
1472 mock_sockets[2] = &data3;
1473 mock_sockets[3] = NULL;
1474
1475 TestCompletionCallback callback1;
1476
1477 int rv = trans->Start(&request, &callback1);
1478 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1479
1480 rv = callback1.WaitForResult();
1481 EXPECT_EQ(net::OK, rv);
1482
1483 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1484 EXPECT_FALSE(response == NULL);
1485
1486 // The password prompt info should have been set in
1487 // response->auth_challenge.
1488 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1489
1490 // TODO(eroman): this should really include the effective port (80)
1491 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
1492 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1493 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1494
1495 TestCompletionCallback callback2;
1496
1497 rv = trans->RestartWithAuth(L"foo3", L"bar3", &callback2);
1498 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1499
1500 rv = callback2.WaitForResult();
1501 EXPECT_EQ(net::OK, rv);
1502
1503 response = trans->GetResponseInfo();
1504 EXPECT_FALSE(response == NULL);
1505 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1506 EXPECT_EQ(100, response->headers->GetContentLength());
1507 }
1508}