blob: 6fba3f7dc7f46c1a1579ffb77f995ffacb65b16a [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
91class HTTPProxyTest : public Test {
92 public:
93 HTTPProxyTest()
Paul Stewartc8f4bef2011-12-13 09:45:51 -080094 : interface_name_(kInterfaceName),
95 server_async_connection_(NULL),
Paul Stewartf65320c2011-10-13 14:34:52 -070096 dns_servers_(kDNSServers, kDNSServers + 2),
97 dns_client_(NULL),
Paul Stewartc8f4bef2011-12-13 09:45:51 -080098 device_info_(new NiceMock<MockDeviceInfo>(
99 &control_,
100 reinterpret_cast<EventDispatcher*>(NULL),
Thieu Le3426c8f2012-01-11 17:35:11 -0800101 reinterpret_cast<Metrics*>(NULL),
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800102 reinterpret_cast<Manager*>(NULL))),
103 connection_(new StrictMock<MockConnection>(device_info_.get())),
104 proxy_(connection_) { }
Paul Stewartf65320c2011-10-13 14:34:52 -0700105 protected:
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800106 virtual void SetUp() {
107 EXPECT_CALL(*connection_.get(), interface_name())
108 .WillRepeatedly(ReturnRef(interface_name_));
109 EXPECT_CALL(*connection_.get(), dns_servers())
110 .WillRepeatedly(ReturnRef(dns_servers_));
111 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700112 virtual void TearDown() {
113 if (proxy_.sockets_) {
114 ExpectStop();
115 }
116 }
117 string CreateRequest(const string &url, const string &http_version,
118 const string &extra_lines) {
119 string append_lines(extra_lines);
120 if (append_lines.size()) {
121 append_lines.append("\r\n");
122 }
123 return StringPrintf(kQueryTemplate, url.c_str(), http_version.c_str(),
124 append_lines.c_str());
125 }
126 int InvokeGetSockName(int fd, struct sockaddr *addr_out,
127 socklen_t *sockaddr_size) {
128 struct sockaddr_in addr;
129 EXPECT_EQ(kProxyFD, fd);
130 EXPECT_GE(sizeof(sockaddr_in), *sockaddr_size);
131 addr.sin_addr.s_addr = 0;
132 addr.sin_port = kServerPort;
133 memcpy(addr_out, &addr, sizeof(addr));
134 *sockaddr_size = sizeof(sockaddr_in);
135 return 0;
136 }
137 void InvokeSyncConnect(const IPAddress &/*address*/, int /*port*/) {
138 proxy_.OnConnectCompletion(true, kServerFD);
139 }
140 size_t FindInRequest(const string &find_string) {
141 const ByteString &request_data = GetClientData();
142 string request_string(
143 reinterpret_cast<const char *>(request_data.GetConstData()),
144 request_data.GetLength());
145 return request_string.find(find_string);
146 }
147 // Accessors
148 const ByteString &GetClientData() {
149 return proxy_.client_data_;
150 }
151 HTTPProxy *proxy() { return &proxy_; }
152 HTTPProxy::State GetProxyState() {
153 return proxy_.state_;
154 }
155 const ByteString &GetServerData() {
156 return proxy_.server_data_;
157 }
158 MockSockets &sockets() { return sockets_; }
159 MockEventDispatcher &dispatcher() { return dispatcher_; }
160
161
162 // Expectations
163 void ExpectClientReset() {
164 EXPECT_EQ(-1, proxy_.client_socket_);
165 EXPECT_TRUE(proxy_.client_version_.empty());
166 EXPECT_EQ(HTTPProxy::kDefaultServerPort, proxy_.server_port_);
167 EXPECT_EQ(-1, proxy_.server_socket_);
168 EXPECT_FALSE(proxy_.idle_timeout_);
169 EXPECT_TRUE(proxy_.client_headers_.empty());
170 EXPECT_TRUE(proxy_.server_hostname_.empty());
171 EXPECT_TRUE(proxy_.client_data_.IsEmpty());
172 EXPECT_TRUE(proxy_.server_data_.IsEmpty());
173 EXPECT_FALSE(proxy_.read_client_handler_.get());
174 EXPECT_FALSE(proxy_.write_client_handler_.get());
175 EXPECT_FALSE(proxy_.read_server_handler_.get());
176 EXPECT_FALSE(proxy_.write_server_handler_.get());
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800177 EXPECT_FALSE(proxy_.is_route_requested_);
Paul Stewartf65320c2011-10-13 14:34:52 -0700178 }
179 void ExpectReset() {
180 EXPECT_FALSE(proxy_.accept_handler_.get());
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800181 EXPECT_EQ(proxy_.connection_.get(), connection_.get());
Paul Stewartf65320c2011-10-13 14:34:52 -0700182 EXPECT_FALSE(proxy_.dispatcher_);
183 EXPECT_FALSE(proxy_.dns_client_.get());
184 EXPECT_EQ(-1, proxy_.proxy_port_);
185 EXPECT_EQ(-1, proxy_.proxy_socket_);
186 EXPECT_FALSE(proxy_.server_async_connection_.get());
187 EXPECT_FALSE(proxy_.sockets_);
188 EXPECT_EQ(HTTPProxy::kStateIdle, proxy_.state_);
189 ExpectClientReset();
190 }
191 void ExpectStart() {
192 EXPECT_CALL(sockets(), Socket(_, _, _))
193 .WillOnce(Return(kProxyFD));
194 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
195 .WillOnce(Return(0));
196 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
197 .WillOnce(Invoke(this, &HTTPProxyTest::InvokeGetSockName));
198 EXPECT_CALL(sockets(), SetNonBlocking(kProxyFD))
199 .WillOnce(Return(0));
200 EXPECT_CALL(sockets(), Listen(kProxyFD, _))
201 .WillOnce(Return(0));
202 EXPECT_CALL(dispatcher_, CreateReadyHandler(kProxyFD,
203 IOHandler::kModeInput,
204 proxy_.accept_callback_.get()))
205 .WillOnce(ReturnNew<IOHandler>());
206 }
207 void ExpectStop() {
208 if (dns_client_) {
209 EXPECT_CALL(*dns_client_, Stop())
210 .Times(AtLeast(1));
211 }
212 if (server_async_connection_) {
213 EXPECT_CALL(*server_async_connection_, Stop())
214 .Times(AtLeast(1));
215 }
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800216 if (proxy_.is_route_requested_) {
217 EXPECT_CALL(*connection_.get(), ReleaseRouting());
218 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700219 }
220 void ExpectClientInput(int fd) {
221 EXPECT_CALL(sockets(), Accept(kProxyFD, _, _))
222 .WillOnce(Return(fd));
223 EXPECT_CALL(sockets(), SetNonBlocking(fd))
224 .WillOnce(Return(0));
225 EXPECT_CALL(dispatcher(),
226 CreateInputHandler(fd, proxy_.read_client_callback_.get()))
227 .WillOnce(ReturnNew<IOHandler>());
228 ExpectTransactionTimeout();
229 ExpectClientHeaderTimeout();
230 }
231 void ExpectTimeout(int timeout) {
232 EXPECT_CALL(dispatcher_, PostDelayedTask(_, timeout * 1000))
233 .WillOnce(Return(true));
234 }
235 void ExpectClientHeaderTimeout() {
236 ExpectTimeout(HTTPProxy::kClientHeaderTimeoutSeconds);
237 }
238 void ExpectConnectTimeout() {
239 ExpectTimeout(HTTPProxy::kConnectTimeoutSeconds);
240 }
241 void ExpectInputTimeout() {
242 ExpectTimeout(HTTPProxy::kInputTimeoutSeconds);
243 }
244 void ExpectRepeatedInputTimeout() {
245 EXPECT_CALL(dispatcher_,
246 PostDelayedTask(_, HTTPProxy::kInputTimeoutSeconds * 1000))
247 .WillRepeatedly(Return(true));
248 }
249 void ExpectTransactionTimeout() {
250 ExpectTimeout(HTTPProxy::kTransactionTimeoutSeconds);
251 }
Paul Stewart58a577b2012-01-10 11:18:52 -0800252 void ExpectInClientResponse(const string &response_data) {
253 string server_data(reinterpret_cast<char *>(proxy_.server_data_.GetData()),
254 proxy_.server_data_.GetLength());
255 EXPECT_NE(string::npos, server_data.find(response_data));
256 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700257 void ExpectClientError(int code, const string &error) {
258 EXPECT_EQ(HTTPProxy::kStateFlushResponse, GetProxyState());
259 string status_line = StringPrintf("HTTP/1.1 %d ERROR", code);
Paul Stewart58a577b2012-01-10 11:18:52 -0800260 ExpectInClientResponse(status_line);
261 ExpectInClientResponse(error);
Paul Stewartf65320c2011-10-13 14:34:52 -0700262 }
263 void ExpectClientInternalError() {
264 ExpectClientError(500, HTTPProxy::kInternalErrorMsg);
265 }
266 void ExpectClientVersion(const string &version) {
267 EXPECT_EQ(version, proxy_.client_version_);
268 }
269 void ExpectServerHostname(const string &hostname) {
270 EXPECT_EQ(hostname, proxy_.server_hostname_);
271 }
272 void ExpectFirstLine(const string &line) {
273 EXPECT_EQ(line, proxy_.client_headers_[0] + "\r\n");
274 }
275 void ExpectDNSRequest(const string &host, bool return_value) {
276 EXPECT_CALL(*dns_client_, Start(StrEq(host)))
277 .WillOnce(Return(return_value));
278 }
279 void ExpectDNSFailure(const string &error) {
280 EXPECT_CALL(*dns_client_, error())
281 .WillOnce(ReturnRef(error));
282 }
283 void ExpectAsyncConnect(const string &address, int port,
284 bool return_value) {
285 EXPECT_CALL(*server_async_connection_, Start(IsIPAddress(address), port))
286 .WillOnce(Return(return_value));
287 }
288 void ExpectSyncConnect(const string &address, int port) {
289 EXPECT_CALL(*server_async_connection_, Start(IsIPAddress(address), port))
290 .WillOnce(DoAll(Invoke(this, &HTTPProxyTest::InvokeSyncConnect),
291 Return(true)));
292 }
Paul Stewart58a577b2012-01-10 11:18:52 -0800293 void ExpectClientData() {
Paul Stewartf65320c2011-10-13 14:34:52 -0700294 EXPECT_CALL(dispatcher(),
295 CreateReadyHandler(kClientFD,
296 IOHandler::kModeOutput,
297 proxy_.write_client_callback_.get()))
298 .WillOnce(ReturnNew<IOHandler>());
Paul Stewart58a577b2012-01-10 11:18:52 -0800299 }
300 void ExpectClientResult() {
301 ExpectClientData();
Paul Stewartf65320c2011-10-13 14:34:52 -0700302 ExpectInputTimeout();
303 }
304 void ExpectServerInput() {
305 EXPECT_CALL(dispatcher(),
306 CreateInputHandler(kServerFD,
307 proxy_.read_server_callback_.get()))
308 .WillOnce(ReturnNew<IOHandler>());
309 ExpectInputTimeout();
310 }
311 void ExpectServerOutput() {
312 EXPECT_CALL(dispatcher(),
313 CreateReadyHandler(kServerFD,
314 IOHandler::kModeOutput,
315 proxy_.write_server_callback_.get()))
316 .WillOnce(ReturnNew<IOHandler>());
317 ExpectInputTimeout();
318 }
319 void ExpectRepeatedServerOutput() {
320 EXPECT_CALL(dispatcher(),
321 CreateReadyHandler(kServerFD,
322 IOHandler::kModeOutput,
323 proxy_.write_server_callback_.get()))
324 .WillOnce(ReturnNew<IOHandler>());
325 ExpectRepeatedInputTimeout();
326 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700327 void ExpectTunnelClose() {
328 EXPECT_CALL(sockets(), Close(kClientFD))
329 .WillOnce(Return(0));
330 EXPECT_CALL(sockets(), Close(kServerFD))
331 .WillOnce(Return(0));
332 ExpectStop();
333 }
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800334 void ExpectRouteRequest() {
335 EXPECT_CALL(*connection_.get(), RequestRouting());
336 }
337 void ExpectRouteRelease() {
338 EXPECT_CALL(*connection_.get(), ReleaseRouting());
339 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700340
341 // Callers for various private routines in the proxy
342 bool StartProxy() {
343 bool ret = proxy_.Start(&dispatcher_, &sockets_);
344 if (ret) {
345 dns_client_ = new StrictMock<MockDNSClient>();
346 // Passes ownership.
347 proxy_.dns_client_.reset(dns_client_);
348 server_async_connection_ = new StrictMock<MockAsyncConnection>();
349 // Passes ownership.
350 proxy_.server_async_connection_.reset(server_async_connection_);
351 }
352 return ret;
353 }
354 void AcceptClient(int fd) {
355 proxy_.AcceptClient(fd);
356 }
357 void GetDNSResult(bool result) {
358 proxy_.GetDNSResult(result);
359 }
360 void OnConnectCompletion(bool result, int sockfd) {
361 proxy_.OnConnectCompletion(result, sockfd);
362 }
363 void ReadFromClient(const string &data) {
364 const unsigned char *ptr =
365 reinterpret_cast<const unsigned char *>(data.c_str());
366 vector<unsigned char> data_bytes(ptr, ptr + data.length());
367 InputData proxy_data(data_bytes.data(), data_bytes.size());
368 proxy_.ReadFromClient(&proxy_data);
369 }
370 void ReadFromServer(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_.ReadFromServer(&proxy_data);
376 }
377 void SendClientError(int code, const string &error) {
378 proxy_.SendClientError(code, error);
379 EXPECT_FALSE(proxy_.server_data_.IsEmpty());
380 }
381 void StopClient() {
382 EXPECT_CALL(*dns_client_, Stop());
383 EXPECT_CALL(*server_async_connection_, Stop());
384 proxy_.StopClient();
385 }
386 void StopProxy() {
387 ExpectStop();
388 proxy_.Stop();
389 server_async_connection_ = NULL;
390 dns_client_ = NULL;
391 ExpectReset();
392 }
393 void WriteToClient(int fd) {
394 proxy_.WriteToClient(fd);
395 }
396 void WriteToServer(int fd) {
397 proxy_.WriteToServer(fd);
398 }
399
400 void SetupClient() {
401 ExpectStart();
402 ASSERT_TRUE(StartProxy());
403 ExpectClientInput(kClientFD);
404 AcceptClient(kProxyFD);
405 EXPECT_EQ(HTTPProxy::kStateReadClientHeader, GetProxyState());
406 }
407 void SetupConnectWithRequest(const string &url, const string &http_version,
408 const string &extra_lines) {
409 ExpectDNSRequest("www.chromium.org", true);
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800410 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700411 ReadFromClient(CreateRequest(url, http_version, extra_lines));
412 IPAddress addr(IPAddress::kFamilyIPv4);
413 EXPECT_TRUE(addr.SetAddressFromString(kServerAddress));
414 EXPECT_CALL(*dns_client_, address())
415 .WillOnce(ReturnRef(addr));;
416 GetDNSResult(true);
417 }
418 void SetupConnect() {
419 SetupConnectWithRequest("/", "1.1", "Host: www.chromium.org:40506");
420 }
421 void SetupConnectAsync() {
422 SetupClient();
423 ExpectAsyncConnect(kServerAddress, kServerPort, true);
424 ExpectConnectTimeout();
425 SetupConnect();
426 }
427 void SetupConnectComplete() {
428 SetupConnectAsync();
429 ExpectServerOutput();
430 OnConnectCompletion(true, kServerFD);
431 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
432 }
433
434 private:
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800435 const string interface_name_;
Paul Stewartf65320c2011-10-13 14:34:52 -0700436 // Owned by the HTTPProxy, but tracked here for EXPECT().
437 StrictMock<MockAsyncConnection> *server_async_connection_;
438 vector<string> dns_servers_;
439 // Owned by the HTTPProxy, but tracked here for EXPECT().
440 StrictMock<MockDNSClient> *dns_client_;
441 MockEventDispatcher dispatcher_;
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800442 MockControl control_;
443 scoped_ptr<MockDeviceInfo> device_info_;
444 scoped_refptr<MockConnection> connection_;
Paul Stewartf65320c2011-10-13 14:34:52 -0700445 HTTPProxy proxy_;
446 StrictMock<MockSockets> sockets_;
447};
448
449TEST_F(HTTPProxyTest, StartFailSocket) {
450 EXPECT_CALL(sockets(), Socket(_, _, _))
451 .WillOnce(Return(-1));
452 EXPECT_FALSE(StartProxy());
453 ExpectReset();
454}
455
456TEST_F(HTTPProxyTest, StartFailBind) {
457 EXPECT_CALL(sockets(), Socket(_, _, _))
458 .WillOnce(Return(kProxyFD));
459 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
460 .WillOnce(Return(-1));
461 EXPECT_CALL(sockets(), Close(kProxyFD))
462 .WillOnce(Return(0));
463 EXPECT_FALSE(StartProxy());
464 ExpectReset();
465}
466
467TEST_F(HTTPProxyTest, StartFailGetSockName) {
468 EXPECT_CALL(sockets(), Socket(_, _, _))
469 .WillOnce(Return(kProxyFD));
470 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
471 .WillOnce(Return(0));
472 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
473 .WillOnce(Return(-1));
474 EXPECT_CALL(sockets(), Close(kProxyFD))
475 .WillOnce(Return(0));
476 EXPECT_FALSE(StartProxy());
477 ExpectReset();
478}
479
480TEST_F(HTTPProxyTest, StartFailSetNonBlocking) {
481 EXPECT_CALL(sockets(), Socket(_, _, _))
482 .WillOnce(Return(kProxyFD));
483 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
484 .WillOnce(Return(0));
485 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
486 .WillOnce(Return(0));
487 EXPECT_CALL(sockets(), SetNonBlocking(kProxyFD))
488 .WillOnce(Return(-1));
489 EXPECT_CALL(sockets(), Close(kProxyFD))
490 .WillOnce(Return(0));
491 EXPECT_FALSE(StartProxy());
492 ExpectReset();
493}
494
495TEST_F(HTTPProxyTest, StartFailListen) {
496 EXPECT_CALL(sockets(), Socket(_, _, _))
497 .WillOnce(Return(kProxyFD));
498 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
499 .WillOnce(Return(0));
500 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
501 .WillOnce(Return(0));
502 EXPECT_CALL(sockets(), SetNonBlocking(kProxyFD))
503 .WillOnce(Return(0));
504 EXPECT_CALL(sockets(), Listen(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, StartSuccess) {
513 ExpectStart();
514 EXPECT_TRUE(StartProxy());
515}
516
517TEST_F(HTTPProxyTest, SendClientError) {
518 SetupClient();
519 ExpectClientResult();
520 SendClientError(500, "This is an error");
521 ExpectClientError(500, "This is an error");
522
523 // We succeed in sending all but one byte of the client response.
524 int buf_len = GetServerData().GetLength();
525 EXPECT_CALL(sockets(), Send(kClientFD, _, buf_len, 0))
526 .WillOnce(Return(buf_len - 1));
527 ExpectInputTimeout();
528 WriteToClient(kClientFD);
529 EXPECT_EQ(1, GetServerData().GetLength());
530 EXPECT_EQ(HTTPProxy::kStateFlushResponse, GetProxyState());
531
532 // When we are able to send the last byte, we close the connection.
533 EXPECT_CALL(sockets(), Send(kClientFD, _, 1, 0))
534 .WillOnce(Return(1));
535 EXPECT_CALL(sockets(), Close(kClientFD))
536 .WillOnce(Return(0));
537 ExpectStop();
538 WriteToClient(kClientFD);
539 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
540}
541
Paul Stewart58a577b2012-01-10 11:18:52 -0800542TEST_F(HTTPProxyTest, ReadMissingURL) {
Paul Stewartf65320c2011-10-13 14:34:52 -0700543 SetupClient();
544 ExpectClientResult();
Paul Stewart58a577b2012-01-10 11:18:52 -0800545 ReadFromClient(kBadHeaderMissingURL);
546 ExpectClientError(501, "Server could not parse HTTP method");
547}
548
549TEST_F(HTTPProxyTest, ReadMissingVersion) {
550 SetupClient();
551 ExpectClientResult();
552 ReadFromClient(kBadHeaderMissingVersion);
Paul Stewartf65320c2011-10-13 14:34:52 -0700553 ExpectClientError(501, "Server only accepts HTTP/1.x requests");
554}
555
556TEST_F(HTTPProxyTest, ReadBadHostname) {
557 SetupClient();
558 ExpectClientResult();
559 ReadFromClient(kBadHostnameLine);
560 ExpectClientInternalError();
561}
562
563TEST_F(HTTPProxyTest, GoodFirstLineWithoutURL) {
564 SetupClient();
565 ExpectClientHeaderTimeout();
566 ReadFromClient(kBasicGetHeader);
567 ExpectClientVersion("1.1");
568 ExpectServerHostname("");
569 ExpectFirstLine(kBasicGetHeader);
570}
571
572TEST_F(HTTPProxyTest, GoodFirstLineWithURL) {
573 SetupClient();
574 ExpectClientHeaderTimeout();
575 ReadFromClient(kBasicGetHeaderWithURL);
576 ExpectClientVersion("1.1");
577 ExpectServerHostname("www.chromium.org");
578 ExpectFirstLine(kBasicGetHeader);
579}
580
581TEST_F(HTTPProxyTest, GoodFirstLineWithURLNoSlash) {
582 SetupClient();
583 ExpectClientHeaderTimeout();
584 ReadFromClient(kBasicGetHeaderWithURLNoTrailingSlash);
585 ExpectClientVersion("1.1");
586 ExpectServerHostname("www.chromium.org");
587 ExpectFirstLine(kBasicGetHeader);
588}
589
590TEST_F(HTTPProxyTest, NoHostInRequest) {
591 SetupClient();
592 ExpectClientResult();
593 ReadFromClient(CreateRequest("/", "1.1", ""));
594 ExpectClientError(400, "I don't know what host you want me to connect to");
595}
596
597TEST_F(HTTPProxyTest, TooManyColonsInHost) {
598 SetupClient();
599 ExpectClientResult();
600 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:80:40506"));
601 ExpectClientError(400, "Too many colons in hostname");
602}
603
604TEST_F(HTTPProxyTest, DNSRequestFailure) {
605 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800606 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700607 ExpectDNSRequest("www.chromium.org", false);
608 ExpectClientResult();
609 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506"));
610 ExpectClientError(502, "Could not resolve hostname");
611}
612
613TEST_F(HTTPProxyTest, DNSRequestDelayedFailure) {
614 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800615 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700616 ExpectDNSRequest("www.chromium.org", true);
617 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506"));
618 ExpectClientResult();
619 const std::string not_found_error(DNSClient::kErrorNotFound);
620 ExpectDNSFailure(not_found_error);
621 GetDNSResult(false);
622 ExpectClientError(502, string("Could not resolve hostname: ") +
623 not_found_error);
624}
625
626TEST_F(HTTPProxyTest, TrailingClientData) {
627 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800628 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700629 ExpectDNSRequest("www.chromium.org", true);
630 const string trailing_data("Trailing client data");
631 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506") +
632 trailing_data);
633 EXPECT_EQ(GetClientData().GetLength() - trailing_data.length(),
634 FindInRequest(trailing_data));
635 EXPECT_EQ(HTTPProxy::kStateLookupServer, GetProxyState());
636}
637
638TEST_F(HTTPProxyTest, LineContinuation) {
639 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800640 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700641 ExpectDNSRequest("www.chromium.org", true);
642 string text_to_keep("X-Long-Header: this is one line\r\n"
643 "\tand this is another");
644 ReadFromClient(CreateRequest("http://www.chromium.org/", "1.1",
645 text_to_keep));
646 EXPECT_NE(string::npos, FindInRequest(text_to_keep));
647}
648
649// NB: This tests two different things:
650// 1) That the system replaces the value for "Proxy-Connection" headers.
651// 2) That when it replaces a header, it also removes the text in the line
652// continuation.
653TEST_F(HTTPProxyTest, LineContinuationRemoval) {
654 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800655 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700656 ExpectDNSRequest("www.chromium.org", true);
657 string text_to_remove("remove this text please");
658 ReadFromClient(CreateRequest("http://www.chromium.org/", "1.1",
659 string("Proxy-Connection: stuff\r\n\t") +
660 text_to_remove));
661 EXPECT_EQ(string::npos, FindInRequest(text_to_remove));
662 EXPECT_NE(string::npos, FindInRequest("Proxy-Connection: close\r\n"));
663}
664
665TEST_F(HTTPProxyTest, ConnectSynchronousFailure) {
666 SetupClient();
667 ExpectAsyncConnect(kServerAddress, kServerPort, false);
668 ExpectClientResult();
669 SetupConnect();
670 ExpectClientError(500, "Could not create socket to connect to server");
671}
672
673TEST_F(HTTPProxyTest, ConnectAsyncConnectFailure) {
674 SetupConnectAsync();
675 ExpectClientResult();
676 OnConnectCompletion(false, -1);
677 ExpectClientError(500, "Socket connection delayed failure");
678}
679
680TEST_F(HTTPProxyTest, ConnectSynchronousSuccess) {
681 SetupClient();
682 ExpectSyncConnect(kServerAddress, 999);
683 ExpectRepeatedServerOutput();
684 SetupConnectWithRequest("/", "1.1", "Host: www.chromium.org:999");
685 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
686}
687
688TEST_F(HTTPProxyTest, ConnectIPAddresss) {
689 SetupClient();
690 ExpectSyncConnect(kServerAddress, 999);
691 ExpectRepeatedServerOutput();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800692 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700693 ReadFromClient(CreateRequest("/", "1.1",
694 StringPrintf("Host: %s:999", kServerAddress)));
695 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
696}
697
698TEST_F(HTTPProxyTest, ConnectAsyncConnectSuccess) {
699 SetupConnectComplete();
700}
701
Paul Stewart58a577b2012-01-10 11:18:52 -0800702TEST_F(HTTPProxyTest, HTTPConnectMethod) {
703 SetupClient();
704 ExpectAsyncConnect(kServerAddress, kConnectPort, true);
705 ExpectConnectTimeout();
706 ExpectRouteRequest();
707 ReadFromClient(kConnectQuery);
708 ExpectRepeatedInputTimeout();
709 ExpectClientData();
710 OnConnectCompletion(true, kServerFD);
711 ExpectInClientResponse("HTTP/1.1 200 OK\r\n\r\n");
712}
713
Paul Stewartf65320c2011-10-13 14:34:52 -0700714TEST_F(HTTPProxyTest, TunnelData) {
715 SetupConnectComplete();
716
717 // The proxy is waiting for the server to be ready to accept data.
718 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
719 .WillOnce(Return(10));
720 ExpectServerInput();
721 WriteToServer(kServerFD);
722 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
723 .WillOnce(ReturnArg<2>());
724 ExpectInputTimeout();
725 WriteToServer(kServerFD);
726 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
727
728 // Tunnel a reply back to the client.
729 const string server_result("200 OK ... and so on");
730 ExpectClientResult();
731 ReadFromServer(server_result);
732 EXPECT_EQ(server_result,
733 string(reinterpret_cast<const char *>(
734 GetServerData().GetConstData()),
735 GetServerData().GetLength()));
736
737 // Allow part of the result string to be sent to the client.
738 const int part = server_result.length() / 2;
739 EXPECT_CALL(sockets(), Send(kClientFD, _, server_result.length(), 0))
740 .WillOnce(Return(part));
741 ExpectInputTimeout();
742 WriteToClient(kClientFD);
743 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
744
745 // The Server closes the connection while the client is still reading.
746 ExpectInputTimeout();
747 ReadFromServer("");
748 EXPECT_EQ(HTTPProxy::kStateFlushResponse, GetProxyState());
749
750 // When the last part of the response is written to the client, we close
751 // all connections.
752 EXPECT_CALL(sockets(), Send(kClientFD, _, server_result.length() - part, 0))
753 .WillOnce(ReturnArg<2>());
754 ExpectTunnelClose();
755 WriteToClient(kClientFD);
756 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
757}
758
759TEST_F(HTTPProxyTest, TunnelDataFailWriteClient) {
760 SetupConnectComplete();
761 EXPECT_CALL(sockets(), Send(kClientFD, _, _, 0))
762 .WillOnce(Return(-1));
763 ExpectTunnelClose();
764 WriteToClient(kClientFD);
765 ExpectClientReset();
766 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
767}
768
769TEST_F(HTTPProxyTest, TunnelDataFailWriteServer) {
770 SetupConnectComplete();
771 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
772 .WillOnce(Return(-1));
773 ExpectTunnelClose();
774 WriteToServer(kServerFD);
775 ExpectClientReset();
776 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
777}
778
779TEST_F(HTTPProxyTest, TunnelDataFailClientClose) {
780 SetupConnectComplete();
781 ExpectTunnelClose();
782 ReadFromClient("");
783 ExpectClientReset();
784 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
785}
786
787TEST_F(HTTPProxyTest, TunnelDataFailServerClose) {
788 SetupConnectComplete();
789 ExpectTunnelClose();
790 ReadFromServer("");
791 ExpectClientReset();
792 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
793}
794
795TEST_F(HTTPProxyTest, StopClient) {
796 SetupConnectComplete();
797 EXPECT_CALL(sockets(), Close(kClientFD))
798 .WillOnce(Return(0));
799 EXPECT_CALL(sockets(), Close(kServerFD))
800 .WillOnce(Return(0));
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800801 ExpectRouteRelease();
Paul Stewartf65320c2011-10-13 14:34:52 -0700802 StopClient();
803 ExpectClientReset();
804 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
805}
806
807} // namespace shill