172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "net/proxy/proxy_script_fetcher_impl.h"
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/compiler_specific.h"
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/i18n/icu_string_conversions.h"
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h"
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/message_loop.h"
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/string_util.h"
12dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "net/base/data_url.h"
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/io_buffer.h"
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/load_flags.h"
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/net_errors.h"
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_response_headers.h"
17731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "net/url_request/url_request_context.h"
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// TODO(eroman):
20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen//   - Support auth-prompts (http://crbug.com/77366)
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace net {
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace {
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// The maximum size (in bytes) allowed for a PAC script. Responses exceeding
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// this will fail with ERR_FILE_TOO_BIG.
28731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickconst int kDefaultMaxResponseBytes = 1048576;  // 1 megabyte
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// The maximum duration (in milliseconds) allowed for fetching the PAC script.
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Responses exceeding this will fail with ERR_TIMED_OUT.
32731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickconst int kDefaultMaxDurationMs = 300000;  // 5 minutes
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Returns true if |mime_type| is one of the known PAC mime type.
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool IsPacMimeType(const std::string& mime_type) {
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  static const char * const kSupportedPacMimeTypes[] = {
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    "application/x-ns-proxy-autoconfig",
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    "application/x-javascript-config",
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  };
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (size_t i = 0; i < arraysize(kSupportedPacMimeTypes); ++i) {
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (LowerCaseEqualsASCII(mime_type, kSupportedPacMimeTypes[i]))
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return true;
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return false;
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Converts |bytes| (which is encoded by |charset|) to UTF16, saving the resul
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// to |*utf16|.
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// If |charset| is empty, then we don't know what it was and guess.
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ConvertResponseToUTF16(const std::string& charset,
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            const std::string& bytes,
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            string16* utf16) {
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const char* codepage;
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (charset.empty()) {
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Assume ISO-8859-1 if no charset was specified.
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    codepage = base::kCodepageLatin1;
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Otherwise trust the charset that was provided.
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    codepage = charset.c_str();
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // We will be generous in the conversion -- if any characters lie
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // outside of |charset| (i.e. invalid), then substitute them with
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // U+FFFD rather than failing.
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::CodepageToUTF16(bytes, codepage,
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        base::OnStringConversionError::SUBSTITUTE,
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        utf16);
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottProxyScriptFetcherImpl::ProxyScriptFetcherImpl(
74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    URLRequestContext* url_request_context)
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    : ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      url_request_context_(url_request_context),
7772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      buf_(new IOBuffer(kBufSize)),
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      next_id_(0),
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      cur_request_(NULL),
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      cur_request_id_(0),
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      callback_(NULL),
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      result_code_(OK),
83731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      result_text_(NULL),
84731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      max_response_bytes_(kDefaultMaxResponseBytes),
85731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      max_duration_(base::TimeDelta::FromMilliseconds(kDefaultMaxDurationMs)) {
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(url_request_context);
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottProxyScriptFetcherImpl::~ProxyScriptFetcherImpl() {
9072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // The URLRequest's destructor will cancel the outstanding request, and
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // ensure that the delegate (this) is not called again.
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
9472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbase::TimeDelta ProxyScriptFetcherImpl::SetTimeoutConstraint(
9572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::TimeDelta timeout) {
9672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  base::TimeDelta prev = max_duration_;
9772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  max_duration_ = timeout;
9872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return prev;
9972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
10072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
10172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsensize_t ProxyScriptFetcherImpl::SetSizeConstraint(size_t size_bytes) {
10272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  size_t prev = max_response_bytes_;
10372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  max_response_bytes_ = size_bytes;
10472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return prev;
10572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
10672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
10772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ProxyScriptFetcherImpl::OnResponseCompleted(URLRequest* request) {
10872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK_EQ(request, cur_request_.get());
10972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
11072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Use |result_code_| as the request's error if we have already set it to
11172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // something specific.
11272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (result_code_ == OK && !request->status().is_success())
11372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    result_code_ = request->status().os_error();
11472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
11572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  FetchCompleted();
11672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
11772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint ProxyScriptFetcherImpl::Fetch(const GURL& url,
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  string16* text,
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                  CompletionCallback* callback) {
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // It is invalid to call Fetch() while a request is already in progress.
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!cur_request_.get());
123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(callback);
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(text);
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
127dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Handle base-64 encoded data-urls that contain custom PAC scripts.
128dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (url.SchemeIs("data")) {
129dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    std::string mime_type;
130dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    std::string charset;
131dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    std::string data;
132dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (!DataURL::Parse(url, &mime_type, &charset, &data))
133dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      return ERR_FAILED;
134dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
135dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    ConvertResponseToUTF16(charset, data, text);
136dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return OK;
137dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
138dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
13972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  cur_request_.reset(new URLRequest(url, this));
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cur_request_->set_context(url_request_context_);
141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cur_request_->set_method("GET");
142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Make sure that the PAC script is downloaded using a direct connection,
144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // to avoid circular dependencies (fetching is a part of proxy resolution).
145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Also disable the use of the disk cache. The cache is disabled so that if
146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // the user switches networks we don't potentially use the cached response
147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // from old network when we should in fact be re-fetching on the new network.
148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cur_request_->set_load_flags(LOAD_BYPASS_PROXY | LOAD_DISABLE_CACHE);
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Save the caller's info for notification on completion.
151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  callback_ = callback;
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result_text_ = text;
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bytes_read_so_far_.clear();
155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Post a task to timeout this request if it takes too long.
157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cur_request_id_ = ++next_id_;
158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  MessageLoop::current()->PostDelayedTask(FROM_HERE,
159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      task_factory_.NewRunnableMethod(&ProxyScriptFetcherImpl::OnTimeout,
160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                      cur_request_id_),
161731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      static_cast<int>(max_duration_.InMilliseconds()));
162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Start the request.
164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cur_request_->Start();
165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return ERR_IO_PENDING;
166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid ProxyScriptFetcherImpl::Cancel() {
16972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // ResetCurRequestState will free the URLRequest, which will cause
170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // cancellation.
171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ResetCurRequestState();
172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottURLRequestContext* ProxyScriptFetcherImpl::GetRequestContext() {
175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return url_request_context_;
176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
17872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ProxyScriptFetcherImpl::OnAuthRequired(URLRequest* request,
179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                            AuthChallengeInfo* auth_info) {
180201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DCHECK_EQ(request, cur_request_.get());
181ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(eroman): http://crbug.com/77366
182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  LOG(WARNING) << "Auth required to fetch PAC script, aborting.";
183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  result_code_ = ERR_NOT_IMPLEMENTED;
184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  request->CancelAuth();
185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
18772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ProxyScriptFetcherImpl::OnSSLCertificateError(URLRequest* request,
188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                                   int cert_error,
189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                                   X509Certificate* cert) {
190201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DCHECK_EQ(request, cur_request_.get());
191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  LOG(WARNING) << "SSL certificate error when fetching PAC script, aborting.";
192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Certificate errors are in same space as net errors.
193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  result_code_ = cert_error;
194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  request->Cancel();
195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
19772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ProxyScriptFetcherImpl::OnResponseStarted(URLRequest* request) {
198201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DCHECK_EQ(request, cur_request_.get());
199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!request->status().is_success()) {
201c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    OnResponseCompleted(request);
202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Require HTTP responses to have a success status code.
206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (request->url().SchemeIs("http") || request->url().SchemeIs("https")) {
207c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // NOTE about status codes: We are like Firefox 3 in this respect.
208c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // {IE 7, Safari 3, Opera 9.5} do not care about the status code.
209c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (request->GetResponseCode() != 200) {
210731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      VLOG(1) << "Fetched PAC script had (bad) status line: "
211731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              << request->response_headers()->GetStatusLine();
212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      result_code_ = ERR_PAC_STATUS_NOT_OK;
213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      request->Cancel();
214c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return;
215c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // NOTE about mime types: We do not enforce mime types on PAC files.
218c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // This is for compatibility with {IE 7, Firefox 3, Opera 9.5}. We will
219c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // however log mismatches to help with debugging.
220c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    std::string mime_type;
221c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    cur_request_->GetMimeType(&mime_type);
222c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (!IsPacMimeType(mime_type)) {
223731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      VLOG(1) << "Fetched PAC script does not have a proper mime type: "
224731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              << mime_type;
225c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
226c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
227c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
228c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ReadBody(request);
229c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
230c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
23172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ProxyScriptFetcherImpl::OnReadCompleted(URLRequest* request,
232c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                             int num_bytes) {
233201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DCHECK_EQ(request, cur_request_.get());
234201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (ConsumeBytesRead(request, num_bytes)) {
235201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // Keep reading.
236c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    ReadBody(request);
237c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
238c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
239c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
24072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ProxyScriptFetcherImpl::ReadBody(URLRequest* request) {
241201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // Read as many bytes as are available synchronously.
242201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  while (true) {
243201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    int num_bytes;
244201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    if (!request->Read(buf_, kBufSize, &num_bytes)) {
245201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      // Check whether the read failed synchronously.
246201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      if (!request->status().is_io_pending())
247201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        OnResponseCompleted(request);
248201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      return;
249201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    }
250201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    if (!ConsumeBytesRead(request, num_bytes))
251201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      return;
252201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
253201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
254201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
25572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool ProxyScriptFetcherImpl::ConsumeBytesRead(URLRequest* request,
256201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                                              int num_bytes) {
257201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (num_bytes <= 0) {
258201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // Error while reading, or EOF.
259c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    OnResponseCompleted(request);
260201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return false;
261c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
262201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
263201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // Enforce maximum size bound.
264201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (num_bytes + bytes_read_so_far_.size() >
265201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      static_cast<size_t>(max_response_bytes_)) {
266201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    result_code_ = ERR_FILE_TOO_BIG;
267201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    request->Cancel();
268201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return false;
269201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
270201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
271201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  bytes_read_so_far_.append(buf_->data(), num_bytes);
272201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  return true;
273c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
274c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
275c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid ProxyScriptFetcherImpl::FetchCompleted() {
276c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (result_code_ == OK) {
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The caller expects the response to be encoded as UTF16.
278c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    std::string charset;
279c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    cur_request_->GetCharset(&charset);
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ConvertResponseToUTF16(charset, bytes_read_so_far_, result_text_);
281c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
282c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // On error, the caller expects empty string for bytes.
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result_text_->clear();
284c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
285c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
286c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int result_code = result_code_;
287c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CompletionCallback* callback = callback_;
288c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
289201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // Hold a reference to the URLRequestContext to prevent re-entrancy from
290201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // ~URLRequestContext.
291201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  scoped_refptr<URLRequestContext> context(cur_request_->context());
292c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ResetCurRequestState();
293c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
294c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  callback->Run(result_code);
295c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
296c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
297c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid ProxyScriptFetcherImpl::ResetCurRequestState() {
298c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cur_request_.reset();
299c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cur_request_id_ = 0;
300c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  callback_ = NULL;
301c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  result_code_ = OK;
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result_text_ = NULL;
303c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
304c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
305c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid ProxyScriptFetcherImpl::OnTimeout(int id) {
30672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Timeout tasks may outlive the URLRequest they reference. Make sure it
307c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // is still applicable.
308c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (cur_request_id_ != id)
309c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
310c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
311c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(cur_request_.get());
312c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  result_code_ = ERR_TIMED_OUT;
313c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cur_request_->Cancel();
314c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
315c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
316c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace net
317