Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(47)

Side by Side Diff: net/proxy/proxy_script_fetcher.cc

Issue 13251: Add a ProxyScriptFetcher class for doing asynch downloads of PAC scripts.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 12 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/proxy/proxy_script_fetcher.h ('k') | net/proxy/proxy_script_fetcher_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. Use of this
2 // source code is governed by a BSD-style license that can be found in the
3 // LICENSE file.
4
5 #include "net/proxy/proxy_script_fetcher.h"
6
7 #include "base/compiler_specific.h"
8 #include "base/message_loop.h"
9 #include "base/string_util.h"
10 #include "net/base/load_flags.h"
11 #include "net/url_request/url_request.h"
12
13 // TODO(eroman):
14 // - Support auth-prompts.
15
16 namespace net {
17
18 namespace {
19
20 // The maximum size (in bytes) allowed for a PAC script. Responses exceeding
21 // this will fail with ERR_FILE_TOO_BIG.
22 int max_response_bytes = 1048576; // 1 megabyte
23
24 // The maximum duration (in milliseconds) allowed for fetching the PAC script.
25 // Responses exceeding this will fail with ERR_TIMED_OUT.
26 int max_duration_ms = 300000; // 5 minutes
27
28 } // namespace
29
30 class ProxyScriptFetcherImpl : public ProxyScriptFetcher,
31 public URLRequest::Delegate {
32 public:
33 // Creates a ProxyScriptFetcher that issues requests through
34 // |url_request_context|. |url_request_context| must remain valid for the
35 // lifetime of ProxyScriptFetcherImpl.
36 explicit ProxyScriptFetcherImpl(URLRequestContext* url_request_context);
37
38 virtual ~ProxyScriptFetcherImpl();
39
40 // ProxyScriptFetcher methods:
41
42 virtual void Fetch(const GURL& url, std::string* bytes,
43 CompletionCallback* callback);
44 virtual void Cancel();
45
46 // URLRequest::Delegate methods:
47
48 virtual void OnAuthRequired(URLRequest* request,
49 AuthChallengeInfo* auth_info);
50 virtual void OnSSLCertificateError(URLRequest* request, int cert_error,
51 X509Certificate* cert);
52 virtual void OnReceivedRedirect(URLRequest* request, const GURL& to_url);
53 virtual void OnResponseStarted(URLRequest* request);
54 virtual void OnReadCompleted(URLRequest* request, int num_bytes);
55 virtual void OnResponseCompleted(URLRequest* request);
56
57 private:
58 // Read more bytes from the response.
59 void ReadBody(URLRequest* request);
60
61 // Called once the request has completed to notify the caller of
62 // |response_code_| and |response_bytes_|.
63 void FetchCompleted();
64
65 // Clear out the state for the current request.
66 void ResetCurRequestState();
67
68 // Callback for time-out task of request with id |id|.
69 void OnTimeout(int id);
70
71 // Factory for creating the time-out task. This takes care of revoking
72 // outstanding tasks when |this| is deleted.
73 ScopedRunnableMethodFactory<ProxyScriptFetcherImpl> task_factory_;
74
75 // The context used for making network requests.
76 URLRequestContext* url_request_context_;
77
78 // Buffer that URLRequest writes into.
79 enum { kBufSize = 4096 };
80 char buf_[kBufSize];
81
82 // The next ID to use for |cur_request_| (monotonically increasing).
83 int next_id_;
84
85 // The current (in progress) request, or NULL.
86 scoped_ptr<URLRequest> cur_request_;
87
88 // State for current request (only valid when |cur_request_| is not NULL):
89
90 // Unique ID for the current request.
91 int cur_request_id_;
92
93 // Callback to invoke on completion of the fetch.
94 CompletionCallback* callback_;
95
96 // Holds the error condition that was hit on the current request, or OK.
97 int result_code_;
98
99 // Holds the bytes read so far. Will not exceed |max_response_bytes|. This
100 // buffer is owned by the owner of |callback|.
101 std::string* result_bytes_;
102 };
103
104 ProxyScriptFetcherImpl::ProxyScriptFetcherImpl(
105 URLRequestContext* url_request_context)
106 : ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
107 url_request_context_(url_request_context),
108 next_id_(0),
109 cur_request_(NULL),
110 cur_request_id_(0),
111 callback_(NULL),
112 result_code_(OK),
113 result_bytes_(NULL) {
114 DCHECK(url_request_context);
115 }
116
117 ProxyScriptFetcherImpl::~ProxyScriptFetcherImpl() {
118 // The URLRequest's destructor will cancel the outstanding request, and
119 // ensure that the delegate (this) is not called again.
120 }
121
122 void ProxyScriptFetcherImpl::Fetch(const GURL& url,
123 std::string* bytes,
124 CompletionCallback* callback) {
125 // It is invalid to call Fetch() while a request is already in progress.
126 DCHECK(!cur_request_.get());
127
128 DCHECK(callback);
129 DCHECK(bytes);
130
131 cur_request_.reset(new URLRequest(url, this));
132 cur_request_->set_context(url_request_context_);
133 cur_request_->set_method("GET");
134
135 // Make sure that the PAC script is downloaded using a direct connection,
136 // to avoid circular dependencies (fetching is a part of proxy resolution).
137 cur_request_->set_load_flags(LOAD_BYPASS_PROXY);
138
139 // Save the caller's info for notification on completion.
140 callback_ = callback;
141 result_bytes_ = bytes;
142 result_bytes_->clear();
143
144 // Post a task to timeout this request if it takes too long.
145 cur_request_id_ = ++next_id_;
146 MessageLoop::current()->PostDelayedTask(FROM_HERE,
147 task_factory_.NewRunnableMethod(&ProxyScriptFetcherImpl::OnTimeout,
148 cur_request_id_),
149 static_cast<int>(max_duration_ms));
150
151 // Start the request.
152 cur_request_->Start();
153 }
154
155 void ProxyScriptFetcherImpl::Cancel() {
156 // ResetCurRequestState will free the URLRequest, which will cause
157 // cancellation.
158 ResetCurRequestState();
159 }
160
161 void ProxyScriptFetcherImpl::OnAuthRequired(URLRequest* request,
162 AuthChallengeInfo* auth_info) {
163 DCHECK(request == cur_request_.get());
164 // TODO(eroman):
165 result_code_ = ERR_NOT_IMPLEMENTED;
166 request->CancelAuth();
167 }
168
169 void ProxyScriptFetcherImpl::OnSSLCertificateError(URLRequest* request,
170 int cert_error,
171 X509Certificate* cert) {
172 DCHECK(request == cur_request_.get());
173 // Certificate errors are in same space as net errors.
174 result_code_ = cert_error;
175 request->Cancel();
176 }
177
178 void ProxyScriptFetcherImpl::OnReceivedRedirect(URLRequest* request,
179 const GURL& to_url) {
180 DCHECK(request == cur_request_.get());
181 // OK, thanks for telling.
182 }
183
184 void ProxyScriptFetcherImpl::OnResponseStarted(URLRequest* request) {
185 DCHECK(request == cur_request_.get());
186
187 if (!request->status().is_success()) {
188 OnResponseCompleted(request);
189 return;
190 }
191
192 // Require HTTP responses to have a success status code.
193 if (request->url().SchemeIs("http") || request->url().SchemeIs("https")) {
194 // NOTE about mime types: We do not enforce mime types on PAC files.
195 // This is for compatibility with {IE 7, Firefox 3, Opera 9.5}
196
197 // NOTE about status codes: We are like Firefox 3 in this respect.
198 // {IE 7, Safari 3, Opera 9.5} do not care about the status code.
199 if (request->GetResponseCode() != 200) {
200 result_code_ = ERR_PAC_STATUS_NOT_OK;
201 request->Cancel();
202 return;
203 }
204 }
205
206 ReadBody(request);
207 }
208
209 void ProxyScriptFetcherImpl::OnReadCompleted(URLRequest* request,
210 int num_bytes) {
211 DCHECK(request == cur_request_.get());
212 if (num_bytes > 0) {
213 // Enforce maximum size bound.
214 if (num_bytes + result_bytes_->size() >
215 static_cast<size_t>(max_response_bytes)) {
216 result_code_ = ERR_FILE_TOO_BIG;
217 request->Cancel();
218 return;
219 }
220 result_bytes_->append(buf_, num_bytes);
221 ReadBody(request);
222 } else { // Error while reading, or EOF
223 OnResponseCompleted(request);
224 }
225 }
226
227 void ProxyScriptFetcherImpl::OnResponseCompleted(URLRequest* request) {
228 DCHECK(request == cur_request_.get());
229
230 // Use |result_code_| as the request's error if we have already set it to
231 // something specific.
232 if (result_code_ == OK && !request->status().is_success())
233 result_code_ = request->status().os_error();
234
235 FetchCompleted();
236 }
237
238 void ProxyScriptFetcherImpl::ReadBody(URLRequest* request) {
239 int num_bytes;
240 if (request->Read(buf_, kBufSize, &num_bytes)) {
241 OnReadCompleted(request, num_bytes);
242 } else if (!request->status().is_io_pending()) {
243 // Read failed synchronously.
244 OnResponseCompleted(request);
245 }
246 }
247
248 void ProxyScriptFetcherImpl::FetchCompleted() {
249 // On error, the caller expects empty string for bytes.
250 if (result_code_ != OK)
251 result_bytes_->clear();
252
253 int result_code = result_code_;
254 CompletionCallback* callback = callback_;
255
256 ResetCurRequestState();
257
258 callback->Run(result_code);
259 }
260
261 void ProxyScriptFetcherImpl::ResetCurRequestState() {
262 cur_request_.reset();
263 cur_request_id_ = 0;
264 callback_ = NULL;
265 result_code_ = OK;
266 result_bytes_ = NULL;
267 }
268
269 void ProxyScriptFetcherImpl::OnTimeout(int id) {
270 // Timeout tasks may outlive the URLRequest they reference. Make sure it
271 // is still applicable.
272 if (cur_request_id_ != id)
273 return;
274
275 DCHECK(cur_request_.get());
276 result_code_ = ERR_TIMED_OUT;
277 cur_request_->Cancel();
278 }
279
280 // static
281 ProxyScriptFetcher* ProxyScriptFetcher::Create(
282 URLRequestContext* url_request_context) {
283 return new ProxyScriptFetcherImpl(url_request_context);
284 }
285
286 // static
287 int ProxyScriptFetcher::SetTimeoutConstraintForUnittest(
288 int timeout_ms) {
289 int prev = max_duration_ms;
290 max_duration_ms = timeout_ms;
291 return prev;
292 }
293
294 // static
295 size_t ProxyScriptFetcher::SetSizeConstraintForUnittest(size_t size_bytes) {
296 size_t prev = max_response_bytes;
297 max_response_bytes = size_bytes;
298 return prev;
299 }
300
301 } // namespace net
OLDNEW
« no previous file with comments | « net/proxy/proxy_script_fetcher.h ('k') | net/proxy/proxy_script_fetcher_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698