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