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