Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(619)

Side by Side Diff: content/public/test/test_download_request_handler.cc

Issue 1203983004: Stop using SpawnedTestServer in DownloadContentTest.* (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address comments Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 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_request_handler.h"
6
7 #include <inttypes.h>
8
9 #include "base/logging.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/run_loop.h"
12 #include "base/strings/stringprintf.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "net/base/io_buffer.h"
15 #include "net/http/http_request_headers.h"
16 #include "net/http/http_response_headers.h"
17 #include "net/url_request/url_request_filter.h"
18 #include "net/url_request/url_request_interceptor.h"
19
20 namespace content {
21
22 namespace {
23
24 using Parameters = TestDownloadRequestHandler::Parameters;
25 using InjectedError = TestDownloadRequestHandler::InjectedError;
26
27 // Intercepts URLRequests on behalf of TestDownloadRequestHandler. Necessarily
28 // lives on the IO thread since that's where net::URLRequestFilter invokes the
29 // URLRequestInterceptor.
30 class TestDownloadRequestInterceptor : public net::URLRequestInterceptor {
31 public:
32 // Invoked on the IO thread to register a URLRequestInterceptor for |url|.
33 // Returns an IO-thread bound weak pointer for interacting with the
34 // interceptor.
35 static base::WeakPtr<TestDownloadRequestInterceptor> Register(
36 const GURL& url);
37
38 using JobFactory = base::Callback<net::URLRequestJob*(
39 net::URLRequest*,
40 net::NetworkDelegate*,
41 base::WeakPtr<TestDownloadRequestInterceptor>)>;
42
43 ~TestDownloadRequestInterceptor() override;
44
45 // Unregisters the URLRequestInterceptor. In reality it unregisters whatever
46 // was registered to intercept |url_|. Since |this| is owned by
47 // net::URLRequestFilter, unregistering the interceptor deletes |this| as a
48 // side-effect.
49 void Unregister();
50
51 // Change the URLRequestJob factory. Can be called multiple times.
52 void SetJobFactory(const JobFactory& factory);
53
54 // Sets |requests| to the vector of completed requests and clears the internal
55 // list. The returned requests are stored in the order in which they were
56 // reported as being complete (not necessarily the order in which they were
57 // received).
58 void GetAndResetCompletedRequests(
59 TestDownloadRequestHandler::CompletedRequests* requests);
60
61 // Can be called by a URLRequestJob to notify this interceptor of a completed
62 // request.
63 void AddCompletedRequest(
64 const TestDownloadRequestHandler::CompletedRequest& request);
65
66 private:
67 TestDownloadRequestInterceptor(const GURL& url);
68
69 // net::URLRequestInterceptor
70 net::URLRequestJob* MaybeInterceptRequest(
71 net::URLRequest* request,
72 net::NetworkDelegate* network_delegate) const override;
73
74 TestDownloadRequestHandler::CompletedRequests completed_requests_;
75 GURL url_;
76 JobFactory job_factory_;
77 // mutable because MaybeInterceptRequest() is inexplicably const.
78 mutable base::WeakPtrFactory<TestDownloadRequestInterceptor>
79 weak_ptr_factory_;
80 DISALLOW_COPY_AND_ASSIGN(TestDownloadRequestInterceptor);
81 };
82
83 // A URLRequestJob that constructs a response to a URLRequest based on the
84 // contents of a Parameters object. It can handle partial (i.e. byte range
85 // requests). Created on and lives on the IO thread.
86 class PartialResponseJob : public net::URLRequestJob {
87 public:
88 static net::URLRequestJob* Factory(
89 const Parameters& parameters,
90 net::URLRequest* request,
91 net::NetworkDelegate* delegate,
92 base::WeakPtr<TestDownloadRequestInterceptor> interceptor);
93
94 // URLRequestJob
95 void Start() override;
96 void GetResponseInfo(net::HttpResponseInfo* response_info) override;
97 int64 GetTotalReceivedBytes() const override;
98 bool GetMimeType(std::string* mime_type) const override;
99 int GetResponseCode() const override;
100 bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
101
102 private:
103 PartialResponseJob(scoped_ptr<Parameters> parameters,
104 base::WeakPtr<TestDownloadRequestInterceptor> interceptor,
105 net::URLRequest* url_request,
106 net::NetworkDelegate* network_delegate);
107
108 ~PartialResponseJob() override;
109 void ReportCompletedRequest(int64_t transferred_content_length);
110 static void OnStartResponseCallbackOnPossiblyIncorrectThread(
111 base::WeakPtr<PartialResponseJob> job,
112 const std::string& headers,
113 net::Error error);
114 void OnStartResponseCallback(const std::string& headers, net::Error error);
115
116 // In general, the Parameters object can specify an explicit OnStart handler.
117 // In its absence or if the explicit OnStart handler requests the default
118 // behavior, this method can be invoked to respond to the request based on the
119 // remaining Parameters fields (as if there was no OnStart handler).
120 void HandleOnStartDefault();
121
122 // Respond Start() assuming that any If-Match or If-Range headers have been
123 // successfully validated. This handler assumes that there *must* be a Range
124 // header even though the spec doesn't strictly require it for If-Match.
125 bool HandleRangeAssumingValidatorMatch();
126
127 // Adds headers that describe the entity (Content-Type, ETag, Last-Modified).
128 // It also adds an 'Accept-Ranges' header if appropriate.
129 void AddCommonEntityHeaders();
130
131 // Schedules NotifyHeadersComplete() to be called and sets
132 // offset_of_next_read_ to begin reading. Since this interceptor is avoiding
133 // network requests, it schedules the NotifyHeadersComplete() call
134 // asynchronously in order to avoid unexpected re-entrancy.
Randy Smith (Not in Mondays) 2015/11/17 22:21:42 I don't understand this sentence; what does avoidi
asanka 2015/11/23 22:04:59 Had we hit the network, we are likely to block and
Randy Smith (Not in Mondays) 2015/11/28 00:38:19 Gotcha. Suggestion, nit: add ".. is avoiding netw
asanka 2015/11/30 18:00:10 Done.
135 void NotifyHeadersCompleteAndPrepareToRead();
136
137 scoped_ptr<Parameters> parameters_;
138
139 base::WeakPtr<TestDownloadRequestInterceptor> interceptor_;
140 net::HttpResponseInfo response_info_;
141 int64_t offset_of_next_read_ = -1;
142 int64_t requested_range_begin_ = -1;
143 int64_t requested_range_end_ = -1;
144 base::WeakPtrFactory<PartialResponseJob> weak_factory_;
145
146 DISALLOW_COPY_AND_ASSIGN(PartialResponseJob);
147 };
148
149 template <class T>
150 void StoreValueAndInvokeClosure(const base::Closure& quit_closure,
Randy Smith (Not in Mondays) 2015/11/17 22:21:42 nitty nit: The name "quit_closure" presumes how th
asanka 2015/11/23 22:04:59 Renamed to 'closure'.
151 T* value_receiver,
152 T value) {
153 *value_receiver = value;
154 quit_closure.Run();
155 }
156
157 // Xorshift* PRNG from https://en.wikipedia.org/wiki/Xorshift
Randy Smith (Not in Mondays) 2015/11/17 22:21:42 Did not review except to validate that it looked a
asanka 2015/11/23 22:04:59 :-P
158 uint64_t XorShift64StarWithIndex(uint64_t seed, uint64_t index) {
159 const uint64_t kMultiplier = UINT64_C(2685821657736338717);
160 uint64_t x = seed * kMultiplier + index;
161 x ^= x >> 12;
162 x ^= x << 25;
163 x ^= x >> 27;
164 return x * kMultiplier;
165 }
166
167 void RespondToOnStartedCallbackWithStaticHeaders(
168 const std::string& headers,
169 const net::HttpRequestHeaders&,
170 const TestDownloadRequestHandler::OnStartResponseCallback& callback) {
171 callback.Run(headers, net::OK);
172 }
173
174 GURL GetNextURLForDownloadInterceptor() {
175 static int index = 0;
176 std::string url_string =
177 base::StringPrintf("https://%d.default.example.com/download/", ++index);
178 return GURL(url_string);
179 }
180
181 scoped_refptr<net::HttpResponseHeaders> HeadersFromString(
182 const std::string& headers_string) {
183 scoped_refptr<net::HttpResponseHeaders> headers =
184 new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
185 headers_string.c_str(), headers_string.size()));
186 return headers;
187 }
188
189 // static
190 net::URLRequestJob* PartialResponseJob::Factory(
191 const Parameters& parameters,
192 net::URLRequest* request,
193 net::NetworkDelegate* delegate,
194 base::WeakPtr<TestDownloadRequestInterceptor> interceptor) {
195 return new PartialResponseJob(make_scoped_ptr(new Parameters(parameters)),
196 interceptor, request, delegate);
197 }
198
199 PartialResponseJob::PartialResponseJob(
200 scoped_ptr<Parameters> parameters,
201 base::WeakPtr<TestDownloadRequestInterceptor> interceptor,
202 net::URLRequest* request,
203 net::NetworkDelegate* network_delegate)
204 : net::URLRequestJob(request, network_delegate),
205 parameters_(parameters.Pass()),
206 interceptor_(interceptor),
207 weak_factory_(this) {
208 DCHECK(parameters_.get());
209 DCHECK_LT(0, parameters_->size);
210 DCHECK_NE(-1, parameters_->pattern_generator_seed);
211 }
212
213 PartialResponseJob::~PartialResponseJob() {}
214
215 void PartialResponseJob::Start() {
216 DCHECK_CURRENTLY_ON(BrowserThread::IO);
217 DVLOG(1) << "Starting request for " << request()->url().spec();
218
219 if (parameters_->on_start_handler.is_null()) {
220 HandleOnStartDefault();
221 return;
222 }
223
224 DVLOG(1) << "Invoking custom OnStart handler.";
225 BrowserThread::PostTask(
226 BrowserThread::UI, FROM_HERE,
227 base::Bind(
228 parameters_->on_start_handler, request()->extra_request_headers(),
229 base::Bind(&PartialResponseJob::
230 OnStartResponseCallbackOnPossiblyIncorrectThread,
231 weak_factory_.GetWeakPtr())));
232 }
233
234 void PartialResponseJob::GetResponseInfo(net::HttpResponseInfo* response_info) {
235 *response_info = response_info_;
236 }
237
238 int64 PartialResponseJob::GetTotalReceivedBytes() const {
239 return offset_of_next_read_ - requested_range_begin_;
240 }
241
242 bool PartialResponseJob::GetMimeType(std::string* mime_type) const {
243 *mime_type = parameters_->content_type;
244 return !parameters_->content_type.empty();
245 }
246
247 int PartialResponseJob::GetResponseCode() const {
248 return response_info_.headers.get() ? response_info_.headers->response_code()
249 : 0;
250 }
251
252 bool PartialResponseJob::ReadRawData(net::IOBuffer* buf,
253 int buf_size,
254 int* bytes_read) {
255 *bytes_read = 0;
256 DVLOG(1) << "Preparing to read " << buf_size << " bytes";
257
258 // requested_range_begin_ == -1 implies that the body was empty.
259 if (offset_of_next_read_ > requested_range_end_ ||
260 requested_range_begin_ == -1) {
261 ReportCompletedRequest(requested_range_end_ - requested_range_begin_ + 1);
262 DVLOG(1) << "Done reading.";
263 return true;
264 }
265
266 int64_t range_end =
267 std::min(requested_range_end_, offset_of_next_read_ + buf_size - 1);
268
269 if (!parameters_->injected_errors.empty()) {
270 const InjectedError& injected_error = parameters_->injected_errors.front();
271
272 if (offset_of_next_read_ == injected_error.offset) {
273 int error = injected_error.error;
274 SetStatus(net::URLRequestStatus(net::URLRequestStatus::FAILED, error));
275 DVLOG(1) << "Returning error " << net::ErrorToString(error);
276 ReportCompletedRequest(injected_error.offset - requested_range_begin_);
277 parameters_->injected_errors.pop();
278 return false;
279 }
280
281 if (offset_of_next_read_ < injected_error.offset &&
282 injected_error.offset <= range_end)
283 range_end = injected_error.offset - 1;
284 }
285 int bytes_to_copy = (range_end - offset_of_next_read_) + 1;
286
287 TestDownloadRequestHandler::GetPatternBytes(
288 parameters_->pattern_generator_seed, offset_of_next_read_, bytes_to_copy,
289 buf->data());
290 DVLOG(1) << "Read " << bytes_to_copy << " bytes at offset "
291 << offset_of_next_read_;
292 offset_of_next_read_ += bytes_to_copy;
293 *bytes_read = bytes_to_copy;
294 return true;
295 }
296
297 void PartialResponseJob::ReportCompletedRequest(
298 int64_t transferred_content_length) {
299 if (interceptor_.get()) {
300 TestDownloadRequestHandler::CompletedRequest completed_request;
301 completed_request.transferred_content_length = transferred_content_length;
302 completed_request.request_headers = request()->extra_request_headers();
303 interceptor_->AddCompletedRequest(completed_request);
304 }
305 }
306
307 // static
308 void PartialResponseJob::OnStartResponseCallbackOnPossiblyIncorrectThread(
309 base::WeakPtr<PartialResponseJob> job,
310 const std::string& headers,
311 net::Error error) {
312 BrowserThread::PostTask(
313 BrowserThread::IO, FROM_HERE,
314 base::Bind(&PartialResponseJob::OnStartResponseCallback, job, headers,
315 error));
316 }
317
318 void PartialResponseJob::OnStartResponseCallback(const std::string& headers,
319 net::Error error) {
320 DVLOG(1) << "OnStartResponse invoked with error:" << error
321 << " and headers:" << std::endl
322 << headers;
323 DCHECK_CURRENTLY_ON(BrowserThread::IO);
324 if (headers.empty() && error == net::OK) {
325 HandleOnStartDefault();
326 return;
327 }
328
329 if (error != net::OK) {
330 NotifyStartError(net::URLRequestStatus::FromError(error));
331 return;
332 }
333
334 response_info_.headers = new net::HttpResponseHeaders(
335 net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size()));
336 NotifyHeadersCompleteAndPrepareToRead();
337 }
338
339 void PartialResponseJob::HandleOnStartDefault() {
340 DCHECK_CURRENTLY_ON(BrowserThread::IO);
341 SetStatus(net::URLRequestStatus());
342
343 const net::HttpRequestHeaders& extra_headers =
344 request()->extra_request_headers();
345
346 DCHECK(request()->method() == "GET") << "PartialResponseJob only "
347 "knows how to respond to GET "
348 "requests";
349 std::string value;
350
351 // If the request contains an 'If-Range' header and the value matches our
352 // ETag, then try to handle the range request.
353 if (parameters_->support_byte_ranges &&
354 extra_headers.GetHeader(net::HttpRequestHeaders::kIfRange, &value) &&
355 value == parameters_->etag && HandleRangeAssumingValidatorMatch())
356 return;
357
358 if (parameters_->support_byte_ranges &&
359 extra_headers.GetHeader("If-Match", &value)) {
360 if (value == parameters_->etag && HandleRangeAssumingValidatorMatch())
361 return;
362
363 // Unlike If-Range, If-Match returns an error if the validators don't match.
364 response_info_.headers = HeadersFromString(
365 "HTTP/1.1 412 Precondition failed\r\n"
366 "Content-Length: 0\r\n");
367 requested_range_begin_ = requested_range_end_ = -1;
368 NotifyHeadersCompleteAndPrepareToRead();
369 return;
370 }
371
372 requested_range_begin_ = 0;
373 requested_range_end_ = parameters_->size - 1;
374 response_info_.headers =
375 HeadersFromString(base::StringPrintf("HTTP/1.1 200 Success\r\n"
376 "Content-Length: %" PRId64 "\r\n",
377 parameters_->size));
378 AddCommonEntityHeaders();
379 NotifyHeadersCompleteAndPrepareToRead();
380 return;
381 }
382
383 bool PartialResponseJob::HandleRangeAssumingValidatorMatch() {
384 const net::HttpRequestHeaders& extra_headers =
385 request()->extra_request_headers();
386
387 std::string range_header;
388 std::vector<net::HttpByteRange> byte_ranges;
389
390 // There needs to be a 'Range' header and it should have exactly one range.
391 // This server is not going to deal with multiple ranges.
392 if (!extra_headers.GetHeader(net::HttpRequestHeaders::kRange,
393 &range_header) ||
394 !net::HttpUtil::ParseRangeHeader(range_header, &byte_ranges) ||
395 byte_ranges.size() != 1)
396 return false;
397
398 // The request may have specified a range that's out of bounds.
399 if (!byte_ranges[0].ComputeBounds(parameters_->size)) {
400 response_info_.headers = HeadersFromString(
401 base::StringPrintf("HTTP/1.1 416 Range not satisfiable\r\n"
402 "Content-Range: bytes */%" PRId64 "\r\n"
403 "Content-Length: 0\r\n",
404 parameters_->size));
405 requested_range_begin_ = requested_range_end_ = -1;
406 NotifyHeadersCompleteAndPrepareToRead();
407 return true;
408 }
409
410 requested_range_begin_ = byte_ranges[0].first_byte_position();
411 requested_range_end_ = byte_ranges[0].last_byte_position();
412 response_info_.headers =
413 HeadersFromString(base::StringPrintf(
414 "HTTP/1.1 206 Partial content\r\n"
415 "Content-Range: bytes %" PRId64 "-%" PRId64 "/%" PRId64 "\r\n"
416 "Content-Length: %" PRId64 "\r\n",
417 requested_range_begin_, requested_range_end_, parameters_->size,
418 (requested_range_end_ - requested_range_begin_) + 1));
419 AddCommonEntityHeaders();
420 NotifyHeadersCompleteAndPrepareToRead();
421 return true;
422 }
423
424 void PartialResponseJob::AddCommonEntityHeaders() {
425 if (parameters_->support_byte_ranges)
426 response_info_.headers->AddHeader("Accept-Ranges: bytes");
427
428 if (!parameters_->content_type.empty())
429 response_info_.headers->AddHeader(base::StringPrintf(
430 "Content-Type: %s", parameters_->content_type.c_str()));
431
432 if (!parameters_->etag.empty())
433 response_info_.headers->AddHeader(
434 base::StringPrintf("ETag: %s", parameters_->etag.c_str()));
435
436 if (!parameters_->last_modified.empty())
437 response_info_.headers->AddHeader(base::StringPrintf(
438 "Last-Modified: %s", parameters_->last_modified.c_str()));
439 }
440
441 void PartialResponseJob::NotifyHeadersCompleteAndPrepareToRead() {
442 std::string normalized_headers;
443 response_info_.headers->GetNormalizedHeaders(&normalized_headers);
444 DVLOG(1) << "Notify ready with headers:\n" << normalized_headers;
445
446 offset_of_next_read_ = requested_range_begin_;
447
448 // Flush out injected_errors that no longer apply. We are going to skip over
449 // ones where the |offset| == |requested_range_begin_| as well. While it
450 // prevents injecting an error at offset 0, it makes it much easier to set up
451 // parameter sets for download resumption. It means that when a request is
452 // interrupted at offset O, a subsequent request for the range O-<end> won't
453 // immediately interrupt as well. If we don't exclude interruptions at
454 // relative offset 0, then test writers would need to reset the parameter
455 // prior to each resumption rather than once at the beginning of the test.
456 while (!parameters_->injected_errors.empty() &&
457 parameters_->injected_errors.front().offset <= requested_range_begin_)
458 parameters_->injected_errors.pop();
459
460 base::MessageLoop::current()->PostTask(
461 FROM_HERE, base::Bind(&PartialResponseJob::NotifyHeadersComplete,
462 weak_factory_.GetWeakPtr()));
463 }
464
465 // static
466 base::WeakPtr<TestDownloadRequestInterceptor>
467 TestDownloadRequestInterceptor::Register(const GURL& url) {
468 DCHECK(url.is_valid());
469 scoped_ptr<TestDownloadRequestInterceptor> interceptor(
470 new TestDownloadRequestInterceptor(url));
471 base::WeakPtr<TestDownloadRequestInterceptor> weak_reference =
472 interceptor->weak_ptr_factory_.GetWeakPtr();
473 net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance();
474 filter->AddUrlInterceptor(url, interceptor.Pass());
475 return weak_reference;
476 }
477
478 void TestDownloadRequestInterceptor::Unregister() {
479 net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance();
480 filter->RemoveUrlHandler(url_);
481 // We are deleted now since the filter owned |this|.
482 }
483
484 void TestDownloadRequestInterceptor::SetJobFactory(
485 const JobFactory& job_factory) {
486 job_factory_ = job_factory;
487 }
488
489 void TestDownloadRequestInterceptor::GetAndResetCompletedRequests(
490 TestDownloadRequestHandler::CompletedRequests* requests) {
491 requests->clear();
492 completed_requests_.swap(*requests);
493 }
494
495 void TestDownloadRequestInterceptor::AddCompletedRequest(
496 const TestDownloadRequestHandler::CompletedRequest& request) {
497 completed_requests_.push_back(request);
498 }
499
500 TestDownloadRequestInterceptor::TestDownloadRequestInterceptor(const GURL& url)
501 : url_(url), weak_ptr_factory_(this) {}
502
503 TestDownloadRequestInterceptor::~TestDownloadRequestInterceptor() {}
504
505 net::URLRequestJob* TestDownloadRequestInterceptor::MaybeInterceptRequest(
506 net::URLRequest* request,
507 net::NetworkDelegate* network_delegate) const {
508 DVLOG(1) << "Intercepting request for " << request->url()
509 << " with headers:\n" << request->extra_request_headers().ToString();
510 if (job_factory_.is_null())
511 return nullptr;
512 return job_factory_.Run(request, network_delegate,
513 weak_ptr_factory_.GetWeakPtr());
514 }
515
516 } // namespace
517
518 struct TestDownloadRequestHandler::InterceptorProxy {
519 base::WeakPtr<TestDownloadRequestInterceptor> interceptor_;
520 };
521
522 TestDownloadRequestHandler::InjectedError::InjectedError(int64_t offset,
523 net::Error error)
524 : offset(offset), error(error) {}
525
526 // static
527 Parameters TestDownloadRequestHandler::Parameters::WithSingleInterruption() {
528 Parameters parameters;
529 parameters.injected_errors.push(
530 InjectedError(parameters.size / 2, net::ERR_CONNECTION_RESET));
531 return parameters;
532 }
533
534 TestDownloadRequestHandler::Parameters::Parameters()
535 : etag("abcd"),
536 last_modified("Tue, 15 Nov 1994 12:45:26 GMT"),
537 content_type("application/octet-stream"),
538 size(102400),
539 pattern_generator_seed(1),
540 support_byte_ranges(true) {}
541
542 TestDownloadRequestHandler::Parameters::~Parameters() {}
543
544 void TestDownloadRequestHandler::Parameters::ClearInjectedErrors() {
545 std::queue<InjectedError> empty_error_list;
546 injected_errors.swap(empty_error_list);
547 }
548
549 TestDownloadRequestHandler::TestDownloadRequestHandler()
550 : TestDownloadRequestHandler(GetNextURLForDownloadInterceptor()) {}
551
552 TestDownloadRequestHandler::TestDownloadRequestHandler(const GURL& url)
553 : url_(url) {
554 interceptor_proxy_.reset(new InterceptorProxy);
555 base::RunLoop run_loop;
556 BrowserThread::PostTaskAndReplyWithResult(
557 BrowserThread::IO, FROM_HERE,
558 base::Bind(&TestDownloadRequestInterceptor::Register, url_),
559 base::Bind(&StoreValueAndInvokeClosure<
560 base::WeakPtr<TestDownloadRequestInterceptor>>,
561 run_loop.QuitClosure(), &interceptor_proxy_->interceptor_));
562 run_loop.Run();
563 }
564
565 void TestDownloadRequestHandler::StartServing(const Parameters& parameters) {
566 TestDownloadRequestInterceptor::JobFactory job_factory =
567 base::Bind(&PartialResponseJob::Factory, parameters);
568 // Interceptor, if valid, is already registered and serving requests. We just
569 // need to set the correct job factory for it to start serving using the new
570 // parameters.
571 BrowserThread::PostTask(
572 BrowserThread::IO, FROM_HERE,
573 base::Bind(&TestDownloadRequestInterceptor::SetJobFactory,
574 interceptor_proxy_->interceptor_, job_factory));
575 }
576
577 void TestDownloadRequestHandler::StartServingStaticResponse(
578 const base::StringPiece& headers) {
579 Parameters parameters;
580 parameters.on_start_handler = base::Bind(
581 &RespondToOnStartedCallbackWithStaticHeaders, headers.as_string());
582 StartServing(parameters);
583 }
584
585 // static
586 void TestDownloadRequestHandler::GetPatternBytes(int seed,
587 int64_t starting_offset,
588 int length,
589 char* buffer) {
590 int64_t seed_offset = starting_offset / sizeof(int64_t);
591 int64_t first_byte_position = starting_offset % sizeof(int64_t);
592 while (length > 0) {
593 uint64_t data = XorShift64StarWithIndex(seed, seed_offset);
594 int length_to_copy =
595 std::min(length, static_cast<int>(sizeof(data) - first_byte_position));
596 memcpy(buffer, reinterpret_cast<char*>(&data) + first_byte_position,
597 length_to_copy);
598 buffer += length_to_copy;
599 length -= length_to_copy;
600 ++seed_offset;
601 first_byte_position = 0;
602 }
603 }
604
605 TestDownloadRequestHandler::~TestDownloadRequestHandler() {
606 BrowserThread::PostTask(
607 BrowserThread::IO, FROM_HERE,
608 base::Bind(&TestDownloadRequestInterceptor::Unregister,
609 interceptor_proxy_->interceptor_));
610 }
611
612 void TestDownloadRequestHandler::GetCompletedRequestInfo(
613 TestDownloadRequestHandler::CompletedRequests* requests) {
614 base::RunLoop run_loop;
615 BrowserThread::PostTaskAndReply(
616 BrowserThread::IO, FROM_HERE,
617 base::Bind(&TestDownloadRequestInterceptor::GetAndResetCompletedRequests,
618 interceptor_proxy_->interceptor_, requests),
619 run_loop.QuitClosure());
620 run_loop.Run();
621 }
622
623 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698