blob: 7b2f04fe47c46d1d95e7da22bfec73bddd61a3a7 [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]68bf9152008-09-25 19:47:305#include "base/compiler_specific.h"
6#include "base/platform_test.h"
initial.commit586acc5fe2008-07-26 22:42:527#include "net/base/client_socket_factory.h"
8#include "net/base/test_completion_callback.h"
9#include "net/base/upload_data.h"
10#include "net/http/http_network_session.h"
11#include "net/http/http_network_transaction.h"
12#include "net/http/http_transaction_unittest.h"
[email protected]038e9a32008-10-08 22:40:1613#include "net/proxy/proxy_resolver_fixed.h"
[email protected]e8d536192008-10-17 22:21:1414#include "net/proxy/proxy_resolver_null.h"
initial.commit586acc5fe2008-07-26 22:42:5215#include "testing/gtest/include/gtest/gtest.h"
16
17//-----------------------------------------------------------------------------
18
initial.commit586acc5fe2008-07-26 22:42:5219
20struct MockConnect {
[email protected]217e6022008-09-29 18:18:3521 // Asynchronous connection success.
22 MockConnect() : async(true), result(net::OK) { }
[email protected]038e9a32008-10-08 22:40:1623
24 bool async;
25 int result;
initial.commit586acc5fe2008-07-26 22:42:5226};
27
28struct MockRead {
[email protected]217e6022008-09-29 18:18:3529 // Read failure (no data).
30 MockRead(bool async, int result) : async(async) , result(result), data(NULL),
31 data_len(0) { }
32
33 // Asynchronous read success (inferred data length).
[email protected]b5462e02008-09-29 18:32:1934 MockRead(const char* data) : async(true), result(0), data(data),
35 data_len(strlen(data)) { }
[email protected]217e6022008-09-29 18:18:3536
37 // Read success (inferred data length).
[email protected]b5462e02008-09-29 18:32:1938 MockRead(bool async, const char* data) : async(async), result(0), data(data),
39 data_len(strlen(data)) { }
[email protected]217e6022008-09-29 18:18:3540
41 // Read success.
42 MockRead(bool async, const char* data, int data_len) : async(async),
[email protected]b5462e02008-09-29 18:32:1943 result(0), data(data), data_len(data_len) { }
[email protected]217e6022008-09-29 18:18:3544
initial.commit586acc5fe2008-07-26 22:42:5245 bool async;
[email protected]217e6022008-09-29 18:18:3546 int result;
initial.commit586acc5fe2008-07-26 22:42:5247 const char* data;
[email protected]217e6022008-09-29 18:18:3548 int data_len;
initial.commit586acc5fe2008-07-26 22:42:5249};
50
[email protected]038e9a32008-10-08 22:40:1651// MockWrite uses the same member fields as MockRead, but with different
52// meanings. The expected input to MockTCPClientSocket::Write() is given
53// by {data, data_len}, and the return value of Write() is controlled by
54// {async, result}.
55typedef MockRead MockWrite;
56
initial.commit586acc5fe2008-07-26 22:42:5257struct MockSocket {
[email protected]038e9a32008-10-08 22:40:1658 MockSocket() : reads(NULL), writes(NULL) { }
[email protected]217e6022008-09-29 18:18:3559
initial.commit586acc5fe2008-07-26 22:42:5260 MockConnect connect;
[email protected]217e6022008-09-29 18:18:3561 MockRead* reads;
[email protected]038e9a32008-10-08 22:40:1662 MockWrite* writes;
initial.commit586acc5fe2008-07-26 22:42:5263};
64
65// Holds an array of MockSocket elements. As MockTCPClientSocket objects get
66// instantiated, they take their data from the i'th element of this array.
67//
68// Tests should assign the first N entries of mock_sockets to point to valid
69// MockSocket objects. The first unused entry should be NULL'd.
70//
71MockSocket* mock_sockets[10];
72
73// Index of the next mock_sockets element to use.
74int mock_sockets_index;
75
76class MockTCPClientSocket : public net::ClientSocket {
77 public:
78 MockTCPClientSocket(const net::AddressList& addresses)
initial.commit586acc5fe2008-07-26 22:42:5279 : data_(mock_sockets[mock_sockets_index++]),
[email protected]68bf9152008-09-25 19:47:3080 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
initial.commit586acc5fe2008-07-26 22:42:5281 callback_(NULL),
82 read_index_(0),
83 read_offset_(0),
[email protected]038e9a32008-10-08 22:40:1684 write_index_(0),
initial.commit586acc5fe2008-07-26 22:42:5285 connected_(false) {
86 DCHECK(data_) << "overran mock_sockets array";
87 }
88 // ClientSocket methods:
89 virtual int Connect(net::CompletionCallback* callback) {
90 DCHECK(!callback_);
91 if (connected_)
92 return net::OK;
93 connected_ = true;
94 if (data_->connect.async) {
95 RunCallbackAsync(callback, data_->connect.result);
96 return net::ERR_IO_PENDING;
97 }
98 return data_->connect.result;
99 }
100 virtual int ReconnectIgnoringLastError(net::CompletionCallback* callback) {
101 NOTREACHED();
102 return net::ERR_FAILED;
103 }
104 virtual void Disconnect() {
105 connected_ = false;
106 callback_ = NULL;
107 }
108 virtual bool IsConnected() const {
109 return connected_;
110 }
111 // Socket methods:
112 virtual int Read(char* buf, int buf_len, net::CompletionCallback* callback) {
113 DCHECK(!callback_);
114 MockRead& r = data_->reads[read_index_];
[email protected]038e9a32008-10-08 22:40:16115 int result = r.result;
initial.commit586acc5fe2008-07-26 22:42:52116 if (r.data) {
initial.commit586acc5fe2008-07-26 22:42:52117 if (r.data_len - read_offset_ > 0) {
118 result = std::min(buf_len, r.data_len - read_offset_);
119 memcpy(buf, r.data + read_offset_, result);
120 read_offset_ += result;
121 if (read_offset_ == r.data_len) {
122 read_index_++;
123 read_offset_ = 0;
124 }
125 } else {
126 result = 0; // EOF
127 }
initial.commit586acc5fe2008-07-26 22:42:52128 }
129 if (r.async) {
130 RunCallbackAsync(callback, result);
131 return net::ERR_IO_PENDING;
132 }
133 return result;
134 }
135 virtual int Write(const char* buf, int buf_len,
136 net::CompletionCallback* callback) {
137 DCHECK(!callback_);
[email protected]038e9a32008-10-08 22:40:16138 // Not using mock writes; succeed synchronously.
139 if (!data_->writes)
140 return buf_len;
[email protected]aaead502008-10-15 00:20:11141
[email protected]038e9a32008-10-08 22:40:16142 // Check that what we are writing matches the expectation.
143 // Then give the mocked return value.
144 MockWrite& w = data_->writes[write_index_];
145 int result = w.result;
146 if (w.data) {
147 std::string expected_data(w.data, w.data_len);
148 std::string actual_data(buf, buf_len);
149 EXPECT_EQ(expected_data, actual_data);
150 if (expected_data != actual_data)
151 return net::ERR_UNEXPECTED;
152 if (result == net::OK)
153 result = w.data_len;
154 }
155 if (w.async) {
156 RunCallbackAsync(callback, result);
157 return net::ERR_IO_PENDING;
158 }
159 return result;
initial.commit586acc5fe2008-07-26 22:42:52160 }
161 private:
162 void RunCallbackAsync(net::CompletionCallback* callback, int result) {
163 callback_ = callback;
164 MessageLoop::current()->PostTask(FROM_HERE,
165 method_factory_.NewRunnableMethod(
166 &MockTCPClientSocket::RunCallback, result));
167 }
168 void RunCallback(int result) {
169 net::CompletionCallback* c = callback_;
170 callback_ = NULL;
171 if (c)
172 c->Run(result);
173 }
174 MockSocket* data_;
175 ScopedRunnableMethodFactory<MockTCPClientSocket> method_factory_;
176 net::CompletionCallback* callback_;
177 int read_index_;
178 int read_offset_;
[email protected]038e9a32008-10-08 22:40:16179 int write_index_;
initial.commit586acc5fe2008-07-26 22:42:52180 bool connected_;
181};
182
183class MockClientSocketFactory : public net::ClientSocketFactory {
184 public:
185 virtual net::ClientSocket* CreateTCPClientSocket(
186 const net::AddressList& addresses) {
187 return new MockTCPClientSocket(addresses);
188 }
[email protected]aaead502008-10-15 00:20:11189 virtual net::SSLClientSocket* CreateSSLClientSocket(
initial.commit586acc5fe2008-07-26 22:42:52190 net::ClientSocket* transport_socket,
[email protected]c5949a32008-10-08 17:28:23191 const std::string& hostname,
[email protected]aaead502008-10-15 00:20:11192 const net::SSLConfig& ssl_config) {
initial.commit586acc5fe2008-07-26 22:42:52193 return NULL;
194 }
195};
196
197MockClientSocketFactory mock_socket_factory;
198
[email protected]e8d536192008-10-17 22:21:14199net::HttpNetworkSession* CreateSession(net::ProxyResolver* proxy_resolver) {
200 if (!proxy_resolver) {
201 proxy_resolver = new net::ProxyResolverNull();
initial.commit586acc5fe2008-07-26 22:42:52202 }
[email protected]038e9a32008-10-08 22:40:16203 return new net::HttpNetworkSession(proxy_resolver);
initial.commit586acc5fe2008-07-26 22:42:52204}
205
[email protected]e8d536192008-10-17 22:21:14206net::HttpNetworkSession* CreateSession() {
207 return CreateSession(NULL);
208}
209
[email protected]89836e22008-09-25 20:33:42210class HttpNetworkTransactionTest : public PlatformTest {
initial.commit586acc5fe2008-07-26 22:42:52211 public:
212 virtual void SetUp() {
[email protected]89836e22008-09-25 20:33:42213 PlatformTest::SetUp();
initial.commit586acc5fe2008-07-26 22:42:52214 mock_sockets[0] = NULL;
215 mock_sockets_index = 0;
216 }
[email protected]3d2a59b2008-09-26 19:44:25217
[email protected]0e75a732008-10-16 20:36:09218 virtual void TearDown() {
219 // Empty the current queue.
220 MessageLoop::current()->RunAllPending();
221 PlatformTest::TearDown();
222 }
223
[email protected]3d2a59b2008-09-26 19:44:25224 protected:
225 void KeepAliveConnectionResendRequestTest(const MockRead& read_failure);
initial.commit586acc5fe2008-07-26 22:42:52226};
227
[email protected]231d5a32008-09-13 00:45:27228struct SimpleGetHelperResult {
[email protected]aecfbf22008-10-16 02:02:47229 int rv;
[email protected]231d5a32008-09-13 00:45:27230 std::string status_line;
231 std::string response_data;
232};
initial.commit586acc5fe2008-07-26 22:42:52233
[email protected]231d5a32008-09-13 00:45:27234SimpleGetHelperResult SimpleGetHelper(MockRead data_reads[]) {
235 SimpleGetHelperResult out;
initial.commit586acc5fe2008-07-26 22:42:52236
initial.commit586acc5fe2008-07-26 22:42:52237 net::HttpTransaction* trans = new net::HttpNetworkTransaction(
238 CreateSession(), &mock_socket_factory);
239
240 net::HttpRequestInfo request;
241 request.method = "GET";
242 request.url = GURL("http://www.google.com/");
243 request.load_flags = 0;
244
initial.commit586acc5fe2008-07-26 22:42:52245 MockSocket data;
initial.commit586acc5fe2008-07-26 22:42:52246 data.reads = data_reads;
247 mock_sockets[0] = &data;
248 mock_sockets[1] = NULL;
249
250 TestCompletionCallback callback;
251
252 int rv = trans->Start(&request, &callback);
253 EXPECT_EQ(net::ERR_IO_PENDING, rv);
254
[email protected]aecfbf22008-10-16 02:02:47255 out.rv = callback.WaitForResult();
[email protected]e8d536192008-10-17 22:21:14256 if (out.rv != net::OK) {
257 trans->Destroy();
[email protected]aecfbf22008-10-16 02:02:47258 return out;
[email protected]e8d536192008-10-17 22:21:14259 }
initial.commit586acc5fe2008-07-26 22:42:52260
261 const net::HttpResponseInfo* response = trans->GetResponseInfo();
262 EXPECT_TRUE(response != NULL);
263
264 EXPECT_TRUE(response->headers != NULL);
[email protected]231d5a32008-09-13 00:45:27265 out.status_line = response->headers->GetStatusLine();
initial.commit586acc5fe2008-07-26 22:42:52266
[email protected]231d5a32008-09-13 00:45:27267 rv = ReadTransaction(trans, &out.response_data);
initial.commit586acc5fe2008-07-26 22:42:52268 EXPECT_EQ(net::OK, rv);
initial.commit586acc5fe2008-07-26 22:42:52269
270 trans->Destroy();
271
[email protected]231d5a32008-09-13 00:45:27272 return out;
273}
274
[email protected]231d5a32008-09-13 00:45:27275//-----------------------------------------------------------------------------
276
277TEST_F(HttpNetworkTransactionTest, Basic) {
278 net::HttpTransaction* trans = new net::HttpNetworkTransaction(
279 CreateSession(), &mock_socket_factory);
280 trans->Destroy();
281}
282
283TEST_F(HttpNetworkTransactionTest, SimpleGET) {
284 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35285 MockRead("HTTP/1.0 200 OK\r\n\r\n"),
286 MockRead("hello world"),
287 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27288 };
[email protected]231d5a32008-09-13 00:45:27289 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47290 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27291 EXPECT_EQ("HTTP/1.0 200 OK", out.status_line);
292 EXPECT_EQ("hello world", out.response_data);
293}
294
295// Response with no status line.
296TEST_F(HttpNetworkTransactionTest, SimpleGETNoHeaders) {
297 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35298 MockRead("hello world"),
299 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27300 };
[email protected]231d5a32008-09-13 00:45:27301 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47302 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27303 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
304 EXPECT_EQ("hello world", out.response_data);
305}
306
307// Allow up to 4 bytes of junk to precede status line.
308TEST_F(HttpNetworkTransactionTest, StatusLineJunk2Bytes) {
309 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35310 MockRead("xxxHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
311 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27312 };
313 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47314 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27315 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
316 EXPECT_EQ("DATA", out.response_data);
317}
318
319// Allow up to 4 bytes of junk to precede status line.
320TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes) {
321 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35322 MockRead("\n\nQJHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
323 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27324 };
325 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47326 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27327 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
328 EXPECT_EQ("DATA", out.response_data);
329}
330
331// Beyond 4 bytes of slop and it should fail to find a status line.
332TEST_F(HttpNetworkTransactionTest, StatusLineJunk5Bytes) {
333 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35334 MockRead("xxxxxHTTP/1.1 404 Not Found\nServer: blah"),
335 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27336 };
337 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47338 EXPECT_EQ(net::OK, out.rv);
[email protected]3d2a59b2008-09-26 19:44:25339 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
340 EXPECT_EQ("xxxxxHTTP/1.1 404 Not Found\nServer: blah", out.response_data);
[email protected]231d5a32008-09-13 00:45:27341}
342
343// Same as StatusLineJunk4Bytes, except the read chunks are smaller.
344TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes_Slow) {
345 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35346 MockRead("\n"),
347 MockRead("\n"),
348 MockRead("Q"),
349 MockRead("J"),
350 MockRead("HTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
351 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27352 };
353 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47354 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27355 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
356 EXPECT_EQ("DATA", out.response_data);
357}
358
359// Close the connection before enough bytes to have a status line.
360TEST_F(HttpNetworkTransactionTest, StatusLinePartial) {
361 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35362 MockRead("HTT"),
363 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27364 };
365 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47366 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27367 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
368 EXPECT_EQ("HTT", out.response_data);
initial.commit586acc5fe2008-07-26 22:42:52369}
370
[email protected]f9d44aa2008-09-23 23:57:17371// Simulate a 204 response, lacking a Content-Length header, sent over a
372// persistent connection. The response should still terminate since a 204
373// cannot have a response body.
374TEST_F(HttpNetworkTransactionTest, StopsReading204) {
375 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35376 MockRead("HTTP/1.1 204 No Content\r\n\r\n"),
377 MockRead("junk"), // Should not be read!!
378 MockRead(false, net::OK),
[email protected]f9d44aa2008-09-23 23:57:17379 };
380 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47381 EXPECT_EQ(net::OK, out.rv);
[email protected]f9d44aa2008-09-23 23:57:17382 EXPECT_EQ("HTTP/1.1 204 No Content", out.status_line);
383 EXPECT_EQ("", out.response_data);
384}
385
initial.commit586acc5fe2008-07-26 22:42:52386TEST_F(HttpNetworkTransactionTest, ReuseConnection) {
387 scoped_refptr<net::HttpNetworkSession> session = CreateSession();
388
389 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35390 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
391 MockRead("hello"),
392 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
393 MockRead("world"),
394 MockRead(false, net::OK),
initial.commit586acc5fe2008-07-26 22:42:52395 };
396 MockSocket data;
initial.commit586acc5fe2008-07-26 22:42:52397 data.reads = data_reads;
398 mock_sockets[0] = &data;
399 mock_sockets[1] = NULL;
400
401 const char* kExpectedResponseData[] = {
402 "hello", "world"
403 };
404
405 for (int i = 0; i < 2; ++i) {
406 net::HttpTransaction* trans =
407 new net::HttpNetworkTransaction(session, &mock_socket_factory);
408
409 net::HttpRequestInfo request;
410 request.method = "GET";
411 request.url = GURL("http://www.google.com/");
412 request.load_flags = 0;
413
414 TestCompletionCallback callback;
415
416 int rv = trans->Start(&request, &callback);
417 EXPECT_EQ(net::ERR_IO_PENDING, rv);
418
419 rv = callback.WaitForResult();
420 EXPECT_EQ(net::OK, rv);
421
422 const net::HttpResponseInfo* response = trans->GetResponseInfo();
423 EXPECT_TRUE(response != NULL);
424
425 EXPECT_TRUE(response->headers != NULL);
[email protected]3d2a59b2008-09-26 19:44:25426 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
initial.commit586acc5fe2008-07-26 22:42:52427
428 std::string response_data;
429 rv = ReadTransaction(trans, &response_data);
430 EXPECT_EQ(net::OK, rv);
[email protected]3d2a59b2008-09-26 19:44:25431 EXPECT_EQ(kExpectedResponseData[i], response_data);
initial.commit586acc5fe2008-07-26 22:42:52432
433 trans->Destroy();
initial.commit586acc5fe2008-07-26 22:42:52434 }
435}
436
437TEST_F(HttpNetworkTransactionTest, Ignores100) {
438 net::HttpTransaction* trans = new net::HttpNetworkTransaction(
439 CreateSession(), &mock_socket_factory);
440
441 net::HttpRequestInfo request;
442 request.method = "POST";
443 request.url = GURL("http://www.foo.com/");
444 request.upload_data = new net::UploadData;
445 request.upload_data->AppendBytes("foo", 3);
446 request.load_flags = 0;
447
448 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35449 MockRead("HTTP/1.0 100 Continue\r\n\r\n"),
450 MockRead("HTTP/1.0 200 OK\r\n\r\n"),
451 MockRead("hello world"),
452 MockRead(false, net::OK),
initial.commit586acc5fe2008-07-26 22:42:52453 };
454 MockSocket data;
initial.commit586acc5fe2008-07-26 22:42:52455 data.reads = data_reads;
456 mock_sockets[0] = &data;
457 mock_sockets[1] = NULL;
458
459 TestCompletionCallback callback;
460
461 int rv = trans->Start(&request, &callback);
462 EXPECT_EQ(net::ERR_IO_PENDING, rv);
463
464 rv = callback.WaitForResult();
465 EXPECT_EQ(net::OK, rv);
466
467 const net::HttpResponseInfo* response = trans->GetResponseInfo();
468 EXPECT_TRUE(response != NULL);
469
470 EXPECT_TRUE(response->headers != NULL);
[email protected]3d2a59b2008-09-26 19:44:25471 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine());
initial.commit586acc5fe2008-07-26 22:42:52472
473 std::string response_data;
474 rv = ReadTransaction(trans, &response_data);
475 EXPECT_EQ(net::OK, rv);
[email protected]3d2a59b2008-09-26 19:44:25476 EXPECT_EQ("hello world", response_data);
initial.commit586acc5fe2008-07-26 22:42:52477
478 trans->Destroy();
initial.commit586acc5fe2008-07-26 22:42:52479}
480
[email protected]3d2a59b2008-09-26 19:44:25481// read_failure specifies a read failure that should cause the network
482// transaction to resend the request.
483void HttpNetworkTransactionTest::KeepAliveConnectionResendRequestTest(
484 const MockRead& read_failure) {
initial.commit586acc5fe2008-07-26 22:42:52485 scoped_refptr<net::HttpNetworkSession> session = CreateSession();
486
487 net::HttpRequestInfo request;
488 request.method = "GET";
489 request.url = GURL("http://www.foo.com/");
490 request.load_flags = 0;
491
492 MockRead data1_reads[] = {
[email protected]217e6022008-09-29 18:18:35493 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
494 MockRead("hello"),
[email protected]3d2a59b2008-09-26 19:44:25495 read_failure, // Now, we reuse the connection and fail the first read.
initial.commit586acc5fe2008-07-26 22:42:52496 };
497 MockSocket data1;
initial.commit586acc5fe2008-07-26 22:42:52498 data1.reads = data1_reads;
499 mock_sockets[0] = &data1;
500
501 MockRead data2_reads[] = {
[email protected]217e6022008-09-29 18:18:35502 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
503 MockRead("world"),
504 MockRead(true, net::OK),
initial.commit586acc5fe2008-07-26 22:42:52505 };
506 MockSocket data2;
initial.commit586acc5fe2008-07-26 22:42:52507 data2.reads = data2_reads;
508 mock_sockets[1] = &data2;
509
510 const char* kExpectedResponseData[] = {
511 "hello", "world"
512 };
513
514 for (int i = 0; i < 2; ++i) {
515 TestCompletionCallback callback;
516
517 net::HttpTransaction* trans =
518 new net::HttpNetworkTransaction(session, &mock_socket_factory);
519
520 int rv = trans->Start(&request, &callback);
521 EXPECT_EQ(net::ERR_IO_PENDING, rv);
522
523 rv = callback.WaitForResult();
524 EXPECT_EQ(net::OK, rv);
525
526 const net::HttpResponseInfo* response = trans->GetResponseInfo();
527 EXPECT_TRUE(response != NULL);
528
529 EXPECT_TRUE(response->headers != NULL);
[email protected]3d2a59b2008-09-26 19:44:25530 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
initial.commit586acc5fe2008-07-26 22:42:52531
532 std::string response_data;
533 rv = ReadTransaction(trans, &response_data);
534 EXPECT_EQ(net::OK, rv);
[email protected]3d2a59b2008-09-26 19:44:25535 EXPECT_EQ(kExpectedResponseData[i], response_data);
initial.commit586acc5fe2008-07-26 22:42:52536
537 trans->Destroy();
initial.commit586acc5fe2008-07-26 22:42:52538 }
539}
[email protected]3d2a59b2008-09-26 19:44:25540
541TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionReset) {
[email protected]217e6022008-09-29 18:18:35542 MockRead read_failure(true, net::ERR_CONNECTION_RESET);
[email protected]3d2a59b2008-09-26 19:44:25543 KeepAliveConnectionResendRequestTest(read_failure);
544}
545
546TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionEOF) {
[email protected]217e6022008-09-29 18:18:35547 MockRead read_failure(false, net::OK); // EOF
[email protected]3d2a59b2008-09-26 19:44:25548 KeepAliveConnectionResendRequestTest(read_failure);
549}
550
551TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionReset) {
552 net::HttpTransaction* trans = new net::HttpNetworkTransaction(
553 CreateSession(), &mock_socket_factory);
554
555 net::HttpRequestInfo request;
556 request.method = "GET";
557 request.url = GURL("http://www.google.com/");
558 request.load_flags = 0;
559
560 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35561 MockRead(true, net::ERR_CONNECTION_RESET),
562 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used
563 MockRead("hello world"),
564 MockRead(false, net::OK),
[email protected]3d2a59b2008-09-26 19:44:25565 };
566 MockSocket data;
[email protected]3d2a59b2008-09-26 19:44:25567 data.reads = data_reads;
568 mock_sockets[0] = &data;
569 mock_sockets[1] = NULL;
570
571 TestCompletionCallback callback;
572
573 int rv = trans->Start(&request, &callback);
574 EXPECT_EQ(net::ERR_IO_PENDING, rv);
575
576 rv = callback.WaitForResult();
577 EXPECT_EQ(net::ERR_CONNECTION_RESET, rv);
578
579 const net::HttpResponseInfo* response = trans->GetResponseInfo();
580 EXPECT_TRUE(response == NULL);
581
582 trans->Destroy();
[email protected]3d2a59b2008-09-26 19:44:25583}
584
585// What do various browsers do when the server closes a non-keepalive
586// connection without sending any response header or body?
587//
588// IE7: error page
589// Safari 3.1.2 (Windows): error page
590// Firefox 3.0.1: blank page
591// Opera 9.52: after five attempts, blank page
592// Us with WinHTTP: error page (net::ERR_INVALID_RESPONSE)
[email protected]aecfbf22008-10-16 02:02:47593// Us: error page (net::EMPTY_RESPONSE)
[email protected]3d2a59b2008-09-26 19:44:25594TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionEOF) {
595 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35596 MockRead(false, net::OK), // EOF
597 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used
598 MockRead("hello world"),
599 MockRead(false, net::OK),
[email protected]3d2a59b2008-09-26 19:44:25600 };
601 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]0e75a732008-10-16 20:36:09602 EXPECT_EQ(net::ERR_EMPTY_RESPONSE, out.rv);
[email protected]3d2a59b2008-09-26 19:44:25603}
[email protected]038e9a32008-10-08 22:40:16604
605// Test the request-challenge-retry sequence for basic auth.
606// (basic auth is the easiest to mock, because it has no randomness).
607TEST_F(HttpNetworkTransactionTest, BasicAuth) {
608 net::HttpTransaction* trans = new net::HttpNetworkTransaction(
609 CreateSession(), &mock_socket_factory);
610
611 net::HttpRequestInfo request;
612 request.method = "GET";
613 request.url = GURL("http://www.google.com/");
614 request.load_flags = 0;
615
616 MockRead data_reads1[] = {
617 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
618 // Give a couple authenticate options (only the middle one is actually
619 // supported).
[email protected]aaead502008-10-15 00:20:11620 MockRead("WWW-Authenticate: Basic\r\n"), // Malformed
[email protected]038e9a32008-10-08 22:40:16621 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
622 MockRead("WWW-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"),
623 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
624 // Large content-length -- won't matter, as connection will be reset.
625 MockRead("Content-Length: 10000\r\n\r\n"),
626 MockRead(false, net::ERR_FAILED),
627 };
628
629 // After calling trans->RestartWithAuth(), this is the request we should
630 // be issuing -- the final header line contains the credentials.
631 MockWrite data_writes2[] = {
632 MockWrite("GET / HTTP/1.1\r\n"
633 "Host: www.google.com\r\n"
634 "Connection: keep-alive\r\n"
635 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
636 };
637
638 // Lastly, the server responds with the actual content.
639 MockRead data_reads2[] = {
640 MockRead("HTTP/1.0 200 OK\r\n"),
641 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
642 MockRead("Content-Length: 100\r\n\r\n"),
643 MockRead(false, net::OK),
644 };
645
646 MockSocket data1;
647 data1.reads = data_reads1;
648 MockSocket data2;
649 data2.reads = data_reads2;
650 data2.writes = data_writes2;
651 mock_sockets[0] = &data1;
652 mock_sockets[1] = &data2;
653 mock_sockets[2] = NULL;
654
655 TestCompletionCallback callback1;
656
657 int rv = trans->Start(&request, &callback1);
658 EXPECT_EQ(net::ERR_IO_PENDING, rv);
659
660 rv = callback1.WaitForResult();
661 EXPECT_EQ(net::OK, rv);
662
663 const net::HttpResponseInfo* response = trans->GetResponseInfo();
664 EXPECT_FALSE(response == NULL);
665
666 // The password prompt info should have been set in response->auth_challenge.
667 EXPECT_FALSE(response->auth_challenge.get() == NULL);
668
669 // TODO(eroman): this should really include the effective port (80)
670 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
671 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
672 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
673
674 TestCompletionCallback callback2;
675
676 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
677 EXPECT_EQ(net::ERR_IO_PENDING, rv);
678
679 rv = callback2.WaitForResult();
680 EXPECT_EQ(net::OK, rv);
681
682 response = trans->GetResponseInfo();
683 EXPECT_FALSE(response == NULL);
684 EXPECT_TRUE(response->auth_challenge.get() == NULL);
685 EXPECT_EQ(100, response->headers->GetContentLength());
686
687 trans->Destroy();
[email protected]038e9a32008-10-08 22:40:16688}
689
690// Test the flow when both the proxy server AND origin server require
691// authentication. Again, this uses basic auth for both since that is
692// the simplest to mock.
693TEST_F(HttpNetworkTransactionTest, BasicAuthProxyThenServer) {
694 net::ProxyInfo proxy_info;
695 proxy_info.UseNamedProxy("myproxy:70");
696
697 // Configure against proxy server "myproxy:70".
698 net::HttpTransaction* trans = new net::HttpNetworkTransaction(
699 CreateSession(new net::ProxyResolverFixed(proxy_info)),
700 &mock_socket_factory);
701
702 net::HttpRequestInfo request;
703 request.method = "GET";
704 request.url = GURL("http://www.google.com/");
705 request.load_flags = 0;
706
707 MockRead data_reads1[] = {
708 MockRead("HTTP/1.0 407 Unauthorized\r\n"),
709 // Give a couple authenticate options (only the middle one is actually
710 // supported).
[email protected]aaead502008-10-15 00:20:11711 MockRead("Proxy-Authenticate: Basic\r\n"), // Malformed
[email protected]038e9a32008-10-08 22:40:16712 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
713 MockRead("Proxy-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"),
714 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
715 // Large content-length -- won't matter, as connection will be reset.
716 MockRead("Content-Length: 10000\r\n\r\n"),
717 MockRead(false, net::ERR_FAILED),
718 };
719
720 // After calling trans->RestartWithAuth() the first time, this is the
721 // request we should be issuing -- the final header line contains the
722 // proxy's credentials.
723 MockWrite data_writes2[] = {
724 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
725 "Host: www.google.com\r\n"
726 "Proxy-Connection: keep-alive\r\n"
727 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
728 };
729
730 // Now the proxy server lets the request pass through to origin server.
731 // The origin server responds with a 401.
732 MockRead data_reads2[] = {
733 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
734 // Note: We are using the same realm-name as the proxy server. This is
735 // completely valid, as realms are unique across hosts.
736 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
737 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
738 MockRead("Content-Length: 2000\r\n\r\n"),
[email protected]aaead502008-10-15 00:20:11739 MockRead(false, net::ERR_FAILED), // Won't be reached.
[email protected]038e9a32008-10-08 22:40:16740 };
741
742 // After calling trans->RestartWithAuth() the second time, we should send
743 // the credentials for both the proxy and origin server.
744 MockWrite data_writes3[] = {
745 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
746 "Host: www.google.com\r\n"
747 "Proxy-Connection: keep-alive\r\n"
748 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n"
749 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"),
750 };
751
752 // Lastly we get the desired content.
753 MockRead data_reads3[] = {
754 MockRead("HTTP/1.0 200 OK\r\n"),
755 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
756 MockRead("Content-Length: 100\r\n\r\n"),
757 MockRead(false, net::OK),
758 };
759
760 MockSocket data1;
761 data1.reads = data_reads1;
762 MockSocket data2;
763 data2.reads = data_reads2;
764 data2.writes = data_writes2;
765 MockSocket data3;
766 data3.reads = data_reads3;
767 data3.writes = data_writes3;
768 mock_sockets[0] = &data1;
769 mock_sockets[1] = &data2;
770 mock_sockets[2] = &data3;
771 mock_sockets[3] = NULL;
772
773 TestCompletionCallback callback1;
774
775 int rv = trans->Start(&request, &callback1);
776 EXPECT_EQ(net::ERR_IO_PENDING, rv);
777
778 rv = callback1.WaitForResult();
779 EXPECT_EQ(net::OK, rv);
780
781 const net::HttpResponseInfo* response = trans->GetResponseInfo();
782 EXPECT_FALSE(response == NULL);
783
784 // The password prompt info should have been set in response->auth_challenge.
785 EXPECT_FALSE(response->auth_challenge.get() == NULL);
786
787 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host);
788 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
789 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
790
791 TestCompletionCallback callback2;
792
793 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
794 EXPECT_EQ(net::ERR_IO_PENDING, rv);
795
796 rv = callback2.WaitForResult();
797 EXPECT_EQ(net::OK, rv);
798
799 response = trans->GetResponseInfo();
800 EXPECT_FALSE(response == NULL);
801 EXPECT_FALSE(response->auth_challenge.get() == NULL);
802
803 // TODO(eroman): this should really include the effective port (80)
804 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
805 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
806 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
807
808 TestCompletionCallback callback3;
809
810 rv = trans->RestartWithAuth(L"foo2", L"bar2", &callback3);
811 EXPECT_EQ(net::ERR_IO_PENDING, rv);
812
813 rv = callback3.WaitForResult();
814 EXPECT_EQ(net::OK, rv);
815
816 response = trans->GetResponseInfo();
817 EXPECT_TRUE(response->auth_challenge.get() == NULL);
818 EXPECT_EQ(100, response->headers->GetContentLength());
819
820 trans->Destroy();
[email protected]038e9a32008-10-08 22:40:16821}