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