blob: 3457d4f0a54d0ffc221330f7280d0f0563a30824 [file] [log] [blame]
Peter Qiuc0beca52015-09-03 11:25:46 -07001//
2// Copyright (C) 2012 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
Paul Stewartf65320c2011-10-13 14:34:52 -070016
17#include "shill/http_proxy.h"
18
19#include <netinet/in.h>
20
Ben Chancd477322014-10-17 14:19:30 -070021#include <memory>
Paul Stewartf65320c2011-10-13 14:34:52 -070022#include <string>
23#include <vector>
24
Ben Chana0ddf462014-02-06 11:32:42 -080025#include <base/strings/stringprintf.h>
Paul Stewartf65320c2011-10-13 14:34:52 -070026#include <gtest/gtest.h>
27
Paul Stewartf65320c2011-10-13 14:34:52 -070028#include "shill/mock_async_connection.h"
Paul Stewartc8f4bef2011-12-13 09:45:51 -080029#include "shill/mock_connection.h"
30#include "shill/mock_control.h"
31#include "shill/mock_device_info.h"
Paul Stewartf65320c2011-10-13 14:34:52 -070032#include "shill/mock_dns_client.h"
33#include "shill/mock_event_dispatcher.h"
Peter Qiu8d6b5972014-10-28 15:33:34 -070034#include "shill/net/ip_address.h"
35#include "shill/net/mock_sockets.h"
Paul Stewartf65320c2011-10-13 14:34:52 -070036
37using base::StringPrintf;
38using std::string;
39using std::vector;
40using ::testing::_;
Alex Vakulenko3a62e232016-01-20 07:47:40 -080041using ::testing::AnyNumber;
Paul Stewartf65320c2011-10-13 14:34:52 -070042using ::testing::AtLeast;
43using ::testing::DoAll;
44using ::testing::Invoke;
Paul Stewartc8f4bef2011-12-13 09:45:51 -080045using ::testing::NiceMock;
Paul Stewartf65320c2011-10-13 14:34:52 -070046using ::testing::Return;
47using ::testing::ReturnArg;
48using ::testing::ReturnNew;
49using ::testing::ReturnRef;
50using ::testing::SetArgumentPointee;
51using ::testing::StrEq;
52using ::testing::StrictMock;
53using ::testing::Test;
54
55namespace shill {
56
57namespace {
Paul Stewart58a577b2012-01-10 11:18:52 -080058const char kBadHeaderMissingURL[] = "BLAH\r\n";
59const char kBadHeaderMissingVersion[] = "BLAH http://hostname\r\n";
Paul Stewartf65320c2011-10-13 14:34:52 -070060const char kBadHostnameLine[] = "GET HTTP/1.1 http://hostname\r\n";
61const char kBasicGetHeader[] = "GET / HTTP/1.1\r\n";
62const char kBasicGetHeaderWithURL[] =
63 "GET http://www.chromium.org/ HTTP/1.1\r\n";
64const char kBasicGetHeaderWithURLNoTrailingSlash[] =
65 "GET http://www.chromium.org HTTP/1.1\r\n";
Paul Stewart58a577b2012-01-10 11:18:52 -080066const char kConnectQuery[] =
67 "CONNECT 10.10.10.10:443 HTTP/1.1\r\n"
68 "Host: 10.10.10.10:443\r\n\r\n";
Paul Stewartf65320c2011-10-13 14:34:52 -070069const char kQueryTemplate[] = "GET %s HTTP/%s\r\n%s"
70 "User-Agent: Mozilla/5.0 (X11; CrOS i686 1299.0.2011) "
71 "AppleWebKit/535.8 (KHTML, like Gecko) Chrome/17.0.936.0 Safari/535.8\r\n"
72 "Accept: text/html,application/xhtml+xml,application/xml;"
73 "q=0.9,*/*;q=0.8\r\n"
74 "Accept-Encoding: gzip,deflate,sdch\r\n"
75 "Accept-Language: en-US,en;q=0.8,ja;q=0.6\r\n"
76 "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n"
77 "Cookie: PREF=ID=xxxxxxxxxxxxxxxx:U=xxxxxxxxxxxxxxxx:FF=0:"
78 "TM=1317340083:LM=1317390705:GM=1:S=_xxxxxxxxxxxxxxx; "
79 "NID=52=xxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
80 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxx; "
81 "HSID=xxxxxxxxxxxx-xxxx; APISID=xxxxxxxxxxxxxxxx/xxxxxxxxxxxxxxxxx; "
82 "SID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_xxxxxxxxxxx"
83 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxx"
84 "xxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxx"
85 "_xxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxx-xx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
86 "xxxxxxxxxxxxxxxx\r\n\r\n";
87const char kInterfaceName[] = "int0";
88const char kDNSServer0[] = "8.8.8.8";
89const char kDNSServer1[] = "8.8.4.4";
90const char kServerAddress[] = "10.10.10.10";
Paul Stewart3b30ca52015-06-16 13:13:10 -070091const char* kDNSServers[] = { kDNSServer0, kDNSServer1 };
Paul Stewartf65320c2011-10-13 14:34:52 -070092const int kProxyFD = 10203;
93const int kServerFD = 10204;
94const int kClientFD = 10205;
95const int kServerPort = 40506;
Paul Stewart58a577b2012-01-10 11:18:52 -080096const int kConnectPort = 443;
Alex Vakulenko8a532292014-06-16 17:18:44 -070097} // namespace
Paul Stewartf65320c2011-10-13 14:34:52 -070098
99MATCHER_P(IsIPAddress, address, "") {
100 IPAddress ip_address(IPAddress::kFamilyIPv4);
101 EXPECT_TRUE(ip_address.SetAddressFromString(address));
102 return ip_address.Equals(arg);
103}
104
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500105MATCHER_P(CallbackEq, callback, "") {
106 return arg.Equals(callback);
107}
108
Paul Stewartf65320c2011-10-13 14:34:52 -0700109class HTTPProxyTest : public Test {
110 public:
111 HTTPProxyTest()
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800112 : interface_name_(kInterfaceName),
Ben Chancc225ef2014-09-30 13:26:51 -0700113 server_async_connection_(nullptr),
Paul Stewartf65320c2011-10-13 14:34:52 -0700114 dns_servers_(kDNSServers, kDNSServers + 2),
Ben Chancc225ef2014-09-30 13:26:51 -0700115 dns_client_(nullptr),
116 device_info_(
117 new NiceMock<MockDeviceInfo>(&control_, nullptr, nullptr, nullptr)),
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800118 connection_(new StrictMock<MockConnection>(device_info_.get())),
Ben Chancc225ef2014-09-30 13:26:51 -0700119 proxy_(connection_) {}
Alex Vakulenko8a532292014-06-16 17:18:44 -0700120
Paul Stewartf65320c2011-10-13 14:34:52 -0700121 protected:
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800122 virtual void SetUp() {
123 EXPECT_CALL(*connection_.get(), interface_name())
124 .WillRepeatedly(ReturnRef(interface_name_));
125 EXPECT_CALL(*connection_.get(), dns_servers())
126 .WillRepeatedly(ReturnRef(dns_servers_));
127 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700128 virtual void TearDown() {
129 if (proxy_.sockets_) {
130 ExpectStop();
131 }
mukesh agrawal7efde5b2013-05-08 11:36:58 -0700132 const int proxy_fds[] = {
133 proxy_.client_socket_,
134 proxy_.server_socket_,
135 proxy_.proxy_socket_
136 };
137 for (const int fd : proxy_fds) {
138 if (fd != -1) {
139 EXPECT_CALL(sockets_, Close(fd));
140 }
141 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700142 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700143 string CreateRequest(const string& url, const string& http_version,
144 const string& extra_lines) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700145 string append_lines(extra_lines);
146 if (append_lines.size()) {
147 append_lines.append("\r\n");
148 }
149 return StringPrintf(kQueryTemplate, url.c_str(), http_version.c_str(),
150 append_lines.c_str());
151 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700152 int InvokeGetSockName(int fd, struct sockaddr* addr_out,
153 socklen_t* sockaddr_size) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700154 struct sockaddr_in addr;
155 EXPECT_EQ(kProxyFD, fd);
156 EXPECT_GE(sizeof(sockaddr_in), *sockaddr_size);
157 addr.sin_addr.s_addr = 0;
158 addr.sin_port = kServerPort;
159 memcpy(addr_out, &addr, sizeof(addr));
160 *sockaddr_size = sizeof(sockaddr_in);
161 return 0;
162 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700163 void InvokeSyncConnect(const IPAddress& /*address*/, int /*port*/) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700164 proxy_.OnConnectCompletion(true, kServerFD);
165 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700166 size_t FindInRequest(const string& find_string) {
167 const ByteString& request_data = GetClientData();
Paul Stewartf65320c2011-10-13 14:34:52 -0700168 string request_string(
Paul Stewart3b30ca52015-06-16 13:13:10 -0700169 reinterpret_cast<const char*>(request_data.GetConstData()),
Paul Stewartf65320c2011-10-13 14:34:52 -0700170 request_data.GetLength());
171 return request_string.find(find_string);
172 }
173 // Accessors
Paul Stewart3b30ca52015-06-16 13:13:10 -0700174 const ByteString& GetClientData() {
Paul Stewartf65320c2011-10-13 14:34:52 -0700175 return proxy_.client_data_;
176 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700177 HTTPProxy* proxy() { return &proxy_; }
Paul Stewartf65320c2011-10-13 14:34:52 -0700178 HTTPProxy::State GetProxyState() {
179 return proxy_.state_;
180 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700181 const ByteString& GetServerData() {
Paul Stewartf65320c2011-10-13 14:34:52 -0700182 return proxy_.server_data_;
183 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700184 MockSockets& sockets() { return sockets_; }
185 MockEventDispatcher& dispatcher() { return dispatcher_; }
Paul Stewartf65320c2011-10-13 14:34:52 -0700186
187
188 // Expectations
189 void ExpectClientReset() {
190 EXPECT_EQ(-1, proxy_.client_socket_);
191 EXPECT_TRUE(proxy_.client_version_.empty());
192 EXPECT_EQ(HTTPProxy::kDefaultServerPort, proxy_.server_port_);
193 EXPECT_EQ(-1, proxy_.server_socket_);
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500194 EXPECT_TRUE(proxy_.idle_timeout_.IsCancelled());
Paul Stewartf65320c2011-10-13 14:34:52 -0700195 EXPECT_TRUE(proxy_.client_headers_.empty());
196 EXPECT_TRUE(proxy_.server_hostname_.empty());
197 EXPECT_TRUE(proxy_.client_data_.IsEmpty());
198 EXPECT_TRUE(proxy_.server_data_.IsEmpty());
199 EXPECT_FALSE(proxy_.read_client_handler_.get());
200 EXPECT_FALSE(proxy_.write_client_handler_.get());
201 EXPECT_FALSE(proxy_.read_server_handler_.get());
202 EXPECT_FALSE(proxy_.write_server_handler_.get());
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800203 EXPECT_FALSE(proxy_.is_route_requested_);
Paul Stewartf65320c2011-10-13 14:34:52 -0700204 }
205 void ExpectReset() {
206 EXPECT_FALSE(proxy_.accept_handler_.get());
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800207 EXPECT_EQ(proxy_.connection_.get(), connection_.get());
Paul Stewartf65320c2011-10-13 14:34:52 -0700208 EXPECT_FALSE(proxy_.dispatcher_);
209 EXPECT_FALSE(proxy_.dns_client_.get());
210 EXPECT_EQ(-1, proxy_.proxy_port_);
211 EXPECT_EQ(-1, proxy_.proxy_socket_);
212 EXPECT_FALSE(proxy_.server_async_connection_.get());
213 EXPECT_FALSE(proxy_.sockets_);
214 EXPECT_EQ(HTTPProxy::kStateIdle, proxy_.state_);
215 ExpectClientReset();
216 }
217 void ExpectStart() {
218 EXPECT_CALL(sockets(), Socket(_, _, _))
219 .WillOnce(Return(kProxyFD));
220 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
221 .WillOnce(Return(0));
222 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
223 .WillOnce(Invoke(this, &HTTPProxyTest::InvokeGetSockName));
224 EXPECT_CALL(sockets(), SetNonBlocking(kProxyFD))
225 .WillOnce(Return(0));
226 EXPECT_CALL(sockets(), Listen(kProxyFD, _))
227 .WillOnce(Return(0));
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500228 EXPECT_CALL(dispatcher_,
229 CreateReadyHandler(kProxyFD,
230 IOHandler::kModeInput,
231 CallbackEq(proxy_.accept_callback_)))
Paul Stewartf65320c2011-10-13 14:34:52 -0700232 .WillOnce(ReturnNew<IOHandler>());
233 }
234 void ExpectStop() {
235 if (dns_client_) {
236 EXPECT_CALL(*dns_client_, Stop())
237 .Times(AtLeast(1));
238 }
239 if (server_async_connection_) {
240 EXPECT_CALL(*server_async_connection_, Stop())
241 .Times(AtLeast(1));
242 }
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800243 if (proxy_.is_route_requested_) {
244 EXPECT_CALL(*connection_.get(), ReleaseRouting());
245 }
Alex Vakulenko8a532292014-06-16 17:18:44 -0700246 }
247 void ExpectClientInput(int fd) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700248 EXPECT_CALL(sockets(), Accept(kProxyFD, _, _))
249 .WillOnce(Return(fd));
250 EXPECT_CALL(sockets(), SetNonBlocking(fd))
251 .WillOnce(Return(0));
252 EXPECT_CALL(dispatcher(),
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500253 CreateInputHandler(fd,
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800254 CallbackEq(proxy_.read_client_callback_), _))
Paul Stewartf65320c2011-10-13 14:34:52 -0700255 .WillOnce(ReturnNew<IOHandler>());
256 ExpectTransactionTimeout();
257 ExpectClientHeaderTimeout();
258 }
259 void ExpectTimeout(int timeout) {
Alex Vakulenko3a62e232016-01-20 07:47:40 -0800260 EXPECT_CALL(dispatcher_, PostDelayedTask(_, timeout * 1000));
Paul Stewartf65320c2011-10-13 14:34:52 -0700261 }
262 void ExpectClientHeaderTimeout() {
263 ExpectTimeout(HTTPProxy::kClientHeaderTimeoutSeconds);
264 }
265 void ExpectConnectTimeout() {
266 ExpectTimeout(HTTPProxy::kConnectTimeoutSeconds);
267 }
268 void ExpectInputTimeout() {
269 ExpectTimeout(HTTPProxy::kInputTimeoutSeconds);
270 }
271 void ExpectRepeatedInputTimeout() {
272 EXPECT_CALL(dispatcher_,
273 PostDelayedTask(_, HTTPProxy::kInputTimeoutSeconds * 1000))
Alex Vakulenko3a62e232016-01-20 07:47:40 -0800274 .Times(AnyNumber());
Paul Stewartf65320c2011-10-13 14:34:52 -0700275 }
276 void ExpectTransactionTimeout() {
277 ExpectTimeout(HTTPProxy::kTransactionTimeoutSeconds);
278 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700279 void ExpectInClientResponse(const string& response_data) {
280 string server_data(reinterpret_cast<char*>(proxy_.server_data_.GetData()),
Paul Stewart58a577b2012-01-10 11:18:52 -0800281 proxy_.server_data_.GetLength());
282 EXPECT_NE(string::npos, server_data.find(response_data));
283 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700284 void ExpectClientError(int code, const string& error) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700285 EXPECT_EQ(HTTPProxy::kStateFlushResponse, GetProxyState());
286 string status_line = StringPrintf("HTTP/1.1 %d ERROR", code);
Paul Stewart58a577b2012-01-10 11:18:52 -0800287 ExpectInClientResponse(status_line);
288 ExpectInClientResponse(error);
Paul Stewartf65320c2011-10-13 14:34:52 -0700289 }
290 void ExpectClientInternalError() {
291 ExpectClientError(500, HTTPProxy::kInternalErrorMsg);
292 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700293 void ExpectClientVersion(const string& version) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700294 EXPECT_EQ(version, proxy_.client_version_);
295 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700296 void ExpectServerHostname(const string& hostname) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700297 EXPECT_EQ(hostname, proxy_.server_hostname_);
298 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700299 void ExpectFirstLine(const string& line) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700300 EXPECT_EQ(line, proxy_.client_headers_[0] + "\r\n");
301 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700302 void ExpectDNSRequest(const string& host, bool return_value) {
Paul Stewartbdb02e62012-02-22 16:24:33 -0800303 EXPECT_CALL(*dns_client_, Start(StrEq(host), _))
Paul Stewartf65320c2011-10-13 14:34:52 -0700304 .WillOnce(Return(return_value));
305 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700306 void ExpectAsyncConnect(const string& address, int port,
Paul Stewartf65320c2011-10-13 14:34:52 -0700307 bool return_value) {
308 EXPECT_CALL(*server_async_connection_, Start(IsIPAddress(address), port))
309 .WillOnce(Return(return_value));
310 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700311 void ExpectSyncConnect(const string& address, int port) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700312 EXPECT_CALL(*server_async_connection_, Start(IsIPAddress(address), port))
313 .WillOnce(DoAll(Invoke(this, &HTTPProxyTest::InvokeSyncConnect),
314 Return(true)));
315 }
Paul Stewart58a577b2012-01-10 11:18:52 -0800316 void ExpectClientData() {
Paul Stewartf65320c2011-10-13 14:34:52 -0700317 EXPECT_CALL(dispatcher(),
318 CreateReadyHandler(kClientFD,
319 IOHandler::kModeOutput,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500320 CallbackEq(proxy_.write_client_callback_)))
Paul Stewartf65320c2011-10-13 14:34:52 -0700321 .WillOnce(ReturnNew<IOHandler>());
Paul Stewart58a577b2012-01-10 11:18:52 -0800322 }
323 void ExpectClientResult() {
324 ExpectClientData();
Paul Stewartf65320c2011-10-13 14:34:52 -0700325 ExpectInputTimeout();
326 }
327 void ExpectServerInput() {
328 EXPECT_CALL(dispatcher(),
329 CreateInputHandler(kServerFD,
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800330 CallbackEq(proxy_.read_server_callback_), _))
Paul Stewartf65320c2011-10-13 14:34:52 -0700331 .WillOnce(ReturnNew<IOHandler>());
332 ExpectInputTimeout();
333 }
334 void ExpectServerOutput() {
335 EXPECT_CALL(dispatcher(),
336 CreateReadyHandler(kServerFD,
337 IOHandler::kModeOutput,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500338 CallbackEq(proxy_.write_server_callback_)))
Paul Stewartf65320c2011-10-13 14:34:52 -0700339 .WillOnce(ReturnNew<IOHandler>());
340 ExpectInputTimeout();
341 }
342 void ExpectRepeatedServerOutput() {
343 EXPECT_CALL(dispatcher(),
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500344 CreateReadyHandler(kServerFD, IOHandler::kModeOutput,
345 CallbackEq(proxy_.write_server_callback_)))
Paul Stewartf65320c2011-10-13 14:34:52 -0700346 .WillOnce(ReturnNew<IOHandler>());
347 ExpectRepeatedInputTimeout();
348 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700349 void ExpectTunnelClose() {
350 EXPECT_CALL(sockets(), Close(kClientFD))
351 .WillOnce(Return(0));
352 EXPECT_CALL(sockets(), Close(kServerFD))
353 .WillOnce(Return(0));
354 ExpectStop();
355 }
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800356 void ExpectRouteRequest() {
357 EXPECT_CALL(*connection_.get(), RequestRouting());
358 }
359 void ExpectRouteRelease() {
360 EXPECT_CALL(*connection_.get(), ReleaseRouting());
361 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700362
363 // Callers for various private routines in the proxy
364 bool StartProxy() {
365 bool ret = proxy_.Start(&dispatcher_, &sockets_);
366 if (ret) {
367 dns_client_ = new StrictMock<MockDNSClient>();
368 // Passes ownership.
369 proxy_.dns_client_.reset(dns_client_);
370 server_async_connection_ = new StrictMock<MockAsyncConnection>();
371 // Passes ownership.
372 proxy_.server_async_connection_.reset(server_async_connection_);
373 }
374 return ret;
375 }
376 void AcceptClient(int fd) {
377 proxy_.AcceptClient(fd);
378 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700379 void GetDNSResultFailure(const string& error_msg) {
Paul Stewartbdb02e62012-02-22 16:24:33 -0800380 Error error(Error::kOperationFailed, error_msg);
381 IPAddress address(IPAddress::kFamilyUnknown);
382 proxy_.GetDNSResult(error, address);
383 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700384 void GetDNSResultSuccess(const IPAddress& address) {
Paul Stewartbdb02e62012-02-22 16:24:33 -0800385 Error error;
386 proxy_.GetDNSResult(error, address);
Paul Stewartf65320c2011-10-13 14:34:52 -0700387 }
388 void OnConnectCompletion(bool result, int sockfd) {
389 proxy_.OnConnectCompletion(result, sockfd);
390 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700391 void ReadFromClient(const string& data) {
392 const unsigned char* ptr =
393 reinterpret_cast<const unsigned char*>(data.c_str());
Paul Stewartf65320c2011-10-13 14:34:52 -0700394 vector<unsigned char> data_bytes(ptr, ptr + data.length());
395 InputData proxy_data(data_bytes.data(), data_bytes.size());
396 proxy_.ReadFromClient(&proxy_data);
397 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700398 void ReadFromServer(const string& data) {
399 const unsigned char* ptr =
400 reinterpret_cast<const unsigned char*>(data.c_str());
Paul Stewartf65320c2011-10-13 14:34:52 -0700401 vector<unsigned char> data_bytes(ptr, ptr + data.length());
402 InputData proxy_data(data_bytes.data(), data_bytes.size());
403 proxy_.ReadFromServer(&proxy_data);
404 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700405 void SendClientError(int code, const string& error) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700406 proxy_.SendClientError(code, error);
407 EXPECT_FALSE(proxy_.server_data_.IsEmpty());
408 }
409 void StopClient() {
410 EXPECT_CALL(*dns_client_, Stop());
411 EXPECT_CALL(*server_async_connection_, Stop());
412 proxy_.StopClient();
413 }
414 void StopProxy() {
415 ExpectStop();
416 proxy_.Stop();
Ben Chancc225ef2014-09-30 13:26:51 -0700417 server_async_connection_ = nullptr;
418 dns_client_ = nullptr;
Paul Stewartf65320c2011-10-13 14:34:52 -0700419 ExpectReset();
420 }
421 void WriteToClient(int fd) {
422 proxy_.WriteToClient(fd);
423 }
424 void WriteToServer(int fd) {
425 proxy_.WriteToServer(fd);
426 }
427
428 void SetupClient() {
429 ExpectStart();
430 ASSERT_TRUE(StartProxy());
431 ExpectClientInput(kClientFD);
432 AcceptClient(kProxyFD);
433 EXPECT_EQ(HTTPProxy::kStateReadClientHeader, GetProxyState());
434 }
Paul Stewart3b30ca52015-06-16 13:13:10 -0700435 void SetupConnectWithRequest(const string& url, const string& http_version,
436 const string& extra_lines) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700437 ExpectDNSRequest("www.chromium.org", true);
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800438 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700439 ReadFromClient(CreateRequest(url, http_version, extra_lines));
440 IPAddress addr(IPAddress::kFamilyIPv4);
441 EXPECT_TRUE(addr.SetAddressFromString(kServerAddress));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800442 GetDNSResultSuccess(addr);
Paul Stewartf65320c2011-10-13 14:34:52 -0700443 }
444 void SetupConnect() {
445 SetupConnectWithRequest("/", "1.1", "Host: www.chromium.org:40506");
446 }
447 void SetupConnectAsync() {
448 SetupClient();
449 ExpectAsyncConnect(kServerAddress, kServerPort, true);
450 ExpectConnectTimeout();
451 SetupConnect();
452 }
453 void SetupConnectComplete() {
454 SetupConnectAsync();
455 ExpectServerOutput();
456 OnConnectCompletion(true, kServerFD);
457 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
458 }
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800459 void CauseReadError() {
Peter Qiu3161caa2014-10-29 09:47:22 -0700460 proxy_.OnReadError(string());
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800461 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700462
463 private:
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800464 const string interface_name_;
Paul Stewartf65320c2011-10-13 14:34:52 -0700465 // Owned by the HTTPProxy, but tracked here for EXPECT().
Paul Stewart3b30ca52015-06-16 13:13:10 -0700466 StrictMock<MockAsyncConnection>* server_async_connection_;
Paul Stewartf65320c2011-10-13 14:34:52 -0700467 vector<string> dns_servers_;
468 // Owned by the HTTPProxy, but tracked here for EXPECT().
Paul Stewart3b30ca52015-06-16 13:13:10 -0700469 StrictMock<MockDNSClient>* dns_client_;
Paul Stewartf65320c2011-10-13 14:34:52 -0700470 MockEventDispatcher dispatcher_;
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800471 MockControl control_;
Ben Chancd477322014-10-17 14:19:30 -0700472 std::unique_ptr<MockDeviceInfo> device_info_;
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800473 scoped_refptr<MockConnection> connection_;
Paul Stewartf65320c2011-10-13 14:34:52 -0700474 StrictMock<MockSockets> sockets_;
mukesh agrawal7efde5b2013-05-08 11:36:58 -0700475 HTTPProxy proxy_; // Destroy first, before anything it references.
Paul Stewartf65320c2011-10-13 14:34:52 -0700476};
477
478TEST_F(HTTPProxyTest, StartFailSocket) {
479 EXPECT_CALL(sockets(), Socket(_, _, _))
480 .WillOnce(Return(-1));
481 EXPECT_FALSE(StartProxy());
482 ExpectReset();
483}
484
485TEST_F(HTTPProxyTest, StartFailBind) {
486 EXPECT_CALL(sockets(), Socket(_, _, _))
487 .WillOnce(Return(kProxyFD));
488 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
489 .WillOnce(Return(-1));
490 EXPECT_CALL(sockets(), Close(kProxyFD))
491 .WillOnce(Return(0));
492 EXPECT_FALSE(StartProxy());
493 ExpectReset();
494}
495
496TEST_F(HTTPProxyTest, StartFailGetSockName) {
497 EXPECT_CALL(sockets(), Socket(_, _, _))
498 .WillOnce(Return(kProxyFD));
499 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
500 .WillOnce(Return(0));
501 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
502 .WillOnce(Return(-1));
503 EXPECT_CALL(sockets(), Close(kProxyFD))
504 .WillOnce(Return(0));
505 EXPECT_FALSE(StartProxy());
506 ExpectReset();
507}
508
509TEST_F(HTTPProxyTest, StartFailSetNonBlocking) {
510 EXPECT_CALL(sockets(), Socket(_, _, _))
511 .WillOnce(Return(kProxyFD));
512 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
513 .WillOnce(Return(0));
514 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
515 .WillOnce(Return(0));
516 EXPECT_CALL(sockets(), SetNonBlocking(kProxyFD))
517 .WillOnce(Return(-1));
518 EXPECT_CALL(sockets(), Close(kProxyFD))
519 .WillOnce(Return(0));
520 EXPECT_FALSE(StartProxy());
521 ExpectReset();
522}
523
524TEST_F(HTTPProxyTest, StartFailListen) {
525 EXPECT_CALL(sockets(), Socket(_, _, _))
526 .WillOnce(Return(kProxyFD));
527 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
528 .WillOnce(Return(0));
529 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
530 .WillOnce(Return(0));
531 EXPECT_CALL(sockets(), SetNonBlocking(kProxyFD))
532 .WillOnce(Return(0));
533 EXPECT_CALL(sockets(), Listen(kProxyFD, _))
534 .WillOnce(Return(-1));
535 EXPECT_CALL(sockets(), Close(kProxyFD))
536 .WillOnce(Return(0));
537 EXPECT_FALSE(StartProxy());
538 ExpectReset();
539}
540
541TEST_F(HTTPProxyTest, StartSuccess) {
542 ExpectStart();
543 EXPECT_TRUE(StartProxy());
544}
545
546TEST_F(HTTPProxyTest, SendClientError) {
547 SetupClient();
548 ExpectClientResult();
549 SendClientError(500, "This is an error");
550 ExpectClientError(500, "This is an error");
551
552 // We succeed in sending all but one byte of the client response.
553 int buf_len = GetServerData().GetLength();
554 EXPECT_CALL(sockets(), Send(kClientFD, _, buf_len, 0))
555 .WillOnce(Return(buf_len - 1));
556 ExpectInputTimeout();
557 WriteToClient(kClientFD);
558 EXPECT_EQ(1, GetServerData().GetLength());
559 EXPECT_EQ(HTTPProxy::kStateFlushResponse, GetProxyState());
560
561 // When we are able to send the last byte, we close the connection.
562 EXPECT_CALL(sockets(), Send(kClientFD, _, 1, 0))
563 .WillOnce(Return(1));
564 EXPECT_CALL(sockets(), Close(kClientFD))
565 .WillOnce(Return(0));
566 ExpectStop();
567 WriteToClient(kClientFD);
568 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
569}
570
Paul Stewart58a577b2012-01-10 11:18:52 -0800571TEST_F(HTTPProxyTest, ReadMissingURL) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700572 SetupClient();
573 ExpectClientResult();
Paul Stewart58a577b2012-01-10 11:18:52 -0800574 ReadFromClient(kBadHeaderMissingURL);
575 ExpectClientError(501, "Server could not parse HTTP method");
576}
577
578TEST_F(HTTPProxyTest, ReadMissingVersion) {
579 SetupClient();
580 ExpectClientResult();
581 ReadFromClient(kBadHeaderMissingVersion);
Paul Stewartf65320c2011-10-13 14:34:52 -0700582 ExpectClientError(501, "Server only accepts HTTP/1.x requests");
583}
584
585TEST_F(HTTPProxyTest, ReadBadHostname) {
586 SetupClient();
587 ExpectClientResult();
588 ReadFromClient(kBadHostnameLine);
589 ExpectClientInternalError();
590}
591
592TEST_F(HTTPProxyTest, GoodFirstLineWithoutURL) {
593 SetupClient();
594 ExpectClientHeaderTimeout();
595 ReadFromClient(kBasicGetHeader);
596 ExpectClientVersion("1.1");
597 ExpectServerHostname("");
598 ExpectFirstLine(kBasicGetHeader);
599}
600
601TEST_F(HTTPProxyTest, GoodFirstLineWithURL) {
602 SetupClient();
603 ExpectClientHeaderTimeout();
604 ReadFromClient(kBasicGetHeaderWithURL);
605 ExpectClientVersion("1.1");
606 ExpectServerHostname("www.chromium.org");
607 ExpectFirstLine(kBasicGetHeader);
608}
609
610TEST_F(HTTPProxyTest, GoodFirstLineWithURLNoSlash) {
611 SetupClient();
612 ExpectClientHeaderTimeout();
613 ReadFromClient(kBasicGetHeaderWithURLNoTrailingSlash);
614 ExpectClientVersion("1.1");
615 ExpectServerHostname("www.chromium.org");
616 ExpectFirstLine(kBasicGetHeader);
617}
618
619TEST_F(HTTPProxyTest, NoHostInRequest) {
620 SetupClient();
621 ExpectClientResult();
622 ReadFromClient(CreateRequest("/", "1.1", ""));
623 ExpectClientError(400, "I don't know what host you want me to connect to");
624}
625
626TEST_F(HTTPProxyTest, TooManyColonsInHost) {
627 SetupClient();
628 ExpectClientResult();
629 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:80:40506"));
630 ExpectClientError(400, "Too many colons in hostname");
631}
632
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800633TEST_F(HTTPProxyTest, ClientReadError) {
634 SetupClient();
635 EXPECT_CALL(sockets(), Close(kClientFD))
636 .WillOnce(Return(0));
637 ExpectStop();
638 CauseReadError();
639 ExpectClientReset();
640}
641
Paul Stewartf65320c2011-10-13 14:34:52 -0700642TEST_F(HTTPProxyTest, DNSRequestFailure) {
643 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800644 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700645 ExpectDNSRequest("www.chromium.org", false);
646 ExpectClientResult();
647 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506"));
648 ExpectClientError(502, "Could not resolve hostname");
649}
650
651TEST_F(HTTPProxyTest, DNSRequestDelayedFailure) {
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 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506"));
656 ExpectClientResult();
657 const std::string not_found_error(DNSClient::kErrorNotFound);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800658 GetDNSResultFailure(not_found_error);
Paul Stewartf65320c2011-10-13 14:34:52 -0700659 ExpectClientError(502, string("Could not resolve hostname: ") +
660 not_found_error);
661}
662
663TEST_F(HTTPProxyTest, TrailingClientData) {
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 const string trailing_data("Trailing client data");
668 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506") +
669 trailing_data);
670 EXPECT_EQ(GetClientData().GetLength() - trailing_data.length(),
671 FindInRequest(trailing_data));
672 EXPECT_EQ(HTTPProxy::kStateLookupServer, GetProxyState());
673}
674
675TEST_F(HTTPProxyTest, LineContinuation) {
676 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800677 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700678 ExpectDNSRequest("www.chromium.org", true);
679 string text_to_keep("X-Long-Header: this is one line\r\n"
680 "\tand this is another");
681 ReadFromClient(CreateRequest("http://www.chromium.org/", "1.1",
682 text_to_keep));
683 EXPECT_NE(string::npos, FindInRequest(text_to_keep));
684}
685
686// NB: This tests two different things:
687// 1) That the system replaces the value for "Proxy-Connection" headers.
688// 2) That when it replaces a header, it also removes the text in the line
689// continuation.
690TEST_F(HTTPProxyTest, LineContinuationRemoval) {
691 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800692 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700693 ExpectDNSRequest("www.chromium.org", true);
694 string text_to_remove("remove this text please");
695 ReadFromClient(CreateRequest("http://www.chromium.org/", "1.1",
696 string("Proxy-Connection: stuff\r\n\t") +
697 text_to_remove));
698 EXPECT_EQ(string::npos, FindInRequest(text_to_remove));
699 EXPECT_NE(string::npos, FindInRequest("Proxy-Connection: close\r\n"));
700}
701
702TEST_F(HTTPProxyTest, ConnectSynchronousFailure) {
703 SetupClient();
704 ExpectAsyncConnect(kServerAddress, kServerPort, false);
705 ExpectClientResult();
706 SetupConnect();
707 ExpectClientError(500, "Could not create socket to connect to server");
708}
709
710TEST_F(HTTPProxyTest, ConnectAsyncConnectFailure) {
711 SetupConnectAsync();
712 ExpectClientResult();
713 OnConnectCompletion(false, -1);
714 ExpectClientError(500, "Socket connection delayed failure");
715}
716
717TEST_F(HTTPProxyTest, ConnectSynchronousSuccess) {
718 SetupClient();
719 ExpectSyncConnect(kServerAddress, 999);
720 ExpectRepeatedServerOutput();
721 SetupConnectWithRequest("/", "1.1", "Host: www.chromium.org:999");
722 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
723}
724
725TEST_F(HTTPProxyTest, ConnectIPAddresss) {
726 SetupClient();
727 ExpectSyncConnect(kServerAddress, 999);
728 ExpectRepeatedServerOutput();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800729 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700730 ReadFromClient(CreateRequest("/", "1.1",
731 StringPrintf("Host: %s:999", kServerAddress)));
732 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
733}
734
735TEST_F(HTTPProxyTest, ConnectAsyncConnectSuccess) {
736 SetupConnectComplete();
737}
738
Paul Stewart58a577b2012-01-10 11:18:52 -0800739TEST_F(HTTPProxyTest, HTTPConnectMethod) {
740 SetupClient();
741 ExpectAsyncConnect(kServerAddress, kConnectPort, true);
742 ExpectConnectTimeout();
743 ExpectRouteRequest();
744 ReadFromClient(kConnectQuery);
745 ExpectRepeatedInputTimeout();
746 ExpectClientData();
747 OnConnectCompletion(true, kServerFD);
748 ExpectInClientResponse("HTTP/1.1 200 OK\r\n\r\n");
749}
750
Paul Stewartf65320c2011-10-13 14:34:52 -0700751TEST_F(HTTPProxyTest, TunnelData) {
752 SetupConnectComplete();
753
754 // The proxy is waiting for the server to be ready to accept data.
755 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
756 .WillOnce(Return(10));
757 ExpectServerInput();
758 WriteToServer(kServerFD);
759 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
760 .WillOnce(ReturnArg<2>());
761 ExpectInputTimeout();
762 WriteToServer(kServerFD);
763 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
764
765 // Tunnel a reply back to the client.
766 const string server_result("200 OK ... and so on");
767 ExpectClientResult();
768 ReadFromServer(server_result);
769 EXPECT_EQ(server_result,
Paul Stewart3b30ca52015-06-16 13:13:10 -0700770 string(reinterpret_cast<const char*>(
Paul Stewartf65320c2011-10-13 14:34:52 -0700771 GetServerData().GetConstData()),
772 GetServerData().GetLength()));
773
774 // Allow part of the result string to be sent to the client.
775 const int part = server_result.length() / 2;
776 EXPECT_CALL(sockets(), Send(kClientFD, _, server_result.length(), 0))
777 .WillOnce(Return(part));
778 ExpectInputTimeout();
779 WriteToClient(kClientFD);
780 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
781
782 // The Server closes the connection while the client is still reading.
783 ExpectInputTimeout();
784 ReadFromServer("");
785 EXPECT_EQ(HTTPProxy::kStateFlushResponse, GetProxyState());
786
787 // When the last part of the response is written to the client, we close
788 // all connections.
789 EXPECT_CALL(sockets(), Send(kClientFD, _, server_result.length() - part, 0))
790 .WillOnce(ReturnArg<2>());
791 ExpectTunnelClose();
792 WriteToClient(kClientFD);
793 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
794}
795
796TEST_F(HTTPProxyTest, TunnelDataFailWriteClient) {
797 SetupConnectComplete();
798 EXPECT_CALL(sockets(), Send(kClientFD, _, _, 0))
799 .WillOnce(Return(-1));
800 ExpectTunnelClose();
801 WriteToClient(kClientFD);
802 ExpectClientReset();
803 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
804}
805
806TEST_F(HTTPProxyTest, TunnelDataFailWriteServer) {
807 SetupConnectComplete();
808 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
809 .WillOnce(Return(-1));
810 ExpectTunnelClose();
811 WriteToServer(kServerFD);
812 ExpectClientReset();
813 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
814}
815
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800816TEST_F(HTTPProxyTest, TunnelDataFailReadServer) {
817 SetupConnectComplete();
818 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
819 .WillOnce(Return(10));
820 ExpectServerInput();
821 WriteToServer(kServerFD);
822 ExpectTunnelClose();
823 CauseReadError();
824 ExpectClientReset();
825 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
826}
827
Paul Stewartf65320c2011-10-13 14:34:52 -0700828TEST_F(HTTPProxyTest, TunnelDataFailClientClose) {
829 SetupConnectComplete();
830 ExpectTunnelClose();
831 ReadFromClient("");
832 ExpectClientReset();
833 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
834}
835
836TEST_F(HTTPProxyTest, TunnelDataFailServerClose) {
837 SetupConnectComplete();
838 ExpectTunnelClose();
839 ReadFromServer("");
840 ExpectClientReset();
841 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
842}
843
844TEST_F(HTTPProxyTest, StopClient) {
845 SetupConnectComplete();
846 EXPECT_CALL(sockets(), Close(kClientFD))
847 .WillOnce(Return(0));
848 EXPECT_CALL(sockets(), Close(kServerFD))
849 .WillOnce(Return(0));
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800850 ExpectRouteRelease();
Paul Stewartf65320c2011-10-13 14:34:52 -0700851 StopClient();
852 ExpectClientReset();
853 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
854}
855
856} // namespace shill