blob: d7f4ddbab393f1be434724ede2eab8d586d6f464 [file] [log] [blame]
Paul Stewartf65320c2011-10-13 14:34:52 -07001// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2// 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 {
44const char kBadHeader[] = "BLAH\r\n";
45const char kBadHostnameLine[] = "GET HTTP/1.1 http://hostname\r\n";
46const char kBasicGetHeader[] = "GET / HTTP/1.1\r\n";
47const char kBasicGetHeaderWithURL[] =
48 "GET http://www.chromium.org/ HTTP/1.1\r\n";
49const char kBasicGetHeaderWithURLNoTrailingSlash[] =
50 "GET http://www.chromium.org HTTP/1.1\r\n";
51const char kQueryTemplate[] = "GET %s HTTP/%s\r\n%s"
52 "User-Agent: Mozilla/5.0 (X11; CrOS i686 1299.0.2011) "
53 "AppleWebKit/535.8 (KHTML, like Gecko) Chrome/17.0.936.0 Safari/535.8\r\n"
54 "Accept: text/html,application/xhtml+xml,application/xml;"
55 "q=0.9,*/*;q=0.8\r\n"
56 "Accept-Encoding: gzip,deflate,sdch\r\n"
57 "Accept-Language: en-US,en;q=0.8,ja;q=0.6\r\n"
58 "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n"
59 "Cookie: PREF=ID=xxxxxxxxxxxxxxxx:U=xxxxxxxxxxxxxxxx:FF=0:"
60 "TM=1317340083:LM=1317390705:GM=1:S=_xxxxxxxxxxxxxxx; "
61 "NID=52=xxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
62 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxx; "
63 "HSID=xxxxxxxxxxxx-xxxx; APISID=xxxxxxxxxxxxxxxx/xxxxxxxxxxxxxxxxx; "
64 "SID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_xxxxxxxxxxx"
65 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxx"
66 "xxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxx"
67 "_xxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxx-xx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
68 "xxxxxxxxxxxxxxxx\r\n\r\n";
69const char kInterfaceName[] = "int0";
70const char kDNSServer0[] = "8.8.8.8";
71const char kDNSServer1[] = "8.8.4.4";
72const char kServerAddress[] = "10.10.10.10";
73const char *kDNSServers[] = { kDNSServer0, kDNSServer1 };
74const int kProxyFD = 10203;
75const int kServerFD = 10204;
76const int kClientFD = 10205;
77const int kServerPort = 40506;
78} // namespace {}
79
80MATCHER_P(IsIPAddress, address, "") {
81 IPAddress ip_address(IPAddress::kFamilyIPv4);
82 EXPECT_TRUE(ip_address.SetAddressFromString(address));
83 return ip_address.Equals(arg);
84}
85
86class HTTPProxyTest : public Test {
87 public:
88 HTTPProxyTest()
Paul Stewartc8f4bef2011-12-13 09:45:51 -080089 : interface_name_(kInterfaceName),
90 server_async_connection_(NULL),
Paul Stewartf65320c2011-10-13 14:34:52 -070091 dns_servers_(kDNSServers, kDNSServers + 2),
92 dns_client_(NULL),
Paul Stewartc8f4bef2011-12-13 09:45:51 -080093 device_info_(new NiceMock<MockDeviceInfo>(
94 &control_,
95 reinterpret_cast<EventDispatcher*>(NULL),
96 reinterpret_cast<Manager*>(NULL))),
97 connection_(new StrictMock<MockConnection>(device_info_.get())),
98 proxy_(connection_) { }
Paul Stewartf65320c2011-10-13 14:34:52 -070099 protected:
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800100 virtual void SetUp() {
101 EXPECT_CALL(*connection_.get(), interface_name())
102 .WillRepeatedly(ReturnRef(interface_name_));
103 EXPECT_CALL(*connection_.get(), dns_servers())
104 .WillRepeatedly(ReturnRef(dns_servers_));
105 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700106 virtual void TearDown() {
107 if (proxy_.sockets_) {
108 ExpectStop();
109 }
110 }
111 string CreateRequest(const string &url, const string &http_version,
112 const string &extra_lines) {
113 string append_lines(extra_lines);
114 if (append_lines.size()) {
115 append_lines.append("\r\n");
116 }
117 return StringPrintf(kQueryTemplate, url.c_str(), http_version.c_str(),
118 append_lines.c_str());
119 }
120 int InvokeGetSockName(int fd, struct sockaddr *addr_out,
121 socklen_t *sockaddr_size) {
122 struct sockaddr_in addr;
123 EXPECT_EQ(kProxyFD, fd);
124 EXPECT_GE(sizeof(sockaddr_in), *sockaddr_size);
125 addr.sin_addr.s_addr = 0;
126 addr.sin_port = kServerPort;
127 memcpy(addr_out, &addr, sizeof(addr));
128 *sockaddr_size = sizeof(sockaddr_in);
129 return 0;
130 }
131 void InvokeSyncConnect(const IPAddress &/*address*/, int /*port*/) {
132 proxy_.OnConnectCompletion(true, kServerFD);
133 }
134 size_t FindInRequest(const string &find_string) {
135 const ByteString &request_data = GetClientData();
136 string request_string(
137 reinterpret_cast<const char *>(request_data.GetConstData()),
138 request_data.GetLength());
139 return request_string.find(find_string);
140 }
141 // Accessors
142 const ByteString &GetClientData() {
143 return proxy_.client_data_;
144 }
145 HTTPProxy *proxy() { return &proxy_; }
146 HTTPProxy::State GetProxyState() {
147 return proxy_.state_;
148 }
149 const ByteString &GetServerData() {
150 return proxy_.server_data_;
151 }
152 MockSockets &sockets() { return sockets_; }
153 MockEventDispatcher &dispatcher() { return dispatcher_; }
154
155
156 // Expectations
157 void ExpectClientReset() {
158 EXPECT_EQ(-1, proxy_.client_socket_);
159 EXPECT_TRUE(proxy_.client_version_.empty());
160 EXPECT_EQ(HTTPProxy::kDefaultServerPort, proxy_.server_port_);
161 EXPECT_EQ(-1, proxy_.server_socket_);
162 EXPECT_FALSE(proxy_.idle_timeout_);
163 EXPECT_TRUE(proxy_.client_headers_.empty());
164 EXPECT_TRUE(proxy_.server_hostname_.empty());
165 EXPECT_TRUE(proxy_.client_data_.IsEmpty());
166 EXPECT_TRUE(proxy_.server_data_.IsEmpty());
167 EXPECT_FALSE(proxy_.read_client_handler_.get());
168 EXPECT_FALSE(proxy_.write_client_handler_.get());
169 EXPECT_FALSE(proxy_.read_server_handler_.get());
170 EXPECT_FALSE(proxy_.write_server_handler_.get());
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800171 EXPECT_FALSE(proxy_.is_route_requested_);
Paul Stewartf65320c2011-10-13 14:34:52 -0700172 }
173 void ExpectReset() {
174 EXPECT_FALSE(proxy_.accept_handler_.get());
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800175 EXPECT_EQ(proxy_.connection_.get(), connection_.get());
Paul Stewartf65320c2011-10-13 14:34:52 -0700176 EXPECT_FALSE(proxy_.dispatcher_);
177 EXPECT_FALSE(proxy_.dns_client_.get());
178 EXPECT_EQ(-1, proxy_.proxy_port_);
179 EXPECT_EQ(-1, proxy_.proxy_socket_);
180 EXPECT_FALSE(proxy_.server_async_connection_.get());
181 EXPECT_FALSE(proxy_.sockets_);
182 EXPECT_EQ(HTTPProxy::kStateIdle, proxy_.state_);
183 ExpectClientReset();
184 }
185 void ExpectStart() {
186 EXPECT_CALL(sockets(), Socket(_, _, _))
187 .WillOnce(Return(kProxyFD));
188 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
189 .WillOnce(Return(0));
190 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
191 .WillOnce(Invoke(this, &HTTPProxyTest::InvokeGetSockName));
192 EXPECT_CALL(sockets(), SetNonBlocking(kProxyFD))
193 .WillOnce(Return(0));
194 EXPECT_CALL(sockets(), Listen(kProxyFD, _))
195 .WillOnce(Return(0));
196 EXPECT_CALL(dispatcher_, CreateReadyHandler(kProxyFD,
197 IOHandler::kModeInput,
198 proxy_.accept_callback_.get()))
199 .WillOnce(ReturnNew<IOHandler>());
200 }
201 void ExpectStop() {
202 if (dns_client_) {
203 EXPECT_CALL(*dns_client_, Stop())
204 .Times(AtLeast(1));
205 }
206 if (server_async_connection_) {
207 EXPECT_CALL(*server_async_connection_, Stop())
208 .Times(AtLeast(1));
209 }
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800210 if (proxy_.is_route_requested_) {
211 EXPECT_CALL(*connection_.get(), ReleaseRouting());
212 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700213 }
214 void ExpectClientInput(int fd) {
215 EXPECT_CALL(sockets(), Accept(kProxyFD, _, _))
216 .WillOnce(Return(fd));
217 EXPECT_CALL(sockets(), SetNonBlocking(fd))
218 .WillOnce(Return(0));
219 EXPECT_CALL(dispatcher(),
220 CreateInputHandler(fd, proxy_.read_client_callback_.get()))
221 .WillOnce(ReturnNew<IOHandler>());
222 ExpectTransactionTimeout();
223 ExpectClientHeaderTimeout();
224 }
225 void ExpectTimeout(int timeout) {
226 EXPECT_CALL(dispatcher_, PostDelayedTask(_, timeout * 1000))
227 .WillOnce(Return(true));
228 }
229 void ExpectClientHeaderTimeout() {
230 ExpectTimeout(HTTPProxy::kClientHeaderTimeoutSeconds);
231 }
232 void ExpectConnectTimeout() {
233 ExpectTimeout(HTTPProxy::kConnectTimeoutSeconds);
234 }
235 void ExpectInputTimeout() {
236 ExpectTimeout(HTTPProxy::kInputTimeoutSeconds);
237 }
238 void ExpectRepeatedInputTimeout() {
239 EXPECT_CALL(dispatcher_,
240 PostDelayedTask(_, HTTPProxy::kInputTimeoutSeconds * 1000))
241 .WillRepeatedly(Return(true));
242 }
243 void ExpectTransactionTimeout() {
244 ExpectTimeout(HTTPProxy::kTransactionTimeoutSeconds);
245 }
246 void ExpectClientError(int code, const string &error) {
247 EXPECT_EQ(HTTPProxy::kStateFlushResponse, GetProxyState());
248 string status_line = StringPrintf("HTTP/1.1 %d ERROR", code);
249 string server_data(reinterpret_cast<char *>(proxy_.server_data_.GetData()),
250 proxy_.server_data_.GetLength());
251 EXPECT_NE(string::npos, server_data.find(status_line));
252 EXPECT_NE(string::npos, server_data.find(error));
253 }
254 void ExpectClientInternalError() {
255 ExpectClientError(500, HTTPProxy::kInternalErrorMsg);
256 }
257 void ExpectClientVersion(const string &version) {
258 EXPECT_EQ(version, proxy_.client_version_);
259 }
260 void ExpectServerHostname(const string &hostname) {
261 EXPECT_EQ(hostname, proxy_.server_hostname_);
262 }
263 void ExpectFirstLine(const string &line) {
264 EXPECT_EQ(line, proxy_.client_headers_[0] + "\r\n");
265 }
266 void ExpectDNSRequest(const string &host, bool return_value) {
267 EXPECT_CALL(*dns_client_, Start(StrEq(host)))
268 .WillOnce(Return(return_value));
269 }
270 void ExpectDNSFailure(const string &error) {
271 EXPECT_CALL(*dns_client_, error())
272 .WillOnce(ReturnRef(error));
273 }
274 void ExpectAsyncConnect(const string &address, int port,
275 bool return_value) {
276 EXPECT_CALL(*server_async_connection_, Start(IsIPAddress(address), port))
277 .WillOnce(Return(return_value));
278 }
279 void ExpectSyncConnect(const string &address, int port) {
280 EXPECT_CALL(*server_async_connection_, Start(IsIPAddress(address), port))
281 .WillOnce(DoAll(Invoke(this, &HTTPProxyTest::InvokeSyncConnect),
282 Return(true)));
283 }
284 void ExpectClientResult() {
285 EXPECT_CALL(dispatcher(),
286 CreateReadyHandler(kClientFD,
287 IOHandler::kModeOutput,
288 proxy_.write_client_callback_.get()))
289 .WillOnce(ReturnNew<IOHandler>());
290 ExpectInputTimeout();
291 }
292 void ExpectServerInput() {
293 EXPECT_CALL(dispatcher(),
294 CreateInputHandler(kServerFD,
295 proxy_.read_server_callback_.get()))
296 .WillOnce(ReturnNew<IOHandler>());
297 ExpectInputTimeout();
298 }
299 void ExpectServerOutput() {
300 EXPECT_CALL(dispatcher(),
301 CreateReadyHandler(kServerFD,
302 IOHandler::kModeOutput,
303 proxy_.write_server_callback_.get()))
304 .WillOnce(ReturnNew<IOHandler>());
305 ExpectInputTimeout();
306 }
307 void ExpectRepeatedServerOutput() {
308 EXPECT_CALL(dispatcher(),
309 CreateReadyHandler(kServerFD,
310 IOHandler::kModeOutput,
311 proxy_.write_server_callback_.get()))
312 .WillOnce(ReturnNew<IOHandler>());
313 ExpectRepeatedInputTimeout();
314 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700315 void ExpectTunnelClose() {
316 EXPECT_CALL(sockets(), Close(kClientFD))
317 .WillOnce(Return(0));
318 EXPECT_CALL(sockets(), Close(kServerFD))
319 .WillOnce(Return(0));
320 ExpectStop();
321 }
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800322 void ExpectRouteRequest() {
323 EXPECT_CALL(*connection_.get(), RequestRouting());
324 }
325 void ExpectRouteRelease() {
326 EXPECT_CALL(*connection_.get(), ReleaseRouting());
327 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700328
329 // Callers for various private routines in the proxy
330 bool StartProxy() {
331 bool ret = proxy_.Start(&dispatcher_, &sockets_);
332 if (ret) {
333 dns_client_ = new StrictMock<MockDNSClient>();
334 // Passes ownership.
335 proxy_.dns_client_.reset(dns_client_);
336 server_async_connection_ = new StrictMock<MockAsyncConnection>();
337 // Passes ownership.
338 proxy_.server_async_connection_.reset(server_async_connection_);
339 }
340 return ret;
341 }
342 void AcceptClient(int fd) {
343 proxy_.AcceptClient(fd);
344 }
345 void GetDNSResult(bool result) {
346 proxy_.GetDNSResult(result);
347 }
348 void OnConnectCompletion(bool result, int sockfd) {
349 proxy_.OnConnectCompletion(result, sockfd);
350 }
351 void ReadFromClient(const string &data) {
352 const unsigned char *ptr =
353 reinterpret_cast<const unsigned char *>(data.c_str());
354 vector<unsigned char> data_bytes(ptr, ptr + data.length());
355 InputData proxy_data(data_bytes.data(), data_bytes.size());
356 proxy_.ReadFromClient(&proxy_data);
357 }
358 void ReadFromServer(const string &data) {
359 const unsigned char *ptr =
360 reinterpret_cast<const unsigned char *>(data.c_str());
361 vector<unsigned char> data_bytes(ptr, ptr + data.length());
362 InputData proxy_data(data_bytes.data(), data_bytes.size());
363 proxy_.ReadFromServer(&proxy_data);
364 }
365 void SendClientError(int code, const string &error) {
366 proxy_.SendClientError(code, error);
367 EXPECT_FALSE(proxy_.server_data_.IsEmpty());
368 }
369 void StopClient() {
370 EXPECT_CALL(*dns_client_, Stop());
371 EXPECT_CALL(*server_async_connection_, Stop());
372 proxy_.StopClient();
373 }
374 void StopProxy() {
375 ExpectStop();
376 proxy_.Stop();
377 server_async_connection_ = NULL;
378 dns_client_ = NULL;
379 ExpectReset();
380 }
381 void WriteToClient(int fd) {
382 proxy_.WriteToClient(fd);
383 }
384 void WriteToServer(int fd) {
385 proxy_.WriteToServer(fd);
386 }
387
388 void SetupClient() {
389 ExpectStart();
390 ASSERT_TRUE(StartProxy());
391 ExpectClientInput(kClientFD);
392 AcceptClient(kProxyFD);
393 EXPECT_EQ(HTTPProxy::kStateReadClientHeader, GetProxyState());
394 }
395 void SetupConnectWithRequest(const string &url, const string &http_version,
396 const string &extra_lines) {
397 ExpectDNSRequest("www.chromium.org", true);
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800398 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700399 ReadFromClient(CreateRequest(url, http_version, extra_lines));
400 IPAddress addr(IPAddress::kFamilyIPv4);
401 EXPECT_TRUE(addr.SetAddressFromString(kServerAddress));
402 EXPECT_CALL(*dns_client_, address())
403 .WillOnce(ReturnRef(addr));;
404 GetDNSResult(true);
405 }
406 void SetupConnect() {
407 SetupConnectWithRequest("/", "1.1", "Host: www.chromium.org:40506");
408 }
409 void SetupConnectAsync() {
410 SetupClient();
411 ExpectAsyncConnect(kServerAddress, kServerPort, true);
412 ExpectConnectTimeout();
413 SetupConnect();
414 }
415 void SetupConnectComplete() {
416 SetupConnectAsync();
417 ExpectServerOutput();
418 OnConnectCompletion(true, kServerFD);
419 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
420 }
421
422 private:
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800423 const string interface_name_;
Paul Stewartf65320c2011-10-13 14:34:52 -0700424 // Owned by the HTTPProxy, but tracked here for EXPECT().
425 StrictMock<MockAsyncConnection> *server_async_connection_;
426 vector<string> dns_servers_;
427 // Owned by the HTTPProxy, but tracked here for EXPECT().
428 StrictMock<MockDNSClient> *dns_client_;
429 MockEventDispatcher dispatcher_;
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800430 MockControl control_;
431 scoped_ptr<MockDeviceInfo> device_info_;
432 scoped_refptr<MockConnection> connection_;
Paul Stewartf65320c2011-10-13 14:34:52 -0700433 HTTPProxy proxy_;
434 StrictMock<MockSockets> sockets_;
435};
436
437TEST_F(HTTPProxyTest, StartFailSocket) {
438 EXPECT_CALL(sockets(), Socket(_, _, _))
439 .WillOnce(Return(-1));
440 EXPECT_FALSE(StartProxy());
441 ExpectReset();
442}
443
444TEST_F(HTTPProxyTest, StartFailBind) {
445 EXPECT_CALL(sockets(), Socket(_, _, _))
446 .WillOnce(Return(kProxyFD));
447 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
448 .WillOnce(Return(-1));
449 EXPECT_CALL(sockets(), Close(kProxyFD))
450 .WillOnce(Return(0));
451 EXPECT_FALSE(StartProxy());
452 ExpectReset();
453}
454
455TEST_F(HTTPProxyTest, StartFailGetSockName) {
456 EXPECT_CALL(sockets(), Socket(_, _, _))
457 .WillOnce(Return(kProxyFD));
458 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
459 .WillOnce(Return(0));
460 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
461 .WillOnce(Return(-1));
462 EXPECT_CALL(sockets(), Close(kProxyFD))
463 .WillOnce(Return(0));
464 EXPECT_FALSE(StartProxy());
465 ExpectReset();
466}
467
468TEST_F(HTTPProxyTest, StartFailSetNonBlocking) {
469 EXPECT_CALL(sockets(), Socket(_, _, _))
470 .WillOnce(Return(kProxyFD));
471 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
472 .WillOnce(Return(0));
473 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
474 .WillOnce(Return(0));
475 EXPECT_CALL(sockets(), SetNonBlocking(kProxyFD))
476 .WillOnce(Return(-1));
477 EXPECT_CALL(sockets(), Close(kProxyFD))
478 .WillOnce(Return(0));
479 EXPECT_FALSE(StartProxy());
480 ExpectReset();
481}
482
483TEST_F(HTTPProxyTest, StartFailListen) {
484 EXPECT_CALL(sockets(), Socket(_, _, _))
485 .WillOnce(Return(kProxyFD));
486 EXPECT_CALL(sockets(), Bind(kProxyFD, _, _))
487 .WillOnce(Return(0));
488 EXPECT_CALL(sockets(), GetSockName(kProxyFD, _, _))
489 .WillOnce(Return(0));
490 EXPECT_CALL(sockets(), SetNonBlocking(kProxyFD))
491 .WillOnce(Return(0));
492 EXPECT_CALL(sockets(), Listen(kProxyFD, _))
493 .WillOnce(Return(-1));
494 EXPECT_CALL(sockets(), Close(kProxyFD))
495 .WillOnce(Return(0));
496 EXPECT_FALSE(StartProxy());
497 ExpectReset();
498}
499
500TEST_F(HTTPProxyTest, StartSuccess) {
501 ExpectStart();
502 EXPECT_TRUE(StartProxy());
503}
504
505TEST_F(HTTPProxyTest, SendClientError) {
506 SetupClient();
507 ExpectClientResult();
508 SendClientError(500, "This is an error");
509 ExpectClientError(500, "This is an error");
510
511 // We succeed in sending all but one byte of the client response.
512 int buf_len = GetServerData().GetLength();
513 EXPECT_CALL(sockets(), Send(kClientFD, _, buf_len, 0))
514 .WillOnce(Return(buf_len - 1));
515 ExpectInputTimeout();
516 WriteToClient(kClientFD);
517 EXPECT_EQ(1, GetServerData().GetLength());
518 EXPECT_EQ(HTTPProxy::kStateFlushResponse, GetProxyState());
519
520 // When we are able to send the last byte, we close the connection.
521 EXPECT_CALL(sockets(), Send(kClientFD, _, 1, 0))
522 .WillOnce(Return(1));
523 EXPECT_CALL(sockets(), Close(kClientFD))
524 .WillOnce(Return(0));
525 ExpectStop();
526 WriteToClient(kClientFD);
527 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
528}
529
530TEST_F(HTTPProxyTest, ReadBadFirstLine) {
531 SetupClient();
532 ExpectClientResult();
533 ReadFromClient(kBadHeader);
534 ExpectClientError(501, "Server only accepts HTTP/1.x requests");
535}
536
537TEST_F(HTTPProxyTest, ReadBadHostname) {
538 SetupClient();
539 ExpectClientResult();
540 ReadFromClient(kBadHostnameLine);
541 ExpectClientInternalError();
542}
543
544TEST_F(HTTPProxyTest, GoodFirstLineWithoutURL) {
545 SetupClient();
546 ExpectClientHeaderTimeout();
547 ReadFromClient(kBasicGetHeader);
548 ExpectClientVersion("1.1");
549 ExpectServerHostname("");
550 ExpectFirstLine(kBasicGetHeader);
551}
552
553TEST_F(HTTPProxyTest, GoodFirstLineWithURL) {
554 SetupClient();
555 ExpectClientHeaderTimeout();
556 ReadFromClient(kBasicGetHeaderWithURL);
557 ExpectClientVersion("1.1");
558 ExpectServerHostname("www.chromium.org");
559 ExpectFirstLine(kBasicGetHeader);
560}
561
562TEST_F(HTTPProxyTest, GoodFirstLineWithURLNoSlash) {
563 SetupClient();
564 ExpectClientHeaderTimeout();
565 ReadFromClient(kBasicGetHeaderWithURLNoTrailingSlash);
566 ExpectClientVersion("1.1");
567 ExpectServerHostname("www.chromium.org");
568 ExpectFirstLine(kBasicGetHeader);
569}
570
571TEST_F(HTTPProxyTest, NoHostInRequest) {
572 SetupClient();
573 ExpectClientResult();
574 ReadFromClient(CreateRequest("/", "1.1", ""));
575 ExpectClientError(400, "I don't know what host you want me to connect to");
576}
577
578TEST_F(HTTPProxyTest, TooManyColonsInHost) {
579 SetupClient();
580 ExpectClientResult();
581 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:80:40506"));
582 ExpectClientError(400, "Too many colons in hostname");
583}
584
585TEST_F(HTTPProxyTest, DNSRequestFailure) {
586 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800587 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700588 ExpectDNSRequest("www.chromium.org", false);
589 ExpectClientResult();
590 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506"));
591 ExpectClientError(502, "Could not resolve hostname");
592}
593
594TEST_F(HTTPProxyTest, DNSRequestDelayedFailure) {
595 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800596 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700597 ExpectDNSRequest("www.chromium.org", true);
598 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506"));
599 ExpectClientResult();
600 const std::string not_found_error(DNSClient::kErrorNotFound);
601 ExpectDNSFailure(not_found_error);
602 GetDNSResult(false);
603 ExpectClientError(502, string("Could not resolve hostname: ") +
604 not_found_error);
605}
606
607TEST_F(HTTPProxyTest, TrailingClientData) {
608 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800609 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700610 ExpectDNSRequest("www.chromium.org", true);
611 const string trailing_data("Trailing client data");
612 ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506") +
613 trailing_data);
614 EXPECT_EQ(GetClientData().GetLength() - trailing_data.length(),
615 FindInRequest(trailing_data));
616 EXPECT_EQ(HTTPProxy::kStateLookupServer, GetProxyState());
617}
618
619TEST_F(HTTPProxyTest, LineContinuation) {
620 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800621 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700622 ExpectDNSRequest("www.chromium.org", true);
623 string text_to_keep("X-Long-Header: this is one line\r\n"
624 "\tand this is another");
625 ReadFromClient(CreateRequest("http://www.chromium.org/", "1.1",
626 text_to_keep));
627 EXPECT_NE(string::npos, FindInRequest(text_to_keep));
628}
629
630// NB: This tests two different things:
631// 1) That the system replaces the value for "Proxy-Connection" headers.
632// 2) That when it replaces a header, it also removes the text in the line
633// continuation.
634TEST_F(HTTPProxyTest, LineContinuationRemoval) {
635 SetupClient();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800636 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700637 ExpectDNSRequest("www.chromium.org", true);
638 string text_to_remove("remove this text please");
639 ReadFromClient(CreateRequest("http://www.chromium.org/", "1.1",
640 string("Proxy-Connection: stuff\r\n\t") +
641 text_to_remove));
642 EXPECT_EQ(string::npos, FindInRequest(text_to_remove));
643 EXPECT_NE(string::npos, FindInRequest("Proxy-Connection: close\r\n"));
644}
645
646TEST_F(HTTPProxyTest, ConnectSynchronousFailure) {
647 SetupClient();
648 ExpectAsyncConnect(kServerAddress, kServerPort, false);
649 ExpectClientResult();
650 SetupConnect();
651 ExpectClientError(500, "Could not create socket to connect to server");
652}
653
654TEST_F(HTTPProxyTest, ConnectAsyncConnectFailure) {
655 SetupConnectAsync();
656 ExpectClientResult();
657 OnConnectCompletion(false, -1);
658 ExpectClientError(500, "Socket connection delayed failure");
659}
660
661TEST_F(HTTPProxyTest, ConnectSynchronousSuccess) {
662 SetupClient();
663 ExpectSyncConnect(kServerAddress, 999);
664 ExpectRepeatedServerOutput();
665 SetupConnectWithRequest("/", "1.1", "Host: www.chromium.org:999");
666 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
667}
668
669TEST_F(HTTPProxyTest, ConnectIPAddresss) {
670 SetupClient();
671 ExpectSyncConnect(kServerAddress, 999);
672 ExpectRepeatedServerOutput();
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800673 ExpectRouteRequest();
Paul Stewartf65320c2011-10-13 14:34:52 -0700674 ReadFromClient(CreateRequest("/", "1.1",
675 StringPrintf("Host: %s:999", kServerAddress)));
676 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
677}
678
679TEST_F(HTTPProxyTest, ConnectAsyncConnectSuccess) {
680 SetupConnectComplete();
681}
682
683TEST_F(HTTPProxyTest, TunnelData) {
684 SetupConnectComplete();
685
686 // The proxy is waiting for the server to be ready to accept data.
687 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
688 .WillOnce(Return(10));
689 ExpectServerInput();
690 WriteToServer(kServerFD);
691 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
692 .WillOnce(ReturnArg<2>());
693 ExpectInputTimeout();
694 WriteToServer(kServerFD);
695 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
696
697 // Tunnel a reply back to the client.
698 const string server_result("200 OK ... and so on");
699 ExpectClientResult();
700 ReadFromServer(server_result);
701 EXPECT_EQ(server_result,
702 string(reinterpret_cast<const char *>(
703 GetServerData().GetConstData()),
704 GetServerData().GetLength()));
705
706 // Allow part of the result string to be sent to the client.
707 const int part = server_result.length() / 2;
708 EXPECT_CALL(sockets(), Send(kClientFD, _, server_result.length(), 0))
709 .WillOnce(Return(part));
710 ExpectInputTimeout();
711 WriteToClient(kClientFD);
712 EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
713
714 // The Server closes the connection while the client is still reading.
715 ExpectInputTimeout();
716 ReadFromServer("");
717 EXPECT_EQ(HTTPProxy::kStateFlushResponse, GetProxyState());
718
719 // When the last part of the response is written to the client, we close
720 // all connections.
721 EXPECT_CALL(sockets(), Send(kClientFD, _, server_result.length() - part, 0))
722 .WillOnce(ReturnArg<2>());
723 ExpectTunnelClose();
724 WriteToClient(kClientFD);
725 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
726}
727
728TEST_F(HTTPProxyTest, TunnelDataFailWriteClient) {
729 SetupConnectComplete();
730 EXPECT_CALL(sockets(), Send(kClientFD, _, _, 0))
731 .WillOnce(Return(-1));
732 ExpectTunnelClose();
733 WriteToClient(kClientFD);
734 ExpectClientReset();
735 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
736}
737
738TEST_F(HTTPProxyTest, TunnelDataFailWriteServer) {
739 SetupConnectComplete();
740 EXPECT_CALL(sockets(), Send(kServerFD, _, _, 0))
741 .WillOnce(Return(-1));
742 ExpectTunnelClose();
743 WriteToServer(kServerFD);
744 ExpectClientReset();
745 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
746}
747
748TEST_F(HTTPProxyTest, TunnelDataFailClientClose) {
749 SetupConnectComplete();
750 ExpectTunnelClose();
751 ReadFromClient("");
752 ExpectClientReset();
753 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
754}
755
756TEST_F(HTTPProxyTest, TunnelDataFailServerClose) {
757 SetupConnectComplete();
758 ExpectTunnelClose();
759 ReadFromServer("");
760 ExpectClientReset();
761 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
762}
763
764TEST_F(HTTPProxyTest, StopClient) {
765 SetupConnectComplete();
766 EXPECT_CALL(sockets(), Close(kClientFD))
767 .WillOnce(Return(0));
768 EXPECT_CALL(sockets(), Close(kServerFD))
769 .WillOnce(Return(0));
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800770 ExpectRouteRelease();
Paul Stewartf65320c2011-10-13 14:34:52 -0700771 StopClient();
772 ExpectClientReset();
773 EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());
774}
775
776} // namespace shill