| 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 |