OLD | NEW |
1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. Use of this | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // source code is governed by a BSD-style license that can be found in the | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/proxy/proxy_script_fetcher.h" | 5 #include "net/proxy/proxy_script_fetcher.h" |
6 | 6 |
7 #include "base/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
8 #include "base/i18n/icu_string_conversions.h" | 8 #include "base/i18n/icu_string_conversions.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
11 #include "base/ref_counted.h" | 11 #include "base/ref_counted.h" |
12 #include "base/string_util.h" | 12 #include "base/string_util.h" |
13 #include "base/utf_string_conversions.h" | 13 #include "base/utf_string_conversions.h" |
(...skipping 24 matching lines...) Expand all Loading... |
38 "application/x-ns-proxy-autoconfig", | 38 "application/x-ns-proxy-autoconfig", |
39 "application/x-javascript-config", | 39 "application/x-javascript-config", |
40 }; | 40 }; |
41 for (size_t i = 0; i < arraysize(kSupportedPacMimeTypes); ++i) { | 41 for (size_t i = 0; i < arraysize(kSupportedPacMimeTypes); ++i) { |
42 if (LowerCaseEqualsASCII(mime_type, kSupportedPacMimeTypes[i])) | 42 if (LowerCaseEqualsASCII(mime_type, kSupportedPacMimeTypes[i])) |
43 return true; | 43 return true; |
44 } | 44 } |
45 return false; | 45 return false; |
46 } | 46 } |
47 | 47 |
48 // Convert |bytes| (which is encoded by |charset|) in place to UTF8. | 48 // Converts |bytes| (which is encoded by |charset|) to UTF16, saving the resul |
| 49 // to |*utf16|. |
49 // If |charset| is empty, then we don't know what it was and guess. | 50 // If |charset| is empty, then we don't know what it was and guess. |
50 void ConvertResponseToUTF8(const std::string& charset, std::string* bytes) { | 51 void ConvertResponseToUTF16(const std::string& charset, |
| 52 const std::string& bytes, |
| 53 string16* utf16) { |
51 const char* codepage; | 54 const char* codepage; |
52 | 55 |
53 if (charset.empty()) { | 56 if (charset.empty()) { |
54 // Assume ISO-8859-1 if no charset was specified. | 57 // Assume ISO-8859-1 if no charset was specified. |
55 codepage = base::kCodepageLatin1; | 58 codepage = base::kCodepageLatin1; |
56 } else { | 59 } else { |
57 // Otherwise trust the charset that was provided. | 60 // Otherwise trust the charset that was provided. |
58 codepage = charset.c_str(); | 61 codepage = charset.c_str(); |
59 } | 62 } |
60 | 63 |
61 // We will be generous in the conversion -- if any characters lie | 64 // We will be generous in the conversion -- if any characters lie |
62 // outside of |charset| (i.e. invalid), then substitute them with | 65 // outside of |charset| (i.e. invalid), then substitute them with |
63 // U+FFFD rather than failing. | 66 // U+FFFD rather than failing. |
64 std::wstring tmp_wide; | 67 base::CodepageToUTF16(bytes, codepage, |
65 base::CodepageToWide(*bytes, codepage, | 68 base::OnStringConversionError::SUBSTITUTE, |
66 base::OnStringConversionError::SUBSTITUTE, | 69 utf16); |
67 &tmp_wide); | |
68 // TODO(eroman): would be nice to have a CodepageToUTF8() function. | |
69 *bytes = WideToUTF8(tmp_wide); | |
70 } | 70 } |
71 | 71 |
72 } // namespace | 72 } // namespace |
73 | 73 |
74 class ProxyScriptFetcherImpl : public ProxyScriptFetcher, | 74 class ProxyScriptFetcherImpl : public ProxyScriptFetcher, |
75 public URLRequest::Delegate { | 75 public URLRequest::Delegate { |
76 public: | 76 public: |
77 // Creates a ProxyScriptFetcher that issues requests through | 77 // Creates a ProxyScriptFetcher that issues requests through |
78 // |url_request_context|. |url_request_context| must remain valid for the | 78 // |url_request_context|. |url_request_context| must remain valid for the |
79 // lifetime of ProxyScriptFetcherImpl. | 79 // lifetime of ProxyScriptFetcherImpl. |
80 explicit ProxyScriptFetcherImpl(URLRequestContext* url_request_context); | 80 explicit ProxyScriptFetcherImpl(URLRequestContext* url_request_context); |
81 | 81 |
82 virtual ~ProxyScriptFetcherImpl(); | 82 virtual ~ProxyScriptFetcherImpl(); |
83 | 83 |
84 // ProxyScriptFetcher methods: | 84 // ProxyScriptFetcher methods: |
85 | 85 |
86 virtual int Fetch(const GURL& url, std::string* bytes, | 86 virtual int Fetch(const GURL& url, string16* text, |
87 CompletionCallback* callback); | 87 CompletionCallback* callback); |
88 virtual void Cancel(); | 88 virtual void Cancel(); |
89 virtual URLRequestContext* GetRequestContext(); | 89 virtual URLRequestContext* GetRequestContext(); |
90 | 90 |
91 // URLRequest::Delegate methods: | 91 // URLRequest::Delegate methods: |
92 | 92 |
93 virtual void OnAuthRequired(URLRequest* request, | 93 virtual void OnAuthRequired(URLRequest* request, |
94 AuthChallengeInfo* auth_info); | 94 AuthChallengeInfo* auth_info); |
95 virtual void OnSSLCertificateError(URLRequest* request, int cert_error, | 95 virtual void OnSSLCertificateError(URLRequest* request, int cert_error, |
96 X509Certificate* cert); | 96 X509Certificate* cert); |
97 virtual void OnResponseStarted(URLRequest* request); | 97 virtual void OnResponseStarted(URLRequest* request); |
98 virtual void OnReadCompleted(URLRequest* request, int num_bytes); | 98 virtual void OnReadCompleted(URLRequest* request, int num_bytes); |
99 virtual void OnResponseCompleted(URLRequest* request); | 99 virtual void OnResponseCompleted(URLRequest* request); |
100 | 100 |
101 private: | 101 private: |
102 // Read more bytes from the response. | 102 // Read more bytes from the response. |
103 void ReadBody(URLRequest* request); | 103 void ReadBody(URLRequest* request); |
104 | 104 |
105 // Called once the request has completed to notify the caller of | 105 // Called once the request has completed to notify the caller of |
106 // |response_code_| and |response_bytes_|. | 106 // |response_code_| and |response_text_|. |
107 void FetchCompleted(); | 107 void FetchCompleted(); |
108 | 108 |
109 // Clear out the state for the current request. | 109 // Clear out the state for the current request. |
110 void ResetCurRequestState(); | 110 void ResetCurRequestState(); |
111 | 111 |
112 // Callback for time-out task of request with id |id|. | 112 // Callback for time-out task of request with id |id|. |
113 void OnTimeout(int id); | 113 void OnTimeout(int id); |
114 | 114 |
115 // Factory for creating the time-out task. This takes care of revoking | 115 // Factory for creating the time-out task. This takes care of revoking |
116 // outstanding tasks when |this| is deleted. | 116 // outstanding tasks when |this| is deleted. |
(...skipping 16 matching lines...) Expand all Loading... |
133 | 133 |
134 // Unique ID for the current request. | 134 // Unique ID for the current request. |
135 int cur_request_id_; | 135 int cur_request_id_; |
136 | 136 |
137 // Callback to invoke on completion of the fetch. | 137 // Callback to invoke on completion of the fetch. |
138 CompletionCallback* callback_; | 138 CompletionCallback* callback_; |
139 | 139 |
140 // Holds the error condition that was hit on the current request, or OK. | 140 // Holds the error condition that was hit on the current request, or OK. |
141 int result_code_; | 141 int result_code_; |
142 | 142 |
143 // Holds the bytes read so far. Will not exceed |max_response_bytes|. This | 143 // Holds the bytes read so far. Will not exceed |max_response_bytes|. |
144 // buffer is owned by the owner of |callback|. | 144 std::string bytes_read_so_far_; |
145 std::string* result_bytes_; | 145 |
| 146 // This buffer is owned by the owner of |callback|, and will be filled with |
| 147 // UTF16 response on completion. |
| 148 string16* result_text_; |
146 }; | 149 }; |
147 | 150 |
148 ProxyScriptFetcherImpl::ProxyScriptFetcherImpl( | 151 ProxyScriptFetcherImpl::ProxyScriptFetcherImpl( |
149 URLRequestContext* url_request_context) | 152 URLRequestContext* url_request_context) |
150 : ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), | 153 : ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), |
151 url_request_context_(url_request_context), | 154 url_request_context_(url_request_context), |
152 buf_(new net::IOBuffer(kBufSize)), | 155 buf_(new net::IOBuffer(kBufSize)), |
153 next_id_(0), | 156 next_id_(0), |
154 cur_request_(NULL), | 157 cur_request_(NULL), |
155 cur_request_id_(0), | 158 cur_request_id_(0), |
156 callback_(NULL), | 159 callback_(NULL), |
157 result_code_(OK), | 160 result_code_(OK), |
158 result_bytes_(NULL) { | 161 result_text_(NULL) { |
159 DCHECK(url_request_context); | 162 DCHECK(url_request_context); |
160 } | 163 } |
161 | 164 |
162 ProxyScriptFetcherImpl::~ProxyScriptFetcherImpl() { | 165 ProxyScriptFetcherImpl::~ProxyScriptFetcherImpl() { |
163 // The URLRequest's destructor will cancel the outstanding request, and | 166 // The URLRequest's destructor will cancel the outstanding request, and |
164 // ensure that the delegate (this) is not called again. | 167 // ensure that the delegate (this) is not called again. |
165 } | 168 } |
166 | 169 |
167 int ProxyScriptFetcherImpl::Fetch(const GURL& url, | 170 int ProxyScriptFetcherImpl::Fetch(const GURL& url, |
168 std::string* bytes, | 171 string16* text, |
169 CompletionCallback* callback) { | 172 CompletionCallback* callback) { |
170 // It is invalid to call Fetch() while a request is already in progress. | 173 // It is invalid to call Fetch() while a request is already in progress. |
171 DCHECK(!cur_request_.get()); | 174 DCHECK(!cur_request_.get()); |
172 | 175 |
173 DCHECK(callback); | 176 DCHECK(callback); |
174 DCHECK(bytes); | 177 DCHECK(text); |
175 | 178 |
176 cur_request_.reset(new URLRequest(url, this)); | 179 cur_request_.reset(new URLRequest(url, this)); |
177 cur_request_->set_context(url_request_context_); | 180 cur_request_->set_context(url_request_context_); |
178 cur_request_->set_method("GET"); | 181 cur_request_->set_method("GET"); |
179 | 182 |
180 // Make sure that the PAC script is downloaded using a direct connection, | 183 // Make sure that the PAC script is downloaded using a direct connection, |
181 // to avoid circular dependencies (fetching is a part of proxy resolution). | 184 // to avoid circular dependencies (fetching is a part of proxy resolution). |
182 // Also disable the use of the disk cache. The cache is disabled so that if | 185 // Also disable the use of the disk cache. The cache is disabled so that if |
183 // the user switches networks we don't potentially use the cached response | 186 // the user switches networks we don't potentially use the cached response |
184 // from old network when we should in fact be re-fetching on the new network. | 187 // from old network when we should in fact be re-fetching on the new network. |
185 cur_request_->set_load_flags(LOAD_BYPASS_PROXY | LOAD_DISABLE_CACHE); | 188 cur_request_->set_load_flags(LOAD_BYPASS_PROXY | LOAD_DISABLE_CACHE); |
186 | 189 |
187 // Save the caller's info for notification on completion. | 190 // Save the caller's info for notification on completion. |
188 callback_ = callback; | 191 callback_ = callback; |
189 result_bytes_ = bytes; | 192 result_text_ = text; |
190 result_bytes_->clear(); | 193 |
| 194 bytes_read_so_far_.clear(); |
191 | 195 |
192 // Post a task to timeout this request if it takes too long. | 196 // Post a task to timeout this request if it takes too long. |
193 cur_request_id_ = ++next_id_; | 197 cur_request_id_ = ++next_id_; |
194 MessageLoop::current()->PostDelayedTask(FROM_HERE, | 198 MessageLoop::current()->PostDelayedTask(FROM_HERE, |
195 task_factory_.NewRunnableMethod(&ProxyScriptFetcherImpl::OnTimeout, | 199 task_factory_.NewRunnableMethod(&ProxyScriptFetcherImpl::OnTimeout, |
196 cur_request_id_), | 200 cur_request_id_), |
197 static_cast<int>(max_duration_ms)); | 201 static_cast<int>(max_duration_ms)); |
198 | 202 |
199 // Start the request. | 203 // Start the request. |
200 cur_request_->Start(); | 204 cur_request_->Start(); |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
262 } | 266 } |
263 | 267 |
264 ReadBody(request); | 268 ReadBody(request); |
265 } | 269 } |
266 | 270 |
267 void ProxyScriptFetcherImpl::OnReadCompleted(URLRequest* request, | 271 void ProxyScriptFetcherImpl::OnReadCompleted(URLRequest* request, |
268 int num_bytes) { | 272 int num_bytes) { |
269 DCHECK(request == cur_request_.get()); | 273 DCHECK(request == cur_request_.get()); |
270 if (num_bytes > 0) { | 274 if (num_bytes > 0) { |
271 // Enforce maximum size bound. | 275 // Enforce maximum size bound. |
272 if (num_bytes + result_bytes_->size() > | 276 if (num_bytes + bytes_read_so_far_.size() > |
273 static_cast<size_t>(max_response_bytes)) { | 277 static_cast<size_t>(max_response_bytes)) { |
274 result_code_ = ERR_FILE_TOO_BIG; | 278 result_code_ = ERR_FILE_TOO_BIG; |
275 request->Cancel(); | 279 request->Cancel(); |
276 return; | 280 return; |
277 } | 281 } |
278 result_bytes_->append(buf_->data(), num_bytes); | 282 bytes_read_so_far_.append(buf_->data(), num_bytes); |
279 ReadBody(request); | 283 ReadBody(request); |
280 } else { // Error while reading, or EOF | 284 } else { // Error while reading, or EOF |
281 OnResponseCompleted(request); | 285 OnResponseCompleted(request); |
282 } | 286 } |
283 } | 287 } |
284 | 288 |
285 void ProxyScriptFetcherImpl::OnResponseCompleted(URLRequest* request) { | 289 void ProxyScriptFetcherImpl::OnResponseCompleted(URLRequest* request) { |
286 DCHECK(request == cur_request_.get()); | 290 DCHECK(request == cur_request_.get()); |
287 | 291 |
288 // Use |result_code_| as the request's error if we have already set it to | 292 // Use |result_code_| as the request's error if we have already set it to |
289 // something specific. | 293 // something specific. |
290 if (result_code_ == OK && !request->status().is_success()) | 294 if (result_code_ == OK && !request->status().is_success()) |
291 result_code_ = request->status().os_error(); | 295 result_code_ = request->status().os_error(); |
292 | 296 |
293 FetchCompleted(); | 297 FetchCompleted(); |
294 } | 298 } |
295 | 299 |
296 void ProxyScriptFetcherImpl::ReadBody(URLRequest* request) { | 300 void ProxyScriptFetcherImpl::ReadBody(URLRequest* request) { |
297 int num_bytes; | 301 int num_bytes; |
298 if (request->Read(buf_, kBufSize, &num_bytes)) { | 302 if (request->Read(buf_, kBufSize, &num_bytes)) { |
299 OnReadCompleted(request, num_bytes); | 303 OnReadCompleted(request, num_bytes); |
300 } else if (!request->status().is_io_pending()) { | 304 } else if (!request->status().is_io_pending()) { |
301 // Read failed synchronously. | 305 // Read failed synchronously. |
302 OnResponseCompleted(request); | 306 OnResponseCompleted(request); |
303 } | 307 } |
304 } | 308 } |
305 | 309 |
306 void ProxyScriptFetcherImpl::FetchCompleted() { | 310 void ProxyScriptFetcherImpl::FetchCompleted() { |
307 if (result_code_ == OK) { | 311 if (result_code_ == OK) { |
308 // The caller expects the response to be encoded as UTF8. | 312 // The caller expects the response to be encoded as UTF16. |
309 std::string charset; | 313 std::string charset; |
310 cur_request_->GetCharset(&charset); | 314 cur_request_->GetCharset(&charset); |
311 ConvertResponseToUTF8(charset, result_bytes_); | 315 ConvertResponseToUTF16(charset, bytes_read_so_far_, result_text_); |
312 } else { | 316 } else { |
313 // On error, the caller expects empty string for bytes. | 317 // On error, the caller expects empty string for bytes. |
314 result_bytes_->clear(); | 318 result_text_->clear(); |
315 } | 319 } |
316 | 320 |
317 int result_code = result_code_; | 321 int result_code = result_code_; |
318 CompletionCallback* callback = callback_; | 322 CompletionCallback* callback = callback_; |
319 | 323 |
320 ResetCurRequestState(); | 324 ResetCurRequestState(); |
321 | 325 |
322 callback->Run(result_code); | 326 callback->Run(result_code); |
323 } | 327 } |
324 | 328 |
325 void ProxyScriptFetcherImpl::ResetCurRequestState() { | 329 void ProxyScriptFetcherImpl::ResetCurRequestState() { |
326 cur_request_.reset(); | 330 cur_request_.reset(); |
327 cur_request_id_ = 0; | 331 cur_request_id_ = 0; |
328 callback_ = NULL; | 332 callback_ = NULL; |
329 result_code_ = OK; | 333 result_code_ = OK; |
330 result_bytes_ = NULL; | 334 result_text_ = NULL; |
331 } | 335 } |
332 | 336 |
333 void ProxyScriptFetcherImpl::OnTimeout(int id) { | 337 void ProxyScriptFetcherImpl::OnTimeout(int id) { |
334 // Timeout tasks may outlive the URLRequest they reference. Make sure it | 338 // Timeout tasks may outlive the URLRequest they reference. Make sure it |
335 // is still applicable. | 339 // is still applicable. |
336 if (cur_request_id_ != id) | 340 if (cur_request_id_ != id) |
337 return; | 341 return; |
338 | 342 |
339 DCHECK(cur_request_.get()); | 343 DCHECK(cur_request_.get()); |
340 result_code_ = ERR_TIMED_OUT; | 344 result_code_ = ERR_TIMED_OUT; |
(...skipping 15 matching lines...) Expand all Loading... |
356 } | 360 } |
357 | 361 |
358 // static | 362 // static |
359 size_t ProxyScriptFetcher::SetSizeConstraintForUnittest(size_t size_bytes) { | 363 size_t ProxyScriptFetcher::SetSizeConstraintForUnittest(size_t size_bytes) { |
360 size_t prev = max_response_bytes; | 364 size_t prev = max_response_bytes; |
361 max_response_bytes = size_bytes; | 365 max_response_bytes = size_bytes; |
362 return prev; | 366 return prev; |
363 } | 367 } |
364 | 368 |
365 } // namespace net | 369 } // namespace net |
OLD | NEW |