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