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