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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: content/public/test/test_download_request_handler.cc
diff --git a/content/public/test/test_download_request_handler.cc b/content/public/test/test_download_request_handler.cc
new file mode 100644
index 0000000000000000000000000000000000000000..1c89e0e20674fb7aea3ad702f046c0bf64cdee51
--- /dev/null
+++ b/content/public/test/test_download_request_handler.cc
@@ -0,0 +1,671 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/test/test_download_request_handler.h"
+
+#include <inttypes.h>
+
+#include "base/logging.h"
+#include "base/memory/weak_ptr.h"
+#include "base/run_loop.h"
+#include "base/sequenced_task_runner.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/base/io_buffer.h"
+#include "net/http/http_request_headers.h"
+#include "net/http/http_response_headers.h"
+#include "net/url_request/url_request_filter.h"
+#include "net/url_request/url_request_interceptor.h"
+
+namespace content {
+
+// Intercepts URLRequests on behalf of TestDownloadRequestHandler. Necessarily
+// lives on the IO thread since that's where net::URLRequestFilter invokes the
+// URLRequestInterceptor.
+class TestDownloadRequestHandler::Interceptor
+ : public net::URLRequestInterceptor {
+ public:
+ // Invoked on the IO thread to register a URLRequestInterceptor for |url|.
+ // Returns an IO-thread bound weak pointer for interacting with the
+ // interceptor.
+ static base::WeakPtr<Interceptor> Register(
+ const GURL& url,
+ scoped_refptr<base::SequencedTaskRunner> client_task_runner);
+
+ using JobFactory =
+ base::Callback<net::URLRequestJob*(net::URLRequest*,
+ net::NetworkDelegate*,
+ base::WeakPtr<Interceptor>)>;
+
+ ~Interceptor() override;
+
+ // Unregisters the URLRequestInterceptor. In reality it unregisters whatever
+ // was registered to intercept |url_|. Since |this| is owned by
+ // net::URLRequestFilter, unregistering the interceptor deletes |this| as a
+ // side-effect.
+ void Unregister();
+
+ // Change the URLRequestJob factory. Can be called multiple times.
+ void SetJobFactory(const JobFactory& factory);
+
+ // Sets |requests| to the vector of completed requests and clears the internal
+ // list. The returned requests are stored in the order in which they were
+ // reported as being complete (not necessarily the order in which they were
+ // received).
+ void GetAndResetCompletedRequests(
+ TestDownloadRequestHandler::CompletedRequests* requests);
+
+ // Can be called by a URLRequestJob to notify this interceptor of a completed
+ // request.
+ void AddCompletedRequest(
+ const TestDownloadRequestHandler::CompletedRequest& request);
+
+ // Returns the task runner that should be used for invoking any client
+ // supplied callbacks.
+ scoped_refptr<base::SequencedTaskRunner> GetClientTaskRunner();
+
+ private:
+ Interceptor(const GURL& url,
+ scoped_refptr<base::SequencedTaskRunner> client_task_runner);
+
+ // net::URLRequestInterceptor
+ net::URLRequestJob* MaybeInterceptRequest(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override;
+
+ TestDownloadRequestHandler::CompletedRequests completed_requests_;
+ GURL url_;
+ JobFactory job_factory_;
+ scoped_refptr<base::SequencedTaskRunner> client_task_runner_;
+
+ // mutable because MaybeInterceptRequest() is inexplicably const.
+ mutable base::WeakPtrFactory<Interceptor> weak_ptr_factory_;
+ DISALLOW_COPY_AND_ASSIGN(Interceptor);
+};
+
+// A URLRequestJob that constructs a response to a URLRequest based on the
+// contents of a Parameters object. It can handle partial (i.e. byte range
+// requests). Created on and lives on the IO thread.
+class TestDownloadRequestHandler::PartialResponseJob
+ : public net::URLRequestJob {
+ public:
+ static net::URLRequestJob* Factory(const Parameters& parameters,
+ net::URLRequest* request,
+ net::NetworkDelegate* delegate,
+ base::WeakPtr<Interceptor> interceptor);
+
+ // URLRequestJob
+ void Start() override;
+ void GetResponseInfo(net::HttpResponseInfo* response_info) override;
+ int64 GetTotalReceivedBytes() const override;
+ bool GetMimeType(std::string* mime_type) const override;
+ int GetResponseCode() const override;
+ int ReadRawData(net::IOBuffer* buf, int buf_size) override;
+
+ private:
+ PartialResponseJob(scoped_ptr<Parameters> parameters,
+ base::WeakPtr<Interceptor> interceptor,
+ net::URLRequest* url_request,
+ net::NetworkDelegate* network_delegate);
+
+ ~PartialResponseJob() override;
+ void ReportCompletedRequest(int64_t transferred_byte_count);
+ static void OnStartResponseCallbackOnPossiblyIncorrectThread(
+ base::WeakPtr<PartialResponseJob> job,
+ const std::string& headers,
+ net::Error error);
+ void OnStartResponseCallback(const std::string& headers, net::Error error);
+
+ // In general, the Parameters object can specify an explicit OnStart handler.
+ // In its absence or if the explicit OnStart handler requests the default
+ // behavior, this method can be invoked to respond to the request based on the
+ // remaining Parameters fields (as if there was no OnStart handler).
+ void HandleOnStartDefault();
+
+ // Respond Start() assuming that any If-Match or If-Range headers have been
+ // successfully validated. This handler assumes that there *must* be a Range
+ // header even though the spec doesn't strictly require it for If-Match.
+ bool HandleRangeAssumingValidatorMatch();
+
+ // Adds headers that describe the entity (Content-Type, ETag, Last-Modified).
+ // It also adds an 'Accept-Ranges' header if appropriate.
+ void AddCommonEntityHeaders();
+
+ // Schedules NotifyHeadersComplete() to be called and sets
+ // offset_of_next_read_ to begin reading. Since this interceptor is avoiding
+ // network requests and hence may complete synchronously, it schedules the
+ // NotifyHeadersComplete() call asynchronously in order to avoid unexpected
+ // re-entrancy.
+ void NotifyHeadersCompleteAndPrepareToRead();
+
+ scoped_ptr<Parameters> parameters_;
+
+ base::WeakPtr<Interceptor> interceptor_;
+ net::HttpResponseInfo response_info_;
+ int64_t offset_of_next_read_ = -1;
+ int64_t requested_range_begin_ = -1;
+ int64_t requested_range_end_ = -1;
+ base::WeakPtrFactory<PartialResponseJob> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PartialResponseJob);
+};
+
+namespace {
+
+template <class T>
+void StoreValueAndInvokeClosure(const base::Closure& closure,
+ T* value_receiver,
+ T value) {
+ *value_receiver = value;
+ closure.Run();
+}
+
+// Xorshift* PRNG from https://en.wikipedia.org/wiki/Xorshift
+uint64_t XorShift64StarWithIndex(uint64_t seed, uint64_t index) {
+ const uint64_t kMultiplier = UINT64_C(2685821657736338717);
+ uint64_t x = seed * kMultiplier + index;
+ x ^= x >> 12;
+ x ^= x << 25;
+ x ^= x >> 27;
+ return x * kMultiplier;
+}
+
+void RespondToOnStartedCallbackWithStaticHeaders(
+ const std::string& headers,
+ const net::HttpRequestHeaders&,
+ const TestDownloadRequestHandler::OnStartResponseCallback& callback) {
+ callback.Run(headers, net::OK);
+}
+
+GURL GetNextURLForDownloadInterceptor() {
+ static int index = 0;
+ std::string url_string =
+ base::StringPrintf("https://%d.default.example.com/download/", ++index);
+ return GURL(url_string);
+}
+
+scoped_refptr<net::HttpResponseHeaders> HeadersFromString(
+ const std::string& headers_string) {
+ scoped_refptr<net::HttpResponseHeaders> headers =
+ new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
+ headers_string.c_str(), headers_string.size()));
+ return headers;
+}
+
+} // namespace
+
+// static
+net::URLRequestJob* TestDownloadRequestHandler::PartialResponseJob::Factory(
+ const Parameters& parameters,
+ net::URLRequest* request,
+ net::NetworkDelegate* delegate,
+ base::WeakPtr<Interceptor> interceptor) {
+ return new PartialResponseJob(make_scoped_ptr(new Parameters(parameters)),
+ interceptor, request, delegate);
+}
+
+TestDownloadRequestHandler::PartialResponseJob::PartialResponseJob(
+ scoped_ptr<Parameters> parameters,
+ base::WeakPtr<Interceptor> interceptor,
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate)
+ : net::URLRequestJob(request, network_delegate),
+ parameters_(parameters.Pass()),
+ interceptor_(interceptor),
+ weak_factory_(this) {
+ DCHECK(parameters_.get());
+ DCHECK_LT(0, parameters_->size);
+ DCHECK_NE(-1, parameters_->pattern_generator_seed);
+}
+
+TestDownloadRequestHandler::PartialResponseJob::~PartialResponseJob() {}
+
+void TestDownloadRequestHandler::PartialResponseJob::Start() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DVLOG(1) << "Starting request for " << request()->url().spec();
+
+ if (parameters_->on_start_handler.is_null() || !interceptor_.get()) {
+ HandleOnStartDefault();
+ return;
+ }
+
+ DVLOG(1) << "Invoking custom OnStart handler.";
+ interceptor_->GetClientTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ parameters_->on_start_handler, request()->extra_request_headers(),
+ base::Bind(&PartialResponseJob::
+ OnStartResponseCallbackOnPossiblyIncorrectThread,
+ weak_factory_.GetWeakPtr())));
+}
+
+void TestDownloadRequestHandler::PartialResponseJob::GetResponseInfo(
+ net::HttpResponseInfo* response_info) {
+ *response_info = response_info_;
+}
+
+int64 TestDownloadRequestHandler::PartialResponseJob::GetTotalReceivedBytes()
+ const {
+ return offset_of_next_read_ - requested_range_begin_;
+}
+
+bool TestDownloadRequestHandler::PartialResponseJob::GetMimeType(
+ std::string* mime_type) const {
+ *mime_type = parameters_->content_type;
+ return !parameters_->content_type.empty();
+}
+
+int TestDownloadRequestHandler::PartialResponseJob::GetResponseCode() const {
+ return response_info_.headers.get() ? response_info_.headers->response_code()
+ : 0;
+}
+
+int TestDownloadRequestHandler::PartialResponseJob::ReadRawData(
+ net::IOBuffer* buf,
+ int buf_size) {
+ DVLOG(1) << "Preparing to read " << buf_size << " bytes";
+
+ // requested_range_begin_ == -1 implies that the body was empty.
+ if (offset_of_next_read_ > requested_range_end_ ||
+ requested_range_begin_ == -1) {
+ ReportCompletedRequest(requested_range_end_ - requested_range_begin_ + 1);
+ DVLOG(1) << "Done reading.";
+ return 0;
+ }
+
+ int64_t range_end =
+ std::min(requested_range_end_, offset_of_next_read_ + buf_size - 1);
+
+ if (!parameters_->injected_errors.empty()) {
+ const InjectedError& injected_error = parameters_->injected_errors.front();
+
+ if (offset_of_next_read_ == injected_error.offset) {
+ int error = injected_error.error;
+ SetStatus(net::URLRequestStatus(net::URLRequestStatus::FAILED, error));
+ DVLOG(1) << "Returning error " << net::ErrorToString(error);
+ ReportCompletedRequest(injected_error.offset - requested_range_begin_);
+ parameters_->injected_errors.pop();
+ return error;
+ }
+
+ if (offset_of_next_read_ < injected_error.offset &&
+ injected_error.offset <= range_end)
+ range_end = injected_error.offset - 1;
+ }
+ int bytes_to_copy = (range_end - offset_of_next_read_) + 1;
+
+ TestDownloadRequestHandler::GetPatternBytes(
+ parameters_->pattern_generator_seed, offset_of_next_read_, bytes_to_copy,
+ buf->data());
+ DVLOG(1) << "Read " << bytes_to_copy << " bytes at offset "
+ << offset_of_next_read_;
+ offset_of_next_read_ += bytes_to_copy;
+ return bytes_to_copy;
+}
+
+void TestDownloadRequestHandler::PartialResponseJob::ReportCompletedRequest(
+ int64_t transferred_byte_count) {
+ if (interceptor_.get()) {
+ TestDownloadRequestHandler::CompletedRequest completed_request;
+ completed_request.transferred_byte_count = transferred_byte_count;
+ completed_request.request_headers = request()->extra_request_headers();
+ interceptor_->AddCompletedRequest(completed_request);
+ }
+}
+
+// static
+void TestDownloadRequestHandler::PartialResponseJob::
+ OnStartResponseCallbackOnPossiblyIncorrectThread(
+ base::WeakPtr<PartialResponseJob> job,
+ const std::string& headers,
+ net::Error error) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&PartialResponseJob::OnStartResponseCallback, job, headers,
+ error));
+}
+
+void TestDownloadRequestHandler::PartialResponseJob::OnStartResponseCallback(
+ const std::string& headers,
+ net::Error error) {
+ DVLOG(1) << "OnStartResponse invoked with error:" << error
+ << " and headers:" << std::endl
+ << headers;
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (headers.empty() && error == net::OK) {
+ HandleOnStartDefault();
+ return;
+ }
+
+ if (error != net::OK) {
+ NotifyStartError(net::URLRequestStatus::FromError(error));
+ return;
+ }
+
+ response_info_.headers = new net::HttpResponseHeaders(
+ net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size()));
+ NotifyHeadersCompleteAndPrepareToRead();
+}
+
+void TestDownloadRequestHandler::PartialResponseJob::HandleOnStartDefault() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ SetStatus(net::URLRequestStatus());
+
+ const net::HttpRequestHeaders& extra_headers =
+ request()->extra_request_headers();
+
+ DCHECK(request()->method() == "GET") << "PartialResponseJob only "
+ "knows how to respond to GET "
+ "requests";
+ std::string value;
+
+ // If the request contains an 'If-Range' header and the value matches our
+ // ETag, then try to handle the range request.
+ if (parameters_->support_byte_ranges &&
+ extra_headers.GetHeader(net::HttpRequestHeaders::kIfRange, &value) &&
+ value == parameters_->etag && HandleRangeAssumingValidatorMatch())
+ return;
+
+ if (parameters_->support_byte_ranges &&
+ extra_headers.GetHeader("If-Match", &value)) {
+ if (value == parameters_->etag && HandleRangeAssumingValidatorMatch())
+ return;
+
+ // Unlike If-Range, If-Match returns an error if the validators don't match.
+ response_info_.headers = HeadersFromString(
+ "HTTP/1.1 412 Precondition failed\r\n"
+ "Content-Length: 0\r\n");
+ requested_range_begin_ = requested_range_end_ = -1;
+ NotifyHeadersCompleteAndPrepareToRead();
+ return;
+ }
+
+ requested_range_begin_ = 0;
+ requested_range_end_ = parameters_->size - 1;
+ response_info_.headers =
+ HeadersFromString(base::StringPrintf("HTTP/1.1 200 Success\r\n"
+ "Content-Length: %" PRId64 "\r\n",
+ parameters_->size));
+ AddCommonEntityHeaders();
+ NotifyHeadersCompleteAndPrepareToRead();
+ return;
+}
+
+bool TestDownloadRequestHandler::PartialResponseJob::
+ HandleRangeAssumingValidatorMatch() {
+ const net::HttpRequestHeaders& extra_headers =
+ request()->extra_request_headers();
+
+ std::string range_header;
+ std::vector<net::HttpByteRange> byte_ranges;
+
+ // There needs to be a 'Range' header and it should have exactly one range.
+ // This server is not going to deal with multiple ranges.
+ if (!extra_headers.GetHeader(net::HttpRequestHeaders::kRange,
+ &range_header) ||
+ !net::HttpUtil::ParseRangeHeader(range_header, &byte_ranges) ||
+ byte_ranges.size() != 1)
+ return false;
+
+ // The request may have specified a range that's out of bounds.
+ if (!byte_ranges[0].ComputeBounds(parameters_->size)) {
+ response_info_.headers = HeadersFromString(
+ base::StringPrintf("HTTP/1.1 416 Range not satisfiable\r\n"
+ "Content-Range: bytes */%" PRId64 "\r\n"
+ "Content-Length: 0\r\n",
+ parameters_->size));
+ requested_range_begin_ = requested_range_end_ = -1;
+ NotifyHeadersCompleteAndPrepareToRead();
+ return true;
+ }
+
+ requested_range_begin_ = byte_ranges[0].first_byte_position();
+ requested_range_end_ = byte_ranges[0].last_byte_position();
+ response_info_.headers =
+ HeadersFromString(base::StringPrintf(
+ "HTTP/1.1 206 Partial content\r\n"
+ "Content-Range: bytes %" PRId64 "-%" PRId64 "/%" PRId64 "\r\n"
+ "Content-Length: %" PRId64 "\r\n",
+ requested_range_begin_, requested_range_end_, parameters_->size,
+ (requested_range_end_ - requested_range_begin_) + 1));
+ AddCommonEntityHeaders();
+ NotifyHeadersCompleteAndPrepareToRead();
+ return true;
+}
+
+void TestDownloadRequestHandler::PartialResponseJob::AddCommonEntityHeaders() {
+ if (parameters_->support_byte_ranges)
+ response_info_.headers->AddHeader("Accept-Ranges: bytes");
+
+ if (!parameters_->content_type.empty())
+ response_info_.headers->AddHeader(base::StringPrintf(
+ "Content-Type: %s", parameters_->content_type.c_str()));
+
+ if (!parameters_->etag.empty())
+ response_info_.headers->AddHeader(
+ base::StringPrintf("ETag: %s", parameters_->etag.c_str()));
+
+ if (!parameters_->last_modified.empty())
+ response_info_.headers->AddHeader(base::StringPrintf(
+ "Last-Modified: %s", parameters_->last_modified.c_str()));
+}
+
+void TestDownloadRequestHandler::PartialResponseJob::
+ NotifyHeadersCompleteAndPrepareToRead() {
+ std::string normalized_headers;
+ response_info_.headers->GetNormalizedHeaders(&normalized_headers);
+ DVLOG(1) << "Notify ready with headers:\n" << normalized_headers;
+
+ offset_of_next_read_ = requested_range_begin_;
+
+ // Flush out injected_errors that no longer apply. We are going to skip over
+ // ones where the |offset| == |requested_range_begin_| as well. While it
+ // prevents injecting an error at offset 0, it makes it much easier to set up
+ // parameter sets for download resumption. It means that when a request is
+ // interrupted at offset O, a subsequent request for the range O-<end> won't
+ // immediately interrupt as well. If we don't exclude interruptions at
+ // relative offset 0, then test writers would need to reset the parameter
+ // prior to each resumption rather than once at the beginning of the test.
+ while (!parameters_->injected_errors.empty() &&
+ parameters_->injected_errors.front().offset <= requested_range_begin_)
+ parameters_->injected_errors.pop();
+
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(&PartialResponseJob::NotifyHeadersComplete,
+ weak_factory_.GetWeakPtr()));
+}
+
+// static
+base::WeakPtr<TestDownloadRequestHandler::Interceptor>
+TestDownloadRequestHandler::Interceptor::Register(
+ const GURL& url,
+ scoped_refptr<base::SequencedTaskRunner> client_task_runner) {
+ DCHECK(url.is_valid());
+ scoped_ptr<Interceptor> interceptor(new Interceptor(url, client_task_runner));
+ base::WeakPtr<Interceptor> weak_reference =
+ interceptor->weak_ptr_factory_.GetWeakPtr();
+ net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance();
+ filter->AddUrlInterceptor(url, interceptor.Pass());
+ return weak_reference;
+}
+
+void TestDownloadRequestHandler::Interceptor::Unregister() {
+ net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance();
+ filter->RemoveUrlHandler(url_);
+ // We are deleted now since the filter owned |this|.
+}
+
+void TestDownloadRequestHandler::Interceptor::SetJobFactory(
+ const JobFactory& job_factory) {
+ job_factory_ = job_factory;
+}
+
+void TestDownloadRequestHandler::Interceptor::GetAndResetCompletedRequests(
+ TestDownloadRequestHandler::CompletedRequests* requests) {
+ requests->clear();
+ completed_requests_.swap(*requests);
+}
+
+void TestDownloadRequestHandler::Interceptor::AddCompletedRequest(
+ const TestDownloadRequestHandler::CompletedRequest& request) {
+ completed_requests_.push_back(request);
+}
+
+scoped_refptr<base::SequencedTaskRunner>
+TestDownloadRequestHandler::Interceptor::GetClientTaskRunner() {
+ return client_task_runner_;
+}
+
+TestDownloadRequestHandler::Interceptor::Interceptor(
+ const GURL& url,
+ scoped_refptr<base::SequencedTaskRunner> client_task_runner)
+ : url_(url),
+ client_task_runner_(client_task_runner),
+ weak_ptr_factory_(this) {}
+
+TestDownloadRequestHandler::Interceptor::~Interceptor() {}
+
+net::URLRequestJob*
+TestDownloadRequestHandler::Interceptor::MaybeInterceptRequest(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const {
+ DVLOG(1) << "Intercepting request for " << request->url()
+ << " with headers:\n" << request->extra_request_headers().ToString();
+ if (job_factory_.is_null())
+ return nullptr;
+ return job_factory_.Run(request, network_delegate,
+ weak_ptr_factory_.GetWeakPtr());
+}
+
+TestDownloadRequestHandler::InjectedError::InjectedError(int64_t offset,
+ net::Error error)
+ : offset(offset), error(error) {}
+
+// static
+TestDownloadRequestHandler::Parameters
+TestDownloadRequestHandler::Parameters::WithSingleInterruption() {
+ Parameters parameters;
+ parameters.injected_errors.push(
+ InjectedError(parameters.size / 2, net::ERR_CONNECTION_RESET));
+ return parameters;
+}
+
+TestDownloadRequestHandler::Parameters::Parameters()
+ : etag("abcd"),
+ last_modified("Tue, 15 Nov 1994 12:45:26 GMT"),
+ content_type("application/octet-stream"),
+ size(102400),
+ pattern_generator_seed(1),
+ support_byte_ranges(true) {}
+
+// Copy and move constructors / assignment operators are all defaults.
+TestDownloadRequestHandler::Parameters::Parameters(const Parameters&) = default;
+TestDownloadRequestHandler::Parameters& TestDownloadRequestHandler::Parameters::
+operator=(const Parameters&) = default;
+
+TestDownloadRequestHandler::Parameters::Parameters(Parameters&& that)
+ : etag(std::move(that.etag)),
+ last_modified(std::move(that.last_modified)),
+ content_type(std::move(that.content_type)),
+ size(that.size),
+ pattern_generator_seed(that.pattern_generator_seed),
+ on_start_handler(that.on_start_handler),
+ injected_errors(std::move(that.injected_errors)) {}
+
+TestDownloadRequestHandler::Parameters& TestDownloadRequestHandler::Parameters::
+operator=(Parameters&& that) {
+ etag = std::move(that.etag);
+ last_modified = std::move(that.etag);
+ content_type = std::move(that.content_type);
+ size = that.size;
+ pattern_generator_seed = that.pattern_generator_seed;
+ on_start_handler = that.on_start_handler;
+ injected_errors.swap(that.injected_errors);
+ return *this;
+}
+
+TestDownloadRequestHandler::Parameters::~Parameters() {}
+
+void TestDownloadRequestHandler::Parameters::ClearInjectedErrors() {
+ std::queue<InjectedError> empty_error_list;
+ injected_errors.swap(empty_error_list);
+}
+
+TestDownloadRequestHandler::TestDownloadRequestHandler()
+ : TestDownloadRequestHandler(GetNextURLForDownloadInterceptor()) {}
+
+TestDownloadRequestHandler::TestDownloadRequestHandler(const GURL& url)
+ : url_(url) {
+ DCHECK(base::SequencedTaskRunnerHandle::IsSet());
+ base::RunLoop run_loop;
+ BrowserThread::PostTaskAndReplyWithResult(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&Interceptor::Register, url_,
+ base::SequencedTaskRunnerHandle::Get()),
+ base::Bind(&StoreValueAndInvokeClosure<base::WeakPtr<Interceptor>>,
+ run_loop.QuitClosure(), &interceptor_));
+ run_loop.Run();
+}
+
+void TestDownloadRequestHandler::StartServing(const Parameters& parameters) {
+ DCHECK(CalledOnValidThread());
+ Interceptor::JobFactory job_factory =
+ base::Bind(&PartialResponseJob::Factory, parameters);
+ // Interceptor, if valid, is already registered and serving requests. We just
+ // need to set the correct job factory for it to start serving using the new
+ // parameters.
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&Interceptor::SetJobFactory, interceptor_, job_factory));
+}
+
+void TestDownloadRequestHandler::StartServingStaticResponse(
+ const base::StringPiece& headers) {
+ DCHECK(CalledOnValidThread());
+ Parameters parameters;
+ parameters.on_start_handler = base::Bind(
+ &RespondToOnStartedCallbackWithStaticHeaders, headers.as_string());
+ StartServing(parameters);
+}
+
+// static
+void TestDownloadRequestHandler::GetPatternBytes(int seed,
+ int64_t starting_offset,
+ int length,
+ char* buffer) {
+ int64_t seed_offset = starting_offset / sizeof(int64_t);
+ int64_t first_byte_position = starting_offset % sizeof(int64_t);
+ while (length > 0) {
+ uint64_t data = XorShift64StarWithIndex(seed, seed_offset);
+ int length_to_copy =
+ std::min(length, static_cast<int>(sizeof(data) - first_byte_position));
+ memcpy(buffer, reinterpret_cast<char*>(&data) + first_byte_position,
+ length_to_copy);
+ buffer += length_to_copy;
+ length -= length_to_copy;
+ ++seed_offset;
+ first_byte_position = 0;
+ }
+}
+
+TestDownloadRequestHandler::~TestDownloadRequestHandler() {
+ DCHECK(CalledOnValidThread());
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&Interceptor::Unregister, interceptor_));
+}
+
+void TestDownloadRequestHandler::GetCompletedRequestInfo(
+ TestDownloadRequestHandler::CompletedRequests* requests) {
+ DCHECK(CalledOnValidThread());
+ base::RunLoop run_loop;
+ BrowserThread::PostTaskAndReply(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&Interceptor::GetAndResetCompletedRequests, interceptor_,
+ requests),
+ run_loop.QuitClosure());
+ run_loop.Run();
+}
+
+} // namespace content
« 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