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