| Index: net/cert_net/cert_net_fetcher_impl.cc
|
| diff --git a/net/cert_net/cert_net_fetcher_impl.cc b/net/cert_net/cert_net_fetcher_impl.cc
|
| index 01fca4f796aa13d957a24df549f631151eec630e..bedd2af413bee6299b8c48e469830103ca155c47 100644
|
| --- a/net/cert_net/cert_net_fetcher_impl.cc
|
| +++ b/net/cert_net/cert_net_fetcher_impl.cc
|
| @@ -1,6 +1,62 @@
|
| // 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.
|
| +//
|
| +// Overview
|
| +//
|
| +// The main entry point is CertNetFetcherImpl. This is an implementation of
|
| +// CertNetFetcher that provides a service for fetching network requests.
|
| +//
|
| +// The interface for CertNetFetcher is synchronous, however allows
|
| +// overlapping requests. When starting a request CertNetFetcherImpl
|
| +// returns a CertNetFetcher::Request (CertNetFetcherImpl) that the
|
| +// caller can use to cancel the fetch, or wait for it to complete
|
| +// (blocking).
|
| +//
|
| +// The classes are mainly organized based on their thread affinity:
|
| +//
|
| +// ---------------
|
| +// Lives on caller thread
|
| +// ---------------
|
| +//
|
| +// CertNetFetcherImpl (implements CertNetFetcher)
|
| +// * Main entry point
|
| +// * Provides a service to start/cancel/wait for URL fetches
|
| +// * Returns callers a CertNetFetcher::Request as a handle
|
| +// * Requests can run in parallel, however will block the current thread when
|
| +// reading results.
|
| +// * Posts tasks to network thread to coordinate actual work
|
| +//
|
| +// CertNetFetcherRequestImpl (implements CertNetFetcher::Request)
|
| +// * Wrapper for cancelling events, or waiting for a request to complete
|
| +// * Waits on a WaitableEvent to complete requests.
|
| +//
|
| +// ---------------
|
| +// Straddles caller thread and network thread
|
| +// ---------------
|
| +//
|
| +// CertNetFetcherCore
|
| +// * Reference-counted bridge between CertNetFetcherImpl and the dependencies
|
| +// on network thread.
|
| +// * Small wrapper to holds the state that is conceptually owned by
|
| +// CertNetFetcherImpl, but belongs on the network thread.
|
| +//
|
| +// RequestCore
|
| +// * Reference-counted bridge between CertNetFetcherRequestImpl and the
|
| +// dependencies on the network thread
|
| +// * Holds the result of the request, a WaitableEvent for signaling
|
| +// completion, and pointers for canceling work on network thread.
|
| +//
|
| +// ---------------
|
| +// Lives on network thread
|
| +// ---------------
|
| +//
|
| +// AsyncCertNetFetcherImpl
|
| +// * Asyncronous manager for outstanding requests. Handles de-duplication,
|
| +// timeouts, and actual integration with network stack. This is where the
|
| +// majority of the logic lives.
|
| +// * Signals completion of requests through RequestCore's WaitableEvent.
|
| +// * Attaches requests to Jobs for the purpose of de-duplication
|
|
|
| #include "net/cert_net/cert_net_fetcher_impl.h"
|
|
|
| @@ -8,15 +64,17 @@
|
| #include <utility>
|
|
|
| #include "base/callback_helpers.h"
|
| -#include "base/containers/linked_list.h"
|
| #include "base/logging.h"
|
| #include "base/macros.h"
|
| #include "base/memory/ptr_util.h"
|
| #include "base/numerics/safe_math.h"
|
| +#include "base/synchronization/waitable_event.h"
|
| #include "base/timer/timer.h"
|
| #include "net/base/load_flags.h"
|
| +#include "net/cert/cert_net_fetcher.h"
|
| #include "net/url_request/redirect_info.h"
|
| #include "net/url_request/url_request_context.h"
|
| +#include "net/url_request/url_request_context_getter.h"
|
|
|
| // TODO(eroman): Add support for POST parameters.
|
| // TODO(eroman): Add controls for bypassing the cache.
|
| @@ -40,6 +98,68 @@ const int kMaxResponseSizeInBytesForAia = 64 * 1024;
|
| // The default timeout in seconds for fetch requests.
|
| const int kTimeoutSeconds = 15;
|
|
|
| +class RequestCore;
|
| +struct RequestParams;
|
| +class Job;
|
| +
|
| +struct JobToRequestParamsComparator;
|
| +
|
| +struct JobComparator {
|
| + bool operator()(const Job* job1, const Job* job2) const;
|
| +};
|
| +
|
| +// Would be a set<unique_ptr> but extraction of owned objects from a set of
|
| +// owned types doesn't come until C++17.
|
| +using JobSet = std::map<Job*, std::unique_ptr<Job>, JobComparator>;
|
| +
|
| +// AsyncCertNetFetcherImpl manages URLRequests in an async fashion on the
|
| +// URLRequestContexts's task runner thread.
|
| +//
|
| +// * Schedules
|
| +// * De-duplicates requests
|
| +// * Handles timeouts
|
| +class AsyncCertNetFetcherImpl {
|
| + public:
|
| + // Initializes AsyncCertNetFetcherImpl using the specified URLRequestContext
|
| + // for issuing requests. |context| must remain valid for the entire
|
| + // lifetime of the AsyncCertNetFetcherImpl.
|
| + explicit AsyncCertNetFetcherImpl(URLRequestContext* context);
|
| +
|
| + // Deletion implicitly cancels any outstanding requests.
|
| + ~AsyncCertNetFetcherImpl();
|
| +
|
| + // Starts an asynchronous request to fetch the given URL. On completion
|
| + // |callback| will be invoked.
|
| + //
|
| + // Completion of the request will never occur synchronously. In other words it
|
| + // is guaranteed that |callback| will only be invoked once the Fetch*() method
|
| + // has returned.
|
| + void Fetch(std::unique_ptr<RequestParams> request_params,
|
| + RequestCore* request);
|
| +
|
| + private:
|
| + friend class Job;
|
| +
|
| + // Finds a job with a matching RequestPararms or returns nullptr if there was
|
| + // no match.
|
| + Job* FindJob(const RequestParams& params);
|
| +
|
| + // Removes |job| from the in progress jobs and transfers ownership to the
|
| + // caller.
|
| + std::unique_ptr<Job> RemoveJob(Job* job);
|
| +
|
| + // The in-progress jobs. This set does not contain the job which is actively
|
| + // invoking callbacks (OnJobCompleted).
|
| + JobSet jobs_;
|
| +
|
| + // Not owned. |context_| must outlive the AsyncCertNetFetcherImpl.
|
| + URLRequestContext* context_ = nullptr;
|
| +
|
| + base::ThreadChecker thread_checker_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(AsyncCertNetFetcherImpl);
|
| +};
|
| +
|
| // Policy for which URLs are allowed to be fetched. This is called both for the
|
| // initial URL and for each redirect. Returns OK on success or a net error
|
| // code on failure.
|
| @@ -74,46 +194,72 @@ enum HttpMethod {
|
| HTTP_METHOD_POST,
|
| };
|
|
|
| -} // namespace
|
| -
|
| -// CertNetFetcherImpl::RequestImpl tracks an outstanding call to Fetch().
|
| -class CertNetFetcherImpl::RequestImpl : public CertNetFetcher::Request,
|
| - public base::LinkNode<RequestImpl> {
|
| +// RequestCore tracks an outstanding call to Fetch(). It is
|
| +// reference-counted for ease of sharing between threads.
|
| +class RequestCore : public base::RefCountedThreadSafe<RequestCore> {
|
| public:
|
| - RequestImpl(Job* job, const FetchCallback& callback)
|
| - : callback_(callback), job_(job) {
|
| - DCHECK(!callback.is_null());
|
| - }
|
| -
|
| - // Deletion cancels the outstanding request.
|
| - ~RequestImpl() override;
|
| -
|
| - void OnJobCancelled(Job* job) {
|
| - DCHECK_EQ(job_, job);
|
| - job_ = nullptr;
|
| - callback_.Reset();
|
| + explicit RequestCore(scoped_refptr<base::SingleThreadTaskRunner> task_runner)
|
| + : completion_event_(base::WaitableEvent::ResetPolicy::MANUAL,
|
| + base::WaitableEvent::InitialState::NOT_SIGNALED),
|
| + task_runner_(std::move(task_runner)) {}
|
| +
|
| + void AttachedToJob(Job* job) {
|
| + DCHECK(task_runner_->RunsTasksOnCurrentThread());
|
| + DCHECK(!job_);
|
| + job_ = job;
|
| }
|
|
|
| void OnJobCompleted(Job* job,
|
| Error error,
|
| const std::vector<uint8_t>& response_body) {
|
| + DCHECK(task_runner_->RunsTasksOnCurrentThread());
|
| +
|
| DCHECK_EQ(job_, job);
|
| job_ = nullptr;
|
| - base::ResetAndReturn(&callback_).Run(error, response_body);
|
| +
|
| + error_ = error;
|
| + bytes_ = response_body;
|
| + completion_event_.Signal();
|
| + }
|
| +
|
| + // Can be called from any thread.
|
| + void Cancel();
|
| +
|
| + // Should only be called once.
|
| + void WaitForResult(Error* error, std::vector<uint8_t>* bytes) {
|
| + DCHECK(!task_runner_->RunsTasksOnCurrentThread());
|
| +
|
| + completion_event_.Wait();
|
| + *bytes = std::move(bytes_);
|
| + *error = error_;
|
| +
|
| + error_ = ERR_UNEXPECTED;
|
| }
|
|
|
| private:
|
| - // The callback to invoke when the request has completed.
|
| - FetchCallback callback_;
|
| + friend class base::RefCountedThreadSafe<RequestCore>;
|
| +
|
| + ~RequestCore() {
|
| + // Requests should have been cancelled prior to destruction.
|
| + DCHECK(!job_);
|
| + }
|
|
|
| // A non-owned pointer to the job that is executing the request.
|
| - Job* job_;
|
| + Job* job_ = nullptr;
|
|
|
| - private:
|
| - DISALLOW_COPY_AND_ASSIGN(RequestImpl);
|
| + // May be written to from network thread.
|
| + Error error_;
|
| + std::vector<uint8_t> bytes_;
|
| +
|
| + // Indicates when |error_| and |bytes_| have been written to.
|
| + base::WaitableEvent completion_event_;
|
| +
|
| + scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(RequestCore);
|
| };
|
|
|
| -struct CertNetFetcherImpl::RequestParams {
|
| +struct RequestParams {
|
| RequestParams();
|
|
|
| bool operator<(const RequestParams& other) const;
|
| @@ -131,48 +277,39 @@ struct CertNetFetcherImpl::RequestParams {
|
| DISALLOW_COPY_AND_ASSIGN(RequestParams);
|
| };
|
|
|
| -CertNetFetcherImpl::RequestParams::RequestParams()
|
| - : http_method(HTTP_METHOD_GET), max_response_bytes(0) {
|
| -}
|
| +RequestParams::RequestParams()
|
| + : http_method(HTTP_METHOD_GET), max_response_bytes(0) {}
|
|
|
| -bool CertNetFetcherImpl::RequestParams::operator<(
|
| - const RequestParams& other) const {
|
| +bool RequestParams::operator<(const RequestParams& other) const {
|
| return std::tie(url, http_method, max_response_bytes, timeout) <
|
| std::tie(other.url, other.http_method, other.max_response_bytes,
|
| other.timeout);
|
| }
|
|
|
| -// CertNetFetcherImpl::Job tracks an outstanding URLRequest as well as all of
|
| -// the pending requests for it.
|
| -class CertNetFetcherImpl::Job : public URLRequest::Delegate {
|
| +// Job tracks an outstanding URLRequest as well as all of the pending requests
|
| +// for it.
|
| +class Job : public URLRequest::Delegate {
|
| public:
|
| Job(std::unique_ptr<RequestParams> request_params,
|
| - CertNetFetcherImpl* parent);
|
| + AsyncCertNetFetcherImpl* parent);
|
| ~Job() override;
|
|
|
| - // Cancels the job and all requests attached to it. No callbacks will be
|
| - // invoked following cancellation.
|
| - void Cancel();
|
| -
|
| const RequestParams& request_params() const { return *request_params_; }
|
|
|
| // Create a request and attaches it to the job. When the job completes it will
|
| // notify the request of completion through OnJobCompleted. Note that the Job
|
| // does NOT own the request.
|
| - std::unique_ptr<Request> CreateRequest(const FetchCallback& callback);
|
| + void AttachRequest(RequestCore* request);
|
|
|
| // Removes |request| from the job.
|
| - void DetachRequest(RequestImpl* request);
|
| + void DetachRequest(RequestCore* request);
|
|
|
| - // Creates and starts a URLRequest for the job. After the request has
|
| + // Creates and starts a URLRequest for the job. After the URLRequest has
|
| // completed, OnJobCompleted() will be invoked and all the registered requests
|
| // notified of completion.
|
| void StartURLRequest(URLRequestContext* context);
|
|
|
| private:
|
| - // The pointers in RequestList are not owned by the Job.
|
| - using RequestList = base::LinkedList<RequestImpl>;
|
| -
|
| // Implementation of URLRequest::Delegate
|
| void OnReceivedRedirect(URLRequest* request,
|
| const RedirectInfo& redirect_info,
|
| @@ -203,8 +340,8 @@ class CertNetFetcherImpl::Job : public URLRequest::Delegate {
|
| // OnUrlRequestCompleted().
|
| void FailRequest(Error error);
|
|
|
| - // The requests attached to this job.
|
| - RequestList requests_;
|
| + // The requests attached to this job (non-owned).
|
| + std::vector<RequestCore*> requests_;
|
|
|
| // The input parameters for starting a URLRequest.
|
| std::unique_ptr<RequestParams> request_params_;
|
| @@ -219,66 +356,59 @@ class CertNetFetcherImpl::Job : public URLRequest::Delegate {
|
| // also used for notifying a failure to start the URLRequest.
|
| base::OneShotTimer timer_;
|
|
|
| - // Non-owned pointer to the CertNetFetcherImpl that created this job.
|
| - CertNetFetcherImpl* parent_;
|
| + // Non-owned pointer to the AsyncCertNetFetcherImpl that created this job.
|
| + AsyncCertNetFetcherImpl* parent_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(Job);
|
| };
|
|
|
| -CertNetFetcherImpl::RequestImpl::~RequestImpl() {
|
| - if (job_)
|
| - job_->DetachRequest(this);
|
| -}
|
| +void RequestCore::Cancel() {
|
| + if (!task_runner_->RunsTasksOnCurrentThread()) {
|
| + task_runner_->PostTask(FROM_HERE, base::Bind(&RequestCore::Cancel, this));
|
| + return;
|
| + }
|
|
|
| -CertNetFetcherImpl::Job::Job(std::unique_ptr<RequestParams> request_params,
|
| - CertNetFetcherImpl* parent)
|
| - : request_params_(std::move(request_params)),
|
| - parent_(parent) {}
|
| + if (job_) {
|
| + auto* job = job_;
|
| + job_ = nullptr;
|
| + job->DetachRequest(this);
|
| + }
|
|
|
| -CertNetFetcherImpl::Job::~Job() {
|
| - Cancel();
|
| + bytes_.clear();
|
| + error_ = ERR_UNEXPECTED;
|
| }
|
|
|
| -void CertNetFetcherImpl::Job::Cancel() {
|
| - parent_ = nullptr;
|
| -
|
| - // Notify each request of cancellation and remove it from the list.
|
| - for (base::LinkNode<RequestImpl>* current = requests_.head();
|
| - current != requests_.end();) {
|
| - base::LinkNode<RequestImpl>* next = current->next();
|
| - current->value()->OnJobCancelled(this);
|
| - current->RemoveFromList();
|
| - current = next;
|
| - }
|
| +Job::Job(std::unique_ptr<RequestParams> request_params,
|
| + AsyncCertNetFetcherImpl* parent)
|
| + : request_params_(std::move(request_params)), parent_(parent) {}
|
|
|
| +Job::~Job() {
|
| DCHECK(requests_.empty());
|
| -
|
| Stop();
|
| }
|
|
|
| -std::unique_ptr<CertNetFetcher::Request> CertNetFetcherImpl::Job::CreateRequest(
|
| - const FetchCallback& callback) {
|
| - std::unique_ptr<RequestImpl> request(new RequestImpl(this, callback));
|
| - requests_.Append(request.get());
|
| - return std::move(request);
|
| +void Job::AttachRequest(RequestCore* request) {
|
| + requests_.push_back(request);
|
| + request->AttachedToJob(this);
|
| }
|
|
|
| -void CertNetFetcherImpl::Job::DetachRequest(RequestImpl* request) {
|
| +void Job::DetachRequest(RequestCore* request) {
|
| std::unique_ptr<Job> delete_this;
|
|
|
| - request->RemoveFromList();
|
| + auto it = std::find(requests_.begin(), requests_.end(), request);
|
| + DCHECK(it != requests_.end());
|
| + requests_.erase(it);
|
|
|
| // If there are no longer any requests attached to the job then
|
| // cancel and delete it.
|
| - if (requests_.empty() && !parent_->IsCurrentlyCompletingJob(this))
|
| + if (requests_.empty())
|
| delete_this = parent_->RemoveJob(this);
|
| }
|
|
|
| -void CertNetFetcherImpl::Job::StartURLRequest(URLRequestContext* context) {
|
| +void Job::StartURLRequest(URLRequestContext* context) {
|
| Error error = CanFetchUrl(request_params_->url);
|
| if (error != OK) {
|
| - // The CertNetFetcher's API contract is that requests always complete
|
| - // asynchronously. Use the timer class so the task is easily cancelled.
|
| + // TODO(eroman): Don't post a task for this case.
|
| timer_.Start(
|
| FROM_HERE, base::TimeDelta(),
|
| base::Bind(&Job::OnJobCompleted, base::Unretained(this), error));
|
| @@ -302,10 +432,9 @@ void CertNetFetcherImpl::Job::StartURLRequest(URLRequestContext* context) {
|
| base::Bind(&Job::FailRequest, base::Unretained(this), ERR_TIMED_OUT));
|
| }
|
|
|
| -void CertNetFetcherImpl::Job::OnReceivedRedirect(
|
| - URLRequest* request,
|
| - const RedirectInfo& redirect_info,
|
| - bool* defer_redirect) {
|
| +void Job::OnReceivedRedirect(URLRequest* request,
|
| + const RedirectInfo& redirect_info,
|
| + bool* defer_redirect) {
|
| DCHECK_EQ(url_request_.get(), request);
|
|
|
| // Ensure that the new URL matches the policy.
|
| @@ -316,8 +445,7 @@ void CertNetFetcherImpl::Job::OnReceivedRedirect(
|
| }
|
| }
|
|
|
| -void CertNetFetcherImpl::Job::OnResponseStarted(URLRequest* request,
|
| - int net_error) {
|
| +void Job::OnResponseStarted(URLRequest* request, int net_error) {
|
| DCHECK_EQ(url_request_.get(), request);
|
| DCHECK_NE(ERR_IO_PENDING, net_error);
|
|
|
| @@ -335,8 +463,7 @@ void CertNetFetcherImpl::Job::OnResponseStarted(URLRequest* request,
|
| ReadBody(request);
|
| }
|
|
|
| -void CertNetFetcherImpl::Job::OnReadCompleted(URLRequest* request,
|
| - int bytes_read) {
|
| +void Job::OnReadCompleted(URLRequest* request, int bytes_read) {
|
| DCHECK_EQ(url_request_.get(), request);
|
| DCHECK_NE(ERR_IO_PENDING, bytes_read);
|
|
|
| @@ -345,12 +472,12 @@ void CertNetFetcherImpl::Job::OnReadCompleted(URLRequest* request,
|
| ReadBody(request);
|
| }
|
|
|
| -void CertNetFetcherImpl::Job::Stop() {
|
| +void Job::Stop() {
|
| timer_.Stop();
|
| url_request_.reset();
|
| }
|
|
|
| -void CertNetFetcherImpl::Job::ReadBody(URLRequest* request) {
|
| +void Job::ReadBody(URLRequest* request) {
|
| // Read as many bytes as are available synchronously.
|
| int num_bytes = 0;
|
| while (num_bytes >= 0) {
|
| @@ -364,8 +491,7 @@ void CertNetFetcherImpl::Job::ReadBody(URLRequest* request) {
|
| OnUrlRequestCompleted(num_bytes);
|
| }
|
|
|
| -bool CertNetFetcherImpl::Job::ConsumeBytesRead(URLRequest* request,
|
| - int num_bytes) {
|
| +bool Job::ConsumeBytesRead(URLRequest* request, int num_bytes) {
|
| DCHECK_NE(ERR_IO_PENDING, num_bytes);
|
| if (num_bytes <= 0) {
|
| // Error while reading, or EOF.
|
| @@ -386,111 +512,50 @@ bool CertNetFetcherImpl::Job::ConsumeBytesRead(URLRequest* request,
|
| return true;
|
| }
|
|
|
| -void CertNetFetcherImpl::Job::OnUrlRequestCompleted(int net_error) {
|
| +void Job::OnUrlRequestCompleted(int net_error) {
|
| DCHECK_NE(ERR_IO_PENDING, net_error);
|
| Error result = static_cast<Error>(net_error);
|
| OnJobCompleted(result);
|
| }
|
|
|
| -void CertNetFetcherImpl::Job::OnJobCompleted(Error error) {
|
| +void Job::OnJobCompleted(Error error) {
|
| DCHECK_NE(ERR_IO_PENDING, error);
|
| // Stop the timer and clear the URLRequest.
|
| Stop();
|
|
|
| - // Invoking the callbacks is subtle as state may be mutated while iterating
|
| - // through the callbacks:
|
| - //
|
| - // * The parent CertNetFetcherImpl may be deleted
|
| - // * Requests in this job may be cancelled
|
| -
|
| std::unique_ptr<Job> delete_this = parent_->RemoveJob(this);
|
| - parent_->SetCurrentlyCompletingJob(this);
|
|
|
| - while (!requests_.empty()) {
|
| - base::LinkNode<RequestImpl>* request = requests_.head();
|
| - request->RemoveFromList();
|
| - request->value()->OnJobCompleted(this, error, response_body_);
|
| + for (auto* request : requests_) {
|
| + request->OnJobCompleted(this, error, response_body_);
|
| }
|
|
|
| - if (parent_)
|
| - parent_->ClearCurrentlyCompletingJob(this);
|
| + requests_.clear();
|
| }
|
|
|
| -void CertNetFetcherImpl::Job::FailRequest(Error error) {
|
| +void Job::FailRequest(Error error) {
|
| DCHECK_NE(ERR_IO_PENDING, error);
|
| int result = url_request_->CancelWithError(error);
|
| OnUrlRequestCompleted(result);
|
| }
|
|
|
| -CertNetFetcherImpl::CertNetFetcherImpl(URLRequestContext* context)
|
| - : currently_completing_job_(nullptr), context_(context) {
|
| +AsyncCertNetFetcherImpl::AsyncCertNetFetcherImpl(URLRequestContext* context)
|
| + : context_(context) {
|
| + // Allow creation to happen from another thread.
|
| + thread_checker_.DetachFromThread();
|
| }
|
|
|
| -CertNetFetcherImpl::~CertNetFetcherImpl() {
|
| +AsyncCertNetFetcherImpl::~AsyncCertNetFetcherImpl() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| jobs_.clear();
|
| -
|
| - // The CertNetFetcherImpl was destroyed in a FetchCallback. Detach all
|
| - // remaining requests from the job so no further callbacks are called.
|
| - if (currently_completing_job_)
|
| - currently_completing_job_->Cancel();
|
| }
|
|
|
| -std::unique_ptr<CertNetFetcher::Request> CertNetFetcherImpl::FetchCaIssuers(
|
| - const GURL& url,
|
| - int timeout_milliseconds,
|
| - int max_response_bytes,
|
| - const FetchCallback& callback) {
|
| - std::unique_ptr<RequestParams> request_params(new RequestParams);
|
| -
|
| - request_params->url = url;
|
| - request_params->http_method = HTTP_METHOD_GET;
|
| - request_params->timeout = GetTimeout(timeout_milliseconds);
|
| - request_params->max_response_bytes =
|
| - GetMaxResponseBytes(max_response_bytes, kMaxResponseSizeInBytesForAia);
|
| -
|
| - return Fetch(std::move(request_params), callback);
|
| -}
|
| -
|
| -std::unique_ptr<CertNetFetcher::Request> CertNetFetcherImpl::FetchCrl(
|
| - const GURL& url,
|
| - int timeout_milliseconds,
|
| - int max_response_bytes,
|
| - const FetchCallback& callback) {
|
| - std::unique_ptr<RequestParams> request_params(new RequestParams);
|
| -
|
| - request_params->url = url;
|
| - request_params->http_method = HTTP_METHOD_GET;
|
| - request_params->timeout = GetTimeout(timeout_milliseconds);
|
| - request_params->max_response_bytes =
|
| - GetMaxResponseBytes(max_response_bytes, kMaxResponseSizeInBytesForCrl);
|
| -
|
| - return Fetch(std::move(request_params), callback);
|
| -}
|
| -
|
| -std::unique_ptr<CertNetFetcher::Request> CertNetFetcherImpl::FetchOcsp(
|
| - const GURL& url,
|
| - int timeout_milliseconds,
|
| - int max_response_bytes,
|
| - const FetchCallback& callback) {
|
| - std::unique_ptr<RequestParams> request_params(new RequestParams);
|
| -
|
| - request_params->url = url;
|
| - request_params->http_method = HTTP_METHOD_GET;
|
| - request_params->timeout = GetTimeout(timeout_milliseconds);
|
| - request_params->max_response_bytes =
|
| - GetMaxResponseBytes(max_response_bytes, kMaxResponseSizeInBytesForAia);
|
| -
|
| - return Fetch(std::move(request_params), callback);
|
| -}
|
| -
|
| -bool CertNetFetcherImpl::JobComparator::operator()(const Job* job1,
|
| - const Job* job2) const {
|
| +bool JobComparator::operator()(const Job* job1, const Job* job2) const {
|
| return job1->request_params() < job2->request_params();
|
| }
|
|
|
| -std::unique_ptr<CertNetFetcher::Request> CertNetFetcherImpl::Fetch(
|
| +void AsyncCertNetFetcherImpl::Fetch(
|
| std::unique_ptr<RequestParams> request_params,
|
| - const FetchCallback& callback) {
|
| + RequestCore* request) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| // If there is an in-progress job that matches the request parameters use it.
|
| @@ -503,18 +568,17 @@ std::unique_ptr<CertNetFetcher::Request> CertNetFetcherImpl::Fetch(
|
| job->StartURLRequest(context_);
|
| }
|
|
|
| - return job->CreateRequest(callback);
|
| + return job->AttachRequest(request);
|
| }
|
|
|
| -struct CertNetFetcherImpl::JobToRequestParamsComparator {
|
| - bool operator()(const CertNetFetcherImpl::JobSet::value_type& job,
|
| - const CertNetFetcherImpl::RequestParams& value) const {
|
| +struct JobToRequestParamsComparator {
|
| + bool operator()(const JobSet::value_type& job,
|
| + const RequestParams& value) const {
|
| return job.first->request_params() < value;
|
| }
|
| };
|
|
|
| -CertNetFetcherImpl::Job* CertNetFetcherImpl::FindJob(
|
| - const RequestParams& params) {
|
| +Job* AsyncCertNetFetcherImpl::FindJob(const RequestParams& params) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| // The JobSet is kept in sorted order so items can be found using binary
|
| @@ -526,8 +590,7 @@ CertNetFetcherImpl::Job* CertNetFetcherImpl::FindJob(
|
| return nullptr;
|
| }
|
|
|
| -std::unique_ptr<CertNetFetcherImpl::Job> CertNetFetcherImpl::RemoveJob(
|
| - Job* job) {
|
| +std::unique_ptr<Job> AsyncCertNetFetcherImpl::RemoveJob(Job* job) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| auto it = jobs_.find(job);
|
| CHECK(it != jobs_.end());
|
| @@ -536,19 +599,149 @@ std::unique_ptr<CertNetFetcherImpl::Job> CertNetFetcherImpl::RemoveJob(
|
| return owned_job;
|
| }
|
|
|
| -void CertNetFetcherImpl::SetCurrentlyCompletingJob(Job* job) {
|
| - DCHECK(!currently_completing_job_);
|
| - DCHECK(job);
|
| - currently_completing_job_ = job;
|
| -}
|
| +class CertNetFetcherRequestImpl : public CertNetFetcher::Request {
|
| + public:
|
| + explicit CertNetFetcherRequestImpl(scoped_refptr<RequestCore> core)
|
| + : core_(std::move(core)) {
|
| + DCHECK(core_);
|
| + }
|
|
|
| -void CertNetFetcherImpl::ClearCurrentlyCompletingJob(Job* job) {
|
| - DCHECK_EQ(currently_completing_job_, job);
|
| - currently_completing_job_ = nullptr;
|
| -}
|
| + void WaitForResult(Error* error, std::vector<uint8_t>* bytes) override {
|
| + // Should only be called a single time.
|
| + DCHECK(core_);
|
| + core_->WaitForResult(error, bytes);
|
| + core_ = nullptr;
|
| + }
|
| +
|
| + ~CertNetFetcherRequestImpl() override {
|
| + if (core_)
|
| + core_->Cancel();
|
| + }
|
| +
|
| + private:
|
| + scoped_refptr<RequestCore> core_;
|
| +};
|
| +
|
| +class CertNetFetcherCore
|
| + : public base::RefCountedThreadSafe<CertNetFetcherCore> {
|
| + public:
|
| + explicit CertNetFetcherCore(URLRequestContextGetter* context_getter)
|
| + : context_getter_(context_getter) {}
|
| +
|
| + void Abandon() {
|
| + GetNetworkTaskRunner()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&CertNetFetcherCore::DoAbandonOnNetworkThread, this));
|
| + }
|
| +
|
| + scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner() {
|
| + return context_getter_->GetNetworkTaskRunner();
|
| + }
|
| +
|
| + void DoFetchOnNetworkThread(std::unique_ptr<RequestParams> request_params,
|
| + scoped_refptr<RequestCore> request) {
|
| + DCHECK(GetNetworkTaskRunner()->RunsTasksOnCurrentThread());
|
| +
|
| + if (!impl_) {
|
| + impl_.reset(
|
| + new AsyncCertNetFetcherImpl(context_getter_->GetURLRequestContext()));
|
| + }
|
| +
|
| + // Don't need to retain a reference to |request| because consume is
|
| + // expected to keep it alive.
|
| + impl_->Fetch(std::move(request_params), request.get());
|
| + }
|
| +
|
| + private:
|
| + friend class base::RefCountedThreadSafe<CertNetFetcherCore>;
|
| +
|
| + void DoAbandonOnNetworkThread() {
|
| + DCHECK(GetNetworkTaskRunner()->RunsTasksOnCurrentThread());
|
| + impl_.reset();
|
| + }
|
| +
|
| + ~CertNetFetcherCore() { DCHECK(!impl_); }
|
| +
|
| + scoped_refptr<URLRequestContextGetter> context_getter_;
|
| +
|
| + std::unique_ptr<AsyncCertNetFetcherImpl> impl_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(CertNetFetcherCore);
|
| +};
|
| +
|
| +class CertNetFetcherImpl : public CertNetFetcher {
|
| + public:
|
| + explicit CertNetFetcherImpl(URLRequestContextGetter* context_getter)
|
| + : core_(new CertNetFetcherCore(context_getter)) {}
|
| +
|
| + ~CertNetFetcherImpl() override { core_->Abandon(); }
|
| +
|
| + std::unique_ptr<Request> FetchCaIssuers(const GURL& url,
|
| + int timeout_milliseconds,
|
| + int max_response_bytes) override {
|
| + std::unique_ptr<RequestParams> request_params(new RequestParams);
|
| +
|
| + request_params->url = url;
|
| + request_params->http_method = HTTP_METHOD_GET;
|
| + request_params->timeout = GetTimeout(timeout_milliseconds);
|
| + request_params->max_response_bytes =
|
| + GetMaxResponseBytes(max_response_bytes, kMaxResponseSizeInBytesForAia);
|
| +
|
| + return DoFetch(std::move(request_params));
|
| + }
|
| +
|
| + std::unique_ptr<Request> FetchCrl(const GURL& url,
|
| + int timeout_milliseconds,
|
| + int max_response_bytes) override {
|
| + std::unique_ptr<RequestParams> request_params(new RequestParams);
|
| +
|
| + request_params->url = url;
|
| + request_params->http_method = HTTP_METHOD_GET;
|
| + request_params->timeout = GetTimeout(timeout_milliseconds);
|
| + request_params->max_response_bytes =
|
| + GetMaxResponseBytes(max_response_bytes, kMaxResponseSizeInBytesForCrl);
|
| +
|
| + return DoFetch(std::move(request_params));
|
| + }
|
| +
|
| + WARN_UNUSED_RESULT std::unique_ptr<Request> FetchOcsp(
|
| + const GURL& url,
|
| + int timeout_milliseconds,
|
| + int max_response_bytes) override {
|
| + std::unique_ptr<RequestParams> request_params(new RequestParams);
|
| +
|
| + request_params->url = url;
|
| + request_params->http_method = HTTP_METHOD_GET;
|
| + request_params->timeout = GetTimeout(timeout_milliseconds);
|
| + request_params->max_response_bytes =
|
| + GetMaxResponseBytes(max_response_bytes, kMaxResponseSizeInBytesForAia);
|
| +
|
| + return DoFetch(std::move(request_params));
|
| + }
|
| +
|
| + private:
|
| + std::unique_ptr<Request> DoFetch(
|
| + std::unique_ptr<RequestParams> request_params) {
|
| + auto task_runner = core_->GetNetworkTaskRunner();
|
| + scoped_refptr<RequestCore> request_core = new RequestCore(task_runner);
|
| +
|
| + task_runner->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&CertNetFetcherCore::DoFetchOnNetworkThread, core_,
|
| + base::Passed(&request_params), request_core));
|
| +
|
| + return base::MakeUnique<CertNetFetcherRequestImpl>(std::move(request_core));
|
| + }
|
| +
|
| + private:
|
| + scoped_refptr<CertNetFetcherCore> core_;
|
| +};
|
| +
|
| +} // namespace
|
|
|
| -bool CertNetFetcherImpl::IsCurrentlyCompletingJob(Job* job) {
|
| - return job == currently_completing_job_;
|
| +std::unique_ptr<CertNetFetcher> CreateCertNetFetcher(
|
| + URLRequestContextGetter* context_getter) {
|
| + return base::MakeUnique<CertNetFetcherImpl>(context_getter);
|
| }
|
|
|
| } // namespace net
|
|
|