blob: 13356490f7cd1daa43bd9098317ea0a9b2345937 [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
Ben Chancd477322014-10-17 14:19:30 -07009#include <memory>
Paul Stewartf65320c2011-10-13 14:34:52 -070010#include <string>
11#include <vector>
12
Ben Chana0ddf462014-02-06 11:32:42 -080013#include <base/strings/stringprintf.h>
Paul Stewartf65320c2011-10-13 14:34:52 -070014#include <gtest/gtest.h>
15
Paul Stewartf65320c2011-10-13 14:34:52 -070016#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"
Peter Qiu8d6b5972014-10-28 15:33:34 -070022#include "shill/net/ip_address.h"
23#include "shill/net/mock_sockets.h"
Paul Stewartf65320c2011-10-13 14:34:52 -070024
25using base::StringPrintf;
26using std::string;
27using std::vector;
28using ::testing::_;
29using ::testing::AtLeast;
30using ::testing::DoAll;
31using ::testing::Invoke;
Paul Stewartc8f4bef2011-12-13 09:45:51 -080032using ::testing::NiceMock;
Paul Stewartf65320c2011-10-13 14:34:52 -070033using ::testing::Return;
34using ::testing::ReturnArg;
35using ::testing::ReturnNew;
36using ::testing::ReturnRef;
37using ::testing::SetArgumentPointee;
38using ::testing::StrEq;
39using ::testing::StrictMock;
40using ::testing::Test;
41
42namespace shill {
43
44namespace {
Paul Stewart58a577b2012-01-10 11:18:52 -080045const char kBadHeaderMissingURL[] = "BLAH\r\n";
46const char kBadHeaderMissingVersion[] = "BLAH http://hostname\r\n";
Paul Stewartf65320c2011-10-13 14:34:52 -070047const char kBadHostnameLine[] = "GET HTTP/1.1 http://hostname\r\n";
48const char kBasicGetHeader[] = "GET / HTTP/1.1\r\n";
49const char kBasicGetHeaderWithURL[] =
50 "GET http://www.chromium.org/ HTTP/1.1\r\n";
51const char kBasicGetHeaderWithURLNoTrailingSlash[] =
52 "GET http://www.chromium.org HTTP/1.1\r\n";
Paul Stewart58a577b2012-01-10 11:18:52 -080053const char kConnectQuery[] =
54 "CONNECT 10.10.10.10:443 HTTP/1.1\r\n"
55 "Host: 10.10.10.10:443\r\n\r\n";
Paul Stewartf65320c2011-10-13 14:34:52 -070056const char kQueryTemplate[] = "GET %s HTTP/%s\r\n%s"
57 "User-Agent: Mozilla/5.0 (X11; CrOS i686 1299.0.2011) "
58 "AppleWebKit/535.8 (KHTML, like Gecko) Chrome/17.0.936.0 Safari/535.8\r\n"
59 "Accept: text/html,application/xhtml+xml,application/xml;"
60 "q=0.9,*/*;q=0.8\r\n"
61 "Accept-Encoding: gzip,deflate,sdch\r\n"
62 "Accept-Language: en-US,en;q=0.8,ja;q=0.6\r\n"
63 "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n"
64 "Cookie: PREF=ID=xxxxxxxxxxxxxxxx:U=xxxxxxxxxxxxxxxx:FF=0:"
65 "TM=1317340083:LM=1317390705:GM=1:S=_xxxxxxxxxxxxxxx; "
66 "NID=52=xxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
67 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxx; "
68 "HSID=xxxxxxxxxxxx-xxxx; APISID=xxxxxxxxxxxxxxxx/xxxxxxxxxxxxxxxxx; "
69 "SID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_xxxxxxxxxxx"
70 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxx"
71 "xxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxx"
72 "_xxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxx-xx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
73 "xxxxxxxxxxxxxxxx\r\n\r\n";
74const char kInterfaceName[] = "int0";
75const char kDNSServer0[] = "8.8.8.8";
76const char kDNSServer1[] = "8.8.4.4";
77const char kServerAddress[] = "10.10.10.10";
Paul Stewart3b30ca52015-06-16 13:13:10 -070078const char* kDNSServers[] = { kDNSServer0, kDNSServer1 };
Paul Stewartf65320c2011-10-13 14:34:52 -070079const int kProxyFD = 10203;
80const int kServerFD = 10204;
81const int kClientFD = 10205;
82const int kServerPort = 40506;
Paul Stewart58a577b2012-01-10 11:18:52 -080083const int kConnectPort = 443;
Alex Vakulenko8a532292014-06-16 17:18:44 -070084} // namespace
Paul Stewartf65320c2011-10-13 14:34:52 -070085
86MATCHER_P(IsIPAddress, address, "") {
87 IPAddress ip_address(IPAddress::kFamilyIPv4);
88 EXPECT_TRUE(ip_address.SetAddressFromString(address));
89 return ip_address.Equals(arg);
90}
91
Eric Shienbrood3e20a232012-02-16 11:35:56 -050092MATCHER_P(CallbackEq, callback, "") {
93 return arg.Equals(callback);
94}
95
Paul Stewartf65320c2011-10-13 14:34:52 -070096class HTTPProxyTest : public Test {
97 public:
98 HTTPProxyTest()
Paul Stewartc8f4bef2011-12-13 09:45:51 -080099 : interface_name_(kInterfaceName),
Ben Chancc225ef2014-09-30 13:26:51 -0700100 server_async_connection_(nullptr),
Paul Stewartf65320c2011-10-13 14:34:52 -0700101 dns_servers_(kDNSServers, kDNSServers + 2),
Ben Chancc225ef2014-09-30 13:26:51 -0700102 dns_client_(nullptr),
103 device_info_(
104 new NiceMock<MockDeviceInfo>(&control_, nullptr, nullptr, nullptr)),
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800105 connection_(new StrictMock<MockConnection>(device_info_.get())),
Ben Chancc225ef2014-09-30 13:26:51 -0700106 proxy_(connection_) {}
Alex Vakulenko8a532292014-06-16 17:18:44 -0700107
Paul Stewartf65320c2011-10-13 14:34:52 -0700108 protected:
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800109 virtual void SetUp() {
110 EXPECT_CALL(*connection_.get(), interface_name())
111 .WillRepeatedly(ReturnRef(interface_name_));
112 EXPECT_CALL(*connection_.get(), dns_servers())
113 .WillRepeatedly(ReturnRef(dns_servers_));
114 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700115 virtual void TearDown() {
116 if (proxy_.sockets_) {
117 ExpectStop();
118 }
mukesh agrawal7efde5b2013-05-08 11:36:58 -0700119 const int proxy_fds[] = {
120 proxy_.client_socket_,
121 proxy_.server_socket_,
122 proxy_.proxy_socket_
123 };
124 for (const int fd : proxy_fds) {
125 if (fd != -1) {
126 EXPECT_CALL(sockets_, Close(fd));
127 }
128 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700129 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700130 string CreateRequest(const string& url, const string& http_version,
131 const string& extra_lines) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700132 string append_lines(extra_lines);
133 if (append_lines.size()) {
134 append_lines.append("\r\n");
135 }
136 return StringPrintf(kQueryTemplate, url.c_str(), http_version.c_str(),
137 append_lines.c_str());
138 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700139 int InvokeGetSockName(int fd, struct sockaddr* addr_out,
140 socklen_t* sockaddr_size) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700141 struct sockaddr_in addr;
142 EXPECT_EQ(kProxyFD, fd);
143 EXPECT_GE(sizeof(sockaddr_in), *sockaddr_size);
144 addr.sin_addr.s_addr = 0;
145 addr.sin_port = kServerPort;
146 memcpy(addr_out, &addr, sizeof(addr));
147 *sockaddr_size = sizeof(sockaddr_in);
148 return 0;
149 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700150 void InvokeSyncConnect(const IPAddress& /*address*/, int /*port*/) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700151 proxy_.OnConnectCompletion(true, kServerFD);
152 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700153 size_t FindInRequest(const string& find_string) {
154 const ByteString& request_data = GetClientData();
Paul Stewartf65320c2011-10-13 14:34:52 -0700155 string request_string(
Paul Stewart3b30ca52015-06-16 13:13:10 -0700156 reinterpret_cast<const char*>(request_data.GetConstData()),
Paul Stewartf65320c2011-10-13 14:34:52 -0700157 request_data.GetLength());
158 return request_string.find(find_string);
159 }
160 // Accessors
Paul Stewart3b30ca52015-06-16 13:13:10 -0700161 const ByteString& GetClientData() {
Paul Stewartf65320c2011-10-13 14:34:52 -0700162 return proxy_.client_data_;
163 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700164 HTTPProxy* proxy() { return &proxy_; }
Paul Stewartf65320c2011-10-13 14:34:52 -0700165 HTTPProxy::State GetProxyState() {
166 return proxy_.state_;
167 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700168 const ByteString& GetServerData() {
Paul Stewartf65320c2011-10-13 14:34:52 -0700169 return proxy_.server_data_;
170 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700171 MockSockets& sockets() { return sockets_; }
172 MockEventDispatcher& dispatcher() { return dispatcher_; }
Paul Stewartf65320c2011-10-13 14:34:52 -0700173
174
175 // Expectations
176 void ExpectClientReset() {
177 EXPECT_EQ(-1, proxy_.client_socket_);
178 EXPECT_TRUE(proxy_.client_version_.empty());
179 EXPECT_EQ(HTTPProxy::kDefaultServerPort, proxy_.server_port_);
180 EXPECT_EQ(-1, proxy_.server_socket_);
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500181 EXPECT_TRUE(proxy_.idle_timeout_.IsCancelled());
Paul Stewartf65320c2011-10-13 14:34:52 -0700182 EXPECT_TRUE(proxy_.client_headers_.empty());
183 EXPECT_TRUE(proxy_.server_hostname_.empty());
184 EXPECT_TRUE(proxy_.client_data_.IsEmpty());
185 EXPECT_TRUE(proxy_.server_data_.IsEmpty());
186 EXPECT_FALSE(proxy_.read_client_handler_.get());
187 EXPECT_FALSE(proxy_.write_client_handler_.get());
188 EXPECT_FALSE(proxy_.read_server_handler_.get());
189 EXPECT_FALSE(proxy_.write_server_handler_.get());
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800190 EXPECT_FALSE(proxy_.is_route_requested_);
Paul Stewartf65320c2011-10-13 14:34:52 -0700191 }
192 void ExpectReset() {
193 EXPECT_FALSE(proxy_.accept_handler_.get());
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800194 EXPECT_EQ(proxy_.connection_.get(), connection_.get());
Paul Stewartf65320c2011-10-13 14:34:52 -0700195 EXPECT_FALSE(proxy_.dispatcher_);
196 EXPECT_FALSE(proxy_.dns_client_.get());
197 EXPECT_EQ(-1, proxy_.proxy_port_);
198 EXPECT_EQ(-1, proxy_.proxy_socket_);
199 EXPECT_FALSE(proxy_.server_async_connection_.get());
200 EXPECT_FALSE(proxy_.sockets_);
201 EXPECT_EQ(HTTPProxy::kStateIdle, proxy_.state_);
202 ExpectClientReset();
203 }
204 void ExpectStart() {
205 EXPECT_CALL(sockets(), Socket(_, _, _))
206 .WillOnce(Return(kProxyFD));
207 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
208 .WillOnce(Return(0));
209 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
210 .WillOnce(Invoke(this, &HTTPProxyTest::InvokeGetSockName));
211 EXPECT_CALL(sockets(), SetNonBlocking(kProxyFD))
212 .WillOnce(Return(0));
213 EXPECT_CALL(sockets(), Listen(kProxyFD, _))
214 .WillOnce(Return(0));
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500215 EXPECT_CALL(dispatcher_,
216 CreateReadyHandler(kProxyFD,
217 IOHandler::kModeInput,
218 CallbackEq(proxy_.accept_callback_)))
Paul Stewartf65320c2011-10-13 14:34:52 -0700219 .WillOnce(ReturnNew<IOHandler>());
220 }
221 void ExpectStop() {
222 if (dns_client_) {
223 EXPECT_CALL(*dns_client_, Stop())
224 .Times(AtLeast(1));
225 }
226 if (server_async_connection_) {
227 EXPECT_CALL(*server_async_connection_, Stop())
228 .Times(AtLeast(1));
229 }
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800230 if (proxy_.is_route_requested_) {
231 EXPECT_CALL(*connection_.get(), ReleaseRouting());
232 }
Alex Vakulenko8a532292014-06-16 17:18:44 -0700233 }
234 void ExpectClientInput(int fd) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700235 EXPECT_CALL(sockets(), Accept(kProxyFD, _, _))
236 .WillOnce(Return(fd));
237 EXPECT_CALL(sockets(), SetNonBlocking(fd))
238 .WillOnce(Return(0));
239 EXPECT_CALL(dispatcher(),
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500240 CreateInputHandler(fd,
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800241 CallbackEq(proxy_.read_client_callback_), _))
Paul Stewartf65320c2011-10-13 14:34:52 -0700242 .WillOnce(ReturnNew<IOHandler>());
243 ExpectTransactionTimeout();
244 ExpectClientHeaderTimeout();
245 }
246 void ExpectTimeout(int timeout) {
247 EXPECT_CALL(dispatcher_, PostDelayedTask(_, timeout * 1000))
248 .WillOnce(Return(true));
249 }
250 void ExpectClientHeaderTimeout() {
251 ExpectTimeout(HTTPProxy::kClientHeaderTimeoutSeconds);
252 }
253 void ExpectConnectTimeout() {
254 ExpectTimeout(HTTPProxy::kConnectTimeoutSeconds);
255 }
256 void ExpectInputTimeout() {
257 ExpectTimeout(HTTPProxy::kInputTimeoutSeconds);
258 }
259 void ExpectRepeatedInputTimeout() {
260 EXPECT_CALL(dispatcher_,
261 PostDelayedTask(_, HTTPProxy::kInputTimeoutSeconds * 1000))
262 .WillRepeatedly(Return(true));
263 }
264 void ExpectTransactionTimeout() {
265 ExpectTimeout(HTTPProxy::kTransactionTimeoutSeconds);
266 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700267 void ExpectInClientResponse(const string& response_data) {
268 string server_data(reinterpret_cast<char*>(proxy_.server_data_.GetData()),
Paul Stewart58a577b2012-01-10 11:18:52 -0800269 proxy_.server_data_.GetLength());
270 EXPECT_NE(string::npos, server_data.find(response_data));
271 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700272 void ExpectClientError(int code, const string& error) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700273 EXPECT_EQ(HTTPProxy::kStateFlushResponse, GetProxyState());
274 string status_line = StringPrintf("HTTP/1.1 %d ERROR", code);
Paul Stewart58a577b2012-01-10 11:18:52 -0800275 ExpectInClientResponse(status_line);
276 ExpectInClientResponse(error);
Paul Stewartf65320c2011-10-13 14:34:52 -0700277 }
278 void ExpectClientInternalError() {
279 ExpectClientError(500, HTTPProxy::kInternalErrorMsg);
280 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700281 void ExpectClientVersion(const string& version) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700282 EXPECT_EQ(version, proxy_.client_version_);
283 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700284 void ExpectServerHostname(const string& hostname) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700285 EXPECT_EQ(hostname, proxy_.server_hostname_);
286 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700287 void ExpectFirstLine(const string& line) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700288 EXPECT_EQ(line, proxy_.client_headers_[0] + "\r\n");
289 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700290 void ExpectDNSRequest(const string& host, bool return_value) {
Paul Stewartbdb02e62012-02-22 16:24:33 -0800291 EXPECT_CALL(*dns_client_, Start(StrEq(host), _))
Paul Stewartf65320c2011-10-13 14:34:52 -0700292 .WillOnce(Return(return_value));
293 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700294 void ExpectAsyncConnect(const string& address, int port,
Paul Stewartf65320c2011-10-13 14:34:52 -0700295 bool return_value) {
296 EXPECT_CALL(*server_async_connection_, Start(IsIPAddress(address), port))
297 .WillOnce(Return(return_value));
298 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700299 void ExpectSyncConnect(const string& address, int port) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700300 EXPECT_CALL(*server_async_connection_, Start(IsIPAddress(address), port))
301 .WillOnce(DoAll(Invoke(this, &HTTPProxyTest::InvokeSyncConnect),
302 Return(true)));
303 }
Paul Stewart58a577b2012-01-10 11:18:52 -0800304 void ExpectClientData() {
Paul Stewartf65320c2011-10-13 14:34:52 -0700305 EXPECT_CALL(dispatcher(),
306 CreateReadyHandler(kClientFD,
307 IOHandler::kModeOutput,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500308 CallbackEq(proxy_.write_client_callback_)))
Paul Stewartf65320c2011-10-13 14:34:52 -0700309 .WillOnce(ReturnNew<IOHandler>());
Paul Stewart58a577b2012-01-10 11:18:52 -0800310 }
311 void ExpectClientResult() {
312 ExpectClientData();
Paul Stewartf65320c2011-10-13 14:34:52 -0700313 ExpectInputTimeout();
314 }
315 void ExpectServerInput() {
316 EXPECT_CALL(dispatcher(),
317 CreateInputHandler(kServerFD,
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800318 CallbackEq(proxy_.read_server_callback_), _))
Paul Stewartf65320c2011-10-13 14:34:52 -0700319 .WillOnce(ReturnNew<IOHandler>());
320 ExpectInputTimeout();
321 }
322 void ExpectServerOutput() {
323 EXPECT_CALL(dispatcher(),
324 CreateReadyHandler(kServerFD,
325 IOHandler::kModeOutput,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500326 CallbackEq(proxy_.write_server_callback_)))
Paul Stewartf65320c2011-10-13 14:34:52 -0700327 .WillOnce(ReturnNew<IOHandler>());
328 ExpectInputTimeout();
329 }
330 void ExpectRepeatedServerOutput() {
331 EXPECT_CALL(dispatcher(),
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500332 CreateReadyHandler(kServerFD, IOHandler::kModeOutput,
333 CallbackEq(proxy_.write_server_callback_)))
Paul Stewartf65320c2011-10-13 14:34:52 -0700334 .WillOnce(ReturnNew<IOHandler>());
335 ExpectRepeatedInputTimeout();
336 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700337 void ExpectTunnelClose() {
338 EXPECT_CALL(sockets(), Close(kClientFD))
339 .WillOnce(Return(0));
340 EXPECT_CALL(sockets(), Close(kServerFD))
341 .WillOnce(Return(0));
342 ExpectStop();
343 }
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800344 void ExpectRouteRequest() {
345 EXPECT_CALL(*connection_.get(), RequestRouting());
346 }
347 void ExpectRouteRelease() {
348 EXPECT_CALL(*connection_.get(), ReleaseRouting());
349 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700350
351 // Callers for various private routines in the proxy
352 bool StartProxy() {
353 bool ret = proxy_.Start(&dispatcher_, &sockets_);
354 if (ret) {
355 dns_client_ = new StrictMock<MockDNSClient>();
356 // Passes ownership.
357 proxy_.dns_client_.reset(dns_client_);
358 server_async_connection_ = new StrictMock<MockAsyncConnection>();
359 // Passes ownership.
360 proxy_.server_async_connection_.reset(server_async_connection_);
361 }
362 return ret;
363 }
364 void AcceptClient(int fd) {
365 proxy_.AcceptClient(fd);
366 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700367 void GetDNSResultFailure(const string& error_msg) {
Paul Stewartbdb02e62012-02-22 16:24:33 -0800368 Error error(Error::kOperationFailed, error_msg);
369 IPAddress address(IPAddress::kFamilyUnknown);
370 proxy_.GetDNSResult(error, address);
371 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700372 void GetDNSResultSuccess(const IPAddress& address) {
Paul Stewartbdb02e62012-02-22 16:24:33 -0800373 Error error;
374 proxy_.GetDNSResult(error, address);
Paul Stewartf65320c2011-10-13 14:34:52 -0700375 }
376 void OnConnectCompletion(bool result, int sockfd) {
377 proxy_.OnConnectCompletion(result, sockfd);
378 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700379 void ReadFromClient(const string& data) {
380 const unsigned char* ptr =
381 reinterpret_cast<const unsigned char*>(data.c_str());
Paul Stewartf65320c2011-10-13 14:34:52 -0700382 vector<unsigned char> data_bytes(ptr, ptr + data.length());
383 InputData proxy_data(data_bytes.data(), data_bytes.size());
384 proxy_.ReadFromClient(&proxy_data);
385 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700386 void ReadFromServer(const string& data) {
387 const unsigned char* ptr =
388 reinterpret_cast<const unsigned char*>(data.c_str());
Paul Stewartf65320c2011-10-13 14:34:52 -0700389 vector<unsigned char> data_bytes(ptr, ptr + data.length());
390 InputData proxy_data(data_bytes.data(), data_bytes.size());
391 proxy_.ReadFromServer(&proxy_data);
392 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700393 void SendClientError(int code, const string& error) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700394 proxy_.SendClientError(code, error);
395 EXPECT_FALSE(proxy_.server_data_.IsEmpty());
396 }
397 void StopClient() {
398 EXPECT_CALL(*dns_client_, Stop());
399 EXPECT_CALL(*server_async_connection_, Stop());
400 proxy_.StopClient();
401 }
402 void StopProxy() {
403 ExpectStop();
404 proxy_.Stop();
Ben Chancc225ef2014-09-30 13:26:51 -0700405 server_async_connection_ = nullptr;
406 dns_client_ = nullptr;
Paul Stewartf65320c2011-10-13 14:34:52 -0700407 ExpectReset();
408 }
409 void WriteToClient(int fd) {
410 proxy_.WriteToClient(fd);
411 }
412 void WriteToServer(int fd) {
413 proxy_.WriteToServer(fd);
414 }
415
416 void SetupClient() {
417 ExpectStart();
418 ASSERT_TRUE(StartProxy());
419 ExpectClientInput(kClientFD);
420 AcceptClient(kProxyFD);
421 EXPECT_EQ(HTTPProxy::kStateReadClientHeader, GetProxyState());
422 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700423 void SetupConnectWithRequest(const string& url, const string& http_version,
424 const string& extra_lines) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700425 ExpectDNSRequest("www.chromium.org", true);
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800426 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700427 ReadFromClient(CreateRequest(url, http_version, extra_lines));
428 IPAddress addr(IPAddress::kFamilyIPv4);
429 EXPECT_TRUE(addr.SetAddressFromString(kServerAddress));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800430 GetDNSResultSuccess(addr);
Paul Stewartf65320c2011-10-13 14:34:52 -0700431 }
432 void SetupConnect() {
433 SetupConnectWithRequest("/", "1.1", "Host: www.chromium.org:40506");
434 }
435 void SetupConnectAsync() {
436 SetupClient();
437 ExpectAsyncConnect(kServerAddress, kServerPort, true);
438 ExpectConnectTimeout();
439 SetupConnect();
440 }
441 void SetupConnectComplete() {
442 SetupConnectAsync();
443 ExpectServerOutput();
444 OnConnectCompletion(true, kServerFD);
445 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
446 }
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800447 void CauseReadError() {
Peter Qiu3161caa2014-10-29 09:47:22 -0700448 proxy_.OnReadError(string());
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800449 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700450
451 private:
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800452 const string interface_name_;
Paul Stewartf65320c2011-10-13 14:34:52 -0700453 // Owned by the HTTPProxy, but tracked here for EXPECT().
Paul Stewart3b30ca52015-06-16 13:13:10 -0700454 StrictMock<MockAsyncConnection>* server_async_connection_;
Paul Stewartf65320c2011-10-13 14:34:52 -0700455 vector<string> dns_servers_;
456 // Owned by the HTTPProxy, but tracked here for EXPECT().
Paul Stewart3b30ca52015-06-16 13:13:10 -0700457 StrictMock<MockDNSClient>* dns_client_;
Paul Stewartf65320c2011-10-13 14:34:52 -0700458 MockEventDispatcher dispatcher_;
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800459 MockControl control_;
Ben Chancd477322014-10-17 14:19:30 -0700460 std::unique_ptr<MockDeviceInfo> device_info_;
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800461 scoped_refptr<MockConnection> connection_;
Paul Stewartf65320c2011-10-13 14:34:52 -0700462 StrictMock<MockSockets> sockets_;
mukesh agrawal7efde5b2013-05-08 11:36:58 -0700463 HTTPProxy proxy_; // Destroy first, before anything it references.
Paul Stewartf65320c2011-10-13 14:34:52 -0700464};
465
466TEST_F(HTTPProxyTest, StartFailSocket) {
467 EXPECT_CALL(sockets(), Socket(_, _, _))
468 .WillOnce(Return(-1));
469 EXPECT_FALSE(StartProxy());
470 ExpectReset();
471}
472
473TEST_F(HTTPProxyTest, StartFailBind) {
474 EXPECT_CALL(sockets(), Socket(_, _, _))
475 .WillOnce(Return(kProxyFD));
476 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
477 .WillOnce(Return(-1));
478 EXPECT_CALL(sockets(), Close(kProxyFD))
479 .WillOnce(Return(0));
480 EXPECT_FALSE(StartProxy());
481 ExpectReset();
482}
483
484TEST_F(HTTPProxyTest, StartFailGetSockName) {
485 EXPECT_CALL(sockets(), Socket(_, _, _))
486 .WillOnce(Return(kProxyFD));
487 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
488 .WillOnce(Return(0));
489 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
490 .WillOnce(Return(-1));
491 EXPECT_CALL(sockets(), Close(kProxyFD))
492 .WillOnce(Return(0));
493 EXPECT_FALSE(StartProxy());
494 ExpectReset();
495}
496
497TEST_F(HTTPProxyTest, StartFailSetNonBlocking) {
498 EXPECT_CALL(sockets(), Socket(_, _, _))
499 .WillOnce(Return(kProxyFD));
500 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
501 .WillOnce(Return(0));
502 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
503 .WillOnce(Return(0));
504 EXPECT_CALL(sockets(), SetNonBlocking(kProxyFD))
505 .WillOnce(Return(-1));
506 EXPECT_CALL(sockets(), Close(kProxyFD))
507 .WillOnce(Return(0));
508 EXPECT_FALSE(StartProxy());
509 ExpectReset();
510}
511
512TEST_F(HTTPProxyTest, StartFailListen) {
513 EXPECT_CALL(sockets(), Socket(_, _, _))
514 .WillOnce(Return(kProxyFD));
515 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
516 .WillOnce(Return(0));
517 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
518 .WillOnce(Return(0));
519 EXPECT_CALL(sockets(), SetNonBlocking(kProxyFD))
520 .WillOnce(Return(0));
521 EXPECT_CALL(sockets(), Listen(kProxyFD, _))
522 .WillOnce(Return(-1));
523 EXPECT_CALL(sockets(), Close(kProxyFD))
524 .WillOnce(Return(0));
525 EXPECT_FALSE(StartProxy());
526 ExpectReset();
527}
528
529TEST_F(HTTPProxyTest, StartSuccess) {
530 ExpectStart();
531 EXPECT_TRUE(StartProxy());
532}
533
534TEST_F(HTTPProxyTest, SendClientError) {
535 SetupClient();
536 ExpectClientResult();
537 SendClientError(500, "This is an error");
538 ExpectClientError(500, "This is an error");
539
540 // We succeed in sending all but one byte of the client response.
541 int buf_len = GetServerData().GetLength();
542 EXPECT_CALL(sockets(), Send(kClientFD, _, buf_len, 0))
543 .WillOnce(Return(buf_len - 1));
544 ExpectInputTimeout();
545 WriteToClient(kClientFD);
546 EXPECT_EQ(1, GetServerData().GetLength());
547 EXPECT_EQ(HTTPProxy::kStateFlushResponse, GetProxyState());
548
549 // When we are able to send the last byte, we close the connection.
550 EXPECT_CALL(sockets(), Send(kClientFD, _, 1, 0))
551 .WillOnce(Return(1));
552 EXPECT_CALL(sockets(), Close(kClientFD))
553 .WillOnce(Return(0));
554 ExpectStop();
555 WriteToClient(kClientFD);
556 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
557}
558
Paul Stewart58a577b2012-01-10 11:18:52 -0800559TEST_F(HTTPProxyTest, ReadMissingURL) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700560 SetupClient();
561 ExpectClientResult();
Paul Stewart58a577b2012-01-10 11:18:52 -0800562 ReadFromClient(kBadHeaderMissingURL);
563 ExpectClientError(501, "Server could not parse HTTP method");
564}
565
566TEST_F(HTTPProxyTest, ReadMissingVersion) {
567 SetupClient();
568 ExpectClientResult();
569 ReadFromClient(kBadHeaderMissingVersion);
Paul Stewartf65320c2011-10-13 14:34:52 -0700570 ExpectClientError(501, "Server only accepts HTTP/1.x requests");
571}
572
573TEST_F(HTTPProxyTest, ReadBadHostname) {
574 SetupClient();
575 ExpectClientResult();
576 ReadFromClient(kBadHostnameLine);
577 ExpectClientInternalError();
578}
579
580TEST_F(HTTPProxyTest, GoodFirstLineWithoutURL) {
581 SetupClient();
582 ExpectClientHeaderTimeout();
583 ReadFromClient(kBasicGetHeader);
584 ExpectClientVersion("1.1");
585 ExpectServerHostname("");
586 ExpectFirstLine(kBasicGetHeader);
587}
588
589TEST_F(HTTPProxyTest, GoodFirstLineWithURL) {
590 SetupClient();
591 ExpectClientHeaderTimeout();
592 ReadFromClient(kBasicGetHeaderWithURL);
593 ExpectClientVersion("1.1");
594 ExpectServerHostname("www.chromium.org");
595 ExpectFirstLine(kBasicGetHeader);
596}
597
598TEST_F(HTTPProxyTest, GoodFirstLineWithURLNoSlash) {
599 SetupClient();
600 ExpectClientHeaderTimeout();
601 ReadFromClient(kBasicGetHeaderWithURLNoTrailingSlash);
602 ExpectClientVersion("1.1");
603 ExpectServerHostname("www.chromium.org");
604 ExpectFirstLine(kBasicGetHeader);
605}
606
607TEST_F(HTTPProxyTest, NoHostInRequest) {
608 SetupClient();
609 ExpectClientResult();
610 ReadFromClient(CreateRequest("/", "1.1", ""));
611 ExpectClientError(400, "I don't know what host you want me to connect to");
612}
613
614TEST_F(HTTPProxyTest, TooManyColonsInHost) {
615 SetupClient();
616 ExpectClientResult();
617 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:80:40506"));
618 ExpectClientError(400, "Too many colons in hostname");
619}
620
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800621TEST_F(HTTPProxyTest, ClientReadError) {
622 SetupClient();
623 EXPECT_CALL(sockets(), Close(kClientFD))
624 .WillOnce(Return(0));
625 ExpectStop();
626 CauseReadError();
627 ExpectClientReset();
628}
629
Paul Stewartf65320c2011-10-13 14:34:52 -0700630TEST_F(HTTPProxyTest, DNSRequestFailure) {
631 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800632 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700633 ExpectDNSRequest("www.chromium.org", false);
634 ExpectClientResult();
635 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506"));
636 ExpectClientError(502, "Could not resolve hostname");
637}
638
639TEST_F(HTTPProxyTest, DNSRequestDelayedFailure) {
640 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800641 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700642 ExpectDNSRequest("www.chromium.org", true);
643 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506"));
644 ExpectClientResult();
645 const std::string not_found_error(DNSClient::kErrorNotFound);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800646 GetDNSResultFailure(not_found_error);
Paul Stewartf65320c2011-10-13 14:34:52 -0700647 ExpectClientError(502, string("Could not resolve hostname: ") +
648 not_found_error);
649}
650
651TEST_F(HTTPProxyTest, TrailingClientData) {
652 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800653 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700654 ExpectDNSRequest("www.chromium.org", true);
655 const string trailing_data("Trailing client data");
656 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506") +
657 trailing_data);
658 EXPECT_EQ(GetClientData().GetLength() - trailing_data.length(),
659 FindInRequest(trailing_data));
660 EXPECT_EQ(HTTPProxy::kStateLookupServer, GetProxyState());
661}
662
663TEST_F(HTTPProxyTest, LineContinuation) {
664 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800665 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700666 ExpectDNSRequest("www.chromium.org", true);
667 string text_to_keep("X-Long-Header: this is one line\r\n"
668 "\tand this is another");
669 ReadFromClient(CreateRequest("http://www.chromium.org/", "1.1",
670 text_to_keep));
671 EXPECT_NE(string::npos, FindInRequest(text_to_keep));
672}
673
674// NB: This tests two different things:
675// 1) That the system replaces the value for "Proxy-Connection" headers.
676// 2) That when it replaces a header, it also removes the text in the line
677// continuation.
678TEST_F(HTTPProxyTest, LineContinuationRemoval) {
679 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800680 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700681 ExpectDNSRequest("www.chromium.org", true);
682 string text_to_remove("remove this text please");
683 ReadFromClient(CreateRequest("http://www.chromium.org/", "1.1",
684 string("Proxy-Connection: stuff\r\n\t") +
685 text_to_remove));
686 EXPECT_EQ(string::npos, FindInRequest(text_to_remove));
687 EXPECT_NE(string::npos, FindInRequest("Proxy-Connection: close\r\n"));
688}
689
690TEST_F(HTTPProxyTest, ConnectSynchronousFailure) {
691 SetupClient();
692 ExpectAsyncConnect(kServerAddress, kServerPort, false);
693 ExpectClientResult();
694 SetupConnect();
695 ExpectClientError(500, "Could not create socket to connect to server");
696}
697
698TEST_F(HTTPProxyTest, ConnectAsyncConnectFailure) {
699 SetupConnectAsync();
700 ExpectClientResult();
701 OnConnectCompletion(false, -1);
702 ExpectClientError(500, "Socket connection delayed failure");
703}
704
705TEST_F(HTTPProxyTest, ConnectSynchronousSuccess) {
706 SetupClient();
707 ExpectSyncConnect(kServerAddress, 999);
708 ExpectRepeatedServerOutput();
709 SetupConnectWithRequest("/", "1.1", "Host: www.chromium.org:999");
710 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
711}
712
713TEST_F(HTTPProxyTest, ConnectIPAddresss) {
714 SetupClient();
715 ExpectSyncConnect(kServerAddress, 999);
716 ExpectRepeatedServerOutput();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800717 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700718 ReadFromClient(CreateRequest("/", "1.1",
719 StringPrintf("Host: %s:999", kServerAddress)));
720 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
721}
722
723TEST_F(HTTPProxyTest, ConnectAsyncConnectSuccess) {
724 SetupConnectComplete();
725}
726
Paul Stewart58a577b2012-01-10 11:18:52 -0800727TEST_F(HTTPProxyTest, HTTPConnectMethod) {
728 SetupClient();
729 ExpectAsyncConnect(kServerAddress, kConnectPort, true);
730 ExpectConnectTimeout();
731 ExpectRouteRequest();
732 ReadFromClient(kConnectQuery);
733 ExpectRepeatedInputTimeout();
734 ExpectClientData();
735 OnConnectCompletion(true, kServerFD);
736 ExpectInClientResponse("HTTP/1.1 200 OK\r\n\r\n");
737}
738
Paul Stewartf65320c2011-10-13 14:34:52 -0700739TEST_F(HTTPProxyTest, TunnelData) {
740 SetupConnectComplete();
741
742 // The proxy is waiting for the server to be ready to accept data.
743 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
744 .WillOnce(Return(10));
745 ExpectServerInput();
746 WriteToServer(kServerFD);
747 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
748 .WillOnce(ReturnArg<2>());
749 ExpectInputTimeout();
750 WriteToServer(kServerFD);
751 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
752
753 // Tunnel a reply back to the client.
754 const string server_result("200 OK ... and so on");
755 ExpectClientResult();
756 ReadFromServer(server_result);
757 EXPECT_EQ(server_result,
Paul Stewart3b30ca52015-06-16 13:13:10 -0700758 string(reinterpret_cast<const char*>(
Paul Stewartf65320c2011-10-13 14:34:52 -0700759 GetServerData().GetConstData()),
760 GetServerData().GetLength()));
761
762 // Allow part of the result string to be sent to the client.
763 const int part = server_result.length() / 2;
764 EXPECT_CALL(sockets(), Send(kClientFD, _, server_result.length(), 0))
765 .WillOnce(Return(part));
766 ExpectInputTimeout();
767 WriteToClient(kClientFD);
768 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
769
770 // The Server closes the connection while the client is still reading.
771 ExpectInputTimeout();
772 ReadFromServer("");
773 EXPECT_EQ(HTTPProxy::kStateFlushResponse, GetProxyState());
774
775 // When the last part of the response is written to the client, we close
776 // all connections.
777 EXPECT_CALL(sockets(), Send(kClientFD, _, server_result.length() - part, 0))
778 .WillOnce(ReturnArg<2>());
779 ExpectTunnelClose();
780 WriteToClient(kClientFD);
781 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
782}
783
784TEST_F(HTTPProxyTest, TunnelDataFailWriteClient) {
785 SetupConnectComplete();
786 EXPECT_CALL(sockets(), Send(kClientFD, _, _, 0))
787 .WillOnce(Return(-1));
788 ExpectTunnelClose();
789 WriteToClient(kClientFD);
790 ExpectClientReset();
791 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
792}
793
794TEST_F(HTTPProxyTest, TunnelDataFailWriteServer) {
795 SetupConnectComplete();
796 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
797 .WillOnce(Return(-1));
798 ExpectTunnelClose();
799 WriteToServer(kServerFD);
800 ExpectClientReset();
801 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
802}
803
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800804TEST_F(HTTPProxyTest, TunnelDataFailReadServer) {
805 SetupConnectComplete();
806 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
807 .WillOnce(Return(10));
808 ExpectServerInput();
809 WriteToServer(kServerFD);
810 ExpectTunnelClose();
811 CauseReadError();
812 ExpectClientReset();
813 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
814}
815
Paul Stewartf65320c2011-10-13 14:34:52 -0700816TEST_F(HTTPProxyTest, TunnelDataFailClientClose) {
817 SetupConnectComplete();
818 ExpectTunnelClose();
819 ReadFromClient("");
820 ExpectClientReset();
821 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
822}
823
824TEST_F(HTTPProxyTest, TunnelDataFailServerClose) {
825 SetupConnectComplete();
826 ExpectTunnelClose();
827 ReadFromServer("");
828 ExpectClientReset();
829 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
830}
831
832TEST_F(HTTPProxyTest, StopClient) {
833 SetupConnectComplete();
834 EXPECT_CALL(sockets(), Close(kClientFD))
835 .WillOnce(Return(0));
836 EXPECT_CALL(sockets(), Close(kServerFD))
837 .WillOnce(Return(0));
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800838 ExpectRouteRelease();
Paul Stewartf65320c2011-10-13 14:34:52 -0700839 StopClient();
840 ExpectClientReset();
841 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
842}
843
844} // namespace shill