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"
8 #include "base/logging.h"
9 #include "base/metrics/histogram.h"
10 #include "base/sequenced_task_runner.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/stl_util.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/tracked_objects.h"
15 #include "net/base/io_buffer.h"
16 #include "net/base/load_flags.h"
17 #include "net/base/net_errors.h"
18 #include "net/base/request_priority.h"
19 #include "net/base/upload_bytes_element_reader.h"
20 #include "net/base/upload_data_stream.h"
21 #include "net/base/upload_file_element_reader.h"
22 #include "net/http/http_response_headers.h"
23 #include "net/url_request/redirect_info.h"
24 #include "net/url_request/url_fetcher_delegate.h"
25 #include "net/url_request/url_fetcher_response_writer.h"
26 #include "net/url_request/url_request_context.h"
27 #include "net/url_request/url_request_context_getter.h"
28 #include "net/url_request/url_request_throttler_manager.h"
32 const int kBufferSize = 4096;
33 const int kUploadProgressTimerInterval = 100;
34 bool g_interception_enabled = false;
35 bool g_ignore_certificate_requests = false;
37 void EmptyCompletionCallback(int result) {}
43 // URLFetcherCore::Registry ---------------------------------------------------
45 URLFetcherCore::Registry::Registry() {}
46 URLFetcherCore::Registry::~Registry() {}
48 void URLFetcherCore::Registry::AddURLFetcherCore(URLFetcherCore* core) {
49 DCHECK(!ContainsKey(fetchers_, core));
50 fetchers_.insert(core);
53 void URLFetcherCore::Registry::RemoveURLFetcherCore(URLFetcherCore* core) {
54 DCHECK(ContainsKey(fetchers_, core));
55 fetchers_.erase(core);
58 void URLFetcherCore::Registry::CancelAll() {
59 while (!fetchers_.empty())
60 (*fetchers_.begin())->CancelURLRequest(ERR_ABORTED);
63 // URLFetcherCore -------------------------------------------------------------
66 base::LazyInstance<URLFetcherCore::Registry>
67 URLFetcherCore::g_registry = LAZY_INSTANCE_INITIALIZER;
69 URLFetcherCore::URLFetcherCore(URLFetcher* fetcher,
70 const GURL& original_url,
71 URLFetcher::RequestType request_type,
72 URLFetcherDelegate* d)
74 original_url_(original_url),
75 request_type_(request_type),
77 delegate_task_runner_(base::ThreadTaskRunnerHandle::Get()),
78 load_flags_(LOAD_NORMAL),
79 response_code_(URLFetcher::RESPONSE_CODE_INVALID),
80 buffer_(new IOBuffer(kBufferSize)),
81 url_request_data_key_(NULL),
82 was_fetched_via_proxy_(false),
83 upload_content_set_(false),
84 upload_range_offset_(0),
85 upload_range_length_(0),
87 URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE),
88 is_chunked_upload_(false),
89 was_cancelled_(false),
90 stop_on_redirect_(false),
91 stopped_on_redirect_(false),
92 automatically_retry_on_5xx_(true),
93 num_retries_on_5xx_(0),
94 max_retries_on_5xx_(0),
95 num_retries_on_network_changes_(0),
96 max_retries_on_network_changes_(0),
97 current_upload_bytes_(-1),
98 current_response_bytes_(0),
99 total_response_bytes_(-1) {
100 CHECK(original_url_.is_valid());
103 void URLFetcherCore::Start() {
104 DCHECK(delegate_task_runner_.get());
105 DCHECK(request_context_getter_.get()) << "We need an URLRequestContext!";
106 if (network_task_runner_.get()) {
107 DCHECK_EQ(network_task_runner_,
108 request_context_getter_->GetNetworkTaskRunner());
110 network_task_runner_ = request_context_getter_->GetNetworkTaskRunner();
112 DCHECK(network_task_runner_.get()) << "We need an IO task runner";
114 network_task_runner_->PostTask(
115 FROM_HERE, base::Bind(&URLFetcherCore::StartOnIOThread, this));
118 void URLFetcherCore::Stop() {
119 if (delegate_task_runner_.get()) // May be NULL in tests.
120 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
124 if (!network_task_runner_.get())
126 if (network_task_runner_->RunsTasksOnCurrentThread()) {
127 CancelURLRequest(ERR_ABORTED);
129 network_task_runner_->PostTask(
131 base::Bind(&URLFetcherCore::CancelURLRequest, this, ERR_ABORTED));
135 void URLFetcherCore::SetUploadData(const std::string& upload_content_type,
136 const std::string& upload_content) {
137 DCHECK(!is_chunked_upload_);
138 DCHECK(!upload_content_set_);
139 DCHECK(upload_content_.empty());
140 DCHECK(upload_file_path_.empty());
141 DCHECK(upload_content_type_.empty());
143 // Empty |upload_content_type| is allowed iff the |upload_content| is empty.
144 DCHECK(upload_content.empty() || !upload_content_type.empty());
146 upload_content_type_ = upload_content_type;
147 upload_content_ = upload_content;
148 upload_content_set_ = true;
151 void URLFetcherCore::SetUploadFilePath(
152 const std::string& upload_content_type,
153 const base::FilePath& file_path,
156 scoped_refptr<base::TaskRunner> file_task_runner) {
157 DCHECK(!is_chunked_upload_);
158 DCHECK(!upload_content_set_);
159 DCHECK(upload_content_.empty());
160 DCHECK(upload_file_path_.empty());
161 DCHECK_EQ(upload_range_offset_, 0ULL);
162 DCHECK_EQ(upload_range_length_, 0ULL);
163 DCHECK(upload_content_type_.empty());
164 DCHECK(!upload_content_type.empty());
166 upload_content_type_ = upload_content_type;
167 upload_file_path_ = file_path;
168 upload_range_offset_ = range_offset;
169 upload_range_length_ = range_length;
170 upload_file_task_runner_ = file_task_runner;
171 upload_content_set_ = true;
174 void URLFetcherCore::SetChunkedUpload(const std::string& content_type) {
175 DCHECK(is_chunked_upload_ ||
176 (upload_content_type_.empty() &&
177 upload_content_.empty()));
179 // Empty |content_type| is not allowed here, because it is impossible
180 // to ensure non-empty upload content as it is not yet supplied.
181 DCHECK(!content_type.empty());
183 upload_content_type_ = content_type;
184 upload_content_.clear();
185 is_chunked_upload_ = true;
188 void URLFetcherCore::AppendChunkToUpload(const std::string& content,
189 bool is_last_chunk) {
190 DCHECK(delegate_task_runner_.get());
191 DCHECK(network_task_runner_.get());
192 network_task_runner_->PostTask(
194 base::Bind(&URLFetcherCore::CompleteAddingUploadDataChunk, this, content,
198 void URLFetcherCore::SetLoadFlags(int load_flags) {
199 load_flags_ = load_flags;
202 int URLFetcherCore::GetLoadFlags() const {
206 void URLFetcherCore::SetReferrer(const std::string& referrer) {
207 referrer_ = referrer;
210 void URLFetcherCore::SetReferrerPolicy(
211 URLRequest::ReferrerPolicy referrer_policy) {
212 referrer_policy_ = referrer_policy;
215 void URLFetcherCore::SetExtraRequestHeaders(
216 const std::string& extra_request_headers) {
217 extra_request_headers_.Clear();
218 extra_request_headers_.AddHeadersFromString(extra_request_headers);
221 void URLFetcherCore::AddExtraRequestHeader(const std::string& header_line) {
222 extra_request_headers_.AddHeaderFromString(header_line);
225 void URLFetcherCore::SetRequestContext(
226 URLRequestContextGetter* request_context_getter) {
227 DCHECK(!request_context_getter_.get());
228 DCHECK(request_context_getter);
229 request_context_getter_ = request_context_getter;
232 void URLFetcherCore::SetFirstPartyForCookies(
233 const GURL& first_party_for_cookies) {
234 DCHECK(first_party_for_cookies_.is_empty());
235 first_party_for_cookies_ = first_party_for_cookies;
238 void URLFetcherCore::SetURLRequestUserData(
240 const URLFetcher::CreateDataCallback& create_data_callback) {
242 DCHECK(!create_data_callback.is_null());
243 url_request_data_key_ = key;
244 url_request_create_data_callback_ = create_data_callback;
247 void URLFetcherCore::SetStopOnRedirect(bool stop_on_redirect) {
248 stop_on_redirect_ = stop_on_redirect;
251 void URLFetcherCore::SetAutomaticallyRetryOn5xx(bool retry) {
252 automatically_retry_on_5xx_ = retry;
255 void URLFetcherCore::SetMaxRetriesOn5xx(int max_retries) {
256 max_retries_on_5xx_ = max_retries;
259 int URLFetcherCore::GetMaxRetriesOn5xx() const {
260 return max_retries_on_5xx_;
263 base::TimeDelta URLFetcherCore::GetBackoffDelay() const {
264 return backoff_delay_;
267 void URLFetcherCore::SetAutomaticallyRetryOnNetworkChanges(int max_retries) {
268 max_retries_on_network_changes_ = max_retries;
271 void URLFetcherCore::SaveResponseToFileAtPath(
272 const base::FilePath& file_path,
273 scoped_refptr<base::SequencedTaskRunner> file_task_runner) {
274 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
275 SaveResponseWithWriter(scoped_ptr<URLFetcherResponseWriter>(
276 new URLFetcherFileWriter(file_task_runner, file_path)));
279 void URLFetcherCore::SaveResponseToTemporaryFile(
280 scoped_refptr<base::SequencedTaskRunner> file_task_runner) {
281 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
282 SaveResponseWithWriter(scoped_ptr<URLFetcherResponseWriter>(
283 new URLFetcherFileWriter(file_task_runner, base::FilePath())));
286 void URLFetcherCore::SaveResponseWithWriter(
287 scoped_ptr<URLFetcherResponseWriter> response_writer) {
288 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
289 response_writer_ = response_writer.Pass();
292 HttpResponseHeaders* URLFetcherCore::GetResponseHeaders() const {
293 return response_headers_.get();
296 // TODO(panayiotis): socket_address_ is written in the IO thread,
297 // if this is accessed in the UI thread, this could result in a race.
298 // Same for response_headers_ above and was_fetched_via_proxy_ below.
299 HostPortPair URLFetcherCore::GetSocketAddress() const {
300 return socket_address_;
303 bool URLFetcherCore::WasFetchedViaProxy() const {
304 return was_fetched_via_proxy_;
307 const GURL& URLFetcherCore::GetOriginalURL() const {
308 return original_url_;
311 const GURL& URLFetcherCore::GetURL() const {
315 const URLRequestStatus& URLFetcherCore::GetStatus() const {
319 int URLFetcherCore::GetResponseCode() const {
320 return response_code_;
323 const ResponseCookies& URLFetcherCore::GetCookies() const {
327 void URLFetcherCore::ReceivedContentWasMalformed() {
328 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
329 if (network_task_runner_.get()) {
330 network_task_runner_->PostTask(
331 FROM_HERE, base::Bind(&URLFetcherCore::NotifyMalformedContent, this));
335 bool URLFetcherCore::GetResponseAsString(
336 std::string* out_response_string) const {
337 URLFetcherStringWriter* string_writer =
338 response_writer_ ? response_writer_->AsStringWriter() : NULL;
342 *out_response_string = string_writer->data();
343 UMA_HISTOGRAM_MEMORY_KB("UrlFetcher.StringResponseSize",
344 (string_writer->data().length() / 1024));
348 bool URLFetcherCore::GetResponseAsFilePath(bool take_ownership,
349 base::FilePath* out_response_path) {
350 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
352 URLFetcherFileWriter* file_writer =
353 response_writer_ ? response_writer_->AsFileWriter() : NULL;
357 *out_response_path = file_writer->file_path();
359 if (take_ownership) {
360 // Intentionally calling a file_writer_ method directly without posting
361 // the task to network_task_runner_.
363 // This is for correctly handling the case when file_writer_->DisownFile()
364 // is soon followed by URLFetcherCore::Stop(). We have to make sure that
365 // DisownFile takes effect before Stop deletes file_writer_.
367 // This direct call should be thread-safe, since DisownFile itself does no
368 // file operation. It just flips the state to be referred in destruction.
369 file_writer->DisownFile();
374 void URLFetcherCore::OnReceivedRedirect(URLRequest* request,
375 const RedirectInfo& redirect_info,
376 bool* defer_redirect) {
377 DCHECK_EQ(request, request_.get());
378 DCHECK(network_task_runner_->BelongsToCurrentThread());
379 if (stop_on_redirect_) {
380 stopped_on_redirect_ = true;
381 url_ = redirect_info.new_url;
382 response_code_ = request_->GetResponseCode();
383 was_fetched_via_proxy_ = request_->was_fetched_via_proxy();
385 OnReadCompleted(request, 0);
389 void URLFetcherCore::OnResponseStarted(URLRequest* request) {
390 DCHECK_EQ(request, request_.get());
391 DCHECK(network_task_runner_->BelongsToCurrentThread());
392 if (request_->status().is_success()) {
393 response_code_ = request_->GetResponseCode();
394 response_headers_ = request_->response_headers();
395 socket_address_ = request_->GetSocketAddress();
396 was_fetched_via_proxy_ = request_->was_fetched_via_proxy();
397 total_response_bytes_ = request_->GetExpectedContentSize();
403 void URLFetcherCore::OnCertificateRequested(
405 SSLCertRequestInfo* cert_request_info) {
406 DCHECK_EQ(request, request_.get());
407 DCHECK(network_task_runner_->BelongsToCurrentThread());
409 if (g_ignore_certificate_requests) {
410 request->ContinueWithCertificate(NULL);
416 void URLFetcherCore::OnReadCompleted(URLRequest* request,
418 DCHECK(request == request_);
419 DCHECK(network_task_runner_->BelongsToCurrentThread());
421 if (!stopped_on_redirect_)
422 url_ = request->url();
423 URLRequestThrottlerManager* throttler_manager =
424 request->context()->throttler_manager();
425 if (throttler_manager) {
426 url_throttler_entry_ = throttler_manager->RegisterRequestUrl(url_);
430 if (!request_->status().is_success() || bytes_read <= 0)
433 current_response_bytes_ += bytes_read;
434 InformDelegateDownloadProgress();
437 WriteBuffer(new DrainableIOBuffer(buffer_.get(), bytes_read));
439 // Write failed or waiting for write completion.
442 } while (request_->Read(buffer_.get(), kBufferSize, &bytes_read));
444 const URLRequestStatus status = request_->status();
446 if (status.is_success())
447 request_->GetResponseCookies(&cookies_);
449 // See comments re: HEAD requests in ReadResponse().
450 if (!status.is_io_pending() || request_type_ == URLFetcher::HEAD) {
454 // No more data to write.
455 const int result = response_writer_->Finish(
456 base::Bind(&URLFetcherCore::DidFinishWriting, this));
457 if (result != ERR_IO_PENDING)
458 DidFinishWriting(result);
462 void URLFetcherCore::CancelAll() {
463 g_registry.Get().CancelAll();
466 int URLFetcherCore::GetNumFetcherCores() {
467 return g_registry.Get().size();
470 void URLFetcherCore::SetEnableInterceptionForTests(bool enabled) {
471 g_interception_enabled = enabled;
474 void URLFetcherCore::SetIgnoreCertificateRequests(bool ignored) {
475 g_ignore_certificate_requests = ignored;
478 URLFetcherCore::~URLFetcherCore() {
479 // |request_| should be NULL. If not, it's unsafe to delete it here since we
480 // may not be on the IO thread.
481 DCHECK(!request_.get());
484 void URLFetcherCore::StartOnIOThread() {
485 DCHECK(network_task_runner_->BelongsToCurrentThread());
487 if (!response_writer_)
488 response_writer_.reset(new URLFetcherStringWriter);
490 const int result = response_writer_->Initialize(
491 base::Bind(&URLFetcherCore::DidInitializeWriter, this));
492 if (result != ERR_IO_PENDING)
493 DidInitializeWriter(result);
496 void URLFetcherCore::StartURLRequest() {
497 DCHECK(network_task_runner_->BelongsToCurrentThread());
499 if (was_cancelled_) {
500 // Since StartURLRequest() is posted as a *delayed* task, it may
501 // run after the URLFetcher was already stopped.
505 DCHECK(request_context_getter_.get());
506 DCHECK(!request_.get());
508 g_registry.Get().AddURLFetcherCore(this);
509 current_response_bytes_ = 0;
510 request_ = request_context_getter_->GetURLRequestContext()->CreateRequest(
511 original_url_, DEFAULT_PRIORITY, this, NULL);
512 request_->set_stack_trace(stack_trace_);
513 int flags = request_->load_flags() | load_flags_;
514 if (!g_interception_enabled)
515 flags = flags | LOAD_DISABLE_INTERCEPT;
517 if (is_chunked_upload_)
518 request_->EnableChunkedUpload();
519 request_->SetLoadFlags(flags);
520 request_->SetReferrer(referrer_);
521 request_->set_referrer_policy(referrer_policy_);
522 request_->set_first_party_for_cookies(first_party_for_cookies_.is_empty() ?
523 original_url_ : first_party_for_cookies_);
524 if (url_request_data_key_ && !url_request_create_data_callback_.is_null()) {
525 request_->SetUserData(url_request_data_key_,
526 url_request_create_data_callback_.Run());
529 switch (request_type_) {
530 case URLFetcher::GET:
533 case URLFetcher::POST:
534 case URLFetcher::PUT:
535 case URLFetcher::PATCH:
536 // Upload content must be set.
537 DCHECK(is_chunked_upload_ || upload_content_set_);
539 request_->set_method(
540 request_type_ == URLFetcher::POST ? "POST" :
541 request_type_ == URLFetcher::PUT ? "PUT" : "PATCH");
542 if (!upload_content_type_.empty()) {
543 extra_request_headers_.SetHeader(HttpRequestHeaders::kContentType,
544 upload_content_type_);
546 if (!upload_content_.empty()) {
547 scoped_ptr<UploadElementReader> reader(new UploadBytesElementReader(
548 upload_content_.data(), upload_content_.size()));
549 request_->set_upload(make_scoped_ptr(
550 UploadDataStream::CreateWithReader(reader.Pass(), 0)));
551 } else if (!upload_file_path_.empty()) {
552 scoped_ptr<UploadElementReader> reader(
553 new UploadFileElementReader(upload_file_task_runner_.get(),
555 upload_range_offset_,
556 upload_range_length_,
558 request_->set_upload(make_scoped_ptr(
559 UploadDataStream::CreateWithReader(reader.Pass(), 0)));
562 current_upload_bytes_ = -1;
563 // TODO(kinaba): http://crbug.com/118103. Implement upload callback in the
564 // layer and avoid using timer here.
565 upload_progress_checker_timer_.reset(
566 new base::RepeatingTimer<URLFetcherCore>());
567 upload_progress_checker_timer_->Start(
569 base::TimeDelta::FromMilliseconds(kUploadProgressTimerInterval),
571 &URLFetcherCore::InformDelegateUploadProgress);
574 case URLFetcher::HEAD:
575 request_->set_method("HEAD");
578 case URLFetcher::DELETE_REQUEST:
579 request_->set_method("DELETE");
586 if (!extra_request_headers_.IsEmpty())
587 request_->SetExtraRequestHeaders(extra_request_headers_);
592 void URLFetcherCore::DidInitializeWriter(int result) {
594 CancelURLRequest(result);
595 delegate_task_runner_->PostTask(
597 base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this));
600 StartURLRequestWhenAppropriate();
603 void URLFetcherCore::StartURLRequestWhenAppropriate() {
604 DCHECK(network_task_runner_->BelongsToCurrentThread());
609 DCHECK(request_context_getter_.get());
612 if (original_url_throttler_entry_.get() == NULL) {
613 URLRequestThrottlerManager* manager =
614 request_context_getter_->GetURLRequestContext()->throttler_manager();
616 original_url_throttler_entry_ =
617 manager->RegisterRequestUrl(original_url_);
620 if (original_url_throttler_entry_.get() != NULL) {
621 delay = original_url_throttler_entry_->ReserveSendingTimeForNextRequest(
622 GetBackoffReleaseTime());
628 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
629 FROM_HERE, base::Bind(&URLFetcherCore::StartURLRequest, this),
630 base::TimeDelta::FromMilliseconds(delay));
634 void URLFetcherCore::CancelURLRequest(int error) {
635 DCHECK(network_task_runner_->BelongsToCurrentThread());
637 if (request_.get()) {
638 request_->CancelWithError(error);
642 // Set the error manually.
643 // Normally, calling URLRequest::CancelWithError() results in calling
644 // OnReadCompleted() with bytes_read = -1 via an asynchronous task posted by
645 // URLRequestJob::NotifyDone(). But, because the request was released
646 // immediately after being canceled, the request could not call
647 // OnReadCompleted() which overwrites |status_| with the error status.
648 status_.set_status(URLRequestStatus::CANCELED);
649 status_.set_error(error);
651 // Release the reference to the request context. There could be multiple
652 // references to URLFetcher::Core at this point so it may take a while to
653 // delete the object, but we cannot delay the destruction of the request
655 request_context_getter_ = NULL;
656 first_party_for_cookies_ = GURL();
657 url_request_data_key_ = NULL;
658 url_request_create_data_callback_.Reset();
659 was_cancelled_ = true;
662 void URLFetcherCore::OnCompletedURLRequest(
663 base::TimeDelta backoff_delay) {
664 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
666 // Save the status and backoff_delay so that delegates can read it.
668 backoff_delay_ = backoff_delay;
669 InformDelegateFetchIsComplete();
673 void URLFetcherCore::InformDelegateFetchIsComplete() {
674 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
676 delegate_->OnURLFetchComplete(fetcher_);
679 void URLFetcherCore::NotifyMalformedContent() {
680 DCHECK(network_task_runner_->BelongsToCurrentThread());
681 if (url_throttler_entry_.get() != NULL) {
682 int status_code = response_code_;
683 if (status_code == URLFetcher::RESPONSE_CODE_INVALID) {
684 // The status code will generally be known by the time clients
685 // call the |ReceivedContentWasMalformed()| function (which ends up
686 // calling the current function) but if it's not, we need to assume
687 // the response was successful so that the total failure count
688 // used to calculate exponential back-off goes up.
691 url_throttler_entry_->ReceivedContentWasMalformed(status_code);
695 void URLFetcherCore::DidFinishWriting(int result) {
697 CancelURLRequest(result);
698 delegate_task_runner_->PostTask(
700 base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this));
703 // If the file was successfully closed, then the URL request is complete.
704 RetryOrCompleteUrlFetch();
707 void URLFetcherCore::RetryOrCompleteUrlFetch() {
708 DCHECK(network_task_runner_->BelongsToCurrentThread());
709 base::TimeDelta backoff_delay;
711 // Checks the response from server.
712 if (response_code_ >= 500 ||
713 status_.error() == ERR_TEMPORARILY_THROTTLED) {
714 // When encountering a server error, we will send the request again
715 // after backoff time.
716 ++num_retries_on_5xx_;
718 // Note that backoff_delay may be 0 because (a) the
719 // URLRequestThrottlerManager and related code does not
720 // necessarily back off on the first error, (b) it only backs off
721 // on some of the 5xx status codes, (c) not all URLRequestContexts
722 // have a throttler manager.
723 base::TimeTicks backoff_release_time = GetBackoffReleaseTime();
724 backoff_delay = backoff_release_time - base::TimeTicks::Now();
725 if (backoff_delay < base::TimeDelta())
726 backoff_delay = base::TimeDelta();
728 if (automatically_retry_on_5xx_ &&
729 num_retries_on_5xx_ <= max_retries_on_5xx_) {
734 backoff_delay = base::TimeDelta();
737 // Retry if the request failed due to network changes.
738 if (status_.error() == ERR_NETWORK_CHANGED &&
739 num_retries_on_network_changes_ < max_retries_on_network_changes_) {
740 ++num_retries_on_network_changes_;
742 // Retry soon, after flushing all the current tasks which may include
743 // further network change observers.
744 network_task_runner_->PostTask(
745 FROM_HERE, base::Bind(&URLFetcherCore::StartOnIOThread, this));
749 request_context_getter_ = NULL;
750 first_party_for_cookies_ = GURL();
751 url_request_data_key_ = NULL;
752 url_request_create_data_callback_.Reset();
753 bool posted = delegate_task_runner_->PostTask(
755 base::Bind(&URLFetcherCore::OnCompletedURLRequest, this, backoff_delay));
757 // If the delegate message loop does not exist any more, then the delegate
758 // should be gone too.
759 DCHECK(posted || !delegate_);
762 void URLFetcherCore::ReleaseRequest() {
763 upload_progress_checker_timer_.reset();
765 g_registry.Get().RemoveURLFetcherCore(this);
768 base::TimeTicks URLFetcherCore::GetBackoffReleaseTime() {
769 DCHECK(network_task_runner_->BelongsToCurrentThread());
771 if (original_url_throttler_entry_.get()) {
772 base::TimeTicks original_url_backoff =
773 original_url_throttler_entry_->GetExponentialBackoffReleaseTime();
774 base::TimeTicks destination_url_backoff;
775 if (url_throttler_entry_.get() != NULL &&
776 original_url_throttler_entry_.get() != url_throttler_entry_.get()) {
777 destination_url_backoff =
778 url_throttler_entry_->GetExponentialBackoffReleaseTime();
781 return original_url_backoff > destination_url_backoff ?
782 original_url_backoff : destination_url_backoff;
784 return base::TimeTicks();
788 void URLFetcherCore::CompleteAddingUploadDataChunk(
789 const std::string& content, bool is_last_chunk) {
790 if (was_cancelled_) {
791 // Since CompleteAddingUploadDataChunk() is posted as a *delayed* task, it
792 // may run after the URLFetcher was already stopped.
795 DCHECK(is_chunked_upload_);
796 DCHECK(request_.get());
797 DCHECK(!content.empty());
798 request_->AppendChunkToUpload(content.data(),
799 static_cast<int>(content.length()),
803 int URLFetcherCore::WriteBuffer(scoped_refptr<DrainableIOBuffer> data) {
804 while (data->BytesRemaining() > 0) {
805 const int result = response_writer_->Write(
807 data->BytesRemaining(),
808 base::Bind(&URLFetcherCore::DidWriteBuffer, this, data));
810 if (result != ERR_IO_PENDING)
811 DidWriteBuffer(data, result);
814 data->DidConsume(result);
819 void URLFetcherCore::DidWriteBuffer(scoped_refptr<DrainableIOBuffer> data,
821 if (result < 0) { // Handle errors.
822 CancelURLRequest(result);
823 response_writer_->Finish(base::Bind(&EmptyCompletionCallback));
824 delegate_task_runner_->PostTask(
826 base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this));
831 data->DidConsume(result);
832 if (WriteBuffer(data) < 0)
835 // Finished writing buffer_. Read some more, unless the request has been
836 // cancelled and deleted.
837 DCHECK_EQ(0, data->BytesRemaining());
842 void URLFetcherCore::ReadResponse() {
843 // Some servers may treat HEAD requests as GET requests. To free up the
844 // network connection as soon as possible, signal that the request has
845 // completed immediately, without trying to read any data back (all we care
846 // about is the response code and headers, which we already have).
848 if (request_->status().is_success() &&
849 (request_type_ != URLFetcher::HEAD))
850 request_->Read(buffer_.get(), kBufferSize, &bytes_read);
851 OnReadCompleted(request_.get(), bytes_read);
854 void URLFetcherCore::InformDelegateUploadProgress() {
855 DCHECK(network_task_runner_->BelongsToCurrentThread());
856 if (request_.get()) {
857 int64 current = request_->GetUploadProgress().position();
858 if (current_upload_bytes_ != current) {
859 current_upload_bytes_ = current;
861 if (!is_chunked_upload_) {
862 total = static_cast<int64>(request_->GetUploadProgress().size());
863 // Total may be zero if the UploadDataStream::Init has not been called
864 // yet. Don't send the upload progress until the size is initialized.
868 delegate_task_runner_->PostTask(
871 &URLFetcherCore::InformDelegateUploadProgressInDelegateThread,
872 this, current, total));
877 void URLFetcherCore::InformDelegateUploadProgressInDelegateThread(
878 int64 current, int64 total) {
879 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
881 delegate_->OnURLFetchUploadProgress(fetcher_, current, total);
884 void URLFetcherCore::InformDelegateDownloadProgress() {
885 DCHECK(network_task_runner_->BelongsToCurrentThread());
886 delegate_task_runner_->PostTask(
889 &URLFetcherCore::InformDelegateDownloadProgressInDelegateThread,
890 this, current_response_bytes_, total_response_bytes_));
893 void URLFetcherCore::InformDelegateDownloadProgressInDelegateThread(
894 int64 current, int64 total) {
895 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
897 delegate_->OnURLFetchDownloadProgress(fetcher_, current, total);