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 |