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