blob: f6c3fa2907150b6781b1fe0263597f62b4b56d49 [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"
[email protected]bacff652009-03-31 17:50:339#include "net/base/completion_callback.h"
10#include "net/base/ssl_client_socket.h"
11#include "net/base/ssl_info.h"
initial.commit586acc5fe2008-07-26 22:42:5212#include "net/base/test_completion_callback.h"
13#include "net/base/upload_data.h"
[email protected]385a4672009-03-11 22:21:2914#include "net/http/http_auth_handler_ntlm.h"
initial.commit586acc5fe2008-07-26 22:42:5215#include "net/http/http_network_session.h"
16#include "net/http/http_network_transaction.h"
17#include "net/http/http_transaction_unittest.h"
[email protected]51fff29d2008-12-19 22:17:5318#include "net/proxy/proxy_config_service_fixed.h"
initial.commit586acc5fe2008-07-26 22:42:5219#include "testing/gtest/include/gtest/gtest.h"
[email protected]23887f04f2008-12-02 19:20:1520#include "testing/platform_test.h"
initial.commit586acc5fe2008-07-26 22:42:5221
22//-----------------------------------------------------------------------------
23
[email protected]89ceba9a2009-03-21 03:46:0624namespace net {
25
initial.commit586acc5fe2008-07-26 22:42:5226struct MockConnect {
[email protected]217e6022008-09-29 18:18:3527 // Asynchronous connection success.
[email protected]bacff652009-03-31 17:50:3328 MockConnect() : async(true), result(OK) { }
29 MockConnect(bool a, int r) : async(a), result(r) { }
[email protected]038e9a32008-10-08 22:40:1630
31 bool async;
32 int result;
initial.commit586acc5fe2008-07-26 22:42:5233};
34
35struct MockRead {
[email protected]217e6022008-09-29 18:18:3536 // Read failure (no data).
37 MockRead(bool async, int result) : async(async) , result(result), data(NULL),
38 data_len(0) { }
39
40 // Asynchronous read success (inferred data length).
[email protected]372d34a2008-11-05 21:30:5141 explicit MockRead(const char* data) : async(true), result(0), data(data),
[email protected]b5462e02008-09-29 18:32:1942 data_len(strlen(data)) { }
[email protected]217e6022008-09-29 18:18:3543
44 // Read success (inferred data length).
[email protected]b5462e02008-09-29 18:32:1945 MockRead(bool async, const char* data) : async(async), result(0), data(data),
46 data_len(strlen(data)) { }
[email protected]217e6022008-09-29 18:18:3547
48 // Read success.
49 MockRead(bool async, const char* data, int data_len) : async(async),
[email protected]b5462e02008-09-29 18:32:1950 result(0), data(data), data_len(data_len) { }
[email protected]217e6022008-09-29 18:18:3551
initial.commit586acc5fe2008-07-26 22:42:5252 bool async;
[email protected]217e6022008-09-29 18:18:3553 int result;
initial.commit586acc5fe2008-07-26 22:42:5254 const char* data;
[email protected]217e6022008-09-29 18:18:3555 int data_len;
initial.commit586acc5fe2008-07-26 22:42:5256};
57
[email protected]038e9a32008-10-08 22:40:1658// MockWrite uses the same member fields as MockRead, but with different
59// meanings. The expected input to MockTCPClientSocket::Write() is given
60// by {data, data_len}, and the return value of Write() is controlled by
61// {async, result}.
62typedef MockRead MockWrite;
63
initial.commit586acc5fe2008-07-26 22:42:5264struct MockSocket {
[email protected]038e9a32008-10-08 22:40:1665 MockSocket() : reads(NULL), writes(NULL) { }
[email protected]bacff652009-03-31 17:50:3366 MockSocket(MockRead* r, MockWrite* w) : reads(r), writes(w) { }
[email protected]217e6022008-09-29 18:18:3567
initial.commit586acc5fe2008-07-26 22:42:5268 MockConnect connect;
[email protected]217e6022008-09-29 18:18:3569 MockRead* reads;
[email protected]038e9a32008-10-08 22:40:1670 MockWrite* writes;
initial.commit586acc5fe2008-07-26 22:42:5271};
72
73// Holds an array of MockSocket elements. As MockTCPClientSocket objects get
74// instantiated, they take their data from the i'th element of this array.
75//
76// Tests should assign the first N entries of mock_sockets to point to valid
77// MockSocket objects. The first unused entry should be NULL'd.
78//
79MockSocket* mock_sockets[10];
80
[email protected]bacff652009-03-31 17:50:3381// MockSSLSockets only need to keep track of the return code from calls to
82// Connect().
83struct MockSSLSocket {
84 MockSSLSocket(bool async, int result) : connect(async, result) { }
85
86 MockConnect connect;
87};
88MockSSLSocket* mock_ssl_sockets[10];
89
initial.commit586acc5fe2008-07-26 22:42:5290// Index of the next mock_sockets element to use.
91int mock_sockets_index;
[email protected]bacff652009-03-31 17:50:3392int mock_ssl_sockets_index;
initial.commit586acc5fe2008-07-26 22:42:5293
[email protected]bacff652009-03-31 17:50:3394class MockClientSocket : public SSLClientSocket {
initial.commit586acc5fe2008-07-26 22:42:5295 public:
[email protected]bacff652009-03-31 17:50:3396 explicit MockClientSocket()
97 : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
initial.commit586acc5fe2008-07-26 22:42:5298 callback_(NULL),
initial.commit586acc5fe2008-07-26 22:42:5299 connected_(false) {
initial.commit586acc5fe2008-07-26 22:42:52100 }
[email protected]bacff652009-03-31 17:50:33101
initial.commit586acc5fe2008-07-26 22:42:52102 // ClientSocket methods:
[email protected]bacff652009-03-31 17:50:33103 virtual int Connect(CompletionCallback* callback) = 0;
104
105 // SSLClientSocket methods:
106 virtual void GetSSLInfo(SSLInfo* ssl_info) {
[email protected]b9a9188d2009-03-30 22:23:51107 NOTREACHED();
[email protected]b9a9188d2009-03-30 22:23:51108 }
[email protected]bacff652009-03-31 17:50:33109
initial.commit586acc5fe2008-07-26 22:42:52110 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:
[email protected]bacff652009-03-31 17:50:33121 virtual int Read(char* buf, int buf_len,
122 CompletionCallback* callback) = 0;
123 virtual int Write(const char* buf, int buf_len,
124 CompletionCallback* callback) = 0;
125
126#if defined(OS_LINUX)
127 virtual int GetPeerName(struct sockaddr *name, socklen_t *namelen) {
128 memset(reinterpret_cast<char *>(name), 0, *namelen);
129 return OK;
130 }
131#endif
132
133
134 protected:
135 void RunCallbackAsync(CompletionCallback* callback, int result) {
136 callback_ = callback;
137 MessageLoop::current()->PostTask(FROM_HERE,
138 method_factory_.NewRunnableMethod(
139 &MockClientSocket::RunCallback, result));
140 }
141
142 void RunCallback(int result) {
143 CompletionCallback* c = callback_;
144 callback_ = NULL;
145 if (c)
146 c->Run(result);
147 }
148
149 ScopedRunnableMethodFactory<MockClientSocket> method_factory_;
150 CompletionCallback* callback_;
151 bool connected_;
152};
153
154class MockTCPClientSocket : public MockClientSocket {
155 public:
156 explicit MockTCPClientSocket(const AddressList& addresses)
157 : data_(mock_sockets[mock_sockets_index++]),
158 read_index_(0),
159 read_offset_(0),
160 write_index_(0) {
161 DCHECK(data_) << "overran mock_sockets array";
162 }
163
164 // ClientSocket methods:
165 virtual int Connect(CompletionCallback* callback) {
166 DCHECK(!callback_);
167 if (connected_)
168 return OK;
169 connected_ = true;
170 if (data_->connect.async) {
171 RunCallbackAsync(callback, data_->connect.result);
172 return ERR_IO_PENDING;
173 }
174 return data_->connect.result;
175 }
176
177 // Socket methods:
178 virtual int Read(char* buf, int buf_len, CompletionCallback* callback) {
initial.commit586acc5fe2008-07-26 22:42:52179 DCHECK(!callback_);
180 MockRead& r = data_->reads[read_index_];
[email protected]038e9a32008-10-08 22:40:16181 int result = r.result;
initial.commit586acc5fe2008-07-26 22:42:52182 if (r.data) {
initial.commit586acc5fe2008-07-26 22:42:52183 if (r.data_len - read_offset_ > 0) {
184 result = std::min(buf_len, r.data_len - read_offset_);
185 memcpy(buf, r.data + read_offset_, result);
186 read_offset_ += result;
187 if (read_offset_ == r.data_len) {
188 read_index_++;
189 read_offset_ = 0;
190 }
191 } else {
192 result = 0; // EOF
193 }
initial.commit586acc5fe2008-07-26 22:42:52194 }
195 if (r.async) {
196 RunCallbackAsync(callback, result);
[email protected]bacff652009-03-31 17:50:33197 return ERR_IO_PENDING;
initial.commit586acc5fe2008-07-26 22:42:52198 }
199 return result;
200 }
[email protected]bacff652009-03-31 17:50:33201
initial.commit586acc5fe2008-07-26 22:42:52202 virtual int Write(const char* buf, int buf_len,
[email protected]bacff652009-03-31 17:50:33203 CompletionCallback* callback) {
[email protected]372d34a2008-11-05 21:30:51204 DCHECK(buf);
205 DCHECK(buf_len > 0);
initial.commit586acc5fe2008-07-26 22:42:52206 DCHECK(!callback_);
[email protected]038e9a32008-10-08 22:40:16207 // Not using mock writes; succeed synchronously.
208 if (!data_->writes)
209 return buf_len;
[email protected]aaead502008-10-15 00:20:11210
[email protected]038e9a32008-10-08 22:40:16211 // Check that what we are writing matches the expectation.
212 // Then give the mocked return value.
[email protected]372d34a2008-11-05 21:30:51213 MockWrite& w = data_->writes[write_index_++];
[email protected]038e9a32008-10-08 22:40:16214 int result = w.result;
215 if (w.data) {
216 std::string expected_data(w.data, w.data_len);
217 std::string actual_data(buf, buf_len);
218 EXPECT_EQ(expected_data, actual_data);
219 if (expected_data != actual_data)
[email protected]bacff652009-03-31 17:50:33220 return ERR_UNEXPECTED;
221 if (result == OK)
[email protected]038e9a32008-10-08 22:40:16222 result = w.data_len;
223 }
224 if (w.async) {
225 RunCallbackAsync(callback, result);
[email protected]bacff652009-03-31 17:50:33226 return ERR_IO_PENDING;
[email protected]038e9a32008-10-08 22:40:16227 }
228 return result;
initial.commit586acc5fe2008-07-26 22:42:52229 }
[email protected]bacff652009-03-31 17:50:33230
initial.commit586acc5fe2008-07-26 22:42:52231 private:
initial.commit586acc5fe2008-07-26 22:42:52232 MockSocket* data_;
initial.commit586acc5fe2008-07-26 22:42:52233 int read_index_;
234 int read_offset_;
[email protected]038e9a32008-10-08 22:40:16235 int write_index_;
initial.commit586acc5fe2008-07-26 22:42:52236};
237
[email protected]bacff652009-03-31 17:50:33238class MockSSLClientSocket : public MockClientSocket {
initial.commit586acc5fe2008-07-26 22:42:52239 public:
[email protected]bacff652009-03-31 17:50:33240 explicit MockSSLClientSocket(
241 ClientSocket* transport_socket,
242 const std::string& hostname,
243 const SSLConfig& ssl_config)
244 : transport_(transport_socket),
245 data_(mock_ssl_sockets[mock_ssl_sockets_index++]) {
246 DCHECK(data_) << "overran mock_ssl_sockets array";
247 }
248
249 ~MockSSLClientSocket() {
250 Disconnect();
251 }
252
253 virtual void GetSSLInfo(SSLInfo* ssl_info) {
254 ssl_info->Reset();
255 }
256
257 friend class ConnectCallback;
258 class ConnectCallback :
259 public CompletionCallbackImpl<ConnectCallback> {
260 public:
261 ConnectCallback(MockSSLClientSocket *ssl_client_socket,
262 CompletionCallback* user_callback,
263 int rv)
264 : ALLOW_THIS_IN_INITIALIZER_LIST(
265 CompletionCallbackImpl<ConnectCallback>(
266 this, &ConnectCallback::Wrapper)),
267 ssl_client_socket_(ssl_client_socket),
268 user_callback_(user_callback),
269 rv_(rv) {
270 }
271
272 private:
273 void Wrapper(int rv) {
274 if (rv_ == OK)
275 ssl_client_socket_->connected_ = true;
276 user_callback_->Run(rv_);
277 delete this;
278 }
279
280 MockSSLClientSocket* ssl_client_socket_;
281 CompletionCallback* user_callback_;
282 int rv_;
283 };
284
285 virtual int Connect(CompletionCallback* callback) {
286 DCHECK(!callback_);
287 ConnectCallback* connect_callback = new ConnectCallback(
288 this, callback, data_->connect.result);
289 int rv = transport_->Connect(connect_callback);
290 if (rv == OK) {
291 delete connect_callback;
292 if (data_->connect.async) {
293 RunCallbackAsync(callback, data_->connect.result);
294 return ERR_IO_PENDING;
295 }
296 if (data_->connect.result == OK)
297 connected_ = true;
298 return data_->connect.result;
299 }
300 return rv;
301 }
302
303 virtual void Disconnect() {
304 MockClientSocket::Disconnect();
305 if (transport_ != NULL)
306 transport_->Disconnect();
307 }
308
309 // Socket methods:
310 virtual int Read(char* buf, int buf_len, CompletionCallback* callback) {
311 DCHECK(!callback_);
312 return transport_->Read(buf, buf_len, callback);
313 }
314
315 virtual int Write(const char* buf, int buf_len,
316 CompletionCallback* callback) {
317 DCHECK(!callback_);
318 return transport_->Write(buf, buf_len, callback);
319 }
320
321 private:
322 scoped_ptr<ClientSocket> transport_;
323 MockSSLSocket* data_;
324};
325
326class MockClientSocketFactory : public ClientSocketFactory {
327 public:
328 virtual ClientSocket* CreateTCPClientSocket(
329 const AddressList& addresses) {
initial.commit586acc5fe2008-07-26 22:42:52330 return new MockTCPClientSocket(addresses);
331 }
[email protected]bacff652009-03-31 17:50:33332 virtual SSLClientSocket* CreateSSLClientSocket(
333 ClientSocket* transport_socket,
[email protected]c5949a32008-10-08 17:28:23334 const std::string& hostname,
[email protected]bacff652009-03-31 17:50:33335 const SSLConfig& ssl_config) {
336 return new MockSSLClientSocket(transport_socket, hostname, ssl_config);
initial.commit586acc5fe2008-07-26 22:42:52337 }
338};
339
340MockClientSocketFactory mock_socket_factory;
341
[email protected]db8f44c2008-12-13 04:52:01342// Create a proxy service which fails on all requests (falls back to direct).
[email protected]1c773ea12009-04-28 19:58:42343ProxyService* CreateNullProxyService() {
344 return ProxyService::CreateNull();
initial.commit586acc5fe2008-07-26 22:42:52345}
346
[email protected]1c773ea12009-04-28 19:58:42347ProxyService* CreateFixedProxyService(const std::string& proxy) {
348 ProxyInfo proxy_info;
[email protected]51fff29d2008-12-19 22:17:53349 proxy_info.UseNamedProxy(proxy);
[email protected]1c773ea12009-04-28 19:58:42350 return ProxyService::Create(&proxy_info);
[email protected]51fff29d2008-12-19 22:17:53351}
352
353
[email protected]1c773ea12009-04-28 19:58:42354HttpNetworkSession* CreateSession(ProxyService* proxy_service) {
355 return new HttpNetworkSession(proxy_service);
[email protected]e8d536192008-10-17 22:21:14356}
357
[email protected]89836e22008-09-25 20:33:42358class HttpNetworkTransactionTest : public PlatformTest {
initial.commit586acc5fe2008-07-26 22:42:52359 public:
360 virtual void SetUp() {
[email protected]89836e22008-09-25 20:33:42361 PlatformTest::SetUp();
initial.commit586acc5fe2008-07-26 22:42:52362 mock_sockets[0] = NULL;
363 mock_sockets_index = 0;
[email protected]bacff652009-03-31 17:50:33364 mock_ssl_sockets_index = 0;
initial.commit586acc5fe2008-07-26 22:42:52365 }
[email protected]3d2a59b2008-09-26 19:44:25366
[email protected]0e75a732008-10-16 20:36:09367 virtual void TearDown() {
368 // Empty the current queue.
369 MessageLoop::current()->RunAllPending();
370 PlatformTest::TearDown();
371 }
372
[email protected]3d2a59b2008-09-26 19:44:25373 protected:
374 void KeepAliveConnectionResendRequestTest(const MockRead& read_failure);
initial.commit586acc5fe2008-07-26 22:42:52375};
376
[email protected]231d5a32008-09-13 00:45:27377struct SimpleGetHelperResult {
[email protected]aecfbf22008-10-16 02:02:47378 int rv;
[email protected]231d5a32008-09-13 00:45:27379 std::string status_line;
380 std::string response_data;
381};
initial.commit586acc5fe2008-07-26 22:42:52382
[email protected]231d5a32008-09-13 00:45:27383SimpleGetHelperResult SimpleGetHelper(MockRead data_reads[]) {
384 SimpleGetHelperResult out;
initial.commit586acc5fe2008-07-26 22:42:52385
[email protected]1c773ea12009-04-28 19:58:42386 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
387 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]db8f44c2008-12-13 04:52:01388 CreateSession(proxy_service.get()), &mock_socket_factory));
initial.commit586acc5fe2008-07-26 22:42:52389
[email protected]1c773ea12009-04-28 19:58:42390 HttpRequestInfo request;
initial.commit586acc5fe2008-07-26 22:42:52391 request.method = "GET";
392 request.url = GURL("http://www.google.com/");
393 request.load_flags = 0;
394
initial.commit586acc5fe2008-07-26 22:42:52395 MockSocket data;
initial.commit586acc5fe2008-07-26 22:42:52396 data.reads = data_reads;
397 mock_sockets[0] = &data;
398 mock_sockets[1] = NULL;
399
400 TestCompletionCallback callback;
401
402 int rv = trans->Start(&request, &callback);
[email protected]1c773ea12009-04-28 19:58:42403 EXPECT_EQ(ERR_IO_PENDING, rv);
initial.commit586acc5fe2008-07-26 22:42:52404
[email protected]aecfbf22008-10-16 02:02:47405 out.rv = callback.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:42406 if (out.rv != OK)
[email protected]aecfbf22008-10-16 02:02:47407 return out;
initial.commit586acc5fe2008-07-26 22:42:52408
[email protected]1c773ea12009-04-28 19:58:42409 const HttpResponseInfo* response = trans->GetResponseInfo();
initial.commit586acc5fe2008-07-26 22:42:52410 EXPECT_TRUE(response != NULL);
411
412 EXPECT_TRUE(response->headers != NULL);
[email protected]231d5a32008-09-13 00:45:27413 out.status_line = response->headers->GetStatusLine();
initial.commit586acc5fe2008-07-26 22:42:52414
[email protected]af4876d2008-10-21 23:10:57415 rv = ReadTransaction(trans.get(), &out.response_data);
[email protected]1c773ea12009-04-28 19:58:42416 EXPECT_EQ(OK, rv);
initial.commit586acc5fe2008-07-26 22:42:52417
[email protected]231d5a32008-09-13 00:45:27418 return out;
419}
420
[email protected]15a5ccf82008-10-23 19:57:43421// Fill |str| with a long header list that consumes >= |size| bytes.
422void FillLargeHeadersString(std::string* str, int size) {
[email protected]4ddaf2502008-10-23 18:26:19423 const char* row =
424 "SomeHeaderName: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n";
425 const int sizeof_row = strlen(row);
426 const int num_rows = static_cast<int>(
427 ceil(static_cast<float>(size) / sizeof_row));
428 const int sizeof_data = num_rows * sizeof_row;
429 DCHECK(sizeof_data >= size);
[email protected]15a5ccf82008-10-23 19:57:43430 str->reserve(sizeof_data);
[email protected]372d34a2008-11-05 21:30:51431
[email protected]4ddaf2502008-10-23 18:26:19432 for (int i = 0; i < num_rows; ++i)
[email protected]15a5ccf82008-10-23 19:57:43433 str->append(row, sizeof_row);
[email protected]4ddaf2502008-10-23 18:26:19434}
435
[email protected]385a4672009-03-11 22:21:29436// Alternative functions that eliminate randomness and dependency on the local
437// host name so that the generated NTLM messages are reproducible.
[email protected]fe2bc6a2009-03-23 16:52:20438void MockGenerateRandom1(uint8* output, size_t n) {
[email protected]385a4672009-03-11 22:21:29439 static const uint8 bytes[] = {
440 0x55, 0x29, 0x66, 0x26, 0x6b, 0x9c, 0x73, 0x54
441 };
442 static size_t current_byte = 0;
443 for (size_t i = 0; i < n; ++i) {
444 output[i] = bytes[current_byte++];
445 current_byte %= arraysize(bytes);
446 }
447}
448
[email protected]fe2bc6a2009-03-23 16:52:20449void MockGenerateRandom2(uint8* output, size_t n) {
[email protected]385a4672009-03-11 22:21:29450 static const uint8 bytes[] = {
451 0x96, 0x79, 0x85, 0xe7, 0x49, 0x93, 0x70, 0xa1,
452 0x4e, 0xe7, 0x87, 0x45, 0x31, 0x5b, 0xd3, 0x1f
453 };
454 static size_t current_byte = 0;
455 for (size_t i = 0; i < n; ++i) {
456 output[i] = bytes[current_byte++];
457 current_byte %= arraysize(bytes);
458 }
459}
460
[email protected]fe2bc6a2009-03-23 16:52:20461std::string MockGetHostName() {
462 return "WTC-WIN7";
[email protected]385a4672009-03-11 22:21:29463}
464
[email protected]231d5a32008-09-13 00:45:27465//-----------------------------------------------------------------------------
466
467TEST_F(HttpNetworkTransactionTest, Basic) {
[email protected]1c773ea12009-04-28 19:58:42468 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
469 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]db8f44c2008-12-13 04:52:01470 CreateSession(proxy_service.get()), &mock_socket_factory));
[email protected]231d5a32008-09-13 00:45:27471}
472
473TEST_F(HttpNetworkTransactionTest, SimpleGET) {
474 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35475 MockRead("HTTP/1.0 200 OK\r\n\r\n"),
476 MockRead("hello world"),
[email protected]1c773ea12009-04-28 19:58:42477 MockRead(false, OK),
[email protected]231d5a32008-09-13 00:45:27478 };
[email protected]231d5a32008-09-13 00:45:27479 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]1c773ea12009-04-28 19:58:42480 EXPECT_EQ(OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27481 EXPECT_EQ("HTTP/1.0 200 OK", out.status_line);
482 EXPECT_EQ("hello world", out.response_data);
483}
484
485// Response with no status line.
486TEST_F(HttpNetworkTransactionTest, SimpleGETNoHeaders) {
487 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35488 MockRead("hello world"),
[email protected]1c773ea12009-04-28 19:58:42489 MockRead(false, OK),
[email protected]231d5a32008-09-13 00:45:27490 };
[email protected]231d5a32008-09-13 00:45:27491 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]1c773ea12009-04-28 19:58:42492 EXPECT_EQ(OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27493 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
494 EXPECT_EQ("hello world", out.response_data);
495}
496
497// Allow up to 4 bytes of junk to precede status line.
498TEST_F(HttpNetworkTransactionTest, StatusLineJunk2Bytes) {
499 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35500 MockRead("xxxHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
[email protected]1c773ea12009-04-28 19:58:42501 MockRead(false, OK),
[email protected]231d5a32008-09-13 00:45:27502 };
503 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]1c773ea12009-04-28 19:58:42504 EXPECT_EQ(OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27505 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
506 EXPECT_EQ("DATA", out.response_data);
507}
508
509// Allow up to 4 bytes of junk to precede status line.
510TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes) {
511 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35512 MockRead("\n\nQJHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
[email protected]1c773ea12009-04-28 19:58:42513 MockRead(false, OK),
[email protected]231d5a32008-09-13 00:45:27514 };
515 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]1c773ea12009-04-28 19:58:42516 EXPECT_EQ(OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27517 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
518 EXPECT_EQ("DATA", out.response_data);
519}
520
521// Beyond 4 bytes of slop and it should fail to find a status line.
522TEST_F(HttpNetworkTransactionTest, StatusLineJunk5Bytes) {
523 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35524 MockRead("xxxxxHTTP/1.1 404 Not Found\nServer: blah"),
[email protected]1c773ea12009-04-28 19:58:42525 MockRead(false, OK),
[email protected]231d5a32008-09-13 00:45:27526 };
527 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]1c773ea12009-04-28 19:58:42528 EXPECT_EQ(OK, out.rv);
[email protected]3d2a59b2008-09-26 19:44:25529 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
530 EXPECT_EQ("xxxxxHTTP/1.1 404 Not Found\nServer: blah", out.response_data);
[email protected]231d5a32008-09-13 00:45:27531}
532
533// Same as StatusLineJunk4Bytes, except the read chunks are smaller.
534TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes_Slow) {
535 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35536 MockRead("\n"),
537 MockRead("\n"),
538 MockRead("Q"),
539 MockRead("J"),
540 MockRead("HTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
[email protected]1c773ea12009-04-28 19:58:42541 MockRead(false, OK),
[email protected]231d5a32008-09-13 00:45:27542 };
543 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]1c773ea12009-04-28 19:58:42544 EXPECT_EQ(OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27545 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
546 EXPECT_EQ("DATA", out.response_data);
547}
548
549// Close the connection before enough bytes to have a status line.
550TEST_F(HttpNetworkTransactionTest, StatusLinePartial) {
551 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35552 MockRead("HTT"),
[email protected]1c773ea12009-04-28 19:58:42553 MockRead(false, OK),
[email protected]231d5a32008-09-13 00:45:27554 };
555 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]1c773ea12009-04-28 19:58:42556 EXPECT_EQ(OK, out.rv);
[email protected]231d5a32008-09-13 00:45:27557 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
558 EXPECT_EQ("HTT", out.response_data);
initial.commit586acc5fe2008-07-26 22:42:52559}
560
[email protected]f9d44aa2008-09-23 23:57:17561// Simulate a 204 response, lacking a Content-Length header, sent over a
562// persistent connection. The response should still terminate since a 204
563// cannot have a response body.
564TEST_F(HttpNetworkTransactionTest, StopsReading204) {
565 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35566 MockRead("HTTP/1.1 204 No Content\r\n\r\n"),
567 MockRead("junk"), // Should not be read!!
[email protected]1c773ea12009-04-28 19:58:42568 MockRead(false, OK),
[email protected]f9d44aa2008-09-23 23:57:17569 };
570 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]1c773ea12009-04-28 19:58:42571 EXPECT_EQ(OK, out.rv);
[email protected]f9d44aa2008-09-23 23:57:17572 EXPECT_EQ("HTTP/1.1 204 No Content", out.status_line);
573 EXPECT_EQ("", out.response_data);
574}
575
[email protected]ef0faf2e72009-03-05 23:27:23576// Do a request using the HEAD method. Verify that we don't try to read the
577// message body (since HEAD has none).
578TEST_F(HttpNetworkTransactionTest, Head) {
[email protected]1c773ea12009-04-28 19:58:42579 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
580 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]ef0faf2e72009-03-05 23:27:23581 CreateSession(proxy_service.get()), &mock_socket_factory));
582
[email protected]1c773ea12009-04-28 19:58:42583 HttpRequestInfo request;
[email protected]ef0faf2e72009-03-05 23:27:23584 request.method = "HEAD";
585 request.url = GURL("http://www.google.com/");
586 request.load_flags = 0;
587
588 MockWrite data_writes1[] = {
589 MockWrite("HEAD / HTTP/1.1\r\n"
590 "Host: www.google.com\r\n"
591 "Connection: keep-alive\r\n"
592 "Content-Length: 0\r\n\r\n"),
593 };
594 MockRead data_reads1[] = {
595 MockRead("HTTP/1.1 404 Not Found\r\n"),
596 MockRead("Server: Blah\r\n"),
597 MockRead("Content-Length: 1234\r\n\r\n"),
598
599 // No response body because the test stops reading here.
[email protected]1c773ea12009-04-28 19:58:42600 MockRead(false, ERR_UNEXPECTED), // Should not be reached.
[email protected]ef0faf2e72009-03-05 23:27:23601 };
602
603 MockSocket data1;
604 data1.reads = data_reads1;
605 data1.writes = data_writes1;
606 mock_sockets[0] = &data1;
607 mock_sockets[1] = NULL;
608
609 TestCompletionCallback callback1;
610
611 int rv = trans->Start(&request, &callback1);
[email protected]1c773ea12009-04-28 19:58:42612 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]ef0faf2e72009-03-05 23:27:23613
614 rv = callback1.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:42615 EXPECT_EQ(OK, rv);
[email protected]ef0faf2e72009-03-05 23:27:23616
[email protected]1c773ea12009-04-28 19:58:42617 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]ef0faf2e72009-03-05 23:27:23618 EXPECT_FALSE(response == NULL);
619
620 // Check that the headers got parsed.
621 EXPECT_TRUE(response->headers != NULL);
622 EXPECT_EQ(1234, response->headers->GetContentLength());
623 EXPECT_EQ("HTTP/1.1 404 Not Found", response->headers->GetStatusLine());
624
625 std::string server_header;
626 void* iter = NULL;
627 bool has_server_header = response->headers->EnumerateHeader(
628 &iter, "Server", &server_header);
629 EXPECT_TRUE(has_server_header);
630 EXPECT_EQ("Blah", server_header);
631
632 // Reading should give EOF right away, since there is no message body
633 // (despite non-zero content-length).
634 std::string response_data;
635 rv = ReadTransaction(trans.get(), &response_data);
[email protected]1c773ea12009-04-28 19:58:42636 EXPECT_EQ(OK, rv);
[email protected]ef0faf2e72009-03-05 23:27:23637 EXPECT_EQ("", response_data);
638}
639
initial.commit586acc5fe2008-07-26 22:42:52640TEST_F(HttpNetworkTransactionTest, ReuseConnection) {
[email protected]1c773ea12009-04-28 19:58:42641 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
642 scoped_refptr<HttpNetworkSession> session =
[email protected]db8f44c2008-12-13 04:52:01643 CreateSession(proxy_service.get());
initial.commit586acc5fe2008-07-26 22:42:52644
645 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35646 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
647 MockRead("hello"),
648 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
649 MockRead("world"),
[email protected]1c773ea12009-04-28 19:58:42650 MockRead(false, OK),
initial.commit586acc5fe2008-07-26 22:42:52651 };
652 MockSocket data;
initial.commit586acc5fe2008-07-26 22:42:52653 data.reads = data_reads;
654 mock_sockets[0] = &data;
655 mock_sockets[1] = NULL;
656
657 const char* kExpectedResponseData[] = {
658 "hello", "world"
659 };
660
661 for (int i = 0; i < 2; ++i) {
[email protected]1c773ea12009-04-28 19:58:42662 scoped_ptr<HttpTransaction> trans(
663 new HttpNetworkTransaction(session, &mock_socket_factory));
initial.commit586acc5fe2008-07-26 22:42:52664
[email protected]1c773ea12009-04-28 19:58:42665 HttpRequestInfo request;
initial.commit586acc5fe2008-07-26 22:42:52666 request.method = "GET";
667 request.url = GURL("http://www.google.com/");
668 request.load_flags = 0;
669
670 TestCompletionCallback callback;
671
672 int rv = trans->Start(&request, &callback);
[email protected]1c773ea12009-04-28 19:58:42673 EXPECT_EQ(ERR_IO_PENDING, rv);
initial.commit586acc5fe2008-07-26 22:42:52674
675 rv = callback.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:42676 EXPECT_EQ(OK, rv);
initial.commit586acc5fe2008-07-26 22:42:52677
[email protected]1c773ea12009-04-28 19:58:42678 const HttpResponseInfo* response = trans->GetResponseInfo();
initial.commit586acc5fe2008-07-26 22:42:52679 EXPECT_TRUE(response != NULL);
680
681 EXPECT_TRUE(response->headers != NULL);
[email protected]3d2a59b2008-09-26 19:44:25682 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
initial.commit586acc5fe2008-07-26 22:42:52683
684 std::string response_data;
[email protected]af4876d2008-10-21 23:10:57685 rv = ReadTransaction(trans.get(), &response_data);
[email protected]1c773ea12009-04-28 19:58:42686 EXPECT_EQ(OK, rv);
[email protected]3d2a59b2008-09-26 19:44:25687 EXPECT_EQ(kExpectedResponseData[i], response_data);
initial.commit586acc5fe2008-07-26 22:42:52688 }
689}
690
691TEST_F(HttpNetworkTransactionTest, Ignores100) {
[email protected]1c773ea12009-04-28 19:58:42692 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
693 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]db8f44c2008-12-13 04:52:01694 CreateSession(proxy_service.get()), &mock_socket_factory));
initial.commit586acc5fe2008-07-26 22:42:52695
[email protected]1c773ea12009-04-28 19:58:42696 HttpRequestInfo request;
initial.commit586acc5fe2008-07-26 22:42:52697 request.method = "POST";
698 request.url = GURL("http://www.foo.com/");
[email protected]1c773ea12009-04-28 19:58:42699 request.upload_data = new UploadData;
initial.commit586acc5fe2008-07-26 22:42:52700 request.upload_data->AppendBytes("foo", 3);
701 request.load_flags = 0;
702
703 MockRead data_reads[] = {
[email protected]217e6022008-09-29 18:18:35704 MockRead("HTTP/1.0 100 Continue\r\n\r\n"),
705 MockRead("HTTP/1.0 200 OK\r\n\r\n"),
706 MockRead("hello world"),
[email protected]1c773ea12009-04-28 19:58:42707 MockRead(false, OK),
initial.commit586acc5fe2008-07-26 22:42:52708 };
709 MockSocket data;
initial.commit586acc5fe2008-07-26 22:42:52710 data.reads = data_reads;
711 mock_sockets[0] = &data;
712 mock_sockets[1] = NULL;
713
714 TestCompletionCallback callback;
715
716 int rv = trans->Start(&request, &callback);
[email protected]1c773ea12009-04-28 19:58:42717 EXPECT_EQ(ERR_IO_PENDING, rv);
initial.commit586acc5fe2008-07-26 22:42:52718
719 rv = callback.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:42720 EXPECT_EQ(OK, rv);
initial.commit586acc5fe2008-07-26 22:42:52721
[email protected]1c773ea12009-04-28 19:58:42722 const HttpResponseInfo* response = trans->GetResponseInfo();
initial.commit586acc5fe2008-07-26 22:42:52723 EXPECT_TRUE(response != NULL);
724
725 EXPECT_TRUE(response->headers != NULL);
[email protected]3d2a59b2008-09-26 19:44:25726 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine());
initial.commit586acc5fe2008-07-26 22:42:52727
728 std::string response_data;
[email protected]af4876d2008-10-21 23:10:57729 rv = ReadTransaction(trans.get(), &response_data);
[email protected]1c773ea12009-04-28 19:58:42730 EXPECT_EQ(OK, rv);
[email protected]3d2a59b2008-09-26 19:44:25731 EXPECT_EQ("hello world", response_data);
initial.commit586acc5fe2008-07-26 22:42:52732}
733
[email protected]3a2d3662009-03-27 03:49:14734// This test is almost the same as Ignores100 above, but the response contains
735// a 102 instead of a 100. Also, instead of HTTP/1.0 the response is
736// HTTP/1.1.
737TEST_F(HttpNetworkTransactionTest, Ignores1xx) {
[email protected]1c773ea12009-04-28 19:58:42738 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
739 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]3a2d3662009-03-27 03:49:14740 CreateSession(proxy_service.get()), &mock_socket_factory));
741
[email protected]1c773ea12009-04-28 19:58:42742 HttpRequestInfo request;
[email protected]3a2d3662009-03-27 03:49:14743 request.method = "GET";
744 request.url = GURL("http://www.foo.com/");
745 request.load_flags = 0;
746
747 MockRead data_reads[] = {
748 MockRead("HTTP/1.1 102 Unspecified status code\r\n\r\n"),
749 MockRead("HTTP/1.1 200 OK\r\n\r\n"),
750 MockRead("hello world"),
[email protected]1c773ea12009-04-28 19:58:42751 MockRead(false, OK),
[email protected]3a2d3662009-03-27 03:49:14752 };
753 MockSocket data;
754 data.reads = data_reads;
755 mock_sockets[0] = &data;
756 mock_sockets[1] = NULL;
757
758 TestCompletionCallback callback;
759
760 int rv = trans->Start(&request, &callback);
[email protected]1c773ea12009-04-28 19:58:42761 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]3a2d3662009-03-27 03:49:14762
763 rv = callback.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:42764 EXPECT_EQ(OK, rv);
[email protected]3a2d3662009-03-27 03:49:14765
[email protected]1c773ea12009-04-28 19:58:42766 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]3a2d3662009-03-27 03:49:14767 EXPECT_TRUE(response != NULL);
768
769 EXPECT_TRUE(response->headers != NULL);
770 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
771
772 std::string response_data;
773 rv = ReadTransaction(trans.get(), &response_data);
[email protected]1c773ea12009-04-28 19:58:42774 EXPECT_EQ(OK, rv);
[email protected]3a2d3662009-03-27 03:49:14775 EXPECT_EQ("hello world", response_data);
776}
777
[email protected]3d2a59b2008-09-26 19:44:25778// read_failure specifies a read failure that should cause the network
779// transaction to resend the request.
780void HttpNetworkTransactionTest::KeepAliveConnectionResendRequestTest(
781 const MockRead& read_failure) {
[email protected]1c773ea12009-04-28 19:58:42782 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
783 scoped_refptr<HttpNetworkSession> session =
[email protected]db8f44c2008-12-13 04:52:01784 CreateSession(proxy_service.get());
initial.commit586acc5fe2008-07-26 22:42:52785
[email protected]1c773ea12009-04-28 19:58:42786 HttpRequestInfo request;
initial.commit586acc5fe2008-07-26 22:42:52787 request.method = "GET";
788 request.url = GURL("http://www.foo.com/");
789 request.load_flags = 0;
790
791 MockRead data1_reads[] = {
[email protected]217e6022008-09-29 18:18:35792 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
793 MockRead("hello"),
[email protected]3d2a59b2008-09-26 19:44:25794 read_failure, // Now, we reuse the connection and fail the first read.
initial.commit586acc5fe2008-07-26 22:42:52795 };
796 MockSocket data1;
initial.commit586acc5fe2008-07-26 22:42:52797 data1.reads = data1_reads;
798 mock_sockets[0] = &data1;
799
800 MockRead data2_reads[] = {
[email protected]217e6022008-09-29 18:18:35801 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
802 MockRead("world"),
[email protected]1c773ea12009-04-28 19:58:42803 MockRead(true, OK),
initial.commit586acc5fe2008-07-26 22:42:52804 };
805 MockSocket data2;
initial.commit586acc5fe2008-07-26 22:42:52806 data2.reads = data2_reads;
807 mock_sockets[1] = &data2;
808
809 const char* kExpectedResponseData[] = {
810 "hello", "world"
811 };
812
813 for (int i = 0; i < 2; ++i) {
814 TestCompletionCallback callback;
815
[email protected]1c773ea12009-04-28 19:58:42816 scoped_ptr<HttpTransaction> trans(
817 new HttpNetworkTransaction(session, &mock_socket_factory));
initial.commit586acc5fe2008-07-26 22:42:52818
819 int rv = trans->Start(&request, &callback);
[email protected]1c773ea12009-04-28 19:58:42820 EXPECT_EQ(ERR_IO_PENDING, rv);
initial.commit586acc5fe2008-07-26 22:42:52821
822 rv = callback.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:42823 EXPECT_EQ(OK, rv);
initial.commit586acc5fe2008-07-26 22:42:52824
[email protected]1c773ea12009-04-28 19:58:42825 const HttpResponseInfo* response = trans->GetResponseInfo();
initial.commit586acc5fe2008-07-26 22:42:52826 EXPECT_TRUE(response != NULL);
827
828 EXPECT_TRUE(response->headers != NULL);
[email protected]3d2a59b2008-09-26 19:44:25829 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
initial.commit586acc5fe2008-07-26 22:42:52830
831 std::string response_data;
[email protected]af4876d2008-10-21 23:10:57832 rv = ReadTransaction(trans.get(), &response_data);
[email protected]1c773ea12009-04-28 19:58:42833 EXPECT_EQ(OK, rv);
[email protected]3d2a59b2008-09-26 19:44:25834 EXPECT_EQ(kExpectedResponseData[i], response_data);
initial.commit586acc5fe2008-07-26 22:42:52835 }
836}
[email protected]3d2a59b2008-09-26 19:44:25837
838TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionReset) {
[email protected]1c773ea12009-04-28 19:58:42839 MockRead read_failure(true, ERR_CONNECTION_RESET);
[email protected]3d2a59b2008-09-26 19:44:25840 KeepAliveConnectionResendRequestTest(read_failure);
841}
842
843TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionEOF) {
[email protected]1c773ea12009-04-28 19:58:42844 MockRead read_failure(false, OK); // EOF
[email protected]3d2a59b2008-09-26 19:44:25845 KeepAliveConnectionResendRequestTest(read_failure);
846}
847
848TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionReset) {
[email protected]1c773ea12009-04-28 19:58:42849 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
850 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]db8f44c2008-12-13 04:52:01851 CreateSession(proxy_service.get()), &mock_socket_factory));
[email protected]3d2a59b2008-09-26 19:44:25852
[email protected]1c773ea12009-04-28 19:58:42853 HttpRequestInfo request;
[email protected]3d2a59b2008-09-26 19:44:25854 request.method = "GET";
855 request.url = GURL("http://www.google.com/");
856 request.load_flags = 0;
857
858 MockRead data_reads[] = {
[email protected]1c773ea12009-04-28 19:58:42859 MockRead(true, ERR_CONNECTION_RESET),
[email protected]217e6022008-09-29 18:18:35860 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used
861 MockRead("hello world"),
[email protected]1c773ea12009-04-28 19:58:42862 MockRead(false, OK),
[email protected]3d2a59b2008-09-26 19:44:25863 };
864 MockSocket data;
[email protected]3d2a59b2008-09-26 19:44:25865 data.reads = data_reads;
866 mock_sockets[0] = &data;
867 mock_sockets[1] = NULL;
868
869 TestCompletionCallback callback;
870
871 int rv = trans->Start(&request, &callback);
[email protected]1c773ea12009-04-28 19:58:42872 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]3d2a59b2008-09-26 19:44:25873
874 rv = callback.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:42875 EXPECT_EQ(ERR_CONNECTION_RESET, rv);
[email protected]3d2a59b2008-09-26 19:44:25876
[email protected]1c773ea12009-04-28 19:58:42877 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]3d2a59b2008-09-26 19:44:25878 EXPECT_TRUE(response == NULL);
[email protected]3d2a59b2008-09-26 19:44:25879}
880
881// What do various browsers do when the server closes a non-keepalive
882// connection without sending any response header or body?
883//
884// IE7: error page
885// Safari 3.1.2 (Windows): error page
886// Firefox 3.0.1: blank page
887// Opera 9.52: after five attempts, blank page
[email protected]1c773ea12009-04-28 19:58:42888// Us with WinHTTP: error page (ERR_INVALID_RESPONSE)
889// Us: error page (EMPTY_RESPONSE)
[email protected]3d2a59b2008-09-26 19:44:25890TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionEOF) {
891 MockRead data_reads[] = {
[email protected]1c773ea12009-04-28 19:58:42892 MockRead(false, OK), // EOF
[email protected]217e6022008-09-29 18:18:35893 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used
894 MockRead("hello world"),
[email protected]1c773ea12009-04-28 19:58:42895 MockRead(false, OK),
[email protected]3d2a59b2008-09-26 19:44:25896 };
897 SimpleGetHelperResult out = SimpleGetHelper(data_reads);
[email protected]1c773ea12009-04-28 19:58:42898 EXPECT_EQ(ERR_EMPTY_RESPONSE, out.rv);
[email protected]3d2a59b2008-09-26 19:44:25899}
[email protected]038e9a32008-10-08 22:40:16900
901// Test the request-challenge-retry sequence for basic auth.
902// (basic auth is the easiest to mock, because it has no randomness).
903TEST_F(HttpNetworkTransactionTest, BasicAuth) {
[email protected]1c773ea12009-04-28 19:58:42904 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
905 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]db8f44c2008-12-13 04:52:01906 CreateSession(proxy_service.get()), &mock_socket_factory));
[email protected]038e9a32008-10-08 22:40:16907
[email protected]1c773ea12009-04-28 19:58:42908 HttpRequestInfo request;
[email protected]038e9a32008-10-08 22:40:16909 request.method = "GET";
910 request.url = GURL("http://www.google.com/");
911 request.load_flags = 0;
912
[email protected]f9ee6b52008-11-08 06:46:23913 MockWrite data_writes1[] = {
914 MockWrite("GET / HTTP/1.1\r\n"
915 "Host: www.google.com\r\n"
916 "Connection: keep-alive\r\n\r\n"),
917 };
918
[email protected]038e9a32008-10-08 22:40:16919 MockRead data_reads1[] = {
920 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
921 // Give a couple authenticate options (only the middle one is actually
922 // supported).
[email protected]aaead502008-10-15 00:20:11923 MockRead("WWW-Authenticate: Basic\r\n"), // Malformed
[email protected]038e9a32008-10-08 22:40:16924 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
925 MockRead("WWW-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"),
926 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
927 // Large content-length -- won't matter, as connection will be reset.
928 MockRead("Content-Length: 10000\r\n\r\n"),
[email protected]1c773ea12009-04-28 19:58:42929 MockRead(false, ERR_FAILED),
[email protected]038e9a32008-10-08 22:40:16930 };
931
932 // After calling trans->RestartWithAuth(), this is the request we should
933 // be issuing -- the final header line contains the credentials.
934 MockWrite data_writes2[] = {
935 MockWrite("GET / HTTP/1.1\r\n"
936 "Host: www.google.com\r\n"
937 "Connection: keep-alive\r\n"
938 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
939 };
940
941 // Lastly, the server responds with the actual content.
942 MockRead data_reads2[] = {
943 MockRead("HTTP/1.0 200 OK\r\n"),
944 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
945 MockRead("Content-Length: 100\r\n\r\n"),
[email protected]1c773ea12009-04-28 19:58:42946 MockRead(false, OK),
[email protected]038e9a32008-10-08 22:40:16947 };
948
949 MockSocket data1;
950 data1.reads = data_reads1;
[email protected]f9ee6b52008-11-08 06:46:23951 data1.writes = data_writes1;
[email protected]038e9a32008-10-08 22:40:16952 MockSocket data2;
953 data2.reads = data_reads2;
954 data2.writes = data_writes2;
955 mock_sockets[0] = &data1;
956 mock_sockets[1] = &data2;
957 mock_sockets[2] = NULL;
958
959 TestCompletionCallback callback1;
960
961 int rv = trans->Start(&request, &callback1);
[email protected]1c773ea12009-04-28 19:58:42962 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]038e9a32008-10-08 22:40:16963
964 rv = callback1.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:42965 EXPECT_EQ(OK, rv);
[email protected]038e9a32008-10-08 22:40:16966
[email protected]1c773ea12009-04-28 19:58:42967 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]038e9a32008-10-08 22:40:16968 EXPECT_FALSE(response == NULL);
969
970 // The password prompt info should have been set in response->auth_challenge.
971 EXPECT_FALSE(response->auth_challenge.get() == NULL);
972
973 // TODO(eroman): this should really include the effective port (80)
974 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
975 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
976 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
977
978 TestCompletionCallback callback2;
979
980 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
[email protected]1c773ea12009-04-28 19:58:42981 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]038e9a32008-10-08 22:40:16982
983 rv = callback2.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:42984 EXPECT_EQ(OK, rv);
[email protected]038e9a32008-10-08 22:40:16985
986 response = trans->GetResponseInfo();
987 EXPECT_FALSE(response == NULL);
988 EXPECT_TRUE(response->auth_challenge.get() == NULL);
989 EXPECT_EQ(100, response->headers->GetContentLength());
[email protected]038e9a32008-10-08 22:40:16990}
991
[email protected]2d2697f92009-02-18 21:00:32992// Test the request-challenge-retry sequence for basic auth, over a keep-alive
993// connection.
994TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAlive) {
[email protected]1c773ea12009-04-28 19:58:42995 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
996 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]2d2697f92009-02-18 21:00:32997 CreateSession(proxy_service.get()), &mock_socket_factory));
998
[email protected]1c773ea12009-04-28 19:58:42999 HttpRequestInfo request;
[email protected]2d2697f92009-02-18 21:00:321000 request.method = "GET";
1001 request.url = GURL("http://www.google.com/");
1002 request.load_flags = 0;
1003
1004 MockWrite data_writes1[] = {
1005 MockWrite("GET / HTTP/1.1\r\n"
1006 "Host: www.google.com\r\n"
1007 "Connection: keep-alive\r\n\r\n"),
1008
1009 // After calling trans->RestartWithAuth(), this is the request we should
1010 // be issuing -- the final header line contains the credentials.
1011 MockWrite("GET / HTTP/1.1\r\n"
1012 "Host: www.google.com\r\n"
1013 "Connection: keep-alive\r\n"
1014 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1015 };
1016
1017 MockRead data_reads1[] = {
1018 MockRead("HTTP/1.1 401 Unauthorized\r\n"),
1019 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1020 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1021 MockRead("Content-Length: 14\r\n\r\n"),
1022 MockRead("Unauthorized\r\n"),
1023
1024 // Lastly, the server responds with the actual content.
1025 MockRead("HTTP/1.1 200 OK\r\n"),
1026 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1027 MockRead("Content-Length: 100\r\n\r\n"),
[email protected]1c773ea12009-04-28 19:58:421028 MockRead(false, OK),
[email protected]2d2697f92009-02-18 21:00:321029 };
1030
1031 MockSocket data1;
1032 data1.reads = data_reads1;
1033 data1.writes = data_writes1;
1034 mock_sockets[0] = &data1;
1035 mock_sockets[1] = NULL;
1036
1037 TestCompletionCallback callback1;
1038
1039 int rv = trans->Start(&request, &callback1);
[email protected]1c773ea12009-04-28 19:58:421040 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]2d2697f92009-02-18 21:00:321041
1042 rv = callback1.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:421043 EXPECT_EQ(OK, rv);
[email protected]2d2697f92009-02-18 21:00:321044
[email protected]1c773ea12009-04-28 19:58:421045 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]2d2697f92009-02-18 21:00:321046 EXPECT_FALSE(response == NULL);
1047
1048 // The password prompt info should have been set in response->auth_challenge.
1049 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1050
1051 // TODO(eroman): this should really include the effective port (80)
1052 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
1053 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1054 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1055
1056 TestCompletionCallback callback2;
1057
1058 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
[email protected]1c773ea12009-04-28 19:58:421059 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]2d2697f92009-02-18 21:00:321060
1061 rv = callback2.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:421062 EXPECT_EQ(OK, rv);
[email protected]2d2697f92009-02-18 21:00:321063
1064 response = trans->GetResponseInfo();
1065 EXPECT_FALSE(response == NULL);
1066 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1067 EXPECT_EQ(100, response->headers->GetContentLength());
1068}
1069
1070// Test the request-challenge-retry sequence for basic auth, over a keep-alive
1071// connection and with no response body to drain.
1072TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) {
[email protected]1c773ea12009-04-28 19:58:421073 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
1074 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]2d2697f92009-02-18 21:00:321075 CreateSession(proxy_service.get()), &mock_socket_factory));
1076
[email protected]1c773ea12009-04-28 19:58:421077 HttpRequestInfo request;
[email protected]2d2697f92009-02-18 21:00:321078 request.method = "GET";
1079 request.url = GURL("http://www.google.com/");
1080 request.load_flags = 0;
1081
1082 MockWrite data_writes1[] = {
1083 MockWrite("GET / HTTP/1.1\r\n"
1084 "Host: www.google.com\r\n"
1085 "Connection: keep-alive\r\n\r\n"),
1086
1087 // After calling trans->RestartWithAuth(), this is the request we should
1088 // be issuing -- the final header line contains the credentials.
1089 MockWrite("GET / HTTP/1.1\r\n"
1090 "Host: www.google.com\r\n"
1091 "Connection: keep-alive\r\n"
1092 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1093 };
1094
1095 // Respond with 5 kb of response body.
1096 std::string large_body_string("Unauthorized");
1097 large_body_string.append(5 * 1024, ' ');
1098 large_body_string.append("\r\n");
1099
1100 MockRead data_reads1[] = {
1101 MockRead("HTTP/1.1 401 Unauthorized\r\n"),
1102 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1103 MockRead("Content-Length: 0\r\n\r\n"),
1104
1105 // Lastly, the server responds with the actual content.
1106 MockRead("HTTP/1.1 200 OK\r\n"),
1107 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1108 MockRead("Content-Length: 100\r\n\r\n"),
[email protected]1c773ea12009-04-28 19:58:421109 MockRead(false, OK),
[email protected]2d2697f92009-02-18 21:00:321110 };
1111
1112 MockSocket data1;
1113 data1.reads = data_reads1;
1114 data1.writes = data_writes1;
1115 mock_sockets[0] = &data1;
1116 mock_sockets[1] = NULL;
1117
1118 TestCompletionCallback callback1;
1119
1120 int rv = trans->Start(&request, &callback1);
[email protected]1c773ea12009-04-28 19:58:421121 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]2d2697f92009-02-18 21:00:321122
1123 rv = callback1.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:421124 EXPECT_EQ(OK, rv);
[email protected]2d2697f92009-02-18 21:00:321125
[email protected]1c773ea12009-04-28 19:58:421126 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]2d2697f92009-02-18 21:00:321127 EXPECT_FALSE(response == NULL);
1128
1129 // The password prompt info should have been set in response->auth_challenge.
1130 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1131
1132 // TODO(eroman): this should really include the effective port (80)
1133 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
1134 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1135 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1136
1137 TestCompletionCallback callback2;
1138
1139 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
[email protected]1c773ea12009-04-28 19:58:421140 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]2d2697f92009-02-18 21:00:321141
1142 rv = callback2.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:421143 EXPECT_EQ(OK, rv);
[email protected]2d2697f92009-02-18 21:00:321144
1145 response = trans->GetResponseInfo();
1146 EXPECT_FALSE(response == NULL);
1147 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1148 EXPECT_EQ(100, response->headers->GetContentLength());
1149}
1150
1151// Test the request-challenge-retry sequence for basic auth, over a keep-alive
1152// connection and with a large response body to drain.
1153TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) {
[email protected]1c773ea12009-04-28 19:58:421154 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
1155 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]2d2697f92009-02-18 21:00:321156 CreateSession(proxy_service.get()), &mock_socket_factory));
1157
[email protected]1c773ea12009-04-28 19:58:421158 HttpRequestInfo request;
[email protected]2d2697f92009-02-18 21:00:321159 request.method = "GET";
1160 request.url = GURL("http://www.google.com/");
1161 request.load_flags = 0;
1162
1163 MockWrite data_writes1[] = {
1164 MockWrite("GET / HTTP/1.1\r\n"
1165 "Host: www.google.com\r\n"
1166 "Connection: keep-alive\r\n\r\n"),
1167
1168 // After calling trans->RestartWithAuth(), this is the request we should
1169 // be issuing -- the final header line contains the credentials.
1170 MockWrite("GET / HTTP/1.1\r\n"
1171 "Host: www.google.com\r\n"
1172 "Connection: keep-alive\r\n"
1173 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1174 };
1175
1176 // Respond with 5 kb of response body.
1177 std::string large_body_string("Unauthorized");
1178 large_body_string.append(5 * 1024, ' ');
1179 large_body_string.append("\r\n");
1180
1181 MockRead data_reads1[] = {
1182 MockRead("HTTP/1.1 401 Unauthorized\r\n"),
1183 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1184 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1185 // 5134 = 12 + 5 * 1024 + 2
1186 MockRead("Content-Length: 5134\r\n\r\n"),
1187 MockRead(true, large_body_string.data(), large_body_string.size()),
1188
1189 // Lastly, the server responds with the actual content.
1190 MockRead("HTTP/1.1 200 OK\r\n"),
1191 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1192 MockRead("Content-Length: 100\r\n\r\n"),
[email protected]1c773ea12009-04-28 19:58:421193 MockRead(false, OK),
[email protected]2d2697f92009-02-18 21:00:321194 };
1195
1196 MockSocket data1;
1197 data1.reads = data_reads1;
1198 data1.writes = data_writes1;
1199 mock_sockets[0] = &data1;
1200 mock_sockets[1] = NULL;
1201
1202 TestCompletionCallback callback1;
1203
1204 int rv = trans->Start(&request, &callback1);
[email protected]1c773ea12009-04-28 19:58:421205 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]2d2697f92009-02-18 21:00:321206
1207 rv = callback1.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:421208 EXPECT_EQ(OK, rv);
[email protected]2d2697f92009-02-18 21:00:321209
[email protected]1c773ea12009-04-28 19:58:421210 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]2d2697f92009-02-18 21:00:321211 EXPECT_FALSE(response == NULL);
1212
1213 // The password prompt info should have been set in response->auth_challenge.
1214 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1215
1216 // TODO(eroman): this should really include the effective port (80)
1217 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
1218 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1219 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1220
1221 TestCompletionCallback callback2;
1222
1223 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
[email protected]1c773ea12009-04-28 19:58:421224 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]2d2697f92009-02-18 21:00:321225
1226 rv = callback2.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:421227 EXPECT_EQ(OK, rv);
[email protected]2d2697f92009-02-18 21:00:321228
1229 response = trans->GetResponseInfo();
1230 EXPECT_FALSE(response == NULL);
1231 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1232 EXPECT_EQ(100, response->headers->GetContentLength());
1233}
1234
1235// Test the request-challenge-retry sequence for basic auth, over a keep-alive
1236// proxy connection, when setting up an SSL tunnel.
1237TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAlive) {
1238 // Configure against proxy server "myproxy:70".
[email protected]1c773ea12009-04-28 19:58:421239 scoped_ptr<ProxyService> proxy_service(
[email protected]2d2697f92009-02-18 21:00:321240 CreateFixedProxyService("myproxy:70"));
1241
[email protected]1c773ea12009-04-28 19:58:421242 scoped_refptr<HttpNetworkSession> session(
[email protected]2d2697f92009-02-18 21:00:321243 CreateSession(proxy_service.get()));
1244
[email protected]1c773ea12009-04-28 19:58:421245 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]2d2697f92009-02-18 21:00:321246 session.get(), &mock_socket_factory));
1247
[email protected]1c773ea12009-04-28 19:58:421248 HttpRequestInfo request;
[email protected]2d2697f92009-02-18 21:00:321249 request.method = "GET";
1250 request.url = GURL("https://www.google.com/");
1251 request.load_flags = 0;
1252
1253 // Since we have proxy, should try to establish tunnel.
1254 MockWrite data_writes1[] = {
1255 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
1256 "Host: www.google.com\r\n\r\n"),
1257
1258 // After calling trans->RestartWithAuth(), this is the request we should
1259 // be issuing -- the final header line contains the credentials.
1260 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
1261 "Host: www.google.com\r\n"
1262 "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"),
1263 };
1264
1265 // The proxy responds to the connect with a 407, using a persistent
1266 // connection.
1267 MockRead data_reads1[] = {
1268 // No credentials.
1269 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
1270 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1271 MockRead("Content-Length: 10\r\n\r\n"),
1272 MockRead("0123456789"),
1273
1274 // Wrong credentials (wrong password).
1275 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
1276 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1277 MockRead("Content-Length: 10\r\n\r\n"),
1278 // No response body because the test stops reading here.
[email protected]1c773ea12009-04-28 19:58:421279 MockRead(false, ERR_UNEXPECTED), // Should not be reached.
[email protected]2d2697f92009-02-18 21:00:321280 };
1281
1282 MockSocket data1;
1283 data1.writes = data_writes1;
1284 data1.reads = data_reads1;
1285 mock_sockets[0] = &data1;
1286 mock_sockets[1] = NULL;
1287
1288 TestCompletionCallback callback1;
1289
1290 int rv = trans->Start(&request, &callback1);
[email protected]1c773ea12009-04-28 19:58:421291 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]2d2697f92009-02-18 21:00:321292
1293 rv = callback1.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:421294 EXPECT_EQ(OK, rv);
[email protected]2d2697f92009-02-18 21:00:321295
[email protected]1c773ea12009-04-28 19:58:421296 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]2d2697f92009-02-18 21:00:321297 EXPECT_FALSE(response == NULL);
1298
1299 EXPECT_TRUE(response->headers->IsKeepAlive());
1300 EXPECT_EQ(407, response->headers->response_code());
1301 EXPECT_EQ(10, response->headers->GetContentLength());
[email protected]1c773ea12009-04-28 19:58:421302 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
[email protected]2d2697f92009-02-18 21:00:321303
1304 // The password prompt info should have been set in response->auth_challenge.
1305 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1306
1307 // TODO(eroman): this should really include the effective port (80)
1308 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host);
1309 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1310 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1311
1312 TestCompletionCallback callback2;
1313
1314 // Wrong password (should be "bar").
1315 rv = trans->RestartWithAuth(L"foo", L"baz", &callback2);
[email protected]1c773ea12009-04-28 19:58:421316 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]2d2697f92009-02-18 21:00:321317
1318 rv = callback2.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:421319 EXPECT_EQ(OK, rv);
[email protected]2d2697f92009-02-18 21:00:321320
1321 response = trans->GetResponseInfo();
1322 EXPECT_FALSE(response == NULL);
1323
1324 EXPECT_TRUE(response->headers->IsKeepAlive());
1325 EXPECT_EQ(407, response->headers->response_code());
1326 EXPECT_EQ(10, response->headers->GetContentLength());
[email protected]1c773ea12009-04-28 19:58:421327 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
[email protected]2d2697f92009-02-18 21:00:321328
1329 // The password prompt info should have been set in response->auth_challenge.
1330 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1331
1332 // TODO(eroman): this should really include the effective port (80)
1333 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host);
1334 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1335 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1336}
1337
[email protected]a8e9b162009-03-12 00:06:441338// Test that we don't read the response body when we fail to establish a tunnel,
1339// even if the user cancels the proxy's auth attempt.
1340TEST_F(HttpNetworkTransactionTest, BasicAuthProxyCancelTunnel) {
1341 // Configure against proxy server "myproxy:70".
[email protected]1c773ea12009-04-28 19:58:421342 scoped_ptr<ProxyService> proxy_service(
[email protected]a8e9b162009-03-12 00:06:441343 CreateFixedProxyService("myproxy:70"));
1344
[email protected]1c773ea12009-04-28 19:58:421345 scoped_refptr<HttpNetworkSession> session(
[email protected]a8e9b162009-03-12 00:06:441346 CreateSession(proxy_service.get()));
1347
[email protected]1c773ea12009-04-28 19:58:421348 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]a8e9b162009-03-12 00:06:441349 session.get(), &mock_socket_factory));
1350
[email protected]1c773ea12009-04-28 19:58:421351 HttpRequestInfo request;
[email protected]a8e9b162009-03-12 00:06:441352 request.method = "GET";
1353 request.url = GURL("https://www.google.com/");
1354 request.load_flags = 0;
1355
1356 // Since we have proxy, should try to establish tunnel.
1357 MockWrite data_writes[] = {
1358 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
1359 "Host: www.google.com\r\n\r\n"),
1360 };
1361
1362 // The proxy responds to the connect with a 407.
1363 MockRead data_reads[] = {
1364 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
1365 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1366 MockRead("Content-Length: 10\r\n\r\n"),
[email protected]1c773ea12009-04-28 19:58:421367 MockRead(false, ERR_UNEXPECTED), // Should not be reached.
[email protected]a8e9b162009-03-12 00:06:441368 };
1369
1370 MockSocket data;
1371 data.writes = data_writes;
1372 data.reads = data_reads;
1373 mock_sockets[0] = &data;
1374 mock_sockets[1] = NULL;
1375
1376 TestCompletionCallback callback;
1377
1378 int rv = trans->Start(&request, &callback);
[email protected]1c773ea12009-04-28 19:58:421379 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]a8e9b162009-03-12 00:06:441380
1381 rv = callback.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:421382 EXPECT_EQ(OK, rv);
[email protected]a8e9b162009-03-12 00:06:441383
[email protected]1c773ea12009-04-28 19:58:421384 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]a8e9b162009-03-12 00:06:441385 EXPECT_FALSE(response == NULL);
1386
1387 EXPECT_TRUE(response->headers->IsKeepAlive());
1388 EXPECT_EQ(407, response->headers->response_code());
1389 EXPECT_EQ(10, response->headers->GetContentLength());
[email protected]1c773ea12009-04-28 19:58:421390 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
[email protected]a8e9b162009-03-12 00:06:441391
1392 std::string response_data;
1393 rv = ReadTransaction(trans.get(), &response_data);
[email protected]1c773ea12009-04-28 19:58:421394 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
[email protected]a8e9b162009-03-12 00:06:441395}
1396
[email protected]c744cf22009-02-27 07:28:081397static void ConnectStatusHelperWithExpectedStatus(
1398 const MockRead& status, int expected_status) {
1399 // Configure against proxy server "myproxy:70".
[email protected]1c773ea12009-04-28 19:58:421400 scoped_ptr<ProxyService> proxy_service(
[email protected]c744cf22009-02-27 07:28:081401 CreateFixedProxyService("myproxy:70"));
1402
[email protected]1c773ea12009-04-28 19:58:421403 scoped_refptr<HttpNetworkSession> session(
[email protected]c744cf22009-02-27 07:28:081404 CreateSession(proxy_service.get()));
1405
[email protected]1c773ea12009-04-28 19:58:421406 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]c744cf22009-02-27 07:28:081407 session.get(), &mock_socket_factory));
1408
[email protected]1c773ea12009-04-28 19:58:421409 HttpRequestInfo request;
[email protected]c744cf22009-02-27 07:28:081410 request.method = "GET";
1411 request.url = GURL("https://www.google.com/");
1412 request.load_flags = 0;
1413
1414 // Since we have proxy, should try to establish tunnel.
1415 MockWrite data_writes[] = {
1416 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
1417 "Host: www.google.com\r\n\r\n"),
1418 };
1419
1420 MockRead data_reads[] = {
1421 status,
1422 MockRead("Content-Length: 10\r\n\r\n"),
1423 // No response body because the test stops reading here.
[email protected]1c773ea12009-04-28 19:58:421424 MockRead(false, ERR_UNEXPECTED), // Should not be reached.
[email protected]c744cf22009-02-27 07:28:081425 };
1426
1427 MockSocket data;
1428 data.writes = data_writes;
1429 data.reads = data_reads;
1430 mock_sockets[0] = &data;
1431 mock_sockets[1] = NULL;
1432
1433 TestCompletionCallback callback;
1434
1435 int rv = trans->Start(&request, &callback);
[email protected]1c773ea12009-04-28 19:58:421436 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]c744cf22009-02-27 07:28:081437
1438 rv = callback.WaitForResult();
1439 EXPECT_EQ(expected_status, rv);
1440}
1441
1442static void ConnectStatusHelper(const MockRead& status) {
1443 ConnectStatusHelperWithExpectedStatus(
[email protected]1c773ea12009-04-28 19:58:421444 status, ERR_TUNNEL_CONNECTION_FAILED);
[email protected]c744cf22009-02-27 07:28:081445}
1446
1447TEST_F(HttpNetworkTransactionTest, ConnectStatus100) {
1448 ConnectStatusHelper(MockRead("HTTP/1.1 100 Continue\r\n"));
1449}
1450
1451TEST_F(HttpNetworkTransactionTest, ConnectStatus101) {
1452 ConnectStatusHelper(MockRead("HTTP/1.1 101 Switching Protocols\r\n"));
1453}
1454
1455TEST_F(HttpNetworkTransactionTest, ConnectStatus201) {
1456 ConnectStatusHelper(MockRead("HTTP/1.1 201 Created\r\n"));
1457}
1458
1459TEST_F(HttpNetworkTransactionTest, ConnectStatus202) {
1460 ConnectStatusHelper(MockRead("HTTP/1.1 202 Accepted\r\n"));
1461}
1462
1463TEST_F(HttpNetworkTransactionTest, ConnectStatus203) {
1464 ConnectStatusHelper(
1465 MockRead("HTTP/1.1 203 Non-Authoritative Information\r\n"));
1466}
1467
1468TEST_F(HttpNetworkTransactionTest, ConnectStatus204) {
1469 ConnectStatusHelper(MockRead("HTTP/1.1 204 No Content\r\n"));
1470}
1471
1472TEST_F(HttpNetworkTransactionTest, ConnectStatus205) {
1473 ConnectStatusHelper(MockRead("HTTP/1.1 205 Reset Content\r\n"));
1474}
1475
1476TEST_F(HttpNetworkTransactionTest, ConnectStatus206) {
1477 ConnectStatusHelper(MockRead("HTTP/1.1 206 Partial Content\r\n"));
1478}
1479
1480TEST_F(HttpNetworkTransactionTest, ConnectStatus300) {
1481 ConnectStatusHelper(MockRead("HTTP/1.1 300 Multiple Choices\r\n"));
1482}
1483
1484TEST_F(HttpNetworkTransactionTest, ConnectStatus301) {
1485 ConnectStatusHelper(MockRead("HTTP/1.1 301 Moved Permanently\r\n"));
1486}
1487
1488TEST_F(HttpNetworkTransactionTest, ConnectStatus302) {
1489 ConnectStatusHelper(MockRead("HTTP/1.1 302 Found\r\n"));
1490}
1491
1492TEST_F(HttpNetworkTransactionTest, ConnectStatus303) {
1493 ConnectStatusHelper(MockRead("HTTP/1.1 303 See Other\r\n"));
1494}
1495
1496TEST_F(HttpNetworkTransactionTest, ConnectStatus304) {
1497 ConnectStatusHelper(MockRead("HTTP/1.1 304 Not Modified\r\n"));
1498}
1499
1500TEST_F(HttpNetworkTransactionTest, ConnectStatus305) {
1501 ConnectStatusHelper(MockRead("HTTP/1.1 305 Use Proxy\r\n"));
1502}
1503
1504TEST_F(HttpNetworkTransactionTest, ConnectStatus306) {
1505 ConnectStatusHelper(MockRead("HTTP/1.1 306\r\n"));
1506}
1507
1508TEST_F(HttpNetworkTransactionTest, ConnectStatus307) {
1509 ConnectStatusHelper(MockRead("HTTP/1.1 307 Temporary Redirect\r\n"));
1510}
1511
1512TEST_F(HttpNetworkTransactionTest, ConnectStatus400) {
1513 ConnectStatusHelper(MockRead("HTTP/1.1 400 Bad Request\r\n"));
1514}
1515
1516TEST_F(HttpNetworkTransactionTest, ConnectStatus401) {
1517 ConnectStatusHelper(MockRead("HTTP/1.1 401 Unauthorized\r\n"));
1518}
1519
1520TEST_F(HttpNetworkTransactionTest, ConnectStatus402) {
1521 ConnectStatusHelper(MockRead("HTTP/1.1 402 Payment Required\r\n"));
1522}
1523
1524TEST_F(HttpNetworkTransactionTest, ConnectStatus403) {
1525 ConnectStatusHelper(MockRead("HTTP/1.1 403 Forbidden\r\n"));
1526}
1527
1528TEST_F(HttpNetworkTransactionTest, ConnectStatus404) {
1529 ConnectStatusHelper(MockRead("HTTP/1.1 404 Not Found\r\n"));
1530}
1531
1532TEST_F(HttpNetworkTransactionTest, ConnectStatus405) {
1533 ConnectStatusHelper(MockRead("HTTP/1.1 405 Method Not Allowed\r\n"));
1534}
1535
1536TEST_F(HttpNetworkTransactionTest, ConnectStatus406) {
1537 ConnectStatusHelper(MockRead("HTTP/1.1 406 Not Acceptable\r\n"));
1538}
1539
1540TEST_F(HttpNetworkTransactionTest, ConnectStatus407) {
1541 ConnectStatusHelperWithExpectedStatus(
1542 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
[email protected]1c773ea12009-04-28 19:58:421543 ERR_PROXY_AUTH_REQUESTED);
[email protected]c744cf22009-02-27 07:28:081544}
1545
1546TEST_F(HttpNetworkTransactionTest, ConnectStatus408) {
1547 ConnectStatusHelper(MockRead("HTTP/1.1 408 Request Timeout\r\n"));
1548}
1549
1550TEST_F(HttpNetworkTransactionTest, ConnectStatus409) {
1551 ConnectStatusHelper(MockRead("HTTP/1.1 409 Conflict\r\n"));
1552}
1553
1554TEST_F(HttpNetworkTransactionTest, ConnectStatus410) {
1555 ConnectStatusHelper(MockRead("HTTP/1.1 410 Gone\r\n"));
1556}
1557
1558TEST_F(HttpNetworkTransactionTest, ConnectStatus411) {
1559 ConnectStatusHelper(MockRead("HTTP/1.1 411 Length Required\r\n"));
1560}
1561
1562TEST_F(HttpNetworkTransactionTest, ConnectStatus412) {
1563 ConnectStatusHelper(MockRead("HTTP/1.1 412 Precondition Failed\r\n"));
1564}
1565
1566TEST_F(HttpNetworkTransactionTest, ConnectStatus413) {
1567 ConnectStatusHelper(MockRead("HTTP/1.1 413 Request Entity Too Large\r\n"));
1568}
1569
1570TEST_F(HttpNetworkTransactionTest, ConnectStatus414) {
1571 ConnectStatusHelper(MockRead("HTTP/1.1 414 Request-URI Too Long\r\n"));
1572}
1573
1574TEST_F(HttpNetworkTransactionTest, ConnectStatus415) {
1575 ConnectStatusHelper(MockRead("HTTP/1.1 415 Unsupported Media Type\r\n"));
1576}
1577
1578TEST_F(HttpNetworkTransactionTest, ConnectStatus416) {
1579 ConnectStatusHelper(
1580 MockRead("HTTP/1.1 416 Requested Range Not Satisfiable\r\n"));
1581}
1582
1583TEST_F(HttpNetworkTransactionTest, ConnectStatus417) {
1584 ConnectStatusHelper(MockRead("HTTP/1.1 417 Expectation Failed\r\n"));
1585}
1586
1587TEST_F(HttpNetworkTransactionTest, ConnectStatus500) {
1588 ConnectStatusHelper(MockRead("HTTP/1.1 500 Internal Server Error\r\n"));
1589}
1590
1591TEST_F(HttpNetworkTransactionTest, ConnectStatus501) {
1592 ConnectStatusHelper(MockRead("HTTP/1.1 501 Not Implemented\r\n"));
1593}
1594
1595TEST_F(HttpNetworkTransactionTest, ConnectStatus502) {
1596 ConnectStatusHelper(MockRead("HTTP/1.1 502 Bad Gateway\r\n"));
1597}
1598
1599TEST_F(HttpNetworkTransactionTest, ConnectStatus503) {
1600 ConnectStatusHelper(MockRead("HTTP/1.1 503 Service Unavailable\r\n"));
1601}
1602
1603TEST_F(HttpNetworkTransactionTest, ConnectStatus504) {
1604 ConnectStatusHelper(MockRead("HTTP/1.1 504 Gateway Timeout\r\n"));
1605}
1606
1607TEST_F(HttpNetworkTransactionTest, ConnectStatus505) {
1608 ConnectStatusHelper(MockRead("HTTP/1.1 505 HTTP Version Not Supported\r\n"));
1609}
1610
[email protected]038e9a32008-10-08 22:40:161611// Test the flow when both the proxy server AND origin server require
1612// authentication. Again, this uses basic auth for both since that is
1613// the simplest to mock.
1614TEST_F(HttpNetworkTransactionTest, BasicAuthProxyThenServer) {
[email protected]1c773ea12009-04-28 19:58:421615 scoped_ptr<ProxyService> proxy_service(
[email protected]51fff29d2008-12-19 22:17:531616 CreateFixedProxyService("myproxy:70"));
[email protected]db8f44c2008-12-13 04:52:011617
[email protected]038e9a32008-10-08 22:40:161618 // Configure against proxy server "myproxy:70".
[email protected]1c773ea12009-04-28 19:58:421619 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]51fff29d2008-12-19 22:17:531620 CreateSession(proxy_service.get()),
[email protected]db8f44c2008-12-13 04:52:011621 &mock_socket_factory));
[email protected]038e9a32008-10-08 22:40:161622
[email protected]1c773ea12009-04-28 19:58:421623 HttpRequestInfo request;
[email protected]038e9a32008-10-08 22:40:161624 request.method = "GET";
1625 request.url = GURL("http://www.google.com/");
1626 request.load_flags = 0;
1627
[email protected]f9ee6b52008-11-08 06:46:231628 MockWrite data_writes1[] = {
1629 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
1630 "Host: www.google.com\r\n"
1631 "Proxy-Connection: keep-alive\r\n\r\n"),
1632 };
1633
[email protected]038e9a32008-10-08 22:40:161634 MockRead data_reads1[] = {
1635 MockRead("HTTP/1.0 407 Unauthorized\r\n"),
1636 // Give a couple authenticate options (only the middle one is actually
1637 // supported).
[email protected]aaead502008-10-15 00:20:111638 MockRead("Proxy-Authenticate: Basic\r\n"), // Malformed
[email protected]038e9a32008-10-08 22:40:161639 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1640 MockRead("Proxy-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"),
1641 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1642 // Large content-length -- won't matter, as connection will be reset.
1643 MockRead("Content-Length: 10000\r\n\r\n"),
[email protected]1c773ea12009-04-28 19:58:421644 MockRead(false, ERR_FAILED),
[email protected]038e9a32008-10-08 22:40:161645 };
1646
1647 // After calling trans->RestartWithAuth() the first time, this is the
1648 // request we should be issuing -- the final header line contains the
1649 // proxy's credentials.
1650 MockWrite data_writes2[] = {
1651 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
1652 "Host: www.google.com\r\n"
1653 "Proxy-Connection: keep-alive\r\n"
1654 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
1655 };
1656
1657 // Now the proxy server lets the request pass through to origin server.
1658 // The origin server responds with a 401.
1659 MockRead data_reads2[] = {
1660 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
1661 // Note: We are using the same realm-name as the proxy server. This is
1662 // completely valid, as realms are unique across hosts.
1663 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
1664 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1665 MockRead("Content-Length: 2000\r\n\r\n"),
[email protected]1c773ea12009-04-28 19:58:421666 MockRead(false, ERR_FAILED), // Won't be reached.
[email protected]038e9a32008-10-08 22:40:161667 };
1668
1669 // After calling trans->RestartWithAuth() the second time, we should send
1670 // the credentials for both the proxy and origin server.
1671 MockWrite data_writes3[] = {
1672 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
1673 "Host: www.google.com\r\n"
1674 "Proxy-Connection: keep-alive\r\n"
1675 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n"
1676 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"),
1677 };
1678
1679 // Lastly we get the desired content.
1680 MockRead data_reads3[] = {
1681 MockRead("HTTP/1.0 200 OK\r\n"),
1682 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
1683 MockRead("Content-Length: 100\r\n\r\n"),
[email protected]1c773ea12009-04-28 19:58:421684 MockRead(false, OK),
[email protected]038e9a32008-10-08 22:40:161685 };
1686
1687 MockSocket data1;
1688 data1.reads = data_reads1;
[email protected]f9ee6b52008-11-08 06:46:231689 data1.writes = data_writes1;
[email protected]038e9a32008-10-08 22:40:161690 MockSocket data2;
1691 data2.reads = data_reads2;
1692 data2.writes = data_writes2;
1693 MockSocket data3;
1694 data3.reads = data_reads3;
1695 data3.writes = data_writes3;
1696 mock_sockets[0] = &data1;
1697 mock_sockets[1] = &data2;
1698 mock_sockets[2] = &data3;
1699 mock_sockets[3] = NULL;
1700
1701 TestCompletionCallback callback1;
1702
1703 int rv = trans->Start(&request, &callback1);
[email protected]1c773ea12009-04-28 19:58:421704 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]038e9a32008-10-08 22:40:161705
1706 rv = callback1.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:421707 EXPECT_EQ(OK, rv);
[email protected]038e9a32008-10-08 22:40:161708
[email protected]1c773ea12009-04-28 19:58:421709 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]038e9a32008-10-08 22:40:161710 EXPECT_FALSE(response == NULL);
1711
1712 // The password prompt info should have been set in response->auth_challenge.
1713 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1714
1715 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host);
1716 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1717 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1718
1719 TestCompletionCallback callback2;
1720
1721 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
[email protected]1c773ea12009-04-28 19:58:421722 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]038e9a32008-10-08 22:40:161723
1724 rv = callback2.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:421725 EXPECT_EQ(OK, rv);
[email protected]038e9a32008-10-08 22:40:161726
1727 response = trans->GetResponseInfo();
1728 EXPECT_FALSE(response == NULL);
1729 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1730
1731 // TODO(eroman): this should really include the effective port (80)
1732 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
1733 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
1734 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
1735
1736 TestCompletionCallback callback3;
1737
1738 rv = trans->RestartWithAuth(L"foo2", L"bar2", &callback3);
[email protected]1c773ea12009-04-28 19:58:421739 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]038e9a32008-10-08 22:40:161740
1741 rv = callback3.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:421742 EXPECT_EQ(OK, rv);
[email protected]038e9a32008-10-08 22:40:161743
1744 response = trans->GetResponseInfo();
1745 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1746 EXPECT_EQ(100, response->headers->GetContentLength());
[email protected]038e9a32008-10-08 22:40:161747}
[email protected]4ddaf2502008-10-23 18:26:191748
[email protected]385a4672009-03-11 22:21:291749// The NTLM authentication unit tests were generated by capturing the HTTP
1750// requests and responses using Fiddler 2 and inspecting the generated random
1751// bytes in the debugger.
1752
1753// Enter the correct password and authenticate successfully.
1754TEST_F(HttpNetworkTransactionTest, NTLMAuth1) {
[email protected]1c773ea12009-04-28 19:58:421755 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockGenerateRandom1,
[email protected]fe2bc6a2009-03-23 16:52:201756 MockGetHostName);
[email protected]385a4672009-03-11 22:21:291757
[email protected]1c773ea12009-04-28 19:58:421758 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
1759 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]3f918782009-02-28 01:29:241760 CreateSession(proxy_service.get()), &mock_socket_factory));
1761
[email protected]1c773ea12009-04-28 19:58:421762 HttpRequestInfo request;
[email protected]3f918782009-02-28 01:29:241763 request.method = "GET";
1764 request.url = GURL("http://172.22.68.17/kids/login.aspx");
1765 request.load_flags = 0;
1766
1767 MockWrite data_writes1[] = {
1768 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1769 "Host: 172.22.68.17\r\n"
1770 "Connection: keep-alive\r\n\r\n"),
1771 };
1772
1773 MockRead data_reads1[] = {
1774 MockRead("HTTP/1.1 401 Access Denied\r\n"),
1775 // Negotiate and NTLM are often requested together. We only support NTLM.
1776 MockRead("WWW-Authenticate: Negotiate\r\n"),
1777 MockRead("WWW-Authenticate: NTLM\r\n"),
1778 MockRead("Connection: close\r\n"),
1779 MockRead("Content-Length: 42\r\n"),
[email protected]076c85082009-04-10 23:21:361780 MockRead("Content-Type: text/html\r\n\r\n"),
[email protected]3f918782009-02-28 01:29:241781 // Missing content -- won't matter, as connection will be reset.
[email protected]1c773ea12009-04-28 19:58:421782 MockRead(false, ERR_UNEXPECTED),
[email protected]3f918782009-02-28 01:29:241783 };
1784
1785 MockWrite data_writes2[] = {
[email protected]0757e7702009-03-27 04:00:221786 // After restarting with a null identity, this is the
[email protected]3f918782009-02-28 01:29:241787 // request we should be issuing -- the final header line contains a Type
1788 // 1 message.
1789 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1790 "Host: 172.22.68.17\r\n"
1791 "Connection: keep-alive\r\n"
1792 "Authorization: NTLM "
1793 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"),
1794
1795 // After calling trans->RestartWithAuth(), we should send a Type 3 message
1796 // (the credentials for the origin server). The second request continues
1797 // on the same connection.
1798 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1799 "Host: 172.22.68.17\r\n"
1800 "Connection: keep-alive\r\n"
[email protected]385a4672009-03-11 22:21:291801 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA"
1802 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA"
1803 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBVKW"
1804 "Yma5xzVAAAAAAAAAAAAAAAAAAAAACH+gWcm+YsP9Tqb9zCR3WAeZZX"
1805 "ahlhx5I=\r\n\r\n"),
[email protected]3f918782009-02-28 01:29:241806 };
1807
1808 MockRead data_reads2[] = {
1809 // The origin server responds with a Type 2 message.
1810 MockRead("HTTP/1.1 401 Access Denied\r\n"),
1811 MockRead("WWW-Authenticate: NTLM "
[email protected]385a4672009-03-11 22:21:291812 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCjGpMpPGlYKkAAAAAAAAAALo"
[email protected]3f918782009-02-28 01:29:241813 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE"
1814 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA"
1815 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy"
1816 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB"
1817 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw"
1818 "BtAAAAAAA=\r\n"),
1819 MockRead("Content-Length: 42\r\n"),
[email protected]076c85082009-04-10 23:21:361820 MockRead("Content-Type: text/html\r\n\r\n"),
[email protected]3f918782009-02-28 01:29:241821 MockRead("You are not authorized to view this page\r\n"),
1822
1823 // Lastly we get the desired content.
1824 MockRead("HTTP/1.1 200 OK\r\n"),
1825 MockRead("Content-Type: text/html; charset=utf-8\r\n"),
1826 MockRead("Content-Length: 13\r\n\r\n"),
1827 MockRead("Please Login\r\n"),
[email protected]1c773ea12009-04-28 19:58:421828 MockRead(false, OK),
[email protected]3f918782009-02-28 01:29:241829 };
1830
1831 MockSocket data1;
1832 data1.reads = data_reads1;
1833 data1.writes = data_writes1;
1834 MockSocket data2;
1835 data2.reads = data_reads2;
1836 data2.writes = data_writes2;
1837 mock_sockets[0] = &data1;
1838 mock_sockets[1] = &data2;
1839 mock_sockets[2] = NULL;
1840
1841 TestCompletionCallback callback1;
1842
1843 int rv = trans->Start(&request, &callback1);
[email protected]1c773ea12009-04-28 19:58:421844 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]3f918782009-02-28 01:29:241845
1846 rv = callback1.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:421847 EXPECT_EQ(OK, rv);
[email protected]3f918782009-02-28 01:29:241848
[email protected]0757e7702009-03-27 04:00:221849 EXPECT_TRUE(trans->IsReadyToRestartForAuth());
1850 TestCompletionCallback callback2;
1851 rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback2);
[email protected]1c773ea12009-04-28 19:58:421852 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]0757e7702009-03-27 04:00:221853 rv = callback2.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:421854 EXPECT_EQ(OK, rv);
[email protected]0757e7702009-03-27 04:00:221855 EXPECT_FALSE(trans->IsReadyToRestartForAuth());
1856
[email protected]1c773ea12009-04-28 19:58:421857 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]3f918782009-02-28 01:29:241858 EXPECT_FALSE(response == NULL);
1859
1860 // The password prompt info should have been set in response->auth_challenge.
1861 EXPECT_FALSE(response->auth_challenge.get() == NULL);
1862
1863 // TODO(eroman): this should really include the effective port (80)
1864 EXPECT_EQ(L"172.22.68.17", response->auth_challenge->host);
1865 EXPECT_EQ(L"", response->auth_challenge->realm);
1866 EXPECT_EQ(L"ntlm", response->auth_challenge->scheme);
1867
[email protected]0757e7702009-03-27 04:00:221868 TestCompletionCallback callback3;
[email protected]3f918782009-02-28 01:29:241869
[email protected]0757e7702009-03-27 04:00:221870 rv = trans->RestartWithAuth(L"testing-ntlm", L"testing-ntlm", &callback3);
[email protected]1c773ea12009-04-28 19:58:421871 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]3f918782009-02-28 01:29:241872
[email protected]0757e7702009-03-27 04:00:221873 rv = callback3.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:421874 EXPECT_EQ(OK, rv);
[email protected]3f918782009-02-28 01:29:241875
1876 response = trans->GetResponseInfo();
1877 EXPECT_TRUE(response->auth_challenge.get() == NULL);
1878 EXPECT_EQ(13, response->headers->GetContentLength());
1879}
1880
[email protected]385a4672009-03-11 22:21:291881// Enter a wrong password, and then the correct one.
1882TEST_F(HttpNetworkTransactionTest, NTLMAuth2) {
[email protected]1c773ea12009-04-28 19:58:421883 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockGenerateRandom2,
[email protected]fe2bc6a2009-03-23 16:52:201884 MockGetHostName);
[email protected]385a4672009-03-11 22:21:291885
[email protected]1c773ea12009-04-28 19:58:421886 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
1887 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]385a4672009-03-11 22:21:291888 CreateSession(proxy_service.get()), &mock_socket_factory));
1889
[email protected]1c773ea12009-04-28 19:58:421890 HttpRequestInfo request;
[email protected]385a4672009-03-11 22:21:291891 request.method = "GET";
1892 request.url = GURL("http://172.22.68.17/kids/login.aspx");
1893 request.load_flags = 0;
1894
1895 MockWrite data_writes1[] = {
1896 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1897 "Host: 172.22.68.17\r\n"
1898 "Connection: keep-alive\r\n\r\n"),
1899 };
1900
1901 MockRead data_reads1[] = {
1902 MockRead("HTTP/1.1 401 Access Denied\r\n"),
1903 // Negotiate and NTLM are often requested together. We only support NTLM.
1904 MockRead("WWW-Authenticate: Negotiate\r\n"),
1905 MockRead("WWW-Authenticate: NTLM\r\n"),
1906 MockRead("Connection: close\r\n"),
1907 MockRead("Content-Length: 42\r\n"),
[email protected]076c85082009-04-10 23:21:361908 MockRead("Content-Type: text/html\r\n\r\n"),
[email protected]385a4672009-03-11 22:21:291909 // Missing content -- won't matter, as connection will be reset.
[email protected]1c773ea12009-04-28 19:58:421910 MockRead(false, ERR_UNEXPECTED),
[email protected]385a4672009-03-11 22:21:291911 };
1912
1913 MockWrite data_writes2[] = {
[email protected]0757e7702009-03-27 04:00:221914 // After restarting with a null identity, this is the
[email protected]385a4672009-03-11 22:21:291915 // request we should be issuing -- the final header line contains a Type
1916 // 1 message.
1917 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1918 "Host: 172.22.68.17\r\n"
1919 "Connection: keep-alive\r\n"
1920 "Authorization: NTLM "
1921 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"),
1922
1923 // After calling trans->RestartWithAuth(), we should send a Type 3 message
1924 // (the credentials for the origin server). The second request continues
1925 // on the same connection.
1926 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1927 "Host: 172.22.68.17\r\n"
1928 "Connection: keep-alive\r\n"
1929 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA"
1930 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA"
1931 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwCWeY"
1932 "XnSZNwoQAAAAAAAAAAAAAAAAAAAADLa34/phTTKzNTWdub+uyFleOj"
1933 "4Ww7b7E=\r\n\r\n"),
1934 };
1935
1936 MockRead data_reads2[] = {
1937 // The origin server responds with a Type 2 message.
1938 MockRead("HTTP/1.1 401 Access Denied\r\n"),
1939 MockRead("WWW-Authenticate: NTLM "
1940 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCbVWUZezVGpAAAAAAAAAAALo"
1941 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE"
1942 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA"
1943 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy"
1944 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB"
1945 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw"
1946 "BtAAAAAAA=\r\n"),
1947 MockRead("Content-Length: 42\r\n"),
[email protected]076c85082009-04-10 23:21:361948 MockRead("Content-Type: text/html\r\n\r\n"),
[email protected]385a4672009-03-11 22:21:291949 MockRead("You are not authorized to view this page\r\n"),
1950
1951 // Wrong password.
1952 MockRead("HTTP/1.1 401 Access Denied\r\n"),
1953 MockRead("WWW-Authenticate: Negotiate\r\n"),
1954 MockRead("WWW-Authenticate: NTLM\r\n"),
1955 MockRead("Connection: close\r\n"),
1956 MockRead("Content-Length: 42\r\n"),
[email protected]076c85082009-04-10 23:21:361957 MockRead("Content-Type: text/html\r\n\r\n"),
[email protected]385a4672009-03-11 22:21:291958 // Missing content -- won't matter, as connection will be reset.
[email protected]1c773ea12009-04-28 19:58:421959 MockRead(false, ERR_UNEXPECTED),
[email protected]385a4672009-03-11 22:21:291960 };
1961
1962 MockWrite data_writes3[] = {
[email protected]0757e7702009-03-27 04:00:221963 // After restarting with a null identity, this is the
[email protected]385a4672009-03-11 22:21:291964 // request we should be issuing -- the final header line contains a Type
1965 // 1 message.
1966 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1967 "Host: 172.22.68.17\r\n"
1968 "Connection: keep-alive\r\n"
1969 "Authorization: NTLM "
1970 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"),
1971
1972 // After calling trans->RestartWithAuth(), we should send a Type 3 message
1973 // (the credentials for the origin server). The second request continues
1974 // on the same connection.
1975 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
1976 "Host: 172.22.68.17\r\n"
1977 "Connection: keep-alive\r\n"
1978 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA"
1979 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA"
1980 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBO54"
1981 "dFMVvTHwAAAAAAAAAAAAAAAAAAAACS7sT6Uzw7L0L//WUqlIaVWpbI"
1982 "+4MUm7c=\r\n\r\n"),
1983 };
1984
1985 MockRead data_reads3[] = {
1986 // The origin server responds with a Type 2 message.
1987 MockRead("HTTP/1.1 401 Access Denied\r\n"),
1988 MockRead("WWW-Authenticate: NTLM "
1989 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCL24VN8dgOR8AAAAAAAAAALo"
1990 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE"
1991 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA"
1992 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy"
1993 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB"
1994 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw"
1995 "BtAAAAAAA=\r\n"),
1996 MockRead("Content-Length: 42\r\n"),
[email protected]076c85082009-04-10 23:21:361997 MockRead("Content-Type: text/html\r\n\r\n"),
[email protected]385a4672009-03-11 22:21:291998 MockRead("You are not authorized to view this page\r\n"),
1999
2000 // Lastly we get the desired content.
2001 MockRead("HTTP/1.1 200 OK\r\n"),
2002 MockRead("Content-Type: text/html; charset=utf-8\r\n"),
2003 MockRead("Content-Length: 13\r\n\r\n"),
2004 MockRead("Please Login\r\n"),
[email protected]1c773ea12009-04-28 19:58:422005 MockRead(false, OK),
[email protected]385a4672009-03-11 22:21:292006 };
2007
2008 MockSocket data1;
2009 data1.reads = data_reads1;
2010 data1.writes = data_writes1;
2011 MockSocket data2;
2012 data2.reads = data_reads2;
2013 data2.writes = data_writes2;
2014 MockSocket data3;
2015 data3.reads = data_reads3;
2016 data3.writes = data_writes3;
2017 mock_sockets[0] = &data1;
2018 mock_sockets[1] = &data2;
2019 mock_sockets[2] = &data3;
2020 mock_sockets[3] = NULL;
2021
2022 TestCompletionCallback callback1;
2023
2024 int rv = trans->Start(&request, &callback1);
[email protected]1c773ea12009-04-28 19:58:422025 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]385a4672009-03-11 22:21:292026
2027 rv = callback1.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:422028 EXPECT_EQ(OK, rv);
[email protected]385a4672009-03-11 22:21:292029
[email protected]0757e7702009-03-27 04:00:222030 EXPECT_TRUE(trans->IsReadyToRestartForAuth());
[email protected]385a4672009-03-11 22:21:292031 TestCompletionCallback callback2;
[email protected]0757e7702009-03-27 04:00:222032 rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback2);
[email protected]1c773ea12009-04-28 19:58:422033 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]385a4672009-03-11 22:21:292034 rv = callback2.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:422035 EXPECT_EQ(OK, rv);
[email protected]0757e7702009-03-27 04:00:222036 EXPECT_FALSE(trans->IsReadyToRestartForAuth());
[email protected]385a4672009-03-11 22:21:292037
[email protected]1c773ea12009-04-28 19:58:422038 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]385a4672009-03-11 22:21:292039 EXPECT_FALSE(response == NULL);
2040
2041 // The password prompt info should have been set in response->auth_challenge.
2042 EXPECT_FALSE(response->auth_challenge.get() == NULL);
2043
2044 // TODO(eroman): this should really include the effective port (80)
2045 EXPECT_EQ(L"172.22.68.17", response->auth_challenge->host);
2046 EXPECT_EQ(L"", response->auth_challenge->realm);
2047 EXPECT_EQ(L"ntlm", response->auth_challenge->scheme);
2048
2049 TestCompletionCallback callback3;
2050
[email protected]0757e7702009-03-27 04:00:222051 // Enter the wrong password.
2052 rv = trans->RestartWithAuth(L"testing-ntlm", L"wrongpassword", &callback3);
[email protected]1c773ea12009-04-28 19:58:422053 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]385a4672009-03-11 22:21:292054
2055 rv = callback3.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:422056 EXPECT_EQ(OK, rv);
[email protected]385a4672009-03-11 22:21:292057
[email protected]0757e7702009-03-27 04:00:222058 EXPECT_TRUE(trans->IsReadyToRestartForAuth());
2059 TestCompletionCallback callback4;
2060 rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback4);
[email protected]1c773ea12009-04-28 19:58:422061 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]0757e7702009-03-27 04:00:222062 rv = callback4.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:422063 EXPECT_EQ(OK, rv);
[email protected]0757e7702009-03-27 04:00:222064 EXPECT_FALSE(trans->IsReadyToRestartForAuth());
2065
2066 response = trans->GetResponseInfo();
2067 EXPECT_FALSE(response == NULL);
2068
2069 // The password prompt info should have been set in response->auth_challenge.
2070 EXPECT_FALSE(response->auth_challenge.get() == NULL);
2071
2072 // TODO(eroman): this should really include the effective port (80)
2073 EXPECT_EQ(L"172.22.68.17", response->auth_challenge->host);
2074 EXPECT_EQ(L"", response->auth_challenge->realm);
2075 EXPECT_EQ(L"ntlm", response->auth_challenge->scheme);
2076
2077 TestCompletionCallback callback5;
2078
2079 // Now enter the right password.
2080 rv = trans->RestartWithAuth(L"testing-ntlm", L"testing-ntlm", &callback5);
[email protected]1c773ea12009-04-28 19:58:422081 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]0757e7702009-03-27 04:00:222082
2083 rv = callback5.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:422084 EXPECT_EQ(OK, rv);
[email protected]0757e7702009-03-27 04:00:222085
[email protected]385a4672009-03-11 22:21:292086 response = trans->GetResponseInfo();
2087 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2088 EXPECT_EQ(13, response->headers->GetContentLength());
2089}
2090
[email protected]4ddaf2502008-10-23 18:26:192091// Test reading a server response which has only headers, and no body.
2092// After some maximum number of bytes is consumed, the transaction should
2093// fail with ERR_RESPONSE_HEADERS_TOO_BIG.
2094TEST_F(HttpNetworkTransactionTest, LargeHeadersNoBody) {
[email protected]1c773ea12009-04-28 19:58:422095 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
2096 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]db8f44c2008-12-13 04:52:012097 CreateSession(proxy_service.get()), &mock_socket_factory));
[email protected]4ddaf2502008-10-23 18:26:192098
[email protected]1c773ea12009-04-28 19:58:422099 HttpRequestInfo request;
[email protected]4ddaf2502008-10-23 18:26:192100 request.method = "GET";
2101 request.url = GURL("http://www.google.com/");
2102 request.load_flags = 0;
2103
2104 // Respond with 50 kb of headers (we should fail after 32 kb).
[email protected]15a5ccf82008-10-23 19:57:432105 std::string large_headers_string;
2106 FillLargeHeadersString(&large_headers_string, 50 * 1024);
[email protected]4ddaf2502008-10-23 18:26:192107
2108 MockRead data_reads[] = {
2109 MockRead("HTTP/1.0 200 OK\r\n"),
[email protected]15a5ccf82008-10-23 19:57:432110 MockRead(true, large_headers_string.data(), large_headers_string.size()),
[email protected]4ddaf2502008-10-23 18:26:192111 MockRead("\r\nBODY"),
[email protected]1c773ea12009-04-28 19:58:422112 MockRead(false, OK),
[email protected]4ddaf2502008-10-23 18:26:192113 };
2114 MockSocket data;
2115 data.reads = data_reads;
2116 mock_sockets[0] = &data;
2117 mock_sockets[1] = NULL;
2118
2119 TestCompletionCallback callback;
2120
2121 int rv = trans->Start(&request, &callback);
[email protected]1c773ea12009-04-28 19:58:422122 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]4ddaf2502008-10-23 18:26:192123
2124 rv = callback.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:422125 EXPECT_EQ(ERR_RESPONSE_HEADERS_TOO_BIG, rv);
[email protected]4ddaf2502008-10-23 18:26:192126
[email protected]1c773ea12009-04-28 19:58:422127 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]4ddaf2502008-10-23 18:26:192128 EXPECT_TRUE(response == NULL);
2129}
[email protected]f4e426b2008-11-05 00:24:492130
2131// Make sure that we don't try to reuse a TCPClientSocket when failing to
2132// establish tunnel.
2133// http://code.google.com/p/chromium/issues/detail?id=3772
2134TEST_F(HttpNetworkTransactionTest, DontRecycleTCPSocketForSSLTunnel) {
2135 // Configure against proxy server "myproxy:70".
[email protected]1c773ea12009-04-28 19:58:422136 scoped_ptr<ProxyService> proxy_service(
[email protected]51fff29d2008-12-19 22:17:532137 CreateFixedProxyService("myproxy:70"));
[email protected]db8f44c2008-12-13 04:52:012138
[email protected]1c773ea12009-04-28 19:58:422139 scoped_refptr<HttpNetworkSession> session(
[email protected]51fff29d2008-12-19 22:17:532140 CreateSession(proxy_service.get()));
[email protected]f4e426b2008-11-05 00:24:492141
[email protected]1c773ea12009-04-28 19:58:422142 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]f4e426b2008-11-05 00:24:492143 session.get(), &mock_socket_factory));
2144
[email protected]1c773ea12009-04-28 19:58:422145 HttpRequestInfo request;
[email protected]f4e426b2008-11-05 00:24:492146 request.method = "GET";
2147 request.url = GURL("https://www.google.com/");
2148 request.load_flags = 0;
2149
2150 // Since we have proxy, should try to establish tunnel.
2151 MockWrite data_writes1[] = {
2152 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
2153 "Host: www.google.com\r\n\r\n"),
2154 };
2155
[email protected]77848d12008-11-14 00:00:222156 // The proxy responds to the connect with a 404, using a persistent
[email protected]f4e426b2008-11-05 00:24:492157 // connection. Usually a proxy would return 501 (not implemented),
2158 // or 200 (tunnel established).
2159 MockRead data_reads1[] = {
2160 MockRead("HTTP/1.1 404 Not Found\r\n"),
2161 MockRead("Content-Length: 10\r\n\r\n"),
[email protected]1c773ea12009-04-28 19:58:422162 MockRead(false, ERR_UNEXPECTED), // Should not be reached.
[email protected]f4e426b2008-11-05 00:24:492163 };
2164
2165 MockSocket data1;
2166 data1.writes = data_writes1;
2167 data1.reads = data_reads1;
2168 mock_sockets[0] = &data1;
2169 mock_sockets[1] = NULL;
2170
2171 TestCompletionCallback callback1;
2172
2173 int rv = trans->Start(&request, &callback1);
[email protected]1c773ea12009-04-28 19:58:422174 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]f4e426b2008-11-05 00:24:492175
2176 rv = callback1.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:422177 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
[email protected]f4e426b2008-11-05 00:24:492178
[email protected]1c773ea12009-04-28 19:58:422179 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]c744cf22009-02-27 07:28:082180 EXPECT_TRUE(response == NULL);
[email protected]f4e426b2008-11-05 00:24:492181
[email protected]b4404c02009-04-10 16:38:522182 // Empty the current queue. This is necessary because idle sockets are
2183 // added to the connection pool asynchronously with a PostTask.
2184 MessageLoop::current()->RunAllPending();
2185
[email protected]f4e426b2008-11-05 00:24:492186 // We now check to make sure the TCPClientSocket was not added back to
2187 // the pool.
2188 EXPECT_EQ(0, session->connection_pool()->idle_socket_count());
2189 trans.reset();
[email protected]b4404c02009-04-10 16:38:522190 MessageLoop::current()->RunAllPending();
[email protected]f4e426b2008-11-05 00:24:492191 // Make sure that the socket didn't get recycled after calling the destructor.
2192 EXPECT_EQ(0, session->connection_pool()->idle_socket_count());
2193}
[email protected]372d34a2008-11-05 21:30:512194
[email protected]1b157c02009-04-21 01:55:402195// Make sure that we recycle a socket after reading all of the response body.
2196TEST_F(HttpNetworkTransactionTest, RecycleSocket) {
[email protected]1c773ea12009-04-28 19:58:422197 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
2198 scoped_refptr<HttpNetworkSession> session(
[email protected]1b157c02009-04-21 01:55:402199 CreateSession(proxy_service.get()));
2200
[email protected]1c773ea12009-04-28 19:58:422201 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]1b157c02009-04-21 01:55:402202 session.get(), &mock_socket_factory));
2203
[email protected]1c773ea12009-04-28 19:58:422204 HttpRequestInfo request;
[email protected]1b157c02009-04-21 01:55:402205 request.method = "GET";
2206 request.url = GURL("http://www.google.com/");
2207 request.load_flags = 0;
2208
2209 MockRead data_reads[] = {
2210 // A part of the response body is received with the response headers.
2211 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\nhel"),
2212 // The rest of the response body is received in two parts.
2213 MockRead("lo"),
2214 MockRead(" world"),
2215 MockRead("junk"), // Should not be read!!
[email protected]1c773ea12009-04-28 19:58:422216 MockRead(false, OK),
[email protected]1b157c02009-04-21 01:55:402217 };
2218
2219 MockSocket data;
2220 data.reads = data_reads;
2221 mock_sockets[0] = &data;
2222 mock_sockets[1] = NULL;
2223
2224 TestCompletionCallback callback;
2225
2226 int rv = trans->Start(&request, &callback);
[email protected]1c773ea12009-04-28 19:58:422227 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]1b157c02009-04-21 01:55:402228
2229 rv = callback.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:422230 EXPECT_EQ(OK, rv);
[email protected]1b157c02009-04-21 01:55:402231
[email protected]1c773ea12009-04-28 19:58:422232 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]1b157c02009-04-21 01:55:402233 EXPECT_TRUE(response != NULL);
2234
2235 EXPECT_TRUE(response->headers != NULL);
2236 std::string status_line = response->headers->GetStatusLine();
2237 EXPECT_EQ("HTTP/1.1 200 OK", status_line);
2238
2239 EXPECT_EQ(0, session->connection_pool()->idle_socket_count());
2240
2241 std::string response_data;
2242 rv = ReadTransaction(trans.get(), &response_data);
[email protected]1c773ea12009-04-28 19:58:422243 EXPECT_EQ(OK, rv);
[email protected]1b157c02009-04-21 01:55:402244 EXPECT_EQ("hello world", response_data);
2245
2246 // Empty the current queue. This is necessary because idle sockets are
2247 // added to the connection pool asynchronously with a PostTask.
2248 MessageLoop::current()->RunAllPending();
2249
2250 // We now check to make sure the socket was added back to the pool.
2251 EXPECT_EQ(1, session->connection_pool()->idle_socket_count());
2252}
2253
[email protected]b4404c02009-04-10 16:38:522254// Make sure that we recycle a socket after a zero-length response.
2255// http://crbug.com/9880
2256TEST_F(HttpNetworkTransactionTest, RecycleSocketAfterZeroContentLength) {
[email protected]1c773ea12009-04-28 19:58:422257 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
2258 scoped_refptr<HttpNetworkSession> session(
[email protected]b4404c02009-04-10 16:38:522259 CreateSession(proxy_service.get()));
2260
[email protected]1c773ea12009-04-28 19:58:422261 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]b4404c02009-04-10 16:38:522262 session.get(), &mock_socket_factory));
2263
[email protected]1c773ea12009-04-28 19:58:422264 HttpRequestInfo request;
[email protected]b4404c02009-04-10 16:38:522265 request.method = "GET";
2266 request.url = GURL("http://www.google.com/csi?v=3&s=web&action=&"
2267 "tran=undefined&ei=mAXcSeegAo-SMurloeUN&"
2268 "e=17259,18167,19592,19773,19981,20133,20173,20233&"
2269 "rt=prt.2642,ol.2649,xjs.2951");
2270 request.load_flags = 0;
2271
2272 MockRead data_reads[] = {
2273 MockRead("HTTP/1.1 204 No Content\r\n"
2274 "Content-Length: 0\r\n"
2275 "Content-Type: text/html\r\n\r\n"),
2276 MockRead("junk"), // Should not be read!!
[email protected]1c773ea12009-04-28 19:58:422277 MockRead(false, OK),
[email protected]b4404c02009-04-10 16:38:522278 };
2279
2280 MockSocket data;
2281 data.reads = data_reads;
2282 mock_sockets[0] = &data;
2283 mock_sockets[1] = NULL;
2284
2285 TestCompletionCallback callback;
2286
2287 int rv = trans->Start(&request, &callback);
[email protected]1c773ea12009-04-28 19:58:422288 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]b4404c02009-04-10 16:38:522289
2290 rv = callback.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:422291 EXPECT_EQ(OK, rv);
[email protected]b4404c02009-04-10 16:38:522292
[email protected]1c773ea12009-04-28 19:58:422293 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]b4404c02009-04-10 16:38:522294 EXPECT_TRUE(response != NULL);
2295
2296 EXPECT_TRUE(response->headers != NULL);
2297 std::string status_line = response->headers->GetStatusLine();
2298 EXPECT_EQ("HTTP/1.1 204 No Content", status_line);
2299
2300 EXPECT_EQ(0, session->connection_pool()->idle_socket_count());
2301
2302 std::string response_data;
2303 rv = ReadTransaction(trans.get(), &response_data);
[email protected]1c773ea12009-04-28 19:58:422304 EXPECT_EQ(OK, rv);
[email protected]b4404c02009-04-10 16:38:522305 EXPECT_EQ("", response_data);
2306
2307 // Empty the current queue. This is necessary because idle sockets are
2308 // added to the connection pool asynchronously with a PostTask.
2309 MessageLoop::current()->RunAllPending();
2310
2311 // We now check to make sure the socket was added back to the pool.
2312 EXPECT_EQ(1, session->connection_pool()->idle_socket_count());
2313}
2314
[email protected]372d34a2008-11-05 21:30:512315TEST_F(HttpNetworkTransactionTest, ResendRequestOnWriteBodyError) {
[email protected]1c773ea12009-04-28 19:58:422316 HttpRequestInfo request[2];
[email protected]372d34a2008-11-05 21:30:512317 // Transaction 1: a GET request that succeeds. The socket is recycled
2318 // after use.
2319 request[0].method = "GET";
2320 request[0].url = GURL("http://www.google.com/");
2321 request[0].load_flags = 0;
2322 // Transaction 2: a POST request. Reuses the socket kept alive from
2323 // transaction 1. The first attempts fails when writing the POST data.
2324 // This causes the transaction to retry with a new socket. The second
2325 // attempt succeeds.
2326 request[1].method = "POST";
2327 request[1].url = GURL("http://www.google.com/login.cgi");
[email protected]1c773ea12009-04-28 19:58:422328 request[1].upload_data = new UploadData;
[email protected]372d34a2008-11-05 21:30:512329 request[1].upload_data->AppendBytes("foo", 3);
2330 request[1].load_flags = 0;
2331
[email protected]1c773ea12009-04-28 19:58:422332 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
2333 scoped_refptr<HttpNetworkSession> session =
[email protected]db8f44c2008-12-13 04:52:012334 CreateSession(proxy_service.get());
[email protected]372d34a2008-11-05 21:30:512335
2336 // The first socket is used for transaction 1 and the first attempt of
2337 // transaction 2.
2338
2339 // The response of transaction 1.
2340 MockRead data_reads1[] = {
2341 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\n"),
2342 MockRead("hello world"),
[email protected]1c773ea12009-04-28 19:58:422343 MockRead(false, OK),
[email protected]372d34a2008-11-05 21:30:512344 };
2345 // The mock write results of transaction 1 and the first attempt of
2346 // transaction 2.
2347 MockWrite data_writes1[] = {
2348 MockWrite(false, 64), // GET
2349 MockWrite(false, 93), // POST
[email protected]1c773ea12009-04-28 19:58:422350 MockWrite(false, ERR_CONNECTION_ABORTED), // POST data
[email protected]372d34a2008-11-05 21:30:512351 };
2352 MockSocket data1;
2353 data1.reads = data_reads1;
2354 data1.writes = data_writes1;
2355
2356 // The second socket is used for the second attempt of transaction 2.
2357
2358 // The response of transaction 2.
2359 MockRead data_reads2[] = {
2360 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 7\r\n\r\n"),
2361 MockRead("welcome"),
[email protected]1c773ea12009-04-28 19:58:422362 MockRead(false, OK),
[email protected]372d34a2008-11-05 21:30:512363 };
2364 // The mock write results of the second attempt of transaction 2.
2365 MockWrite data_writes2[] = {
2366 MockWrite(false, 93), // POST
2367 MockWrite(false, 3), // POST data
2368 };
2369 MockSocket data2;
2370 data2.reads = data_reads2;
2371 data2.writes = data_writes2;
2372
2373 mock_sockets[0] = &data1;
2374 mock_sockets[1] = &data2;
2375 mock_sockets[2] = NULL;
2376
2377 const char* kExpectedResponseData[] = {
2378 "hello world", "welcome"
2379 };
2380
2381 for (int i = 0; i < 2; ++i) {
[email protected]1c773ea12009-04-28 19:58:422382 scoped_ptr<HttpTransaction> trans(
2383 new HttpNetworkTransaction(session, &mock_socket_factory));
[email protected]372d34a2008-11-05 21:30:512384
2385 TestCompletionCallback callback;
2386
2387 int rv = trans->Start(&request[i], &callback);
[email protected]1c773ea12009-04-28 19:58:422388 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]372d34a2008-11-05 21:30:512389
2390 rv = callback.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:422391 EXPECT_EQ(OK, rv);
[email protected]372d34a2008-11-05 21:30:512392
[email protected]1c773ea12009-04-28 19:58:422393 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]372d34a2008-11-05 21:30:512394 EXPECT_TRUE(response != NULL);
2395
2396 EXPECT_TRUE(response->headers != NULL);
2397 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
2398
2399 std::string response_data;
2400 rv = ReadTransaction(trans.get(), &response_data);
[email protected]1c773ea12009-04-28 19:58:422401 EXPECT_EQ(OK, rv);
[email protected]372d34a2008-11-05 21:30:512402 EXPECT_EQ(kExpectedResponseData[i], response_data);
2403 }
2404}
[email protected]f9ee6b52008-11-08 06:46:232405
2406// Test the request-challenge-retry sequence for basic auth when there is
2407// an identity in the URL. The request should be sent as normal, but when
2408// it fails the identity from the URL is used to answer the challenge.
2409TEST_F(HttpNetworkTransactionTest, AuthIdentityInUrl) {
[email protected]1c773ea12009-04-28 19:58:422410 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
2411 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]db8f44c2008-12-13 04:52:012412 CreateSession(proxy_service.get()), &mock_socket_factory));
[email protected]f9ee6b52008-11-08 06:46:232413
[email protected]1c773ea12009-04-28 19:58:422414 HttpRequestInfo request;
[email protected]f9ee6b52008-11-08 06:46:232415 request.method = "GET";
2416 // Note: the URL has a username:password in it.
2417 request.url = GURL("http://foo:[email protected]/");
2418 request.load_flags = 0;
2419
2420 MockWrite data_writes1[] = {
2421 MockWrite("GET / HTTP/1.1\r\n"
2422 "Host: www.google.com\r\n"
2423 "Connection: keep-alive\r\n\r\n"),
2424 };
2425
2426 MockRead data_reads1[] = {
2427 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
2428 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
2429 MockRead("Content-Length: 10\r\n\r\n"),
[email protected]1c773ea12009-04-28 19:58:422430 MockRead(false, ERR_FAILED),
[email protected]f9ee6b52008-11-08 06:46:232431 };
2432
2433 // After the challenge above, the transaction will be restarted using the
2434 // identity from the url (foo, bar) to answer the challenge.
2435 MockWrite data_writes2[] = {
2436 MockWrite("GET / HTTP/1.1\r\n"
2437 "Host: www.google.com\r\n"
2438 "Connection: keep-alive\r\n"
2439 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
2440 };
2441
2442 MockRead data_reads2[] = {
2443 MockRead("HTTP/1.0 200 OK\r\n"),
2444 MockRead("Content-Length: 100\r\n\r\n"),
[email protected]1c773ea12009-04-28 19:58:422445 MockRead(false, OK),
[email protected]f9ee6b52008-11-08 06:46:232446 };
2447
2448 MockSocket data1;
2449 data1.reads = data_reads1;
2450 data1.writes = data_writes1;
2451 MockSocket data2;
2452 data2.reads = data_reads2;
2453 data2.writes = data_writes2;
2454 mock_sockets[0] = &data1;
2455 mock_sockets[1] = &data2;
2456 mock_sockets[2] = NULL;
2457
2458 TestCompletionCallback callback1;
2459
2460 int rv = trans->Start(&request, &callback1);
[email protected]1c773ea12009-04-28 19:58:422461 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]f9ee6b52008-11-08 06:46:232462
2463 rv = callback1.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:422464 EXPECT_EQ(OK, rv);
[email protected]f9ee6b52008-11-08 06:46:232465
[email protected]0757e7702009-03-27 04:00:222466 EXPECT_TRUE(trans->IsReadyToRestartForAuth());
2467 TestCompletionCallback callback2;
2468 rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback2);
[email protected]1c773ea12009-04-28 19:58:422469 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]0757e7702009-03-27 04:00:222470 rv = callback2.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:422471 EXPECT_EQ(OK, rv);
[email protected]0757e7702009-03-27 04:00:222472 EXPECT_FALSE(trans->IsReadyToRestartForAuth());
2473
[email protected]1c773ea12009-04-28 19:58:422474 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]f9ee6b52008-11-08 06:46:232475 EXPECT_FALSE(response == NULL);
2476
2477 // There is no challenge info, since the identity in URL worked.
2478 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2479
2480 EXPECT_EQ(100, response->headers->GetContentLength());
2481
2482 // Empty the current queue.
2483 MessageLoop::current()->RunAllPending();
2484}
2485
2486// Test that previously tried username/passwords for a realm get re-used.
2487TEST_F(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
[email protected]1c773ea12009-04-28 19:58:422488 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
2489 scoped_refptr<HttpNetworkSession> session =
[email protected]db8f44c2008-12-13 04:52:012490 CreateSession(proxy_service.get());
[email protected]f9ee6b52008-11-08 06:46:232491
2492 // Transaction 1: authenticate (foo, bar) on MyRealm1
2493 {
[email protected]1c773ea12009-04-28 19:58:422494 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]f9ee6b52008-11-08 06:46:232495 session, &mock_socket_factory));
2496
[email protected]1c773ea12009-04-28 19:58:422497 HttpRequestInfo request;
[email protected]f9ee6b52008-11-08 06:46:232498 request.method = "GET";
2499 request.url = GURL("http://www.google.com/x/y/z");
2500 request.load_flags = 0;
2501
2502 MockWrite data_writes1[] = {
2503 MockWrite("GET /x/y/z HTTP/1.1\r\n"
2504 "Host: www.google.com\r\n"
2505 "Connection: keep-alive\r\n\r\n"),
2506 };
2507
2508 MockRead data_reads1[] = {
2509 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
2510 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
2511 MockRead("Content-Length: 10000\r\n\r\n"),
[email protected]1c773ea12009-04-28 19:58:422512 MockRead(false, ERR_FAILED),
[email protected]f9ee6b52008-11-08 06:46:232513 };
2514
2515 // Resend with authorization (username=foo, password=bar)
2516 MockWrite data_writes2[] = {
2517 MockWrite("GET /x/y/z HTTP/1.1\r\n"
2518 "Host: www.google.com\r\n"
2519 "Connection: keep-alive\r\n"
2520 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
2521 };
2522
2523 // Sever accepts the authorization.
2524 MockRead data_reads2[] = {
2525 MockRead("HTTP/1.0 200 OK\r\n"),
2526 MockRead("Content-Length: 100\r\n\r\n"),
[email protected]1c773ea12009-04-28 19:58:422527 MockRead(false, OK),
[email protected]f9ee6b52008-11-08 06:46:232528 };
2529
2530 MockSocket data1;
2531 data1.reads = data_reads1;
2532 data1.writes = data_writes1;
2533 MockSocket data2;
2534 data2.reads = data_reads2;
2535 data2.writes = data_writes2;
2536 mock_sockets_index = 0;
2537 mock_sockets[0] = &data1;
2538 mock_sockets[1] = &data2;
2539 mock_sockets[2] = NULL;
2540
2541 TestCompletionCallback callback1;
2542
2543 int rv = trans->Start(&request, &callback1);
[email protected]1c773ea12009-04-28 19:58:422544 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]f9ee6b52008-11-08 06:46:232545
2546 rv = callback1.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:422547 EXPECT_EQ(OK, rv);
[email protected]f9ee6b52008-11-08 06:46:232548
[email protected]1c773ea12009-04-28 19:58:422549 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]f9ee6b52008-11-08 06:46:232550 EXPECT_FALSE(response == NULL);
2551
2552 // The password prompt info should have been set in
2553 // response->auth_challenge.
2554 EXPECT_FALSE(response->auth_challenge.get() == NULL);
2555
2556 // TODO(eroman): this should really include the effective port (80)
2557 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
2558 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
2559 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
2560
2561 TestCompletionCallback callback2;
2562
2563 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
[email protected]1c773ea12009-04-28 19:58:422564 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]f9ee6b52008-11-08 06:46:232565
2566 rv = callback2.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:422567 EXPECT_EQ(OK, rv);
[email protected]f9ee6b52008-11-08 06:46:232568
2569 response = trans->GetResponseInfo();
2570 EXPECT_FALSE(response == NULL);
2571 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2572 EXPECT_EQ(100, response->headers->GetContentLength());
2573 }
2574
2575 // ------------------------------------------------------------------------
2576
2577 // Transaction 2: authenticate (foo2, bar2) on MyRealm2
2578 {
[email protected]1c773ea12009-04-28 19:58:422579 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]f9ee6b52008-11-08 06:46:232580 session, &mock_socket_factory));
2581
[email protected]1c773ea12009-04-28 19:58:422582 HttpRequestInfo request;
[email protected]f9ee6b52008-11-08 06:46:232583 request.method = "GET";
2584 // Note that Transaction 1 was at /x/y/z, so this is in the same
2585 // protection space as MyRealm1.
2586 request.url = GURL("http://www.google.com/x/y/a/b");
2587 request.load_flags = 0;
2588
2589 MockWrite data_writes1[] = {
2590 MockWrite("GET /x/y/a/b HTTP/1.1\r\n"
2591 "Host: www.google.com\r\n"
2592 "Connection: keep-alive\r\n"
2593 // Send preemptive authorization for MyRealm1
2594 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
2595 };
2596
2597 // The server didn't like the preemptive authorization, and
2598 // challenges us for a different realm (MyRealm2).
2599 MockRead data_reads1[] = {
2600 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
2601 MockRead("WWW-Authenticate: Basic realm=\"MyRealm2\"\r\n"),
2602 MockRead("Content-Length: 10000\r\n\r\n"),
[email protected]1c773ea12009-04-28 19:58:422603 MockRead(false, ERR_FAILED),
[email protected]f9ee6b52008-11-08 06:46:232604 };
2605
2606 // Resend with authorization for MyRealm2 (username=foo2, password=bar2)
2607 MockWrite data_writes2[] = {
2608 MockWrite("GET /x/y/a/b HTTP/1.1\r\n"
2609 "Host: www.google.com\r\n"
2610 "Connection: keep-alive\r\n"
2611 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"),
2612 };
2613
2614 // Sever accepts the authorization.
2615 MockRead data_reads2[] = {
2616 MockRead("HTTP/1.0 200 OK\r\n"),
2617 MockRead("Content-Length: 100\r\n\r\n"),
[email protected]1c773ea12009-04-28 19:58:422618 MockRead(false, OK),
[email protected]f9ee6b52008-11-08 06:46:232619 };
2620
2621 MockSocket data1;
2622 data1.reads = data_reads1;
2623 data1.writes = data_writes1;
2624 MockSocket data2;
2625 data2.reads = data_reads2;
2626 data2.writes = data_writes2;
2627 mock_sockets_index = 0;
2628 mock_sockets[0] = &data1;
2629 mock_sockets[1] = &data2;
2630 mock_sockets[2] = NULL;
2631
2632 TestCompletionCallback callback1;
2633
2634 int rv = trans->Start(&request, &callback1);
[email protected]1c773ea12009-04-28 19:58:422635 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]f9ee6b52008-11-08 06:46:232636
2637 rv = callback1.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:422638 EXPECT_EQ(OK, rv);
[email protected]f9ee6b52008-11-08 06:46:232639
[email protected]1c773ea12009-04-28 19:58:422640 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]f9ee6b52008-11-08 06:46:232641 EXPECT_FALSE(response == NULL);
2642
2643 // The password prompt info should have been set in
2644 // response->auth_challenge.
2645 EXPECT_FALSE(response->auth_challenge.get() == NULL);
2646
2647 // TODO(eroman): this should really include the effective port (80)
2648 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
2649 EXPECT_EQ(L"MyRealm2", response->auth_challenge->realm);
2650 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
2651
2652 TestCompletionCallback callback2;
2653
2654 rv = trans->RestartWithAuth(L"foo2", L"bar2", &callback2);
[email protected]1c773ea12009-04-28 19:58:422655 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]f9ee6b52008-11-08 06:46:232656
2657 rv = callback2.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:422658 EXPECT_EQ(OK, rv);
[email protected]f9ee6b52008-11-08 06:46:232659
2660 response = trans->GetResponseInfo();
2661 EXPECT_FALSE(response == NULL);
2662 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2663 EXPECT_EQ(100, response->headers->GetContentLength());
2664 }
2665
2666 // ------------------------------------------------------------------------
2667
2668 // Transaction 3: Resend a request in MyRealm's protection space --
2669 // succeed with preemptive authorization.
2670 {
[email protected]1c773ea12009-04-28 19:58:422671 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]f9ee6b52008-11-08 06:46:232672 session, &mock_socket_factory));
2673
[email protected]1c773ea12009-04-28 19:58:422674 HttpRequestInfo request;
[email protected]f9ee6b52008-11-08 06:46:232675 request.method = "GET";
2676 request.url = GURL("http://www.google.com/x/y/z2");
2677 request.load_flags = 0;
2678
2679 MockWrite data_writes1[] = {
2680 MockWrite("GET /x/y/z2 HTTP/1.1\r\n"
2681 "Host: www.google.com\r\n"
2682 "Connection: keep-alive\r\n"
2683 // The authorization for MyRealm1 gets sent preemptively
2684 // (since the url is in the same protection space)
2685 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
2686 };
2687
2688 // Sever accepts the preemptive authorization
2689 MockRead data_reads1[] = {
2690 MockRead("HTTP/1.0 200 OK\r\n"),
2691 MockRead("Content-Length: 100\r\n\r\n"),
[email protected]1c773ea12009-04-28 19:58:422692 MockRead(false, OK),
[email protected]f9ee6b52008-11-08 06:46:232693 };
2694
2695 MockSocket data1;
2696 data1.reads = data_reads1;
2697 data1.writes = data_writes1;
2698 mock_sockets_index = 0;
2699 mock_sockets[0] = &data1;
2700 mock_sockets[1] = NULL;
2701
2702 TestCompletionCallback callback1;
2703
2704 int rv = trans->Start(&request, &callback1);
[email protected]1c773ea12009-04-28 19:58:422705 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]f9ee6b52008-11-08 06:46:232706
2707 rv = callback1.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:422708 EXPECT_EQ(OK, rv);
[email protected]f9ee6b52008-11-08 06:46:232709
[email protected]1c773ea12009-04-28 19:58:422710 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]f9ee6b52008-11-08 06:46:232711 EXPECT_FALSE(response == NULL);
2712
2713 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2714 EXPECT_EQ(100, response->headers->GetContentLength());
2715 }
2716
2717 // ------------------------------------------------------------------------
2718
2719 // Transaction 4: request another URL in MyRealm (however the
2720 // url is not known to belong to the protection space, so no pre-auth).
2721 {
[email protected]1c773ea12009-04-28 19:58:422722 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]f9ee6b52008-11-08 06:46:232723 session, &mock_socket_factory));
2724
[email protected]1c773ea12009-04-28 19:58:422725 HttpRequestInfo request;
[email protected]f9ee6b52008-11-08 06:46:232726 request.method = "GET";
2727 request.url = GURL("http://www.google.com/x/1");
2728 request.load_flags = 0;
2729
2730 MockWrite data_writes1[] = {
2731 MockWrite("GET /x/1 HTTP/1.1\r\n"
2732 "Host: www.google.com\r\n"
2733 "Connection: keep-alive\r\n\r\n"),
2734 };
2735
2736 MockRead data_reads1[] = {
2737 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
2738 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
2739 MockRead("Content-Length: 10000\r\n\r\n"),
[email protected]1c773ea12009-04-28 19:58:422740 MockRead(false, ERR_FAILED),
[email protected]f9ee6b52008-11-08 06:46:232741 };
2742
2743 // Resend with authorization from MyRealm's cache.
2744 MockWrite data_writes2[] = {
2745 MockWrite("GET /x/1 HTTP/1.1\r\n"
2746 "Host: www.google.com\r\n"
2747 "Connection: keep-alive\r\n"
2748 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
2749 };
2750
2751 // Sever accepts the authorization.
2752 MockRead data_reads2[] = {
2753 MockRead("HTTP/1.0 200 OK\r\n"),
2754 MockRead("Content-Length: 100\r\n\r\n"),
[email protected]1c773ea12009-04-28 19:58:422755 MockRead(false, OK),
[email protected]f9ee6b52008-11-08 06:46:232756 };
2757
2758 MockSocket data1;
2759 data1.reads = data_reads1;
2760 data1.writes = data_writes1;
2761 MockSocket data2;
2762 data2.reads = data_reads2;
2763 data2.writes = data_writes2;
2764 mock_sockets_index = 0;
2765 mock_sockets[0] = &data1;
2766 mock_sockets[1] = &data2;
2767 mock_sockets[2] = NULL;
2768
2769 TestCompletionCallback callback1;
2770
2771 int rv = trans->Start(&request, &callback1);
[email protected]1c773ea12009-04-28 19:58:422772 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]f9ee6b52008-11-08 06:46:232773
2774 rv = callback1.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:422775 EXPECT_EQ(OK, rv);
[email protected]f9ee6b52008-11-08 06:46:232776
[email protected]0757e7702009-03-27 04:00:222777 EXPECT_TRUE(trans->IsReadyToRestartForAuth());
2778 TestCompletionCallback callback2;
2779 rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback2);
[email protected]1c773ea12009-04-28 19:58:422780 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]0757e7702009-03-27 04:00:222781 rv = callback2.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:422782 EXPECT_EQ(OK, rv);
[email protected]0757e7702009-03-27 04:00:222783 EXPECT_FALSE(trans->IsReadyToRestartForAuth());
2784
[email protected]1c773ea12009-04-28 19:58:422785 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]f9ee6b52008-11-08 06:46:232786 EXPECT_FALSE(response == NULL);
2787 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2788 EXPECT_EQ(100, response->headers->GetContentLength());
2789 }
2790
2791 // ------------------------------------------------------------------------
2792
2793 // Transaction 5: request a URL in MyRealm, but the server rejects the
2794 // cached identity. Should invalidate and re-prompt.
2795 {
[email protected]1c773ea12009-04-28 19:58:422796 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
[email protected]f9ee6b52008-11-08 06:46:232797 session, &mock_socket_factory));
2798
[email protected]1c773ea12009-04-28 19:58:422799 HttpRequestInfo request;
[email protected]f9ee6b52008-11-08 06:46:232800 request.method = "GET";
2801 request.url = GURL("http://www.google.com/p/q/t");
2802 request.load_flags = 0;
2803
2804 MockWrite data_writes1[] = {
2805 MockWrite("GET /p/q/t HTTP/1.1\r\n"
2806 "Host: www.google.com\r\n"
2807 "Connection: keep-alive\r\n\r\n"),
2808 };
2809
2810 MockRead data_reads1[] = {
2811 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
2812 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
2813 MockRead("Content-Length: 10000\r\n\r\n"),
[email protected]1c773ea12009-04-28 19:58:422814 MockRead(false, ERR_FAILED),
[email protected]f9ee6b52008-11-08 06:46:232815 };
2816
2817 // Resend with authorization from cache for MyRealm.
2818 MockWrite data_writes2[] = {
2819 MockWrite("GET /p/q/t HTTP/1.1\r\n"
2820 "Host: www.google.com\r\n"
2821 "Connection: keep-alive\r\n"
2822 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
2823 };
2824
2825 // Sever rejects the authorization.
2826 MockRead data_reads2[] = {
2827 MockRead("HTTP/1.0 401 Unauthorized\r\n"),
2828 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
2829 MockRead("Content-Length: 10000\r\n\r\n"),
[email protected]1c773ea12009-04-28 19:58:422830 MockRead(false, ERR_FAILED),
[email protected]f9ee6b52008-11-08 06:46:232831 };
2832
2833 // At this point we should prompt for new credentials for MyRealm.
2834 // Restart with username=foo3, password=foo4.
2835 MockWrite data_writes3[] = {
2836 MockWrite("GET /p/q/t HTTP/1.1\r\n"
2837 "Host: www.google.com\r\n"
2838 "Connection: keep-alive\r\n"
2839 "Authorization: Basic Zm9vMzpiYXIz\r\n\r\n"),
2840 };
2841
2842 // Sever accepts the authorization.
2843 MockRead data_reads3[] = {
2844 MockRead("HTTP/1.0 200 OK\r\n"),
2845 MockRead("Content-Length: 100\r\n\r\n"),
[email protected]1c773ea12009-04-28 19:58:422846 MockRead(false, OK),
[email protected]f9ee6b52008-11-08 06:46:232847 };
2848
2849 MockSocket data1;
2850 data1.reads = data_reads1;
2851 data1.writes = data_writes1;
2852 MockSocket data2;
2853 data2.reads = data_reads2;
2854 data2.writes = data_writes2;
2855 MockSocket data3;
2856 data3.reads = data_reads3;
2857 data3.writes = data_writes3;
2858 mock_sockets_index = 0;
2859 mock_sockets[0] = &data1;
2860 mock_sockets[1] = &data2;
2861 mock_sockets[2] = &data3;
2862 mock_sockets[3] = NULL;
2863
2864 TestCompletionCallback callback1;
2865
2866 int rv = trans->Start(&request, &callback1);
[email protected]1c773ea12009-04-28 19:58:422867 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]f9ee6b52008-11-08 06:46:232868
2869 rv = callback1.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:422870 EXPECT_EQ(OK, rv);
[email protected]f9ee6b52008-11-08 06:46:232871
[email protected]0757e7702009-03-27 04:00:222872 EXPECT_TRUE(trans->IsReadyToRestartForAuth());
2873 TestCompletionCallback callback2;
2874 rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback2);
[email protected]1c773ea12009-04-28 19:58:422875 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]0757e7702009-03-27 04:00:222876 rv = callback2.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:422877 EXPECT_EQ(OK, rv);
[email protected]0757e7702009-03-27 04:00:222878 EXPECT_FALSE(trans->IsReadyToRestartForAuth());
2879
[email protected]1c773ea12009-04-28 19:58:422880 const HttpResponseInfo* response = trans->GetResponseInfo();
[email protected]f9ee6b52008-11-08 06:46:232881 EXPECT_FALSE(response == NULL);
2882
2883 // The password prompt info should have been set in
2884 // response->auth_challenge.
2885 EXPECT_FALSE(response->auth_challenge.get() == NULL);
2886
2887 // TODO(eroman): this should really include the effective port (80)
2888 EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
2889 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
2890 EXPECT_EQ(L"basic", response->auth_challenge->scheme);
2891
[email protected]0757e7702009-03-27 04:00:222892 TestCompletionCallback callback3;
[email protected]f9ee6b52008-11-08 06:46:232893
[email protected]0757e7702009-03-27 04:00:222894 rv = trans->RestartWithAuth(L"foo3", L"bar3", &callback3);
[email protected]1c773ea12009-04-28 19:58:422895 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]f9ee6b52008-11-08 06:46:232896
[email protected]0757e7702009-03-27 04:00:222897 rv = callback3.WaitForResult();
[email protected]1c773ea12009-04-28 19:58:422898 EXPECT_EQ(OK, rv);
[email protected]f9ee6b52008-11-08 06:46:232899
2900 response = trans->GetResponseInfo();
2901 EXPECT_FALSE(response == NULL);
2902 EXPECT_TRUE(response->auth_challenge.get() == NULL);
2903 EXPECT_EQ(100, response->headers->GetContentLength());
2904 }
2905}
[email protected]89ceba9a2009-03-21 03:46:062906
2907// Test the ResetStateForRestart() private method.
2908TEST_F(HttpNetworkTransactionTest, ResetStateForRestart) {
2909 // Create a transaction (the dependencies aren't important).
2910 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
2911 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(
2912 CreateSession(proxy_service.get()), &mock_socket_factory));
2913
2914 // Setup some state (which we expect ResetStateForRestart() will clear).
2915 trans->header_buf_.reset(static_cast<char*>(malloc(10)));
2916 trans->header_buf_capacity_ = 10;
2917 trans->header_buf_len_ = 3;
2918 trans->header_buf_body_offset_ = 11;
2919 trans->header_buf_http_offset_ = 0;
2920 trans->response_body_length_ = 100;
2921 trans->response_body_read_ = 1;
2922 trans->read_buf_ = new IOBuffer(15);
2923 trans->read_buf_len_ = 15;
2924 trans->request_headers_ = "Authorization: NTLM";
2925 trans->request_headers_bytes_sent_ = 3;
2926
2927 // Setup state in response_
2928 trans->response_.auth_challenge = new AuthChallengeInfo();
2929 trans->response_.ssl_info.cert_status = -15;
2930 trans->response_.response_time = base::Time::Now();
[email protected]b4404c02009-04-10 16:38:522931 trans->response_.was_cached = true; // (Wouldn't ever actually be true...)
[email protected]89ceba9a2009-03-21 03:46:062932
2933 { // Setup state for response_.vary_data
2934 HttpRequestInfo request;
2935 std::string temp("HTTP/1.1 200 OK\nVary: foo, bar\n\n");
2936 std::replace(temp.begin(), temp.end(), '\n', '\0');
2937 scoped_refptr<HttpResponseHeaders> response = new HttpResponseHeaders(temp);
2938 request.extra_headers = "Foo: 1\nbar: 23";
2939 EXPECT_TRUE(trans->response_.vary_data.Init(request, *response));
2940 }
2941
2942 // Cause the above state to be reset.
2943 trans->ResetStateForRestart();
2944
2945 // Verify that the state that needed to be reset, has been reset.
2946 EXPECT_EQ(NULL, trans->header_buf_.get());
2947 EXPECT_EQ(0, trans->header_buf_capacity_);
2948 EXPECT_EQ(0, trans->header_buf_len_);
2949 EXPECT_EQ(-1, trans->header_buf_body_offset_);
2950 EXPECT_EQ(-1, trans->header_buf_http_offset_);
2951 EXPECT_EQ(-1, trans->response_body_length_);
2952 EXPECT_EQ(0, trans->response_body_read_);
2953 EXPECT_EQ(NULL, trans->read_buf_.get());
2954 EXPECT_EQ(0, trans->read_buf_len_);
2955 EXPECT_EQ("", trans->request_headers_);
2956 EXPECT_EQ(0U, trans->request_headers_bytes_sent_);
2957 EXPECT_EQ(NULL, trans->response_.auth_challenge.get());
2958 EXPECT_EQ(NULL, trans->response_.headers.get());
2959 EXPECT_EQ(false, trans->response_.was_cached);
2960 EXPECT_EQ(base::kInvalidPlatformFileValue,
2961 trans->response_.response_data_file);
2962 EXPECT_EQ(0, trans->response_.ssl_info.cert_status);
2963 EXPECT_FALSE(trans->response_.vary_data.is_valid());
2964}
2965
[email protected]bacff652009-03-31 17:50:332966// Test HTTPS connections to a site with a bad certificate
2967TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificate) {
2968 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
2969 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
2970 CreateSession(proxy_service.get()), &mock_socket_factory));
2971
2972 HttpRequestInfo request;
2973 request.method = "GET";
2974 request.url = GURL("https://www.google.com/");
2975 request.load_flags = 0;
2976
2977 MockWrite data_writes[] = {
2978 MockWrite("GET / HTTP/1.1\r\n"
2979 "Host: www.google.com\r\n"
2980 "Connection: keep-alive\r\n\r\n"),
2981 };
2982
2983 MockRead data_reads[] = {
2984 MockRead("HTTP/1.0 200 OK\r\n"),
2985 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
2986 MockRead("Content-Length: 100\r\n\r\n"),
2987 MockRead(false, OK),
2988 };
2989
2990 MockSocket ssl_bad_certificate;
2991 MockSocket data(data_reads, data_writes);
2992 MockSSLSocket ssl_bad(true, ERR_CERT_AUTHORITY_INVALID);
2993 MockSSLSocket ssl(true, OK);
2994
2995 mock_sockets[0] = &ssl_bad_certificate;
2996 mock_sockets[1] = &data;
2997 mock_sockets[2] = NULL;
2998
2999 mock_ssl_sockets[0] = &ssl_bad;
3000 mock_ssl_sockets[1] = &ssl;
3001 mock_ssl_sockets[2] = NULL;
3002
3003 TestCompletionCallback callback;
3004
3005 int rv = trans->Start(&request, &callback);
3006 EXPECT_EQ(ERR_IO_PENDING, rv);
3007
3008 rv = callback.WaitForResult();
3009 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv);
3010
3011 rv = trans->RestartIgnoringLastError(&callback);
3012 EXPECT_EQ(ERR_IO_PENDING, rv);
3013
3014 rv = callback.WaitForResult();
3015 EXPECT_EQ(OK, rv);
3016
3017 const HttpResponseInfo* response = trans->GetResponseInfo();
3018
3019 EXPECT_FALSE(response == NULL);
3020 EXPECT_EQ(100, response->headers->GetContentLength());
3021}
3022
3023// Test HTTPS connections to a site with a bad certificate, going through a
3024// proxy
3025TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificateViaProxy) {
3026 scoped_ptr<ProxyService> proxy_service(
3027 CreateFixedProxyService("myproxy:70"));
3028
3029 HttpRequestInfo request;
3030 request.method = "GET";
3031 request.url = GURL("https://www.google.com/");
3032 request.load_flags = 0;
3033
3034 MockWrite proxy_writes[] = {
3035 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
3036 "Host: www.google.com\r\n\r\n"),
3037 };
3038
3039 MockRead proxy_reads[] = {
3040 MockRead("HTTP/1.0 200 Connected\r\n\r\n"),
[email protected]1c773ea12009-04-28 19:58:423041 MockRead(false, OK)
[email protected]bacff652009-03-31 17:50:333042 };
3043
3044 MockWrite data_writes[] = {
3045 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
3046 "Host: www.google.com\r\n\r\n"),
3047 MockWrite("GET / HTTP/1.1\r\n"
3048 "Host: www.google.com\r\n"
3049 "Connection: keep-alive\r\n\r\n"),
3050 };
3051
3052 MockRead data_reads[] = {
3053 MockRead("HTTP/1.0 200 Connected\r\n\r\n"),
3054 MockRead("HTTP/1.0 200 OK\r\n"),
3055 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
3056 MockRead("Content-Length: 100\r\n\r\n"),
3057 MockRead(false, OK),
3058 };
3059
3060 MockSocket ssl_bad_certificate(proxy_reads, proxy_writes);
3061 MockSocket data(data_reads, data_writes);
3062 MockSSLSocket ssl_bad(true, ERR_CERT_AUTHORITY_INVALID);
3063 MockSSLSocket ssl(true, OK);
3064
3065 mock_sockets[0] = &ssl_bad_certificate;
3066 mock_sockets[1] = &data;
3067 mock_sockets[2] = NULL;
3068
3069 mock_ssl_sockets[0] = &ssl_bad;
3070 mock_ssl_sockets[1] = &ssl;
3071 mock_ssl_sockets[2] = NULL;
3072
3073 TestCompletionCallback callback;
3074
3075 for (int i = 0; i < 2; i++) {
3076 mock_sockets_index = 0;
3077 mock_ssl_sockets_index = 0;
3078
3079 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
3080 CreateSession(proxy_service.get()), &mock_socket_factory));
3081
3082 int rv = trans->Start(&request, &callback);
3083 EXPECT_EQ(ERR_IO_PENDING, rv);
3084
3085 rv = callback.WaitForResult();
3086 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv);
3087
3088 rv = trans->RestartIgnoringLastError(&callback);
3089 EXPECT_EQ(ERR_IO_PENDING, rv);
3090
3091 rv = callback.WaitForResult();
3092 EXPECT_EQ(OK, rv);
3093
3094 const HttpResponseInfo* response = trans->GetResponseInfo();
3095
3096 EXPECT_FALSE(response == NULL);
3097 EXPECT_EQ(100, response->headers->GetContentLength());
3098 }
3099}
3100
[email protected]1c773ea12009-04-28 19:58:423101TEST_F(HttpNetworkTransactionTest, BuildRequest_UserAgent) {
3102 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
3103 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
3104 CreateSession(proxy_service.get()), &mock_socket_factory));
3105
3106 HttpRequestInfo request;
3107 request.method = "GET";
3108 request.url = GURL("http://www.google.com/");
3109 request.user_agent = "Chromium Ultra Awesome X Edition";
3110
3111 MockWrite data_writes[] = {
3112 MockWrite("GET / HTTP/1.1\r\n"
3113 "Host: www.google.com\r\n"
3114 "Connection: keep-alive\r\n"
3115 "User-Agent: Chromium Ultra Awesome X Edition\r\n\r\n"),
3116 };
3117
3118 // Lastly, the server responds with the actual content.
3119 MockRead data_reads[] = {
3120 MockRead("HTTP/1.0 200 OK\r\n"),
3121 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
3122 MockRead("Content-Length: 100\r\n\r\n"),
3123 MockRead(false, OK),
3124 };
3125
3126 MockSocket data;
3127 data.reads = data_reads;
3128 data.writes = data_writes;
3129 mock_sockets[0] = &data;
3130 mock_sockets[1] = NULL;
3131
3132 TestCompletionCallback callback;
3133
3134 int rv = trans->Start(&request, &callback);
3135 EXPECT_EQ(ERR_IO_PENDING, rv);
3136
3137 rv = callback.WaitForResult();
3138 EXPECT_EQ(OK, rv);
3139}
3140
3141TEST_F(HttpNetworkTransactionTest, BuildRequest_Referer) {
3142 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
3143 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
3144 CreateSession(proxy_service.get()), &mock_socket_factory));
3145
3146 HttpRequestInfo request;
3147 request.method = "GET";
3148 request.url = GURL("http://www.google.com/");
3149 request.load_flags = 0;
3150 request.referrer = GURL("http://the.previous.site.com/");
3151
3152 MockWrite data_writes[] = {
3153 MockWrite("GET / HTTP/1.1\r\n"
3154 "Host: www.google.com\r\n"
3155 "Connection: keep-alive\r\n"
3156 "Referer: http://the.previous.site.com/\r\n\r\n"),
3157 };
3158
3159 // Lastly, the server responds with the actual content.
3160 MockRead data_reads[] = {
3161 MockRead("HTTP/1.0 200 OK\r\n"),
3162 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
3163 MockRead("Content-Length: 100\r\n\r\n"),
3164 MockRead(false, OK),
3165 };
3166
3167 MockSocket data;
3168 data.reads = data_reads;
3169 data.writes = data_writes;
3170 mock_sockets[0] = &data;
3171 mock_sockets[1] = NULL;
3172
3173 TestCompletionCallback callback;
3174
3175 int rv = trans->Start(&request, &callback);
3176 EXPECT_EQ(ERR_IO_PENDING, rv);
3177
3178 rv = callback.WaitForResult();
3179 EXPECT_EQ(OK, rv);
3180}
3181
3182TEST_F(HttpNetworkTransactionTest, BuildRequest_PostContentLengthZero) {
3183 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
3184 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
3185 CreateSession(proxy_service.get()), &mock_socket_factory));
3186
3187 HttpRequestInfo request;
3188 request.method = "POST";
3189 request.url = GURL("http://www.google.com/");
3190
3191 MockWrite data_writes[] = {
3192 MockWrite("POST / HTTP/1.1\r\n"
3193 "Host: www.google.com\r\n"
3194 "Connection: keep-alive\r\n"
3195 "Content-Length: 0\r\n\r\n"),
3196 };
3197
3198 // Lastly, the server responds with the actual content.
3199 MockRead data_reads[] = {
3200 MockRead("HTTP/1.0 200 OK\r\n"),
3201 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
3202 MockRead("Content-Length: 100\r\n\r\n"),
3203 MockRead(false, OK),
3204 };
3205
3206 MockSocket data;
3207 data.reads = data_reads;
3208 data.writes = data_writes;
3209 mock_sockets[0] = &data;
3210 mock_sockets[1] = NULL;
3211
3212 TestCompletionCallback callback;
3213
3214 int rv = trans->Start(&request, &callback);
3215 EXPECT_EQ(ERR_IO_PENDING, rv);
3216
3217 rv = callback.WaitForResult();
3218 EXPECT_EQ(OK, rv);
3219}
3220
3221TEST_F(HttpNetworkTransactionTest, BuildRequest_PutContentLengthZero) {
3222 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
3223 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
3224 CreateSession(proxy_service.get()), &mock_socket_factory));
3225
3226 HttpRequestInfo request;
3227 request.method = "PUT";
3228 request.url = GURL("http://www.google.com/");
3229
3230 MockWrite data_writes[] = {
3231 MockWrite("PUT / HTTP/1.1\r\n"
3232 "Host: www.google.com\r\n"
3233 "Connection: keep-alive\r\n"
3234 "Content-Length: 0\r\n\r\n"),
3235 };
3236
3237 // Lastly, the server responds with the actual content.
3238 MockRead data_reads[] = {
3239 MockRead("HTTP/1.0 200 OK\r\n"),
3240 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
3241 MockRead("Content-Length: 100\r\n\r\n"),
3242 MockRead(false, OK),
3243 };
3244
3245 MockSocket data;
3246 data.reads = data_reads;
3247 data.writes = data_writes;
3248 mock_sockets[0] = &data;
3249 mock_sockets[1] = NULL;
3250
3251 TestCompletionCallback callback;
3252
3253 int rv = trans->Start(&request, &callback);
3254 EXPECT_EQ(ERR_IO_PENDING, rv);
3255
3256 rv = callback.WaitForResult();
3257 EXPECT_EQ(OK, rv);
3258}
3259
3260TEST_F(HttpNetworkTransactionTest, BuildRequest_HeadContentLengthZero) {
3261 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
3262 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
3263 CreateSession(proxy_service.get()), &mock_socket_factory));
3264
3265 HttpRequestInfo request;
3266 request.method = "HEAD";
3267 request.url = GURL("http://www.google.com/");
3268
3269 MockWrite data_writes[] = {
3270 MockWrite("HEAD / HTTP/1.1\r\n"
3271 "Host: www.google.com\r\n"
3272 "Connection: keep-alive\r\n"
3273 "Content-Length: 0\r\n\r\n"),
3274 };
3275
3276 // Lastly, the server responds with the actual content.
3277 MockRead data_reads[] = {
3278 MockRead("HTTP/1.0 200 OK\r\n"),
3279 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
3280 MockRead("Content-Length: 100\r\n\r\n"),
3281 MockRead(false, OK),
3282 };
3283
3284 MockSocket data;
3285 data.reads = data_reads;
3286 data.writes = data_writes;
3287 mock_sockets[0] = &data;
3288 mock_sockets[1] = NULL;
3289
3290 TestCompletionCallback callback;
3291
3292 int rv = trans->Start(&request, &callback);
3293 EXPECT_EQ(ERR_IO_PENDING, rv);
3294
3295 rv = callback.WaitForResult();
3296 EXPECT_EQ(OK, rv);
3297}
3298
3299TEST_F(HttpNetworkTransactionTest, BuildRequest_CacheControlNoCache) {
3300 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
3301 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
3302 CreateSession(proxy_service.get()), &mock_socket_factory));
3303
3304 HttpRequestInfo request;
3305 request.method = "GET";
3306 request.url = GURL("http://www.google.com/");
3307 request.load_flags = LOAD_BYPASS_CACHE;
3308
3309 MockWrite data_writes[] = {
3310 MockWrite("GET / HTTP/1.1\r\n"
3311 "Host: www.google.com\r\n"
3312 "Connection: keep-alive\r\n"
3313 "Pragma: no-cache\r\n"
3314 "Cache-Control: no-cache\r\n\r\n"),
3315 };
3316
3317 // Lastly, the server responds with the actual content.
3318 MockRead data_reads[] = {
3319 MockRead("HTTP/1.0 200 OK\r\n"),
3320 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
3321 MockRead("Content-Length: 100\r\n\r\n"),
3322 MockRead(false, OK),
3323 };
3324
3325 MockSocket data;
3326 data.reads = data_reads;
3327 data.writes = data_writes;
3328 mock_sockets[0] = &data;
3329 mock_sockets[1] = NULL;
3330
3331 TestCompletionCallback callback;
3332
3333 int rv = trans->Start(&request, &callback);
3334 EXPECT_EQ(ERR_IO_PENDING, rv);
3335
3336 rv = callback.WaitForResult();
3337 EXPECT_EQ(OK, rv);
3338}
3339
3340TEST_F(HttpNetworkTransactionTest,
3341 BuildRequest_CacheControlValidateCache) {
3342 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
3343 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
3344 CreateSession(proxy_service.get()), &mock_socket_factory));
3345
3346 HttpRequestInfo request;
3347 request.method = "GET";
3348 request.url = GURL("http://www.google.com/");
3349 request.load_flags = LOAD_VALIDATE_CACHE;
3350
3351 MockWrite data_writes[] = {
3352 MockWrite("GET / HTTP/1.1\r\n"
3353 "Host: www.google.com\r\n"
3354 "Connection: keep-alive\r\n"
3355 "Cache-Control: max-age=0\r\n\r\n"),
3356 };
3357
3358 // Lastly, the server responds with the actual content.
3359 MockRead data_reads[] = {
3360 MockRead("HTTP/1.0 200 OK\r\n"),
3361 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
3362 MockRead("Content-Length: 100\r\n\r\n"),
3363 MockRead(false, OK),
3364 };
3365
3366 MockSocket data;
3367 data.reads = data_reads;
3368 data.writes = data_writes;
3369 mock_sockets[0] = &data;
3370 mock_sockets[1] = NULL;
3371
3372 TestCompletionCallback callback;
3373
3374 int rv = trans->Start(&request, &callback);
3375 EXPECT_EQ(ERR_IO_PENDING, rv);
3376
3377 rv = callback.WaitForResult();
3378 EXPECT_EQ(OK, rv);
3379}
3380
3381TEST_F(HttpNetworkTransactionTest, BuildRequest_ExtraHeaders) {
3382 scoped_ptr<ProxyService> proxy_service(CreateNullProxyService());
3383 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
3384 CreateSession(proxy_service.get()), &mock_socket_factory));
3385
3386 HttpRequestInfo request;
3387 request.method = "GET";
3388 request.url = GURL("http://www.google.com/");
3389 request.extra_headers = "FooHeader: Bar\r\n";
3390
3391 MockWrite data_writes[] = {
3392 MockWrite("GET / HTTP/1.1\r\n"
3393 "Host: www.google.com\r\n"
3394 "Connection: keep-alive\r\n"
3395 "FooHeader: Bar\r\n\r\n"),
3396 };
3397
3398 // Lastly, the server responds with the actual content.
3399 MockRead data_reads[] = {
3400 MockRead("HTTP/1.0 200 OK\r\n"),
3401 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
3402 MockRead("Content-Length: 100\r\n\r\n"),
3403 MockRead(false, OK),
3404 };
3405
3406 MockSocket data;
3407 data.reads = data_reads;
3408 data.writes = data_writes;
3409 mock_sockets[0] = &data;
3410 mock_sockets[1] = NULL;
3411
3412 TestCompletionCallback callback;
3413
3414 int rv = trans->Start(&request, &callback);
3415 EXPECT_EQ(ERR_IO_PENDING, rv);
3416
3417 rv = callback.WaitForResult();
3418 EXPECT_EQ(OK, rv);
3419}
3420
[email protected]89ceba9a2009-03-21 03:46:063421} // namespace net