mac: Don't limit GL_MAX_TEXTURE_SIZE on 10.9.0+.
[chromium-blink-merge.git] / net / url_request / url_fetcher_core.cc
blob420e83147b48c09c24c5967edef462a7357cef0d
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.
5 #include "net/url_request/url_fetcher_core.h"
7 #include <stdint.h>
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/metrics/histogram.h"
12 #include "base/profiler/scoped_tracker.h"
13 #include "base/sequenced_task_runner.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/stl_util.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "base/tracked_objects.h"
18 #include "net/base/elements_upload_data_stream.h"
19 #include "net/base/io_buffer.h"
20 #include "net/base/load_flags.h"
21 #include "net/base/net_errors.h"
22 #include "net/base/request_priority.h"
23 #include "net/base/upload_bytes_element_reader.h"
24 #include "net/base/upload_data_stream.h"
25 #include "net/base/upload_file_element_reader.h"
26 #include "net/http/http_response_headers.h"
27 #include "net/url_request/redirect_info.h"
28 #include "net/url_request/url_fetcher_delegate.h"
29 #include "net/url_request/url_fetcher_response_writer.h"
30 #include "net/url_request/url_request_context.h"
31 #include "net/url_request/url_request_context_getter.h"
32 #include "net/url_request/url_request_throttler_manager.h"
34 namespace {
36 const int kBufferSize = 4096;
37 const int kUploadProgressTimerInterval = 100;
38 bool g_ignore_certificate_requests = false;
40 void EmptyCompletionCallback(int result) {}
42 } // namespace
44 namespace net {
46 // URLFetcherCore::Registry ---------------------------------------------------
48 URLFetcherCore::Registry::Registry() {}
49 URLFetcherCore::Registry::~Registry() {}
51 void URLFetcherCore::Registry::AddURLFetcherCore(URLFetcherCore* core) {
52 DCHECK(!ContainsKey(fetchers_, core));
53 fetchers_.insert(core);
56 void URLFetcherCore::Registry::RemoveURLFetcherCore(URLFetcherCore* core) {
57 DCHECK(ContainsKey(fetchers_, core));
58 fetchers_.erase(core);
61 void URLFetcherCore::Registry::CancelAll() {
62 while (!fetchers_.empty())
63 (*fetchers_.begin())->CancelURLRequest(ERR_ABORTED);
66 // URLFetcherCore -------------------------------------------------------------
68 // static
69 base::LazyInstance<URLFetcherCore::Registry>
70 URLFetcherCore::g_registry = LAZY_INSTANCE_INITIALIZER;
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());
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();
115 DCHECK(network_task_runner_.get()) << "We need an IO task runner";
117 network_task_runner_->PostTask(
118 FROM_HERE, base::Bind(&URLFetcherCore::StartOnIOThread, this));
121 void URLFetcherCore::Stop() {
122 if (delegate_task_runner_.get()) // May be NULL in tests.
123 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
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));
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());
146 // Empty |upload_content_type| is allowed iff the |upload_content| is empty.
147 DCHECK(upload_content.empty() || !upload_content_type.empty());
149 upload_content_type_ = upload_content_type;
150 upload_content_ = upload_content;
151 upload_content_set_ = true;
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());
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;
177 void URLFetcherCore::SetChunkedUpload(const std::string& content_type) {
178 DCHECK(is_chunked_upload_ ||
179 (upload_content_type_.empty() &&
180 upload_content_.empty()));
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());
186 upload_content_type_ = content_type;
187 upload_content_.clear();
188 is_chunked_upload_ = true;
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));
201 void URLFetcherCore::SetLoadFlags(int load_flags) {
202 load_flags_ = load_flags;
205 int URLFetcherCore::GetLoadFlags() const {
206 return load_flags_;
209 void URLFetcherCore::SetReferrer(const std::string& referrer) {
210 referrer_ = referrer;
213 void URLFetcherCore::SetReferrerPolicy(
214 URLRequest::ReferrerPolicy referrer_policy) {
215 referrer_policy_ = referrer_policy;
218 void URLFetcherCore::SetExtraRequestHeaders(
219 const std::string& extra_request_headers) {
220 extra_request_headers_.Clear();
221 extra_request_headers_.AddHeadersFromString(extra_request_headers);
224 void URLFetcherCore::AddExtraRequestHeader(const std::string& header_line) {
225 extra_request_headers_.AddHeaderFromString(header_line);
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;
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;
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;
250 void URLFetcherCore::SetStopOnRedirect(bool stop_on_redirect) {
251 stop_on_redirect_ = stop_on_redirect;
254 void URLFetcherCore::SetAutomaticallyRetryOn5xx(bool retry) {
255 automatically_retry_on_5xx_ = retry;
258 void URLFetcherCore::SetMaxRetriesOn5xx(int max_retries) {
259 max_retries_on_5xx_ = max_retries;
262 int URLFetcherCore::GetMaxRetriesOn5xx() const {
263 return max_retries_on_5xx_;
266 base::TimeDelta URLFetcherCore::GetBackoffDelay() const {
267 return backoff_delay_;
270 void URLFetcherCore::SetAutomaticallyRetryOnNetworkChanges(int max_retries) {
271 max_retries_on_network_changes_ = max_retries;
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)));
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())));
289 void URLFetcherCore::SaveResponseWithWriter(
290 scoped_ptr<URLFetcherResponseWriter> response_writer) {
291 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
292 response_writer_ = response_writer.Pass();
295 HttpResponseHeaders* URLFetcherCore::GetResponseHeaders() const {
296 return response_headers_.get();
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_;
306 bool URLFetcherCore::WasFetchedViaProxy() const {
307 return was_fetched_via_proxy_;
310 const GURL& URLFetcherCore::GetOriginalURL() const {
311 return original_url_;
314 const GURL& URLFetcherCore::GetURL() const {
315 return url_;
318 const URLRequestStatus& URLFetcherCore::GetStatus() const {
319 return status_;
322 int URLFetcherCore::GetResponseCode() const {
323 return response_code_;
326 const ResponseCookies& URLFetcherCore::GetCookies() const {
327 return cookies_;
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));
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;
345 *out_response_string = string_writer->data();
346 UMA_HISTOGRAM_MEMORY_KB("UrlFetcher.StringResponseSize",
347 (string_writer->data().length() / 1024));
348 return true;
351 bool URLFetcherCore::GetResponseAsFilePath(bool take_ownership,
352 base::FilePath* out_response_path) {
353 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
355 URLFetcherFileWriter* file_writer =
356 response_writer_ ? response_writer_->AsFileWriter() : NULL;
357 if (!file_writer)
358 return false;
360 *out_response_path = file_writer->file_path();
362 if (take_ownership) {
363 // Intentionally calling a file_writer_ method directly without posting
364 // the task to network_task_runner_.
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_.
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();
374 return true;
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);
392 void URLFetcherCore::OnResponseStarted(URLRequest* request) {
393 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
394 tracked_objects::ScopedTracker tracking_profile(
395 FROM_HERE_WITH_EXPLICIT_FUNCTION(
396 "423948 URLFetcherCore::OnResponseStarted"));
398 DCHECK_EQ(request, request_.get());
399 DCHECK(network_task_runner_->BelongsToCurrentThread());
400 if (request_->status().is_success()) {
401 response_code_ = request_->GetResponseCode();
402 response_headers_ = request_->response_headers();
403 socket_address_ = request_->GetSocketAddress();
404 was_fetched_via_proxy_ = request_->was_fetched_via_proxy();
405 total_response_bytes_ = request_->GetExpectedContentSize();
408 ReadResponse();
411 void URLFetcherCore::OnCertificateRequested(
412 URLRequest* request,
413 SSLCertRequestInfo* cert_request_info) {
414 DCHECK_EQ(request, request_.get());
415 DCHECK(network_task_runner_->BelongsToCurrentThread());
417 if (g_ignore_certificate_requests) {
418 request->ContinueWithCertificate(NULL);
419 } else {
420 request->Cancel();
424 void URLFetcherCore::OnReadCompleted(URLRequest* request,
425 int bytes_read) {
426 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
427 tracked_objects::ScopedTracker tracking_profile(
428 FROM_HERE_WITH_EXPLICIT_FUNCTION(
429 "423948 URLFetcherCore::OnReadCompleted"));
431 DCHECK(request == request_);
432 DCHECK(network_task_runner_->BelongsToCurrentThread());
434 if (!stopped_on_redirect_)
435 url_ = request->url();
436 URLRequestThrottlerManager* throttler_manager =
437 request->context()->throttler_manager();
438 if (throttler_manager) {
439 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
440 tracked_objects::ScopedTracker tracking_profile1(
441 FROM_HERE_WITH_EXPLICIT_FUNCTION(
442 "423948 URLFetcherCore::OnReadCompleted1"));
444 url_throttler_entry_ = throttler_manager->RegisterRequestUrl(url_);
447 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
448 tracked_objects::ScopedTracker tracking_profile2(
449 FROM_HERE_WITH_EXPLICIT_FUNCTION(
450 "423948 URLFetcherCore::OnReadCompleted2"));
452 do {
453 if (!request_->status().is_success() || bytes_read <= 0)
454 break;
456 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
457 tracked_objects::ScopedTracker tracking_profile3(
458 FROM_HERE_WITH_EXPLICIT_FUNCTION(
459 "423948 URLFetcherCore::OnReadCompleted3"));
461 current_response_bytes_ += bytes_read;
462 InformDelegateDownloadProgress();
464 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
465 tracked_objects::ScopedTracker tracking_profile4(
466 FROM_HERE_WITH_EXPLICIT_FUNCTION(
467 "423948 URLFetcherCore::OnReadCompleted4"));
469 const int result =
470 WriteBuffer(new DrainableIOBuffer(buffer_.get(), bytes_read));
471 if (result < 0) {
472 // Write failed or waiting for write completion.
473 return;
475 } while (request_->Read(buffer_.get(), kBufferSize, &bytes_read));
477 const URLRequestStatus status = request_->status();
479 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
480 tracked_objects::ScopedTracker tracking_profile5(
481 FROM_HERE_WITH_EXPLICIT_FUNCTION(
482 "423948 URLFetcherCore::OnReadCompleted5"));
484 if (status.is_success())
485 request_->GetResponseCookies(&cookies_);
487 // See comments re: HEAD requests in ReadResponse().
488 if (!status.is_io_pending() || request_type_ == URLFetcher::HEAD) {
489 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
490 tracked_objects::ScopedTracker tracking_profile6(
491 FROM_HERE_WITH_EXPLICIT_FUNCTION(
492 "423948 URLFetcherCore::OnReadCompleted6"));
494 status_ = status;
495 ReleaseRequest();
497 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
498 tracked_objects::ScopedTracker tracking_profile7(
499 FROM_HERE_WITH_EXPLICIT_FUNCTION(
500 "423948 URLFetcherCore::OnReadCompleted7"));
502 // No more data to write.
503 const int result = response_writer_->Finish(
504 base::Bind(&URLFetcherCore::DidFinishWriting, this));
506 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
507 tracked_objects::ScopedTracker tracking_profile8(
508 FROM_HERE_WITH_EXPLICIT_FUNCTION(
509 "423948 URLFetcherCore::OnReadCompleted8"));
511 if (result != ERR_IO_PENDING)
512 DidFinishWriting(result);
516 void URLFetcherCore::CancelAll() {
517 g_registry.Get().CancelAll();
520 int URLFetcherCore::GetNumFetcherCores() {
521 return g_registry.Get().size();
524 void URLFetcherCore::SetIgnoreCertificateRequests(bool ignored) {
525 g_ignore_certificate_requests = ignored;
528 URLFetcherCore::~URLFetcherCore() {
529 // |request_| should be NULL. If not, it's unsafe to delete it here since we
530 // may not be on the IO thread.
531 DCHECK(!request_.get());
534 void URLFetcherCore::StartOnIOThread() {
535 DCHECK(network_task_runner_->BelongsToCurrentThread());
537 if (!response_writer_)
538 response_writer_.reset(new URLFetcherStringWriter);
540 const int result = response_writer_->Initialize(
541 base::Bind(&URLFetcherCore::DidInitializeWriter, this));
542 if (result != ERR_IO_PENDING)
543 DidInitializeWriter(result);
546 void URLFetcherCore::StartURLRequest() {
547 DCHECK(network_task_runner_->BelongsToCurrentThread());
549 if (was_cancelled_) {
550 // Since StartURLRequest() is posted as a *delayed* task, it may
551 // run after the URLFetcher was already stopped.
552 return;
555 DCHECK(request_context_getter_.get());
556 DCHECK(!request_.get());
558 g_registry.Get().AddURLFetcherCore(this);
559 current_response_bytes_ = 0;
560 request_ = request_context_getter_->GetURLRequestContext()->CreateRequest(
561 original_url_, DEFAULT_PRIORITY, this, NULL);
562 request_->set_stack_trace(stack_trace_);
563 int flags = request_->load_flags() | load_flags_;
565 if (is_chunked_upload_)
566 request_->EnableChunkedUpload();
567 request_->SetLoadFlags(flags);
568 request_->SetReferrer(referrer_);
569 request_->set_referrer_policy(referrer_policy_);
570 request_->set_first_party_for_cookies(first_party_for_cookies_.is_empty() ?
571 original_url_ : first_party_for_cookies_);
572 if (url_request_data_key_ && !url_request_create_data_callback_.is_null()) {
573 request_->SetUserData(url_request_data_key_,
574 url_request_create_data_callback_.Run());
577 switch (request_type_) {
578 case URLFetcher::GET:
579 break;
581 case URLFetcher::POST:
582 case URLFetcher::PUT:
583 case URLFetcher::PATCH:
584 // Upload content must be set.
585 DCHECK(is_chunked_upload_ || upload_content_set_);
587 request_->set_method(
588 request_type_ == URLFetcher::POST ? "POST" :
589 request_type_ == URLFetcher::PUT ? "PUT" : "PATCH");
590 if (!upload_content_type_.empty()) {
591 extra_request_headers_.SetHeader(HttpRequestHeaders::kContentType,
592 upload_content_type_);
594 if (!upload_content_.empty()) {
595 scoped_ptr<UploadElementReader> reader(new UploadBytesElementReader(
596 upload_content_.data(), upload_content_.size()));
597 request_->set_upload(
598 ElementsUploadDataStream::CreateWithReader(reader.Pass(), 0));
599 } else if (!upload_file_path_.empty()) {
600 scoped_ptr<UploadElementReader> reader(
601 new UploadFileElementReader(upload_file_task_runner_.get(),
602 upload_file_path_,
603 upload_range_offset_,
604 upload_range_length_,
605 base::Time()));
606 request_->set_upload(
607 ElementsUploadDataStream::CreateWithReader(reader.Pass(), 0));
610 current_upload_bytes_ = -1;
611 // TODO(kinaba): http://crbug.com/118103. Implement upload callback in the
612 // layer and avoid using timer here.
613 upload_progress_checker_timer_.reset(
614 new base::RepeatingTimer<URLFetcherCore>());
615 upload_progress_checker_timer_->Start(
616 FROM_HERE,
617 base::TimeDelta::FromMilliseconds(kUploadProgressTimerInterval),
618 this,
619 &URLFetcherCore::InformDelegateUploadProgress);
620 break;
622 case URLFetcher::HEAD:
623 request_->set_method("HEAD");
624 break;
626 case URLFetcher::DELETE_REQUEST:
627 request_->set_method("DELETE");
628 break;
630 default:
631 NOTREACHED();
634 if (!extra_request_headers_.IsEmpty())
635 request_->SetExtraRequestHeaders(extra_request_headers_);
637 request_->Start();
640 void URLFetcherCore::DidInitializeWriter(int result) {
641 if (result != OK) {
642 CancelURLRequest(result);
643 delegate_task_runner_->PostTask(
644 FROM_HERE,
645 base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this));
646 return;
648 StartURLRequestWhenAppropriate();
651 void URLFetcherCore::StartURLRequestWhenAppropriate() {
652 DCHECK(network_task_runner_->BelongsToCurrentThread());
654 if (was_cancelled_)
655 return;
657 DCHECK(request_context_getter_.get());
659 int64 delay = INT64_C(0);
660 if (!original_url_throttler_entry_.get()) {
661 URLRequestThrottlerManager* manager =
662 request_context_getter_->GetURLRequestContext()->throttler_manager();
663 if (manager) {
664 original_url_throttler_entry_ =
665 manager->RegisterRequestUrl(original_url_);
668 if (original_url_throttler_entry_.get()) {
669 delay = original_url_throttler_entry_->ReserveSendingTimeForNextRequest(
670 GetBackoffReleaseTime());
673 if (delay == INT64_C(0)) {
674 StartURLRequest();
675 } else {
676 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
677 FROM_HERE, base::Bind(&URLFetcherCore::StartURLRequest, this),
678 base::TimeDelta::FromMilliseconds(delay));
682 void URLFetcherCore::CancelURLRequest(int error) {
683 DCHECK(network_task_runner_->BelongsToCurrentThread());
685 if (request_.get()) {
686 request_->CancelWithError(error);
687 ReleaseRequest();
690 // Set the error manually.
691 // Normally, calling URLRequest::CancelWithError() results in calling
692 // OnReadCompleted() with bytes_read = -1 via an asynchronous task posted by
693 // URLRequestJob::NotifyDone(). But, because the request was released
694 // immediately after being canceled, the request could not call
695 // OnReadCompleted() which overwrites |status_| with the error status.
696 status_.set_status(URLRequestStatus::CANCELED);
697 status_.set_error(error);
699 // Release the reference to the request context. There could be multiple
700 // references to URLFetcher::Core at this point so it may take a while to
701 // delete the object, but we cannot delay the destruction of the request
702 // context.
703 request_context_getter_ = NULL;
704 first_party_for_cookies_ = GURL();
705 url_request_data_key_ = NULL;
706 url_request_create_data_callback_.Reset();
707 was_cancelled_ = true;
710 void URLFetcherCore::OnCompletedURLRequest(
711 base::TimeDelta backoff_delay) {
712 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
714 // Save the status and backoff_delay so that delegates can read it.
715 if (delegate_) {
716 backoff_delay_ = backoff_delay;
717 InformDelegateFetchIsComplete();
721 void URLFetcherCore::InformDelegateFetchIsComplete() {
722 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
723 if (delegate_)
724 delegate_->OnURLFetchComplete(fetcher_);
727 void URLFetcherCore::NotifyMalformedContent() {
728 DCHECK(network_task_runner_->BelongsToCurrentThread());
729 if (url_throttler_entry_.get()) {
730 int status_code = response_code_;
731 if (status_code == URLFetcher::RESPONSE_CODE_INVALID) {
732 // The status code will generally be known by the time clients
733 // call the |ReceivedContentWasMalformed()| function (which ends up
734 // calling the current function) but if it's not, we need to assume
735 // the response was successful so that the total failure count
736 // used to calculate exponential back-off goes up.
737 status_code = 200;
739 url_throttler_entry_->ReceivedContentWasMalformed(status_code);
743 void URLFetcherCore::DidFinishWriting(int result) {
744 if (result != OK) {
745 CancelURLRequest(result);
746 delegate_task_runner_->PostTask(
747 FROM_HERE,
748 base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this));
749 return;
751 // If the file was successfully closed, then the URL request is complete.
752 RetryOrCompleteUrlFetch();
755 void URLFetcherCore::RetryOrCompleteUrlFetch() {
756 DCHECK(network_task_runner_->BelongsToCurrentThread());
757 base::TimeDelta backoff_delay;
759 // Checks the response from server.
760 if (response_code_ >= 500 ||
761 status_.error() == ERR_TEMPORARILY_THROTTLED) {
762 // When encountering a server error, we will send the request again
763 // after backoff time.
764 ++num_retries_on_5xx_;
766 // Note that backoff_delay may be 0 because (a) the
767 // URLRequestThrottlerManager and related code does not
768 // necessarily back off on the first error, (b) it only backs off
769 // on some of the 5xx status codes, (c) not all URLRequestContexts
770 // have a throttler manager.
771 base::TimeTicks backoff_release_time = GetBackoffReleaseTime();
772 backoff_delay = backoff_release_time - base::TimeTicks::Now();
773 if (backoff_delay < base::TimeDelta())
774 backoff_delay = base::TimeDelta();
776 if (automatically_retry_on_5xx_ &&
777 num_retries_on_5xx_ <= max_retries_on_5xx_) {
778 StartOnIOThread();
779 return;
781 } else {
782 backoff_delay = base::TimeDelta();
785 // Retry if the request failed due to network changes.
786 if (status_.error() == ERR_NETWORK_CHANGED &&
787 num_retries_on_network_changes_ < max_retries_on_network_changes_) {
788 ++num_retries_on_network_changes_;
790 // Retry soon, after flushing all the current tasks which may include
791 // further network change observers.
792 network_task_runner_->PostTask(
793 FROM_HERE, base::Bind(&URLFetcherCore::StartOnIOThread, this));
794 return;
797 request_context_getter_ = NULL;
798 first_party_for_cookies_ = GURL();
799 url_request_data_key_ = NULL;
800 url_request_create_data_callback_.Reset();
801 bool posted = delegate_task_runner_->PostTask(
802 FROM_HERE,
803 base::Bind(&URLFetcherCore::OnCompletedURLRequest, this, backoff_delay));
805 // If the delegate message loop does not exist any more, then the delegate
806 // should be gone too.
807 DCHECK(posted || !delegate_);
810 void URLFetcherCore::ReleaseRequest() {
811 upload_progress_checker_timer_.reset();
812 request_.reset();
813 g_registry.Get().RemoveURLFetcherCore(this);
816 base::TimeTicks URLFetcherCore::GetBackoffReleaseTime() {
817 DCHECK(network_task_runner_->BelongsToCurrentThread());
819 if (!original_url_throttler_entry_.get())
820 return base::TimeTicks();
822 base::TimeTicks original_url_backoff =
823 original_url_throttler_entry_->GetExponentialBackoffReleaseTime();
824 base::TimeTicks destination_url_backoff;
825 if (url_throttler_entry_.get() &&
826 original_url_throttler_entry_.get() != url_throttler_entry_.get()) {
827 destination_url_backoff =
828 url_throttler_entry_->GetExponentialBackoffReleaseTime();
831 return original_url_backoff > destination_url_backoff ?
832 original_url_backoff : destination_url_backoff;
835 void URLFetcherCore::CompleteAddingUploadDataChunk(
836 const std::string& content, bool is_last_chunk) {
837 if (was_cancelled_) {
838 // Since CompleteAddingUploadDataChunk() is posted as a *delayed* task, it
839 // may run after the URLFetcher was already stopped.
840 return;
842 DCHECK(is_chunked_upload_);
843 DCHECK(request_.get());
844 DCHECK(!content.empty());
845 request_->AppendChunkToUpload(content.data(),
846 static_cast<int>(content.length()),
847 is_last_chunk);
850 int URLFetcherCore::WriteBuffer(scoped_refptr<DrainableIOBuffer> data) {
851 while (data->BytesRemaining() > 0) {
852 const int result = response_writer_->Write(
853 data.get(),
854 data->BytesRemaining(),
855 base::Bind(&URLFetcherCore::DidWriteBuffer, this, data));
856 if (result < 0) {
857 if (result != ERR_IO_PENDING)
858 DidWriteBuffer(data, result);
859 return result;
861 data->DidConsume(result);
863 return OK;
866 void URLFetcherCore::DidWriteBuffer(scoped_refptr<DrainableIOBuffer> data,
867 int result) {
868 if (result < 0) { // Handle errors.
869 CancelURLRequest(result);
870 response_writer_->Finish(base::Bind(&EmptyCompletionCallback));
871 delegate_task_runner_->PostTask(
872 FROM_HERE,
873 base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this));
874 return;
877 // Continue writing.
878 data->DidConsume(result);
879 if (WriteBuffer(data) < 0)
880 return;
882 // Finished writing buffer_. Read some more, unless the request has been
883 // cancelled and deleted.
884 DCHECK_EQ(0, data->BytesRemaining());
885 if (request_.get())
886 ReadResponse();
889 void URLFetcherCore::ReadResponse() {
890 // Some servers may treat HEAD requests as GET requests. To free up the
891 // network connection as soon as possible, signal that the request has
892 // completed immediately, without trying to read any data back (all we care
893 // about is the response code and headers, which we already have).
894 int bytes_read = 0;
895 if (request_->status().is_success() &&
896 (request_type_ != URLFetcher::HEAD)) {
897 if (!request_->Read(buffer_.get(), kBufferSize, &bytes_read))
898 bytes_read = -1; // Match OnReadCompleted() interface contract.
900 OnReadCompleted(request_.get(), bytes_read);
903 void URLFetcherCore::InformDelegateUploadProgress() {
904 DCHECK(network_task_runner_->BelongsToCurrentThread());
905 if (request_.get()) {
906 int64 current = request_->GetUploadProgress().position();
907 if (current_upload_bytes_ != current) {
908 current_upload_bytes_ = current;
909 int64 total = -1;
910 if (!is_chunked_upload_) {
911 total = static_cast<int64>(request_->GetUploadProgress().size());
912 // Total may be zero if the UploadDataStream::Init has not been called
913 // yet. Don't send the upload progress until the size is initialized.
914 if (!total)
915 return;
917 delegate_task_runner_->PostTask(
918 FROM_HERE,
919 base::Bind(
920 &URLFetcherCore::InformDelegateUploadProgressInDelegateThread,
921 this, current, total));
926 void URLFetcherCore::InformDelegateUploadProgressInDelegateThread(
927 int64 current, int64 total) {
928 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
929 if (delegate_)
930 delegate_->OnURLFetchUploadProgress(fetcher_, current, total);
933 void URLFetcherCore::InformDelegateDownloadProgress() {
934 DCHECK(network_task_runner_->BelongsToCurrentThread());
935 delegate_task_runner_->PostTask(
936 FROM_HERE,
937 base::Bind(
938 &URLFetcherCore::InformDelegateDownloadProgressInDelegateThread,
939 this, current_response_bytes_, total_response_bytes_));
942 void URLFetcherCore::InformDelegateDownloadProgressInDelegateThread(
943 int64 current, int64 total) {
944 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
945 if (delegate_)
946 delegate_->OnURLFetchDownloadProgress(fetcher_, current, total);
949 } // namespace net