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