| Index: net/proxy/single_threaded_proxy_resolver.cc
|
| ===================================================================
|
| --- net/proxy/single_threaded_proxy_resolver.cc (revision 22399)
|
| +++ net/proxy/single_threaded_proxy_resolver.cc (working copy)
|
| @@ -10,28 +10,77 @@
|
|
|
| namespace net {
|
|
|
| -// Runs on the worker thread to call ProxyResolver::SetPacScriptByUrl or
|
| -// ProxyResolver::SetPacScriptByData.
|
| -// TODO(eroman): the lifetime of this task is ill-defined; |resolver_| must
|
| -// be valid when the task eventually is run. Make this task cancellable.
|
| -class SetPacScriptTask : public Task {
|
| +// SingleThreadedProxyResolver::SetPacScriptTask ------------------------------
|
| +
|
| +// Runs on the worker thread to call ProxyResolver::SetPacScript.
|
| +class SingleThreadedProxyResolver::SetPacScriptTask
|
| + : public base::RefCountedThreadSafe<
|
| + SingleThreadedProxyResolver::SetPacScriptTask> {
|
| public:
|
| - SetPacScriptTask(ProxyResolver* resolver,
|
| + SetPacScriptTask(SingleThreadedProxyResolver* coordinator,
|
| const GURL& pac_url,
|
| - const std::string& bytes)
|
| - : resolver_(resolver), pac_url_(pac_url), bytes_(bytes) {}
|
| + const std::string& pac_bytes,
|
| + CompletionCallback* callback)
|
| + : coordinator_(coordinator),
|
| + callback_(callback),
|
| + pac_bytes_(pac_bytes),
|
| + pac_url_(pac_url),
|
| + origin_loop_(MessageLoop::current()) {
|
| + DCHECK(callback);
|
| + }
|
|
|
| - virtual void Run() {
|
| - if (resolver_->expects_pac_bytes())
|
| - resolver_->SetPacScriptByData(bytes_);
|
| - else
|
| - resolver_->SetPacScriptByUrl(pac_url_);
|
| + // Start the SetPacScript request on the worker thread.
|
| + void Start() {
|
| + // TODO(eroman): Are these manual AddRef / Release necessary?
|
| + AddRef(); // balanced in RequestComplete
|
| +
|
| + 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:
|
| - ProxyResolver* resolver_;
|
| + // Runs on the worker thread.
|
| + void DoRequest(ProxyResolver* resolver) {
|
| + int rv = resolver->expects_pac_bytes() ?
|
| + resolver->SetPacScriptByData(pac_bytes_, 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);
|
| + }
|
| +
|
| + Release(); // Balances the AddRef in Start.
|
| + }
|
| +
|
| + // Must only be used on the "origin" thread.
|
| + SingleThreadedProxyResolver* coordinator_;
|
| + CompletionCallback* callback_;
|
| + std::string pac_bytes_;
|
| GURL pac_url_;
|
| - std::string bytes_;
|
| +
|
| + // Usable from within DoQuery on the worker thread.
|
| + MessageLoop* origin_loop_;
|
| };
|
|
|
| // SingleThreadedProxyResolver::Job -------------------------------------------
|
| @@ -102,7 +151,7 @@
|
| coordinator_->RemoveFrontOfJobsQueueAndStartNext(this);
|
| }
|
|
|
| - Release(); // balances the AddRef in Query. we may get deleted after
|
| + Release(); // Balances the AddRef in Start. We may get deleted after
|
| // we return.
|
| }
|
|
|
| @@ -134,6 +183,9 @@
|
| (*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_|.
|
| }
|
| @@ -182,21 +234,24 @@
|
| pending_jobs_.erase(it);
|
| }
|
|
|
| -void SingleThreadedProxyResolver::SetPacScriptByUrlInternal(
|
| - const GURL& pac_url) {
|
| - SetPacScriptHelper(pac_url, std::string());
|
| +void SingleThreadedProxyResolver::CancelSetPacScript() {
|
| + DCHECK(outstanding_set_pac_script_task_);
|
| + outstanding_set_pac_script_task_->Cancel();
|
| + outstanding_set_pac_script_task_ = NULL;
|
| }
|
|
|
| -void SingleThreadedProxyResolver::SetPacScriptByDataInternal(
|
| - const std::string& bytes) {
|
| - SetPacScriptHelper(GURL(), bytes);
|
| -}
|
| +int SingleThreadedProxyResolver::SetPacScript(
|
| + const GURL& pac_url,
|
| + const std::string& pac_bytes,
|
| + CompletionCallback* callback) {
|
| + EnsureThreadStarted();
|
| + DCHECK(!outstanding_set_pac_script_task_);
|
|
|
| -void SingleThreadedProxyResolver::SetPacScriptHelper(const GURL& pac_url,
|
| - const std::string& bytes) {
|
| - EnsureThreadStarted();
|
| - thread()->message_loop()->PostTask(
|
| - FROM_HERE, new SetPacScriptTask(resolver(), pac_url, bytes));
|
| + SetPacScriptTask* task = new SetPacScriptTask(
|
| + this, pac_url, pac_bytes, callback);
|
| + outstanding_set_pac_script_task_ = task;
|
| + task->Start();
|
| + return ERR_IO_PENDING;
|
| }
|
|
|
| void SingleThreadedProxyResolver::EnsureThreadStarted() {
|
| @@ -228,4 +283,10 @@
|
| ProcessPendingJobs();
|
| }
|
|
|
| +void SingleThreadedProxyResolver::RemoveOutstandingSetPacScriptTask(
|
| + SetPacScriptTask* task) {
|
| + DCHECK_EQ(outstanding_set_pac_script_task_.get(), task);
|
| + outstanding_set_pac_script_task_ = NULL;
|
| +}
|
| +
|
| } // namespace net
|
|
|