blob: 71e350922e8462631475a8ac1358fdd8f052fc74 [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 }
mukesh agrawal7efde5b2013-05-08 11:36:58 -0700120 const int proxy_fds[] = {
121 proxy_.client_socket_,
122 proxy_.server_socket_,
123 proxy_.proxy_socket_
124 };
125 for (const int fd : proxy_fds) {
126 if (fd != -1) {
127 EXPECT_CALL(sockets_, Close(fd));
128 }
129 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700130 }
131 string CreateRequest(const string &url, const string &http_version,
132 const string &extra_lines) {
133 string append_lines(extra_lines);
134 if (append_lines.size()) {
135 append_lines.append("\r\n");
136 }
137 return StringPrintf(kQueryTemplate, url.c_str(), http_version.c_str(),
138 append_lines.c_str());
139 }
140 int InvokeGetSockName(int fd, struct sockaddr *addr_out,
141 socklen_t *sockaddr_size) {
142 struct sockaddr_in addr;
143 EXPECT_EQ(kProxyFD, fd);
144 EXPECT_GE(sizeof(sockaddr_in), *sockaddr_size);
145 addr.sin_addr.s_addr = 0;
146 addr.sin_port = kServerPort;
147 memcpy(addr_out, &addr, sizeof(addr));
148 *sockaddr_size = sizeof(sockaddr_in);
149 return 0;
150 }
151 void InvokeSyncConnect(const IPAddress &/*address*/, int /*port*/) {
152 proxy_.OnConnectCompletion(true, kServerFD);
153 }
154 size_t FindInRequest(const string &find_string) {
155 const ByteString &request_data = GetClientData();
156 string request_string(
157 reinterpret_cast<const char *>(request_data.GetConstData()),
158 request_data.GetLength());
159 return request_string.find(find_string);
160 }
161 // Accessors
162 const ByteString &GetClientData() {
163 return proxy_.client_data_;
164 }
165 HTTPProxy *proxy() { return &proxy_; }
166 HTTPProxy::State GetProxyState() {
167 return proxy_.state_;
168 }
169 const ByteString &GetServerData() {
170 return proxy_.server_data_;
171 }
172 MockSockets &sockets() { return sockets_; }
173 MockEventDispatcher &dispatcher() { return dispatcher_; }
174
175
176 // Expectations
177 void ExpectClientReset() {
178 EXPECT_EQ(-1, proxy_.client_socket_);
179 EXPECT_TRUE(proxy_.client_version_.empty());
180 EXPECT_EQ(HTTPProxy::kDefaultServerPort, proxy_.server_port_);
181 EXPECT_EQ(-1, proxy_.server_socket_);
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500182 EXPECT_TRUE(proxy_.idle_timeout_.IsCancelled());
Paul Stewartf65320c2011-10-13 14:34:52 -0700183 EXPECT_TRUE(proxy_.client_headers_.empty());
184 EXPECT_TRUE(proxy_.server_hostname_.empty());
185 EXPECT_TRUE(proxy_.client_data_.IsEmpty());
186 EXPECT_TRUE(proxy_.server_data_.IsEmpty());
187 EXPECT_FALSE(proxy_.read_client_handler_.get());
188 EXPECT_FALSE(proxy_.write_client_handler_.get());
189 EXPECT_FALSE(proxy_.read_server_handler_.get());
190 EXPECT_FALSE(proxy_.write_server_handler_.get());
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800191 EXPECT_FALSE(proxy_.is_route_requested_);
Paul Stewartf65320c2011-10-13 14:34:52 -0700192 }
193 void ExpectReset() {
194 EXPECT_FALSE(proxy_.accept_handler_.get());
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800195 EXPECT_EQ(proxy_.connection_.get(), connection_.get());
Paul Stewartf65320c2011-10-13 14:34:52 -0700196 EXPECT_FALSE(proxy_.dispatcher_);
197 EXPECT_FALSE(proxy_.dns_client_.get());
198 EXPECT_EQ(-1, proxy_.proxy_port_);
199 EXPECT_EQ(-1, proxy_.proxy_socket_);
200 EXPECT_FALSE(proxy_.server_async_connection_.get());
201 EXPECT_FALSE(proxy_.sockets_);
202 EXPECT_EQ(HTTPProxy::kStateIdle, proxy_.state_);
203 ExpectClientReset();
204 }
205 void ExpectStart() {
206 EXPECT_CALL(sockets(), Socket(_, _, _))
207 .WillOnce(Return(kProxyFD));
208 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
209 .WillOnce(Return(0));
210 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
211 .WillOnce(Invoke(this, &HTTPProxyTest::InvokeGetSockName));
212 EXPECT_CALL(sockets(), SetNonBlocking(kProxyFD))
213 .WillOnce(Return(0));
214 EXPECT_CALL(sockets(), Listen(kProxyFD, _))
215 .WillOnce(Return(0));
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500216 EXPECT_CALL(dispatcher_,
217 CreateReadyHandler(kProxyFD,
218 IOHandler::kModeInput,
219 CallbackEq(proxy_.accept_callback_)))
Paul Stewartf65320c2011-10-13 14:34:52 -0700220 .WillOnce(ReturnNew<IOHandler>());
221 }
222 void ExpectStop() {
223 if (dns_client_) {
224 EXPECT_CALL(*dns_client_, Stop())
225 .Times(AtLeast(1));
226 }
227 if (server_async_connection_) {
228 EXPECT_CALL(*server_async_connection_, Stop())
229 .Times(AtLeast(1));
230 }
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800231 if (proxy_.is_route_requested_) {
232 EXPECT_CALL(*connection_.get(), ReleaseRouting());
233 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700234 }
235 void ExpectClientInput(int fd) {
236 EXPECT_CALL(sockets(), Accept(kProxyFD, _, _))
237 .WillOnce(Return(fd));
238 EXPECT_CALL(sockets(), SetNonBlocking(fd))
239 .WillOnce(Return(0));
240 EXPECT_CALL(dispatcher(),
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500241 CreateInputHandler(fd,
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800242 CallbackEq(proxy_.read_client_callback_), _))
Paul Stewartf65320c2011-10-13 14:34:52 -0700243 .WillOnce(ReturnNew<IOHandler>());
244 ExpectTransactionTimeout();
245 ExpectClientHeaderTimeout();
246 }
247 void ExpectTimeout(int timeout) {
248 EXPECT_CALL(dispatcher_, PostDelayedTask(_, timeout * 1000))
249 .WillOnce(Return(true));
250 }
251 void ExpectClientHeaderTimeout() {
252 ExpectTimeout(HTTPProxy::kClientHeaderTimeoutSeconds);
253 }
254 void ExpectConnectTimeout() {
255 ExpectTimeout(HTTPProxy::kConnectTimeoutSeconds);
256 }
257 void ExpectInputTimeout() {
258 ExpectTimeout(HTTPProxy::kInputTimeoutSeconds);
259 }
260 void ExpectRepeatedInputTimeout() {
261 EXPECT_CALL(dispatcher_,
262 PostDelayedTask(_, HTTPProxy::kInputTimeoutSeconds * 1000))
263 .WillRepeatedly(Return(true));
264 }
265 void ExpectTransactionTimeout() {
266 ExpectTimeout(HTTPProxy::kTransactionTimeoutSeconds);
267 }
Paul Stewart58a577b2012-01-10 11:18:52 -0800268 void ExpectInClientResponse(const string &response_data) {
269 string server_data(reinterpret_cast<char *>(proxy_.server_data_.GetData()),
270 proxy_.server_data_.GetLength());
271 EXPECT_NE(string::npos, server_data.find(response_data));
272 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700273 void ExpectClientError(int code, const string &error) {
274 EXPECT_EQ(HTTPProxy::kStateFlushResponse, GetProxyState());
275 string status_line = StringPrintf("HTTP/1.1 %d ERROR", code);
Paul Stewart58a577b2012-01-10 11:18:52 -0800276 ExpectInClientResponse(status_line);
277 ExpectInClientResponse(error);
Paul Stewartf65320c2011-10-13 14:34:52 -0700278 }
279 void ExpectClientInternalError() {
280 ExpectClientError(500, HTTPProxy::kInternalErrorMsg);
281 }
282 void ExpectClientVersion(const string &version) {
283 EXPECT_EQ(version, proxy_.client_version_);
284 }
285 void ExpectServerHostname(const string &hostname) {
286 EXPECT_EQ(hostname, proxy_.server_hostname_);
287 }
288 void ExpectFirstLine(const string &line) {
289 EXPECT_EQ(line, proxy_.client_headers_[0] + "\r\n");
290 }
291 void ExpectDNSRequest(const string &host, bool return_value) {
Paul Stewartbdb02e62012-02-22 16:24:33 -0800292 EXPECT_CALL(*dns_client_, Start(StrEq(host), _))
Paul Stewartf65320c2011-10-13 14:34:52 -0700293 .WillOnce(Return(return_value));
294 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700295 void ExpectAsyncConnect(const string &address, int port,
296 bool return_value) {
297 EXPECT_CALL(*server_async_connection_, Start(IsIPAddress(address), port))
298 .WillOnce(Return(return_value));
299 }
300 void ExpectSyncConnect(const string &address, int port) {
301 EXPECT_CALL(*server_async_connection_, Start(IsIPAddress(address), port))
302 .WillOnce(DoAll(Invoke(this, &HTTPProxyTest::InvokeSyncConnect),
303 Return(true)));
304 }
Paul Stewart58a577b2012-01-10 11:18:52 -0800305 void ExpectClientData() {
Paul Stewartf65320c2011-10-13 14:34:52 -0700306 EXPECT_CALL(dispatcher(),
307 CreateReadyHandler(kClientFD,
308 IOHandler::kModeOutput,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500309 CallbackEq(proxy_.write_client_callback_)))
Paul Stewartf65320c2011-10-13 14:34:52 -0700310 .WillOnce(ReturnNew<IOHandler>());
Paul Stewart58a577b2012-01-10 11:18:52 -0800311 }
312 void ExpectClientResult() {
313 ExpectClientData();
Paul Stewartf65320c2011-10-13 14:34:52 -0700314 ExpectInputTimeout();
315 }
316 void ExpectServerInput() {
317 EXPECT_CALL(dispatcher(),
318 CreateInputHandler(kServerFD,
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800319 CallbackEq(proxy_.read_server_callback_), _))
Paul Stewartf65320c2011-10-13 14:34:52 -0700320 .WillOnce(ReturnNew<IOHandler>());
321 ExpectInputTimeout();
322 }
323 void ExpectServerOutput() {
324 EXPECT_CALL(dispatcher(),
325 CreateReadyHandler(kServerFD,
326 IOHandler::kModeOutput,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500327 CallbackEq(proxy_.write_server_callback_)))
Paul Stewartf65320c2011-10-13 14:34:52 -0700328 .WillOnce(ReturnNew<IOHandler>());
329 ExpectInputTimeout();
330 }
331 void ExpectRepeatedServerOutput() {
332 EXPECT_CALL(dispatcher(),
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500333 CreateReadyHandler(kServerFD, IOHandler::kModeOutput,
334 CallbackEq(proxy_.write_server_callback_)))
Paul Stewartf65320c2011-10-13 14:34:52 -0700335 .WillOnce(ReturnNew<IOHandler>());
336 ExpectRepeatedInputTimeout();
337 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700338 void ExpectTunnelClose() {
339 EXPECT_CALL(sockets(), Close(kClientFD))
340 .WillOnce(Return(0));
341 EXPECT_CALL(sockets(), Close(kServerFD))
342 .WillOnce(Return(0));
343 ExpectStop();
344 }
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800345 void ExpectRouteRequest() {
346 EXPECT_CALL(*connection_.get(), RequestRouting());
347 }
348 void ExpectRouteRelease() {
349 EXPECT_CALL(*connection_.get(), ReleaseRouting());
350 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700351
352 // Callers for various private routines in the proxy
353 bool StartProxy() {
354 bool ret = proxy_.Start(&dispatcher_, &sockets_);
355 if (ret) {
356 dns_client_ = new StrictMock<MockDNSClient>();
357 // Passes ownership.
358 proxy_.dns_client_.reset(dns_client_);
359 server_async_connection_ = new StrictMock<MockAsyncConnection>();
360 // Passes ownership.
361 proxy_.server_async_connection_.reset(server_async_connection_);
362 }
363 return ret;
364 }
365 void AcceptClient(int fd) {
366 proxy_.AcceptClient(fd);
367 }
Paul Stewartbdb02e62012-02-22 16:24:33 -0800368 void GetDNSResultFailure(const string &error_msg) {
369 Error error(Error::kOperationFailed, error_msg);
370 IPAddress address(IPAddress::kFamilyUnknown);
371 proxy_.GetDNSResult(error, address);
372 }
373 void GetDNSResultSuccess(const IPAddress &address) {
374 Error error;
375 proxy_.GetDNSResult(error, address);
Paul Stewartf65320c2011-10-13 14:34:52 -0700376 }
377 void OnConnectCompletion(bool result, int sockfd) {
378 proxy_.OnConnectCompletion(result, sockfd);
379 }
380 void ReadFromClient(const string &data) {
381 const unsigned char *ptr =
382 reinterpret_cast<const unsigned char *>(data.c_str());
383 vector<unsigned char> data_bytes(ptr, ptr + data.length());
384 InputData proxy_data(data_bytes.data(), data_bytes.size());
385 proxy_.ReadFromClient(&proxy_data);
386 }
387 void ReadFromServer(const string &data) {
388 const unsigned char *ptr =
389 reinterpret_cast<const unsigned char *>(data.c_str());
390 vector<unsigned char> data_bytes(ptr, ptr + data.length());
391 InputData proxy_data(data_bytes.data(), data_bytes.size());
392 proxy_.ReadFromServer(&proxy_data);
393 }
394 void SendClientError(int code, const string &error) {
395 proxy_.SendClientError(code, error);
396 EXPECT_FALSE(proxy_.server_data_.IsEmpty());
397 }
398 void StopClient() {
399 EXPECT_CALL(*dns_client_, Stop());
400 EXPECT_CALL(*server_async_connection_, Stop());
401 proxy_.StopClient();
402 }
403 void StopProxy() {
404 ExpectStop();
405 proxy_.Stop();
406 server_async_connection_ = NULL;
407 dns_client_ = NULL;
408 ExpectReset();
409 }
410 void WriteToClient(int fd) {
411 proxy_.WriteToClient(fd);
412 }
413 void WriteToServer(int fd) {
414 proxy_.WriteToServer(fd);
415 }
416
417 void SetupClient() {
418 ExpectStart();
419 ASSERT_TRUE(StartProxy());
420 ExpectClientInput(kClientFD);
421 AcceptClient(kProxyFD);
422 EXPECT_EQ(HTTPProxy::kStateReadClientHeader, GetProxyState());
423 }
424 void SetupConnectWithRequest(const string &url, const string &http_version,
425 const string &extra_lines) {
426 ExpectDNSRequest("www.chromium.org", true);
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800427 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700428 ReadFromClient(CreateRequest(url, http_version, extra_lines));
429 IPAddress addr(IPAddress::kFamilyIPv4);
430 EXPECT_TRUE(addr.SetAddressFromString(kServerAddress));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800431 GetDNSResultSuccess(addr);
Paul Stewartf65320c2011-10-13 14:34:52 -0700432 }
433 void SetupConnect() {
434 SetupConnectWithRequest("/", "1.1", "Host: www.chromium.org:40506");
435 }
436 void SetupConnectAsync() {
437 SetupClient();
438 ExpectAsyncConnect(kServerAddress, kServerPort, true);
439 ExpectConnectTimeout();
440 SetupConnect();
441 }
442 void SetupConnectComplete() {
443 SetupConnectAsync();
444 ExpectServerOutput();
445 OnConnectCompletion(true, kServerFD);
446 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
447 }
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800448 void CauseReadError() {
449 proxy_.OnReadError(Error());
450 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700451
452 private:
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800453 const string interface_name_;
Paul Stewartf65320c2011-10-13 14:34:52 -0700454 // Owned by the HTTPProxy, but tracked here for EXPECT().
455 StrictMock<MockAsyncConnection> *server_async_connection_;
456 vector<string> dns_servers_;
457 // Owned by the HTTPProxy, but tracked here for EXPECT().
458 StrictMock<MockDNSClient> *dns_client_;
459 MockEventDispatcher dispatcher_;
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800460 MockControl control_;
461 scoped_ptr<MockDeviceInfo> device_info_;
462 scoped_refptr<MockConnection> connection_;
Paul Stewartf65320c2011-10-13 14:34:52 -0700463 StrictMock<MockSockets> sockets_;
mukesh agrawal7efde5b2013-05-08 11:36:58 -0700464 HTTPProxy proxy_; // Destroy first, before anything it references.
Paul Stewartf65320c2011-10-13 14:34:52 -0700465};
466
467TEST_F(HTTPProxyTest, StartFailSocket) {
468 EXPECT_CALL(sockets(), Socket(_, _, _))
469 .WillOnce(Return(-1));
470 EXPECT_FALSE(StartProxy());
471 ExpectReset();
472}
473
474TEST_F(HTTPProxyTest, StartFailBind) {
475 EXPECT_CALL(sockets(), Socket(_, _, _))
476 .WillOnce(Return(kProxyFD));
477 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
478 .WillOnce(Return(-1));
479 EXPECT_CALL(sockets(), Close(kProxyFD))
480 .WillOnce(Return(0));
481 EXPECT_FALSE(StartProxy());
482 ExpectReset();
483}
484
485TEST_F(HTTPProxyTest, StartFailGetSockName) {
486 EXPECT_CALL(sockets(), Socket(_, _, _))
487 .WillOnce(Return(kProxyFD));
488 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
489 .WillOnce(Return(0));
490 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
491 .WillOnce(Return(-1));
492 EXPECT_CALL(sockets(), Close(kProxyFD))
493 .WillOnce(Return(0));
494 EXPECT_FALSE(StartProxy());
495 ExpectReset();
496}
497
498TEST_F(HTTPProxyTest, StartFailSetNonBlocking) {
499 EXPECT_CALL(sockets(), Socket(_, _, _))
500 .WillOnce(Return(kProxyFD));
501 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
502 .WillOnce(Return(0));
503 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
504 .WillOnce(Return(0));
505 EXPECT_CALL(sockets(), SetNonBlocking(kProxyFD))
506 .WillOnce(Return(-1));
507 EXPECT_CALL(sockets(), Close(kProxyFD))
508 .WillOnce(Return(0));
509 EXPECT_FALSE(StartProxy());
510 ExpectReset();
511}
512
513TEST_F(HTTPProxyTest, StartFailListen) {
514 EXPECT_CALL(sockets(), Socket(_, _, _))
515 .WillOnce(Return(kProxyFD));
516 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
517 .WillOnce(Return(0));
518 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
519 .WillOnce(Return(0));
520 EXPECT_CALL(sockets(), SetNonBlocking(kProxyFD))
521 .WillOnce(Return(0));
522 EXPECT_CALL(sockets(), Listen(kProxyFD, _))
523 .WillOnce(Return(-1));
524 EXPECT_CALL(sockets(), Close(kProxyFD))
525 .WillOnce(Return(0));
526 EXPECT_FALSE(StartProxy());
527 ExpectReset();
528}
529
530TEST_F(HTTPProxyTest, StartSuccess) {
531 ExpectStart();
532 EXPECT_TRUE(StartProxy());
533}
534
535TEST_F(HTTPProxyTest, SendClientError) {
536 SetupClient();
537 ExpectClientResult();
538 SendClientError(500, "This is an error");
539 ExpectClientError(500, "This is an error");
540
541 // We succeed in sending all but one byte of the client response.
542 int buf_len = GetServerData().GetLength();
543 EXPECT_CALL(sockets(), Send(kClientFD, _, buf_len, 0))
544 .WillOnce(Return(buf_len - 1));
545 ExpectInputTimeout();
546 WriteToClient(kClientFD);
547 EXPECT_EQ(1, GetServerData().GetLength());
548 EXPECT_EQ(HTTPProxy::kStateFlushResponse, GetProxyState());
549
550 // When we are able to send the last byte, we close the connection.
551 EXPECT_CALL(sockets(), Send(kClientFD, _, 1, 0))
552 .WillOnce(Return(1));
553 EXPECT_CALL(sockets(), Close(kClientFD))
554 .WillOnce(Return(0));
555 ExpectStop();
556 WriteToClient(kClientFD);
557 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
558}
559
Paul Stewart58a577b2012-01-10 11:18:52 -0800560TEST_F(HTTPProxyTest, ReadMissingURL) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700561 SetupClient();
562 ExpectClientResult();
Paul Stewart58a577b2012-01-10 11:18:52 -0800563 ReadFromClient(kBadHeaderMissingURL);
564 ExpectClientError(501, "Server could not parse HTTP method");
565}
566
567TEST_F(HTTPProxyTest, ReadMissingVersion) {
568 SetupClient();
569 ExpectClientResult();
570 ReadFromClient(kBadHeaderMissingVersion);
Paul Stewartf65320c2011-10-13 14:34:52 -0700571 ExpectClientError(501, "Server only accepts HTTP/1.x requests");
572}
573
574TEST_F(HTTPProxyTest, ReadBadHostname) {
575 SetupClient();
576 ExpectClientResult();
577 ReadFromClient(kBadHostnameLine);
578 ExpectClientInternalError();
579}
580
581TEST_F(HTTPProxyTest, GoodFirstLineWithoutURL) {
582 SetupClient();
583 ExpectClientHeaderTimeout();
584 ReadFromClient(kBasicGetHeader);
585 ExpectClientVersion("1.1");
586 ExpectServerHostname("");
587 ExpectFirstLine(kBasicGetHeader);
588}
589
590TEST_F(HTTPProxyTest, GoodFirstLineWithURL) {
591 SetupClient();
592 ExpectClientHeaderTimeout();
593 ReadFromClient(kBasicGetHeaderWithURL);
594 ExpectClientVersion("1.1");
595 ExpectServerHostname("www.chromium.org");
596 ExpectFirstLine(kBasicGetHeader);
597}
598
599TEST_F(HTTPProxyTest, GoodFirstLineWithURLNoSlash) {
600 SetupClient();
601 ExpectClientHeaderTimeout();
602 ReadFromClient(kBasicGetHeaderWithURLNoTrailingSlash);
603 ExpectClientVersion("1.1");
604 ExpectServerHostname("www.chromium.org");
605 ExpectFirstLine(kBasicGetHeader);
606}
607
608TEST_F(HTTPProxyTest, NoHostInRequest) {
609 SetupClient();
610 ExpectClientResult();
611 ReadFromClient(CreateRequest("/", "1.1", ""));
612 ExpectClientError(400, "I don't know what host you want me to connect to");
613}
614
615TEST_F(HTTPProxyTest, TooManyColonsInHost) {
616 SetupClient();
617 ExpectClientResult();
618 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:80:40506"));
619 ExpectClientError(400, "Too many colons in hostname");
620}
621
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800622TEST_F(HTTPProxyTest, ClientReadError) {
623 SetupClient();
624 EXPECT_CALL(sockets(), Close(kClientFD))
625 .WillOnce(Return(0));
626 ExpectStop();
627 CauseReadError();
628 ExpectClientReset();
629}
630
Paul Stewartf65320c2011-10-13 14:34:52 -0700631TEST_F(HTTPProxyTest, DNSRequestFailure) {
632 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800633 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700634 ExpectDNSRequest("www.chromium.org", false);
635 ExpectClientResult();
636 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506"));
637 ExpectClientError(502, "Could not resolve hostname");
638}
639
640TEST_F(HTTPProxyTest, DNSRequestDelayedFailure) {
641 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800642 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700643 ExpectDNSRequest("www.chromium.org", true);
644 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506"));
645 ExpectClientResult();
646 const std::string not_found_error(DNSClient::kErrorNotFound);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800647 GetDNSResultFailure(not_found_error);
Paul Stewartf65320c2011-10-13 14:34:52 -0700648 ExpectClientError(502, string("Could not resolve hostname: ") +
649 not_found_error);
650}
651
652TEST_F(HTTPProxyTest, TrailingClientData) {
653 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800654 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700655 ExpectDNSRequest("www.chromium.org", true);
656 const string trailing_data("Trailing client data");
657 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506") +
658 trailing_data);
659 EXPECT_EQ(GetClientData().GetLength() - trailing_data.length(),
660 FindInRequest(trailing_data));
661 EXPECT_EQ(HTTPProxy::kStateLookupServer, GetProxyState());
662}
663
664TEST_F(HTTPProxyTest, LineContinuation) {
665 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800666 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700667 ExpectDNSRequest("www.chromium.org", true);
668 string text_to_keep("X-Long-Header: this is one line\r\n"
669 "\tand this is another");
670 ReadFromClient(CreateRequest("http://www.chromium.org/", "1.1",
671 text_to_keep));
672 EXPECT_NE(string::npos, FindInRequest(text_to_keep));
673}
674
675// NB: This tests two different things:
676// 1) That the system replaces the value for "Proxy-Connection" headers.
677// 2) That when it replaces a header, it also removes the text in the line
678// continuation.
679TEST_F(HTTPProxyTest, LineContinuationRemoval) {
680 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800681 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700682 ExpectDNSRequest("www.chromium.org", true);
683 string text_to_remove("remove this text please");
684 ReadFromClient(CreateRequest("http://www.chromium.org/", "1.1",
685 string("Proxy-Connection: stuff\r\n\t") +
686 text_to_remove));
687 EXPECT_EQ(string::npos, FindInRequest(text_to_remove));
688 EXPECT_NE(string::npos, FindInRequest("Proxy-Connection: close\r\n"));
689}
690
691TEST_F(HTTPProxyTest, ConnectSynchronousFailure) {
692 SetupClient();
693 ExpectAsyncConnect(kServerAddress, kServerPort, false);
694 ExpectClientResult();
695 SetupConnect();
696 ExpectClientError(500, "Could not create socket to connect to server");
697}
698
699TEST_F(HTTPProxyTest, ConnectAsyncConnectFailure) {
700 SetupConnectAsync();
701 ExpectClientResult();
702 OnConnectCompletion(false, -1);
703 ExpectClientError(500, "Socket connection delayed failure");
704}
705
706TEST_F(HTTPProxyTest, ConnectSynchronousSuccess) {
707 SetupClient();
708 ExpectSyncConnect(kServerAddress, 999);
709 ExpectRepeatedServerOutput();
710 SetupConnectWithRequest("/", "1.1", "Host: www.chromium.org:999");
711 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
712}
713
714TEST_F(HTTPProxyTest, ConnectIPAddresss) {
715 SetupClient();
716 ExpectSyncConnect(kServerAddress, 999);
717 ExpectRepeatedServerOutput();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800718 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700719 ReadFromClient(CreateRequest("/", "1.1",
720 StringPrintf("Host: %s:999", kServerAddress)));
721 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
722}
723
724TEST_F(HTTPProxyTest, ConnectAsyncConnectSuccess) {
725 SetupConnectComplete();
726}
727
Paul Stewart58a577b2012-01-10 11:18:52 -0800728TEST_F(HTTPProxyTest, HTTPConnectMethod) {
729 SetupClient();
730 ExpectAsyncConnect(kServerAddress, kConnectPort, true);
731 ExpectConnectTimeout();
732 ExpectRouteRequest();
733 ReadFromClient(kConnectQuery);
734 ExpectRepeatedInputTimeout();
735 ExpectClientData();
736 OnConnectCompletion(true, kServerFD);
737 ExpectInClientResponse("HTTP/1.1 200 OK\r\n\r\n");
738}
739
Paul Stewartf65320c2011-10-13 14:34:52 -0700740TEST_F(HTTPProxyTest, TunnelData) {
741 SetupConnectComplete();
742
743 // The proxy is waiting for the server to be ready to accept data.
744 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
745 .WillOnce(Return(10));
746 ExpectServerInput();
747 WriteToServer(kServerFD);
748 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
749 .WillOnce(ReturnArg<2>());
750 ExpectInputTimeout();
751 WriteToServer(kServerFD);
752 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
753
754 // Tunnel a reply back to the client.
755 const string server_result("200 OK ... and so on");
756 ExpectClientResult();
757 ReadFromServer(server_result);
758 EXPECT_EQ(server_result,
759 string(reinterpret_cast<const char *>(
760 GetServerData().GetConstData()),
761 GetServerData().GetLength()));
762
763 // Allow part of the result string to be sent to the client.
764 const int part = server_result.length() / 2;
765 EXPECT_CALL(sockets(), Send(kClientFD, _, server_result.length(), 0))
766 .WillOnce(Return(part));
767 ExpectInputTimeout();
768 WriteToClient(kClientFD);
769 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
770
771 // The Server closes the connection while the client is still reading.
772 ExpectInputTimeout();
773 ReadFromServer("");
774 EXPECT_EQ(HTTPProxy::kStateFlushResponse, GetProxyState());
775
776 // When the last part of the response is written to the client, we close
777 // all connections.
778 EXPECT_CALL(sockets(), Send(kClientFD, _, server_result.length() - part, 0))
779 .WillOnce(ReturnArg<2>());
780 ExpectTunnelClose();
781 WriteToClient(kClientFD);
782 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
783}
784
785TEST_F(HTTPProxyTest, TunnelDataFailWriteClient) {
786 SetupConnectComplete();
787 EXPECT_CALL(sockets(), Send(kClientFD, _, _, 0))
788 .WillOnce(Return(-1));
789 ExpectTunnelClose();
790 WriteToClient(kClientFD);
791 ExpectClientReset();
792 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
793}
794
795TEST_F(HTTPProxyTest, TunnelDataFailWriteServer) {
796 SetupConnectComplete();
797 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
798 .WillOnce(Return(-1));
799 ExpectTunnelClose();
800 WriteToServer(kServerFD);
801 ExpectClientReset();
802 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
803}
804
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800805TEST_F(HTTPProxyTest, TunnelDataFailReadServer) {
806 SetupConnectComplete();
807 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
808 .WillOnce(Return(10));
809 ExpectServerInput();
810 WriteToServer(kServerFD);
811 ExpectTunnelClose();
812 CauseReadError();
813 ExpectClientReset();
814 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
815}
816
Paul Stewartf65320c2011-10-13 14:34:52 -0700817TEST_F(HTTPProxyTest, TunnelDataFailClientClose) {
818 SetupConnectComplete();
819 ExpectTunnelClose();
820 ReadFromClient("");
821 ExpectClientReset();
822 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
823}
824
825TEST_F(HTTPProxyTest, TunnelDataFailServerClose) {
826 SetupConnectComplete();
827 ExpectTunnelClose();
828 ReadFromServer("");
829 ExpectClientReset();
830 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
831}
832
833TEST_F(HTTPProxyTest, StopClient) {
834 SetupConnectComplete();
835 EXPECT_CALL(sockets(), Close(kClientFD))
836 .WillOnce(Return(0));
837 EXPECT_CALL(sockets(), Close(kServerFD))
838 .WillOnce(Return(0));
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800839 ExpectRouteRelease();
Paul Stewartf65320c2011-10-13 14:34:52 -0700840 StopClient();
841 ExpectClientReset();
842 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
843}
844
845} // namespace shill