1 //
2 // Copyright (C) 2012 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include <netinet/in.h>
18 #include <netinet/ip.h>
19 #include <sys/socket.h>
20 #include <unistd.h>
21
22 #include <memory>
23 #include <string>
24 #include <utility>
25 #include <vector>
26
27 #include <base/bind.h>
28 #include <base/location.h>
29 #include <base/logging.h>
30 #include <base/message_loop/message_loop.h>
31 #include <base/strings/string_number_conversions.h>
32 #include <base/strings/string_util.h>
33 #include <base/strings/stringprintf.h>
34 #include <base/time/time.h>
35 #include <brillo/message_loops/base_message_loop.h>
36 #include <brillo/message_loops/message_loop.h>
37 #include <brillo/message_loops/message_loop_utils.h>
38 #include <brillo/process.h>
39 #include <brillo/streams/file_stream.h>
40 #include <brillo/streams/stream.h>
41 #include <gtest/gtest.h>
42
43 #include "update_engine/common/fake_hardware.h"
44 #include "update_engine/common/file_fetcher.h"
45 #include "update_engine/common/http_common.h"
46 #include "update_engine/common/mock_http_fetcher.h"
47 #include "update_engine/common/multi_range_http_fetcher.h"
48 #include "update_engine/common/test_utils.h"
49 #include "update_engine/common/utils.h"
50 #include "update_engine/libcurl_http_fetcher.h"
51 #include "update_engine/mock_proxy_resolver.h"
52 #include "update_engine/proxy_resolver.h"
53
54 using brillo::MessageLoop;
55 using std::make_pair;
56 using std::pair;
57 using std::string;
58 using std::unique_ptr;
59 using std::vector;
60 using testing::DoAll;
61 using testing::Return;
62 using testing::SaveArg;
63 using testing::_;
64
65 namespace {
66
67 const int kBigLength = 100000;
68 const int kMediumLength = 1000;
69 const int kFlakyTruncateLength = 29000;
70 const int kFlakySleepEvery = 3;
71 const int kFlakySleepSecs = 10;
72
73 } // namespace
74
75 namespace chromeos_update_engine {
76
77 static const char *kUnusedUrl = "unused://unused";
78
LocalServerUrlForPath(in_port_t port,const string & path)79 static inline string LocalServerUrlForPath(in_port_t port,
80 const string& path) {
81 string port_str = (port ? base::StringPrintf(":%hu", port) : "");
82 return base::StringPrintf("http://127.0.0.1%s%s", port_str.c_str(),
83 path.c_str());
84 }
85
86 //
87 // Class hierarchy for HTTP server implementations.
88 //
89
90 class HttpServer {
91 public:
92 // This makes it an abstract class (dirty but works).
93 virtual ~HttpServer() = 0;
94
GetPort() const95 virtual in_port_t GetPort() const {
96 return 0;
97 }
98
99 bool started_;
100 };
101
~HttpServer()102 HttpServer::~HttpServer() {}
103
104
105 class NullHttpServer : public HttpServer {
106 public:
NullHttpServer()107 NullHttpServer() {
108 started_ = true;
109 }
110 };
111
112
113 class PythonHttpServer : public HttpServer {
114 public:
PythonHttpServer()115 PythonHttpServer() : port_(0) {
116 started_ = false;
117
118 // Spawn the server process.
119 unique_ptr<brillo::Process> http_server(new brillo::ProcessImpl());
120 http_server->AddArg(test_utils::GetBuildArtifactsPath("test_http_server"));
121 http_server->RedirectUsingPipe(STDOUT_FILENO, false);
122
123 if (!http_server->Start()) {
124 ADD_FAILURE() << "failed to spawn http server process";
125 return;
126 }
127 LOG(INFO) << "started http server with pid " << http_server->pid();
128
129 // Wait for server to begin accepting connections, obtain its port.
130 brillo::StreamPtr stdout = brillo::FileStream::FromFileDescriptor(
131 http_server->GetPipe(STDOUT_FILENO), false /* own */, nullptr);
132 if (!stdout)
133 return;
134
135 vector<char> buf(128);
136 string line;
137 while (line.find('\n') == string::npos) {
138 size_t read;
139 if (!stdout->ReadBlocking(buf.data(), buf.size(), &read, nullptr)) {
140 ADD_FAILURE() << "error reading http server stdout";
141 return;
142 }
143 line.append(buf.data(), read);
144 if (read == 0)
145 break;
146 }
147 // Parse the port from the output line.
148 const size_t listening_msg_prefix_len = strlen(kServerListeningMsgPrefix);
149 if (line.size() < listening_msg_prefix_len) {
150 ADD_FAILURE() << "server output too short";
151 return;
152 }
153
154 EXPECT_EQ(kServerListeningMsgPrefix,
155 line.substr(0, listening_msg_prefix_len));
156 string port_str = line.substr(listening_msg_prefix_len);
157 port_str.resize(port_str.find('\n'));
158 EXPECT_TRUE(base::StringToUint(port_str, &port_));
159
160 started_ = true;
161 LOG(INFO) << "server running, listening on port " << port_;
162
163 // Any failure before this point will SIGKILL the test server if started
164 // when the |http_server| goes out of scope.
165 http_server_ = std::move(http_server);
166 }
167
~PythonHttpServer()168 ~PythonHttpServer() {
169 // If there's no process, do nothing.
170 if (!http_server_)
171 return;
172 // Wait up to 10 seconds for the process to finish. Destroying the process
173 // will kill it with a SIGKILL otherwise.
174 http_server_->Kill(SIGTERM, 10);
175 }
176
GetPort() const177 in_port_t GetPort() const override {
178 return port_;
179 }
180
181 private:
182 static const char* kServerListeningMsgPrefix;
183
184 unique_ptr<brillo::Process> http_server_;
185 unsigned int port_;
186 };
187
188 const char* PythonHttpServer::kServerListeningMsgPrefix = "listening on port ";
189
190 //
191 // Class hierarchy for HTTP fetcher test wrappers.
192 //
193
194 class AnyHttpFetcherTest {
195 public:
AnyHttpFetcherTest()196 AnyHttpFetcherTest() {}
~AnyHttpFetcherTest()197 virtual ~AnyHttpFetcherTest() {}
198
199 virtual HttpFetcher* NewLargeFetcher(ProxyResolver* proxy_resolver) = 0;
NewLargeFetcher(size_t num_proxies)200 HttpFetcher* NewLargeFetcher(size_t num_proxies) {
201 proxy_resolver_.set_num_proxies(num_proxies);
202 return NewLargeFetcher(&proxy_resolver_);
203 }
NewLargeFetcher()204 HttpFetcher* NewLargeFetcher() {
205 return NewLargeFetcher(1);
206 }
207
208 virtual HttpFetcher* NewSmallFetcher(ProxyResolver* proxy_resolver) = 0;
NewSmallFetcher()209 HttpFetcher* NewSmallFetcher() {
210 proxy_resolver_.set_num_proxies(1);
211 return NewSmallFetcher(&proxy_resolver_);
212 }
213
BigUrl(in_port_t port) const214 virtual string BigUrl(in_port_t port) const { return kUnusedUrl; }
SmallUrl(in_port_t port) const215 virtual string SmallUrl(in_port_t port) const { return kUnusedUrl; }
ErrorUrl(in_port_t port) const216 virtual string ErrorUrl(in_port_t port) const { return kUnusedUrl; }
217
218 virtual bool IsMock() const = 0;
219 virtual bool IsMulti() const = 0;
220 virtual bool IsHttpSupported() const = 0;
221
IgnoreServerAborting(HttpServer * server) const222 virtual void IgnoreServerAborting(HttpServer* server) const {}
223
224 virtual HttpServer* CreateServer() = 0;
225
fake_hardware()226 FakeHardware* fake_hardware() {
227 return &fake_hardware_;
228 }
229
230 protected:
231 DirectProxyResolver proxy_resolver_;
232 FakeHardware fake_hardware_;
233 };
234
235 class MockHttpFetcherTest : public AnyHttpFetcherTest {
236 public:
237 // Necessary to unhide the definition in the base class.
238 using AnyHttpFetcherTest::NewLargeFetcher;
NewLargeFetcher(ProxyResolver * proxy_resolver)239 HttpFetcher* NewLargeFetcher(ProxyResolver* proxy_resolver) override {
240 brillo::Blob big_data(1000000);
241 return new MockHttpFetcher(
242 big_data.data(), big_data.size(), proxy_resolver);
243 }
244
245 // Necessary to unhide the definition in the base class.
246 using AnyHttpFetcherTest::NewSmallFetcher;
NewSmallFetcher(ProxyResolver * proxy_resolver)247 HttpFetcher* NewSmallFetcher(ProxyResolver* proxy_resolver) override {
248 return new MockHttpFetcher("x", 1, proxy_resolver);
249 }
250
IsMock() const251 bool IsMock() const override { return true; }
IsMulti() const252 bool IsMulti() const override { return false; }
IsHttpSupported() const253 bool IsHttpSupported() const override { return true; }
254
CreateServer()255 HttpServer* CreateServer() override {
256 return new NullHttpServer;
257 }
258 };
259
260 class LibcurlHttpFetcherTest : public AnyHttpFetcherTest {
261 public:
262 // Necessary to unhide the definition in the base class.
263 using AnyHttpFetcherTest::NewLargeFetcher;
NewLargeFetcher(ProxyResolver * proxy_resolver)264 HttpFetcher* NewLargeFetcher(ProxyResolver* proxy_resolver) override {
265 LibcurlHttpFetcher* ret =
266 new LibcurlHttpFetcher(proxy_resolver, &fake_hardware_);
267 // Speed up test execution.
268 ret->set_idle_seconds(1);
269 ret->set_retry_seconds(1);
270 fake_hardware_.SetIsOfficialBuild(false);
271 return ret;
272 }
273
274 // Necessary to unhide the definition in the base class.
275 using AnyHttpFetcherTest::NewSmallFetcher;
NewSmallFetcher(ProxyResolver * proxy_resolver)276 HttpFetcher* NewSmallFetcher(ProxyResolver* proxy_resolver) override {
277 return NewLargeFetcher(proxy_resolver);
278 }
279
BigUrl(in_port_t port) const280 string BigUrl(in_port_t port) const override {
281 return LocalServerUrlForPath(port,
282 base::StringPrintf("/download/%d",
283 kBigLength));
284 }
SmallUrl(in_port_t port) const285 string SmallUrl(in_port_t port) const override {
286 return LocalServerUrlForPath(port, "/foo");
287 }
ErrorUrl(in_port_t port) const288 string ErrorUrl(in_port_t port) const override {
289 return LocalServerUrlForPath(port, "/error");
290 }
291
IsMock() const292 bool IsMock() const override { return false; }
IsMulti() const293 bool IsMulti() const override { return false; }
IsHttpSupported() const294 bool IsHttpSupported() const override { return true; }
295
IgnoreServerAborting(HttpServer * server) const296 void IgnoreServerAborting(HttpServer* server) const override {
297 // Nothing to do.
298 }
299
CreateServer()300 HttpServer* CreateServer() override {
301 return new PythonHttpServer;
302 }
303 };
304
305 class MultiRangeHttpFetcherTest : public LibcurlHttpFetcherTest {
306 public:
307 // Necessary to unhide the definition in the base class.
308 using AnyHttpFetcherTest::NewLargeFetcher;
NewLargeFetcher(ProxyResolver * proxy_resolver)309 HttpFetcher* NewLargeFetcher(ProxyResolver* proxy_resolver) override {
310 MultiRangeHttpFetcher* ret = new MultiRangeHttpFetcher(
311 new LibcurlHttpFetcher(proxy_resolver, &fake_hardware_));
312 ret->ClearRanges();
313 ret->AddRange(0);
314 // Speed up test execution.
315 ret->set_idle_seconds(1);
316 ret->set_retry_seconds(1);
317 fake_hardware_.SetIsOfficialBuild(false);
318 return ret;
319 }
320
321 // Necessary to unhide the definition in the base class.
322 using AnyHttpFetcherTest::NewSmallFetcher;
NewSmallFetcher(ProxyResolver * proxy_resolver)323 HttpFetcher* NewSmallFetcher(ProxyResolver* proxy_resolver) override {
324 return NewLargeFetcher(proxy_resolver);
325 }
326
IsMulti() const327 bool IsMulti() const override { return true; }
328 };
329
330 class FileFetcherTest : public AnyHttpFetcherTest {
331 public:
332 // Necessary to unhide the definition in the base class.
333 using AnyHttpFetcherTest::NewLargeFetcher;
NewLargeFetcher(ProxyResolver *)334 HttpFetcher* NewLargeFetcher(ProxyResolver* /* proxy_resolver */) override {
335 return new FileFetcher();
336 }
337
338 // Necessary to unhide the definition in the base class.
339 using AnyHttpFetcherTest::NewSmallFetcher;
NewSmallFetcher(ProxyResolver * proxy_resolver)340 HttpFetcher* NewSmallFetcher(ProxyResolver* proxy_resolver) override {
341 return NewLargeFetcher(proxy_resolver);
342 }
343
BigUrl(in_port_t port) const344 string BigUrl(in_port_t port) const override {
345 return "file://" + temp_file_.path();
346 }
SmallUrl(in_port_t port) const347 string SmallUrl(in_port_t port) const override {
348 test_utils::WriteFileString(temp_file_.path(), "small contents");
349 return "file://" + temp_file_.path();
350 }
ErrorUrl(in_port_t port) const351 string ErrorUrl(in_port_t port) const override {
352 return "file:///path/to/non-existing-file";
353 }
354
IsMock() const355 bool IsMock() const override { return false; }
IsMulti() const356 bool IsMulti() const override { return false; }
IsHttpSupported() const357 bool IsHttpSupported() const override { return false; }
358
IgnoreServerAborting(HttpServer * server) const359 void IgnoreServerAborting(HttpServer* server) const override {}
360
CreateServer()361 HttpServer* CreateServer() override { return new NullHttpServer; }
362
363 private:
364 test_utils::ScopedTempFile temp_file_{"ue_file_fetcher.XXXXXX"};
365 };
366
367 //
368 // Infrastructure for type tests of HTTP fetcher.
369 // See: http://code.google.com/p/googletest/wiki/AdvancedGuide#Typed_Tests
370 //
371
372 // Fixture class template. We use an explicit constraint to guarantee that it
373 // can only be instantiated with an AnyHttpFetcherTest type, see:
374 // http://www2.research.att.com/~bs/bs_faq2.html#constraints
375 template <typename T>
376 class HttpFetcherTest : public ::testing::Test {
377 public:
378 base::MessageLoopForIO base_loop_;
379 brillo::BaseMessageLoop loop_{&base_loop_};
380
381 T test_;
382
383 protected:
HttpFetcherTest()384 HttpFetcherTest() {
385 loop_.SetAsCurrent();
386 }
387
TearDown()388 void TearDown() override {
389 EXPECT_EQ(0, brillo::MessageLoopRunMaxIterations(&loop_, 1));
390 }
391
392 private:
TypeConstraint(T * a)393 static void TypeConstraint(T* a) {
394 AnyHttpFetcherTest *b = a;
395 if (b == 0) // Silence compiler warning of unused variable.
396 *b = a;
397 }
398 };
399
400 // Test case types list.
401 typedef ::testing::Types<LibcurlHttpFetcherTest,
402 MockHttpFetcherTest,
403 MultiRangeHttpFetcherTest,
404 FileFetcherTest>
405 HttpFetcherTestTypes;
406 TYPED_TEST_CASE(HttpFetcherTest, HttpFetcherTestTypes);
407
408
409 namespace {
410 class HttpFetcherTestDelegate : public HttpFetcherDelegate {
411 public:
412 HttpFetcherTestDelegate() = default;
413
ReceivedBytes(HttpFetcher *,const void * bytes,size_t length)414 void ReceivedBytes(HttpFetcher* /* fetcher */,
415 const void* bytes,
416 size_t length) override {
417 data.append(reinterpret_cast<const char*>(bytes), length);
418 // Update counters
419 times_received_bytes_called_++;
420 }
421
TransferComplete(HttpFetcher * fetcher,bool successful)422 void TransferComplete(HttpFetcher* fetcher, bool successful) override {
423 if (is_expect_error_)
424 EXPECT_EQ(kHttpResponseNotFound, fetcher->http_response_code());
425 else
426 EXPECT_EQ(kHttpResponseOk, fetcher->http_response_code());
427 MessageLoop::current()->BreakLoop();
428
429 // Update counter
430 times_transfer_complete_called_++;
431 }
432
TransferTerminated(HttpFetcher * fetcher)433 void TransferTerminated(HttpFetcher* fetcher) override {
434 times_transfer_terminated_called_++;
435 MessageLoop::current()->BreakLoop();
436 }
437
438 // Are we expecting an error response? (default: no)
439 bool is_expect_error_{false};
440
441 // Counters for callback invocations.
442 int times_transfer_complete_called_{0};
443 int times_transfer_terminated_called_{0};
444 int times_received_bytes_called_{0};
445
446 // The received data bytes.
447 string data;
448 };
449
450
StartTransfer(HttpFetcher * http_fetcher,const string & url)451 void StartTransfer(HttpFetcher* http_fetcher, const string& url) {
452 http_fetcher->BeginTransfer(url);
453 }
454 } // namespace
455
TYPED_TEST(HttpFetcherTest,SimpleTest)456 TYPED_TEST(HttpFetcherTest, SimpleTest) {
457 HttpFetcherTestDelegate delegate;
458 unique_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
459 fetcher->set_delegate(&delegate);
460
461 unique_ptr<HttpServer> server(this->test_.CreateServer());
462 ASSERT_TRUE(server->started_);
463
464 this->loop_.PostTask(FROM_HERE, base::Bind(
465 StartTransfer,
466 fetcher.get(),
467 this->test_.SmallUrl(server->GetPort())));
468 this->loop_.Run();
469 EXPECT_EQ(0, delegate.times_transfer_terminated_called_);
470 }
471
TYPED_TEST(HttpFetcherTest,SimpleBigTest)472 TYPED_TEST(HttpFetcherTest, SimpleBigTest) {
473 HttpFetcherTestDelegate delegate;
474 unique_ptr<HttpFetcher> fetcher(this->test_.NewLargeFetcher());
475 fetcher->set_delegate(&delegate);
476
477 unique_ptr<HttpServer> server(this->test_.CreateServer());
478 ASSERT_TRUE(server->started_);
479
480 this->loop_.PostTask(FROM_HERE, base::Bind(
481 StartTransfer,
482 fetcher.get(),
483 this->test_.BigUrl(server->GetPort())));
484 this->loop_.Run();
485 EXPECT_EQ(0, delegate.times_transfer_terminated_called_);
486 }
487
488 // Issue #9648: when server returns an error HTTP response, the fetcher needs to
489 // terminate transfer prematurely, rather than try to process the error payload.
TYPED_TEST(HttpFetcherTest,ErrorTest)490 TYPED_TEST(HttpFetcherTest, ErrorTest) {
491 if (this->test_.IsMock() || this->test_.IsMulti())
492 return;
493 HttpFetcherTestDelegate delegate;
494
495 // Delegate should expect an error response.
496 delegate.is_expect_error_ = true;
497
498 unique_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
499 fetcher->set_delegate(&delegate);
500
501 unique_ptr<HttpServer> server(this->test_.CreateServer());
502 ASSERT_TRUE(server->started_);
503
504 this->loop_.PostTask(FROM_HERE, base::Bind(
505 StartTransfer,
506 fetcher.get(),
507 this->test_.ErrorUrl(server->GetPort())));
508 this->loop_.Run();
509
510 // Make sure that no bytes were received.
511 EXPECT_EQ(0, delegate.times_received_bytes_called_);
512 EXPECT_EQ(0U, fetcher->GetBytesDownloaded());
513
514 // Make sure that transfer completion was signaled once, and no termination
515 // was signaled.
516 EXPECT_EQ(1, delegate.times_transfer_complete_called_);
517 EXPECT_EQ(0, delegate.times_transfer_terminated_called_);
518 }
519
TYPED_TEST(HttpFetcherTest,ExtraHeadersInRequestTest)520 TYPED_TEST(HttpFetcherTest, ExtraHeadersInRequestTest) {
521 if (this->test_.IsMock() || !this->test_.IsHttpSupported())
522 return;
523
524 HttpFetcherTestDelegate delegate;
525 unique_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
526 fetcher->set_delegate(&delegate);
527 fetcher->SetHeader("User-Agent", "MyTest");
528 fetcher->SetHeader("user-agent", "Override that header");
529 fetcher->SetHeader("Authorization", "Basic user:passwd");
530
531 // Invalid headers.
532 fetcher->SetHeader("X-Foo", "Invalid\nHeader\nIgnored");
533 fetcher->SetHeader("X-Bar: ", "I do not know how to parse");
534
535 // Hide Accept header normally added by default.
536 fetcher->SetHeader("Accept", "");
537
538 PythonHttpServer server;
539 int port = server.GetPort();
540 ASSERT_TRUE(server.started_);
541
542 this->loop_.PostTask(
543 FROM_HERE,
544 base::Bind(StartTransfer,
545 fetcher.get(),
546 LocalServerUrlForPath(port, "/echo-headers")));
547 this->loop_.Run();
548
549 EXPECT_NE(string::npos,
550 delegate.data.find("user-agent: Override that header\r\n"));
551 EXPECT_NE(string::npos,
552 delegate.data.find("Authorization: Basic user:passwd\r\n"));
553
554 EXPECT_EQ(string::npos, delegate.data.find("\nAccept:"));
555 EXPECT_EQ(string::npos, delegate.data.find("X-Foo: Invalid"));
556 EXPECT_EQ(string::npos, delegate.data.find("X-Bar: I do not"));
557 }
558
559 namespace {
560 class PausingHttpFetcherTestDelegate : public HttpFetcherDelegate {
561 public:
ReceivedBytes(HttpFetcher * fetcher,const void *,size_t)562 void ReceivedBytes(HttpFetcher* fetcher,
563 const void* /* bytes */, size_t /* length */) override {
564 CHECK(!paused_);
565 paused_ = true;
566 fetcher->Pause();
567 }
TransferComplete(HttpFetcher * fetcher,bool successful)568 void TransferComplete(HttpFetcher* fetcher, bool successful) override {
569 MessageLoop::current()->BreakLoop();
570 }
TransferTerminated(HttpFetcher * fetcher)571 void TransferTerminated(HttpFetcher* fetcher) override {
572 ADD_FAILURE();
573 }
Unpause()574 void Unpause() {
575 CHECK(paused_);
576 paused_ = false;
577 fetcher_->Unpause();
578 }
579 bool paused_;
580 HttpFetcher* fetcher_;
581 };
582
UnpausingTimeoutCallback(PausingHttpFetcherTestDelegate * delegate,MessageLoop::TaskId * my_id)583 void UnpausingTimeoutCallback(PausingHttpFetcherTestDelegate* delegate,
584 MessageLoop::TaskId* my_id) {
585 if (delegate->paused_)
586 delegate->Unpause();
587 // Update the task id with the new scheduled callback.
588 *my_id = MessageLoop::current()->PostDelayedTask(
589 FROM_HERE,
590 base::Bind(&UnpausingTimeoutCallback, delegate, my_id),
591 base::TimeDelta::FromMilliseconds(200));
592 }
593 } // namespace
594
TYPED_TEST(HttpFetcherTest,PauseTest)595 TYPED_TEST(HttpFetcherTest, PauseTest) {
596 PausingHttpFetcherTestDelegate delegate;
597 unique_ptr<HttpFetcher> fetcher(this->test_.NewLargeFetcher());
598 delegate.paused_ = false;
599 delegate.fetcher_ = fetcher.get();
600 fetcher->set_delegate(&delegate);
601
602 unique_ptr<HttpServer> server(this->test_.CreateServer());
603 ASSERT_TRUE(server->started_);
604
605 MessageLoop::TaskId callback_id;
606 callback_id = this->loop_.PostDelayedTask(
607 FROM_HERE,
608 base::Bind(&UnpausingTimeoutCallback, &delegate, &callback_id),
609 base::TimeDelta::FromMilliseconds(200));
610 fetcher->BeginTransfer(this->test_.BigUrl(server->GetPort()));
611
612 this->loop_.Run();
613 EXPECT_TRUE(this->loop_.CancelTask(callback_id));
614 }
615
616 // This test will pause the fetcher while the download is not yet started
617 // because it is waiting for the proxy to be resolved.
TYPED_TEST(HttpFetcherTest,PauseWhileResolvingProxyTest)618 TYPED_TEST(HttpFetcherTest, PauseWhileResolvingProxyTest) {
619 if (this->test_.IsMock() || !this->test_.IsHttpSupported())
620 return;
621 MockProxyResolver mock_resolver;
622 unique_ptr<HttpFetcher> fetcher(this->test_.NewLargeFetcher(&mock_resolver));
623
624 // Saved arguments from the proxy call.
625 ProxiesResolvedFn proxy_callback;
626 EXPECT_CALL(mock_resolver, GetProxiesForUrl("http://fake_url", _))
627 .WillOnce(DoAll(SaveArg<1>(&proxy_callback), Return(true)));
628 fetcher->BeginTransfer("http://fake_url");
629 testing::Mock::VerifyAndClearExpectations(&mock_resolver);
630
631 // Pausing and unpausing while resolving the proxy should not affect anything.
632 fetcher->Pause();
633 fetcher->Unpause();
634 fetcher->Pause();
635 // Proxy resolver comes back after we paused the fetcher.
636 ASSERT_FALSE(proxy_callback.is_null());
637 proxy_callback.Run({1, kNoProxy});
638 }
639
640 namespace {
641 class AbortingHttpFetcherTestDelegate : public HttpFetcherDelegate {
642 public:
ReceivedBytes(HttpFetcher * fetcher,const void * bytes,size_t length)643 void ReceivedBytes(HttpFetcher* fetcher,
644 const void* bytes, size_t length) override {}
TransferComplete(HttpFetcher * fetcher,bool successful)645 void TransferComplete(HttpFetcher* fetcher, bool successful) override {
646 ADD_FAILURE(); // We should never get here
647 MessageLoop::current()->BreakLoop();
648 }
TransferTerminated(HttpFetcher * fetcher)649 void TransferTerminated(HttpFetcher* fetcher) override {
650 EXPECT_EQ(fetcher, fetcher_.get());
651 EXPECT_FALSE(once_);
652 EXPECT_TRUE(callback_once_);
653 callback_once_ = false;
654 // The fetcher could have a callback scheduled on the ProxyResolver that
655 // can fire after this callback. We wait until the end of the test to
656 // delete the fetcher.
657 }
TerminateTransfer()658 void TerminateTransfer() {
659 CHECK(once_);
660 once_ = false;
661 fetcher_->TerminateTransfer();
662 }
EndLoop()663 void EndLoop() {
664 MessageLoop::current()->BreakLoop();
665 }
666 bool once_;
667 bool callback_once_;
668 unique_ptr<HttpFetcher> fetcher_;
669 };
670
AbortingTimeoutCallback(AbortingHttpFetcherTestDelegate * delegate,MessageLoop::TaskId * my_id)671 void AbortingTimeoutCallback(AbortingHttpFetcherTestDelegate* delegate,
672 MessageLoop::TaskId* my_id) {
673 if (delegate->once_) {
674 delegate->TerminateTransfer();
675 *my_id = MessageLoop::current()->PostTask(
676 FROM_HERE,
677 base::Bind(AbortingTimeoutCallback, delegate, my_id));
678 } else {
679 delegate->EndLoop();
680 *my_id = MessageLoop::kTaskIdNull;
681 }
682 }
683 } // namespace
684
TYPED_TEST(HttpFetcherTest,AbortTest)685 TYPED_TEST(HttpFetcherTest, AbortTest) {
686 AbortingHttpFetcherTestDelegate delegate;
687 delegate.fetcher_.reset(this->test_.NewLargeFetcher());
688 delegate.once_ = true;
689 delegate.callback_once_ = true;
690 delegate.fetcher_->set_delegate(&delegate);
691
692 unique_ptr<HttpServer> server(this->test_.CreateServer());
693 this->test_.IgnoreServerAborting(server.get());
694 ASSERT_TRUE(server->started_);
695
696 MessageLoop::TaskId task_id = MessageLoop::kTaskIdNull;
697
698 task_id = this->loop_.PostTask(
699 FROM_HERE,
700 base::Bind(AbortingTimeoutCallback, &delegate, &task_id));
701 delegate.fetcher_->BeginTransfer(this->test_.BigUrl(server->GetPort()));
702
703 this->loop_.Run();
704 CHECK(!delegate.once_);
705 CHECK(!delegate.callback_once_);
706 this->loop_.CancelTask(task_id);
707 }
708
TYPED_TEST(HttpFetcherTest,TerminateTransferWhileResolvingProxyTest)709 TYPED_TEST(HttpFetcherTest, TerminateTransferWhileResolvingProxyTest) {
710 if (this->test_.IsMock() || !this->test_.IsHttpSupported())
711 return;
712 MockProxyResolver mock_resolver;
713 unique_ptr<HttpFetcher> fetcher(this->test_.NewLargeFetcher(&mock_resolver));
714
715 HttpFetcherTestDelegate delegate;
716 fetcher->set_delegate(&delegate);
717
718 EXPECT_CALL(mock_resolver, GetProxiesForUrl(_, _)).WillOnce(Return(123));
719 fetcher->BeginTransfer("http://fake_url");
720 // Run the message loop until idle. This must call the MockProxyResolver with
721 // the request.
722 while (this->loop_.RunOnce(false)) {
723 }
724 testing::Mock::VerifyAndClearExpectations(&mock_resolver);
725
726 EXPECT_CALL(mock_resolver, CancelProxyRequest(123)).WillOnce(Return(true));
727
728 // Terminate the transfer right before the proxy resolution response.
729 fetcher->TerminateTransfer();
730 EXPECT_EQ(0, delegate.times_received_bytes_called_);
731 EXPECT_EQ(0, delegate.times_transfer_complete_called_);
732 EXPECT_EQ(1, delegate.times_transfer_terminated_called_);
733 }
734
735 namespace {
736 class FlakyHttpFetcherTestDelegate : public HttpFetcherDelegate {
737 public:
ReceivedBytes(HttpFetcher * fetcher,const void * bytes,size_t length)738 void ReceivedBytes(HttpFetcher* fetcher,
739 const void* bytes, size_t length) override {
740 data.append(reinterpret_cast<const char*>(bytes), length);
741 }
TransferComplete(HttpFetcher * fetcher,bool successful)742 void TransferComplete(HttpFetcher* fetcher, bool successful) override {
743 EXPECT_TRUE(successful);
744 EXPECT_EQ(kHttpResponsePartialContent, fetcher->http_response_code());
745 MessageLoop::current()->BreakLoop();
746 }
TransferTerminated(HttpFetcher * fetcher)747 void TransferTerminated(HttpFetcher* fetcher) override {
748 ADD_FAILURE();
749 }
750 string data;
751 };
752 } // namespace
753
TYPED_TEST(HttpFetcherTest,FlakyTest)754 TYPED_TEST(HttpFetcherTest, FlakyTest) {
755 if (this->test_.IsMock() || !this->test_.IsHttpSupported())
756 return;
757 {
758 FlakyHttpFetcherTestDelegate delegate;
759 unique_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
760 fetcher->set_delegate(&delegate);
761
762 unique_ptr<HttpServer> server(this->test_.CreateServer());
763 ASSERT_TRUE(server->started_);
764
765 this->loop_.PostTask(FROM_HERE, base::Bind(
766 &StartTransfer,
767 fetcher.get(),
768 LocalServerUrlForPath(server->GetPort(),
769 base::StringPrintf("/flaky/%d/%d/%d/%d",
770 kBigLength,
771 kFlakyTruncateLength,
772 kFlakySleepEvery,
773 kFlakySleepSecs))));
774 this->loop_.Run();
775
776 // verify the data we get back
777 ASSERT_EQ(kBigLength, static_cast<int>(delegate.data.size()));
778 for (int i = 0; i < kBigLength; i += 10) {
779 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
780 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
781 }
782 }
783 }
784
785 namespace {
786 // This delegate kills the server attached to it after receiving any bytes.
787 // This can be used for testing what happens when you try to fetch data and
788 // the server dies.
789 class FailureHttpFetcherTestDelegate : public HttpFetcherDelegate {
790 public:
FailureHttpFetcherTestDelegate(PythonHttpServer * server)791 explicit FailureHttpFetcherTestDelegate(PythonHttpServer* server)
792 : server_(server) {}
793
~FailureHttpFetcherTestDelegate()794 ~FailureHttpFetcherTestDelegate() override {
795 if (server_) {
796 LOG(INFO) << "Stopping server in destructor";
797 server_.reset();
798 LOG(INFO) << "server stopped";
799 }
800 }
801
ReceivedBytes(HttpFetcher * fetcher,const void * bytes,size_t length)802 void ReceivedBytes(HttpFetcher* fetcher,
803 const void* bytes, size_t length) override {
804 if (server_) {
805 LOG(INFO) << "Stopping server in ReceivedBytes";
806 server_.reset();
807 LOG(INFO) << "server stopped";
808 }
809 }
TransferComplete(HttpFetcher * fetcher,bool successful)810 void TransferComplete(HttpFetcher* fetcher, bool successful) override {
811 EXPECT_FALSE(successful);
812 EXPECT_EQ(0, fetcher->http_response_code());
813 times_transfer_complete_called_++;
814 MessageLoop::current()->BreakLoop();
815 }
TransferTerminated(HttpFetcher * fetcher)816 void TransferTerminated(HttpFetcher* fetcher) override {
817 times_transfer_terminated_called_++;
818 MessageLoop::current()->BreakLoop();
819 }
820 unique_ptr<PythonHttpServer> server_;
821 int times_transfer_terminated_called_{0};
822 int times_transfer_complete_called_{0};
823 };
824 } // namespace
825
826
TYPED_TEST(HttpFetcherTest,FailureTest)827 TYPED_TEST(HttpFetcherTest, FailureTest) {
828 // This test ensures that a fetcher responds correctly when a server isn't
829 // available at all.
830 if (this->test_.IsMock())
831 return;
832 FailureHttpFetcherTestDelegate delegate(nullptr);
833 unique_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
834 fetcher->set_delegate(&delegate);
835
836 this->loop_.PostTask(
837 FROM_HERE,
838 base::Bind(
839 StartTransfer, fetcher.get(), "http://host_doesnt_exist99999999"));
840 this->loop_.Run();
841 EXPECT_EQ(1, delegate.times_transfer_complete_called_);
842 EXPECT_EQ(0, delegate.times_transfer_terminated_called_);
843
844 // Exiting and testing happens in the delegate
845 }
846
TYPED_TEST(HttpFetcherTest,NoResponseTest)847 TYPED_TEST(HttpFetcherTest, NoResponseTest) {
848 // This test starts a new http server but the server doesn't respond and just
849 // closes the connection.
850 if (this->test_.IsMock())
851 return;
852
853 PythonHttpServer* server = new PythonHttpServer();
854 int port = server->GetPort();
855 ASSERT_TRUE(server->started_);
856
857 // Handles destruction and claims ownership.
858 FailureHttpFetcherTestDelegate delegate(server);
859 unique_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
860 fetcher->set_delegate(&delegate);
861 // The server will not reply at all, so we can limit the execution time of the
862 // test by reducing the low-speed timeout to something small. The test will
863 // finish once the TimeoutCallback() triggers (every second) and the timeout
864 // expired.
865 fetcher->set_low_speed_limit(kDownloadLowSpeedLimitBps, 1);
866
867 this->loop_.PostTask(FROM_HERE, base::Bind(
868 StartTransfer,
869 fetcher.get(),
870 LocalServerUrlForPath(port, "/hang")));
871 this->loop_.Run();
872 EXPECT_EQ(1, delegate.times_transfer_complete_called_);
873 EXPECT_EQ(0, delegate.times_transfer_terminated_called_);
874
875 // Check that no other callback runs in the next two seconds. That would
876 // indicate a leaked callback.
877 bool timeout = false;
878 auto callback = base::Bind([](bool* timeout) { *timeout = true; },
879 base::Unretained(&timeout));
880 this->loop_.PostDelayedTask(FROM_HERE, callback,
881 base::TimeDelta::FromSeconds(2));
882 EXPECT_TRUE(this->loop_.RunOnce(true));
883 EXPECT_TRUE(timeout);
884 }
885
TYPED_TEST(HttpFetcherTest,ServerDiesTest)886 TYPED_TEST(HttpFetcherTest, ServerDiesTest) {
887 // This test starts a new http server and kills it after receiving its first
888 // set of bytes. It test whether or not our fetcher eventually gives up on
889 // retries and aborts correctly.
890 if (this->test_.IsMock())
891 return;
892 PythonHttpServer* server = new PythonHttpServer();
893 int port = server->GetPort();
894 ASSERT_TRUE(server->started_);
895
896 // Handles destruction and claims ownership.
897 FailureHttpFetcherTestDelegate delegate(server);
898 unique_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
899 fetcher->set_delegate(&delegate);
900
901 this->loop_.PostTask(
902 FROM_HERE,
903 base::Bind(StartTransfer,
904 fetcher.get(),
905 LocalServerUrlForPath(port,
906 base::StringPrintf("/flaky/%d/%d/%d/%d",
907 kBigLength,
908 kFlakyTruncateLength,
909 kFlakySleepEvery,
910 kFlakySleepSecs))));
911 this->loop_.Run();
912 EXPECT_EQ(1, delegate.times_transfer_complete_called_);
913 EXPECT_EQ(0, delegate.times_transfer_terminated_called_);
914
915 // Exiting and testing happens in the delegate
916 }
917
918 // Test that we can cancel a transfer while it is still trying to connect to the
919 // server. This test kills the server after a few bytes are received.
TYPED_TEST(HttpFetcherTest,TerminateTransferWhenServerDiedTest)920 TYPED_TEST(HttpFetcherTest, TerminateTransferWhenServerDiedTest) {
921 if (this->test_.IsMock() || !this->test_.IsHttpSupported())
922 return;
923
924 PythonHttpServer* server = new PythonHttpServer();
925 int port = server->GetPort();
926 ASSERT_TRUE(server->started_);
927
928 // Handles destruction and claims ownership.
929 FailureHttpFetcherTestDelegate delegate(server);
930 unique_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
931 fetcher->set_delegate(&delegate);
932
933 this->loop_.PostTask(
934 FROM_HERE,
935 base::Bind(StartTransfer,
936 fetcher.get(),
937 LocalServerUrlForPath(port,
938 base::StringPrintf("/flaky/%d/%d/%d/%d",
939 kBigLength,
940 kFlakyTruncateLength,
941 kFlakySleepEvery,
942 kFlakySleepSecs))));
943 // Terminating the transfer after 3 seconds gives it a chance to contact the
944 // server and enter the retry loop.
945 this->loop_.PostDelayedTask(FROM_HERE,
946 base::Bind(&HttpFetcher::TerminateTransfer,
947 base::Unretained(fetcher.get())),
948 base::TimeDelta::FromSeconds(3));
949
950 // Exiting and testing happens in the delegate.
951 this->loop_.Run();
952 EXPECT_EQ(0, delegate.times_transfer_complete_called_);
953 EXPECT_EQ(1, delegate.times_transfer_terminated_called_);
954
955 // Check that no other callback runs in the next two seconds. That would
956 // indicate a leaked callback.
957 bool timeout = false;
958 auto callback = base::Bind([](bool* timeout) { *timeout = true; },
959 base::Unretained(&timeout));
960 this->loop_.PostDelayedTask(
961 FROM_HERE, callback, base::TimeDelta::FromSeconds(2));
962 EXPECT_TRUE(this->loop_.RunOnce(true));
963 EXPECT_TRUE(timeout);
964 }
965
966 namespace {
967 const HttpResponseCode kRedirectCodes[] = {
968 kHttpResponseMovedPermanently, kHttpResponseFound, kHttpResponseSeeOther,
969 kHttpResponseTempRedirect
970 };
971
972 class RedirectHttpFetcherTestDelegate : public HttpFetcherDelegate {
973 public:
RedirectHttpFetcherTestDelegate(bool expected_successful)974 explicit RedirectHttpFetcherTestDelegate(bool expected_successful)
975 : expected_successful_(expected_successful) {}
ReceivedBytes(HttpFetcher * fetcher,const void * bytes,size_t length)976 void ReceivedBytes(HttpFetcher* fetcher,
977 const void* bytes, size_t length) override {
978 data.append(reinterpret_cast<const char*>(bytes), length);
979 }
TransferComplete(HttpFetcher * fetcher,bool successful)980 void TransferComplete(HttpFetcher* fetcher, bool successful) override {
981 EXPECT_EQ(expected_successful_, successful);
982 if (expected_successful_) {
983 EXPECT_EQ(kHttpResponseOk, fetcher->http_response_code());
984 } else {
985 EXPECT_GE(fetcher->http_response_code(), kHttpResponseMovedPermanently);
986 EXPECT_LE(fetcher->http_response_code(), kHttpResponseTempRedirect);
987 }
988 MessageLoop::current()->BreakLoop();
989 }
TransferTerminated(HttpFetcher * fetcher)990 void TransferTerminated(HttpFetcher* fetcher) override {
991 ADD_FAILURE();
992 }
993 bool expected_successful_;
994 string data;
995 };
996
997 // RedirectTest takes ownership of |http_fetcher|.
RedirectTest(const HttpServer * server,bool expected_successful,const string & url,HttpFetcher * http_fetcher)998 void RedirectTest(const HttpServer* server,
999 bool expected_successful,
1000 const string& url,
1001 HttpFetcher* http_fetcher) {
1002 RedirectHttpFetcherTestDelegate delegate(expected_successful);
1003 unique_ptr<HttpFetcher> fetcher(http_fetcher);
1004 fetcher->set_delegate(&delegate);
1005
1006 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
1007 StartTransfer,
1008 fetcher.get(),
1009 LocalServerUrlForPath(server->GetPort(), url)));
1010 MessageLoop::current()->Run();
1011 if (expected_successful) {
1012 // verify the data we get back
1013 ASSERT_EQ(static_cast<size_t>(kMediumLength), delegate.data.size());
1014 for (int i = 0; i < kMediumLength; i += 10) {
1015 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
1016 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
1017 }
1018 }
1019 }
1020 } // namespace
1021
TYPED_TEST(HttpFetcherTest,SimpleRedirectTest)1022 TYPED_TEST(HttpFetcherTest, SimpleRedirectTest) {
1023 if (this->test_.IsMock() || !this->test_.IsHttpSupported())
1024 return;
1025
1026 unique_ptr<HttpServer> server(this->test_.CreateServer());
1027 ASSERT_TRUE(server->started_);
1028
1029 for (size_t c = 0; c < arraysize(kRedirectCodes); ++c) {
1030 const string url = base::StringPrintf("/redirect/%d/download/%d",
1031 kRedirectCodes[c],
1032 kMediumLength);
1033 RedirectTest(server.get(), true, url, this->test_.NewLargeFetcher());
1034 }
1035 }
1036
TYPED_TEST(HttpFetcherTest,MaxRedirectTest)1037 TYPED_TEST(HttpFetcherTest, MaxRedirectTest) {
1038 if (this->test_.IsMock() || !this->test_.IsHttpSupported())
1039 return;
1040
1041 unique_ptr<HttpServer> server(this->test_.CreateServer());
1042 ASSERT_TRUE(server->started_);
1043
1044 string url;
1045 for (int r = 0; r < kDownloadMaxRedirects; r++) {
1046 url += base::StringPrintf("/redirect/%d",
1047 kRedirectCodes[r % arraysize(kRedirectCodes)]);
1048 }
1049 url += base::StringPrintf("/download/%d", kMediumLength);
1050 RedirectTest(server.get(), true, url, this->test_.NewLargeFetcher());
1051 }
1052
TYPED_TEST(HttpFetcherTest,BeyondMaxRedirectTest)1053 TYPED_TEST(HttpFetcherTest, BeyondMaxRedirectTest) {
1054 if (this->test_.IsMock() || !this->test_.IsHttpSupported())
1055 return;
1056
1057 unique_ptr<HttpServer> server(this->test_.CreateServer());
1058 ASSERT_TRUE(server->started_);
1059
1060 string url;
1061 for (int r = 0; r < kDownloadMaxRedirects + 1; r++) {
1062 url += base::StringPrintf("/redirect/%d",
1063 kRedirectCodes[r % arraysize(kRedirectCodes)]);
1064 }
1065 url += base::StringPrintf("/download/%d", kMediumLength);
1066 RedirectTest(server.get(), false, url, this->test_.NewLargeFetcher());
1067 }
1068
1069 namespace {
1070 class MultiHttpFetcherTestDelegate : public HttpFetcherDelegate {
1071 public:
MultiHttpFetcherTestDelegate(int expected_response_code)1072 explicit MultiHttpFetcherTestDelegate(int expected_response_code)
1073 : expected_response_code_(expected_response_code) {}
1074
ReceivedBytes(HttpFetcher * fetcher,const void * bytes,size_t length)1075 void ReceivedBytes(HttpFetcher* fetcher,
1076 const void* bytes, size_t length) override {
1077 EXPECT_EQ(fetcher, fetcher_.get());
1078 data.append(reinterpret_cast<const char*>(bytes), length);
1079 }
1080
TransferComplete(HttpFetcher * fetcher,bool successful)1081 void TransferComplete(HttpFetcher* fetcher, bool successful) override {
1082 EXPECT_EQ(fetcher, fetcher_.get());
1083 EXPECT_EQ(expected_response_code_ != kHttpResponseUndefined, successful);
1084 if (expected_response_code_ != 0)
1085 EXPECT_EQ(expected_response_code_, fetcher->http_response_code());
1086 // Destroy the fetcher (because we're allowed to).
1087 fetcher_.reset(nullptr);
1088 MessageLoop::current()->BreakLoop();
1089 }
1090
TransferTerminated(HttpFetcher * fetcher)1091 void TransferTerminated(HttpFetcher* fetcher) override {
1092 ADD_FAILURE();
1093 }
1094
1095 unique_ptr<HttpFetcher> fetcher_;
1096 int expected_response_code_;
1097 string data;
1098 };
1099
MultiTest(HttpFetcher * fetcher_in,FakeHardware * fake_hardware,const string & url,const vector<pair<off_t,off_t>> & ranges,const string & expected_prefix,size_t expected_size,HttpResponseCode expected_response_code)1100 void MultiTest(HttpFetcher* fetcher_in,
1101 FakeHardware* fake_hardware,
1102 const string& url,
1103 const vector<pair<off_t, off_t>>& ranges,
1104 const string& expected_prefix,
1105 size_t expected_size,
1106 HttpResponseCode expected_response_code) {
1107 MultiHttpFetcherTestDelegate delegate(expected_response_code);
1108 delegate.fetcher_.reset(fetcher_in);
1109
1110 MultiRangeHttpFetcher* multi_fetcher =
1111 static_cast<MultiRangeHttpFetcher*>(fetcher_in);
1112 ASSERT_TRUE(multi_fetcher);
1113 multi_fetcher->ClearRanges();
1114 for (vector<pair<off_t, off_t>>::const_iterator it = ranges.begin(),
1115 e = ranges.end(); it != e; ++it) {
1116 string tmp_str = base::StringPrintf("%jd+", it->first);
1117 if (it->second > 0) {
1118 base::StringAppendF(&tmp_str, "%jd", it->second);
1119 multi_fetcher->AddRange(it->first, it->second);
1120 } else {
1121 base::StringAppendF(&tmp_str, "?");
1122 multi_fetcher->AddRange(it->first);
1123 }
1124 LOG(INFO) << "added range: " << tmp_str;
1125 }
1126 fake_hardware->SetIsOfficialBuild(false);
1127 multi_fetcher->set_delegate(&delegate);
1128
1129 MessageLoop::current()->PostTask(
1130 FROM_HERE,
1131 base::Bind(StartTransfer, multi_fetcher, url));
1132 MessageLoop::current()->Run();
1133
1134 EXPECT_EQ(expected_size, delegate.data.size());
1135 EXPECT_EQ(expected_prefix,
1136 string(delegate.data.data(), expected_prefix.size()));
1137 }
1138 } // namespace
1139
TYPED_TEST(HttpFetcherTest,MultiHttpFetcherSimpleTest)1140 TYPED_TEST(HttpFetcherTest, MultiHttpFetcherSimpleTest) {
1141 if (!this->test_.IsMulti())
1142 return;
1143
1144 unique_ptr<HttpServer> server(this->test_.CreateServer());
1145 ASSERT_TRUE(server->started_);
1146
1147 vector<pair<off_t, off_t>> ranges;
1148 ranges.push_back(make_pair(0, 25));
1149 ranges.push_back(make_pair(99, 0));
1150 MultiTest(this->test_.NewLargeFetcher(),
1151 this->test_.fake_hardware(),
1152 this->test_.BigUrl(server->GetPort()),
1153 ranges,
1154 "abcdefghijabcdefghijabcdejabcdefghijabcdef",
1155 kBigLength - (99 - 25),
1156 kHttpResponsePartialContent);
1157 }
1158
TYPED_TEST(HttpFetcherTest,MultiHttpFetcherLengthLimitTest)1159 TYPED_TEST(HttpFetcherTest, MultiHttpFetcherLengthLimitTest) {
1160 if (!this->test_.IsMulti())
1161 return;
1162
1163 unique_ptr<HttpServer> server(this->test_.CreateServer());
1164 ASSERT_TRUE(server->started_);
1165
1166 vector<pair<off_t, off_t>> ranges;
1167 ranges.push_back(make_pair(0, 24));
1168 MultiTest(this->test_.NewLargeFetcher(),
1169 this->test_.fake_hardware(),
1170 this->test_.BigUrl(server->GetPort()),
1171 ranges,
1172 "abcdefghijabcdefghijabcd",
1173 24,
1174 kHttpResponsePartialContent);
1175 }
1176
TYPED_TEST(HttpFetcherTest,MultiHttpFetcherMultiEndTest)1177 TYPED_TEST(HttpFetcherTest, MultiHttpFetcherMultiEndTest) {
1178 if (!this->test_.IsMulti())
1179 return;
1180
1181 unique_ptr<HttpServer> server(this->test_.CreateServer());
1182 ASSERT_TRUE(server->started_);
1183
1184 vector<pair<off_t, off_t>> ranges;
1185 ranges.push_back(make_pair(kBigLength - 2, 0));
1186 ranges.push_back(make_pair(kBigLength - 3, 0));
1187 MultiTest(this->test_.NewLargeFetcher(),
1188 this->test_.fake_hardware(),
1189 this->test_.BigUrl(server->GetPort()),
1190 ranges,
1191 "ijhij",
1192 5,
1193 kHttpResponsePartialContent);
1194 }
1195
TYPED_TEST(HttpFetcherTest,MultiHttpFetcherInsufficientTest)1196 TYPED_TEST(HttpFetcherTest, MultiHttpFetcherInsufficientTest) {
1197 if (!this->test_.IsMulti())
1198 return;
1199
1200 unique_ptr<HttpServer> server(this->test_.CreateServer());
1201 ASSERT_TRUE(server->started_);
1202
1203 vector<pair<off_t, off_t>> ranges;
1204 ranges.push_back(make_pair(kBigLength - 2, 4));
1205 for (int i = 0; i < 2; ++i) {
1206 LOG(INFO) << "i = " << i;
1207 MultiTest(this->test_.NewLargeFetcher(),
1208 this->test_.fake_hardware(),
1209 this->test_.BigUrl(server->GetPort()),
1210 ranges,
1211 "ij",
1212 2,
1213 kHttpResponseUndefined);
1214 ranges.push_back(make_pair(0, 5));
1215 }
1216 }
1217
1218 // Issue #18143: when a fetch of a secondary chunk out of a chain, then it
1219 // should retry with other proxies listed before giving up.
1220 //
1221 // (1) successful recovery: The offset fetch will fail twice but succeed with
1222 // the third proxy.
TYPED_TEST(HttpFetcherTest,MultiHttpFetcherErrorIfOffsetRecoverableTest)1223 TYPED_TEST(HttpFetcherTest, MultiHttpFetcherErrorIfOffsetRecoverableTest) {
1224 if (!this->test_.IsMulti())
1225 return;
1226
1227 unique_ptr<HttpServer> server(this->test_.CreateServer());
1228 ASSERT_TRUE(server->started_);
1229
1230 vector<pair<off_t, off_t>> ranges;
1231 ranges.push_back(make_pair(0, 25));
1232 ranges.push_back(make_pair(99, 0));
1233 MultiTest(this->test_.NewLargeFetcher(3),
1234 this->test_.fake_hardware(),
1235 LocalServerUrlForPath(server->GetPort(),
1236 base::StringPrintf("/error-if-offset/%d/2",
1237 kBigLength)),
1238 ranges,
1239 "abcdefghijabcdefghijabcdejabcdefghijabcdef",
1240 kBigLength - (99 - 25),
1241 kHttpResponsePartialContent);
1242 }
1243
1244 // (2) unsuccessful recovery: The offset fetch will fail repeatedly. The
1245 // fetcher will signal a (failed) completed transfer to the delegate.
TYPED_TEST(HttpFetcherTest,MultiHttpFetcherErrorIfOffsetUnrecoverableTest)1246 TYPED_TEST(HttpFetcherTest, MultiHttpFetcherErrorIfOffsetUnrecoverableTest) {
1247 if (!this->test_.IsMulti())
1248 return;
1249
1250 unique_ptr<HttpServer> server(this->test_.CreateServer());
1251 ASSERT_TRUE(server->started_);
1252
1253 vector<pair<off_t, off_t>> ranges;
1254 ranges.push_back(make_pair(0, 25));
1255 ranges.push_back(make_pair(99, 0));
1256 MultiTest(this->test_.NewLargeFetcher(2),
1257 this->test_.fake_hardware(),
1258 LocalServerUrlForPath(server->GetPort(),
1259 base::StringPrintf("/error-if-offset/%d/3",
1260 kBigLength)),
1261 ranges,
1262 "abcdefghijabcdefghijabcde", // only received the first chunk
1263 25,
1264 kHttpResponseUndefined);
1265 }
1266
1267 namespace {
1268 // This HttpFetcherDelegate calls TerminateTransfer at a configurable point.
1269 class MultiHttpFetcherTerminateTestDelegate : public HttpFetcherDelegate {
1270 public:
MultiHttpFetcherTerminateTestDelegate(size_t terminate_trigger_bytes)1271 explicit MultiHttpFetcherTerminateTestDelegate(size_t terminate_trigger_bytes)
1272 : terminate_trigger_bytes_(terminate_trigger_bytes) {}
1273
ReceivedBytes(HttpFetcher * fetcher,const void * bytes,size_t length)1274 void ReceivedBytes(HttpFetcher* fetcher,
1275 const void* bytes,
1276 size_t length) override {
1277 LOG(INFO) << "ReceivedBytes, " << length << " bytes.";
1278 EXPECT_EQ(fetcher, fetcher_.get());
1279 if (bytes_downloaded_ < terminate_trigger_bytes_ &&
1280 bytes_downloaded_ + length >= terminate_trigger_bytes_) {
1281 MessageLoop::current()->PostTask(
1282 FROM_HERE,
1283 base::Bind(&HttpFetcher::TerminateTransfer,
1284 base::Unretained(fetcher_.get())));
1285 }
1286 bytes_downloaded_ += length;
1287 }
1288
TransferComplete(HttpFetcher * fetcher,bool successful)1289 void TransferComplete(HttpFetcher* fetcher, bool successful) override {
1290 ADD_FAILURE() << "TransferComplete called but expected a failure";
1291 // Destroy the fetcher (because we're allowed to).
1292 fetcher_.reset(nullptr);
1293 MessageLoop::current()->BreakLoop();
1294 }
1295
TransferTerminated(HttpFetcher * fetcher)1296 void TransferTerminated(HttpFetcher* fetcher) override {
1297 // Destroy the fetcher (because we're allowed to).
1298 fetcher_.reset(nullptr);
1299 MessageLoop::current()->BreakLoop();
1300 }
1301
1302 unique_ptr<HttpFetcher> fetcher_;
1303 size_t bytes_downloaded_{0};
1304 size_t terminate_trigger_bytes_;
1305 };
1306 } // namespace
1307
TYPED_TEST(HttpFetcherTest,MultiHttpFetcherTerminateBetweenRangesTest)1308 TYPED_TEST(HttpFetcherTest, MultiHttpFetcherTerminateBetweenRangesTest) {
1309 if (!this->test_.IsMulti())
1310 return;
1311 const size_t kRangeTrigger = 1000;
1312 MultiHttpFetcherTerminateTestDelegate delegate(kRangeTrigger);
1313
1314 unique_ptr<HttpServer> server(this->test_.CreateServer());
1315 ASSERT_TRUE(server->started_);
1316
1317 MultiRangeHttpFetcher* multi_fetcher =
1318 static_cast<MultiRangeHttpFetcher*>(this->test_.NewLargeFetcher());
1319 ASSERT_TRUE(multi_fetcher);
1320 // Transfer ownership of the fetcher to the delegate.
1321 delegate.fetcher_.reset(multi_fetcher);
1322 multi_fetcher->set_delegate(&delegate);
1323
1324 multi_fetcher->ClearRanges();
1325 multi_fetcher->AddRange(45, kRangeTrigger);
1326 multi_fetcher->AddRange(2000, 100);
1327
1328 this->test_.fake_hardware()->SetIsOfficialBuild(false);
1329
1330 StartTransfer(multi_fetcher, this->test_.BigUrl(server->GetPort()));
1331 MessageLoop::current()->Run();
1332
1333 // Check that the delegate made it to the trigger point.
1334 EXPECT_EQ(kRangeTrigger, delegate.bytes_downloaded_);
1335 }
1336
1337 namespace {
1338 class BlockedTransferTestDelegate : public HttpFetcherDelegate {
1339 public:
ReceivedBytes(HttpFetcher * fetcher,const void * bytes,size_t length)1340 void ReceivedBytes(HttpFetcher* fetcher,
1341 const void* bytes, size_t length) override {
1342 ADD_FAILURE();
1343 }
TransferComplete(HttpFetcher * fetcher,bool successful)1344 void TransferComplete(HttpFetcher* fetcher, bool successful) override {
1345 EXPECT_FALSE(successful);
1346 MessageLoop::current()->BreakLoop();
1347 }
TransferTerminated(HttpFetcher * fetcher)1348 void TransferTerminated(HttpFetcher* fetcher) override {
1349 ADD_FAILURE();
1350 }
1351 };
1352
BlockedTransferTestHelper(AnyHttpFetcherTest * fetcher_test,bool is_official_build)1353 void BlockedTransferTestHelper(AnyHttpFetcherTest* fetcher_test,
1354 bool is_official_build) {
1355 if (fetcher_test->IsMock() || fetcher_test->IsMulti())
1356 return;
1357
1358 unique_ptr<HttpServer> server(fetcher_test->CreateServer());
1359 ASSERT_TRUE(server->started_);
1360
1361 BlockedTransferTestDelegate delegate;
1362 unique_ptr<HttpFetcher> fetcher(fetcher_test->NewLargeFetcher());
1363 LOG(INFO) << "is_official_build: " << is_official_build;
1364 // NewLargeFetcher creates the HttpFetcher* with a FakeSystemState.
1365 fetcher_test->fake_hardware()->SetIsOfficialBuild(is_official_build);
1366 fetcher->set_delegate(&delegate);
1367
1368 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
1369 StartTransfer,
1370 fetcher.get(),
1371 LocalServerUrlForPath(server->GetPort(),
1372 fetcher_test->SmallUrl(server->GetPort()))));
1373 MessageLoop::current()->Run();
1374 }
1375 } // namespace
1376
TYPED_TEST(HttpFetcherTest,BlockedTransferTest)1377 TYPED_TEST(HttpFetcherTest, BlockedTransferTest) {
1378 BlockedTransferTestHelper(&this->test_, false);
1379 }
1380
TYPED_TEST(HttpFetcherTest,BlockedTransferOfficialBuildTest)1381 TYPED_TEST(HttpFetcherTest, BlockedTransferOfficialBuildTest) {
1382 BlockedTransferTestHelper(&this->test_, true);
1383 }
1384
1385 } // namespace chromeos_update_engine
1386