| Index: net/proxy/single_threaded_proxy_resolver.cc
|
| ===================================================================
|
| --- net/proxy/single_threaded_proxy_resolver.cc (revision 51914)
|
| +++ net/proxy/single_threaded_proxy_resolver.cc (working copy)
|
| @@ -1,353 +0,0 @@
|
| -// Copyright (c) 2010 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 "net/proxy/single_threaded_proxy_resolver.h"
|
| -
|
| -#include "base/message_loop.h"
|
| -#include "base/thread.h"
|
| -#include "net/base/capturing_net_log.h"
|
| -#include "net/base/net_errors.h"
|
| -#include "net/proxy/proxy_info.h"
|
| -
|
| -namespace net {
|
| -
|
| -namespace {
|
| -
|
| -class PurgeMemoryTask : public base::RefCountedThreadSafe<PurgeMemoryTask> {
|
| - public:
|
| - explicit PurgeMemoryTask(ProxyResolver* resolver) : resolver_(resolver) {}
|
| - void PurgeMemory() { resolver_->PurgeMemory(); }
|
| - private:
|
| - friend class base::RefCountedThreadSafe<PurgeMemoryTask>;
|
| - ~PurgeMemoryTask() {}
|
| - ProxyResolver* resolver_;
|
| -};
|
| -
|
| -} // namespace
|
| -
|
| -// SingleThreadedProxyResolver::SetPacScriptTask ------------------------------
|
| -
|
| -// Runs on the worker thread to call ProxyResolver::SetPacScript.
|
| -class SingleThreadedProxyResolver::SetPacScriptTask
|
| - : public base::RefCountedThreadSafe<
|
| - SingleThreadedProxyResolver::SetPacScriptTask> {
|
| - public:
|
| - SetPacScriptTask(SingleThreadedProxyResolver* coordinator,
|
| - const GURL& pac_url,
|
| - const string16& pac_script,
|
| - CompletionCallback* callback)
|
| - : coordinator_(coordinator),
|
| - callback_(callback),
|
| - pac_script_(pac_script),
|
| - pac_url_(pac_url),
|
| - origin_loop_(MessageLoop::current()) {
|
| - DCHECK(callback);
|
| - }
|
| -
|
| - // Start the SetPacScript request on the worker thread.
|
| - void Start() {
|
| - coordinator_->thread()->message_loop()->PostTask(
|
| - FROM_HERE, NewRunnableMethod(this, &SetPacScriptTask::DoRequest,
|
| - coordinator_->resolver_.get()));
|
| - }
|
| -
|
| - void Cancel() {
|
| - // Clear these to inform RequestComplete that it should not try to
|
| - // access them.
|
| - coordinator_ = NULL;
|
| - callback_ = NULL;
|
| - }
|
| -
|
| - // Returns true if Cancel() has been called.
|
| - bool was_cancelled() const { return callback_ == NULL; }
|
| -
|
| - private:
|
| - friend class base::RefCountedThreadSafe<
|
| - SingleThreadedProxyResolver::SetPacScriptTask>;
|
| -
|
| - ~SetPacScriptTask() {}
|
| -
|
| - // Runs on the worker thread.
|
| - void DoRequest(ProxyResolver* resolver) {
|
| - int rv = resolver->expects_pac_bytes() ?
|
| - resolver->SetPacScriptByData(pac_script_, NULL) :
|
| - resolver->SetPacScriptByUrl(pac_url_, NULL);
|
| -
|
| - DCHECK_NE(rv, ERR_IO_PENDING);
|
| - origin_loop_->PostTask(FROM_HERE,
|
| - NewRunnableMethod(this, &SetPacScriptTask::RequestComplete, rv));
|
| - }
|
| -
|
| - // Runs the completion callback on the origin thread.
|
| - void RequestComplete(int result_code) {
|
| - // The task may have been cancelled after it was started.
|
| - if (!was_cancelled()) {
|
| - CompletionCallback* callback = callback_;
|
| - coordinator_->RemoveOutstandingSetPacScriptTask(this);
|
| - callback->Run(result_code);
|
| - }
|
| - }
|
| -
|
| - // Must only be used on the "origin" thread.
|
| - SingleThreadedProxyResolver* coordinator_;
|
| - CompletionCallback* callback_;
|
| - string16 pac_script_;
|
| - GURL pac_url_;
|
| -
|
| - // Usable from within DoQuery on the worker thread.
|
| - MessageLoop* origin_loop_;
|
| -};
|
| -
|
| -// SingleThreadedProxyResolver::Job -------------------------------------------
|
| -
|
| -class SingleThreadedProxyResolver::Job
|
| - : public base::RefCountedThreadSafe<SingleThreadedProxyResolver::Job> {
|
| - public:
|
| - // |coordinator| -- the SingleThreadedProxyResolver that owns this job.
|
| - // |url| -- the URL of the query.
|
| - // |results| -- the structure to fill with proxy resolve results.
|
| - Job(SingleThreadedProxyResolver* coordinator,
|
| - const GURL& url,
|
| - ProxyInfo* results,
|
| - CompletionCallback* callback,
|
| - const BoundNetLog& net_log)
|
| - : coordinator_(coordinator),
|
| - callback_(callback),
|
| - results_(results),
|
| - net_log_(net_log),
|
| - url_(url),
|
| - is_started_(false),
|
| - origin_loop_(MessageLoop::current()) {
|
| - DCHECK(callback);
|
| - }
|
| -
|
| - // Start the resolve proxy request on the worker thread.
|
| - void Start() {
|
| - is_started_ = true;
|
| -
|
| - size_t load_log_bound = 100;
|
| -
|
| - coordinator_->thread()->message_loop()->PostTask(
|
| - FROM_HERE, NewRunnableMethod(this, &Job::DoQuery,
|
| - coordinator_->resolver_.get(),
|
| - load_log_bound));
|
| - }
|
| -
|
| - bool is_started() const { return is_started_; }
|
| -
|
| - void Cancel() {
|
| - // Clear these to inform QueryComplete that it should not try to
|
| - // access them.
|
| - coordinator_ = NULL;
|
| - callback_ = NULL;
|
| - results_ = NULL;
|
| - }
|
| -
|
| - // Returns true if Cancel() has been called.
|
| - bool was_cancelled() const { return callback_ == NULL; }
|
| -
|
| - BoundNetLog* net_log() { return &net_log_; }
|
| -
|
| - private:
|
| - friend class base::RefCountedThreadSafe<SingleThreadedProxyResolver::Job>;
|
| -
|
| - ~Job() {}
|
| -
|
| - // Runs on the worker thread.
|
| - void DoQuery(ProxyResolver* resolver, size_t load_log_bound) {
|
| - worker_log_.reset(new CapturingNetLog(load_log_bound));
|
| - BoundNetLog bound_worker_log(NetLog::Source(), worker_log_.get());
|
| -
|
| - int rv = resolver->GetProxyForURL(url_, &results_buf_, NULL, NULL,
|
| - bound_worker_log);
|
| - DCHECK_NE(rv, ERR_IO_PENDING);
|
| -
|
| - origin_loop_->PostTask(FROM_HERE,
|
| - NewRunnableMethod(this, &Job::QueryComplete, rv));
|
| - }
|
| -
|
| - // Runs the completion callback on the origin thread.
|
| - void QueryComplete(int result_code) {
|
| - // Merge the load log that was generated on the worker thread, into the
|
| - // main log.
|
| - CapturingBoundNetLog bound_worker_log(NetLog::Source(),
|
| - worker_log_.release());
|
| - bound_worker_log.AppendTo(net_log_);
|
| -
|
| - // The Job may have been cancelled after it was started.
|
| - if (!was_cancelled()) {
|
| - if (result_code >= OK) { // Note: unit-tests use values > 0.
|
| - results_->Use(results_buf_);
|
| - }
|
| - callback_->Run(result_code);
|
| -
|
| - // We check for cancellation once again, in case the callback deleted
|
| - // the owning ProxyService (whose destructor will in turn cancel us).
|
| - if (!was_cancelled())
|
| - coordinator_->RemoveFrontOfJobsQueueAndStartNext(this);
|
| - }
|
| - }
|
| -
|
| - // Must only be used on the "origin" thread.
|
| - SingleThreadedProxyResolver* coordinator_;
|
| - CompletionCallback* callback_;
|
| - ProxyInfo* results_;
|
| - BoundNetLog net_log_;
|
| - GURL url_;
|
| - bool is_started_;
|
| -
|
| - // Usable from within DoQuery on the worker thread.
|
| - ProxyInfo results_buf_;
|
| - MessageLoop* origin_loop_;
|
| -
|
| - // Used to pass the captured events between DoQuery [worker thread] and
|
| - // QueryComplete [origin thread].
|
| - scoped_ptr<CapturingNetLog> worker_log_;
|
| -};
|
| -
|
| -// SingleThreadedProxyResolver ------------------------------------------------
|
| -
|
| -SingleThreadedProxyResolver::SingleThreadedProxyResolver(
|
| - ProxyResolver* resolver)
|
| - : ProxyResolver(resolver->expects_pac_bytes()),
|
| - resolver_(resolver) {
|
| -}
|
| -
|
| -SingleThreadedProxyResolver::~SingleThreadedProxyResolver() {
|
| - // Cancel the inprogress job (if any), and free the rest.
|
| - for (PendingJobsQueue::iterator it = pending_jobs_.begin();
|
| - it != pending_jobs_.end();
|
| - ++it) {
|
| - (*it)->Cancel();
|
| - }
|
| -
|
| - if (outstanding_set_pac_script_task_)
|
| - outstanding_set_pac_script_task_->Cancel();
|
| -
|
| - // Note that |thread_| is destroyed before |resolver_|. This is important
|
| - // since |resolver_| could be running on |thread_|.
|
| -}
|
| -
|
| -int SingleThreadedProxyResolver::GetProxyForURL(const GURL& url,
|
| - ProxyInfo* results,
|
| - CompletionCallback* callback,
|
| - RequestHandle* request,
|
| - const BoundNetLog& net_log) {
|
| - DCHECK(callback);
|
| -
|
| - scoped_refptr<Job> job = new Job(this, url, results, callback, net_log);
|
| - bool is_first_job = pending_jobs_.empty();
|
| - pending_jobs_.push_back(job); // Jobs can never finish synchronously.
|
| -
|
| - if (is_first_job) {
|
| - // If there is nothing already running, start the job now.
|
| - EnsureThreadStarted();
|
| - job->Start();
|
| - } else {
|
| - // Otherwise the job will get started eventually by ProcessPendingJobs().
|
| - job->net_log()->BeginEvent(
|
| - NetLog::TYPE_WAITING_FOR_SINGLE_PROXY_RESOLVER_THREAD, NULL);
|
| - }
|
| -
|
| - // Completion will be notified through |callback|, unless the caller cancels
|
| - // the request using |request|.
|
| - if (request)
|
| - *request = reinterpret_cast<RequestHandle>(job.get());
|
| -
|
| - return ERR_IO_PENDING;
|
| -}
|
| -
|
| -// There are three states of the request we need to handle:
|
| -// (1) Not started (just sitting in the queue).
|
| -// (2) Executing Job::DoQuery in the worker thread.
|
| -// (3) Waiting for Job::QueryComplete to be run on the origin thread.
|
| -void SingleThreadedProxyResolver::CancelRequest(RequestHandle req) {
|
| - DCHECK(req);
|
| -
|
| - Job* job = reinterpret_cast<Job*>(req);
|
| -
|
| - bool is_active_job = job->is_started() && !pending_jobs_.empty() &&
|
| - pending_jobs_.front().get() == job;
|
| -
|
| - job->Cancel();
|
| -
|
| - if (is_active_job) {
|
| - RemoveFrontOfJobsQueueAndStartNext(job);
|
| - return;
|
| - }
|
| -
|
| - // Otherwise just delete the job from the queue.
|
| - PendingJobsQueue::iterator it = std::find(
|
| - pending_jobs_.begin(), pending_jobs_.end(), job);
|
| - DCHECK(it != pending_jobs_.end());
|
| - pending_jobs_.erase(it);
|
| -}
|
| -
|
| -void SingleThreadedProxyResolver::CancelSetPacScript() {
|
| - DCHECK(outstanding_set_pac_script_task_);
|
| - outstanding_set_pac_script_task_->Cancel();
|
| - outstanding_set_pac_script_task_ = NULL;
|
| -}
|
| -
|
| -void SingleThreadedProxyResolver::PurgeMemory() {
|
| - if (thread_.get()) {
|
| - scoped_refptr<PurgeMemoryTask> helper(new PurgeMemoryTask(resolver_.get()));
|
| - thread_->message_loop()->PostTask(FROM_HERE,
|
| - NewRunnableMethod(helper.get(), &PurgeMemoryTask::PurgeMemory));
|
| - }
|
| -}
|
| -
|
| -int SingleThreadedProxyResolver::SetPacScript(
|
| - const GURL& pac_url,
|
| - const string16& pac_script,
|
| - CompletionCallback* callback) {
|
| - EnsureThreadStarted();
|
| - DCHECK(!outstanding_set_pac_script_task_);
|
| -
|
| - SetPacScriptTask* task = new SetPacScriptTask(
|
| - this, pac_url, pac_script, callback);
|
| - outstanding_set_pac_script_task_ = task;
|
| - task->Start();
|
| - return ERR_IO_PENDING;
|
| -}
|
| -
|
| -void SingleThreadedProxyResolver::EnsureThreadStarted() {
|
| - if (!thread_.get()) {
|
| - thread_.reset(new base::Thread("pac-thread"));
|
| - thread_->Start();
|
| - }
|
| -}
|
| -
|
| -void SingleThreadedProxyResolver::ProcessPendingJobs() {
|
| - if (pending_jobs_.empty())
|
| - return;
|
| -
|
| - // Get the next job to process (FIFO).
|
| - Job* job = pending_jobs_.front().get();
|
| - if (job->is_started())
|
| - return;
|
| -
|
| - job->net_log()->EndEvent(
|
| - NetLog::TYPE_WAITING_FOR_SINGLE_PROXY_RESOLVER_THREAD, NULL);
|
| -
|
| - EnsureThreadStarted();
|
| - job->Start();
|
| -}
|
| -
|
| -void SingleThreadedProxyResolver::RemoveFrontOfJobsQueueAndStartNext(
|
| - Job* expected_job) {
|
| - DCHECK_EQ(expected_job, pending_jobs_.front().get());
|
| - pending_jobs_.pop_front();
|
| -
|
| - // Start next work item.
|
| - ProcessPendingJobs();
|
| -}
|
| -
|
| -void SingleThreadedProxyResolver::RemoveOutstandingSetPacScriptTask(
|
| - SetPacScriptTask* task) {
|
| - DCHECK_EQ(outstanding_set_pac_script_task_.get(), task);
|
| - outstanding_set_pac_script_task_ = NULL;
|
| -}
|
| -
|
| -} // namespace net
|
|
|