blob: ba46b0e42191bfdf338f86599c500c698877e7c7 [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,
232 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,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500309 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 }
438
439 private:
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800440 const string interface_name_;
Paul Stewartf65320c2011-10-13 14:34:52 -0700441 // Owned by the HTTPProxy, but tracked here for EXPECT().
442 StrictMock<MockAsyncConnection> *server_async_connection_;
443 vector<string> dns_servers_;
444 // Owned by the HTTPProxy, but tracked here for EXPECT().
445 StrictMock<MockDNSClient> *dns_client_;
446 MockEventDispatcher dispatcher_;
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800447 MockControl control_;
448 scoped_ptr<MockDeviceInfo> device_info_;
449 scoped_refptr<MockConnection> connection_;
Paul Stewartf65320c2011-10-13 14:34:52 -0700450 HTTPProxy proxy_;
451 StrictMock<MockSockets> sockets_;
452};
453
454TEST_F(HTTPProxyTest, StartFailSocket) {
455 EXPECT_CALL(sockets(), Socket(_, _, _))
456 .WillOnce(Return(-1));
457 EXPECT_FALSE(StartProxy());
458 ExpectReset();
459}
460
461TEST_F(HTTPProxyTest, StartFailBind) {
462 EXPECT_CALL(sockets(), Socket(_, _, _))
463 .WillOnce(Return(kProxyFD));
464 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
465 .WillOnce(Return(-1));
466 EXPECT_CALL(sockets(), Close(kProxyFD))
467 .WillOnce(Return(0));
468 EXPECT_FALSE(StartProxy());
469 ExpectReset();
470}
471
472TEST_F(HTTPProxyTest, StartFailGetSockName) {
473 EXPECT_CALL(sockets(), Socket(_, _, _))
474 .WillOnce(Return(kProxyFD));
475 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
476 .WillOnce(Return(0));
477 EXPECT_CALL(sockets(), GetSockName(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, StartFailSetNonBlocking) {
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(0));
492 EXPECT_CALL(sockets(), SetNonBlocking(kProxyFD))
493 .WillOnce(Return(-1));
494 EXPECT_CALL(sockets(), Close(kProxyFD))
495 .WillOnce(Return(0));
496 EXPECT_FALSE(StartProxy());
497 ExpectReset();
498}
499
500TEST_F(HTTPProxyTest, StartFailListen) {
501 EXPECT_CALL(sockets(), Socket(_, _, _))
502 .WillOnce(Return(kProxyFD));
503 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
504 .WillOnce(Return(0));
505 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
506 .WillOnce(Return(0));
507 EXPECT_CALL(sockets(), SetNonBlocking(kProxyFD))
508 .WillOnce(Return(0));
509 EXPECT_CALL(sockets(), Listen(kProxyFD, _))
510 .WillOnce(Return(-1));
511 EXPECT_CALL(sockets(), Close(kProxyFD))
512 .WillOnce(Return(0));
513 EXPECT_FALSE(StartProxy());
514 ExpectReset();
515}
516
517TEST_F(HTTPProxyTest, StartSuccess) {
518 ExpectStart();
519 EXPECT_TRUE(StartProxy());
520}
521
522TEST_F(HTTPProxyTest, SendClientError) {
523 SetupClient();
524 ExpectClientResult();
525 SendClientError(500, "This is an error");
526 ExpectClientError(500, "This is an error");
527
528 // We succeed in sending all but one byte of the client response.
529 int buf_len = GetServerData().GetLength();
530 EXPECT_CALL(sockets(), Send(kClientFD, _, buf_len, 0))
531 .WillOnce(Return(buf_len - 1));
532 ExpectInputTimeout();
533 WriteToClient(kClientFD);
534 EXPECT_EQ(1, GetServerData().GetLength());
535 EXPECT_EQ(HTTPProxy::kStateFlushResponse, GetProxyState());
536
537 // When we are able to send the last byte, we close the connection.
538 EXPECT_CALL(sockets(), Send(kClientFD, _, 1, 0))
539 .WillOnce(Return(1));
540 EXPECT_CALL(sockets(), Close(kClientFD))
541 .WillOnce(Return(0));
542 ExpectStop();
543 WriteToClient(kClientFD);
544 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
545}
546
Paul Stewart58a577b2012-01-10 11:18:52 -0800547TEST_F(HTTPProxyTest, ReadMissingURL) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700548 SetupClient();
549 ExpectClientResult();
Paul Stewart58a577b2012-01-10 11:18:52 -0800550 ReadFromClient(kBadHeaderMissingURL);
551 ExpectClientError(501, "Server could not parse HTTP method");
552}
553
554TEST_F(HTTPProxyTest, ReadMissingVersion) {
555 SetupClient();
556 ExpectClientResult();
557 ReadFromClient(kBadHeaderMissingVersion);
Paul Stewartf65320c2011-10-13 14:34:52 -0700558 ExpectClientError(501, "Server only accepts HTTP/1.x requests");
559}
560
561TEST_F(HTTPProxyTest, ReadBadHostname) {
562 SetupClient();
563 ExpectClientResult();
564 ReadFromClient(kBadHostnameLine);
565 ExpectClientInternalError();
566}
567
568TEST_F(HTTPProxyTest, GoodFirstLineWithoutURL) {
569 SetupClient();
570 ExpectClientHeaderTimeout();
571 ReadFromClient(kBasicGetHeader);
572 ExpectClientVersion("1.1");
573 ExpectServerHostname("");
574 ExpectFirstLine(kBasicGetHeader);
575}
576
577TEST_F(HTTPProxyTest, GoodFirstLineWithURL) {
578 SetupClient();
579 ExpectClientHeaderTimeout();
580 ReadFromClient(kBasicGetHeaderWithURL);
581 ExpectClientVersion("1.1");
582 ExpectServerHostname("www.chromium.org");
583 ExpectFirstLine(kBasicGetHeader);
584}
585
586TEST_F(HTTPProxyTest, GoodFirstLineWithURLNoSlash) {
587 SetupClient();
588 ExpectClientHeaderTimeout();
589 ReadFromClient(kBasicGetHeaderWithURLNoTrailingSlash);
590 ExpectClientVersion("1.1");
591 ExpectServerHostname("www.chromium.org");
592 ExpectFirstLine(kBasicGetHeader);
593}
594
595TEST_F(HTTPProxyTest, NoHostInRequest) {
596 SetupClient();
597 ExpectClientResult();
598 ReadFromClient(CreateRequest("/", "1.1", ""));
599 ExpectClientError(400, "I don't know what host you want me to connect to");
600}
601
602TEST_F(HTTPProxyTest, TooManyColonsInHost) {
603 SetupClient();
604 ExpectClientResult();
605 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:80:40506"));
606 ExpectClientError(400, "Too many colons in hostname");
607}
608
609TEST_F(HTTPProxyTest, DNSRequestFailure) {
610 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800611 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700612 ExpectDNSRequest("www.chromium.org", false);
613 ExpectClientResult();
614 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506"));
615 ExpectClientError(502, "Could not resolve hostname");
616}
617
618TEST_F(HTTPProxyTest, DNSRequestDelayedFailure) {
619 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800620 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700621 ExpectDNSRequest("www.chromium.org", true);
622 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506"));
623 ExpectClientResult();
624 const std::string not_found_error(DNSClient::kErrorNotFound);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800625 GetDNSResultFailure(not_found_error);
Paul Stewartf65320c2011-10-13 14:34:52 -0700626 ExpectClientError(502, string("Could not resolve hostname: ") +
627 not_found_error);
628}
629
630TEST_F(HTTPProxyTest, TrailingClientData) {
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 const string trailing_data("Trailing client data");
635 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506") +
636 trailing_data);
637 EXPECT_EQ(GetClientData().GetLength() - trailing_data.length(),
638 FindInRequest(trailing_data));
639 EXPECT_EQ(HTTPProxy::kStateLookupServer, GetProxyState());
640}
641
642TEST_F(HTTPProxyTest, LineContinuation) {
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 string text_to_keep("X-Long-Header: this is one line\r\n"
647 "\tand this is another");
648 ReadFromClient(CreateRequest("http://www.chromium.org/", "1.1",
649 text_to_keep));
650 EXPECT_NE(string::npos, FindInRequest(text_to_keep));
651}
652
653// NB: This tests two different things:
654// 1) That the system replaces the value for "Proxy-Connection" headers.
655// 2) That when it replaces a header, it also removes the text in the line
656// continuation.
657TEST_F(HTTPProxyTest, LineContinuationRemoval) {
658 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800659 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700660 ExpectDNSRequest("www.chromium.org", true);
661 string text_to_remove("remove this text please");
662 ReadFromClient(CreateRequest("http://www.chromium.org/", "1.1",
663 string("Proxy-Connection: stuff\r\n\t") +
664 text_to_remove));
665 EXPECT_EQ(string::npos, FindInRequest(text_to_remove));
666 EXPECT_NE(string::npos, FindInRequest("Proxy-Connection: close\r\n"));
667}
668
669TEST_F(HTTPProxyTest, ConnectSynchronousFailure) {
670 SetupClient();
671 ExpectAsyncConnect(kServerAddress, kServerPort, false);
672 ExpectClientResult();
673 SetupConnect();
674 ExpectClientError(500, "Could not create socket to connect to server");
675}
676
677TEST_F(HTTPProxyTest, ConnectAsyncConnectFailure) {
678 SetupConnectAsync();
679 ExpectClientResult();
680 OnConnectCompletion(false, -1);
681 ExpectClientError(500, "Socket connection delayed failure");
682}
683
684TEST_F(HTTPProxyTest, ConnectSynchronousSuccess) {
685 SetupClient();
686 ExpectSyncConnect(kServerAddress, 999);
687 ExpectRepeatedServerOutput();
688 SetupConnectWithRequest("/", "1.1", "Host: www.chromium.org:999");
689 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
690}
691
692TEST_F(HTTPProxyTest, ConnectIPAddresss) {
693 SetupClient();
694 ExpectSyncConnect(kServerAddress, 999);
695 ExpectRepeatedServerOutput();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800696 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700697 ReadFromClient(CreateRequest("/", "1.1",
698 StringPrintf("Host: %s:999", kServerAddress)));
699 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
700}
701
702TEST_F(HTTPProxyTest, ConnectAsyncConnectSuccess) {
703 SetupConnectComplete();
704}
705
Paul Stewart58a577b2012-01-10 11:18:52 -0800706TEST_F(HTTPProxyTest, HTTPConnectMethod) {
707 SetupClient();
708 ExpectAsyncConnect(kServerAddress, kConnectPort, true);
709 ExpectConnectTimeout();
710 ExpectRouteRequest();
711 ReadFromClient(kConnectQuery);
712 ExpectRepeatedInputTimeout();
713 ExpectClientData();
714 OnConnectCompletion(true, kServerFD);
715 ExpectInClientResponse("HTTP/1.1 200 OK\r\n\r\n");
716}
717
Paul Stewartf65320c2011-10-13 14:34:52 -0700718TEST_F(HTTPProxyTest, TunnelData) {
719 SetupConnectComplete();
720
721 // The proxy is waiting for the server to be ready to accept data.
722 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
723 .WillOnce(Return(10));
724 ExpectServerInput();
725 WriteToServer(kServerFD);
726 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
727 .WillOnce(ReturnArg<2>());
728 ExpectInputTimeout();
729 WriteToServer(kServerFD);
730 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
731
732 // Tunnel a reply back to the client.
733 const string server_result("200 OK ... and so on");
734 ExpectClientResult();
735 ReadFromServer(server_result);
736 EXPECT_EQ(server_result,
737 string(reinterpret_cast<const char *>(
738 GetServerData().GetConstData()),
739 GetServerData().GetLength()));
740
741 // Allow part of the result string to be sent to the client.
742 const int part = server_result.length() / 2;
743 EXPECT_CALL(sockets(), Send(kClientFD, _, server_result.length(), 0))
744 .WillOnce(Return(part));
745 ExpectInputTimeout();
746 WriteToClient(kClientFD);
747 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
748
749 // The Server closes the connection while the client is still reading.
750 ExpectInputTimeout();
751 ReadFromServer("");
752 EXPECT_EQ(HTTPProxy::kStateFlushResponse, GetProxyState());
753
754 // When the last part of the response is written to the client, we close
755 // all connections.
756 EXPECT_CALL(sockets(), Send(kClientFD, _, server_result.length() - part, 0))
757 .WillOnce(ReturnArg<2>());
758 ExpectTunnelClose();
759 WriteToClient(kClientFD);
760 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
761}
762
763TEST_F(HTTPProxyTest, TunnelDataFailWriteClient) {
764 SetupConnectComplete();
765 EXPECT_CALL(sockets(), Send(kClientFD, _, _, 0))
766 .WillOnce(Return(-1));
767 ExpectTunnelClose();
768 WriteToClient(kClientFD);
769 ExpectClientReset();
770 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
771}
772
773TEST_F(HTTPProxyTest, TunnelDataFailWriteServer) {
774 SetupConnectComplete();
775 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
776 .WillOnce(Return(-1));
777 ExpectTunnelClose();
778 WriteToServer(kServerFD);
779 ExpectClientReset();
780 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
781}
782
783TEST_F(HTTPProxyTest, TunnelDataFailClientClose) {
784 SetupConnectComplete();
785 ExpectTunnelClose();
786 ReadFromClient("");
787 ExpectClientReset();
788 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
789}
790
791TEST_F(HTTPProxyTest, TunnelDataFailServerClose) {
792 SetupConnectComplete();
793 ExpectTunnelClose();
794 ReadFromServer("");
795 ExpectClientReset();
796 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
797}
798
799TEST_F(HTTPProxyTest, StopClient) {
800 SetupConnectComplete();
801 EXPECT_CALL(sockets(), Close(kClientFD))
802 .WillOnce(Return(0));
803 EXPECT_CALL(sockets(), Close(kServerFD))
804 .WillOnce(Return(0));
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800805 ExpectRouteRelease();
Paul Stewartf65320c2011-10-13 14:34:52 -0700806 StopClient();
807 ExpectClientReset();
808 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
809}
810
811} // namespace shill