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