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