xref: /aosp_15_r20/system/update_engine/common/http_fetcher_unittest.cc (revision 5a9231315b4521097b8dc3750bc806fcafe0c72f)
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