Home | History | Annotate | Download | only in url_request
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "net/url_request/url_fetcher_core.h"
      6 
      7 #include <stdint.h>
      8 
      9 #include "base/bind.h"
     10 #include "base/logging.h"
     11 #include "base/metrics/histogram.h"
     12 #include "base/sequenced_task_runner.h"
     13 #include "base/single_thread_task_runner.h"
     14 #include "base/stl_util.h"
     15 #include "base/thread_task_runner_handle.h"
     16 #include "base/tracked_objects.h"
     17 #include "net/base/io_buffer.h"
     18 #include "net/base/load_flags.h"
     19 #include "net/base/net_errors.h"
     20 #include "net/base/request_priority.h"
     21 #include "net/base/upload_bytes_element_reader.h"
     22 #include "net/base/upload_data_stream.h"
     23 #include "net/base/upload_file_element_reader.h"
     24 #include "net/http/http_response_headers.h"
     25 #include "net/url_request/redirect_info.h"
     26 #include "net/url_request/url_fetcher_delegate.h"
     27 #include "net/url_request/url_fetcher_response_writer.h"
     28 #include "net/url_request/url_request_context.h"
     29 #include "net/url_request/url_request_context_getter.h"
     30 #include "net/url_request/url_request_throttler_manager.h"
     31 
     32 namespace {
     33 
     34 const int kBufferSize = 4096;
     35 const int kUploadProgressTimerInterval = 100;
     36 bool g_interception_enabled = false;
     37 bool g_ignore_certificate_requests = false;
     38 
     39 void EmptyCompletionCallback(int result) {}
     40 
     41 }  // namespace
     42 
     43 namespace net {
     44 
     45 // URLFetcherCore::Registry ---------------------------------------------------
     46 
     47 URLFetcherCore::Registry::Registry() {}
     48 URLFetcherCore::Registry::~Registry() {}
     49 
     50 void URLFetcherCore::Registry::AddURLFetcherCore(URLFetcherCore* core) {
     51   DCHECK(!ContainsKey(fetchers_, core));
     52   fetchers_.insert(core);
     53 }
     54 
     55 void URLFetcherCore::Registry::RemoveURLFetcherCore(URLFetcherCore* core) {
     56   DCHECK(ContainsKey(fetchers_, core));
     57   fetchers_.erase(core);
     58 }
     59 
     60 void URLFetcherCore::Registry::CancelAll() {
     61   while (!fetchers_.empty())
     62     (*fetchers_.begin())->CancelURLRequest(ERR_ABORTED);
     63 }
     64 
     65 // URLFetcherCore -------------------------------------------------------------
     66 
     67 // static
     68 base::LazyInstance<URLFetcherCore::Registry>
     69     URLFetcherCore::g_registry = LAZY_INSTANCE_INITIALIZER;
     70 
     71 URLFetcherCore::URLFetcherCore(URLFetcher* fetcher,
     72                                const GURL& original_url,
     73                                URLFetcher::RequestType request_type,
     74                                URLFetcherDelegate* d)
     75     : fetcher_(fetcher),
     76       original_url_(original_url),
     77       request_type_(request_type),
     78       delegate_(d),
     79       delegate_task_runner_(base::ThreadTaskRunnerHandle::Get()),
     80       load_flags_(LOAD_NORMAL),
     81       response_code_(URLFetcher::RESPONSE_CODE_INVALID),
     82       buffer_(new IOBuffer(kBufferSize)),
     83       url_request_data_key_(NULL),
     84       was_fetched_via_proxy_(false),
     85       upload_content_set_(false),
     86       upload_range_offset_(0),
     87       upload_range_length_(0),
     88       referrer_policy_(
     89           URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE),
     90       is_chunked_upload_(false),
     91       was_cancelled_(false),
     92       stop_on_redirect_(false),
     93       stopped_on_redirect_(false),
     94       automatically_retry_on_5xx_(true),
     95       num_retries_on_5xx_(0),
     96       max_retries_on_5xx_(0),
     97       num_retries_on_network_changes_(0),
     98       max_retries_on_network_changes_(0),
     99       current_upload_bytes_(-1),
    100       current_response_bytes_(0),
    101       total_response_bytes_(-1) {
    102   CHECK(original_url_.is_valid());
    103 }
    104 
    105 void URLFetcherCore::Start() {
    106   DCHECK(delegate_task_runner_.get());
    107   DCHECK(request_context_getter_.get()) << "We need an URLRequestContext!";
    108   if (network_task_runner_.get()) {
    109     DCHECK_EQ(network_task_runner_,
    110               request_context_getter_->GetNetworkTaskRunner());
    111   } else {
    112     network_task_runner_ = request_context_getter_->GetNetworkTaskRunner();
    113   }
    114   DCHECK(network_task_runner_.get()) << "We need an IO task runner";
    115 
    116   network_task_runner_->PostTask(
    117       FROM_HERE, base::Bind(&URLFetcherCore::StartOnIOThread, this));
    118 }
    119 
    120 void URLFetcherCore::Stop() {
    121   if (delegate_task_runner_.get())  // May be NULL in tests.
    122     DCHECK(delegate_task_runner_->BelongsToCurrentThread());
    123 
    124   delegate_ = NULL;
    125   fetcher_ = NULL;
    126   if (!network_task_runner_.get())
    127     return;
    128   if (network_task_runner_->RunsTasksOnCurrentThread()) {
    129     CancelURLRequest(ERR_ABORTED);
    130   } else {
    131     network_task_runner_->PostTask(
    132         FROM_HERE,
    133         base::Bind(&URLFetcherCore::CancelURLRequest, this, ERR_ABORTED));
    134   }
    135 }
    136 
    137 void URLFetcherCore::SetUploadData(const std::string& upload_content_type,
    138                                    const std::string& upload_content) {
    139   DCHECK(!is_chunked_upload_);
    140   DCHECK(!upload_content_set_);
    141   DCHECK(upload_content_.empty());
    142   DCHECK(upload_file_path_.empty());
    143   DCHECK(upload_content_type_.empty());
    144 
    145   // Empty |upload_content_type| is allowed iff the |upload_content| is empty.
    146   DCHECK(upload_content.empty() || !upload_content_type.empty());
    147 
    148   upload_content_type_ = upload_content_type;
    149   upload_content_ = upload_content;
    150   upload_content_set_ = true;
    151 }
    152 
    153 void URLFetcherCore::SetUploadFilePath(
    154     const std::string& upload_content_type,
    155     const base::FilePath& file_path,
    156     uint64 range_offset,
    157     uint64 range_length,
    158     scoped_refptr<base::TaskRunner> file_task_runner) {
    159   DCHECK(!is_chunked_upload_);
    160   DCHECK(!upload_content_set_);
    161   DCHECK(upload_content_.empty());
    162   DCHECK(upload_file_path_.empty());
    163   DCHECK_EQ(upload_range_offset_, 0ULL);
    164   DCHECK_EQ(upload_range_length_, 0ULL);
    165   DCHECK(upload_content_type_.empty());
    166   DCHECK(!upload_content_type.empty());
    167 
    168   upload_content_type_ = upload_content_type;
    169   upload_file_path_ = file_path;
    170   upload_range_offset_ = range_offset;
    171   upload_range_length_ = range_length;
    172   upload_file_task_runner_ = file_task_runner;
    173   upload_content_set_ = true;
    174 }
    175 
    176 void URLFetcherCore::SetChunkedUpload(const std::string& content_type) {
    177   DCHECK(is_chunked_upload_ ||
    178          (upload_content_type_.empty() &&
    179           upload_content_.empty()));
    180 
    181   // Empty |content_type| is not allowed here, because it is impossible
    182   // to ensure non-empty upload content as it is not yet supplied.
    183   DCHECK(!content_type.empty());
    184 
    185   upload_content_type_ = content_type;
    186   upload_content_.clear();
    187   is_chunked_upload_ = true;
    188 }
    189 
    190 void URLFetcherCore::AppendChunkToUpload(const std::string& content,
    191                                          bool is_last_chunk) {
    192   DCHECK(delegate_task_runner_.get());
    193   DCHECK(network_task_runner_.get());
    194   network_task_runner_->PostTask(
    195       FROM_HERE,
    196       base::Bind(&URLFetcherCore::CompleteAddingUploadDataChunk, this, content,
    197                  is_last_chunk));
    198 }
    199 
    200 void URLFetcherCore::SetLoadFlags(int load_flags) {
    201   load_flags_ = load_flags;
    202 }
    203 
    204 int URLFetcherCore::GetLoadFlags() const {
    205   return load_flags_;
    206 }
    207 
    208 void URLFetcherCore::SetReferrer(const std::string& referrer) {
    209   referrer_ = referrer;
    210 }
    211 
    212 void URLFetcherCore::SetReferrerPolicy(
    213     URLRequest::ReferrerPolicy referrer_policy) {
    214   referrer_policy_ = referrer_policy;
    215 }
    216 
    217 void URLFetcherCore::SetExtraRequestHeaders(
    218     const std::string& extra_request_headers) {
    219   extra_request_headers_.Clear();
    220   extra_request_headers_.AddHeadersFromString(extra_request_headers);
    221 }
    222 
    223 void URLFetcherCore::AddExtraRequestHeader(const std::string& header_line) {
    224   extra_request_headers_.AddHeaderFromString(header_line);
    225 }
    226 
    227 void URLFetcherCore::SetRequestContext(
    228     URLRequestContextGetter* request_context_getter) {
    229   DCHECK(!request_context_getter_.get());
    230   DCHECK(request_context_getter);
    231   request_context_getter_ = request_context_getter;
    232 }
    233 
    234 void URLFetcherCore::SetFirstPartyForCookies(
    235     const GURL& first_party_for_cookies) {
    236   DCHECK(first_party_for_cookies_.is_empty());
    237   first_party_for_cookies_ = first_party_for_cookies;
    238 }
    239 
    240 void URLFetcherCore::SetURLRequestUserData(
    241     const void* key,
    242     const URLFetcher::CreateDataCallback& create_data_callback) {
    243   DCHECK(key);
    244   DCHECK(!create_data_callback.is_null());
    245   url_request_data_key_ = key;
    246   url_request_create_data_callback_ = create_data_callback;
    247 }
    248 
    249 void URLFetcherCore::SetStopOnRedirect(bool stop_on_redirect) {
    250   stop_on_redirect_ = stop_on_redirect;
    251 }
    252 
    253 void URLFetcherCore::SetAutomaticallyRetryOn5xx(bool retry) {
    254   automatically_retry_on_5xx_ = retry;
    255 }
    256 
    257 void URLFetcherCore::SetMaxRetriesOn5xx(int max_retries) {
    258   max_retries_on_5xx_ = max_retries;
    259 }
    260 
    261 int URLFetcherCore::GetMaxRetriesOn5xx() const {
    262   return max_retries_on_5xx_;
    263 }
    264 
    265 base::TimeDelta URLFetcherCore::GetBackoffDelay() const {
    266   return backoff_delay_;
    267 }
    268 
    269 void URLFetcherCore::SetAutomaticallyRetryOnNetworkChanges(int max_retries) {
    270   max_retries_on_network_changes_ = max_retries;
    271 }
    272 
    273 void URLFetcherCore::SaveResponseToFileAtPath(
    274     const base::FilePath& file_path,
    275     scoped_refptr<base::SequencedTaskRunner> file_task_runner) {
    276   DCHECK(delegate_task_runner_->BelongsToCurrentThread());
    277   SaveResponseWithWriter(scoped_ptr<URLFetcherResponseWriter>(
    278       new URLFetcherFileWriter(file_task_runner, file_path)));
    279 }
    280 
    281 void URLFetcherCore::SaveResponseToTemporaryFile(
    282     scoped_refptr<base::SequencedTaskRunner> file_task_runner) {
    283   DCHECK(delegate_task_runner_->BelongsToCurrentThread());
    284   SaveResponseWithWriter(scoped_ptr<URLFetcherResponseWriter>(
    285       new URLFetcherFileWriter(file_task_runner, base::FilePath())));
    286 }
    287 
    288 void URLFetcherCore::SaveResponseWithWriter(
    289     scoped_ptr<URLFetcherResponseWriter> response_writer) {
    290   DCHECK(delegate_task_runner_->BelongsToCurrentThread());
    291   response_writer_ = response_writer.Pass();
    292 }
    293 
    294 HttpResponseHeaders* URLFetcherCore::GetResponseHeaders() const {
    295   return response_headers_.get();
    296 }
    297 
    298 // TODO(panayiotis): socket_address_ is written in the IO thread,
    299 // if this is accessed in the UI thread, this could result in a race.
    300 // Same for response_headers_ above and was_fetched_via_proxy_ below.
    301 HostPortPair URLFetcherCore::GetSocketAddress() const {
    302   return socket_address_;
    303 }
    304 
    305 bool URLFetcherCore::WasFetchedViaProxy() const {
    306   return was_fetched_via_proxy_;
    307 }
    308 
    309 const GURL& URLFetcherCore::GetOriginalURL() const {
    310   return original_url_;
    311 }
    312 
    313 const GURL& URLFetcherCore::GetURL() const {
    314   return url_;
    315 }
    316 
    317 const URLRequestStatus& URLFetcherCore::GetStatus() const {
    318   return status_;
    319 }
    320 
    321 int URLFetcherCore::GetResponseCode() const {
    322   return response_code_;
    323 }
    324 
    325 const ResponseCookies& URLFetcherCore::GetCookies() const {
    326   return cookies_;
    327 }
    328 
    329 void URLFetcherCore::ReceivedContentWasMalformed() {
    330   DCHECK(delegate_task_runner_->BelongsToCurrentThread());
    331   if (network_task_runner_.get()) {
    332     network_task_runner_->PostTask(
    333         FROM_HERE, base::Bind(&URLFetcherCore::NotifyMalformedContent, this));
    334   }
    335 }
    336 
    337 bool URLFetcherCore::GetResponseAsString(
    338     std::string* out_response_string) const {
    339   URLFetcherStringWriter* string_writer =
    340       response_writer_ ? response_writer_->AsStringWriter() : NULL;
    341   if (!string_writer)
    342     return false;
    343 
    344   *out_response_string = string_writer->data();
    345   UMA_HISTOGRAM_MEMORY_KB("UrlFetcher.StringResponseSize",
    346                           (string_writer->data().length() / 1024));
    347   return true;
    348 }
    349 
    350 bool URLFetcherCore::GetResponseAsFilePath(bool take_ownership,
    351                                            base::FilePath* out_response_path) {
    352   DCHECK(delegate_task_runner_->BelongsToCurrentThread());
    353 
    354   URLFetcherFileWriter* file_writer =
    355       response_writer_ ? response_writer_->AsFileWriter() : NULL;
    356   if (!file_writer)
    357     return false;
    358 
    359   *out_response_path = file_writer->file_path();
    360 
    361   if (take_ownership) {
    362     // Intentionally calling a file_writer_ method directly without posting
    363     // the task to network_task_runner_.
    364     //
    365     // This is for correctly handling the case when file_writer_->DisownFile()
    366     // is soon followed by URLFetcherCore::Stop(). We have to make sure that
    367     // DisownFile takes effect before Stop deletes file_writer_.
    368     //
    369     // This direct call should be thread-safe, since DisownFile itself does no
    370     // file operation. It just flips the state to be referred in destruction.
    371     file_writer->DisownFile();
    372   }
    373   return true;
    374 }
    375 
    376 void URLFetcherCore::OnReceivedRedirect(URLRequest* request,
    377                                         const RedirectInfo& redirect_info,
    378                                         bool* defer_redirect) {
    379   DCHECK_EQ(request, request_.get());
    380   DCHECK(network_task_runner_->BelongsToCurrentThread());
    381   if (stop_on_redirect_) {
    382     stopped_on_redirect_ = true;
    383     url_ = redirect_info.new_url;
    384     response_code_ = request_->GetResponseCode();
    385     was_fetched_via_proxy_ = request_->was_fetched_via_proxy();
    386     request->Cancel();
    387     OnReadCompleted(request, 0);
    388   }
    389 }
    390 
    391 void URLFetcherCore::OnResponseStarted(URLRequest* request) {
    392   DCHECK_EQ(request, request_.get());
    393   DCHECK(network_task_runner_->BelongsToCurrentThread());
    394   if (request_->status().is_success()) {
    395     response_code_ = request_->GetResponseCode();
    396     response_headers_ = request_->response_headers();
    397     socket_address_ = request_->GetSocketAddress();
    398     was_fetched_via_proxy_ = request_->was_fetched_via_proxy();
    399     total_response_bytes_ = request_->GetExpectedContentSize();
    400   }
    401 
    402   ReadResponse();
    403 }
    404 
    405 void URLFetcherCore::OnCertificateRequested(
    406     URLRequest* request,
    407     SSLCertRequestInfo* cert_request_info) {
    408   DCHECK_EQ(request, request_.get());
    409   DCHECK(network_task_runner_->BelongsToCurrentThread());
    410 
    411   if (g_ignore_certificate_requests) {
    412     request->ContinueWithCertificate(NULL);
    413   } else {
    414     request->Cancel();
    415   }
    416 }
    417 
    418 void URLFetcherCore::OnReadCompleted(URLRequest* request,
    419                                      int bytes_read) {
    420   DCHECK(request == request_);
    421   DCHECK(network_task_runner_->BelongsToCurrentThread());
    422 
    423   if (!stopped_on_redirect_)
    424     url_ = request->url();
    425   URLRequestThrottlerManager* throttler_manager =
    426       request->context()->throttler_manager();
    427   if (throttler_manager) {
    428     url_throttler_entry_ = throttler_manager->RegisterRequestUrl(url_);
    429   }
    430 
    431   do {
    432     if (!request_->status().is_success() || bytes_read <= 0)
    433       break;
    434 
    435     current_response_bytes_ += bytes_read;
    436     InformDelegateDownloadProgress();
    437 
    438     const int result =
    439         WriteBuffer(new DrainableIOBuffer(buffer_.get(), bytes_read));
    440     if (result < 0) {
    441       // Write failed or waiting for write completion.
    442       return;
    443     }
    444   } while (request_->Read(buffer_.get(), kBufferSize, &bytes_read));
    445 
    446   const URLRequestStatus status = request_->status();
    447 
    448   if (status.is_success())
    449     request_->GetResponseCookies(&cookies_);
    450 
    451   // See comments re: HEAD requests in ReadResponse().
    452   if (!status.is_io_pending() || request_type_ == URLFetcher::HEAD) {
    453     status_ = status;
    454     ReleaseRequest();
    455 
    456     // No more data to write.
    457     const int result = response_writer_->Finish(
    458         base::Bind(&URLFetcherCore::DidFinishWriting, this));
    459     if (result != ERR_IO_PENDING)
    460       DidFinishWriting(result);
    461   }
    462 }
    463 
    464 void URLFetcherCore::CancelAll() {
    465   g_registry.Get().CancelAll();
    466 }
    467 
    468 int URLFetcherCore::GetNumFetcherCores() {
    469   return g_registry.Get().size();
    470 }
    471 
    472 void URLFetcherCore::SetEnableInterceptionForTests(bool enabled) {
    473   g_interception_enabled = enabled;
    474 }
    475 
    476 void URLFetcherCore::SetIgnoreCertificateRequests(bool ignored) {
    477   g_ignore_certificate_requests = ignored;
    478 }
    479 
    480 URLFetcherCore::~URLFetcherCore() {
    481   // |request_| should be NULL. If not, it's unsafe to delete it here since we
    482   // may not be on the IO thread.
    483   DCHECK(!request_.get());
    484 }
    485 
    486 void URLFetcherCore::StartOnIOThread() {
    487   DCHECK(network_task_runner_->BelongsToCurrentThread());
    488 
    489   if (!response_writer_)
    490     response_writer_.reset(new URLFetcherStringWriter);
    491 
    492   const int result = response_writer_->Initialize(
    493       base::Bind(&URLFetcherCore::DidInitializeWriter, this));
    494   if (result != ERR_IO_PENDING)
    495     DidInitializeWriter(result);
    496 }
    497 
    498 void URLFetcherCore::StartURLRequest() {
    499   DCHECK(network_task_runner_->BelongsToCurrentThread());
    500 
    501   if (was_cancelled_) {
    502     // Since StartURLRequest() is posted as a *delayed* task, it may
    503     // run after the URLFetcher was already stopped.
    504     return;
    505   }
    506 
    507   DCHECK(request_context_getter_.get());
    508   DCHECK(!request_.get());
    509 
    510   g_registry.Get().AddURLFetcherCore(this);
    511   current_response_bytes_ = 0;
    512   request_ = request_context_getter_->GetURLRequestContext()->CreateRequest(
    513       original_url_, DEFAULT_PRIORITY, this, NULL);
    514   request_->set_stack_trace(stack_trace_);
    515   int flags = request_->load_flags() | load_flags_;
    516   if (!g_interception_enabled)
    517     flags = flags | LOAD_DISABLE_INTERCEPT;
    518 
    519   if (is_chunked_upload_)
    520     request_->EnableChunkedUpload();
    521   request_->SetLoadFlags(flags);
    522   request_->SetReferrer(referrer_);
    523   request_->set_referrer_policy(referrer_policy_);
    524   request_->set_first_party_for_cookies(first_party_for_cookies_.is_empty() ?
    525       original_url_ : first_party_for_cookies_);
    526   if (url_request_data_key_ && !url_request_create_data_callback_.is_null()) {
    527     request_->SetUserData(url_request_data_key_,
    528                           url_request_create_data_callback_.Run());
    529   }
    530 
    531   switch (request_type_) {
    532     case URLFetcher::GET:
    533       break;
    534 
    535     case URLFetcher::POST:
    536     case URLFetcher::PUT:
    537     case URLFetcher::PATCH:
    538       // Upload content must be set.
    539       DCHECK(is_chunked_upload_ || upload_content_set_);
    540 
    541       request_->set_method(
    542           request_type_ == URLFetcher::POST ? "POST" :
    543           request_type_ == URLFetcher::PUT ? "PUT" : "PATCH");
    544       if (!upload_content_type_.empty()) {
    545         extra_request_headers_.SetHeader(HttpRequestHeaders::kContentType,
    546                                          upload_content_type_);
    547       }
    548       if (!upload_content_.empty()) {
    549         scoped_ptr<UploadElementReader> reader(new UploadBytesElementReader(
    550             upload_content_.data(), upload_content_.size()));
    551         request_->set_upload(make_scoped_ptr(
    552             UploadDataStream::CreateWithReader(reader.Pass(), 0)));
    553       } else if (!upload_file_path_.empty()) {
    554         scoped_ptr<UploadElementReader> reader(
    555             new UploadFileElementReader(upload_file_task_runner_.get(),
    556                                         upload_file_path_,
    557                                         upload_range_offset_,
    558                                         upload_range_length_,
    559                                         base::Time()));
    560         request_->set_upload(make_scoped_ptr(
    561             UploadDataStream::CreateWithReader(reader.Pass(), 0)));
    562       }
    563 
    564       current_upload_bytes_ = -1;
    565       // TODO(kinaba): http://crbug.com/118103. Implement upload callback in the
    566       //  layer and avoid using timer here.
    567       upload_progress_checker_timer_.reset(
    568           new base::RepeatingTimer<URLFetcherCore>());
    569       upload_progress_checker_timer_->Start(
    570           FROM_HERE,
    571           base::TimeDelta::FromMilliseconds(kUploadProgressTimerInterval),
    572           this,
    573           &URLFetcherCore::InformDelegateUploadProgress);
    574       break;
    575 
    576     case URLFetcher::HEAD:
    577       request_->set_method("HEAD");
    578       break;
    579 
    580     case URLFetcher::DELETE_REQUEST:
    581       request_->set_method("DELETE");
    582       break;
    583 
    584     default:
    585       NOTREACHED();
    586   }
    587 
    588   if (!extra_request_headers_.IsEmpty())
    589     request_->SetExtraRequestHeaders(extra_request_headers_);
    590 
    591   request_->Start();
    592 }
    593 
    594 void URLFetcherCore::DidInitializeWriter(int result) {
    595   if (result != OK) {
    596     CancelURLRequest(result);
    597     delegate_task_runner_->PostTask(
    598         FROM_HERE,
    599         base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this));
    600     return;
    601   }
    602   StartURLRequestWhenAppropriate();
    603 }
    604 
    605 void URLFetcherCore::StartURLRequestWhenAppropriate() {
    606   DCHECK(network_task_runner_->BelongsToCurrentThread());
    607 
    608   if (was_cancelled_)
    609     return;
    610 
    611   DCHECK(request_context_getter_.get());
    612 
    613   int64 delay = INT64_C(0);
    614   if (!original_url_throttler_entry_.get()) {
    615     URLRequestThrottlerManager* manager =
    616         request_context_getter_->GetURLRequestContext()->throttler_manager();
    617     if (manager) {
    618       original_url_throttler_entry_ =
    619           manager->RegisterRequestUrl(original_url_);
    620     }
    621   }
    622   if (original_url_throttler_entry_.get()) {
    623     delay = original_url_throttler_entry_->ReserveSendingTimeForNextRequest(
    624         GetBackoffReleaseTime());
    625   }
    626 
    627   if (delay == INT64_C(0)) {
    628     StartURLRequest();
    629   } else {
    630     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
    631         FROM_HERE, base::Bind(&URLFetcherCore::StartURLRequest, this),
    632         base::TimeDelta::FromMilliseconds(delay));
    633   }
    634 }
    635 
    636 void URLFetcherCore::CancelURLRequest(int error) {
    637   DCHECK(network_task_runner_->BelongsToCurrentThread());
    638 
    639   if (request_.get()) {
    640     request_->CancelWithError(error);
    641     ReleaseRequest();
    642   }
    643 
    644   // Set the error manually.
    645   // Normally, calling URLRequest::CancelWithError() results in calling
    646   // OnReadCompleted() with bytes_read = -1 via an asynchronous task posted by
    647   // URLRequestJob::NotifyDone(). But, because the request was released
    648   // immediately after being canceled, the request could not call
    649   // OnReadCompleted() which overwrites |status_| with the error status.
    650   status_.set_status(URLRequestStatus::CANCELED);
    651   status_.set_error(error);
    652 
    653   // Release the reference to the request context. There could be multiple
    654   // references to URLFetcher::Core at this point so it may take a while to
    655   // delete the object, but we cannot delay the destruction of the request
    656   // context.
    657   request_context_getter_ = NULL;
    658   first_party_for_cookies_ = GURL();
    659   url_request_data_key_ = NULL;
    660   url_request_create_data_callback_.Reset();
    661   was_cancelled_ = true;
    662 }
    663 
    664 void URLFetcherCore::OnCompletedURLRequest(
    665     base::TimeDelta backoff_delay) {
    666   DCHECK(delegate_task_runner_->BelongsToCurrentThread());
    667 
    668   // Save the status and backoff_delay so that delegates can read it.
    669   if (delegate_) {
    670     backoff_delay_ = backoff_delay;
    671     InformDelegateFetchIsComplete();
    672   }
    673 }
    674 
    675 void URLFetcherCore::InformDelegateFetchIsComplete() {
    676   DCHECK(delegate_task_runner_->BelongsToCurrentThread());
    677   if (delegate_)
    678     delegate_->OnURLFetchComplete(fetcher_);
    679 }
    680 
    681 void URLFetcherCore::NotifyMalformedContent() {
    682   DCHECK(network_task_runner_->BelongsToCurrentThread());
    683   if (url_throttler_entry_.get()) {
    684     int status_code = response_code_;
    685     if (status_code == URLFetcher::RESPONSE_CODE_INVALID) {
    686       // The status code will generally be known by the time clients
    687       // call the |ReceivedContentWasMalformed()| function (which ends up
    688       // calling the current function) but if it's not, we need to assume
    689       // the response was successful so that the total failure count
    690       // used to calculate exponential back-off goes up.
    691       status_code = 200;
    692     }
    693     url_throttler_entry_->ReceivedContentWasMalformed(status_code);
    694   }
    695 }
    696 
    697 void URLFetcherCore::DidFinishWriting(int result) {
    698   if (result != OK) {
    699     CancelURLRequest(result);
    700     delegate_task_runner_->PostTask(
    701         FROM_HERE,
    702         base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this));
    703     return;
    704   }
    705   // If the file was successfully closed, then the URL request is complete.
    706   RetryOrCompleteUrlFetch();
    707 }
    708 
    709 void URLFetcherCore::RetryOrCompleteUrlFetch() {
    710   DCHECK(network_task_runner_->BelongsToCurrentThread());
    711   base::TimeDelta backoff_delay;
    712 
    713   // Checks the response from server.
    714   if (response_code_ >= 500 ||
    715       status_.error() == ERR_TEMPORARILY_THROTTLED) {
    716     // When encountering a server error, we will send the request again
    717     // after backoff time.
    718     ++num_retries_on_5xx_;
    719 
    720     // Note that backoff_delay may be 0 because (a) the
    721     // URLRequestThrottlerManager and related code does not
    722     // necessarily back off on the first error, (b) it only backs off
    723     // on some of the 5xx status codes, (c) not all URLRequestContexts
    724     // have a throttler manager.
    725     base::TimeTicks backoff_release_time = GetBackoffReleaseTime();
    726     backoff_delay = backoff_release_time - base::TimeTicks::Now();
    727     if (backoff_delay < base::TimeDelta())
    728       backoff_delay = base::TimeDelta();
    729 
    730     if (automatically_retry_on_5xx_ &&
    731         num_retries_on_5xx_ <= max_retries_on_5xx_) {
    732       StartOnIOThread();
    733       return;
    734     }
    735   } else {
    736     backoff_delay = base::TimeDelta();
    737   }
    738 
    739   // Retry if the request failed due to network changes.
    740   if (status_.error() == ERR_NETWORK_CHANGED &&
    741       num_retries_on_network_changes_ < max_retries_on_network_changes_) {
    742     ++num_retries_on_network_changes_;
    743 
    744     // Retry soon, after flushing all the current tasks which may include
    745     // further network change observers.
    746     network_task_runner_->PostTask(
    747         FROM_HERE, base::Bind(&URLFetcherCore::StartOnIOThread, this));
    748     return;
    749   }
    750 
    751   request_context_getter_ = NULL;
    752   first_party_for_cookies_ = GURL();
    753   url_request_data_key_ = NULL;
    754   url_request_create_data_callback_.Reset();
    755   bool posted = delegate_task_runner_->PostTask(
    756       FROM_HERE,
    757       base::Bind(&URLFetcherCore::OnCompletedURLRequest, this, backoff_delay));
    758 
    759   // If the delegate message loop does not exist any more, then the delegate
    760   // should be gone too.
    761   DCHECK(posted || !delegate_);
    762 }
    763 
    764 void URLFetcherCore::ReleaseRequest() {
    765   upload_progress_checker_timer_.reset();
    766   request_.reset();
    767   g_registry.Get().RemoveURLFetcherCore(this);
    768 }
    769 
    770 base::TimeTicks URLFetcherCore::GetBackoffReleaseTime() {
    771   DCHECK(network_task_runner_->BelongsToCurrentThread());
    772 
    773   if (!original_url_throttler_entry_.get())
    774     return base::TimeTicks();
    775 
    776   base::TimeTicks original_url_backoff =
    777       original_url_throttler_entry_->GetExponentialBackoffReleaseTime();
    778   base::TimeTicks destination_url_backoff;
    779   if (url_throttler_entry_.get() &&
    780       original_url_throttler_entry_.get() != url_throttler_entry_.get()) {
    781     destination_url_backoff =
    782         url_throttler_entry_->GetExponentialBackoffReleaseTime();
    783   }
    784 
    785   return original_url_backoff > destination_url_backoff ?
    786       original_url_backoff : destination_url_backoff;
    787 }
    788 
    789 void URLFetcherCore::CompleteAddingUploadDataChunk(
    790     const std::string& content, bool is_last_chunk) {
    791   if (was_cancelled_) {
    792     // Since CompleteAddingUploadDataChunk() is posted as a *delayed* task, it
    793     // may run after the URLFetcher was already stopped.
    794     return;
    795   }
    796   DCHECK(is_chunked_upload_);
    797   DCHECK(request_.get());
    798   DCHECK(!content.empty());
    799   request_->AppendChunkToUpload(content.data(),
    800                                 static_cast<int>(content.length()),
    801                                 is_last_chunk);
    802 }
    803 
    804 int URLFetcherCore::WriteBuffer(scoped_refptr<DrainableIOBuffer> data) {
    805   while (data->BytesRemaining() > 0) {
    806     const int result = response_writer_->Write(
    807         data.get(),
    808         data->BytesRemaining(),
    809         base::Bind(&URLFetcherCore::DidWriteBuffer, this, data));
    810     if (result < 0) {
    811       if (result != ERR_IO_PENDING)
    812         DidWriteBuffer(data, result);
    813       return result;
    814     }
    815     data->DidConsume(result);
    816   }
    817   return OK;
    818 }
    819 
    820 void URLFetcherCore::DidWriteBuffer(scoped_refptr<DrainableIOBuffer> data,
    821                                     int result) {
    822   if (result < 0) {  // Handle errors.
    823     CancelURLRequest(result);
    824     response_writer_->Finish(base::Bind(&EmptyCompletionCallback));
    825     delegate_task_runner_->PostTask(
    826         FROM_HERE,
    827         base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this));
    828     return;
    829   }
    830 
    831   // Continue writing.
    832   data->DidConsume(result);
    833   if (WriteBuffer(data) < 0)
    834     return;
    835 
    836   // Finished writing buffer_. Read some more, unless the request has been
    837   // cancelled and deleted.
    838   DCHECK_EQ(0, data->BytesRemaining());
    839   if (request_.get())
    840     ReadResponse();
    841 }
    842 
    843 void URLFetcherCore::ReadResponse() {
    844   // Some servers may treat HEAD requests as GET requests. To free up the
    845   // network connection as soon as possible, signal that the request has
    846   // completed immediately, without trying to read any data back (all we care
    847   // about is the response code and headers, which we already have).
    848   int bytes_read = 0;
    849   if (request_->status().is_success() &&
    850       (request_type_ != URLFetcher::HEAD)) {
    851     if (!request_->Read(buffer_.get(), kBufferSize, &bytes_read))
    852       bytes_read = -1;  // Match OnReadCompleted() interface contract.
    853   }
    854   OnReadCompleted(request_.get(), bytes_read);
    855 }
    856 
    857 void URLFetcherCore::InformDelegateUploadProgress() {
    858   DCHECK(network_task_runner_->BelongsToCurrentThread());
    859   if (request_.get()) {
    860     int64 current = request_->GetUploadProgress().position();
    861     if (current_upload_bytes_ != current) {
    862       current_upload_bytes_ = current;
    863       int64 total = -1;
    864       if (!is_chunked_upload_) {
    865         total = static_cast<int64>(request_->GetUploadProgress().size());
    866         // Total may be zero if the UploadDataStream::Init has not been called
    867         // yet. Don't send the upload progress until the size is initialized.
    868         if (!total)
    869           return;
    870       }
    871       delegate_task_runner_->PostTask(
    872           FROM_HERE,
    873           base::Bind(
    874               &URLFetcherCore::InformDelegateUploadProgressInDelegateThread,
    875               this, current, total));
    876     }
    877   }
    878 }
    879 
    880 void URLFetcherCore::InformDelegateUploadProgressInDelegateThread(
    881     int64 current, int64 total) {
    882   DCHECK(delegate_task_runner_->BelongsToCurrentThread());
    883   if (delegate_)
    884     delegate_->OnURLFetchUploadProgress(fetcher_, current, total);
    885 }
    886 
    887 void URLFetcherCore::InformDelegateDownloadProgress() {
    888   DCHECK(network_task_runner_->BelongsToCurrentThread());
    889   delegate_task_runner_->PostTask(
    890       FROM_HERE,
    891       base::Bind(
    892           &URLFetcherCore::InformDelegateDownloadProgressInDelegateThread,
    893           this, current_response_bytes_, total_response_bytes_));
    894 }
    895 
    896 void URLFetcherCore::InformDelegateDownloadProgressInDelegateThread(
    897     int64 current, int64 total) {
    898   DCHECK(delegate_task_runner_->BelongsToCurrentThread());
    899   if (delegate_)
    900     delegate_->OnURLFetchDownloadProgress(fetcher_, current, total);
    901 }
    902 
    903 }  // namespace net
    904