1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/public/test/test_download_http_response.h"
6 
7 #include <inttypes.h>
8 
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "base/lazy_instance.h"
12 #include "base/logging.h"
13 #include "base/numerics/ranges.h"
14 #include "base/run_loop.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/synchronization/lock.h"
19 #include "base/threading/thread_task_runner_handle.h"
20 #include "content/public/browser/browser_task_traits.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "net/http/http_request_headers.h"
23 #include "net/http/http_util.h"
24 
25 namespace content {
26 
27 namespace {
28 
29 // Lock object for protecting |g_parameters_map|.
30 base::LazyInstance<base::Lock>::Leaky g_lock = LAZY_INSTANCE_INITIALIZER;
31 
32 using ParametersMap = std::map<GURL, TestDownloadHttpResponse::Parameters>;
33 // Maps url to Parameters so that requests for the same URL will get the same
34 // parameters.
35 base::LazyInstance<ParametersMap>::Leaky g_parameters_map =
36     LAZY_INSTANCE_INITIALIZER;
37 
38 const char* kTestDownloadPath = "/download/";
39 
40 // The size of buffer to send the entity body. The header will always be sent in
41 // one buffer.
42 const int64_t kBufferSize = 64 * 1024;
43 
44 // Xorshift* PRNG from https://en.wikipedia.org/wiki/Xorshift
XorShift64StarWithIndex(uint64_t seed,uint64_t index)45 uint64_t XorShift64StarWithIndex(uint64_t seed, uint64_t index) {
46   const uint64_t kMultiplier = UINT64_C(2685821657736338717);
47   uint64_t x = seed * kMultiplier + index;
48   x ^= x >> 12;
49   x ^= x << 25;
50   x ^= x >> 27;
51   return x * kMultiplier;
52 }
53 
54 // Called to resume the response.
OnResume(scoped_refptr<base::SingleThreadTaskRunner> task_runner,base::OnceClosure resume_callback)55 void OnResume(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
56               base::OnceClosure resume_callback) {
57   task_runner->PostTask(FROM_HERE, std::move(resume_callback));
58 }
59 
OnResponseSentOnServerIOThread(TestDownloadHttpResponse::OnResponseSentCallback callback,std::unique_ptr<TestDownloadHttpResponse::CompletedRequest> request)60 void OnResponseSentOnServerIOThread(
61     TestDownloadHttpResponse::OnResponseSentCallback callback,
62     std::unique_ptr<TestDownloadHttpResponse::CompletedRequest> request) {
63   GetUIThreadTaskRunner({})->PostTask(
64       FROM_HERE, base::BindOnce(std::move(callback), std::move(request)));
65 }
66 
GetURLFromRequest(const net::test_server::HttpRequest & request)67 GURL GetURLFromRequest(const net::test_server::HttpRequest& request) {
68   return GURL(base::StringPrintf(
69       "http://%s%s", request.headers.at(net::HttpRequestHeaders::kHost).c_str(),
70       request.relative_url.c_str()));
71 }
72 // The shim response object used by embedded_test_server. After this object is
73 // deleted, we may continue to send data with cached SendBytesCallback to
74 // support pause/resume behaviors.
75 class HttpResponse : public net::test_server::HttpResponse {
76  public:
HttpResponse(base::WeakPtr<TestDownloadHttpResponse> owner)77   explicit HttpResponse(base::WeakPtr<TestDownloadHttpResponse> owner)
78       : owner_(owner) {}
79   ~HttpResponse() override = default;
80 
81  private:
82   // net::test_server::HttpResponse implementations.
SendResponse(const net::test_server::SendBytesCallback & send,net::test_server::SendCompleteCallback done)83   void SendResponse(const net::test_server::SendBytesCallback& send,
84                     net::test_server::SendCompleteCallback done) override {
85     if (owner_)
86       owner_->SendResponse(send, std::move(done));
87   }
88 
89   base::WeakPtr<TestDownloadHttpResponse> owner_;
90   DISALLOW_COPY_AND_ASSIGN(HttpResponse);
91 };
92 
93 }  // namespace
94 
95 const char TestDownloadHttpResponse::kTestDownloadHostName[] =
96     "*.default.example.com";
97 
98 // static
GetNextURLForDownload()99 GURL TestDownloadHttpResponse::GetNextURLForDownload() {
100   static int index = 0;
101   std::string url_string = base::StringPrintf("http://%d.default.example.com%s",
102                                               ++index, kTestDownloadPath);
103   return GURL(url_string);
104 }
105 
HttpResponseData(int64_t min_offset,int64_t max_offset,const std::string & response,bool is_transient,bool delay_response)106 TestDownloadHttpResponse::HttpResponseData::HttpResponseData(
107     int64_t min_offset,
108     int64_t max_offset,
109     const std::string& response,
110     bool is_transient,
111     bool delay_response)
112     : min_offset(min_offset),
113       max_offset(max_offset),
114       response(response),
115       is_transient(is_transient),
116       delay_response(delay_response) {}
117 
118 // static
119 TestDownloadHttpResponse::Parameters
WithSingleInterruption(const TestDownloadHttpResponse::InjectErrorCallback & inject_error_cb)120 TestDownloadHttpResponse::Parameters::WithSingleInterruption(
121     const TestDownloadHttpResponse::InjectErrorCallback& inject_error_cb) {
122   Parameters parameters;
123   parameters.injected_errors.push(parameters.size / 2);
124   parameters.inject_error_cb = inject_error_cb;
125   return parameters;
126 }
127 
Parameters()128 TestDownloadHttpResponse::Parameters::Parameters()
129     : etag("abcd"),
130       last_modified("Tue, 15 Nov 1994 12:45:26 GMT"),
131       content_type("application/octet-stream"),
132       size(102400),
133       pattern_generator_seed(1),
134       support_byte_ranges(true),
135       support_partial_response(true),
136       connection_type(
137           net::HttpResponseInfo::ConnectionInfo::CONNECTION_INFO_UNKNOWN) {}
138 
139 TestDownloadHttpResponse::Parameters::Parameters(const Parameters& that) =
140     default;
141 TestDownloadHttpResponse::Parameters& TestDownloadHttpResponse::Parameters::
142 operator=(const Parameters& that) = default;
143 
144 TestDownloadHttpResponse::Parameters::~Parameters() = default;
145 
ClearInjectedErrors()146 void TestDownloadHttpResponse::Parameters::ClearInjectedErrors() {
147   base::queue<int64_t> empty_error_list;
148   injected_errors.swap(empty_error_list);
149   inject_error_cb.Reset();
150 }
151 
SetResponseForRangeRequest(int64_t min_offset,int64_t max_offset,const std::string & response,bool is_transient,bool delay_response)152 void TestDownloadHttpResponse::Parameters::SetResponseForRangeRequest(
153     int64_t min_offset,
154     int64_t max_offset,
155     const std::string& response,
156     bool is_transient,
157     bool delay_response) {
158   range_request_responses.emplace_back(HttpResponseData(
159       min_offset, max_offset, response, is_transient, delay_response));
160 }
161 
CompletedRequest(const net::test_server::HttpRequest & request)162 TestDownloadHttpResponse::CompletedRequest::CompletedRequest(
163     const net::test_server::HttpRequest& request)
164     : http_request(request) {}
165 
166 TestDownloadHttpResponse::CompletedRequest::~CompletedRequest() = default;
167 
168 // static
StartServing(const TestDownloadHttpResponse::Parameters & parameters,const GURL & url)169 void TestDownloadHttpResponse::StartServing(
170     const TestDownloadHttpResponse::Parameters& parameters,
171     const GURL& url) {
172   base::AutoLock lock(*g_lock.Pointer());
173   auto iter = g_parameters_map.Get().find(url);
174   if (iter != g_parameters_map.Get().end())
175     g_parameters_map.Get().erase(iter);
176   g_parameters_map.Get().emplace(url, parameters);
177 }
178 
179 // static
StartServingStaticResponse(const std::string & response,const GURL & url)180 void TestDownloadHttpResponse::StartServingStaticResponse(
181     const std::string& response,
182     const GURL& url) {
183   TestDownloadHttpResponse::Parameters parameters;
184   parameters.static_response = response;
185   StartServing(std::move(parameters), url);
186 }
187 
188 std::unique_ptr<net::test_server::HttpResponse>
CreateResponseForTestServer()189 TestDownloadHttpResponse::CreateResponseForTestServer() {
190   return std::make_unique<HttpResponse>(weak_ptr_factory_.GetWeakPtr());
191 }
192 
193 // static
GetPatternBytes(int seed,int64_t starting_offset,int length)194 std::string TestDownloadHttpResponse::GetPatternBytes(int seed,
195                                                       int64_t starting_offset,
196                                                       int length) {
197   int64_t seed_offset = starting_offset / sizeof(int64_t);
198   int64_t first_byte_position = starting_offset % sizeof(int64_t);
199   std::string output;
200   while (length > 0) {
201     uint64_t data = XorShift64StarWithIndex(seed, seed_offset);
202     int length_to_copy =
203         std::min(length, static_cast<int>(sizeof(data) - first_byte_position));
204     char* start_pos = reinterpret_cast<char*>(&data) + first_byte_position;
205     std::string string_to_append(start_pos, start_pos + length_to_copy);
206     output.append(string_to_append);
207     length -= length_to_copy;
208     ++seed_offset;
209     first_byte_position = 0;
210   }
211   return output;
212 }
213 
TestDownloadHttpResponse(const net::test_server::HttpRequest & request,const Parameters & parameters,OnResponseSentCallback on_response_sent_callback)214 TestDownloadHttpResponse::TestDownloadHttpResponse(
215     const net::test_server::HttpRequest& request,
216     const Parameters& parameters,
217     OnResponseSentCallback on_response_sent_callback)
218     : range_(net::HttpByteRange::Bounded(0, parameters.size - 1)),
219       response_sent_offset_(0u),
220       parameters_(parameters),
221       request_(request),
222       transferred_bytes_(0u),
223       on_response_sent_callback_(std::move(on_response_sent_callback)) {
224   DCHECK_GT(parameters.size, 0) << "File size need to be greater than 0.";
225   ParseRequestHeader();
226 }
227 
228 TestDownloadHttpResponse::~TestDownloadHttpResponse() = default;
229 
SendResponse(const net::test_server::SendBytesCallback & send,net::test_server::SendCompleteCallback done)230 void TestDownloadHttpResponse::SendResponse(
231     const net::test_server::SendBytesCallback& send,
232     net::test_server::SendCompleteCallback done) {
233   bytes_sender_ = send;
234   done_callback_ = std::move(done);
235 
236   // Throw error before sending headers.
237   if (ShouldAbortImmediately()) {
238     bytes_sender_.Run(std::string(), GenerateResultClosure());
239     return;
240   }
241 
242   // Call inject error callback to UI thread.
243   if (!parameters_.injected_errors.empty() &&
244       parameters_.injected_errors.front() <= range_.last_byte_position() &&
245       parameters_.injected_errors.front() >= range_.first_byte_position() &&
246       !parameters_.inject_error_cb.is_null()) {
247     GetUIThreadTaskRunner({})->PostTask(
248         FROM_HERE, base::BindOnce(parameters_.inject_error_cb,
249                                   range_.first_byte_position(),
250                                   parameters_.injected_errors.front() -
251                                       range_.first_byte_position()));
252   }
253 
254   // Pause before sending headers.
255   if (ShouldPauseImmediately()) {
256     PauseResponsesAndWaitForResumption();
257     return;
258   }
259 
260   // Start to send the response.
261   SendResponseHeaders();
262 }
263 
ParseRequestHeader()264 void TestDownloadHttpResponse::ParseRequestHeader() {
265   // Parse HTTP range header from the request.
266   std::vector<net::HttpByteRange> ranges;
267   if (request_.headers.find(net::HttpRequestHeaders::kRange) ==
268       request_.headers.end()) {
269     return;
270   }
271 
272   if (!net::HttpUtil::ParseRangeHeader(
273           request_.headers.at(net::HttpRequestHeaders::kRange), &ranges)) {
274     return;
275   }
276 
277   if (ranges.size() > 1)
278     LOG(WARNING) << "Multiple range intervals are not supported.";
279 
280   // Adjust the response range according to request range. The first byte offset
281   // of the request may be larger than entity body size.
282   request_range_ = ranges[0];
283   if (parameters_.support_partial_response)
284     range_.set_first_byte_position(request_range_.first_byte_position());
285   range_.ComputeBounds(parameters_.size);
286 
287   response_sent_offset_ = range_.first_byte_position();
288 }
289 
SendResponseHeaders()290 void TestDownloadHttpResponse::SendResponseHeaders() {
291   // Send static response in |parameters_| and close connection.
292   if (!parameters_.static_response.empty()) {
293     bytes_sender_.Run(parameters_.static_response, GenerateResultClosure());
294     return;
295   }
296 
297   // Send static |range_request_responses| in |parameters_| and close
298   // connection.
299   std::string response;
300   bool delay_response = false;
301   if (GetResponseForRangeRequest(&response, &delay_response)) {
302     if (delay_response) {
303       delayed_response_callback_ =
304           base::BindOnce(bytes_sender_, response, GenerateResultClosure()),
305       bytes_sender_.Run(GetDefaultResponseHeaders(), base::DoNothing());
306     } else {
307       bytes_sender_.Run(response, GenerateResultClosure());
308     }
309     return;
310   }
311 
312   // Send the headers and start to send the body.
313   bytes_sender_.Run(GetDefaultResponseHeaders(), SendNextBodyChunkClosure());
314 }
315 
GetDefaultResponseHeaders()316 std::string TestDownloadHttpResponse::GetDefaultResponseHeaders() {
317   std::string headers;
318   // Send partial response.
319   if (parameters_.support_partial_response && parameters_.support_byte_ranges) {
320     bool has_if_range =
321         request_.headers.find(net::HttpRequestHeaders::kIfRange) !=
322         request_.headers.end();
323     if (((has_if_range &&
324           request_.headers.at(net::HttpRequestHeaders::kIfRange) ==
325               parameters_.etag) ||
326          (!has_if_range &&
327           request_.headers.find(net::HttpRequestHeaders::kRange) !=
328               request_.headers.end())) &&
329         HandleRangeAssumingValidatorMatch(headers)) {
330       return headers;
331     }
332   }
333 
334   // Send precondition failed for "If-Match" request header.
335   if (parameters_.support_partial_response && parameters_.support_byte_ranges &&
336       request_.headers.find(net::HttpRequestHeaders::kIfMatch) !=
337           request_.headers.end()) {
338     if (request_.headers.at(net::HttpRequestHeaders::kIfMatch) !=
339             parameters_.etag ||
340         !HandleRangeAssumingValidatorMatch(headers)) {
341       // Unlike If-Range, If-Match returns an error if the validators don't
342       // match.
343       headers =
344           "HTTP/1.1 412 Precondition failed\r\n"
345           "Content-Length: 0\r\n"
346           "\r\n";
347     }
348     return headers;
349   }
350 
351   // Send the whole file in entity body if partial response is not supported.
352   range_.set_first_byte_position(0u);
353   range_.set_last_byte_position(parameters_.size - 1);
354   response_sent_offset_ = 0;
355 
356   headers.append("HTTP/1.1 200 OK\r\n");
357   if (parameters_.support_byte_ranges)
358     headers.append("Accept-Ranges: bytes\r\n");
359   headers.append(
360       base::StringPrintf("Content-Length: %" PRId64 "\r\n", parameters_.size));
361   headers.append(GetCommonEntityHeaders());
362   return headers;
363 }
364 
GetResponseForRangeRequest(std::string * output,bool * delay_response)365 bool TestDownloadHttpResponse::GetResponseForRangeRequest(
366     std::string* output,
367     bool* delay_response) {
368   if (!range_.IsValid())
369     return false;
370 
371   // Find the response for range request that starts from |requset_offset|.
372   // Use default logic to generate the response if nothing can be found.
373   int64_t requset_offset = range_.first_byte_position();
374   for (auto it = parameters_.range_request_responses.begin();
375        it != parameters_.range_request_responses.end(); ++it) {
376     if (it->min_offset == -1 && it->max_offset == -1)
377       continue;
378 
379     if (requset_offset < it->min_offset)
380       continue;
381 
382     if (it->max_offset == -1 || requset_offset <= it->max_offset) {
383       *output = it->response;
384       *delay_response = it->delay_response;
385       // Update the global parameter for transient response, so the
386       // next response will be different.
387       if (it->is_transient) {
388         parameters_.range_request_responses.erase(it);
389         base::AutoLock lock(*g_lock.Pointer());
390         GURL url = GetURLFromRequest(request_);
391         auto iter = g_parameters_map.Get().find(url);
392         if (iter != g_parameters_map.Get().end())
393           g_parameters_map.Get().erase(iter);
394         g_parameters_map.Get().emplace(url, std::move(parameters_));
395       }
396 
397       return true;
398     }
399   }
400 
401   return false;
402 }
403 
HandleRangeAssumingValidatorMatch(std::string & response)404 bool TestDownloadHttpResponse::HandleRangeAssumingValidatorMatch(
405     std::string& response) {
406   // The request may have specified a range that's out of bounds.
407   if (request_range_.first_byte_position() >= parameters_.size) {
408     response = base::StringPrintf(
409         "HTTP/1.1 416 Range not satisfiable\r\n"
410         "Content-Range: bytes */%" PRId64
411         "\r\n"
412         "Content-Length: 0\r\n",
413         parameters_.size);
414     return true;
415   }
416 
417   response.append("HTTP/1.1 206 Partial content\r\n");
418   response.append(base::StringPrintf(
419       "Content-Range: bytes %" PRId64 "-%" PRId64 "/%" PRId64 "\r\n",
420       range_.first_byte_position(), range_.last_byte_position(),
421       parameters_.size));
422   response.append(base::StringPrintf(
423       "Content-Length: %" PRId64 "\r\n",
424       (range_.last_byte_position() - range_.first_byte_position()) + 1));
425   response.append(GetCommonEntityHeaders());
426   return true;
427 }
428 
GetCommonEntityHeaders()429 std::string TestDownloadHttpResponse::GetCommonEntityHeaders() {
430   std::string headers;
431   if (!parameters_.content_type.empty()) {
432     headers.append(base::StringPrintf("Content-Type: %s\r\n",
433                                       parameters_.content_type.c_str()));
434   }
435 
436   if (!parameters_.etag.empty()) {
437     headers.append(
438         base::StringPrintf("ETag: %s\r\n", parameters_.etag.c_str()));
439   }
440 
441   if (!parameters_.last_modified.empty()) {
442     headers.append(base::StringPrintf("Last-Modified: %s\r\n",
443                                       parameters_.last_modified.c_str()));
444   }
445   headers.append("\r\n");
446   return headers;
447 }
448 
GetResponseChunk(const net::HttpByteRange & buffer_range)449 std::string TestDownloadHttpResponse::GetResponseChunk(
450     const net::HttpByteRange& buffer_range) {
451   DCHECK(buffer_range.IsValid());
452   DCHECK(buffer_range.HasLastBytePosition());
453 
454   int64_t length = buffer_range.last_byte_position() -
455                    buffer_range.first_byte_position() + 1;
456   return GetPatternBytes(parameters_.pattern_generator_seed,
457                          buffer_range.first_byte_position(), length);
458 }
459 
ShouldAbortImmediately() const460 bool TestDownloadHttpResponse::ShouldAbortImmediately() const {
461   return !parameters_.injected_errors.empty() &&
462          parameters_.injected_errors.front() == -1 &&
463          !parameters_.inject_error_cb.is_null();
464 }
465 
ShouldPauseImmediately() const466 bool TestDownloadHttpResponse::ShouldPauseImmediately() const {
467   return parameters_.pause_offset.has_value() &&
468          parameters_.pause_offset.value() == -1 && parameters_.on_pause_handler;
469 }
470 
HandlePause(const net::HttpByteRange & buffer_range)471 bool TestDownloadHttpResponse::HandlePause(
472     const net::HttpByteRange& buffer_range) {
473   if (!parameters_.on_pause_handler || !parameters_.pause_offset.has_value())
474     return false;
475 
476   int64_t pause_offset = parameters_.pause_offset.value();
477   if (pause_offset < request_range_.first_byte_position())
478     return false;
479 
480   if (pause_offset > buffer_range.last_byte_position() ||
481       pause_offset < buffer_range.first_byte_position()) {
482     return false;
483   }
484 
485   // Send the bytes before the pause offset.
486   net::HttpByteRange range = buffer_range;
487   if (range.last_byte_position() > pause_offset) {
488     range.set_last_byte_position(pause_offset - 1);
489     response_sent_offset_ = pause_offset;
490     SendBodyChunkInternal(range, base::DoNothing());
491   }
492 
493   // Pause now. Don't close the connection to wait for resumption.
494   PauseResponsesAndWaitForResumption();
495   return true;
496 }
497 
HandleInjectedError(const net::HttpByteRange & buffer_range)498 bool TestDownloadHttpResponse::HandleInjectedError(
499     const net::HttpByteRange& buffer_range) {
500   if (parameters_.injected_errors.empty())
501     return false;
502 
503   // Clear all errors before first byte of |range|.
504   while (!parameters_.injected_errors.empty() &&
505          parameters_.injected_errors.front() <
506              buffer_range.first_byte_position()) {
507     parameters_.injected_errors.pop();
508   }
509 
510   int64_t error_offset = parameters_.injected_errors.front();
511   if (error_offset > buffer_range.last_byte_position())
512     return false;
513 
514   // Send the bytes before the error offset, then close the connection.
515   net::HttpByteRange range = buffer_range;
516   if (error_offset > buffer_range.first_byte_position()) {
517     range.set_last_byte_position(error_offset - 1);
518     DCHECK(range.IsValid());
519     response_sent_offset_ = error_offset;
520     SendBodyChunkInternal(range, GenerateResultClosure());
521   }
522 
523   return true;
524 }
525 
ShouldPause(const net::HttpByteRange & buffer_range) const526 bool TestDownloadHttpResponse::ShouldPause(
527     const net::HttpByteRange& buffer_range) const {
528   if (!parameters_.on_pause_handler)
529     return false;
530 
531   return parameters_.pause_offset >= buffer_range.first_byte_position() &&
532          parameters_.pause_offset <= buffer_range.last_byte_position();
533 }
534 
PauseResponsesAndWaitForResumption()535 void TestDownloadHttpResponse::PauseResponsesAndWaitForResumption() {
536   // Clean up the on_pause_handler so response will not be paused again.
537   base::OnceCallback<OnPauseHandler::RunType> pause_callback =
538       std::move(parameters_.on_pause_handler);
539 
540   base::OnceClosure continue_closure = SendNextBodyChunkClosure();
541 
542   // We may pause before sending the headers.
543   if (parameters_.pause_offset == -1) {
544     continue_closure = base::BindOnce(
545         &TestDownloadHttpResponse::SendResponseHeaders, base::Unretained(this));
546   }
547 
548   // Continue to send data after resumption.
549   // TODO(xingliu): Unwind thread hopping callbacks here.
550   GetUIThreadTaskRunner({})->PostTask(
551       FROM_HERE,
552       base::BindOnce(
553           std::move(pause_callback),
554           base::BindOnce(OnResume, base::ThreadTaskRunnerHandle::Get(),
555                          std::move(continue_closure))));
556 }
557 
SendResponseBodyChunk()558 void TestDownloadHttpResponse::SendResponseBodyChunk() {
559   // Close the connection when reaching the end.
560   if (response_sent_offset_ > range_.last_byte_position()) {
561     GenerateResult();
562     return;
563   }
564 
565   int64_t upper_bound = base::ClampToRange(response_sent_offset_ + kBufferSize,
566                                            range_.first_byte_position(),
567                                            range_.last_byte_position());
568   auto buffer_range =
569       net::HttpByteRange::Bounded(response_sent_offset_, upper_bound);
570 
571   // Handle pause if needed.
572   if (HandlePause(buffer_range))
573     return;
574 
575   // Handle injected error if needed.
576   if (HandleInjectedError(buffer_range))
577     return;
578 
579   // Send the data buffer by buffer without throwing errors.
580   response_sent_offset_ = buffer_range.last_byte_position() + 1;
581   SendBodyChunkInternal(buffer_range, SendNextBodyChunkClosure());
582   return;
583 }
584 
SendBodyChunkInternal(const net::HttpByteRange & buffer_range,base::OnceClosure next)585 void TestDownloadHttpResponse::SendBodyChunkInternal(
586     const net::HttpByteRange& buffer_range,
587     base::OnceClosure next) {
588   std::string response_chunk = GetResponseChunk(buffer_range);
589   transferred_bytes_ += static_cast<int64_t>(response_chunk.size());
590   bytes_sender_.Run(response_chunk, std::move(next));
591 }
592 
593 net::test_server::SendCompleteCallback
SendNextBodyChunkClosure()594 TestDownloadHttpResponse::SendNextBodyChunkClosure() {
595   return base::BindOnce(&TestDownloadHttpResponse::SendResponseBodyChunk,
596                         base::Unretained(this));
597 }
598 
SendDelayedResponse()599 void TestDownloadHttpResponse::SendDelayedResponse() {
600   if (delayed_response_callback_)
601     std::move(delayed_response_callback_).Run();
602 }
603 
GenerateResult()604 void TestDownloadHttpResponse::GenerateResult() {
605   auto completed_request = std::make_unique<CompletedRequest>(request_);
606   // Transferred bytes in [range_.first_byte_position(), response_sent_offset_).
607   completed_request->transferred_byte_count = transferred_bytes_;
608   OnResponseSentOnServerIOThread(std::move(on_response_sent_callback_),
609                                  std::move(completed_request));
610 
611   // Close the HTTP connection.
612   std::move(done_callback_).Run();
613 }
614 
615 net::test_server::SendCompleteCallback
GenerateResultClosure()616 TestDownloadHttpResponse::GenerateResultClosure() {
617   return base::BindOnce(&TestDownloadHttpResponse::GenerateResult,
618                         base::Unretained(this));
619 }
620 
621 std::unique_ptr<net::test_server::HttpResponse>
HandleTestDownloadRequest(TestDownloadHttpResponse::OnResponseSentCallback callback,const net::test_server::HttpRequest & request)622 TestDownloadResponseHandler::HandleTestDownloadRequest(
623     TestDownloadHttpResponse::OnResponseSentCallback callback,
624     const net::test_server::HttpRequest& request) {
625   server_task_runner_ = base::ThreadTaskRunnerHandle::Get();
626 
627   if (request.headers.find(net::HttpRequestHeaders::kHost) ==
628       request.headers.end()) {
629     return nullptr;
630   }
631 
632   base::AutoLock lock(*g_lock.Pointer());
633   GURL url = GetURLFromRequest(request);
634   auto iter = g_parameters_map.Get().find(url);
635   if (iter != g_parameters_map.Get().end()) {
636     auto test_response = std::make_unique<TestDownloadHttpResponse>(
637         request, std::move(iter->second), std::move(callback));
638     auto response = test_response->CreateResponseForTestServer();
639     responses_.emplace_back(std::move(test_response));
640     return response;
641   }
642   return nullptr;
643 }
644 
645 TestDownloadResponseHandler::TestDownloadResponseHandler() = default;
646 
~TestDownloadResponseHandler()647 TestDownloadResponseHandler::~TestDownloadResponseHandler() {
648   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
649   for (auto& response : responses_)
650     server_task_runner_->DeleteSoon(FROM_HERE, response.release());
651 }
652 
RegisterToTestServer(net::test_server::EmbeddedTestServer * server)653 void TestDownloadResponseHandler::RegisterToTestServer(
654     net::test_server::EmbeddedTestServer* server) {
655   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
656   DCHECK(!server->Started())
657       << "Register request handler before starting the server";
658   server->RegisterRequestHandler(base::BindRepeating(
659       &content::TestDownloadResponseHandler::HandleTestDownloadRequest,
660       base::Unretained(this),
661       base::BindRepeating(
662           &content::TestDownloadResponseHandler::OnRequestCompleted,
663           base::Unretained(this))));
664 }
665 
OnRequestCompleted(std::unique_ptr<TestDownloadHttpResponse::CompletedRequest> request)666 void TestDownloadResponseHandler::OnRequestCompleted(
667     std::unique_ptr<TestDownloadHttpResponse::CompletedRequest> request) {
668   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
669   completed_requests_.push_back(std::move(request));
670 
671   if (run_loop_ && run_loop_->running() &&
672       completed_requests().size() >= request_count_) {
673     run_loop_->Quit();
674   }
675 }
676 
WaitUntilCompletion(size_t request_count)677 void TestDownloadResponseHandler::WaitUntilCompletion(size_t request_count) {
678   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
679   request_count_ = request_count;
680 
681   if ((run_loop_ && run_loop_->running()) ||
682       completed_requests().size() >= request_count_) {
683     return;
684   }
685 
686   run_loop_ = std::make_unique<base::RunLoop>();
687   run_loop_->Run();
688 }
689 
DispatchDelayedResponses()690 void TestDownloadResponseHandler::DispatchDelayedResponses() {
691   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
692   for (auto& response : responses_) {
693     server_task_runner_->PostTask(
694         FROM_HERE,
695         base::BindOnce(&TestDownloadHttpResponse::SendDelayedResponse,
696                        base::Unretained(response.get())));
697   }
698 }
699 
700 }  // namespace content
701