blob: 340dfe49f9ff548b88a8ac27a9a6b3f2d4428461 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit586acc5fe2008-07-26 22:42:524
[email protected]77848d12008-11-14 00:00:225#include <math.h> // ceil
6
[email protected]68bf9152008-09-25 19:47:307#include "base/compiler_specific.h"
initial.commit586acc5fe2008-07-26 22:42:528#include "net/base/client_socket_factory.h"
9#include "net/base/test_completion_callback.h"
10#include "net/base/upload_data.h"
[email protected]385a4672009-03-11 22:21:2911#include "net/http/http_auth_handler_ntlm.h"
initial.commit586acc5fe2008-07-26 22:42:5212#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]51fff29d2008-12-19 22:17:5315#include "net/proxy/proxy_config_service_fixed.h"
initial.commit586acc5fe2008-07-26 22:42:5216#include "testing/gtest/include/gtest/gtest.h"
[email protected]23887f04f2008-12-02 19:20:1517#include "testing/platform_test.h"
initial.commit586acc5fe2008-07-26 22:42:5218
19//-----------------------------------------------------------------------------
20
[email protected]89ceba9a2009-03-21 03:46:0621namespace net {
22
23// TODO(eroman): Now that this is inside the net namespace, remove the redundant
24// net:: qualifiers.
initial.commit586acc5fe2008-07-26 22:42:5225
26struct MockConnect {
[email protected]217e6022008-09-29 18:18:3527 // Asynchronous connection success.
28 MockConnect() : async(true), result(net::OK) { }
[email protected]038e9a32008-10-08 22:40:1629
30 bool async;
31 int result;
initial.commit586acc5fe2008-07-26 22:42:5232};
33
34struct MockRead {
[email protected]217e6022008-09-29 18:18:3535 // Read failure (no data).
36 MockRead(bool async, int result) : async(async) , result(result), data(NULL),
37 data_len(0) { }
38
39 // Asynchronous read success (inferred data length).
[email protected]372d34a2008-11-05 21:30:5140 explicit MockRead(const char* data) : async(true), result(0), data(data),
[email protected]b5462e02008-09-29 18:32:1941 data_len(strlen(data)) { }
[email protected]217e6022008-09-29 18:18:3542
43 // Read success (inferred data length).
[email protected]b5462e02008-09-29 18:32:1944 MockRead(bool async, const char* data) : async(async), result(0), data(data),
45 data_len(strlen(data)) { }
[email protected]217e6022008-09-29 18:18:3546
47 // Read success.
48 MockRead(bool async, const char* data, int data_len) : async(async),
[email protected]b5462e02008-09-29 18:32:1949 result(0), data(data), data_len(data_len) { }
[email protected]217e6022008-09-29 18:18:3550
initial.commit586acc5fe2008-07-26 22:42:5251 bool async;
[email protected]217e6022008-09-29 18:18:3552 int result;
initial.commit586acc5fe2008-07-26 22:42:5253 const char* data;
[email protected]217e6022008-09-29 18:18:3554 int data_len;
initial.commit586acc5fe2008-07-26 22:42:5255};
56
[email protected]038e9a32008-10-08 22:40:1657// MockWrite uses the same member fields as MockRead, but with different
58// meanings. The expected input to MockTCPClientSocket::Write() is given
59// by {data, data_len}, and the return value of Write() is controlled by
60// {async, result}.
61typedef MockRead MockWrite;
62
initial.commit586acc5fe2008-07-26 22:42:5263struct MockSocket {
[email protected]038e9a32008-10-08 22:40:1664 MockSocket() : reads(NULL), writes(NULL) { }
[email protected]217e6022008-09-29 18:18:3565
initial.commit586acc5fe2008-07-26 22:42:5266 MockConnect connect;
[email protected]217e6022008-09-29 18:18:3567 MockRead* reads;
[email protected]038e9a32008-10-08 22:40:1668 MockWrite* writes;
initial.commit586acc5fe2008-07-26 22:42:5269};
70
71// Holds an array of MockSocket elements. As MockTCPClientSocket objects get
72// instantiated, they take their data from the i'th element of this array.
73//
74// Tests should assign the first N entries of mock_sockets to point to valid
75// MockSocket objects. The first unused entry should be NULL'd.
76//
77MockSocket* mock_sockets[10];
78
79// Index of the next mock_sockets element to use.
80int mock_sockets_index;
81
82class MockTCPClientSocket : public net::ClientSocket {
83 public:
[email protected]372d34a2008-11-05 21:30:5184 explicit MockTCPClientSocket(const net::AddressList& addresses)
initial.commit586acc5fe2008-07-26 22:42:5285 : data_(mock_sockets[mock_sockets_index++]),
[email protected]68bf9152008-09-25 19:47:3086 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
initial.commit586acc5fe2008-07-26 22:42:5287 callback_(NULL),
88 read_index_(0),
89 read_offset_(0),
[email protected]038e9a32008-10-08 22:40:1690 write_index_(0),
initial.commit586acc5fe2008-07-26 22:42:5291 connected_(false) {
92 DCHECK(data_) << "overran mock_sockets array";
93 }
94 // ClientSocket methods:
95 virtual int Connect(net::CompletionCallback* callback) {
96 DCHECK(!callback_);
97 if (connected_)
98 return net::OK;
99 connected_ = true;
100 if (data_->connect.async) {
101 RunCallbackAsync(callback, data_->connect.result);
102 return net::ERR_IO_PENDING;
103 }
104 return data_->connect.result;
105 }
106 virtual int ReconnectIgnoringLastError(net::CompletionCallback* callback) {
107 NOTREACHED();
108 return net::ERR_FAILED;
109 }
110 virtual void Disconnect() {
111 connected_ = false;
112 callback_ = NULL;
113 }
114 virtual bool IsConnected() const {
115 return connected_;
116 }
[email protected]b2197852009-02-19 23:27:33117 virtual bool IsConnectedAndIdle() const {
118 return connected_;
119 }
initial.commit586acc5fe2008-07-26 22:42:52120 // Socket methods:
121 virtual int Read(char* buf, int buf_len, net::CompletionCallback* callback) {
122 DCHECK(!callback_);
123 MockRead& r = data_->reads[read_index_];
[email protected]038e9a32008-10-08 22:40:16124 int result = r.result;
initial.commit586acc5fe2008-07-26 22:42:52125 if (r.data) {
initial.commit586acc5fe2008-07-26 22:42:52126 if (r.data_len - read_offset_ > 0) {
127 result = std::min(buf_len, r.data_len - read_offset_);
128 memcpy(buf, r.data + read_offset_, result);
129 read_offset_ += result;
130 if (read_offset_ == r.data_len) {
131 read_index_++;
132 read_offset_ = 0;
133 }
134 } else {
135 result = 0; // EOF
136 }
initial.commit586acc5fe2008-07-26 22:42:52137 }
138 if (r.async) {
139 RunCallbackAsync(callback, result);
140 return net::ERR_IO_PENDING;
141 }
142 return result;
143 }
144 virtual int Write(const char* buf, int buf_len,
145 net::CompletionCallback* callback) {
[email protected]372d34a2008-11-05 21:30:51146 DCHECK(buf);
147 DCHECK(buf_len > 0);
initial.commit586acc5fe2008-07-26 22:42:52148 DCHECK(!callback_);
[email protected]038e9a32008-10-08 22:40:16149 // Not using mock writes; succeed synchronously.
150 if (!data_->writes)
151 return buf_len;
[email protected]aaead502008-10-15 00:20:11152
[email protected]038e9a32008-10-08 22:40:16153 // Check that what we are writing matches the expectation.
154 // Then give the mocked return value.
[email protected]372d34a2008-11-05 21:30:51155 MockWrite& w = data_->writes[write_index_++];
[email protected]038e9a32008-10-08 22:40:16156 int result = w.result;
157 if (w.data) {
158 std::string expected_data(w.data, w.data_len);
159 std::string actual_data(buf, buf_len);
160 EXPECT_EQ(expected_data, actual_data);
161 if (expected_data != actual_data)
162 return net::ERR_UNEXPECTED;
163 if (result == net::OK)
164 result = w.data_len;
165 }
166 if (w.async) {
167 RunCallbackAsync(callback, result);
168 return net::ERR_IO_PENDING;
169 }
170 return result;
initial.commit586acc5fe2008-07-26 22:42:52171 }
172 private:
173 void RunCallbackAsync(net::CompletionCallback* callback, int result) {
174 callback_ = callback;
175 MessageLoop::current()->PostTask(FROM_HERE,
176 method_factory_.NewRunnableMethod(
177 &MockTCPClientSocket::RunCallback, result));
178 }
179 void RunCallback(int result) {
180 net::CompletionCallback* c = callback_;
181 callback_ = NULL;
182 if (c)
183 c->Run(result);
184 }
185 MockSocket* data_;
186 ScopedRunnableMethodFactory<MockTCPClientSocket> method_factory_;
187 net::CompletionCallback* callback_;
188 int read_index_;
189 int read_offset_;
[email protected]038e9a32008-10-08 22:40:16190 int write_index_;
initial.commit586acc5fe2008-07-26 22:42:52191 bool connected_;
192};
193
194class MockClientSocketFactory : public net::ClientSocketFactory {
195 public:
196 virtual net::ClientSocket* CreateTCPClientSocket(
197 const net::AddressList& addresses) {
198 return new MockTCPClientSocket(addresses);
199 }
[email protected]aaead502008-10-15 00:20:11200 virtual net::SSLClientSocket* CreateSSLClientSocket(
initial.commit586acc5fe2008-07-26 22:42:52201 net::ClientSocket* transport_socket,
[email protected]c5949a32008-10-08 17:28:23202 const std::string& hostname,
[email protected]aaead502008-10-15 00:20:11203 const net::SSLConfig& ssl_config) {
initial.commit586acc5fe2008-07-26 22:42:52204 return NULL;
205 }
206};
207
208MockClientSocketFactory mock_socket_factory;
209
[email protected]db8f44c2008-12-13 04:52:01210// Create a proxy service which fails on all requests (falls back to direct).
211net::ProxyService* CreateNullProxyService() {
[email protected]51fff29d2008-12-19 22:17:53212 return net::ProxyService::CreateNull();
initial.commit586acc5fe2008-07-26 22:42:52213}
214
[email protected]51fff29d2008-12-19 22:17:53215net::ProxyService* CreateFixedProxyService(const std::string& proxy) {
216 net::ProxyInfo proxy_info;
217 proxy_info.UseNamedProxy(proxy);
[email protected]d1ec59082009-02-11 02:48:15218 return net::ProxyService::Create(&proxy_info);
[email protected]51fff29d2008-12-19 22:17:53219}
220
221
[email protected]db8f44c2008-12-13 04:52:01222net::HttpNetworkSession* CreateSession(net::ProxyService* proxy_service) {
223 return new net::HttpNetworkSession(proxy_service);
[email protected]e8d536192008-10-17 22:21:14224}
225
[email protected]89836e22008-09-25 20:33:42226class HttpNetworkTransactionTest : public PlatformTest {
initial.commit586acc5fe2008-07-26 22:42:52227 public:
228 virtual void SetUp() {
[email protected]89836e22008-09-25 20:33:42229 PlatformTest::SetUp();
initial.commit586acc5fe2008-07-26 22:42:52230 mock_sockets[0] = NULL;
231 mock_sockets_index = 0;
232 }
[email protected]3d2a59b2008-09-26 19:44:25233
[email protected]0e75a732008-10-16 20:36:09234 virtual void TearDown() {
235 // Empty the current queue.
236 MessageLoop::current()->RunAllPending();
237 PlatformTest::TearDown();
238 }
239
[email protected]3d2a59b2008-09-26 19:44:25240 protected:
241 void KeepAliveConnectionResendRequestTest(const MockRead& read_failure);
initial.commit586acc5fe2008-07-26 22:42:52242};
243
[email protected]231d5a32008-09-13 00:45:27244struct SimpleGetHelperResult {
[email protected]aecfbf22008-10-16 02:02:47245 int rv;
[email protected]231d5a32008-09-13 00:45:27246 std::string status_line;
247 std::string response_data;
248};
initial.commit586acc5fe2008-07-26 22:42:52249
[email protected]231d5a32008-09-13 00:45:27250SimpleGetHelperResult SimpleGetHelper(MockRead data_reads[]) {
251 SimpleGetHelperResult out;
initial.commit586acc5fe2008-07-26 22:42:52252
[email protected]db8f44c2008-12-13 04:52:01253 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
[email protected]af4876d2008-10-21 23:10:57254 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
[email protected]db8f44c2008-12-13 04:52:01255 CreateSession(proxy_service.get()), &mock_socket_factory));
initial.commit586acc5fe2008-07-26 22:42:52256
257 net::HttpRequestInfo request;
258 request.method = "GET";
259 request.url = GURL("http://www.google.com/");
260 request.load_flags = 0;
261
initial.commit586acc5fe2008-07-26 22:42:52262 MockSocket data;
initial.commit586acc5fe2008-07-26 22:42:52263 data.reads = data_reads;
264 mock_sockets[0] = &data;
265 mock_sockets[1] = NULL;
266
267 TestCompletionCallback callback;
268
269 int rv = trans->Start(&request, &callback);
270 EXPECT_EQ(net::ERR_IO_PENDING, rv);
271
[email protected]aecfbf22008-10-16 02:02:47272 out.rv = callback.WaitForResult();
[email protected]af4876d2008-10-21 23:10:57273 if (out.rv != net::OK)
[email protected]aecfbf22008-10-16 02:02:47274 return out;
initial.commit586acc5fe2008-07-26 22:42:52275
276 const net::HttpResponseInfo* response = trans->GetResponseInfo();
277 EXPECT_TRUE(response != NULL);
278
279 EXPECT_TRUE(response->headers != NULL);
[email protected]231d5a32008-09-13 00:45:27280 out.status_line = response->headers->GetStatusLine();
initial.commit586acc5fe2008-07-26 22:42:52281
[email protected]af4876d2008-10-21 23:10:57282 rv = ReadTransaction(trans.get(), &out.response_data);
initial.commit586acc5fe2008-07-26 22:42:52283 EXPECT_EQ(net::OK, rv);
initial.commit586acc5fe2008-07-26 22:42:52284
[email protected]231d5a32008-09-13 00:45:27285 return out;
286}
287
[email protected]15a5ccf82008-10-23 19:57:43288// Fill |str| with a long header list that consumes >= |size| bytes.
289void FillLargeHeadersString(std::string* str, int size) {
[email protected]4ddaf2502008-10-23 18:26:19290 const char* row =
291 "SomeHeaderName: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n";
292 const int sizeof_row = strlen(row);
293 const int num_rows = static_cast<int>(
294 ceil(static_cast<float>(size) / sizeof_row));
295 const int sizeof_data = num_rows * sizeof_row;
296 DCHECK(sizeof_data >= size);
[email protected]15a5ccf82008-10-23 19:57:43297 str->reserve(sizeof_data);
[email protected]372d34a2008-11-05 21:30:51298
[email protected]4ddaf2502008-10-23 18:26:19299 for (int i = 0; i < num_rows; ++i)
[email protected]15a5ccf82008-10-23 19:57:43300 str->append(row, sizeof_row);
[email protected]4ddaf2502008-10-23 18:26:19301}
302
[email protected]385a4672009-03-11 22:21:29303// Alternative functions that eliminate randomness and dependency on the local
304// host name so that the generated NTLM messages are reproducible.
305void MyGenerateRandom1(uint8* output, size_t n) {
306 static const uint8 bytes[] = {
307 0x55, 0x29, 0x66, 0x26, 0x6b, 0x9c, 0x73, 0x54
308 };
309 static size_t current_byte = 0;
310 for (size_t i = 0; i < n; ++i) {
311 output[i] = bytes[current_byte++];
312 current_byte %= arraysize(bytes);
313 }
314}
315
316void MyGenerateRandom2(uint8* output, size_t n) {
317 static const uint8 bytes[] = {
318 0x96, 0x79, 0x85, 0xe7, 0x49, 0x93, 0x70, 0xa1,
319 0x4e, 0xe7, 0x87, 0x45, 0x31, 0x5b, 0xd3, 0x1f
320 };
321 static size_t current_byte = 0;
322 for (size_t i = 0; i < n; ++i) {
323 output[i] = bytes[current_byte++];
324 current_byte %= arraysize(bytes);
325 }
326}
327
328void MyGetHostName(char* name, size_t namelen) {
329 static const char hostname[] = "WTC-WIN7";
330 if (namelen >= arraysize(hostname)) {
331 memcpy(name, hostname, arraysize(hostname));
332 } else {
333 name[0] = '\0';
334 }
335}
336
[email protected]231d5a32008-09-13 00:45:27337//-----------------------------------------------------------------------------
338
339TEST_F(HttpNetworkTransactionTest, Basic) {
[email protected]db8f44c2008-12-13 04:52:01340 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
[email protected]af4876d2008-10-21 23:10:57341 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
[email protected]db8f44c2008-12-13 04:52:01342 CreateSession(proxy_service.get()), &mock_socket_factory));
[email protected]231d5a32008-09-13 00:45:27343}
344
345TEST_F(HttpNetworkTransactionTest, SimpleGET) {
346 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35347 MockRead("HTTP/1.0 200 OK\r\n\r\n"),
348 MockRead("hello world"),
349 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27350 };
[email protected]231d5a32008-09-13 00:45:27351 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47352 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27353 EXPECT_EQ("HTTP/1.0 200 OK", out.status_line);
354 EXPECT_EQ("hello world", out.response_data);
355}
356
357// Response with no status line.
358TEST_F(HttpNetworkTransactionTest, SimpleGETNoHeaders) {
359 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35360 MockRead("hello world"),
361 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27362 };
[email protected]231d5a32008-09-13 00:45:27363 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47364 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27365 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
366 EXPECT_EQ("hello world", out.response_data);
367}
368
369// Allow up to 4 bytes of junk to precede status line.
370TEST_F(HttpNetworkTransactionTest, StatusLineJunk2Bytes) {
371 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35372 MockRead("xxxHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
373 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27374 };
375 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47376 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27377 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
378 EXPECT_EQ("DATA", out.response_data);
379}
380
381// Allow up to 4 bytes of junk to precede status line.
382TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes) {
383 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35384 MockRead("\n\nQJHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
385 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27386 };
387 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47388 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27389 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
390 EXPECT_EQ("DATA", out.response_data);
391}
392
393// Beyond 4 bytes of slop and it should fail to find a status line.
394TEST_F(HttpNetworkTransactionTest, StatusLineJunk5Bytes) {
395 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35396 MockRead("xxxxxHTTP/1.1 404 Not Found\nServer: blah"),
397 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27398 };
399 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47400 EXPECT_EQ(net::OK, out.rv);
[email protected]3d2a59b2008-09-26 19:44:25401 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
402 EXPECT_EQ("xxxxxHTTP/1.1 404 Not Found\nServer: blah", out.response_data);
[email protected]231d5a32008-09-13 00:45:27403}
404
405// Same as StatusLineJunk4Bytes, except the read chunks are smaller.
406TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes_Slow) {
407 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35408 MockRead("\n"),
409 MockRead("\n"),
410 MockRead("Q"),
411 MockRead("J"),
412 MockRead("HTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
413 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27414 };
415 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47416 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27417 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
418 EXPECT_EQ("DATA", out.response_data);
419}
420
421// Close the connection before enough bytes to have a status line.
422TEST_F(HttpNetworkTransactionTest, StatusLinePartial) {
423 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35424 MockRead("HTT"),
425 MockRead(false, net::OK),
[email protected]231d5a32008-09-13 00:45:27426 };
427 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47428 EXPECT_EQ(net::OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27429 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
430 EXPECT_EQ("HTT", out.response_data);
initial.commit586acc5fe2008-07-26 22:42:52431}
432
[email protected]f9d44aa2008-09-23 23:57:17433// Simulate a 204 response, lacking a Content-Length header, sent over a
434// persistent connection. The response should still terminate since a 204
435// cannot have a response body.
436TEST_F(HttpNetworkTransactionTest, StopsReading204) {
437 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35438 MockRead("HTTP/1.1 204 No Content\r\n\r\n"),
439 MockRead("junk"), // Should not be read!!
440 MockRead(false, net::OK),
[email protected]f9d44aa2008-09-23 23:57:17441 };
442 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]aecfbf22008-10-16 02:02:47443 EXPECT_EQ(net::OK, out.rv);
[email protected]f9d44aa2008-09-23 23:57:17444 EXPECT_EQ("HTTP/1.1 204 No Content", out.status_line);
445 EXPECT_EQ("", out.response_data);
446}
447
[email protected]ef0faf2e72009-03-05 23:27:23448// Do a request using the HEAD method. Verify that we don't try to read the
449// message body (since HEAD has none).
450TEST_F(HttpNetworkTransactionTest, Head) {
451 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
452 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
453 CreateSession(proxy_service.get()), &mock_socket_factory));
454
455 net::HttpRequestInfo request;
456 request.method = "HEAD";
457 request.url = GURL("http://www.google.com/");
458 request.load_flags = 0;
459
460 MockWrite data_writes1[] = {
461 MockWrite("HEAD / HTTP/1.1\r\n"
462 "Host: www.google.com\r\n"
463 "Connection: keep-alive\r\n"
464 "Content-Length: 0\r\n\r\n"),
465 };
466 MockRead data_reads1[] = {
467 MockRead("HTTP/1.1 404 Not Found\r\n"),
468 MockRead("Server: Blah\r\n"),
469 MockRead("Content-Length: 1234\r\n\r\n"),
470
471 // No response body because the test stops reading here.
472 MockRead(false, net::ERR_UNEXPECTED), // Should not be reached.
473 };
474
475 MockSocket data1;
476 data1.reads = data_reads1;
477 data1.writes = data_writes1;
478 mock_sockets[0] = &data1;
479 mock_sockets[1] = NULL;
480
481 TestCompletionCallback callback1;
482
483 int rv = trans->Start(&request, &callback1);
484 EXPECT_EQ(net::ERR_IO_PENDING, rv);
485
486 rv = callback1.WaitForResult();
487 EXPECT_EQ(net::OK, rv);
488
489 const net::HttpResponseInfo* response = trans->GetResponseInfo();
490 EXPECT_FALSE(response == NULL);
491
492 // Check that the headers got parsed.
493 EXPECT_TRUE(response->headers != NULL);
494 EXPECT_EQ(1234, response->headers->GetContentLength());
495 EXPECT_EQ("HTTP/1.1 404 Not Found", response->headers->GetStatusLine());
496
497 std::string server_header;
498 void* iter = NULL;
499 bool has_server_header = response->headers->EnumerateHeader(
500 &iter, "Server", &server_header);
501 EXPECT_TRUE(has_server_header);
502 EXPECT_EQ("Blah", server_header);
503
504 // Reading should give EOF right away, since there is no message body
505 // (despite non-zero content-length).
506 std::string response_data;
507 rv = ReadTransaction(trans.get(), &response_data);
508 EXPECT_EQ(net::OK, rv);
509 EXPECT_EQ("", response_data);
510}
511
initial.commit586acc5fe2008-07-26 22:42:52512TEST_F(HttpNetworkTransactionTest, ReuseConnection) {
[email protected]db8f44c2008-12-13 04:52:01513 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
514 scoped_refptr<net::HttpNetworkSession> session =
515 CreateSession(proxy_service.get());
initial.commit586acc5fe2008-07-26 22:42:52516
517 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35518 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
519 MockRead("hello"),
520 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
521 MockRead("world"),
522 MockRead(false, net::OK),
initial.commit586acc5fe2008-07-26 22:42:52523 };
524 MockSocket data;
initial.commit586acc5fe2008-07-26 22:42:52525 data.reads = data_reads;
526 mock_sockets[0] = &data;
527 mock_sockets[1] = NULL;
528
529 const char* kExpectedResponseData[] = {
530 "hello", "world"
531 };
532
533 for (int i = 0; i < 2; ++i) {
[email protected]af4876d2008-10-21 23:10:57534 scoped_ptr<net::HttpTransaction> trans(
535 new net::HttpNetworkTransaction(session, &mock_socket_factory));
initial.commit586acc5fe2008-07-26 22:42:52536
537 net::HttpRequestInfo request;
538 request.method = "GET";
539 request.url = GURL("http://www.google.com/");
540 request.load_flags = 0;
541
542 TestCompletionCallback callback;
543
544 int rv = trans->Start(&request, &callback);
545 EXPECT_EQ(net::ERR_IO_PENDING, rv);
546
547 rv = callback.WaitForResult();
548 EXPECT_EQ(net::OK, rv);
549
550 const net::HttpResponseInfo* response = trans->GetResponseInfo();
551 EXPECT_TRUE(response != NULL);
552
553 EXPECT_TRUE(response->headers != NULL);
[email protected]3d2a59b2008-09-26 19:44:25554 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
initial.commit586acc5fe2008-07-26 22:42:52555
556 std::string response_data;
[email protected]af4876d2008-10-21 23:10:57557 rv = ReadTransaction(trans.get(), &response_data);
initial.commit586acc5fe2008-07-26 22:42:52558 EXPECT_EQ(net::OK, rv);
[email protected]3d2a59b2008-09-26 19:44:25559 EXPECT_EQ(kExpectedResponseData[i], response_data);
initial.commit586acc5fe2008-07-26 22:42:52560 }
561}
562
563TEST_F(HttpNetworkTransactionTest, Ignores100) {
[email protected]db8f44c2008-12-13 04:52:01564 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
[email protected]af4876d2008-10-21 23:10:57565 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
[email protected]db8f44c2008-12-13 04:52:01566 CreateSession(proxy_service.get()), &mock_socket_factory));
initial.commit586acc5fe2008-07-26 22:42:52567
568 net::HttpRequestInfo request;
569 request.method = "POST";
570 request.url = GURL("http://www.foo.com/");
571 request.upload_data = new net::UploadData;
572 request.upload_data->AppendBytes("foo", 3);
573 request.load_flags = 0;
574
575 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35576 MockRead("HTTP/1.0 100 Continue\r\n\r\n"),
577 MockRead("HTTP/1.0 200 OK\r\n\r\n"),
578 MockRead("hello world"),
579 MockRead(false, net::OK),
initial.commit586acc5fe2008-07-26 22:42:52580 };
581 MockSocket data;
initial.commit586acc5fe2008-07-26 22:42:52582 data.reads = data_reads;
583 mock_sockets[0] = &data;
584 mock_sockets[1] = NULL;
585
586 TestCompletionCallback callback;
587
588 int rv = trans->Start(&request, &callback);
589 EXPECT_EQ(net::ERR_IO_PENDING, rv);
590
591 rv = callback.WaitForResult();
592 EXPECT_EQ(net::OK, rv);
593
594 const net::HttpResponseInfo* response = trans->GetResponseInfo();
595 EXPECT_TRUE(response != NULL);
596
597 EXPECT_TRUE(response->headers != NULL);
[email protected]3d2a59b2008-09-26 19:44:25598 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine());
initial.commit586acc5fe2008-07-26 22:42:52599
600 std::string response_data;
[email protected]af4876d2008-10-21 23:10:57601 rv = ReadTransaction(trans.get(), &response_data);
initial.commit586acc5fe2008-07-26 22:42:52602 EXPECT_EQ(net::OK, rv);
[email protected]3d2a59b2008-09-26 19:44:25603 EXPECT_EQ("hello world", response_data);
initial.commit586acc5fe2008-07-26 22:42:52604}
605
[email protected]3d2a59b2008-09-26 19:44:25606// read_failure specifies a read failure that should cause the network
607// transaction to resend the request.
608void HttpNetworkTransactionTest::KeepAliveConnectionResendRequestTest(
609 const MockRead& read_failure) {
[email protected]db8f44c2008-12-13 04:52:01610 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
611 scoped_refptr<net::HttpNetworkSession> session =
612 CreateSession(proxy_service.get());
initial.commit586acc5fe2008-07-26 22:42:52613
614 net::HttpRequestInfo request;
615 request.method = "GET";
616 request.url = GURL("http://www.foo.com/");
617 request.load_flags = 0;
618
619 MockRead data1_reads[] = {
[email protected]217e6022008-09-29 18:18:35620 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
621 MockRead("hello"),
[email protected]3d2a59b2008-09-26 19:44:25622 read_failure, // Now, we reuse the connection and fail the first read.
initial.commit586acc5fe2008-07-26 22:42:52623 };
624 MockSocket data1;
initial.commit586acc5fe2008-07-26 22:42:52625 data1.reads = data1_reads;
626 mock_sockets[0] = &data1;
627
628 MockRead data2_reads[] = {
[email protected]217e6022008-09-29 18:18:35629 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
630 MockRead("world"),
631 MockRead(true, net::OK),
initial.commit586acc5fe2008-07-26 22:42:52632 };
633 MockSocket data2;
initial.commit586acc5fe2008-07-26 22:42:52634 data2.reads = data2_reads;
635 mock_sockets[1] = &data2;
636
637 const char* kExpectedResponseData[] = {
638 "hello", "world"
639 };
640
641 for (int i = 0; i < 2; ++i) {
642 TestCompletionCallback callback;
643
[email protected]af4876d2008-10-21 23:10:57644 scoped_ptr<net::HttpTransaction> trans(
645 new net::HttpNetworkTransaction(session, &mock_socket_factory));
initial.commit586acc5fe2008-07-26 22:42:52646
647 int rv = trans->Start(&request, &callback);
648 EXPECT_EQ(net::ERR_IO_PENDING, rv);
649
650 rv = callback.WaitForResult();
651 EXPECT_EQ(net::OK, rv);
652
653 const net::HttpResponseInfo* response = trans->GetResponseInfo();
654 EXPECT_TRUE(response != NULL);
655
656 EXPECT_TRUE(response->headers != NULL);
[email protected]3d2a59b2008-09-26 19:44:25657 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
initial.commit586acc5fe2008-07-26 22:42:52658
659 std::string response_data;
[email protected]af4876d2008-10-21 23:10:57660 rv = ReadTransaction(trans.get(), &response_data);
initial.commit586acc5fe2008-07-26 22:42:52661 EXPECT_EQ(net::OK, rv);
[email protected]3d2a59b2008-09-26 19:44:25662 EXPECT_EQ(kExpectedResponseData[i], response_data);
initial.commit586acc5fe2008-07-26 22:42:52663 }
664}
[email protected]3d2a59b2008-09-26 19:44:25665
666TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionReset) {
[email protected]217e6022008-09-29 18:18:35667 MockRead read_failure(true, net::ERR_CONNECTION_RESET);
[email protected]3d2a59b2008-09-26 19:44:25668 KeepAliveConnectionResendRequestTest(read_failure);
669}
670
671TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionEOF) {
[email protected]217e6022008-09-29 18:18:35672 MockRead read_failure(false, net::OK); // EOF
[email protected]3d2a59b2008-09-26 19:44:25673 KeepAliveConnectionResendRequestTest(read_failure);
674}
675
676TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionReset) {
[email protected]db8f44c2008-12-13 04:52:01677 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
[email protected]af4876d2008-10-21 23:10:57678 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
[email protected]db8f44c2008-12-13 04:52:01679 CreateSession(proxy_service.get()), &mock_socket_factory));
[email protected]3d2a59b2008-09-26 19:44:25680
681 net::HttpRequestInfo request;
682 request.method = "GET";
683 request.url = GURL("http://www.google.com/");
684 request.load_flags = 0;
685
686 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35687 MockRead(true, net::ERR_CONNECTION_RESET),
688 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used
689 MockRead("hello world"),
690 MockRead(false, net::OK),
[email protected]3d2a59b2008-09-26 19:44:25691 };
692 MockSocket data;
[email protected]3d2a59b2008-09-26 19:44:25693 data.reads = data_reads;
694 mock_sockets[0] = &data;
695 mock_sockets[1] = NULL;
696
697 TestCompletionCallback callback;
698
699 int rv = trans->Start(&request, &callback);
700 EXPECT_EQ(net::ERR_IO_PENDING, rv);
701
702 rv = callback.WaitForResult();
703 EXPECT_EQ(net::ERR_CONNECTION_RESET, rv);
704
705 const net::HttpResponseInfo* response = trans->GetResponseInfo();
706 EXPECT_TRUE(response == NULL);
[email protected]3d2a59b2008-09-26 19:44:25707}
708
709// What do various browsers do when the server closes a non-keepalive
710// connection without sending any response header or body?
711//
712// IE7: error page
713// Safari 3.1.2 (Windows): error page
714// Firefox 3.0.1: blank page
715// Opera 9.52: after five attempts, blank page
716// Us with WinHTTP: error page (net::ERR_INVALID_RESPONSE)
[email protected]aecfbf22008-10-16 02:02:47717// Us: error page (net::EMPTY_RESPONSE)
[email protected]3d2a59b2008-09-26 19:44:25718TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionEOF) {
719 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35720 MockRead(false, net::OK), // EOF
721 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used
722 MockRead("hello world"),
723 MockRead(false, net::OK),
[email protected]3d2a59b2008-09-26 19:44:25724 };
725 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]0e75a732008-10-16 20:36:09726 EXPECT_EQ(net::ERR_EMPTY_RESPONSE, out.rv);
[email protected]3d2a59b2008-09-26 19:44:25727}
[email protected]038e9a32008-10-08 22:40:16728
729// Test the request-challenge-retry sequence for basic auth.
730// (basic auth is the easiest to mock, because it has no randomness).
731TEST_F(HttpNetworkTransactionTest, BasicAuth) {
[email protected]db8f44c2008-12-13 04:52:01732 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
[email protected]af4876d2008-10-21 23:10:57733 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
[email protected]db8f44c2008-12-13 04:52:01734 CreateSession(proxy_service.get()), &mock_socket_factory));
[email protected]038e9a32008-10-08 22:40:16735
736 net::HttpRequestInfo request;
737 request.method = "GET";
738 request.url = GURL("http://www.google.com/");
739 request.load_flags = 0;
740
[email protected]f9ee6b52008-11-08 06:46:23741 MockWrite data_writes1[] = {
742 MockWrite("GET / HTTP/1.1\r\n"
743 "Host: www.google.com\r\n"
744 "Connection: keep-alive\r\n\r\n"),
745 };
746
[email protected]038e9a32008-10-08 22:40:16747 MockRead data_reads1[] = {
748 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
749 // Give a couple authenticate options (only the middle one is actually
750 // supported).
[email protected]aaead502008-10-15 00:20:11751 MockRead("WWW-Authenticate: Basic\r\n"), // Malformed
[email protected]038e9a32008-10-08 22:40:16752 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
753 MockRead("WWW-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"),
754 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
755 // Large content-length -- won't matter, as connection will be reset.
756 MockRead("Content-Length: 10000\r\n\r\n"),
757 MockRead(false, net::ERR_FAILED),
758 };
759
760 // After calling trans->RestartWithAuth(), this is the request we should
761 // be issuing -- the final header line contains the credentials.
762 MockWrite data_writes2[] = {
763 MockWrite("GET / HTTP/1.1\r\n"
764 "Host: www.google.com\r\n"
765 "Connection: keep-alive\r\n"
766 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
767 };
768
769 // Lastly, the server responds with the actual content.
770 MockRead data_reads2[] = {
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 mock_sockets[0] = &data1;
784 mock_sockets[1] = &data2;
785 mock_sockets[2] = NULL;
786
787 TestCompletionCallback callback1;
788
789 int rv = trans->Start(&request, &callback1);
790 EXPECT_EQ(net::ERR_IO_PENDING, rv);
791
792 rv = callback1.WaitForResult();
793 EXPECT_EQ(net::OK, rv);
794
795 const net::HttpResponseInfo* response = trans->GetResponseInfo();
796 EXPECT_FALSE(response == NULL);
797
798 // The password prompt info should have been set in response->auth_challenge.
799 EXPECT_FALSE(response->auth_challenge.get() == NULL);
800
801 // TODO(eroman): this should really include the effective port (80)
802 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
803 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
804 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
805
806 TestCompletionCallback callback2;
807
808 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
809 EXPECT_EQ(net::ERR_IO_PENDING, rv);
810
811 rv = callback2.WaitForResult();
812 EXPECT_EQ(net::OK, rv);
813
814 response = trans->GetResponseInfo();
815 EXPECT_FALSE(response == NULL);
816 EXPECT_TRUE(response->auth_challenge.get() == NULL);
817 EXPECT_EQ(100, response->headers->GetContentLength());
[email protected]038e9a32008-10-08 22:40:16818}
819
[email protected]2d2697f92009-02-18 21:00:32820// Test the request-challenge-retry sequence for basic auth, over a keep-alive
821// connection.
822TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAlive) {
823 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
824 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
825 CreateSession(proxy_service.get()), &mock_socket_factory));
826
827 net::HttpRequestInfo request;
828 request.method = "GET";
829 request.url = GURL("http://www.google.com/");
830 request.load_flags = 0;
831
832 MockWrite data_writes1[] = {
833 MockWrite("GET / HTTP/1.1\r\n"
834 "Host: www.google.com\r\n"
835 "Connection: keep-alive\r\n\r\n"),
836
837 // After calling trans->RestartWithAuth(), this is the request we should
838 // be issuing -- the final header line contains the credentials.
839 MockWrite("GET / HTTP/1.1\r\n"
840 "Host: www.google.com\r\n"
841 "Connection: keep-alive\r\n"
842 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
843 };
844
845 MockRead data_reads1[] = {
846 MockRead("HTTP/1.1 401 Unauthorized\r\n"),
847 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
848 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
849 MockRead("Content-Length: 14\r\n\r\n"),
850 MockRead("Unauthorized\r\n"),
851
852 // Lastly, the server responds with the actual content.
853 MockRead("HTTP/1.1 200 OK\r\n"),
854 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
855 MockRead("Content-Length: 100\r\n\r\n"),
856 MockRead(false, net::OK),
857 };
858
859 MockSocket data1;
860 data1.reads = data_reads1;
861 data1.writes = data_writes1;
862 mock_sockets[0] = &data1;
863 mock_sockets[1] = NULL;
864
865 TestCompletionCallback callback1;
866
867 int rv = trans->Start(&request, &callback1);
868 EXPECT_EQ(net::ERR_IO_PENDING, rv);
869
870 rv = callback1.WaitForResult();
871 EXPECT_EQ(net::OK, rv);
872
873 const net::HttpResponseInfo* response = trans->GetResponseInfo();
874 EXPECT_FALSE(response == NULL);
875
876 // The password prompt info should have been set in response->auth_challenge.
877 EXPECT_FALSE(response->auth_challenge.get() == NULL);
878
879 // TODO(eroman): this should really include the effective port (80)
880 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
881 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
882 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
883
884 TestCompletionCallback callback2;
885
886 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
887 EXPECT_EQ(net::ERR_IO_PENDING, rv);
888
889 rv = callback2.WaitForResult();
890 EXPECT_EQ(net::OK, rv);
891
892 response = trans->GetResponseInfo();
893 EXPECT_FALSE(response == NULL);
894 EXPECT_TRUE(response->auth_challenge.get() == NULL);
895 EXPECT_EQ(100, response->headers->GetContentLength());
896}
897
898// Test the request-challenge-retry sequence for basic auth, over a keep-alive
899// connection and with no response body to drain.
900TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) {
901 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
902 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
903 CreateSession(proxy_service.get()), &mock_socket_factory));
904
905 net::HttpRequestInfo request;
906 request.method = "GET";
907 request.url = GURL("http://www.google.com/");
908 request.load_flags = 0;
909
910 MockWrite data_writes1[] = {
911 MockWrite("GET / HTTP/1.1\r\n"
912 "Host: www.google.com\r\n"
913 "Connection: keep-alive\r\n\r\n"),
914
915 // After calling trans->RestartWithAuth(), this is the request we should
916 // be issuing -- the final header line contains the credentials.
917 MockWrite("GET / HTTP/1.1\r\n"
918 "Host: www.google.com\r\n"
919 "Connection: keep-alive\r\n"
920 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
921 };
922
923 // Respond with 5 kb of response body.
924 std::string large_body_string("Unauthorized");
925 large_body_string.append(5 * 1024, ' ');
926 large_body_string.append("\r\n");
927
928 MockRead data_reads1[] = {
929 MockRead("HTTP/1.1 401 Unauthorized\r\n"),
930 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
931 MockRead("Content-Length: 0\r\n\r\n"),
932
933 // Lastly, the server responds with the actual content.
934 MockRead("HTTP/1.1 200 OK\r\n"),
935 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
936 MockRead("Content-Length: 100\r\n\r\n"),
937 MockRead(false, net::OK),
938 };
939
940 MockSocket data1;
941 data1.reads = data_reads1;
942 data1.writes = data_writes1;
943 mock_sockets[0] = &data1;
944 mock_sockets[1] = NULL;
945
946 TestCompletionCallback callback1;
947
948 int rv = trans->Start(&request, &callback1);
949 EXPECT_EQ(net::ERR_IO_PENDING, rv);
950
951 rv = callback1.WaitForResult();
952 EXPECT_EQ(net::OK, rv);
953
954 const net::HttpResponseInfo* response = trans->GetResponseInfo();
955 EXPECT_FALSE(response == NULL);
956
957 // The password prompt info should have been set in response->auth_challenge.
958 EXPECT_FALSE(response->auth_challenge.get() == NULL);
959
960 // TODO(eroman): this should really include the effective port (80)
961 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
962 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
963 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
964
965 TestCompletionCallback callback2;
966
967 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
968 EXPECT_EQ(net::ERR_IO_PENDING, rv);
969
970 rv = callback2.WaitForResult();
971 EXPECT_EQ(net::OK, rv);
972
973 response = trans->GetResponseInfo();
974 EXPECT_FALSE(response == NULL);
975 EXPECT_TRUE(response->auth_challenge.get() == NULL);
976 EXPECT_EQ(100, response->headers->GetContentLength());
977}
978
979// Test the request-challenge-retry sequence for basic auth, over a keep-alive
980// connection and with a large response body to drain.
981TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) {
982 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
983 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
984 CreateSession(proxy_service.get()), &mock_socket_factory));
985
986 net::HttpRequestInfo request;
987 request.method = "GET";
988 request.url = GURL("http://www.google.com/");
989 request.load_flags = 0;
990
991 MockWrite data_writes1[] = {
992 MockWrite("GET / HTTP/1.1\r\n"
993 "Host: www.google.com\r\n"
994 "Connection: keep-alive\r\n\r\n"),
995
996 // After calling trans->RestartWithAuth(), this is the request we should
997 // be issuing -- the final header line contains the credentials.
998 MockWrite("GET / HTTP/1.1\r\n"
999 "Host: www.google.com\r\n"
1000 "Connection: keep-alive\r\n"
1001 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1002 };
1003
1004 // Respond with 5 kb of response body.
1005 std::string large_body_string("Unauthorized");
1006 large_body_string.append(5 * 1024, ' ');
1007 large_body_string.append("\r\n");
1008
1009 MockRead data_reads1[] = {
1010 MockRead("HTTP/1.1 401 Unauthorized\r\n"),
1011 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1012 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1013 // 5134 = 12 + 5 * 1024 + 2
1014 MockRead("Content-Length: 5134\r\n\r\n"),
1015 MockRead(true, large_body_string.data(), large_body_string.size()),
1016
1017 // Lastly, the server responds with the actual content.
1018 MockRead("HTTP/1.1 200 OK\r\n"),
1019 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1020 MockRead("Content-Length: 100\r\n\r\n"),
1021 MockRead(false, net::OK),
1022 };
1023
1024 MockSocket data1;
1025 data1.reads = data_reads1;
1026 data1.writes = data_writes1;
1027 mock_sockets[0] = &data1;
1028 mock_sockets[1] = NULL;
1029
1030 TestCompletionCallback callback1;
1031
1032 int rv = trans->Start(&request, &callback1);
1033 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1034
1035 rv = callback1.WaitForResult();
1036 EXPECT_EQ(net::OK, rv);
1037
1038 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1039 EXPECT_FALSE(response == NULL);
1040
1041 // The password prompt info should have been set in response->auth_challenge.
1042 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1043
1044 // TODO(eroman): this should really include the effective port (80)
1045 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
1046 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1047 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1048
1049 TestCompletionCallback callback2;
1050
1051 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
1052 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1053
1054 rv = callback2.WaitForResult();
1055 EXPECT_EQ(net::OK, rv);
1056
1057 response = trans->GetResponseInfo();
1058 EXPECT_FALSE(response == NULL);
1059 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1060 EXPECT_EQ(100, response->headers->GetContentLength());
1061}
1062
1063// Test the request-challenge-retry sequence for basic auth, over a keep-alive
1064// proxy connection, when setting up an SSL tunnel.
1065TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAlive) {
1066 // Configure against proxy server "myproxy:70".
1067 scoped_ptr<net::ProxyService> proxy_service(
1068 CreateFixedProxyService("myproxy:70"));
1069
1070 scoped_refptr<net::HttpNetworkSession> session(
1071 CreateSession(proxy_service.get()));
1072
1073 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1074 session.get(), &mock_socket_factory));
1075
1076 net::HttpRequestInfo request;
1077 request.method = "GET";
1078 request.url = GURL("https://www.google.com/");
1079 request.load_flags = 0;
1080
1081 // Since we have proxy, should try to establish tunnel.
1082 MockWrite data_writes1[] = {
1083 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
1084 "Host: www.google.com\r\n\r\n"),
1085
1086 // After calling trans->RestartWithAuth(), this is the request we should
1087 // be issuing -- the final header line contains the credentials.
1088 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
1089 "Host: www.google.com\r\n"
1090 "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"),
1091 };
1092
1093 // The proxy responds to the connect with a 407, using a persistent
1094 // connection.
1095 MockRead data_reads1[] = {
1096 // No credentials.
1097 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
1098 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1099 MockRead("Content-Length: 10\r\n\r\n"),
1100 MockRead("0123456789"),
1101
1102 // Wrong credentials (wrong password).
1103 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
1104 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1105 MockRead("Content-Length: 10\r\n\r\n"),
1106 // No response body because the test stops reading here.
1107 MockRead(false, net::ERR_UNEXPECTED), // Should not be reached.
1108 };
1109
1110 MockSocket data1;
1111 data1.writes = data_writes1;
1112 data1.reads = data_reads1;
1113 mock_sockets[0] = &data1;
1114 mock_sockets[1] = NULL;
1115
1116 TestCompletionCallback callback1;
1117
1118 int rv = trans->Start(&request, &callback1);
1119 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1120
1121 rv = callback1.WaitForResult();
1122 EXPECT_EQ(net::OK, rv);
1123
1124 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1125 EXPECT_FALSE(response == NULL);
1126
1127 EXPECT_TRUE(response->headers->IsKeepAlive());
1128 EXPECT_EQ(407, response->headers->response_code());
1129 EXPECT_EQ(10, response->headers->GetContentLength());
1130 EXPECT_TRUE(net::HttpVersion(1, 1) == response->headers->GetHttpVersion());
1131
1132 // The password prompt info should have been set in response->auth_challenge.
1133 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1134
1135 // TODO(eroman): this should really include the effective port (80)
1136 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host);
1137 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1138 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1139
1140 TestCompletionCallback callback2;
1141
1142 // Wrong password (should be "bar").
1143 rv = trans->RestartWithAuth(L"foo", L"baz", &callback2);
1144 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1145
1146 rv = callback2.WaitForResult();
1147 EXPECT_EQ(net::OK, rv);
1148
1149 response = trans->GetResponseInfo();
1150 EXPECT_FALSE(response == NULL);
1151
1152 EXPECT_TRUE(response->headers->IsKeepAlive());
1153 EXPECT_EQ(407, response->headers->response_code());
1154 EXPECT_EQ(10, response->headers->GetContentLength());
1155 EXPECT_TRUE(net::HttpVersion(1, 1) == response->headers->GetHttpVersion());
1156
1157 // The password prompt info should have been set in response->auth_challenge.
1158 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1159
1160 // TODO(eroman): this should really include the effective port (80)
1161 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host);
1162 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1163 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1164}
1165
[email protected]a8e9b162009-03-12 00:06:441166// Test that we don't read the response body when we fail to establish a tunnel,
1167// even if the user cancels the proxy's auth attempt.
1168TEST_F(HttpNetworkTransactionTest, BasicAuthProxyCancelTunnel) {
1169 // Configure against proxy server "myproxy:70".
1170 scoped_ptr<net::ProxyService> proxy_service(
1171 CreateFixedProxyService("myproxy:70"));
1172
1173 scoped_refptr<net::HttpNetworkSession> session(
1174 CreateSession(proxy_service.get()));
1175
1176 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1177 session.get(), &mock_socket_factory));
1178
1179 net::HttpRequestInfo request;
1180 request.method = "GET";
1181 request.url = GURL("https://www.google.com/");
1182 request.load_flags = 0;
1183
1184 // Since we have proxy, should try to establish tunnel.
1185 MockWrite data_writes[] = {
1186 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
1187 "Host: www.google.com\r\n\r\n"),
1188 };
1189
1190 // The proxy responds to the connect with a 407.
1191 MockRead data_reads[] = {
1192 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
1193 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1194 MockRead("Content-Length: 10\r\n\r\n"),
1195 MockRead(false, net::ERR_UNEXPECTED), // Should not be reached.
1196 };
1197
1198 MockSocket data;
1199 data.writes = data_writes;
1200 data.reads = data_reads;
1201 mock_sockets[0] = &data;
1202 mock_sockets[1] = NULL;
1203
1204 TestCompletionCallback callback;
1205
1206 int rv = trans->Start(&request, &callback);
1207 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1208
1209 rv = callback.WaitForResult();
1210 EXPECT_EQ(net::OK, rv);
1211
1212 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1213 EXPECT_FALSE(response == NULL);
1214
1215 EXPECT_TRUE(response->headers->IsKeepAlive());
1216 EXPECT_EQ(407, response->headers->response_code());
1217 EXPECT_EQ(10, response->headers->GetContentLength());
1218 EXPECT_TRUE(net::HttpVersion(1, 1) == response->headers->GetHttpVersion());
1219
1220 std::string response_data;
1221 rv = ReadTransaction(trans.get(), &response_data);
1222 EXPECT_EQ(net::ERR_TUNNEL_CONNECTION_FAILED, rv);
1223}
1224
[email protected]c744cf22009-02-27 07:28:081225static void ConnectStatusHelperWithExpectedStatus(
1226 const MockRead& status, int expected_status) {
1227 // Configure against proxy server "myproxy:70".
1228 scoped_ptr<net::ProxyService> proxy_service(
1229 CreateFixedProxyService("myproxy:70"));
1230
1231 scoped_refptr<net::HttpNetworkSession> session(
1232 CreateSession(proxy_service.get()));
1233
1234 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1235 session.get(), &mock_socket_factory));
1236
1237 net::HttpRequestInfo request;
1238 request.method = "GET";
1239 request.url = GURL("https://www.google.com/");
1240 request.load_flags = 0;
1241
1242 // Since we have proxy, should try to establish tunnel.
1243 MockWrite data_writes[] = {
1244 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
1245 "Host: www.google.com\r\n\r\n"),
1246 };
1247
1248 MockRead data_reads[] = {
1249 status,
1250 MockRead("Content-Length: 10\r\n\r\n"),
1251 // No response body because the test stops reading here.
1252 MockRead(false, net::ERR_UNEXPECTED), // Should not be reached.
1253 };
1254
1255 MockSocket data;
1256 data.writes = data_writes;
1257 data.reads = data_reads;
1258 mock_sockets[0] = &data;
1259 mock_sockets[1] = NULL;
1260
1261 TestCompletionCallback callback;
1262
1263 int rv = trans->Start(&request, &callback);
1264 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1265
1266 rv = callback.WaitForResult();
1267 EXPECT_EQ(expected_status, rv);
1268}
1269
1270static void ConnectStatusHelper(const MockRead& status) {
1271 ConnectStatusHelperWithExpectedStatus(
1272 status, net::ERR_TUNNEL_CONNECTION_FAILED);
1273}
1274
1275TEST_F(HttpNetworkTransactionTest, ConnectStatus100) {
1276 ConnectStatusHelper(MockRead("HTTP/1.1 100 Continue\r\n"));
1277}
1278
1279TEST_F(HttpNetworkTransactionTest, ConnectStatus101) {
1280 ConnectStatusHelper(MockRead("HTTP/1.1 101 Switching Protocols\r\n"));
1281}
1282
1283TEST_F(HttpNetworkTransactionTest, ConnectStatus201) {
1284 ConnectStatusHelper(MockRead("HTTP/1.1 201 Created\r\n"));
1285}
1286
1287TEST_F(HttpNetworkTransactionTest, ConnectStatus202) {
1288 ConnectStatusHelper(MockRead("HTTP/1.1 202 Accepted\r\n"));
1289}
1290
1291TEST_F(HttpNetworkTransactionTest, ConnectStatus203) {
1292 ConnectStatusHelper(
1293 MockRead("HTTP/1.1 203 Non-Authoritative Information\r\n"));
1294}
1295
1296TEST_F(HttpNetworkTransactionTest, ConnectStatus204) {
1297 ConnectStatusHelper(MockRead("HTTP/1.1 204 No Content\r\n"));
1298}
1299
1300TEST_F(HttpNetworkTransactionTest, ConnectStatus205) {
1301 ConnectStatusHelper(MockRead("HTTP/1.1 205 Reset Content\r\n"));
1302}
1303
1304TEST_F(HttpNetworkTransactionTest, ConnectStatus206) {
1305 ConnectStatusHelper(MockRead("HTTP/1.1 206 Partial Content\r\n"));
1306}
1307
1308TEST_F(HttpNetworkTransactionTest, ConnectStatus300) {
1309 ConnectStatusHelper(MockRead("HTTP/1.1 300 Multiple Choices\r\n"));
1310}
1311
1312TEST_F(HttpNetworkTransactionTest, ConnectStatus301) {
1313 ConnectStatusHelper(MockRead("HTTP/1.1 301 Moved Permanently\r\n"));
1314}
1315
1316TEST_F(HttpNetworkTransactionTest, ConnectStatus302) {
1317 ConnectStatusHelper(MockRead("HTTP/1.1 302 Found\r\n"));
1318}
1319
1320TEST_F(HttpNetworkTransactionTest, ConnectStatus303) {
1321 ConnectStatusHelper(MockRead("HTTP/1.1 303 See Other\r\n"));
1322}
1323
1324TEST_F(HttpNetworkTransactionTest, ConnectStatus304) {
1325 ConnectStatusHelper(MockRead("HTTP/1.1 304 Not Modified\r\n"));
1326}
1327
1328TEST_F(HttpNetworkTransactionTest, ConnectStatus305) {
1329 ConnectStatusHelper(MockRead("HTTP/1.1 305 Use Proxy\r\n"));
1330}
1331
1332TEST_F(HttpNetworkTransactionTest, ConnectStatus306) {
1333 ConnectStatusHelper(MockRead("HTTP/1.1 306\r\n"));
1334}
1335
1336TEST_F(HttpNetworkTransactionTest, ConnectStatus307) {
1337 ConnectStatusHelper(MockRead("HTTP/1.1 307 Temporary Redirect\r\n"));
1338}
1339
1340TEST_F(HttpNetworkTransactionTest, ConnectStatus400) {
1341 ConnectStatusHelper(MockRead("HTTP/1.1 400 Bad Request\r\n"));
1342}
1343
1344TEST_F(HttpNetworkTransactionTest, ConnectStatus401) {
1345 ConnectStatusHelper(MockRead("HTTP/1.1 401 Unauthorized\r\n"));
1346}
1347
1348TEST_F(HttpNetworkTransactionTest, ConnectStatus402) {
1349 ConnectStatusHelper(MockRead("HTTP/1.1 402 Payment Required\r\n"));
1350}
1351
1352TEST_F(HttpNetworkTransactionTest, ConnectStatus403) {
1353 ConnectStatusHelper(MockRead("HTTP/1.1 403 Forbidden\r\n"));
1354}
1355
1356TEST_F(HttpNetworkTransactionTest, ConnectStatus404) {
1357 ConnectStatusHelper(MockRead("HTTP/1.1 404 Not Found\r\n"));
1358}
1359
1360TEST_F(HttpNetworkTransactionTest, ConnectStatus405) {
1361 ConnectStatusHelper(MockRead("HTTP/1.1 405 Method Not Allowed\r\n"));
1362}
1363
1364TEST_F(HttpNetworkTransactionTest, ConnectStatus406) {
1365 ConnectStatusHelper(MockRead("HTTP/1.1 406 Not Acceptable\r\n"));
1366}
1367
1368TEST_F(HttpNetworkTransactionTest, ConnectStatus407) {
1369 ConnectStatusHelperWithExpectedStatus(
1370 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
1371 net::ERR_PROXY_AUTH_REQUESTED);
1372}
1373
1374TEST_F(HttpNetworkTransactionTest, ConnectStatus408) {
1375 ConnectStatusHelper(MockRead("HTTP/1.1 408 Request Timeout\r\n"));
1376}
1377
1378TEST_F(HttpNetworkTransactionTest, ConnectStatus409) {
1379 ConnectStatusHelper(MockRead("HTTP/1.1 409 Conflict\r\n"));
1380}
1381
1382TEST_F(HttpNetworkTransactionTest, ConnectStatus410) {
1383 ConnectStatusHelper(MockRead("HTTP/1.1 410 Gone\r\n"));
1384}
1385
1386TEST_F(HttpNetworkTransactionTest, ConnectStatus411) {
1387 ConnectStatusHelper(MockRead("HTTP/1.1 411 Length Required\r\n"));
1388}
1389
1390TEST_F(HttpNetworkTransactionTest, ConnectStatus412) {
1391 ConnectStatusHelper(MockRead("HTTP/1.1 412 Precondition Failed\r\n"));
1392}
1393
1394TEST_F(HttpNetworkTransactionTest, ConnectStatus413) {
1395 ConnectStatusHelper(MockRead("HTTP/1.1 413 Request Entity Too Large\r\n"));
1396}
1397
1398TEST_F(HttpNetworkTransactionTest, ConnectStatus414) {
1399 ConnectStatusHelper(MockRead("HTTP/1.1 414 Request-URI Too Long\r\n"));
1400}
1401
1402TEST_F(HttpNetworkTransactionTest, ConnectStatus415) {
1403 ConnectStatusHelper(MockRead("HTTP/1.1 415 Unsupported Media Type\r\n"));
1404}
1405
1406TEST_F(HttpNetworkTransactionTest, ConnectStatus416) {
1407 ConnectStatusHelper(
1408 MockRead("HTTP/1.1 416 Requested Range Not Satisfiable\r\n"));
1409}
1410
1411TEST_F(HttpNetworkTransactionTest, ConnectStatus417) {
1412 ConnectStatusHelper(MockRead("HTTP/1.1 417 Expectation Failed\r\n"));
1413}
1414
1415TEST_F(HttpNetworkTransactionTest, ConnectStatus500) {
1416 ConnectStatusHelper(MockRead("HTTP/1.1 500 Internal Server Error\r\n"));
1417}
1418
1419TEST_F(HttpNetworkTransactionTest, ConnectStatus501) {
1420 ConnectStatusHelper(MockRead("HTTP/1.1 501 Not Implemented\r\n"));
1421}
1422
1423TEST_F(HttpNetworkTransactionTest, ConnectStatus502) {
1424 ConnectStatusHelper(MockRead("HTTP/1.1 502 Bad Gateway\r\n"));
1425}
1426
1427TEST_F(HttpNetworkTransactionTest, ConnectStatus503) {
1428 ConnectStatusHelper(MockRead("HTTP/1.1 503 Service Unavailable\r\n"));
1429}
1430
1431TEST_F(HttpNetworkTransactionTest, ConnectStatus504) {
1432 ConnectStatusHelper(MockRead("HTTP/1.1 504 Gateway Timeout\r\n"));
1433}
1434
1435TEST_F(HttpNetworkTransactionTest, ConnectStatus505) {
1436 ConnectStatusHelper(MockRead("HTTP/1.1 505 HTTP Version Not Supported\r\n"));
1437}
1438
[email protected]038e9a32008-10-08 22:40:161439// Test the flow when both the proxy server AND origin server require
1440// authentication. Again, this uses basic auth for both since that is
1441// the simplest to mock.
1442TEST_F(HttpNetworkTransactionTest, BasicAuthProxyThenServer) {
[email protected]51fff29d2008-12-19 22:17:531443 scoped_ptr<net::ProxyService> proxy_service(
1444 CreateFixedProxyService("myproxy:70"));
[email protected]db8f44c2008-12-13 04:52:011445
[email protected]038e9a32008-10-08 22:40:161446 // Configure against proxy server "myproxy:70".
[email protected]af4876d2008-10-21 23:10:571447 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
[email protected]51fff29d2008-12-19 22:17:531448 CreateSession(proxy_service.get()),
[email protected]db8f44c2008-12-13 04:52:011449 &mock_socket_factory));
[email protected]038e9a32008-10-08 22:40:161450
1451 net::HttpRequestInfo request;
1452 request.method = "GET";
1453 request.url = GURL("http://www.google.com/");
1454 request.load_flags = 0;
1455
[email protected]f9ee6b52008-11-08 06:46:231456 MockWrite data_writes1[] = {
1457 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
1458 "Host: www.google.com\r\n"
1459 "Proxy-Connection: keep-alive\r\n\r\n"),
1460 };
1461
[email protected]038e9a32008-10-08 22:40:161462 MockRead data_reads1[] = {
1463 MockRead("HTTP/1.0 407 Unauthorized\r\n"),
1464 // Give a couple authenticate options (only the middle one is actually
1465 // supported).
[email protected]aaead502008-10-15 00:20:111466 MockRead("Proxy-Authenticate: Basic\r\n"), // Malformed
[email protected]038e9a32008-10-08 22:40:161467 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1468 MockRead("Proxy-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"),
1469 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1470 // Large content-length -- won't matter, as connection will be reset.
1471 MockRead("Content-Length: 10000\r\n\r\n"),
1472 MockRead(false, net::ERR_FAILED),
1473 };
1474
1475 // After calling trans->RestartWithAuth() the first time, this is the
1476 // request we should be issuing -- the final header line contains the
1477 // proxy's credentials.
1478 MockWrite data_writes2[] = {
1479 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
1480 "Host: www.google.com\r\n"
1481 "Proxy-Connection: keep-alive\r\n"
1482 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1483 };
1484
1485 // Now the proxy server lets the request pass through to origin server.
1486 // The origin server responds with a 401.
1487 MockRead data_reads2[] = {
1488 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
1489 // Note: We are using the same realm-name as the proxy server. This is
1490 // completely valid, as realms are unique across hosts.
1491 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1492 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1493 MockRead("Content-Length: 2000\r\n\r\n"),
[email protected]aaead502008-10-15 00:20:111494 MockRead(false, net::ERR_FAILED), // Won't be reached.
[email protected]038e9a32008-10-08 22:40:161495 };
1496
1497 // After calling trans->RestartWithAuth() the second time, we should send
1498 // the credentials for both the proxy and origin server.
1499 MockWrite data_writes3[] = {
1500 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
1501 "Host: www.google.com\r\n"
1502 "Proxy-Connection: keep-alive\r\n"
1503 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n"
1504 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"),
1505 };
1506
1507 // Lastly we get the desired content.
1508 MockRead data_reads3[] = {
1509 MockRead("HTTP/1.0 200 OK\r\n"),
1510 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1511 MockRead("Content-Length: 100\r\n\r\n"),
1512 MockRead(false, net::OK),
1513 };
1514
1515 MockSocket data1;
1516 data1.reads = data_reads1;
[email protected]f9ee6b52008-11-08 06:46:231517 data1.writes = data_writes1;
[email protected]038e9a32008-10-08 22:40:161518 MockSocket data2;
1519 data2.reads = data_reads2;
1520 data2.writes = data_writes2;
1521 MockSocket data3;
1522 data3.reads = data_reads3;
1523 data3.writes = data_writes3;
1524 mock_sockets[0] = &data1;
1525 mock_sockets[1] = &data2;
1526 mock_sockets[2] = &data3;
1527 mock_sockets[3] = NULL;
1528
1529 TestCompletionCallback callback1;
1530
1531 int rv = trans->Start(&request, &callback1);
1532 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1533
1534 rv = callback1.WaitForResult();
1535 EXPECT_EQ(net::OK, rv);
1536
1537 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1538 EXPECT_FALSE(response == NULL);
1539
1540 // The password prompt info should have been set in response->auth_challenge.
1541 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1542
1543 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host);
1544 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1545 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1546
1547 TestCompletionCallback callback2;
1548
1549 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
1550 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1551
1552 rv = callback2.WaitForResult();
1553 EXPECT_EQ(net::OK, rv);
1554
1555 response = trans->GetResponseInfo();
1556 EXPECT_FALSE(response == NULL);
1557 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1558
1559 // TODO(eroman): this should really include the effective port (80)
1560 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
1561 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1562 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1563
1564 TestCompletionCallback callback3;
1565
1566 rv = trans->RestartWithAuth(L"foo2", L"bar2", &callback3);
1567 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1568
1569 rv = callback3.WaitForResult();
1570 EXPECT_EQ(net::OK, rv);
1571
1572 response = trans->GetResponseInfo();
1573 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1574 EXPECT_EQ(100, response->headers->GetContentLength());
[email protected]038e9a32008-10-08 22:40:161575}
[email protected]4ddaf2502008-10-23 18:26:191576
[email protected]385a4672009-03-11 22:21:291577// The NTLM authentication unit tests were generated by capturing the HTTP
1578// requests and responses using Fiddler 2 and inspecting the generated random
1579// bytes in the debugger.
1580
1581// Enter the correct password and authenticate successfully.
1582TEST_F(HttpNetworkTransactionTest, NTLMAuth1) {
1583 net::HttpAuthHandlerNTLM::SetGenerateRandomProc(MyGenerateRandom1);
1584 net::HttpAuthHandlerNTLM::SetHostNameProc(MyGetHostName);
1585
[email protected]3f918782009-02-28 01:29:241586 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
1587 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1588 CreateSession(proxy_service.get()), &mock_socket_factory));
1589
1590 net::HttpRequestInfo request;
1591 request.method = "GET";
1592 request.url = GURL("http://172.22.68.17/kids/login.aspx");
1593 request.load_flags = 0;
1594
1595 MockWrite data_writes1[] = {
1596 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1597 "Host: 172.22.68.17\r\n"
1598 "Connection: keep-alive\r\n\r\n"),
1599 };
1600
1601 MockRead data_reads1[] = {
1602 MockRead("HTTP/1.1 401 Access Denied\r\n"),
1603 // Negotiate and NTLM are often requested together. We only support NTLM.
1604 MockRead("WWW-Authenticate: Negotiate\r\n"),
1605 MockRead("WWW-Authenticate: NTLM\r\n"),
1606 MockRead("Connection: close\r\n"),
1607 MockRead("Content-Length: 42\r\n"),
1608 MockRead("Content-Type: text/html\r\n"),
1609 MockRead("Proxy-Support: Session-Based-Authentication\r\n\r\n"),
1610 // Missing content -- won't matter, as connection will be reset.
1611 MockRead(false, net::ERR_UNEXPECTED),
1612 };
1613
1614 MockWrite data_writes2[] = {
1615 // After automatically restarting with a null identity, this is the
1616 // request we should be issuing -- the final header line contains a Type
1617 // 1 message.
1618 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1619 "Host: 172.22.68.17\r\n"
1620 "Connection: keep-alive\r\n"
1621 "Authorization: NTLM "
1622 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"),
1623
1624 // After calling trans->RestartWithAuth(), we should send a Type 3 message
1625 // (the credentials for the origin server). The second request continues
1626 // on the same connection.
1627 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1628 "Host: 172.22.68.17\r\n"
1629 "Connection: keep-alive\r\n"
[email protected]385a4672009-03-11 22:21:291630 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA"
1631 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA"
1632 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBVKW"
1633 "Yma5xzVAAAAAAAAAAAAAAAAAAAAACH+gWcm+YsP9Tqb9zCR3WAeZZX"
1634 "ahlhx5I=\r\n\r\n"),
[email protected]3f918782009-02-28 01:29:241635 };
1636
1637 MockRead data_reads2[] = {
1638 // The origin server responds with a Type 2 message.
1639 MockRead("HTTP/1.1 401 Access Denied\r\n"),
1640 MockRead("WWW-Authenticate: NTLM "
[email protected]385a4672009-03-11 22:21:291641 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCjGpMpPGlYKkAAAAAAAAAALo"
[email protected]3f918782009-02-28 01:29:241642 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE"
1643 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA"
1644 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy"
1645 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB"
1646 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw"
1647 "BtAAAAAAA=\r\n"),
1648 MockRead("Content-Length: 42\r\n"),
1649 MockRead("Content-Type: text/html\r\n"),
1650 MockRead("Proxy-Support: Session-Based-Authentication\r\n\r\n"),
1651 MockRead("You are not authorized to view this page\r\n"),
1652
1653 // Lastly we get the desired content.
1654 MockRead("HTTP/1.1 200 OK\r\n"),
1655 MockRead("Content-Type: text/html; charset=utf-8\r\n"),
1656 MockRead("Content-Length: 13\r\n\r\n"),
1657 MockRead("Please Login\r\n"),
1658 MockRead(false, net::OK),
1659 };
1660
1661 MockSocket data1;
1662 data1.reads = data_reads1;
1663 data1.writes = data_writes1;
1664 MockSocket data2;
1665 data2.reads = data_reads2;
1666 data2.writes = data_writes2;
1667 mock_sockets[0] = &data1;
1668 mock_sockets[1] = &data2;
1669 mock_sockets[2] = NULL;
1670
1671 TestCompletionCallback callback1;
1672
1673 int rv = trans->Start(&request, &callback1);
1674 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1675
1676 rv = callback1.WaitForResult();
1677 EXPECT_EQ(net::OK, rv);
1678
1679 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1680 EXPECT_FALSE(response == NULL);
1681
1682 // The password prompt info should have been set in response->auth_challenge.
1683 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1684
1685 // TODO(eroman): this should really include the effective port (80)
1686 EXPECT_EQ(L"172.22.68.17", response->auth_challenge->host);
1687 EXPECT_EQ(L"", response->auth_challenge->realm);
1688 EXPECT_EQ(L"ntlm", response->auth_challenge->scheme);
1689
[email protected]3f918782009-02-28 01:29:241690 TestCompletionCallback callback2;
1691
1692 rv = trans->RestartWithAuth(L"testing-ntlm", L"testing-ntlm", &callback2);
1693 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1694
1695 rv = callback2.WaitForResult();
1696 EXPECT_EQ(net::OK, rv);
1697
1698 response = trans->GetResponseInfo();
1699 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1700 EXPECT_EQ(13, response->headers->GetContentLength());
1701}
1702
[email protected]385a4672009-03-11 22:21:291703// Enter a wrong password, and then the correct one.
1704TEST_F(HttpNetworkTransactionTest, NTLMAuth2) {
1705 net::HttpAuthHandlerNTLM::SetGenerateRandomProc(MyGenerateRandom2);
1706 net::HttpAuthHandlerNTLM::SetHostNameProc(MyGetHostName);
1707
1708 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
1709 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1710 CreateSession(proxy_service.get()), &mock_socket_factory));
1711
1712 net::HttpRequestInfo request;
1713 request.method = "GET";
1714 request.url = GURL("http://172.22.68.17/kids/login.aspx");
1715 request.load_flags = 0;
1716
1717 MockWrite data_writes1[] = {
1718 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1719 "Host: 172.22.68.17\r\n"
1720 "Connection: keep-alive\r\n\r\n"),
1721 };
1722
1723 MockRead data_reads1[] = {
1724 MockRead("HTTP/1.1 401 Access Denied\r\n"),
1725 // Negotiate and NTLM are often requested together. We only support NTLM.
1726 MockRead("WWW-Authenticate: Negotiate\r\n"),
1727 MockRead("WWW-Authenticate: NTLM\r\n"),
1728 MockRead("Connection: close\r\n"),
1729 MockRead("Content-Length: 42\r\n"),
1730 MockRead("Content-Type: text/html\r\n"),
1731 MockRead("Proxy-Support: Session-Based-Authentication\r\n\r\n"),
1732 // Missing content -- won't matter, as connection will be reset.
1733 MockRead(false, net::ERR_UNEXPECTED),
1734 };
1735
1736 MockWrite data_writes2[] = {
1737 // After automatically restarting with a null identity, this is the
1738 // request we should be issuing -- the final header line contains a Type
1739 // 1 message.
1740 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1741 "Host: 172.22.68.17\r\n"
1742 "Connection: keep-alive\r\n"
1743 "Authorization: NTLM "
1744 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"),
1745
1746 // After calling trans->RestartWithAuth(), we should send a Type 3 message
1747 // (the credentials for the origin server). The second request continues
1748 // on the same connection.
1749 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1750 "Host: 172.22.68.17\r\n"
1751 "Connection: keep-alive\r\n"
1752 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA"
1753 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA"
1754 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwCWeY"
1755 "XnSZNwoQAAAAAAAAAAAAAAAAAAAADLa34/phTTKzNTWdub+uyFleOj"
1756 "4Ww7b7E=\r\n\r\n"),
1757 };
1758
1759 MockRead data_reads2[] = {
1760 // The origin server responds with a Type 2 message.
1761 MockRead("HTTP/1.1 401 Access Denied\r\n"),
1762 MockRead("WWW-Authenticate: NTLM "
1763 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCbVWUZezVGpAAAAAAAAAAALo"
1764 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE"
1765 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA"
1766 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy"
1767 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB"
1768 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw"
1769 "BtAAAAAAA=\r\n"),
1770 MockRead("Content-Length: 42\r\n"),
1771 MockRead("Content-Type: text/html\r\n"),
1772 MockRead("Proxy-Support: Session-Based-Authentication\r\n\r\n"),
1773 MockRead("You are not authorized to view this page\r\n"),
1774
1775 // Wrong password.
1776 MockRead("HTTP/1.1 401 Access Denied\r\n"),
1777 MockRead("WWW-Authenticate: Negotiate\r\n"),
1778 MockRead("WWW-Authenticate: NTLM\r\n"),
1779 MockRead("Connection: close\r\n"),
1780 MockRead("Content-Length: 42\r\n"),
1781 MockRead("Content-Type: text/html\r\n"),
1782 MockRead("Proxy-Support: Session-Based-Authentication\r\n\r\n"),
1783 // Missing content -- won't matter, as connection will be reset.
1784 MockRead(false, net::ERR_UNEXPECTED),
1785 };
1786
1787 MockWrite data_writes3[] = {
1788 // After automatically restarting with a null identity, this is the
1789 // request we should be issuing -- the final header line contains a Type
1790 // 1 message.
1791 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1792 "Host: 172.22.68.17\r\n"
1793 "Connection: keep-alive\r\n"
1794 "Authorization: NTLM "
1795 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"),
1796
1797 // After calling trans->RestartWithAuth(), we should send a Type 3 message
1798 // (the credentials for the origin server). The second request continues
1799 // on the same connection.
1800 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1801 "Host: 172.22.68.17\r\n"
1802 "Connection: keep-alive\r\n"
1803 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA"
1804 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA"
1805 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBO54"
1806 "dFMVvTHwAAAAAAAAAAAAAAAAAAAACS7sT6Uzw7L0L//WUqlIaVWpbI"
1807 "+4MUm7c=\r\n\r\n"),
1808 };
1809
1810 MockRead data_reads3[] = {
1811 // The origin server responds with a Type 2 message.
1812 MockRead("HTTP/1.1 401 Access Denied\r\n"),
1813 MockRead("WWW-Authenticate: NTLM "
1814 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCL24VN8dgOR8AAAAAAAAAALo"
1815 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE"
1816 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA"
1817 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy"
1818 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB"
1819 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw"
1820 "BtAAAAAAA=\r\n"),
1821 MockRead("Content-Length: 42\r\n"),
1822 MockRead("Content-Type: text/html\r\n"),
1823 MockRead("Proxy-Support: Session-Based-Authentication\r\n\r\n"),
1824 MockRead("You are not authorized to view this page\r\n"),
1825
1826 // Lastly we get the desired content.
1827 MockRead("HTTP/1.1 200 OK\r\n"),
1828 MockRead("Content-Type: text/html; charset=utf-8\r\n"),
1829 MockRead("Content-Length: 13\r\n\r\n"),
1830 MockRead("Please Login\r\n"),
1831 MockRead(false, net::OK),
1832 };
1833
1834 MockSocket data1;
1835 data1.reads = data_reads1;
1836 data1.writes = data_writes1;
1837 MockSocket data2;
1838 data2.reads = data_reads2;
1839 data2.writes = data_writes2;
1840 MockSocket data3;
1841 data3.reads = data_reads3;
1842 data3.writes = data_writes3;
1843 mock_sockets[0] = &data1;
1844 mock_sockets[1] = &data2;
1845 mock_sockets[2] = &data3;
1846 mock_sockets[3] = NULL;
1847
1848 TestCompletionCallback callback1;
1849
1850 int rv = trans->Start(&request, &callback1);
1851 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1852
1853 rv = callback1.WaitForResult();
1854 EXPECT_EQ(net::OK, rv);
1855
1856 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1857 EXPECT_FALSE(response == NULL);
1858
1859 // The password prompt info should have been set in response->auth_challenge.
1860 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1861
1862 // TODO(eroman): this should really include the effective port (80)
1863 EXPECT_EQ(L"172.22.68.17", response->auth_challenge->host);
1864 EXPECT_EQ(L"", response->auth_challenge->realm);
1865 EXPECT_EQ(L"ntlm", response->auth_challenge->scheme);
1866
1867 TestCompletionCallback callback2;
1868
1869 // Enter the wrong password.
1870 rv = trans->RestartWithAuth(L"testing-ntlm", L"wrongpassword", &callback2);
1871 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1872
1873 rv = callback2.WaitForResult();
1874 EXPECT_EQ(net::OK, rv);
1875
1876 response = trans->GetResponseInfo();
1877 EXPECT_FALSE(response == NULL);
1878
1879 // The password prompt info should have been set in response->auth_challenge.
1880 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1881
1882 // TODO(eroman): this should really include the effective port (80)
1883 EXPECT_EQ(L"172.22.68.17", response->auth_challenge->host);
1884 EXPECT_EQ(L"", response->auth_challenge->realm);
1885 EXPECT_EQ(L"ntlm", response->auth_challenge->scheme);
1886
1887 TestCompletionCallback callback3;
1888
1889 // Now enter the right password.
1890 rv = trans->RestartWithAuth(L"testing-ntlm", L"testing-ntlm", &callback3);
1891 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1892
1893 rv = callback3.WaitForResult();
1894 EXPECT_EQ(net::OK, rv);
1895
1896 response = trans->GetResponseInfo();
1897 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1898 EXPECT_EQ(13, response->headers->GetContentLength());
1899}
1900
[email protected]4ddaf2502008-10-23 18:26:191901// Test reading a server response which has only headers, and no body.
1902// After some maximum number of bytes is consumed, the transaction should
1903// fail with ERR_RESPONSE_HEADERS_TOO_BIG.
1904TEST_F(HttpNetworkTransactionTest, LargeHeadersNoBody) {
[email protected]db8f44c2008-12-13 04:52:011905 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
[email protected]4ddaf2502008-10-23 18:26:191906 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
[email protected]db8f44c2008-12-13 04:52:011907 CreateSession(proxy_service.get()), &mock_socket_factory));
[email protected]4ddaf2502008-10-23 18:26:191908
1909 net::HttpRequestInfo request;
1910 request.method = "GET";
1911 request.url = GURL("http://www.google.com/");
1912 request.load_flags = 0;
1913
1914 // Respond with 50 kb of headers (we should fail after 32 kb).
[email protected]15a5ccf82008-10-23 19:57:431915 std::string large_headers_string;
1916 FillLargeHeadersString(&large_headers_string, 50 * 1024);
[email protected]4ddaf2502008-10-23 18:26:191917
1918 MockRead data_reads[] = {
1919 MockRead("HTTP/1.0 200 OK\r\n"),
[email protected]15a5ccf82008-10-23 19:57:431920 MockRead(true, large_headers_string.data(), large_headers_string.size()),
[email protected]4ddaf2502008-10-23 18:26:191921 MockRead("\r\nBODY"),
1922 MockRead(false, net::OK),
1923 };
1924 MockSocket data;
1925 data.reads = data_reads;
1926 mock_sockets[0] = &data;
1927 mock_sockets[1] = NULL;
1928
1929 TestCompletionCallback callback;
1930
1931 int rv = trans->Start(&request, &callback);
1932 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1933
1934 rv = callback.WaitForResult();
1935 EXPECT_EQ(net::ERR_RESPONSE_HEADERS_TOO_BIG, rv);
1936
1937 const net::HttpResponseInfo* response = trans->GetResponseInfo();
1938 EXPECT_TRUE(response == NULL);
1939}
[email protected]f4e426b2008-11-05 00:24:491940
1941// Make sure that we don't try to reuse a TCPClientSocket when failing to
1942// establish tunnel.
1943// http://code.google.com/p/chromium/issues/detail?id=3772
1944TEST_F(HttpNetworkTransactionTest, DontRecycleTCPSocketForSSLTunnel) {
1945 // Configure against proxy server "myproxy:70".
[email protected]51fff29d2008-12-19 22:17:531946 scoped_ptr<net::ProxyService> proxy_service(
1947 CreateFixedProxyService("myproxy:70"));
[email protected]db8f44c2008-12-13 04:52:011948
[email protected]f4e426b2008-11-05 00:24:491949 scoped_refptr<net::HttpNetworkSession> session(
[email protected]51fff29d2008-12-19 22:17:531950 CreateSession(proxy_service.get()));
[email protected]f4e426b2008-11-05 00:24:491951
1952 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
1953 session.get(), &mock_socket_factory));
1954
1955 net::HttpRequestInfo request;
1956 request.method = "GET";
1957 request.url = GURL("https://www.google.com/");
1958 request.load_flags = 0;
1959
1960 // Since we have proxy, should try to establish tunnel.
1961 MockWrite data_writes1[] = {
1962 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
1963 "Host: www.google.com\r\n\r\n"),
1964 };
1965
[email protected]77848d12008-11-14 00:00:221966 // The proxy responds to the connect with a 404, using a persistent
[email protected]f4e426b2008-11-05 00:24:491967 // connection. Usually a proxy would return 501 (not implemented),
1968 // or 200 (tunnel established).
1969 MockRead data_reads1[] = {
1970 MockRead("HTTP/1.1 404 Not Found\r\n"),
1971 MockRead("Content-Length: 10\r\n\r\n"),
[email protected]77848d12008-11-14 00:00:221972 MockRead(false, net::ERR_UNEXPECTED), // Should not be reached.
[email protected]f4e426b2008-11-05 00:24:491973 };
1974
1975 MockSocket data1;
1976 data1.writes = data_writes1;
1977 data1.reads = data_reads1;
1978 mock_sockets[0] = &data1;
1979 mock_sockets[1] = NULL;
1980
1981 TestCompletionCallback callback1;
1982
1983 int rv = trans->Start(&request, &callback1);
1984 EXPECT_EQ(net::ERR_IO_PENDING, rv);
1985
1986 rv = callback1.WaitForResult();
[email protected]c744cf22009-02-27 07:28:081987 EXPECT_EQ(net::ERR_TUNNEL_CONNECTION_FAILED, rv);
[email protected]f4e426b2008-11-05 00:24:491988
1989 const net::HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]c744cf22009-02-27 07:28:081990 EXPECT_TRUE(response == NULL);
[email protected]f4e426b2008-11-05 00:24:491991
1992 // We now check to make sure the TCPClientSocket was not added back to
1993 // the pool.
1994 EXPECT_EQ(0, session->connection_pool()->idle_socket_count());
1995 trans.reset();
1996 // Make sure that the socket didn't get recycled after calling the destructor.
1997 EXPECT_EQ(0, session->connection_pool()->idle_socket_count());
1998}
[email protected]372d34a2008-11-05 21:30:511999
2000TEST_F(HttpNetworkTransactionTest, ResendRequestOnWriteBodyError) {
2001 net::HttpRequestInfo request[2];
2002 // Transaction 1: a GET request that succeeds. The socket is recycled
2003 // after use.
2004 request[0].method = "GET";
2005 request[0].url = GURL("http://www.google.com/");
2006 request[0].load_flags = 0;
2007 // Transaction 2: a POST request. Reuses the socket kept alive from
2008 // transaction 1. The first attempts fails when writing the POST data.
2009 // This causes the transaction to retry with a new socket. The second
2010 // attempt succeeds.
2011 request[1].method = "POST";
2012 request[1].url = GURL("http://www.google.com/login.cgi");
2013 request[1].upload_data = new net::UploadData;
2014 request[1].upload_data->AppendBytes("foo", 3);
2015 request[1].load_flags = 0;
2016
[email protected]db8f44c2008-12-13 04:52:012017 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
2018 scoped_refptr<net::HttpNetworkSession> session =
2019 CreateSession(proxy_service.get());
[email protected]372d34a2008-11-05 21:30:512020
2021 // The first socket is used for transaction 1 and the first attempt of
2022 // transaction 2.
2023
2024 // The response of transaction 1.
2025 MockRead data_reads1[] = {
2026 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\n"),
2027 MockRead("hello world"),
2028 MockRead(false, net::OK),
2029 };
2030 // The mock write results of transaction 1 and the first attempt of
2031 // transaction 2.
2032 MockWrite data_writes1[] = {
2033 MockWrite(false, 64), // GET
2034 MockWrite(false, 93), // POST
2035 MockWrite(false, net::ERR_CONNECTION_ABORTED), // POST data
2036 };
2037 MockSocket data1;
2038 data1.reads = data_reads1;
2039 data1.writes = data_writes1;
2040
2041 // The second socket is used for the second attempt of transaction 2.
2042
2043 // The response of transaction 2.
2044 MockRead data_reads2[] = {
2045 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 7\r\n\r\n"),
2046 MockRead("welcome"),
2047 MockRead(false, net::OK),
2048 };
2049 // The mock write results of the second attempt of transaction 2.
2050 MockWrite data_writes2[] = {
2051 MockWrite(false, 93), // POST
2052 MockWrite(false, 3), // POST data
2053 };
2054 MockSocket data2;
2055 data2.reads = data_reads2;
2056 data2.writes = data_writes2;
2057
2058 mock_sockets[0] = &data1;
2059 mock_sockets[1] = &data2;
2060 mock_sockets[2] = NULL;
2061
2062 const char* kExpectedResponseData[] = {
2063 "hello world", "welcome"
2064 };
2065
2066 for (int i = 0; i < 2; ++i) {
2067 scoped_ptr<net::HttpTransaction> trans(
2068 new net::HttpNetworkTransaction(session, &mock_socket_factory));
2069
2070 TestCompletionCallback callback;
2071
2072 int rv = trans->Start(&request[i], &callback);
2073 EXPECT_EQ(net::ERR_IO_PENDING, rv);
2074
2075 rv = callback.WaitForResult();
2076 EXPECT_EQ(net::OK, rv);
2077
2078 const net::HttpResponseInfo* response = trans->GetResponseInfo();
2079 EXPECT_TRUE(response != NULL);
2080
2081 EXPECT_TRUE(response->headers != NULL);
2082 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
2083
2084 std::string response_data;
2085 rv = ReadTransaction(trans.get(), &response_data);
2086 EXPECT_EQ(net::OK, rv);
2087 EXPECT_EQ(kExpectedResponseData[i], response_data);
2088 }
2089}
[email protected]f9ee6b52008-11-08 06:46:232090
2091// Test the request-challenge-retry sequence for basic auth when there is
2092// an identity in the URL. The request should be sent as normal, but when
2093// it fails the identity from the URL is used to answer the challenge.
2094TEST_F(HttpNetworkTransactionTest, AuthIdentityInUrl) {
[email protected]db8f44c2008-12-13 04:52:012095 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
[email protected]f9ee6b52008-11-08 06:46:232096 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
[email protected]db8f44c2008-12-13 04:52:012097 CreateSession(proxy_service.get()), &mock_socket_factory));
[email protected]f9ee6b52008-11-08 06:46:232098
2099 net::HttpRequestInfo request;
2100 request.method = "GET";
2101 // Note: the URL has a username:password in it.
2102 request.url = GURL("http://foo:[email protected]/");
2103 request.load_flags = 0;
2104
2105 MockWrite data_writes1[] = {
2106 MockWrite("GET / HTTP/1.1\r\n"
2107 "Host: www.google.com\r\n"
2108 "Connection: keep-alive\r\n\r\n"),
2109 };
2110
2111 MockRead data_reads1[] = {
2112 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
2113 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
2114 MockRead("Content-Length: 10\r\n\r\n"),
2115 MockRead(false, net::ERR_FAILED),
2116 };
2117
2118 // After the challenge above, the transaction will be restarted using the
2119 // identity from the url (foo, bar) to answer the challenge.
2120 MockWrite data_writes2[] = {
2121 MockWrite("GET / HTTP/1.1\r\n"
2122 "Host: www.google.com\r\n"
2123 "Connection: keep-alive\r\n"
2124 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
2125 };
2126
2127 MockRead data_reads2[] = {
2128 MockRead("HTTP/1.0 200 OK\r\n"),
2129 MockRead("Content-Length: 100\r\n\r\n"),
2130 MockRead(false, net::OK),
2131 };
2132
2133 MockSocket data1;
2134 data1.reads = data_reads1;
2135 data1.writes = data_writes1;
2136 MockSocket data2;
2137 data2.reads = data_reads2;
2138 data2.writes = data_writes2;
2139 mock_sockets[0] = &data1;
2140 mock_sockets[1] = &data2;
2141 mock_sockets[2] = NULL;
2142
2143 TestCompletionCallback callback1;
2144
2145 int rv = trans->Start(&request, &callback1);
2146 EXPECT_EQ(net::ERR_IO_PENDING, rv);
2147
2148 rv = callback1.WaitForResult();
2149 EXPECT_EQ(net::OK, rv);
2150
2151 const net::HttpResponseInfo* response = trans->GetResponseInfo();
2152 EXPECT_FALSE(response == NULL);
2153
2154 // There is no challenge info, since the identity in URL worked.
2155 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2156
2157 EXPECT_EQ(100, response->headers->GetContentLength());
2158
2159 // Empty the current queue.
2160 MessageLoop::current()->RunAllPending();
2161}
2162
2163// Test that previously tried username/passwords for a realm get re-used.
2164TEST_F(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
[email protected]db8f44c2008-12-13 04:52:012165 scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
2166 scoped_refptr<net::HttpNetworkSession> session =
2167 CreateSession(proxy_service.get());
[email protected]f9ee6b52008-11-08 06:46:232168
2169 // Transaction 1: authenticate (foo, bar) on MyRealm1
2170 {
2171 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
2172 session, &mock_socket_factory));
2173
2174 net::HttpRequestInfo request;
2175 request.method = "GET";
2176 request.url = GURL("http://www.google.com/x/y/z");
2177 request.load_flags = 0;
2178
2179 MockWrite data_writes1[] = {
2180 MockWrite("GET /x/y/z HTTP/1.1\r\n"
2181 "Host: www.google.com\r\n"
2182 "Connection: keep-alive\r\n\r\n"),
2183 };
2184
2185 MockRead data_reads1[] = {
2186 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
2187 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
2188 MockRead("Content-Length: 10000\r\n\r\n"),
2189 MockRead(false, net::ERR_FAILED),
2190 };
2191
2192 // Resend with authorization (username=foo, password=bar)
2193 MockWrite data_writes2[] = {
2194 MockWrite("GET /x/y/z HTTP/1.1\r\n"
2195 "Host: www.google.com\r\n"
2196 "Connection: keep-alive\r\n"
2197 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
2198 };
2199
2200 // Sever accepts the authorization.
2201 MockRead data_reads2[] = {
2202 MockRead("HTTP/1.0 200 OK\r\n"),
2203 MockRead("Content-Length: 100\r\n\r\n"),
2204 MockRead(false, net::OK),
2205 };
2206
2207 MockSocket data1;
2208 data1.reads = data_reads1;
2209 data1.writes = data_writes1;
2210 MockSocket data2;
2211 data2.reads = data_reads2;
2212 data2.writes = data_writes2;
2213 mock_sockets_index = 0;
2214 mock_sockets[0] = &data1;
2215 mock_sockets[1] = &data2;
2216 mock_sockets[2] = NULL;
2217
2218 TestCompletionCallback callback1;
2219
2220 int rv = trans->Start(&request, &callback1);
2221 EXPECT_EQ(net::ERR_IO_PENDING, rv);
2222
2223 rv = callback1.WaitForResult();
2224 EXPECT_EQ(net::OK, rv);
2225
2226 const net::HttpResponseInfo* response = trans->GetResponseInfo();
2227 EXPECT_FALSE(response == NULL);
2228
2229 // The password prompt info should have been set in
2230 // response->auth_challenge.
2231 EXPECT_FALSE(response->auth_challenge.get() == NULL);
2232
2233 // TODO(eroman): this should really include the effective port (80)
2234 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
2235 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
2236 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
2237
2238 TestCompletionCallback callback2;
2239
2240 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
2241 EXPECT_EQ(net::ERR_IO_PENDING, rv);
2242
2243 rv = callback2.WaitForResult();
2244 EXPECT_EQ(net::OK, rv);
2245
2246 response = trans->GetResponseInfo();
2247 EXPECT_FALSE(response == NULL);
2248 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2249 EXPECT_EQ(100, response->headers->GetContentLength());
2250 }
2251
2252 // ------------------------------------------------------------------------
2253
2254 // Transaction 2: authenticate (foo2, bar2) on MyRealm2
2255 {
2256 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
2257 session, &mock_socket_factory));
2258
2259 net::HttpRequestInfo request;
2260 request.method = "GET";
2261 // Note that Transaction 1 was at /x/y/z, so this is in the same
2262 // protection space as MyRealm1.
2263 request.url = GURL("http://www.google.com/x/y/a/b");
2264 request.load_flags = 0;
2265
2266 MockWrite data_writes1[] = {
2267 MockWrite("GET /x/y/a/b HTTP/1.1\r\n"
2268 "Host: www.google.com\r\n"
2269 "Connection: keep-alive\r\n"
2270 // Send preemptive authorization for MyRealm1
2271 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
2272 };
2273
2274 // The server didn't like the preemptive authorization, and
2275 // challenges us for a different realm (MyRealm2).
2276 MockRead data_reads1[] = {
2277 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
2278 MockRead("WWW-Authenticate: Basic realm=\"MyRealm2\"\r\n"),
2279 MockRead("Content-Length: 10000\r\n\r\n"),
2280 MockRead(false, net::ERR_FAILED),
2281 };
2282
2283 // Resend with authorization for MyRealm2 (username=foo2, password=bar2)
2284 MockWrite data_writes2[] = {
2285 MockWrite("GET /x/y/a/b HTTP/1.1\r\n"
2286 "Host: www.google.com\r\n"
2287 "Connection: keep-alive\r\n"
2288 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"),
2289 };
2290
2291 // Sever accepts the authorization.
2292 MockRead data_reads2[] = {
2293 MockRead("HTTP/1.0 200 OK\r\n"),
2294 MockRead("Content-Length: 100\r\n\r\n"),
2295 MockRead(false, net::OK),
2296 };
2297
2298 MockSocket data1;
2299 data1.reads = data_reads1;
2300 data1.writes = data_writes1;
2301 MockSocket data2;
2302 data2.reads = data_reads2;
2303 data2.writes = data_writes2;
2304 mock_sockets_index = 0;
2305 mock_sockets[0] = &data1;
2306 mock_sockets[1] = &data2;
2307 mock_sockets[2] = NULL;
2308
2309 TestCompletionCallback callback1;
2310
2311 int rv = trans->Start(&request, &callback1);
2312 EXPECT_EQ(net::ERR_IO_PENDING, rv);
2313
2314 rv = callback1.WaitForResult();
2315 EXPECT_EQ(net::OK, rv);
2316
2317 const net::HttpResponseInfo* response = trans->GetResponseInfo();
2318 EXPECT_FALSE(response == NULL);
2319
2320 // The password prompt info should have been set in
2321 // response->auth_challenge.
2322 EXPECT_FALSE(response->auth_challenge.get() == NULL);
2323
2324 // TODO(eroman): this should really include the effective port (80)
2325 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
2326 EXPECT_EQ(L"MyRealm2", response->auth_challenge->realm);
2327 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
2328
2329 TestCompletionCallback callback2;
2330
2331 rv = trans->RestartWithAuth(L"foo2", L"bar2", &callback2);
2332 EXPECT_EQ(net::ERR_IO_PENDING, rv);
2333
2334 rv = callback2.WaitForResult();
2335 EXPECT_EQ(net::OK, rv);
2336
2337 response = trans->GetResponseInfo();
2338 EXPECT_FALSE(response == NULL);
2339 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2340 EXPECT_EQ(100, response->headers->GetContentLength());
2341 }
2342
2343 // ------------------------------------------------------------------------
2344
2345 // Transaction 3: Resend a request in MyRealm's protection space --
2346 // succeed with preemptive authorization.
2347 {
2348 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
2349 session, &mock_socket_factory));
2350
2351 net::HttpRequestInfo request;
2352 request.method = "GET";
2353 request.url = GURL("http://www.google.com/x/y/z2");
2354 request.load_flags = 0;
2355
2356 MockWrite data_writes1[] = {
2357 MockWrite("GET /x/y/z2 HTTP/1.1\r\n"
2358 "Host: www.google.com\r\n"
2359 "Connection: keep-alive\r\n"
2360 // The authorization for MyRealm1 gets sent preemptively
2361 // (since the url is in the same protection space)
2362 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
2363 };
2364
2365 // Sever accepts the preemptive authorization
2366 MockRead data_reads1[] = {
2367 MockRead("HTTP/1.0 200 OK\r\n"),
2368 MockRead("Content-Length: 100\r\n\r\n"),
2369 MockRead(false, net::OK),
2370 };
2371
2372 MockSocket data1;
2373 data1.reads = data_reads1;
2374 data1.writes = data_writes1;
2375 mock_sockets_index = 0;
2376 mock_sockets[0] = &data1;
2377 mock_sockets[1] = NULL;
2378
2379 TestCompletionCallback callback1;
2380
2381 int rv = trans->Start(&request, &callback1);
2382 EXPECT_EQ(net::ERR_IO_PENDING, rv);
2383
2384 rv = callback1.WaitForResult();
2385 EXPECT_EQ(net::OK, rv);
2386
2387 const net::HttpResponseInfo* response = trans->GetResponseInfo();
2388 EXPECT_FALSE(response == NULL);
2389
2390 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2391 EXPECT_EQ(100, response->headers->GetContentLength());
2392 }
2393
2394 // ------------------------------------------------------------------------
2395
2396 // Transaction 4: request another URL in MyRealm (however the
2397 // url is not known to belong to the protection space, so no pre-auth).
2398 {
2399 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
2400 session, &mock_socket_factory));
2401
2402 net::HttpRequestInfo request;
2403 request.method = "GET";
2404 request.url = GURL("http://www.google.com/x/1");
2405 request.load_flags = 0;
2406
2407 MockWrite data_writes1[] = {
2408 MockWrite("GET /x/1 HTTP/1.1\r\n"
2409 "Host: www.google.com\r\n"
2410 "Connection: keep-alive\r\n\r\n"),
2411 };
2412
2413 MockRead data_reads1[] = {
2414 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
2415 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
2416 MockRead("Content-Length: 10000\r\n\r\n"),
2417 MockRead(false, net::ERR_FAILED),
2418 };
2419
2420 // Resend with authorization from MyRealm's cache.
2421 MockWrite data_writes2[] = {
2422 MockWrite("GET /x/1 HTTP/1.1\r\n"
2423 "Host: www.google.com\r\n"
2424 "Connection: keep-alive\r\n"
2425 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
2426 };
2427
2428 // Sever accepts the authorization.
2429 MockRead data_reads2[] = {
2430 MockRead("HTTP/1.0 200 OK\r\n"),
2431 MockRead("Content-Length: 100\r\n\r\n"),
2432 MockRead(false, net::OK),
2433 };
2434
2435 MockSocket data1;
2436 data1.reads = data_reads1;
2437 data1.writes = data_writes1;
2438 MockSocket data2;
2439 data2.reads = data_reads2;
2440 data2.writes = data_writes2;
2441 mock_sockets_index = 0;
2442 mock_sockets[0] = &data1;
2443 mock_sockets[1] = &data2;
2444 mock_sockets[2] = NULL;
2445
2446 TestCompletionCallback callback1;
2447
2448 int rv = trans->Start(&request, &callback1);
2449 EXPECT_EQ(net::ERR_IO_PENDING, rv);
2450
2451 rv = callback1.WaitForResult();
2452 EXPECT_EQ(net::OK, rv);
2453
2454 const net::HttpResponseInfo* response = trans->GetResponseInfo();
2455 EXPECT_FALSE(response == NULL);
2456 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2457 EXPECT_EQ(100, response->headers->GetContentLength());
2458 }
2459
2460 // ------------------------------------------------------------------------
2461
2462 // Transaction 5: request a URL in MyRealm, but the server rejects the
2463 // cached identity. Should invalidate and re-prompt.
2464 {
2465 scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
2466 session, &mock_socket_factory));
2467
2468 net::HttpRequestInfo request;
2469 request.method = "GET";
2470 request.url = GURL("http://www.google.com/p/q/t");
2471 request.load_flags = 0;
2472
2473 MockWrite data_writes1[] = {
2474 MockWrite("GET /p/q/t HTTP/1.1\r\n"
2475 "Host: www.google.com\r\n"
2476 "Connection: keep-alive\r\n\r\n"),
2477 };
2478
2479 MockRead data_reads1[] = {
2480 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
2481 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
2482 MockRead("Content-Length: 10000\r\n\r\n"),
2483 MockRead(false, net::ERR_FAILED),
2484 };
2485
2486 // Resend with authorization from cache for MyRealm.
2487 MockWrite data_writes2[] = {
2488 MockWrite("GET /p/q/t HTTP/1.1\r\n"
2489 "Host: www.google.com\r\n"
2490 "Connection: keep-alive\r\n"
2491 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
2492 };
2493
2494 // Sever rejects the authorization.
2495 MockRead data_reads2[] = {
2496 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
2497 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
2498 MockRead("Content-Length: 10000\r\n\r\n"),
2499 MockRead(false, net::ERR_FAILED),
2500 };
2501
2502 // At this point we should prompt for new credentials for MyRealm.
2503 // Restart with username=foo3, password=foo4.
2504 MockWrite data_writes3[] = {
2505 MockWrite("GET /p/q/t HTTP/1.1\r\n"
2506 "Host: www.google.com\r\n"
2507 "Connection: keep-alive\r\n"
2508 "Authorization: Basic Zm9vMzpiYXIz\r\n\r\n"),
2509 };
2510
2511 // Sever accepts the authorization.
2512 MockRead data_reads3[] = {
2513 MockRead("HTTP/1.0 200 OK\r\n"),
2514 MockRead("Content-Length: 100\r\n\r\n"),
2515 MockRead(false, net::OK),
2516 };
2517
2518 MockSocket data1;
2519 data1.reads = data_reads1;
2520 data1.writes = data_writes1;
2521 MockSocket data2;
2522 data2.reads = data_reads2;
2523 data2.writes = data_writes2;
2524 MockSocket data3;
2525 data3.reads = data_reads3;
2526 data3.writes = data_writes3;
2527 mock_sockets_index = 0;
2528 mock_sockets[0] = &data1;
2529 mock_sockets[1] = &data2;
2530 mock_sockets[2] = &data3;
2531 mock_sockets[3] = NULL;
2532
2533 TestCompletionCallback callback1;
2534
2535 int rv = trans->Start(&request, &callback1);
2536 EXPECT_EQ(net::ERR_IO_PENDING, rv);
2537
2538 rv = callback1.WaitForResult();
2539 EXPECT_EQ(net::OK, rv);
2540
2541 const net::HttpResponseInfo* response = trans->GetResponseInfo();
2542 EXPECT_FALSE(response == NULL);
2543
2544 // The password prompt info should have been set in
2545 // response->auth_challenge.
2546 EXPECT_FALSE(response->auth_challenge.get() == NULL);
2547
2548 // TODO(eroman): this should really include the effective port (80)
2549 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
2550 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
2551 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
2552
2553 TestCompletionCallback callback2;
2554
2555 rv = trans->RestartWithAuth(L"foo3", L"bar3", &callback2);
2556 EXPECT_EQ(net::ERR_IO_PENDING, rv);
2557
2558 rv = callback2.WaitForResult();
2559 EXPECT_EQ(net::OK, rv);
2560
2561 response = trans->GetResponseInfo();
2562 EXPECT_FALSE(response == NULL);
2563 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2564 EXPECT_EQ(100, response->headers->GetContentLength());
2565 }
2566}
[email protected]89ceba9a2009-03-21 03:46:062567
2568// Test the ResetStateForRestart() private method.
2569TEST_F(HttpNetworkTransactionTest, ResetStateForRestart) {
2570 // Create a transaction (the dependencies aren't important).
2571 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
2572 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(
2573 CreateSession(proxy_service.get()), &mock_socket_factory));
2574
2575 // Setup some state (which we expect ResetStateForRestart() will clear).
2576 trans->header_buf_.reset(static_cast<char*>(malloc(10)));
2577 trans->header_buf_capacity_ = 10;
2578 trans->header_buf_len_ = 3;
2579 trans->header_buf_body_offset_ = 11;
2580 trans->header_buf_http_offset_ = 0;
2581 trans->response_body_length_ = 100;
2582 trans->response_body_read_ = 1;
2583 trans->read_buf_ = new IOBuffer(15);
2584 trans->read_buf_len_ = 15;
2585 trans->request_headers_ = "Authorization: NTLM";
2586 trans->request_headers_bytes_sent_ = 3;
2587
2588 // Setup state in response_
2589 trans->response_.auth_challenge = new AuthChallengeInfo();
2590 trans->response_.ssl_info.cert_status = -15;
2591 trans->response_.response_time = base::Time::Now();
2592 trans->response_.was_cached = true; // (Wouldn't ever actually be true...)
2593
2594 { // Setup state for response_.vary_data
2595 HttpRequestInfo request;
2596 std::string temp("HTTP/1.1 200 OK\nVary: foo, bar\n\n");
2597 std::replace(temp.begin(), temp.end(), '\n', '\0');
2598 scoped_refptr<HttpResponseHeaders> response = new HttpResponseHeaders(temp);
2599 request.extra_headers = "Foo: 1\nbar: 23";
2600 EXPECT_TRUE(trans->response_.vary_data.Init(request, *response));
2601 }
2602
2603 // Cause the above state to be reset.
2604 trans->ResetStateForRestart();
2605
2606 // Verify that the state that needed to be reset, has been reset.
2607 EXPECT_EQ(NULL, trans->header_buf_.get());
2608 EXPECT_EQ(0, trans->header_buf_capacity_);
2609 EXPECT_EQ(0, trans->header_buf_len_);
2610 EXPECT_EQ(-1, trans->header_buf_body_offset_);
2611 EXPECT_EQ(-1, trans->header_buf_http_offset_);
2612 EXPECT_EQ(-1, trans->response_body_length_);
2613 EXPECT_EQ(0, trans->response_body_read_);
2614 EXPECT_EQ(NULL, trans->read_buf_.get());
2615 EXPECT_EQ(0, trans->read_buf_len_);
2616 EXPECT_EQ("", trans->request_headers_);
2617 EXPECT_EQ(0U, trans->request_headers_bytes_sent_);
2618 EXPECT_EQ(NULL, trans->response_.auth_challenge.get());
2619 EXPECT_EQ(NULL, trans->response_.headers.get());
2620 EXPECT_EQ(false, trans->response_.was_cached);
2621 EXPECT_EQ(base::kInvalidPlatformFileValue,
2622 trans->response_.response_data_file);
2623 EXPECT_EQ(0, trans->response_.ssl_info.cert_status);
2624 EXPECT_FALSE(trans->response_.vary_data.is_valid());
2625}
2626
2627} // namespace net