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"
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/io_buffer.h"
18 #include "net/base/load_flags.h"
19 #include "net/base/net_errors.h"
20 #include "net/base/request_priority.h"
21 #include "net/base/upload_bytes_element_reader.h"
22 #include "net/base/upload_data_stream.h"
23 #include "net/base/upload_file_element_reader.h"
24 #include "net/http/http_response_headers.h"
25 #include "net/url_request/redirect_info.h"
26 #include "net/url_request/url_fetcher_delegate.h"
27 #include "net/url_request/url_fetcher_response_writer.h"
28 #include "net/url_request/url_request_context.h"
29 #include "net/url_request/url_request_context_getter.h"
30 #include "net/url_request/url_request_throttler_manager.h"
34 const int kBufferSize = 4096;
35 const int kUploadProgressTimerInterval = 100;
36 bool g_interception_enabled = false;
37 bool g_ignore_certificate_requests = false;
39 void EmptyCompletionCallback(int result) {}
45 // URLFetcherCore::Registry ---------------------------------------------------
47 URLFetcherCore::Registry::Registry() {}
48 URLFetcherCore::Registry::~Registry() {}
50 void URLFetcherCore::Registry::AddURLFetcherCore(URLFetcherCore* core) {
51 DCHECK(!ContainsKey(fetchers_, core));
52 fetchers_.insert(core);
55 void URLFetcherCore::Registry::RemoveURLFetcherCore(URLFetcherCore* core) {
56 DCHECK(ContainsKey(fetchers_, core));
57 fetchers_.erase(core);
60 void URLFetcherCore::Registry::CancelAll() {
61 while (!fetchers_.empty())
62 (*fetchers_.begin())->CancelURLRequest(ERR_ABORTED);
65 // URLFetcherCore -------------------------------------------------------------
68 base::LazyInstance<URLFetcherCore::Registry>
69 URLFetcherCore::g_registry = LAZY_INSTANCE_INITIALIZER;
71 URLFetcherCore::URLFetcherCore(URLFetcher* fetcher,
72 const GURL& original_url,
73 URLFetcher::RequestType request_type,
74 URLFetcherDelegate* d)
76 original_url_(original_url),
77 request_type_(request_type),
79 delegate_task_runner_(base::ThreadTaskRunnerHandle::Get()),
80 load_flags_(LOAD_NORMAL),
81 response_code_(URLFetcher::RESPONSE_CODE_INVALID),
82 buffer_(new IOBuffer(kBufferSize)),
83 url_request_data_key_(NULL),
84 was_fetched_via_proxy_(false),
85 upload_content_set_(false),
86 upload_range_offset_(0),
87 upload_range_length_(0),
89 URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE),
90 is_chunked_upload_(false),
91 was_cancelled_(false),
92 stop_on_redirect_(false),
93 stopped_on_redirect_(false),
94 automatically_retry_on_5xx_(true),
95 num_retries_on_5xx_(0),
96 max_retries_on_5xx_(0),
97 num_retries_on_network_changes_(0),
98 max_retries_on_network_changes_(0),
99 current_upload_bytes_(-1),
100 current_response_bytes_(0),
101 total_response_bytes_(-1) {
102 CHECK(original_url_.is_valid());
105 void URLFetcherCore::Start() {
106 DCHECK(delegate_task_runner_.get());
107 DCHECK(request_context_getter_.get()) << "We need an URLRequestContext!";
108 if (network_task_runner_.get()) {
109 DCHECK_EQ(network_task_runner_,
110 request_context_getter_->GetNetworkTaskRunner());
112 network_task_runner_ = request_context_getter_->GetNetworkTaskRunner();
114 DCHECK(network_task_runner_.get()) << "We need an IO task runner";
116 network_task_runner_->PostTask(
117 FROM_HERE, base::Bind(&URLFetcherCore::StartOnIOThread, this));
120 void URLFetcherCore::Stop() {
121 if (delegate_task_runner_.get()) // May be NULL in tests.
122 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
126 if (!network_task_runner_.get())
128 if (network_task_runner_->RunsTasksOnCurrentThread()) {
129 CancelURLRequest(ERR_ABORTED);
131 network_task_runner_->PostTask(
133 base::Bind(&URLFetcherCore::CancelURLRequest, this, ERR_ABORTED));
137 void URLFetcherCore::SetUploadData(const std::string& upload_content_type,
138 const std::string& upload_content) {
139 DCHECK(!is_chunked_upload_);
140 DCHECK(!upload_content_set_);
141 DCHECK(upload_content_.empty());
142 DCHECK(upload_file_path_.empty());
143 DCHECK(upload_content_type_.empty());
145 // Empty |upload_content_type| is allowed iff the |upload_content| is empty.
146 DCHECK(upload_content.empty() || !upload_content_type.empty());
148 upload_content_type_ = upload_content_type;
149 upload_content_ = upload_content;
150 upload_content_set_ = true;
153 void URLFetcherCore::SetUploadFilePath(
154 const std::string& upload_content_type,
155 const base::FilePath& file_path,
158 scoped_refptr<base::TaskRunner> file_task_runner) {
159 DCHECK(!is_chunked_upload_);
160 DCHECK(!upload_content_set_);
161 DCHECK(upload_content_.empty());
162 DCHECK(upload_file_path_.empty());
163 DCHECK_EQ(upload_range_offset_, 0ULL);
164 DCHECK_EQ(upload_range_length_, 0ULL);
165 DCHECK(upload_content_type_.empty());
166 DCHECK(!upload_content_type.empty());
168 upload_content_type_ = upload_content_type;
169 upload_file_path_ = file_path;
170 upload_range_offset_ = range_offset;
171 upload_range_length_ = range_length;
172 upload_file_task_runner_ = file_task_runner;
173 upload_content_set_ = true;
176 void URLFetcherCore::SetChunkedUpload(const std::string& content_type) {
177 DCHECK(is_chunked_upload_ ||
178 (upload_content_type_.empty() &&
179 upload_content_.empty()));
181 // Empty |content_type| is not allowed here, because it is impossible
182 // to ensure non-empty upload content as it is not yet supplied.
183 DCHECK(!content_type.empty());
185 upload_content_type_ = content_type;
186 upload_content_.clear();
187 is_chunked_upload_ = true;
190 void URLFetcherCore::AppendChunkToUpload(const std::string& content,
191 bool is_last_chunk) {
192 DCHECK(delegate_task_runner_.get());
193 DCHECK(network_task_runner_.get());
194 network_task_runner_->PostTask(
196 base::Bind(&URLFetcherCore::CompleteAddingUploadDataChunk, this, content,
200 void URLFetcherCore::SetLoadFlags(int load_flags) {
201 load_flags_ = load_flags;
204 int URLFetcherCore::GetLoadFlags() const {
208 void URLFetcherCore::SetReferrer(const std::string& referrer) {
209 referrer_ = referrer;
212 void URLFetcherCore::SetReferrerPolicy(
213 URLRequest::ReferrerPolicy referrer_policy) {
214 referrer_policy_ = referrer_policy;
217 void URLFetcherCore::SetExtraRequestHeaders(
218 const std::string& extra_request_headers) {
219 extra_request_headers_.Clear();
220 extra_request_headers_.AddHeadersFromString(extra_request_headers);
223 void URLFetcherCore::AddExtraRequestHeader(const std::string& header_line) {
224 extra_request_headers_.AddHeaderFromString(header_line);
227 void URLFetcherCore::SetRequestContext(
228 URLRequestContextGetter* request_context_getter) {
229 DCHECK(!request_context_getter_.get());
230 DCHECK(request_context_getter);
231 request_context_getter_ = request_context_getter;
234 void URLFetcherCore::SetFirstPartyForCookies(
235 const GURL& first_party_for_cookies) {
236 DCHECK(first_party_for_cookies_.is_empty());
237 first_party_for_cookies_ = first_party_for_cookies;
240 void URLFetcherCore::SetURLRequestUserData(
242 const URLFetcher::CreateDataCallback& create_data_callback) {
244 DCHECK(!create_data_callback.is_null());
245 url_request_data_key_ = key;
246 url_request_create_data_callback_ = create_data_callback;
249 void URLFetcherCore::SetStopOnRedirect(bool stop_on_redirect) {
250 stop_on_redirect_ = stop_on_redirect;
253 void URLFetcherCore::SetAutomaticallyRetryOn5xx(bool retry) {
254 automatically_retry_on_5xx_ = retry;
257 void URLFetcherCore::SetMaxRetriesOn5xx(int max_retries) {
258 max_retries_on_5xx_ = max_retries;
261 int URLFetcherCore::GetMaxRetriesOn5xx() const {
262 return max_retries_on_5xx_;
265 base::TimeDelta URLFetcherCore::GetBackoffDelay() const {
266 return backoff_delay_;
269 void URLFetcherCore::SetAutomaticallyRetryOnNetworkChanges(int max_retries) {
270 max_retries_on_network_changes_ = max_retries;
273 void URLFetcherCore::SaveResponseToFileAtPath(
274 const base::FilePath& file_path,
275 scoped_refptr<base::SequencedTaskRunner> file_task_runner) {
276 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
277 SaveResponseWithWriter(scoped_ptr<URLFetcherResponseWriter>(
278 new URLFetcherFileWriter(file_task_runner, file_path)));
281 void URLFetcherCore::SaveResponseToTemporaryFile(
282 scoped_refptr<base::SequencedTaskRunner> file_task_runner) {
283 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
284 SaveResponseWithWriter(scoped_ptr<URLFetcherResponseWriter>(
285 new URLFetcherFileWriter(file_task_runner, base::FilePath())));
288 void URLFetcherCore::SaveResponseWithWriter(
289 scoped_ptr<URLFetcherResponseWriter> response_writer) {
290 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
291 response_writer_ = response_writer.Pass();
294 HttpResponseHeaders* URLFetcherCore::GetResponseHeaders() const {
295 return response_headers_.get();
298 // TODO(panayiotis): socket_address_ is written in the IO thread,
299 // if this is accessed in the UI thread, this could result in a race.
300 // Same for response_headers_ above and was_fetched_via_proxy_ below.
301 HostPortPair URLFetcherCore::GetSocketAddress() const {
302 return socket_address_;
305 bool URLFetcherCore::WasFetchedViaProxy() const {
306 return was_fetched_via_proxy_;
309 const GURL& URLFetcherCore::GetOriginalURL() const {
310 return original_url_;
313 const GURL& URLFetcherCore::GetURL() const {
317 const URLRequestStatus& URLFetcherCore::GetStatus() const {
321 int URLFetcherCore::GetResponseCode() const {
322 return response_code_;
325 const ResponseCookies& URLFetcherCore::GetCookies() const {
329 void 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));
337 bool URLFetcherCore::GetResponseAsString(
338 std::string* out_response_string) const {
339 URLFetcherStringWriter* string_writer =
340 response_writer_ ? response_writer_->AsStringWriter() : NULL;
344 *out_response_string = string_writer->data();
345 UMA_HISTOGRAM_MEMORY_KB("UrlFetcher.StringResponseSize",
346 (string_writer->data().length() / 1024));
350 bool URLFetcherCore::GetResponseAsFilePath(bool take_ownership,
351 base::FilePath* out_response_path) {
352 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
354 URLFetcherFileWriter* file_writer =
355 response_writer_ ? response_writer_->AsFileWriter() : NULL;
359 *out_response_path = file_writer->file_path();
361 if (take_ownership) {
362 // Intentionally calling a file_writer_ method directly without posting
363 // the task to network_task_runner_.
365 // This is for correctly handling the case when file_writer_->DisownFile()
366 // is soon followed by URLFetcherCore::Stop(). We have to make sure that
367 // DisownFile takes effect before Stop deletes file_writer_.
369 // This direct call should be thread-safe, since DisownFile itself does no
370 // file operation. It just flips the state to be referred in destruction.
371 file_writer->DisownFile();
376 void URLFetcherCore::OnReceivedRedirect(URLRequest* request,
377 const RedirectInfo& redirect_info,
378 bool* defer_redirect) {
379 DCHECK_EQ(request, request_.get());
380 DCHECK(network_task_runner_->BelongsToCurrentThread());
381 if (stop_on_redirect_) {
382 stopped_on_redirect_ = true;
383 url_ = redirect_info.new_url;
384 response_code_ = request_->GetResponseCode();
385 was_fetched_via_proxy_ = request_->was_fetched_via_proxy();
387 OnReadCompleted(request, 0);
391 void URLFetcherCore::OnResponseStarted(URLRequest* request) {
392 DCHECK_EQ(request, request_.get());
393 DCHECK(network_task_runner_->BelongsToCurrentThread());
394 if (request_->status().is_success()) {
395 response_code_ = request_->GetResponseCode();
396 response_headers_ = request_->response_headers();
397 socket_address_ = request_->GetSocketAddress();
398 was_fetched_via_proxy_ = request_->was_fetched_via_proxy();
399 total_response_bytes_ = request_->GetExpectedContentSize();
405 void URLFetcherCore::OnCertificateRequested(
407 SSLCertRequestInfo* cert_request_info) {
408 DCHECK_EQ(request, request_.get());
409 DCHECK(network_task_runner_->BelongsToCurrentThread());
411 if (g_ignore_certificate_requests) {
412 request->ContinueWithCertificate(NULL);
418 void URLFetcherCore::OnReadCompleted(URLRequest* request,
420 DCHECK(request == request_);
421 DCHECK(network_task_runner_->BelongsToCurrentThread());
423 if (!stopped_on_redirect_)
424 url_ = request->url();
425 URLRequestThrottlerManager* throttler_manager =
426 request->context()->throttler_manager();
427 if (throttler_manager) {
428 url_throttler_entry_ = throttler_manager->RegisterRequestUrl(url_);
432 if (!request_->status().is_success() || bytes_read <= 0)
435 current_response_bytes_ += bytes_read;
436 InformDelegateDownloadProgress();
439 WriteBuffer(new DrainableIOBuffer(buffer_.get(), bytes_read));
441 // Write failed or waiting for write completion.
444 } while (request_->Read(buffer_.get(), kBufferSize, &bytes_read));
446 const URLRequestStatus status = request_->status();
448 if (status.is_success())
449 request_->GetResponseCookies(&cookies_);
451 // See comments re: HEAD requests in ReadResponse().
452 if (!status.is_io_pending() || request_type_ == URLFetcher::HEAD) {
456 // No more data to write.
457 const int result = response_writer_->Finish(
458 base::Bind(&URLFetcherCore::DidFinishWriting, this));
459 if (result != ERR_IO_PENDING)
460 DidFinishWriting(result);
464 void URLFetcherCore::CancelAll() {
465 g_registry.Get().CancelAll();
468 int URLFetcherCore::GetNumFetcherCores() {
469 return g_registry.Get().size();
472 void URLFetcherCore::SetEnableInterceptionForTests(bool enabled) {
473 g_interception_enabled = enabled;
476 void URLFetcherCore::SetIgnoreCertificateRequests(bool ignored) {
477 g_ignore_certificate_requests = ignored;
480 URLFetcherCore::~URLFetcherCore() {
481 // |request_| should be NULL. If not, it's unsafe to delete it here since we
482 // may not be on the IO thread.
483 DCHECK(!request_.get());
486 void URLFetcherCore::StartOnIOThread() {
487 DCHECK(network_task_runner_->BelongsToCurrentThread());
489 if (!response_writer_)
490 response_writer_.reset(new URLFetcherStringWriter);
492 const int result = response_writer_->Initialize(
493 base::Bind(&URLFetcherCore::DidInitializeWriter, this));
494 if (result != ERR_IO_PENDING)
495 DidInitializeWriter(result);
498 void URLFetcherCore::StartURLRequest() {
499 DCHECK(network_task_runner_->BelongsToCurrentThread());
501 if (was_cancelled_) {
502 // Since StartURLRequest() is posted as a *delayed* task, it may
503 // run after the URLFetcher was already stopped.
507 DCHECK(request_context_getter_.get());
508 DCHECK(!request_.get());
510 g_registry.Get().AddURLFetcherCore(this);
511 current_response_bytes_ = 0;
512 request_ = request_context_getter_->GetURLRequestContext()->CreateRequest(
513 original_url_, DEFAULT_PRIORITY, this, NULL);
514 request_->set_stack_trace(stack_trace_);
515 int flags = request_->load_flags() | load_flags_;
516 if (!g_interception_enabled)
517 flags = flags | LOAD_DISABLE_INTERCEPT;
519 if (is_chunked_upload_)
520 request_->EnableChunkedUpload();
521 request_->SetLoadFlags(flags);
522 request_->SetReferrer(referrer_);
523 request_->set_referrer_policy(referrer_policy_);
524 request_->set_first_party_for_cookies(first_party_for_cookies_.is_empty() ?
525 original_url_ : first_party_for_cookies_);
526 if (url_request_data_key_ && !url_request_create_data_callback_.is_null()) {
527 request_->SetUserData(url_request_data_key_,
528 url_request_create_data_callback_.Run());
531 switch (request_type_) {
532 case URLFetcher::GET:
535 case URLFetcher::POST:
536 case URLFetcher::PUT:
537 case URLFetcher::PATCH:
538 // Upload content must be set.
539 DCHECK(is_chunked_upload_ || upload_content_set_);
541 request_->set_method(
542 request_type_ == URLFetcher::POST ? "POST" :
543 request_type_ == URLFetcher::PUT ? "PUT" : "PATCH");
544 if (!upload_content_type_.empty()) {
545 extra_request_headers_.SetHeader(HttpRequestHeaders::kContentType,
546 upload_content_type_);
548 if (!upload_content_.empty()) {
549 scoped_ptr<UploadElementReader> reader(new UploadBytesElementReader(
550 upload_content_.data(), upload_content_.size()));
551 request_->set_upload(make_scoped_ptr(
552 UploadDataStream::CreateWithReader(reader.Pass(), 0)));
553 } else if (!upload_file_path_.empty()) {
554 scoped_ptr<UploadElementReader> reader(
555 new UploadFileElementReader(upload_file_task_runner_.get(),
557 upload_range_offset_,
558 upload_range_length_,
560 request_->set_upload(make_scoped_ptr(
561 UploadDataStream::CreateWithReader(reader.Pass(), 0)));
564 current_upload_bytes_ = -1;
565 // TODO(kinaba): http://crbug.com/118103. Implement upload callback in the
566 // layer and avoid using timer here.
567 upload_progress_checker_timer_.reset(
568 new base::RepeatingTimer<URLFetcherCore>());
569 upload_progress_checker_timer_->Start(
571 base::TimeDelta::FromMilliseconds(kUploadProgressTimerInterval),
573 &URLFetcherCore::InformDelegateUploadProgress);
576 case URLFetcher::HEAD:
577 request_->set_method("HEAD");
580 case URLFetcher::DELETE_REQUEST:
581 request_->set_method("DELETE");
588 if (!extra_request_headers_.IsEmpty())
589 request_->SetExtraRequestHeaders(extra_request_headers_);
594 void URLFetcherCore::DidInitializeWriter(int result) {
596 CancelURLRequest(result);
597 delegate_task_runner_->PostTask(
599 base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this));
602 StartURLRequestWhenAppropriate();
605 void URLFetcherCore::StartURLRequestWhenAppropriate() {
606 DCHECK(network_task_runner_->BelongsToCurrentThread());
611 DCHECK(request_context_getter_.get());
613 int64 delay = INT64_C(0);
614 if (!original_url_throttler_entry_.get()) {
615 URLRequestThrottlerManager* manager =
616 request_context_getter_->GetURLRequestContext()->throttler_manager();
618 original_url_throttler_entry_ =
619 manager->RegisterRequestUrl(original_url_);
622 if (original_url_throttler_entry_.get()) {
623 delay = original_url_throttler_entry_->ReserveSendingTimeForNextRequest(
624 GetBackoffReleaseTime());
627 if (delay == INT64_C(0)) {
630 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
631 FROM_HERE, base::Bind(&URLFetcherCore::StartURLRequest, this),
632 base::TimeDelta::FromMilliseconds(delay));
636 void URLFetcherCore::CancelURLRequest(int error) {
637 DCHECK(network_task_runner_->BelongsToCurrentThread());
639 if (request_.get()) {
640 request_->CancelWithError(error);
644 // Set the error manually.
645 // Normally, calling URLRequest::CancelWithError() results in calling
646 // OnReadCompleted() with bytes_read = -1 via an asynchronous task posted by
647 // URLRequestJob::NotifyDone(). But, because the request was released
648 // immediately after being canceled, the request could not call
649 // OnReadCompleted() which overwrites |status_| with the error status.
650 status_.set_status(URLRequestStatus::CANCELED);
651 status_.set_error(error);
653 // Release the reference to the request context. There could be multiple
654 // references to URLFetcher::Core at this point so it may take a while to
655 // delete the object, but we cannot delay the destruction of the request
657 request_context_getter_ = NULL;
658 first_party_for_cookies_ = GURL();
659 url_request_data_key_ = NULL;
660 url_request_create_data_callback_.Reset();
661 was_cancelled_ = true;
664 void URLFetcherCore::OnCompletedURLRequest(
665 base::TimeDelta backoff_delay) {
666 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
668 // Save the status and backoff_delay so that delegates can read it.
670 backoff_delay_ = backoff_delay;
671 InformDelegateFetchIsComplete();
675 void URLFetcherCore::InformDelegateFetchIsComplete() {
676 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
678 delegate_->OnURLFetchComplete(fetcher_);
681 void URLFetcherCore::NotifyMalformedContent() {
682 DCHECK(network_task_runner_->BelongsToCurrentThread());
683 if (url_throttler_entry_.get()) {
684 int status_code = response_code_;
685 if (status_code == URLFetcher::RESPONSE_CODE_INVALID) {
686 // The status code will generally be known by the time clients
687 // call the |ReceivedContentWasMalformed()| function (which ends up
688 // calling the current function) but if it's not, we need to assume
689 // the response was successful so that the total failure count
690 // used to calculate exponential back-off goes up.
693 url_throttler_entry_->ReceivedContentWasMalformed(status_code);
697 void URLFetcherCore::DidFinishWriting(int result) {
699 CancelURLRequest(result);
700 delegate_task_runner_->PostTask(
702 base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this));
705 // If the file was successfully closed, then the URL request is complete.
706 RetryOrCompleteUrlFetch();
709 void URLFetcherCore::RetryOrCompleteUrlFetch() {
710 DCHECK(network_task_runner_->BelongsToCurrentThread());
711 base::TimeDelta backoff_delay;
713 // Checks the response from server.
714 if (response_code_ >= 500 ||
715 status_.error() == ERR_TEMPORARILY_THROTTLED) {
716 // When encountering a server error, we will send the request again
717 // after backoff time.
718 ++num_retries_on_5xx_;
720 // Note that backoff_delay may be 0 because (a) the
721 // URLRequestThrottlerManager and related code does not
722 // necessarily back off on the first error, (b) it only backs off
723 // on some of the 5xx status codes, (c) not all URLRequestContexts
724 // have a throttler manager.
725 base::TimeTicks backoff_release_time = GetBackoffReleaseTime();
726 backoff_delay = backoff_release_time - base::TimeTicks::Now();
727 if (backoff_delay < base::TimeDelta())
728 backoff_delay = base::TimeDelta();
730 if (automatically_retry_on_5xx_ &&
731 num_retries_on_5xx_ <= max_retries_on_5xx_) {
736 backoff_delay = base::TimeDelta();
739 // Retry if the request failed due to network changes.
740 if (status_.error() == ERR_NETWORK_CHANGED &&
741 num_retries_on_network_changes_ < max_retries_on_network_changes_) {
742 ++num_retries_on_network_changes_;
744 // Retry soon, after flushing all the current tasks which may include
745 // further network change observers.
746 network_task_runner_->PostTask(
747 FROM_HERE, base::Bind(&URLFetcherCore::StartOnIOThread, this));
751 request_context_getter_ = NULL;
752 first_party_for_cookies_ = GURL();
753 url_request_data_key_ = NULL;
754 url_request_create_data_callback_.Reset();
755 bool posted = delegate_task_runner_->PostTask(
757 base::Bind(&URLFetcherCore::OnCompletedURLRequest, this, backoff_delay));
759 // If the delegate message loop does not exist any more, then the delegate
760 // should be gone too.
761 DCHECK(posted || !delegate_);
764 void URLFetcherCore::ReleaseRequest() {
765 upload_progress_checker_timer_.reset();
767 g_registry.Get().RemoveURLFetcherCore(this);
770 base::TimeTicks URLFetcherCore::GetBackoffReleaseTime() {
771 DCHECK(network_task_runner_->BelongsToCurrentThread());
773 if (!original_url_throttler_entry_.get())
774 return base::TimeTicks();
776 base::TimeTicks original_url_backoff =
777 original_url_throttler_entry_->GetExponentialBackoffReleaseTime();
778 base::TimeTicks destination_url_backoff;
779 if (url_throttler_entry_.get() &&
780 original_url_throttler_entry_.get() != url_throttler_entry_.get()) {
781 destination_url_backoff =
782 url_throttler_entry_->GetExponentialBackoffReleaseTime();
785 return original_url_backoff > destination_url_backoff ?
786 original_url_backoff : destination_url_backoff;
789 void URLFetcherCore::CompleteAddingUploadDataChunk(
790 const std::string& content, bool is_last_chunk) {
791 if (was_cancelled_) {
792 // Since CompleteAddingUploadDataChunk() is posted as a *delayed* task, it
793 // may run after the URLFetcher was already stopped.
796 DCHECK(is_chunked_upload_);
797 DCHECK(request_.get());
798 DCHECK(!content.empty());
799 request_->AppendChunkToUpload(content.data(),
800 static_cast<int>(content.length()),
804 int URLFetcherCore::WriteBuffer(scoped_refptr<DrainableIOBuffer> data) {
805 while (data->BytesRemaining() > 0) {
806 const int result = response_writer_->Write(
808 data->BytesRemaining(),
809 base::Bind(&URLFetcherCore::DidWriteBuffer, this, data));
811 if (result != ERR_IO_PENDING)
812 DidWriteBuffer(data, result);
815 data->DidConsume(result);
820 void URLFetcherCore::DidWriteBuffer(scoped_refptr<DrainableIOBuffer> data,
822 if (result < 0) { // Handle errors.
823 CancelURLRequest(result);
824 response_writer_->Finish(base::Bind(&EmptyCompletionCallback));
825 delegate_task_runner_->PostTask(
827 base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this));
832 data->DidConsume(result);
833 if (WriteBuffer(data) < 0)
836 // Finished writing buffer_. Read some more, unless the request has been
837 // cancelled and deleted.
838 DCHECK_EQ(0, data->BytesRemaining());
843 void URLFetcherCore::ReadResponse() {
844 // Some servers may treat HEAD requests as GET requests. To free up the
845 // network connection as soon as possible, signal that the request has
846 // completed immediately, without trying to read any data back (all we care
847 // about is the response code and headers, which we already have).
849 if (request_->status().is_success() &&
850 (request_type_ != URLFetcher::HEAD)) {
851 if (!request_->Read(buffer_.get(), kBufferSize, &bytes_read))
852 bytes_read = -1; // Match OnReadCompleted() interface contract.
854 OnReadCompleted(request_.get(), bytes_read);
857 void URLFetcherCore::InformDelegateUploadProgress() {
858 DCHECK(network_task_runner_->BelongsToCurrentThread());
859 if (request_.get()) {
860 int64 current = request_->GetUploadProgress().position();
861 if (current_upload_bytes_ != current) {
862 current_upload_bytes_ = current;
864 if (!is_chunked_upload_) {
865 total = static_cast<int64>(request_->GetUploadProgress().size());
866 // Total may be zero if the UploadDataStream::Init has not been called
867 // yet. Don't send the upload progress until the size is initialized.
871 delegate_task_runner_->PostTask(
874 &URLFetcherCore::InformDelegateUploadProgressInDelegateThread,
875 this, current, total));
880 void URLFetcherCore::InformDelegateUploadProgressInDelegateThread(
881 int64 current, int64 total) {
882 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
884 delegate_->OnURLFetchUploadProgress(fetcher_, current, total);
887 void URLFetcherCore::InformDelegateDownloadProgress() {
888 DCHECK(network_task_runner_->BelongsToCurrentThread());
889 delegate_task_runner_->PostTask(
892 &URLFetcherCore::InformDelegateDownloadProgressInDelegateThread,
893 this, current_response_bytes_, total_response_bytes_));
896 void URLFetcherCore::InformDelegateDownloadProgressInDelegateThread(
897 int64 current, int64 total) {
898 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
900 delegate_->OnURLFetchDownloadProgress(fetcher_, current, total);