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

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

Powered by Google App Engine
This is Rietveld 408576698