1c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/proxy/single_threaded_proxy_resolver.h"
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/thread.h"
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/load_log.h"
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/net_errors.h"
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/proxy/proxy_info.h"
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace net {
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace {
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass PurgeMemoryTask : public base::RefCountedThreadSafe<PurgeMemoryTask> {
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public:
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  explicit PurgeMemoryTask(ProxyResolver* resolver) : resolver_(resolver) {}
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void PurgeMemory() { resolver_->PurgeMemory(); }
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private:
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  friend class base::RefCountedThreadSafe<PurgeMemoryTask>;
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ~PurgeMemoryTask() {}
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ProxyResolver* resolver_;
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// SingleThreadedProxyResolver::SetPacScriptTask ------------------------------
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Runs on the worker thread to call ProxyResolver::SetPacScript.
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass SingleThreadedProxyResolver::SetPacScriptTask
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    : public base::RefCountedThreadSafe<
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        SingleThreadedProxyResolver::SetPacScriptTask> {
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public:
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SetPacScriptTask(SingleThreadedProxyResolver* coordinator,
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                   const GURL& pac_url,
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                   const std::string& pac_bytes,
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                   CompletionCallback* callback)
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    : coordinator_(coordinator),
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      callback_(callback),
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      pac_bytes_(pac_bytes),
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      pac_url_(pac_url),
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      origin_loop_(MessageLoop::current()) {
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DCHECK(callback);
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Start the SetPacScript request on the worker thread.
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void Start() {
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    coordinator_->thread()->message_loop()->PostTask(
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        FROM_HERE, NewRunnableMethod(this, &SetPacScriptTask::DoRequest,
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        coordinator_->resolver_.get()));
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void Cancel() {
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Clear these to inform RequestComplete that it should not try to
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // access them.
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    coordinator_ = NULL;
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    callback_ = NULL;
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Returns true if Cancel() has been called.
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool was_cancelled() const { return callback_ == NULL; }
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private:
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  friend class base::RefCountedThreadSafe<
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        SingleThreadedProxyResolver::SetPacScriptTask>;
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ~SetPacScriptTask() {}
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Runs on the worker thread.
71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void DoRequest(ProxyResolver* resolver) {
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int rv = resolver->expects_pac_bytes() ?
73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        resolver->SetPacScriptByData(pac_bytes_, NULL) :
74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        resolver->SetPacScriptByUrl(pac_url_, NULL);
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DCHECK_NE(rv, ERR_IO_PENDING);
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    origin_loop_->PostTask(FROM_HERE,
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        NewRunnableMethod(this, &SetPacScriptTask::RequestComplete, rv));
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Runs the completion callback on the origin thread.
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void RequestComplete(int result_code) {
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // The task may have been cancelled after it was started.
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (!was_cancelled()) {
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      CompletionCallback* callback = callback_;
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      coordinator_->RemoveOutstandingSetPacScriptTask(this);
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      callback->Run(result_code);
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Must only be used on the "origin" thread.
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SingleThreadedProxyResolver* coordinator_;
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CompletionCallback* callback_;
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  std::string pac_bytes_;
95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  GURL pac_url_;
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Usable from within DoQuery on the worker thread.
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  MessageLoop* origin_loop_;
99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// SingleThreadedProxyResolver::Job -------------------------------------------
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass SingleThreadedProxyResolver::Job
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    : public base::RefCountedThreadSafe<SingleThreadedProxyResolver::Job> {
105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public:
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // |coordinator| -- the SingleThreadedProxyResolver that owns this job.
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // |url|         -- the URL of the query.
108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // |results|     -- the structure to fill with proxy resolve results.
109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Job(SingleThreadedProxyResolver* coordinator,
110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      const GURL& url,
111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      ProxyInfo* results,
112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      CompletionCallback* callback,
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      LoadLog* load_log)
114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    : coordinator_(coordinator),
115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      callback_(callback),
116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      results_(results),
117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      load_log_(load_log),
118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      url_(url),
119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      is_started_(false),
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      origin_loop_(MessageLoop::current()) {
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DCHECK(callback);
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Start the resolve proxy request on the worker thread.
125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void Start() {
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    is_started_ = true;
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    size_t load_log_bound = load_log_ ? load_log_->max_num_entries() : 0;
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    coordinator_->thread()->message_loop()->PostTask(
131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        FROM_HERE, NewRunnableMethod(this, &Job::DoQuery,
132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        coordinator_->resolver_.get(),
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        load_log_bound));
134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool is_started() const { return is_started_; }
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void Cancel() {
139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Clear these to inform QueryComplete that it should not try to
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // access them.
141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    coordinator_ = NULL;
142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    callback_ = NULL;
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    results_ = NULL;
144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Returns true if Cancel() has been called.
147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool was_cancelled() const { return callback_ == NULL; }
148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private:
150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  friend class base::RefCountedThreadSafe<SingleThreadedProxyResolver::Job>;
151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ~Job() {}
153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Runs on the worker thread.
155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void DoQuery(ProxyResolver* resolver, size_t load_log_bound) {
156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    LoadLog* worker_log = NULL;
157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (load_log_bound > 0) {
158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      worker_log = new LoadLog(load_log_bound);
159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      worker_log->AddRef();  // Balanced in QueryComplete.
160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int rv = resolver->GetProxyForURL(url_, &results_buf_, NULL, NULL,
163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                      worker_log);
164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DCHECK_NE(rv, ERR_IO_PENDING);
165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    origin_loop_->PostTask(FROM_HERE,
167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        NewRunnableMethod(this, &Job::QueryComplete, rv, worker_log));
168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Runs the completion callback on the origin thread.
171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void QueryComplete(int result_code, LoadLog* worker_log) {
172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Merge the load log that was generated on the worker thread, into the
173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // main log.
174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (worker_log) {
175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      if (load_log_)
176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        load_log_->Append(worker_log);
177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      worker_log->Release();
178c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // The Job may have been cancelled after it was started.
181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (!was_cancelled()) {
182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      if (result_code >= OK) {  // Note: unit-tests use values > 0.
183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        results_->Use(results_buf_);
184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      }
185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      callback_->Run(result_code);
186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // We check for cancellation once again, in case the callback deleted
188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // the owning ProxyService (whose destructor will in turn cancel us).
189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      if (!was_cancelled())
190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        coordinator_->RemoveFrontOfJobsQueueAndStartNext(this);
191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Must only be used on the "origin" thread.
195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SingleThreadedProxyResolver* coordinator_;
196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CompletionCallback* callback_;
197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ProxyInfo* results_;
198c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_refptr<LoadLog> load_log_;
199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  GURL url_;
200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool is_started_;
201c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Usable from within DoQuery on the worker thread.
203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ProxyInfo results_buf_;
204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  MessageLoop* origin_loop_;
205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
207c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// SingleThreadedProxyResolver ------------------------------------------------
208c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
209c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottSingleThreadedProxyResolver::SingleThreadedProxyResolver(
210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    ProxyResolver* resolver)
211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    : ProxyResolver(resolver->expects_pac_bytes()),
212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      resolver_(resolver) {
213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
214c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
215c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottSingleThreadedProxyResolver::~SingleThreadedProxyResolver() {
216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Cancel the inprogress job (if any), and free the rest.
217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (PendingJobsQueue::iterator it = pending_jobs_.begin();
218c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott       it != pending_jobs_.end();
219c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott       ++it) {
220c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    (*it)->Cancel();
221c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
222c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
223c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (outstanding_set_pac_script_task_)
224c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    outstanding_set_pac_script_task_->Cancel();
225c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
226c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Note that |thread_| is destroyed before |resolver_|. This is important
227c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // since |resolver_| could be running on |thread_|.
228c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
229c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
230c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SingleThreadedProxyResolver::GetProxyForURL(const GURL& url,
231c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                                ProxyInfo* results,
232c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                                CompletionCallback* callback,
233c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                                RequestHandle* request,
234c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                                LoadLog* load_log) {
235c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(callback);
236c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
237c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_refptr<Job> job = new Job(this, url, results, callback, load_log);
238c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pending_jobs_.push_back(job);
239c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ProcessPendingJobs();  // Jobs can never finish synchronously.
240c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
241c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Completion will be notified through |callback|, unless the caller cancels
242c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // the request using |request|.
243c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (request)
244c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    *request = reinterpret_cast<RequestHandle>(job.get());
245c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
246c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return ERR_IO_PENDING;
247c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
248c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
249c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// There are three states of the request we need to handle:
250c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// (1) Not started (just sitting in the queue).
251c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// (2) Executing Job::DoQuery in the worker thread.
252c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// (3) Waiting for Job::QueryComplete to be run on the origin thread.
253c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SingleThreadedProxyResolver::CancelRequest(RequestHandle req) {
254c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(req);
255c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
256c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Job* job = reinterpret_cast<Job*>(req);
257c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
258c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool is_active_job = job->is_started() && !pending_jobs_.empty() &&
259c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      pending_jobs_.front().get() == job;
260c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
261c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  job->Cancel();
262c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
263c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (is_active_job) {
264c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    RemoveFrontOfJobsQueueAndStartNext(job);
265c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
266c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
267c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
268c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Otherwise just delete the job from the queue.
269c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  PendingJobsQueue::iterator it = std::find(
270c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      pending_jobs_.begin(), pending_jobs_.end(), job);
271c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(it != pending_jobs_.end());
272c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pending_jobs_.erase(it);
273c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
274c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
275c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SingleThreadedProxyResolver::CancelSetPacScript() {
276c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(outstanding_set_pac_script_task_);
277c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  outstanding_set_pac_script_task_->Cancel();
278c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  outstanding_set_pac_script_task_ = NULL;
279c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
280c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
281c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SingleThreadedProxyResolver::PurgeMemory() {
282c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (thread_.get()) {
283c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    scoped_refptr<PurgeMemoryTask> helper(new PurgeMemoryTask(resolver_.get()));
284c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    thread_->message_loop()->PostTask(FROM_HERE,
285c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        NewRunnableMethod(helper.get(), &PurgeMemoryTask::PurgeMemory));
286c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
287c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
288c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
289c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SingleThreadedProxyResolver::SetPacScript(
290c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const GURL& pac_url,
291c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const std::string& pac_bytes,
292c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CompletionCallback* callback) {
293c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EnsureThreadStarted();
294c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!outstanding_set_pac_script_task_);
295c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
296c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SetPacScriptTask* task = new SetPacScriptTask(
297c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      this, pac_url, pac_bytes, callback);
298c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  outstanding_set_pac_script_task_ = task;
299c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  task->Start();
300c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return ERR_IO_PENDING;
301c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
302c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
303c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SingleThreadedProxyResolver::EnsureThreadStarted() {
304c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!thread_.get()) {
305c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    thread_.reset(new base::Thread("pac-thread"));
306c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    thread_->Start();
307c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
308c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
309c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
310c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SingleThreadedProxyResolver::ProcessPendingJobs() {
311c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (pending_jobs_.empty())
312c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
313c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
314c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Get the next job to process (FIFO).
315c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Job* job = pending_jobs_.front().get();
316c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (job->is_started())
317c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
318c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
319c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EnsureThreadStarted();
320c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  job->Start();
321c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
322c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
323c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SingleThreadedProxyResolver::RemoveFrontOfJobsQueueAndStartNext(
324c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    Job* expected_job) {
325c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(expected_job, pending_jobs_.front().get());
326c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pending_jobs_.pop_front();
327c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
328c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Start next work item.
329c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ProcessPendingJobs();
330c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
331c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
332c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SingleThreadedProxyResolver::RemoveOutstandingSetPacScriptTask(
333c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    SetPacScriptTask* task) {
334c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(outstanding_set_pac_script_task_.get(), task);
335c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  outstanding_set_pac_script_task_ = NULL;
336c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
337c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
338c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace net
339