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