blob: ab7c5667e0918a0e6461c5c4dec3f936d95c2135 [file] [log] [blame]
Paul Stewart188a84a2012-01-20 16:28:15 -08001// Copyright (c) 2012 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_request.h"
6
7#include <netinet/in.h>
8
9#include <string>
10#include <vector>
11
Eric Shienbrood3e20a232012-02-16 11:35:56 -050012#include <base/bind.h>
Paul Stewart188a84a2012-01-20 16:28:15 -080013#include <base/stringprintf.h>
14#include <gtest/gtest.h>
15
16#include "shill/ip_address.h"
17#include "shill/http_url.h"
18#include "shill/mock_async_connection.h"
19#include "shill/mock_connection.h"
20#include "shill/mock_control.h"
21#include "shill/mock_device_info.h"
22#include "shill/mock_dns_client.h"
23#include "shill/mock_event_dispatcher.h"
24#include "shill/mock_sockets.h"
25
Eric Shienbrood3e20a232012-02-16 11:35:56 -050026using base::Bind;
27using base::Callback;
Paul Stewart188a84a2012-01-20 16:28:15 -080028using base::StringPrintf;
Eric Shienbrood3e20a232012-02-16 11:35:56 -050029using base::Unretained;
Paul Stewart188a84a2012-01-20 16:28:15 -080030using std::string;
31using std::vector;
32using ::testing::_;
33using ::testing::AtLeast;
34using ::testing::DoAll;
35using ::testing::Invoke;
36using ::testing::NiceMock;
37using ::testing::Return;
38using ::testing::ReturnArg;
39using ::testing::ReturnNew;
40using ::testing::ReturnRef;
41using ::testing::SetArgumentPointee;
42using ::testing::StrEq;
43using ::testing::StrictMock;
44using ::testing::Test;
45
46namespace shill {
47
48namespace {
49const char kTextSiteName[] = "www.chromium.org";
50const char kTextURL[] = "http://www.chromium.org/path/to/resource";
51const char kNumericURL[] = "http://10.1.1.1";
52const char kPath[] = "/path/to/resource";
53const char kBadURL[] = "xxx";
54const char kInterfaceName[] = "int0";
55const char kDNSServer0[] = "8.8.8.8";
56const char kDNSServer1[] = "8.8.4.4";
57const char *kDNSServers[] = { kDNSServer0, kDNSServer1 };
58const char kServerAddress[] = "10.1.1.1";
59const int kServerFD = 10203;
60const int kServerPort = 80;
61} // namespace {}
62
63MATCHER_P(IsIPAddress, address, "") {
64 IPAddress ip_address(IPAddress::kFamilyIPv4);
65 EXPECT_TRUE(ip_address.SetAddressFromString(address));
66 return ip_address.Equals(arg);
67}
68
Paul Stewartbdb02e62012-02-22 16:24:33 -080069MATCHER_P(ByteStringMatches, byte_string, "") {
70 return byte_string.Equals(arg);
71}
72
Eric Shienbrood3e20a232012-02-16 11:35:56 -050073MATCHER_P(CallbackEq, callback, "") {
74 return arg.Equals(callback);
75}
76
Paul Stewart188a84a2012-01-20 16:28:15 -080077class HTTPRequestTest : public Test {
78 public:
79 HTTPRequestTest()
80 : interface_name_(kInterfaceName),
81 server_async_connection_(new StrictMock<MockAsyncConnection>()),
82 dns_servers_(kDNSServers, kDNSServers + 2),
83 dns_client_(new StrictMock<MockDNSClient>()),
84 device_info_(new NiceMock<MockDeviceInfo>(
85 &control_,
86 reinterpret_cast<EventDispatcher*>(NULL),
87 reinterpret_cast<Metrics*>(NULL),
88 reinterpret_cast<Manager*>(NULL))),
89 connection_(new StrictMock<MockConnection>(device_info_.get())) { }
90 protected:
91 class CallbackTarget {
92 public:
93 CallbackTarget()
94 : read_event_callback_(
Eric Shienbrood3e20a232012-02-16 11:35:56 -050095 Bind(&CallbackTarget::ReadEventCallTarget, Unretained(this))),
Paul Stewart188a84a2012-01-20 16:28:15 -080096 result_callback_(
Eric Shienbrood3e20a232012-02-16 11:35:56 -050097 Bind(&CallbackTarget::ResultCallTarget, Unretained(this))) {}
Paul Stewart188a84a2012-01-20 16:28:15 -080098
Paul Stewartbdb02e62012-02-22 16:24:33 -080099 MOCK_METHOD1(ReadEventCallTarget, void(const ByteString &response_data));
100 MOCK_METHOD2(ResultCallTarget, void(HTTPRequest::Result result,
101 const ByteString &response_data));
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500102 const Callback<void(const ByteString &)> &read_event_callback() {
103 return read_event_callback_;
Paul Stewart188a84a2012-01-20 16:28:15 -0800104 }
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500105 const Callback<void(HTTPRequest::Result,
106 const ByteString &)> &result_callback() {
107 return result_callback_;
Paul Stewart188a84a2012-01-20 16:28:15 -0800108 }
109
110 private:
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500111 Callback<void(const ByteString &)> read_event_callback_;
112 Callback<void(HTTPRequest::Result, const ByteString &)> result_callback_;
Paul Stewart188a84a2012-01-20 16:28:15 -0800113 };
114
115 virtual void SetUp() {
116 EXPECT_CALL(*connection_.get(), interface_name())
117 .WillRepeatedly(ReturnRef(interface_name_));
118 EXPECT_CALL(*connection_.get(), dns_servers())
119 .WillRepeatedly(ReturnRef(dns_servers_));
120
121 request_.reset(new HTTPRequest(connection_, &dispatcher_, &sockets_));
122 // Passes ownership.
123 request_->dns_client_.reset(dns_client_);
124 // Passes ownership.
125 request_->server_async_connection_.reset(server_async_connection_);
126 }
127 virtual void TearDown() {
128 if (request_->is_running_) {
129 ExpectStop();
130
131 // Subtle: Make sure the finalization of the request happens while our
132 // expectations are still active.
133 request_.reset();
134 }
135 }
136 size_t FindInRequestData(const string &find_string) {
137 string request_string(
138 reinterpret_cast<char *>(request_->request_data_.GetData()),
139 request_->request_data_.GetLength());
140 return request_string.find(find_string);
141 }
142 // Accessors
143 const ByteString &GetRequestData() {
144 return request_->request_data_;
145 }
146 HTTPRequest *request() { return request_.get(); }
147 MockSockets &sockets() { return sockets_; }
148
149 // Expectations
150 void ExpectReset() {
151 EXPECT_EQ(connection_.get(), request_->connection_.get());
152 EXPECT_EQ(&dispatcher_, request_->dispatcher_);
153 EXPECT_EQ(&sockets_, request_->sockets_);
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500154 EXPECT_TRUE(request_->result_callback_.is_null());
155 EXPECT_TRUE(request_->read_event_callback_.is_null());
Eric Shienbrood9a245532012-03-07 14:20:39 -0500156 EXPECT_FALSE(request_->connect_completion_callback_.is_null());
157 EXPECT_FALSE(request_->dns_client_callback_.is_null());
158 EXPECT_FALSE(request_->read_server_callback_.is_null());
159 EXPECT_FALSE(request_->write_server_callback_.is_null());
Paul Stewart188a84a2012-01-20 16:28:15 -0800160 EXPECT_FALSE(request_->read_server_handler_.get());
161 EXPECT_FALSE(request_->write_server_handler_.get());
162 EXPECT_EQ(dns_client_, request_->dns_client_.get());
163 EXPECT_EQ(server_async_connection_,
164 request_->server_async_connection_.get());
165 EXPECT_TRUE(request_->server_hostname_.empty());
166 EXPECT_EQ(-1, request_->server_port_);
167 EXPECT_EQ(-1, request_->server_socket_);
168 EXPECT_EQ(HTTPRequest::kResultUnknown, request_->timeout_result_);
169 EXPECT_TRUE(request_->request_data_.IsEmpty());
170 EXPECT_TRUE(request_->response_data_.IsEmpty());
171 EXPECT_FALSE(request_->is_running_);
172 }
173 void ExpectStop() {
174 if (request_->server_socket_ != -1) {
175 EXPECT_CALL(sockets(), Close(kServerFD))
176 .WillOnce(Return(0));
177 }
178 EXPECT_CALL(*dns_client_, Stop())
179 .Times(AtLeast(1));
180 EXPECT_CALL(*server_async_connection_, Stop())
181 .Times(AtLeast(1));
182 EXPECT_CALL(*connection_.get(), ReleaseRouting());
183 }
184 void ExpectSetTimeout(int timeout) {
185 EXPECT_CALL(dispatcher_, PostDelayedTask(_, timeout * 1000))
186 .WillOnce(Return(true));
187 }
188 void ExpectSetConnectTimeout() {
189 ExpectSetTimeout(HTTPRequest::kConnectTimeoutSeconds);
190 }
191 void ExpectSetInputTimeout() {
192 ExpectSetTimeout(HTTPRequest::kInputTimeoutSeconds);
193 }
194 void ExpectInResponse(const string &expected_response_data) {
195 string response_string(
196 reinterpret_cast<char *>(request_->response_data_.GetData()),
197 request_->response_data_.GetLength());
198 EXPECT_NE(string::npos, response_string.find(expected_response_data));
199 }
200 void ExpectDNSRequest(const string &host, bool return_value) {
Paul Stewartbdb02e62012-02-22 16:24:33 -0800201 EXPECT_CALL(*dns_client_, Start(StrEq(host), _))
Paul Stewart188a84a2012-01-20 16:28:15 -0800202 .WillOnce(Return(return_value));
203 }
Paul Stewart188a84a2012-01-20 16:28:15 -0800204 void ExpectAsyncConnect(const string &address, int port,
205 bool return_value) {
206 EXPECT_CALL(*server_async_connection_, Start(IsIPAddress(address), port))
207 .WillOnce(Return(return_value));
208 if (return_value) {
209 ExpectSetConnectTimeout();
210 }
211 }
212 void InvokeSyncConnect(const IPAddress &/*address*/, int /*port*/) {
213 CallConnectCompletion(true, kServerFD);
214 }
215 void CallConnectCompletion(bool success, int fd) {
216 request_->OnConnectCompletion(success, fd);
217 }
218 void ExpectSyncConnect(const string &address, int port) {
219 EXPECT_CALL(*server_async_connection_, Start(IsIPAddress(address), port))
220 .WillOnce(DoAll(Invoke(this, &HTTPRequestTest::InvokeSyncConnect),
221 Return(true)));
222 }
223 void ExpectConnectFailure() {
224 EXPECT_CALL(*server_async_connection_, Start(_, _))
225 .WillOnce(Return(false));
226 }
227 void ExpectMonitorServerInput() {
228 EXPECT_CALL(dispatcher_,
229 CreateInputHandler(kServerFD,
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800230 CallbackEq(request_->read_server_callback_),
231 _))
Paul Stewart188a84a2012-01-20 16:28:15 -0800232 .WillOnce(ReturnNew<IOHandler>());
233 ExpectSetInputTimeout();
234 }
235 void ExpectMonitorServerOutput() {
236 EXPECT_CALL(dispatcher_,
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500237 CreateReadyHandler(
238 kServerFD, IOHandler::kModeOutput,
239 CallbackEq(request_->write_server_callback_)))
Paul Stewart188a84a2012-01-20 16:28:15 -0800240 .WillOnce(ReturnNew<IOHandler>());
241 ExpectSetInputTimeout();
242 }
243 void ExpectRouteRequest() {
244 EXPECT_CALL(*connection_.get(), RequestRouting());
245 }
246 void ExpectRouteRelease() {
247 EXPECT_CALL(*connection_.get(), ReleaseRouting());
248 }
249 void ExpectResultCallback(HTTPRequest::Result result) {
Paul Stewartbdb02e62012-02-22 16:24:33 -0800250 EXPECT_CALL(target_, ResultCallTarget(result, _));
Paul Stewart188a84a2012-01-20 16:28:15 -0800251 }
Paul Stewartbdb02e62012-02-22 16:24:33 -0800252 void InvokeResultVerify(HTTPRequest::Result result,
253 const ByteString &response_data) {
Paul Stewart188a84a2012-01-20 16:28:15 -0800254 EXPECT_EQ(HTTPRequest::kResultSuccess, result);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800255 EXPECT_TRUE(expected_response_.Equals(response_data));
Paul Stewart188a84a2012-01-20 16:28:15 -0800256 }
257 void ExpectResultCallbackWithResponse(const string &response) {
258 expected_response_ = ByteString(response, false);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800259 EXPECT_CALL(target_, ResultCallTarget(HTTPRequest::kResultSuccess, _))
Paul Stewart188a84a2012-01-20 16:28:15 -0800260 .WillOnce(Invoke(this, &HTTPRequestTest::InvokeResultVerify));
261 }
Paul Stewartbdb02e62012-02-22 16:24:33 -0800262 void ExpectReadEventCallback(const string &response) {
263 ByteString response_data(response, false);
264 EXPECT_CALL(target_, ReadEventCallTarget(ByteStringMatches(response_data)));
Paul Stewart188a84a2012-01-20 16:28:15 -0800265 }
Paul Stewartbdb02e62012-02-22 16:24:33 -0800266 void GetDNSResultFailure(const string &error_msg) {
267 Error error(Error::kOperationFailed, error_msg);
268 IPAddress address(IPAddress::kFamilyUnknown);
269 request_->GetDNSResult(error, address);
270 }
271 void GetDNSResultSuccess(const IPAddress &address) {
272 Error error;
273 request_->GetDNSResult(error, address);
Paul Stewart188a84a2012-01-20 16:28:15 -0800274 }
275 void OnConnectCompletion(bool result, int sockfd) {
276 request_->OnConnectCompletion(result, sockfd);
277 }
278 void ReadFromServer(const string &data) {
279 const unsigned char *ptr =
280 reinterpret_cast<const unsigned char *>(data.c_str());
281 vector<unsigned char> data_writable(ptr, ptr + data.length());
282 InputData server_data(data_writable.data(), data_writable.size());
283 request_->ReadFromServer(&server_data);
284 }
285 void WriteToServer(int fd) {
286 request_->WriteToServer(fd);
287 }
288 HTTPRequest::Result StartRequest(const string &url) {
289 HTTPURL http_url;
290 EXPECT_TRUE(http_url.ParseFromString(url));
291 return request_->Start(http_url,
292 target_.read_event_callback(),
293 target_.result_callback());
294 }
295 void SetupConnectWithURL(const string &url, const string &expected_hostname) {
296 ExpectRouteRequest();
297 ExpectDNSRequest(expected_hostname, true);
298 EXPECT_EQ(HTTPRequest::kResultInProgress, StartRequest(url));
299 IPAddress addr(IPAddress::kFamilyIPv4);
300 EXPECT_TRUE(addr.SetAddressFromString(kServerAddress));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800301 GetDNSResultSuccess(addr);
Paul Stewart188a84a2012-01-20 16:28:15 -0800302 }
303 void SetupConnect() {
304 SetupConnectWithURL(kTextURL, kTextSiteName);
305 }
306 void SetupConnectAsync() {
307 ExpectAsyncConnect(kServerAddress, kServerPort, true);
308 SetupConnect();
309 }
310 void SetupConnectComplete() {
311 SetupConnectAsync();
312 ExpectMonitorServerOutput();
313 OnConnectCompletion(true, kServerFD);
314 }
315 void CallTimeoutTask() {
316 request_->TimeoutTask();
317 }
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800318 void CallServerErrorCallback() {
319 request_->OnServerReadError(Error());
320 }
Paul Stewart188a84a2012-01-20 16:28:15 -0800321
322 private:
323 const string interface_name_;
324 // Owned by the HTTPRequest, but tracked here for EXPECT().
325 StrictMock<MockAsyncConnection> *server_async_connection_;
326 vector<string> dns_servers_;
327 // Owned by the HTTPRequest, but tracked here for EXPECT().
328 StrictMock<MockDNSClient> *dns_client_;
329 StrictMock<MockEventDispatcher> dispatcher_;
330 MockControl control_;
331 scoped_ptr<MockDeviceInfo> device_info_;
332 scoped_refptr<MockConnection> connection_;
333 scoped_ptr<HTTPRequest> request_;
334 StrictMock<MockSockets> sockets_;
335 StrictMock<CallbackTarget> target_;
336 ByteString expected_response_;
337};
338
339TEST_F(HTTPRequestTest, Constructor) {
340 ExpectReset();
341}
342
343
344TEST_F(HTTPRequestTest, FailConnectNumericSynchronous) {
345 ExpectRouteRequest();
346 ExpectConnectFailure();
347 ExpectStop();
348 EXPECT_EQ(HTTPRequest::kResultConnectionFailure, StartRequest(kNumericURL));
349 ExpectReset();
350}
351
352TEST_F(HTTPRequestTest, FailConnectNumericAsynchronous) {
353 ExpectRouteRequest();
354 ExpectAsyncConnect(kServerAddress, HTTPURL::kDefaultHTTPPort, true);
355 EXPECT_EQ(HTTPRequest::kResultInProgress, StartRequest(kNumericURL));
356 ExpectResultCallback(HTTPRequest::kResultConnectionFailure);
357 ExpectStop();
358 CallConnectCompletion(false, -1);
359 ExpectReset();
360}
361
362TEST_F(HTTPRequestTest, FailConnectNumericTimeout) {
363 ExpectRouteRequest();
364 ExpectAsyncConnect(kServerAddress, HTTPURL::kDefaultHTTPPort, true);
365 EXPECT_EQ(HTTPRequest::kResultInProgress, StartRequest(kNumericURL));
366 ExpectResultCallback(HTTPRequest::kResultConnectionTimeout);
367 ExpectStop();
368 CallTimeoutTask();
369 ExpectReset();
370}
371
372TEST_F(HTTPRequestTest, SyncConnectNumeric) {
373 ExpectRouteRequest();
374 ExpectSyncConnect(kServerAddress, HTTPURL::kDefaultHTTPPort);
375 ExpectMonitorServerOutput();
376 EXPECT_EQ(HTTPRequest::kResultInProgress, StartRequest(kNumericURL));
377}
378
379TEST_F(HTTPRequestTest, FailDNSStart) {
380 ExpectRouteRequest();
381 ExpectDNSRequest(kTextSiteName, false);
382 ExpectStop();
383 EXPECT_EQ(HTTPRequest::kResultDNSFailure, StartRequest(kTextURL));
384 ExpectReset();
385}
386
387TEST_F(HTTPRequestTest, FailDNSFailure) {
388 ExpectRouteRequest();
389 ExpectDNSRequest(kTextSiteName, true);
390 EXPECT_EQ(HTTPRequest::kResultInProgress, StartRequest(kTextURL));
Paul Stewart188a84a2012-01-20 16:28:15 -0800391 ExpectResultCallback(HTTPRequest::kResultDNSFailure);
392 ExpectStop();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800393 GetDNSResultFailure(DNSClient::kErrorNoData);
Paul Stewart188a84a2012-01-20 16:28:15 -0800394 ExpectReset();
395}
396
397TEST_F(HTTPRequestTest, FailDNSTimeout) {
398 ExpectRouteRequest();
399 ExpectDNSRequest(kTextSiteName, true);
400 EXPECT_EQ(HTTPRequest::kResultInProgress, StartRequest(kTextURL));
Paul Stewart188a84a2012-01-20 16:28:15 -0800401 ExpectResultCallback(HTTPRequest::kResultDNSTimeout);
402 ExpectStop();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800403 const string error(DNSClient::kErrorTimedOut);
404 GetDNSResultFailure(error);
Paul Stewart188a84a2012-01-20 16:28:15 -0800405 ExpectReset();
406}
407
408TEST_F(HTTPRequestTest, FailConnectText) {
409 ExpectConnectFailure();
410 ExpectResultCallback(HTTPRequest::kResultConnectionFailure);
411 ExpectStop();
412 SetupConnect();
413 ExpectReset();
414}
415
416TEST_F(HTTPRequestTest, ConnectComplete) {
417 SetupConnectComplete();
418}
419
420TEST_F(HTTPRequestTest, RequestTimeout) {
421 SetupConnectComplete();
422 ExpectResultCallback(HTTPRequest::kResultRequestTimeout);
423 ExpectStop();
424 CallTimeoutTask();
425}
426
427TEST_F(HTTPRequestTest, RequestData) {
428 SetupConnectComplete();
429 EXPECT_EQ(0, FindInRequestData(string("GET ") + kPath));
430 EXPECT_NE(string::npos,
431 FindInRequestData(string("\r\nHost: ") + kTextSiteName));
432 ByteString request_data = GetRequestData();
433 EXPECT_CALL(sockets(), Send(kServerFD, _, request_data.GetLength(), 0))
434 .WillOnce(Return(request_data.GetLength() - 1));
435 ExpectSetInputTimeout();
436 WriteToServer(kServerFD);
437 EXPECT_CALL(sockets(), Send(kServerFD, _, 1, 0))
438 .WillOnce(Return(1));
439 ExpectMonitorServerInput();
440 WriteToServer(kServerFD);
441}
442
443TEST_F(HTTPRequestTest, ResponseTimeout) {
444 SetupConnectComplete();
445 ByteString request_data = GetRequestData();
446 EXPECT_CALL(sockets(), Send(kServerFD, _, request_data.GetLength(), 0))
447 .WillOnce(Return(request_data.GetLength()));
448 ExpectMonitorServerInput();
449 WriteToServer(kServerFD);
450 ExpectResultCallback(HTTPRequest::kResultResponseTimeout);
451 ExpectStop();
452 CallTimeoutTask();
453}
454
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800455TEST_F(HTTPRequestTest, ResponseInputError) {
456 SetupConnectComplete();
457 ByteString request_data = GetRequestData();
458 EXPECT_CALL(sockets(), Send(kServerFD, _, request_data.GetLength(), 0))
459 .WillOnce(Return(request_data.GetLength()));
460 ExpectMonitorServerInput();
461 WriteToServer(kServerFD);
462 ExpectResultCallback(HTTPRequest::kResultResponseFailure);
463 ExpectStop();
464 CallServerErrorCallback();
465}
466
Paul Stewart188a84a2012-01-20 16:28:15 -0800467TEST_F(HTTPRequestTest, ResponseData) {
468 SetupConnectComplete();
469 const string response0("hello");
Paul Stewartbdb02e62012-02-22 16:24:33 -0800470 ExpectReadEventCallback(response0);
Paul Stewart188a84a2012-01-20 16:28:15 -0800471 ExpectSetInputTimeout();
472 ReadFromServer(response0);
473 ExpectInResponse(response0);
474
475 const string response1(" to you");
Paul Stewartbdb02e62012-02-22 16:24:33 -0800476 ExpectReadEventCallback(response0 + response1);
Paul Stewart188a84a2012-01-20 16:28:15 -0800477 ExpectSetInputTimeout();
478 ReadFromServer(response1);
479 ExpectInResponse(response1);
480
481 ExpectResultCallbackWithResponse(response0 + response1);
482 ExpectStop();
483 ReadFromServer("");
Paul Stewartbdb02e62012-02-22 16:24:33 -0800484 ExpectReset();
Paul Stewart188a84a2012-01-20 16:28:15 -0800485}
486
487} // namespace shill