blob: d814dfe44aeb10c4b13d7553a77f2c2323d0ef90 [file] [log] [blame]
Paul Stewart58a577b2012-01-10 11:18:52 -08001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Paul Stewartf65320c2011-10-13 14:34:52 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/http_proxy.h"
6
7#include <netinet/in.h>
8
9#include <string>
10#include <vector>
11
12#include <base/stringprintf.h>
13#include <gtest/gtest.h>
14
15#include "shill/ip_address.h"
16#include "shill/mock_async_connection.h"
Paul Stewartc8f4bef2011-12-13 09:45:51 -080017#include "shill/mock_connection.h"
18#include "shill/mock_control.h"
19#include "shill/mock_device_info.h"
Paul Stewartf65320c2011-10-13 14:34:52 -070020#include "shill/mock_dns_client.h"
21#include "shill/mock_event_dispatcher.h"
22#include "shill/mock_sockets.h"
23
24using base::StringPrintf;
25using std::string;
26using std::vector;
27using ::testing::_;
28using ::testing::AtLeast;
29using ::testing::DoAll;
30using ::testing::Invoke;
Paul Stewartc8f4bef2011-12-13 09:45:51 -080031using ::testing::NiceMock;
Paul Stewartf65320c2011-10-13 14:34:52 -070032using ::testing::Return;
33using ::testing::ReturnArg;
34using ::testing::ReturnNew;
35using ::testing::ReturnRef;
36using ::testing::SetArgumentPointee;
37using ::testing::StrEq;
38using ::testing::StrictMock;
39using ::testing::Test;
40
41namespace shill {
42
43namespace {
Paul Stewart58a577b2012-01-10 11:18:52 -080044const char kBadHeaderMissingURL[] = "BLAH\r\n";
45const char kBadHeaderMissingVersion[] = "BLAH http://hostname\r\n";
Paul Stewartf65320c2011-10-13 14:34:52 -070046const char kBadHostnameLine[] = "GET HTTP/1.1 http://hostname\r\n";
47const char kBasicGetHeader[] = "GET / HTTP/1.1\r\n";
48const char kBasicGetHeaderWithURL[] =
49 "GET http://www.chromium.org/ HTTP/1.1\r\n";
50const char kBasicGetHeaderWithURLNoTrailingSlash[] =
51 "GET http://www.chromium.org HTTP/1.1\r\n";
Paul Stewart58a577b2012-01-10 11:18:52 -080052const char kConnectQuery[] =
53 "CONNECT 10.10.10.10:443 HTTP/1.1\r\n"
54 "Host: 10.10.10.10:443\r\n\r\n";
Paul Stewartf65320c2011-10-13 14:34:52 -070055const char kQueryTemplate[] = "GET %s HTTP/%s\r\n%s"
56 "User-Agent: Mozilla/5.0 (X11; CrOS i686 1299.0.2011) "
57 "AppleWebKit/535.8 (KHTML, like Gecko) Chrome/17.0.936.0 Safari/535.8\r\n"
58 "Accept: text/html,application/xhtml+xml,application/xml;"
59 "q=0.9,*/*;q=0.8\r\n"
60 "Accept-Encoding: gzip,deflate,sdch\r\n"
61 "Accept-Language: en-US,en;q=0.8,ja;q=0.6\r\n"
62 "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n"
63 "Cookie: PREF=ID=xxxxxxxxxxxxxxxx:U=xxxxxxxxxxxxxxxx:FF=0:"
64 "TM=1317340083:LM=1317390705:GM=1:S=_xxxxxxxxxxxxxxx; "
65 "NID=52=xxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
66 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxx; "
67 "HSID=xxxxxxxxxxxx-xxxx; APISID=xxxxxxxxxxxxxxxx/xxxxxxxxxxxxxxxxx; "
68 "SID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_xxxxxxxxxxx"
69 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxx"
70 "xxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxx"
71 "_xxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxx-xx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
72 "xxxxxxxxxxxxxxxx\r\n\r\n";
73const char kInterfaceName[] = "int0";
74const char kDNSServer0[] = "8.8.8.8";
75const char kDNSServer1[] = "8.8.4.4";
76const char kServerAddress[] = "10.10.10.10";
77const char *kDNSServers[] = { kDNSServer0, kDNSServer1 };
78const int kProxyFD = 10203;
79const int kServerFD = 10204;
80const int kClientFD = 10205;
81const int kServerPort = 40506;
Paul Stewart58a577b2012-01-10 11:18:52 -080082const int kConnectPort = 443;
Paul Stewartf65320c2011-10-13 14:34:52 -070083} // namespace {}
84
85MATCHER_P(IsIPAddress, address, "") {
86 IPAddress ip_address(IPAddress::kFamilyIPv4);
87 EXPECT_TRUE(ip_address.SetAddressFromString(address));
88 return ip_address.Equals(arg);
89}
90
Eric Shienbrood3e20a232012-02-16 11:35:56 -050091MATCHER_P(CallbackEq, callback, "") {
92 return arg.Equals(callback);
93}
94
Paul Stewartf65320c2011-10-13 14:34:52 -070095class HTTPProxyTest : public Test {
96 public:
97 HTTPProxyTest()
Paul Stewartc8f4bef2011-12-13 09:45:51 -080098 : interface_name_(kInterfaceName),
99 server_async_connection_(NULL),
Paul Stewartf65320c2011-10-13 14:34:52 -0700100 dns_servers_(kDNSServers, kDNSServers + 2),
101 dns_client_(NULL),
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800102 device_info_(new NiceMock<MockDeviceInfo>(
103 &control_,
104 reinterpret_cast<EventDispatcher*>(NULL),
Thieu Le3426c8f2012-01-11 17:35:11 -0800105 reinterpret_cast<Metrics*>(NULL),
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800106 reinterpret_cast<Manager*>(NULL))),
107 connection_(new StrictMock<MockConnection>(device_info_.get())),
108 proxy_(connection_) { }
Paul Stewartf65320c2011-10-13 14:34:52 -0700109 protected:
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800110 virtual void SetUp() {
111 EXPECT_CALL(*connection_.get(), interface_name())
112 .WillRepeatedly(ReturnRef(interface_name_));
113 EXPECT_CALL(*connection_.get(), dns_servers())
114 .WillRepeatedly(ReturnRef(dns_servers_));
115 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700116 virtual void TearDown() {
117 if (proxy_.sockets_) {
118 ExpectStop();
119 }
120 }
121 string CreateRequest(const string &url, const string &http_version,
122 const string &extra_lines) {
123 string append_lines(extra_lines);
124 if (append_lines.size()) {
125 append_lines.append("\r\n");
126 }
127 return StringPrintf(kQueryTemplate, url.c_str(), http_version.c_str(),
128 append_lines.c_str());
129 }
130 int InvokeGetSockName(int fd, struct sockaddr *addr_out,
131 socklen_t *sockaddr_size) {
132 struct sockaddr_in addr;
133 EXPECT_EQ(kProxyFD, fd);
134 EXPECT_GE(sizeof(sockaddr_in), *sockaddr_size);
135 addr.sin_addr.s_addr = 0;
136 addr.sin_port = kServerPort;
137 memcpy(addr_out, &addr, sizeof(addr));
138 *sockaddr_size = sizeof(sockaddr_in);
139 return 0;
140 }
141 void InvokeSyncConnect(const IPAddress &/*address*/, int /*port*/) {
142 proxy_.OnConnectCompletion(true, kServerFD);
143 }
144 size_t FindInRequest(const string &find_string) {
145 const ByteString &request_data = GetClientData();
146 string request_string(
147 reinterpret_cast<const char *>(request_data.GetConstData()),
148 request_data.GetLength());
149 return request_string.find(find_string);
150 }
151 // Accessors
152 const ByteString &GetClientData() {
153 return proxy_.client_data_;
154 }
155 HTTPProxy *proxy() { return &proxy_; }
156 HTTPProxy::State GetProxyState() {
157 return proxy_.state_;
158 }
159 const ByteString &GetServerData() {
160 return proxy_.server_data_;
161 }
162 MockSockets &sockets() { return sockets_; }
163 MockEventDispatcher &dispatcher() { return dispatcher_; }
164
165
166 // Expectations
167 void ExpectClientReset() {
168 EXPECT_EQ(-1, proxy_.client_socket_);
169 EXPECT_TRUE(proxy_.client_version_.empty());
170 EXPECT_EQ(HTTPProxy::kDefaultServerPort, proxy_.server_port_);
171 EXPECT_EQ(-1, proxy_.server_socket_);
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500172 EXPECT_TRUE(proxy_.idle_timeout_.IsCancelled());
Paul Stewartf65320c2011-10-13 14:34:52 -0700173 EXPECT_TRUE(proxy_.client_headers_.empty());
174 EXPECT_TRUE(proxy_.server_hostname_.empty());
175 EXPECT_TRUE(proxy_.client_data_.IsEmpty());
176 EXPECT_TRUE(proxy_.server_data_.IsEmpty());
177 EXPECT_FALSE(proxy_.read_client_handler_.get());
178 EXPECT_FALSE(proxy_.write_client_handler_.get());
179 EXPECT_FALSE(proxy_.read_server_handler_.get());
180 EXPECT_FALSE(proxy_.write_server_handler_.get());
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800181 EXPECT_FALSE(proxy_.is_route_requested_);
Paul Stewartf65320c2011-10-13 14:34:52 -0700182 }
183 void ExpectReset() {
184 EXPECT_FALSE(proxy_.accept_handler_.get());
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800185 EXPECT_EQ(proxy_.connection_.get(), connection_.get());
Paul Stewartf65320c2011-10-13 14:34:52 -0700186 EXPECT_FALSE(proxy_.dispatcher_);
187 EXPECT_FALSE(proxy_.dns_client_.get());
188 EXPECT_EQ(-1, proxy_.proxy_port_);
189 EXPECT_EQ(-1, proxy_.proxy_socket_);
190 EXPECT_FALSE(proxy_.server_async_connection_.get());
191 EXPECT_FALSE(proxy_.sockets_);
192 EXPECT_EQ(HTTPProxy::kStateIdle, proxy_.state_);
193 ExpectClientReset();
194 }
195 void ExpectStart() {
196 EXPECT_CALL(sockets(), Socket(_, _, _))
197 .WillOnce(Return(kProxyFD));
198 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
199 .WillOnce(Return(0));
200 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
201 .WillOnce(Invoke(this, &HTTPProxyTest::InvokeGetSockName));
202 EXPECT_CALL(sockets(), SetNonBlocking(kProxyFD))
203 .WillOnce(Return(0));
204 EXPECT_CALL(sockets(), Listen(kProxyFD, _))
205 .WillOnce(Return(0));
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500206 EXPECT_CALL(dispatcher_,
207 CreateReadyHandler(kProxyFD,
208 IOHandler::kModeInput,
209 CallbackEq(proxy_.accept_callback_)))
Paul Stewartf65320c2011-10-13 14:34:52 -0700210 .WillOnce(ReturnNew<IOHandler>());
211 }
212 void ExpectStop() {
213 if (dns_client_) {
214 EXPECT_CALL(*dns_client_, Stop())
215 .Times(AtLeast(1));
216 }
217 if (server_async_connection_) {
218 EXPECT_CALL(*server_async_connection_, Stop())
219 .Times(AtLeast(1));
220 }
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800221 if (proxy_.is_route_requested_) {
222 EXPECT_CALL(*connection_.get(), ReleaseRouting());
223 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700224 }
225 void ExpectClientInput(int fd) {
226 EXPECT_CALL(sockets(), Accept(kProxyFD, _, _))
227 .WillOnce(Return(fd));
228 EXPECT_CALL(sockets(), SetNonBlocking(fd))
229 .WillOnce(Return(0));
230 EXPECT_CALL(dispatcher(),
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500231 CreateInputHandler(fd,
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800232 CallbackEq(proxy_.read_client_callback_), _))
Paul Stewartf65320c2011-10-13 14:34:52 -0700233 .WillOnce(ReturnNew<IOHandler>());
234 ExpectTransactionTimeout();
235 ExpectClientHeaderTimeout();
236 }
237 void ExpectTimeout(int timeout) {
238 EXPECT_CALL(dispatcher_, PostDelayedTask(_, timeout * 1000))
239 .WillOnce(Return(true));
240 }
241 void ExpectClientHeaderTimeout() {
242 ExpectTimeout(HTTPProxy::kClientHeaderTimeoutSeconds);
243 }
244 void ExpectConnectTimeout() {
245 ExpectTimeout(HTTPProxy::kConnectTimeoutSeconds);
246 }
247 void ExpectInputTimeout() {
248 ExpectTimeout(HTTPProxy::kInputTimeoutSeconds);
249 }
250 void ExpectRepeatedInputTimeout() {
251 EXPECT_CALL(dispatcher_,
252 PostDelayedTask(_, HTTPProxy::kInputTimeoutSeconds * 1000))
253 .WillRepeatedly(Return(true));
254 }
255 void ExpectTransactionTimeout() {
256 ExpectTimeout(HTTPProxy::kTransactionTimeoutSeconds);
257 }
Paul Stewart58a577b2012-01-10 11:18:52 -0800258 void ExpectInClientResponse(const string &response_data) {
259 string server_data(reinterpret_cast<char *>(proxy_.server_data_.GetData()),
260 proxy_.server_data_.GetLength());
261 EXPECT_NE(string::npos, server_data.find(response_data));
262 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700263 void ExpectClientError(int code, const string &error) {
264 EXPECT_EQ(HTTPProxy::kStateFlushResponse, GetProxyState());
265 string status_line = StringPrintf("HTTP/1.1 %d ERROR", code);
Paul Stewart58a577b2012-01-10 11:18:52 -0800266 ExpectInClientResponse(status_line);
267 ExpectInClientResponse(error);
Paul Stewartf65320c2011-10-13 14:34:52 -0700268 }
269 void ExpectClientInternalError() {
270 ExpectClientError(500, HTTPProxy::kInternalErrorMsg);
271 }
272 void ExpectClientVersion(const string &version) {
273 EXPECT_EQ(version, proxy_.client_version_);
274 }
275 void ExpectServerHostname(const string &hostname) {
276 EXPECT_EQ(hostname, proxy_.server_hostname_);
277 }
278 void ExpectFirstLine(const string &line) {
279 EXPECT_EQ(line, proxy_.client_headers_[0] + "\r\n");
280 }
281 void ExpectDNSRequest(const string &host, bool return_value) {
Paul Stewartbdb02e62012-02-22 16:24:33 -0800282 EXPECT_CALL(*dns_client_, Start(StrEq(host), _))
Paul Stewartf65320c2011-10-13 14:34:52 -0700283 .WillOnce(Return(return_value));
284 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700285 void ExpectAsyncConnect(const string &address, int port,
286 bool return_value) {
287 EXPECT_CALL(*server_async_connection_, Start(IsIPAddress(address), port))
288 .WillOnce(Return(return_value));
289 }
290 void ExpectSyncConnect(const string &address, int port) {
291 EXPECT_CALL(*server_async_connection_, Start(IsIPAddress(address), port))
292 .WillOnce(DoAll(Invoke(this, &HTTPProxyTest::InvokeSyncConnect),
293 Return(true)));
294 }
Paul Stewart58a577b2012-01-10 11:18:52 -0800295 void ExpectClientData() {
Paul Stewartf65320c2011-10-13 14:34:52 -0700296 EXPECT_CALL(dispatcher(),
297 CreateReadyHandler(kClientFD,
298 IOHandler::kModeOutput,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500299 CallbackEq(proxy_.write_client_callback_)))
Paul Stewartf65320c2011-10-13 14:34:52 -0700300 .WillOnce(ReturnNew<IOHandler>());
Paul Stewart58a577b2012-01-10 11:18:52 -0800301 }
302 void ExpectClientResult() {
303 ExpectClientData();
Paul Stewartf65320c2011-10-13 14:34:52 -0700304 ExpectInputTimeout();
305 }
306 void ExpectServerInput() {
307 EXPECT_CALL(dispatcher(),
308 CreateInputHandler(kServerFD,
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800309 CallbackEq(proxy_.read_server_callback_), _))
Paul Stewartf65320c2011-10-13 14:34:52 -0700310 .WillOnce(ReturnNew<IOHandler>());
311 ExpectInputTimeout();
312 }
313 void ExpectServerOutput() {
314 EXPECT_CALL(dispatcher(),
315 CreateReadyHandler(kServerFD,
316 IOHandler::kModeOutput,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500317 CallbackEq(proxy_.write_server_callback_)))
Paul Stewartf65320c2011-10-13 14:34:52 -0700318 .WillOnce(ReturnNew<IOHandler>());
319 ExpectInputTimeout();
320 }
321 void ExpectRepeatedServerOutput() {
322 EXPECT_CALL(dispatcher(),
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500323 CreateReadyHandler(kServerFD, IOHandler::kModeOutput,
324 CallbackEq(proxy_.write_server_callback_)))
Paul Stewartf65320c2011-10-13 14:34:52 -0700325 .WillOnce(ReturnNew<IOHandler>());
326 ExpectRepeatedInputTimeout();
327 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700328 void ExpectTunnelClose() {
329 EXPECT_CALL(sockets(), Close(kClientFD))
330 .WillOnce(Return(0));
331 EXPECT_CALL(sockets(), Close(kServerFD))
332 .WillOnce(Return(0));
333 ExpectStop();
334 }
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800335 void ExpectRouteRequest() {
336 EXPECT_CALL(*connection_.get(), RequestRouting());
337 }
338 void ExpectRouteRelease() {
339 EXPECT_CALL(*connection_.get(), ReleaseRouting());
340 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700341
342 // Callers for various private routines in the proxy
343 bool StartProxy() {
344 bool ret = proxy_.Start(&dispatcher_, &sockets_);
345 if (ret) {
346 dns_client_ = new StrictMock<MockDNSClient>();
347 // Passes ownership.
348 proxy_.dns_client_.reset(dns_client_);
349 server_async_connection_ = new StrictMock<MockAsyncConnection>();
350 // Passes ownership.
351 proxy_.server_async_connection_.reset(server_async_connection_);
352 }
353 return ret;
354 }
355 void AcceptClient(int fd) {
356 proxy_.AcceptClient(fd);
357 }
Paul Stewartbdb02e62012-02-22 16:24:33 -0800358 void GetDNSResultFailure(const string &error_msg) {
359 Error error(Error::kOperationFailed, error_msg);
360 IPAddress address(IPAddress::kFamilyUnknown);
361 proxy_.GetDNSResult(error, address);
362 }
363 void GetDNSResultSuccess(const IPAddress &address) {
364 Error error;
365 proxy_.GetDNSResult(error, address);
Paul Stewartf65320c2011-10-13 14:34:52 -0700366 }
367 void OnConnectCompletion(bool result, int sockfd) {
368 proxy_.OnConnectCompletion(result, sockfd);
369 }
370 void ReadFromClient(const string &data) {
371 const unsigned char *ptr =
372 reinterpret_cast<const unsigned char *>(data.c_str());
373 vector<unsigned char> data_bytes(ptr, ptr + data.length());
374 InputData proxy_data(data_bytes.data(), data_bytes.size());
375 proxy_.ReadFromClient(&proxy_data);
376 }
377 void ReadFromServer(const string &data) {
378 const unsigned char *ptr =
379 reinterpret_cast<const unsigned char *>(data.c_str());
380 vector<unsigned char> data_bytes(ptr, ptr + data.length());
381 InputData proxy_data(data_bytes.data(), data_bytes.size());
382 proxy_.ReadFromServer(&proxy_data);
383 }
384 void SendClientError(int code, const string &error) {
385 proxy_.SendClientError(code, error);
386 EXPECT_FALSE(proxy_.server_data_.IsEmpty());
387 }
388 void StopClient() {
389 EXPECT_CALL(*dns_client_, Stop());
390 EXPECT_CALL(*server_async_connection_, Stop());
391 proxy_.StopClient();
392 }
393 void StopProxy() {
394 ExpectStop();
395 proxy_.Stop();
396 server_async_connection_ = NULL;
397 dns_client_ = NULL;
398 ExpectReset();
399 }
400 void WriteToClient(int fd) {
401 proxy_.WriteToClient(fd);
402 }
403 void WriteToServer(int fd) {
404 proxy_.WriteToServer(fd);
405 }
406
407 void SetupClient() {
408 ExpectStart();
409 ASSERT_TRUE(StartProxy());
410 ExpectClientInput(kClientFD);
411 AcceptClient(kProxyFD);
412 EXPECT_EQ(HTTPProxy::kStateReadClientHeader, GetProxyState());
413 }
414 void SetupConnectWithRequest(const string &url, const string &http_version,
415 const string &extra_lines) {
416 ExpectDNSRequest("www.chromium.org", true);
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800417 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700418 ReadFromClient(CreateRequest(url, http_version, extra_lines));
419 IPAddress addr(IPAddress::kFamilyIPv4);
420 EXPECT_TRUE(addr.SetAddressFromString(kServerAddress));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800421 GetDNSResultSuccess(addr);
Paul Stewartf65320c2011-10-13 14:34:52 -0700422 }
423 void SetupConnect() {
424 SetupConnectWithRequest("/", "1.1", "Host: www.chromium.org:40506");
425 }
426 void SetupConnectAsync() {
427 SetupClient();
428 ExpectAsyncConnect(kServerAddress, kServerPort, true);
429 ExpectConnectTimeout();
430 SetupConnect();
431 }
432 void SetupConnectComplete() {
433 SetupConnectAsync();
434 ExpectServerOutput();
435 OnConnectCompletion(true, kServerFD);
436 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
437 }
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800438 void CauseReadError() {
439 proxy_.OnReadError(Error());
440 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700441
442 private:
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800443 const string interface_name_;
Paul Stewartf65320c2011-10-13 14:34:52 -0700444 // Owned by the HTTPProxy, but tracked here for EXPECT().
445 StrictMock<MockAsyncConnection> *server_async_connection_;
446 vector<string> dns_servers_;
447 // Owned by the HTTPProxy, but tracked here for EXPECT().
448 StrictMock<MockDNSClient> *dns_client_;
449 MockEventDispatcher dispatcher_;
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800450 MockControl control_;
451 scoped_ptr<MockDeviceInfo> device_info_;
452 scoped_refptr<MockConnection> connection_;
Paul Stewartf65320c2011-10-13 14:34:52 -0700453 HTTPProxy proxy_;
454 StrictMock<MockSockets> sockets_;
455};
456
457TEST_F(HTTPProxyTest, StartFailSocket) {
458 EXPECT_CALL(sockets(), Socket(_, _, _))
459 .WillOnce(Return(-1));
460 EXPECT_FALSE(StartProxy());
461 ExpectReset();
462}
463
464TEST_F(HTTPProxyTest, StartFailBind) {
465 EXPECT_CALL(sockets(), Socket(_, _, _))
466 .WillOnce(Return(kProxyFD));
467 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
468 .WillOnce(Return(-1));
469 EXPECT_CALL(sockets(), Close(kProxyFD))
470 .WillOnce(Return(0));
471 EXPECT_FALSE(StartProxy());
472 ExpectReset();
473}
474
475TEST_F(HTTPProxyTest, StartFailGetSockName) {
476 EXPECT_CALL(sockets(), Socket(_, _, _))
477 .WillOnce(Return(kProxyFD));
478 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
479 .WillOnce(Return(0));
480 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
481 .WillOnce(Return(-1));
482 EXPECT_CALL(sockets(), Close(kProxyFD))
483 .WillOnce(Return(0));
484 EXPECT_FALSE(StartProxy());
485 ExpectReset();
486}
487
488TEST_F(HTTPProxyTest, StartFailSetNonBlocking) {
489 EXPECT_CALL(sockets(), Socket(_, _, _))
490 .WillOnce(Return(kProxyFD));
491 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
492 .WillOnce(Return(0));
493 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
494 .WillOnce(Return(0));
495 EXPECT_CALL(sockets(), SetNonBlocking(kProxyFD))
496 .WillOnce(Return(-1));
497 EXPECT_CALL(sockets(), Close(kProxyFD))
498 .WillOnce(Return(0));
499 EXPECT_FALSE(StartProxy());
500 ExpectReset();
501}
502
503TEST_F(HTTPProxyTest, StartFailListen) {
504 EXPECT_CALL(sockets(), Socket(_, _, _))
505 .WillOnce(Return(kProxyFD));
506 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
507 .WillOnce(Return(0));
508 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
509 .WillOnce(Return(0));
510 EXPECT_CALL(sockets(), SetNonBlocking(kProxyFD))
511 .WillOnce(Return(0));
512 EXPECT_CALL(sockets(), Listen(kProxyFD, _))
513 .WillOnce(Return(-1));
514 EXPECT_CALL(sockets(), Close(kProxyFD))
515 .WillOnce(Return(0));
516 EXPECT_FALSE(StartProxy());
517 ExpectReset();
518}
519
520TEST_F(HTTPProxyTest, StartSuccess) {
521 ExpectStart();
522 EXPECT_TRUE(StartProxy());
523}
524
525TEST_F(HTTPProxyTest, SendClientError) {
526 SetupClient();
527 ExpectClientResult();
528 SendClientError(500, "This is an error");
529 ExpectClientError(500, "This is an error");
530
531 // We succeed in sending all but one byte of the client response.
532 int buf_len = GetServerData().GetLength();
533 EXPECT_CALL(sockets(), Send(kClientFD, _, buf_len, 0))
534 .WillOnce(Return(buf_len - 1));
535 ExpectInputTimeout();
536 WriteToClient(kClientFD);
537 EXPECT_EQ(1, GetServerData().GetLength());
538 EXPECT_EQ(HTTPProxy::kStateFlushResponse, GetProxyState());
539
540 // When we are able to send the last byte, we close the connection.
541 EXPECT_CALL(sockets(), Send(kClientFD, _, 1, 0))
542 .WillOnce(Return(1));
543 EXPECT_CALL(sockets(), Close(kClientFD))
544 .WillOnce(Return(0));
545 ExpectStop();
546 WriteToClient(kClientFD);
547 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
548}
549
Paul Stewart58a577b2012-01-10 11:18:52 -0800550TEST_F(HTTPProxyTest, ReadMissingURL) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700551 SetupClient();
552 ExpectClientResult();
Paul Stewart58a577b2012-01-10 11:18:52 -0800553 ReadFromClient(kBadHeaderMissingURL);
554 ExpectClientError(501, "Server could not parse HTTP method");
555}
556
557TEST_F(HTTPProxyTest, ReadMissingVersion) {
558 SetupClient();
559 ExpectClientResult();
560 ReadFromClient(kBadHeaderMissingVersion);
Paul Stewartf65320c2011-10-13 14:34:52 -0700561 ExpectClientError(501, "Server only accepts HTTP/1.x requests");
562}
563
564TEST_F(HTTPProxyTest, ReadBadHostname) {
565 SetupClient();
566 ExpectClientResult();
567 ReadFromClient(kBadHostnameLine);
568 ExpectClientInternalError();
569}
570
571TEST_F(HTTPProxyTest, GoodFirstLineWithoutURL) {
572 SetupClient();
573 ExpectClientHeaderTimeout();
574 ReadFromClient(kBasicGetHeader);
575 ExpectClientVersion("1.1");
576 ExpectServerHostname("");
577 ExpectFirstLine(kBasicGetHeader);
578}
579
580TEST_F(HTTPProxyTest, GoodFirstLineWithURL) {
581 SetupClient();
582 ExpectClientHeaderTimeout();
583 ReadFromClient(kBasicGetHeaderWithURL);
584 ExpectClientVersion("1.1");
585 ExpectServerHostname("www.chromium.org");
586 ExpectFirstLine(kBasicGetHeader);
587}
588
589TEST_F(HTTPProxyTest, GoodFirstLineWithURLNoSlash) {
590 SetupClient();
591 ExpectClientHeaderTimeout();
592 ReadFromClient(kBasicGetHeaderWithURLNoTrailingSlash);
593 ExpectClientVersion("1.1");
594 ExpectServerHostname("www.chromium.org");
595 ExpectFirstLine(kBasicGetHeader);
596}
597
598TEST_F(HTTPProxyTest, NoHostInRequest) {
599 SetupClient();
600 ExpectClientResult();
601 ReadFromClient(CreateRequest("/", "1.1", ""));
602 ExpectClientError(400, "I don't know what host you want me to connect to");
603}
604
605TEST_F(HTTPProxyTest, TooManyColonsInHost) {
606 SetupClient();
607 ExpectClientResult();
608 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:80:40506"));
609 ExpectClientError(400, "Too many colons in hostname");
610}
611
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800612TEST_F(HTTPProxyTest, ClientReadError) {
613 SetupClient();
614 EXPECT_CALL(sockets(), Close(kClientFD))
615 .WillOnce(Return(0));
616 ExpectStop();
617 CauseReadError();
618 ExpectClientReset();
619}
620
Paul Stewartf65320c2011-10-13 14:34:52 -0700621TEST_F(HTTPProxyTest, DNSRequestFailure) {
622 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800623 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700624 ExpectDNSRequest("www.chromium.org", false);
625 ExpectClientResult();
626 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506"));
627 ExpectClientError(502, "Could not resolve hostname");
628}
629
630TEST_F(HTTPProxyTest, DNSRequestDelayedFailure) {
631 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800632 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700633 ExpectDNSRequest("www.chromium.org", true);
634 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506"));
635 ExpectClientResult();
636 const std::string not_found_error(DNSClient::kErrorNotFound);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800637 GetDNSResultFailure(not_found_error);
Paul Stewartf65320c2011-10-13 14:34:52 -0700638 ExpectClientError(502, string("Could not resolve hostname: ") +
639 not_found_error);
640}
641
642TEST_F(HTTPProxyTest, TrailingClientData) {
643 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800644 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700645 ExpectDNSRequest("www.chromium.org", true);
646 const string trailing_data("Trailing client data");
647 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506") +
648 trailing_data);
649 EXPECT_EQ(GetClientData().GetLength() - trailing_data.length(),
650 FindInRequest(trailing_data));
651 EXPECT_EQ(HTTPProxy::kStateLookupServer, GetProxyState());
652}
653
654TEST_F(HTTPProxyTest, LineContinuation) {
655 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800656 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700657 ExpectDNSRequest("www.chromium.org", true);
658 string text_to_keep("X-Long-Header: this is one line\r\n"
659 "\tand this is another");
660 ReadFromClient(CreateRequest("http://www.chromium.org/", "1.1",
661 text_to_keep));
662 EXPECT_NE(string::npos, FindInRequest(text_to_keep));
663}
664
665// NB: This tests two different things:
666// 1) That the system replaces the value for "Proxy-Connection" headers.
667// 2) That when it replaces a header, it also removes the text in the line
668// continuation.
669TEST_F(HTTPProxyTest, LineContinuationRemoval) {
670 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800671 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700672 ExpectDNSRequest("www.chromium.org", true);
673 string text_to_remove("remove this text please");
674 ReadFromClient(CreateRequest("http://www.chromium.org/", "1.1",
675 string("Proxy-Connection: stuff\r\n\t") +
676 text_to_remove));
677 EXPECT_EQ(string::npos, FindInRequest(text_to_remove));
678 EXPECT_NE(string::npos, FindInRequest("Proxy-Connection: close\r\n"));
679}
680
681TEST_F(HTTPProxyTest, ConnectSynchronousFailure) {
682 SetupClient();
683 ExpectAsyncConnect(kServerAddress, kServerPort, false);
684 ExpectClientResult();
685 SetupConnect();
686 ExpectClientError(500, "Could not create socket to connect to server");
687}
688
689TEST_F(HTTPProxyTest, ConnectAsyncConnectFailure) {
690 SetupConnectAsync();
691 ExpectClientResult();
692 OnConnectCompletion(false, -1);
693 ExpectClientError(500, "Socket connection delayed failure");
694}
695
696TEST_F(HTTPProxyTest, ConnectSynchronousSuccess) {
697 SetupClient();
698 ExpectSyncConnect(kServerAddress, 999);
699 ExpectRepeatedServerOutput();
700 SetupConnectWithRequest("/", "1.1", "Host: www.chromium.org:999");
701 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
702}
703
704TEST_F(HTTPProxyTest, ConnectIPAddresss) {
705 SetupClient();
706 ExpectSyncConnect(kServerAddress, 999);
707 ExpectRepeatedServerOutput();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800708 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700709 ReadFromClient(CreateRequest("/", "1.1",
710 StringPrintf("Host: %s:999", kServerAddress)));
711 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
712}
713
714TEST_F(HTTPProxyTest, ConnectAsyncConnectSuccess) {
715 SetupConnectComplete();
716}
717
Paul Stewart58a577b2012-01-10 11:18:52 -0800718TEST_F(HTTPProxyTest, HTTPConnectMethod) {
719 SetupClient();
720 ExpectAsyncConnect(kServerAddress, kConnectPort, true);
721 ExpectConnectTimeout();
722 ExpectRouteRequest();
723 ReadFromClient(kConnectQuery);
724 ExpectRepeatedInputTimeout();
725 ExpectClientData();
726 OnConnectCompletion(true, kServerFD);
727 ExpectInClientResponse("HTTP/1.1 200 OK\r\n\r\n");
728}
729
Paul Stewartf65320c2011-10-13 14:34:52 -0700730TEST_F(HTTPProxyTest, TunnelData) {
731 SetupConnectComplete();
732
733 // The proxy is waiting for the server to be ready to accept data.
734 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
735 .WillOnce(Return(10));
736 ExpectServerInput();
737 WriteToServer(kServerFD);
738 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
739 .WillOnce(ReturnArg<2>());
740 ExpectInputTimeout();
741 WriteToServer(kServerFD);
742 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
743
744 // Tunnel a reply back to the client.
745 const string server_result("200 OK ... and so on");
746 ExpectClientResult();
747 ReadFromServer(server_result);
748 EXPECT_EQ(server_result,
749 string(reinterpret_cast<const char *>(
750 GetServerData().GetConstData()),
751 GetServerData().GetLength()));
752
753 // Allow part of the result string to be sent to the client.
754 const int part = server_result.length() / 2;
755 EXPECT_CALL(sockets(), Send(kClientFD, _, server_result.length(), 0))
756 .WillOnce(Return(part));
757 ExpectInputTimeout();
758 WriteToClient(kClientFD);
759 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
760
761 // The Server closes the connection while the client is still reading.
762 ExpectInputTimeout();
763 ReadFromServer("");
764 EXPECT_EQ(HTTPProxy::kStateFlushResponse, GetProxyState());
765
766 // When the last part of the response is written to the client, we close
767 // all connections.
768 EXPECT_CALL(sockets(), Send(kClientFD, _, server_result.length() - part, 0))
769 .WillOnce(ReturnArg<2>());
770 ExpectTunnelClose();
771 WriteToClient(kClientFD);
772 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
773}
774
775TEST_F(HTTPProxyTest, TunnelDataFailWriteClient) {
776 SetupConnectComplete();
777 EXPECT_CALL(sockets(), Send(kClientFD, _, _, 0))
778 .WillOnce(Return(-1));
779 ExpectTunnelClose();
780 WriteToClient(kClientFD);
781 ExpectClientReset();
782 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
783}
784
785TEST_F(HTTPProxyTest, TunnelDataFailWriteServer) {
786 SetupConnectComplete();
787 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
788 .WillOnce(Return(-1));
789 ExpectTunnelClose();
790 WriteToServer(kServerFD);
791 ExpectClientReset();
792 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
793}
794
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800795TEST_F(HTTPProxyTest, TunnelDataFailReadServer) {
796 SetupConnectComplete();
797 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
798 .WillOnce(Return(10));
799 ExpectServerInput();
800 WriteToServer(kServerFD);
801 ExpectTunnelClose();
802 CauseReadError();
803 ExpectClientReset();
804 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
805}
806
Paul Stewartf65320c2011-10-13 14:34:52 -0700807TEST_F(HTTPProxyTest, TunnelDataFailClientClose) {
808 SetupConnectComplete();
809 ExpectTunnelClose();
810 ReadFromClient("");
811 ExpectClientReset();
812 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
813}
814
815TEST_F(HTTPProxyTest, TunnelDataFailServerClose) {
816 SetupConnectComplete();
817 ExpectTunnelClose();
818 ReadFromServer("");
819 ExpectClientReset();
820 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
821}
822
823TEST_F(HTTPProxyTest, StopClient) {
824 SetupConnectComplete();
825 EXPECT_CALL(sockets(), Close(kClientFD))
826 .WillOnce(Return(0));
827 EXPECT_CALL(sockets(), Close(kServerFD))
828 .WillOnce(Return(0));
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800829 ExpectRouteRelease();
Paul Stewartf65320c2011-10-13 14:34:52 -0700830 StopClient();
831 ExpectClientReset();
832 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
833}
834
835} // namespace shill