Index: net/url_request/url_fetcher_core.cc |
diff --git a/net/url_request/url_fetcher_core.cc b/net/url_request/url_fetcher_core.cc |
deleted file mode 100644 |
index 23857ad057427b2f5efc2282090c14ba53ed14c8..0000000000000000000000000000000000000000 |
--- a/net/url_request/url_fetcher_core.cc |
+++ /dev/null |
@@ -1,998 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "net/url_request/url_fetcher_core.h" |
- |
-#include <stdint.h> |
- |
-#include "base/bind.h" |
-#include "base/logging.h" |
-#include "base/metrics/histogram.h" |
-#include "base/profiler/scoped_tracker.h" |
-#include "base/sequenced_task_runner.h" |
-#include "base/single_thread_task_runner.h" |
-#include "base/stl_util.h" |
-#include "base/thread_task_runner_handle.h" |
-#include "base/tracked_objects.h" |
-#include "net/base/elements_upload_data_stream.h" |
-#include "net/base/io_buffer.h" |
-#include "net/base/load_flags.h" |
-#include "net/base/net_errors.h" |
-#include "net/base/request_priority.h" |
-#include "net/base/upload_bytes_element_reader.h" |
-#include "net/base/upload_data_stream.h" |
-#include "net/base/upload_file_element_reader.h" |
-#include "net/http/http_response_headers.h" |
-#include "net/url_request/redirect_info.h" |
-#include "net/url_request/url_fetcher_delegate.h" |
-#include "net/url_request/url_fetcher_response_writer.h" |
-#include "net/url_request/url_request_context.h" |
-#include "net/url_request/url_request_context_getter.h" |
-#include "net/url_request/url_request_throttler_manager.h" |
- |
-namespace { |
- |
-const int kBufferSize = 4096; |
-const int kUploadProgressTimerInterval = 100; |
-bool g_ignore_certificate_requests = false; |
- |
-void EmptyCompletionCallback(int result) {} |
- |
-} // namespace |
- |
-namespace net { |
- |
-// URLFetcherCore::Registry --------------------------------------------------- |
- |
-URLFetcherCore::Registry::Registry() {} |
-URLFetcherCore::Registry::~Registry() {} |
- |
-void URLFetcherCore::Registry::AddURLFetcherCore(URLFetcherCore* core) { |
- DCHECK(!ContainsKey(fetchers_, core)); |
- fetchers_.insert(core); |
-} |
- |
-void URLFetcherCore::Registry::RemoveURLFetcherCore(URLFetcherCore* core) { |
- DCHECK(ContainsKey(fetchers_, core)); |
- fetchers_.erase(core); |
-} |
- |
-void URLFetcherCore::Registry::CancelAll() { |
- while (!fetchers_.empty()) |
- (*fetchers_.begin())->CancelURLRequest(ERR_ABORTED); |
-} |
- |
-// URLFetcherCore ------------------------------------------------------------- |
- |
-// static |
-base::LazyInstance<URLFetcherCore::Registry> |
- URLFetcherCore::g_registry = LAZY_INSTANCE_INITIALIZER; |
- |
-URLFetcherCore::URLFetcherCore(URLFetcher* fetcher, |
- const GURL& original_url, |
- URLFetcher::RequestType request_type, |
- URLFetcherDelegate* d) |
- : fetcher_(fetcher), |
- original_url_(original_url), |
- request_type_(request_type), |
- delegate_(d), |
- delegate_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
- load_flags_(LOAD_NORMAL), |
- response_code_(URLFetcher::RESPONSE_CODE_INVALID), |
- buffer_(new IOBuffer(kBufferSize)), |
- url_request_data_key_(NULL), |
- was_fetched_via_proxy_(false), |
- upload_content_set_(false), |
- upload_range_offset_(0), |
- upload_range_length_(0), |
- referrer_policy_( |
- URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE), |
- is_chunked_upload_(false), |
- was_cancelled_(false), |
- stop_on_redirect_(false), |
- stopped_on_redirect_(false), |
- automatically_retry_on_5xx_(true), |
- num_retries_on_5xx_(0), |
- max_retries_on_5xx_(0), |
- num_retries_on_network_changes_(0), |
- max_retries_on_network_changes_(0), |
- current_upload_bytes_(-1), |
- current_response_bytes_(0), |
- total_response_bytes_(-1) { |
- CHECK(original_url_.is_valid()); |
-} |
- |
-void URLFetcherCore::Start() { |
- DCHECK(delegate_task_runner_.get()); |
- DCHECK(request_context_getter_.get()) << "We need an URLRequestContext!"; |
- if (network_task_runner_.get()) { |
- DCHECK_EQ(network_task_runner_, |
- request_context_getter_->GetNetworkTaskRunner()); |
- } else { |
- network_task_runner_ = request_context_getter_->GetNetworkTaskRunner(); |
- } |
- DCHECK(network_task_runner_.get()) << "We need an IO task runner"; |
- |
- network_task_runner_->PostTask( |
- FROM_HERE, base::Bind(&URLFetcherCore::StartOnIOThread, this)); |
-} |
- |
-void URLFetcherCore::Stop() { |
- if (delegate_task_runner_.get()) // May be NULL in tests. |
- DCHECK(delegate_task_runner_->BelongsToCurrentThread()); |
- |
- delegate_ = NULL; |
- fetcher_ = NULL; |
- if (!network_task_runner_.get()) |
- return; |
- if (network_task_runner_->RunsTasksOnCurrentThread()) { |
- CancelURLRequest(ERR_ABORTED); |
- } else { |
- network_task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind(&URLFetcherCore::CancelURLRequest, this, ERR_ABORTED)); |
- } |
-} |
- |
-void URLFetcherCore::SetUploadData(const std::string& upload_content_type, |
- const std::string& upload_content) { |
- AssertHasNoUploadData(); |
- DCHECK(!is_chunked_upload_); |
- DCHECK(upload_content_type_.empty()); |
- |
- // Empty |upload_content_type| is allowed iff the |upload_content| is empty. |
- DCHECK(upload_content.empty() || !upload_content_type.empty()); |
- |
- upload_content_type_ = upload_content_type; |
- upload_content_ = upload_content; |
- upload_content_set_ = true; |
-} |
- |
-void URLFetcherCore::SetUploadFilePath( |
- const std::string& upload_content_type, |
- const base::FilePath& file_path, |
- uint64 range_offset, |
- uint64 range_length, |
- scoped_refptr<base::TaskRunner> file_task_runner) { |
- AssertHasNoUploadData(); |
- DCHECK(!is_chunked_upload_); |
- DCHECK_EQ(upload_range_offset_, 0ULL); |
- DCHECK_EQ(upload_range_length_, 0ULL); |
- DCHECK(upload_content_type_.empty()); |
- DCHECK(!upload_content_type.empty()); |
- |
- upload_content_type_ = upload_content_type; |
- upload_file_path_ = file_path; |
- upload_range_offset_ = range_offset; |
- upload_range_length_ = range_length; |
- upload_file_task_runner_ = file_task_runner; |
- upload_content_set_ = true; |
-} |
- |
-void URLFetcherCore::SetUploadStreamFactory( |
- const std::string& upload_content_type, |
- const URLFetcher::CreateUploadStreamCallback& factory) { |
- AssertHasNoUploadData(); |
- DCHECK(!is_chunked_upload_); |
- DCHECK(upload_content_type_.empty()); |
- |
- upload_content_type_ = upload_content_type; |
- upload_stream_factory_ = factory; |
- upload_content_set_ = true; |
-} |
- |
-void URLFetcherCore::SetChunkedUpload(const std::string& content_type) { |
- if (!is_chunked_upload_) { |
- AssertHasNoUploadData(); |
- DCHECK(upload_content_type_.empty()); |
- } |
- |
- // Empty |content_type| is not allowed here, because it is impossible |
- // to ensure non-empty upload content as it is not yet supplied. |
- DCHECK(!content_type.empty()); |
- |
- upload_content_type_ = content_type; |
- upload_content_.clear(); |
- is_chunked_upload_ = true; |
-} |
- |
-void URLFetcherCore::AppendChunkToUpload(const std::string& content, |
- bool is_last_chunk) { |
- DCHECK(delegate_task_runner_.get()); |
- DCHECK(network_task_runner_.get()); |
- network_task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind(&URLFetcherCore::CompleteAddingUploadDataChunk, this, content, |
- is_last_chunk)); |
-} |
- |
-void URLFetcherCore::SetLoadFlags(int load_flags) { |
- load_flags_ = load_flags; |
-} |
- |
-int URLFetcherCore::GetLoadFlags() const { |
- return load_flags_; |
-} |
- |
-void URLFetcherCore::SetReferrer(const std::string& referrer) { |
- referrer_ = referrer; |
-} |
- |
-void URLFetcherCore::SetReferrerPolicy( |
- URLRequest::ReferrerPolicy referrer_policy) { |
- referrer_policy_ = referrer_policy; |
-} |
- |
-void URLFetcherCore::SetExtraRequestHeaders( |
- const std::string& extra_request_headers) { |
- extra_request_headers_.Clear(); |
- extra_request_headers_.AddHeadersFromString(extra_request_headers); |
-} |
- |
-void URLFetcherCore::AddExtraRequestHeader(const std::string& header_line) { |
- extra_request_headers_.AddHeaderFromString(header_line); |
-} |
- |
-void URLFetcherCore::SetRequestContext( |
- URLRequestContextGetter* request_context_getter) { |
- DCHECK(!request_context_getter_.get()); |
- DCHECK(request_context_getter); |
- request_context_getter_ = request_context_getter; |
-} |
- |
-void URLFetcherCore::SetFirstPartyForCookies( |
- const GURL& first_party_for_cookies) { |
- DCHECK(first_party_for_cookies_.is_empty()); |
- first_party_for_cookies_ = first_party_for_cookies; |
-} |
- |
-void URLFetcherCore::SetURLRequestUserData( |
- const void* key, |
- const URLFetcher::CreateDataCallback& create_data_callback) { |
- DCHECK(key); |
- DCHECK(!create_data_callback.is_null()); |
- url_request_data_key_ = key; |
- url_request_create_data_callback_ = create_data_callback; |
-} |
- |
-void URLFetcherCore::SetStopOnRedirect(bool stop_on_redirect) { |
- stop_on_redirect_ = stop_on_redirect; |
-} |
- |
-void URLFetcherCore::SetAutomaticallyRetryOn5xx(bool retry) { |
- automatically_retry_on_5xx_ = retry; |
-} |
- |
-void URLFetcherCore::SetMaxRetriesOn5xx(int max_retries) { |
- max_retries_on_5xx_ = max_retries; |
-} |
- |
-int URLFetcherCore::GetMaxRetriesOn5xx() const { |
- return max_retries_on_5xx_; |
-} |
- |
-base::TimeDelta URLFetcherCore::GetBackoffDelay() const { |
- return backoff_delay_; |
-} |
- |
-void URLFetcherCore::SetAutomaticallyRetryOnNetworkChanges(int max_retries) { |
- max_retries_on_network_changes_ = max_retries; |
-} |
- |
-void URLFetcherCore::SaveResponseToFileAtPath( |
- const base::FilePath& file_path, |
- scoped_refptr<base::SequencedTaskRunner> file_task_runner) { |
- DCHECK(delegate_task_runner_->BelongsToCurrentThread()); |
- SaveResponseWithWriter(scoped_ptr<URLFetcherResponseWriter>( |
- new URLFetcherFileWriter(file_task_runner, file_path))); |
-} |
- |
-void URLFetcherCore::SaveResponseToTemporaryFile( |
- scoped_refptr<base::SequencedTaskRunner> file_task_runner) { |
- DCHECK(delegate_task_runner_->BelongsToCurrentThread()); |
- SaveResponseWithWriter(scoped_ptr<URLFetcherResponseWriter>( |
- new URLFetcherFileWriter(file_task_runner, base::FilePath()))); |
-} |
- |
-void URLFetcherCore::SaveResponseWithWriter( |
- scoped_ptr<URLFetcherResponseWriter> response_writer) { |
- DCHECK(delegate_task_runner_->BelongsToCurrentThread()); |
- response_writer_ = response_writer.Pass(); |
-} |
- |
-HttpResponseHeaders* URLFetcherCore::GetResponseHeaders() const { |
- return response_headers_.get(); |
-} |
- |
-// TODO(panayiotis): socket_address_ is written in the IO thread, |
-// if this is accessed in the UI thread, this could result in a race. |
-// Same for response_headers_ above and was_fetched_via_proxy_ below. |
-HostPortPair URLFetcherCore::GetSocketAddress() const { |
- return socket_address_; |
-} |
- |
-bool URLFetcherCore::WasFetchedViaProxy() const { |
- return was_fetched_via_proxy_; |
-} |
- |
-const GURL& URLFetcherCore::GetOriginalURL() const { |
- return original_url_; |
-} |
- |
-const GURL& URLFetcherCore::GetURL() const { |
- return url_; |
-} |
- |
-const URLRequestStatus& URLFetcherCore::GetStatus() const { |
- return status_; |
-} |
- |
-int URLFetcherCore::GetResponseCode() const { |
- return response_code_; |
-} |
- |
-const ResponseCookies& URLFetcherCore::GetCookies() const { |
- return cookies_; |
-} |
- |
-void URLFetcherCore::ReceivedContentWasMalformed() { |
- DCHECK(delegate_task_runner_->BelongsToCurrentThread()); |
- if (network_task_runner_.get()) { |
- network_task_runner_->PostTask( |
- FROM_HERE, base::Bind(&URLFetcherCore::NotifyMalformedContent, this)); |
- } |
-} |
- |
-bool URLFetcherCore::GetResponseAsString( |
- std::string* out_response_string) const { |
- URLFetcherStringWriter* string_writer = |
- response_writer_ ? response_writer_->AsStringWriter() : NULL; |
- if (!string_writer) |
- return false; |
- |
- *out_response_string = string_writer->data(); |
- UMA_HISTOGRAM_MEMORY_KB("UrlFetcher.StringResponseSize", |
- (string_writer->data().length() / 1024)); |
- return true; |
-} |
- |
-bool URLFetcherCore::GetResponseAsFilePath(bool take_ownership, |
- base::FilePath* out_response_path) { |
- DCHECK(delegate_task_runner_->BelongsToCurrentThread()); |
- |
- URLFetcherFileWriter* file_writer = |
- response_writer_ ? response_writer_->AsFileWriter() : NULL; |
- if (!file_writer) |
- return false; |
- |
- *out_response_path = file_writer->file_path(); |
- |
- if (take_ownership) { |
- // Intentionally calling a file_writer_ method directly without posting |
- // the task to network_task_runner_. |
- // |
- // This is for correctly handling the case when file_writer_->DisownFile() |
- // is soon followed by URLFetcherCore::Stop(). We have to make sure that |
- // DisownFile takes effect before Stop deletes file_writer_. |
- // |
- // This direct call should be thread-safe, since DisownFile itself does no |
- // file operation. It just flips the state to be referred in destruction. |
- file_writer->DisownFile(); |
- } |
- return true; |
-} |
- |
-void URLFetcherCore::OnReceivedRedirect(URLRequest* request, |
- const RedirectInfo& redirect_info, |
- bool* defer_redirect) { |
- DCHECK_EQ(request, request_.get()); |
- DCHECK(network_task_runner_->BelongsToCurrentThread()); |
- if (stop_on_redirect_) { |
- stopped_on_redirect_ = true; |
- url_ = redirect_info.new_url; |
- response_code_ = request_->GetResponseCode(); |
- was_fetched_via_proxy_ = request_->was_fetched_via_proxy(); |
- request->Cancel(); |
- OnReadCompleted(request, 0); |
- } |
-} |
- |
-void URLFetcherCore::OnResponseStarted(URLRequest* request) { |
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. |
- tracked_objects::ScopedTracker tracking_profile( |
- FROM_HERE_WITH_EXPLICIT_FUNCTION( |
- "423948 URLFetcherCore::OnResponseStarted")); |
- |
- DCHECK_EQ(request, request_.get()); |
- DCHECK(network_task_runner_->BelongsToCurrentThread()); |
- if (request_->status().is_success()) { |
- response_code_ = request_->GetResponseCode(); |
- response_headers_ = request_->response_headers(); |
- socket_address_ = request_->GetSocketAddress(); |
- was_fetched_via_proxy_ = request_->was_fetched_via_proxy(); |
- total_response_bytes_ = request_->GetExpectedContentSize(); |
- } |
- |
- ReadResponse(); |
-} |
- |
-void URLFetcherCore::OnCertificateRequested( |
- URLRequest* request, |
- SSLCertRequestInfo* cert_request_info) { |
- DCHECK_EQ(request, request_.get()); |
- DCHECK(network_task_runner_->BelongsToCurrentThread()); |
- |
- if (g_ignore_certificate_requests) { |
- request->ContinueWithCertificate(NULL); |
- } else { |
- request->Cancel(); |
- } |
-} |
- |
-void URLFetcherCore::OnReadCompleted(URLRequest* request, |
- int bytes_read) { |
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. |
- tracked_objects::ScopedTracker tracking_profile( |
- FROM_HERE_WITH_EXPLICIT_FUNCTION( |
- "423948 URLFetcherCore::OnReadCompleted")); |
- |
- DCHECK(request == request_); |
- DCHECK(network_task_runner_->BelongsToCurrentThread()); |
- |
- if (!stopped_on_redirect_) |
- url_ = request->url(); |
- URLRequestThrottlerManager* throttler_manager = |
- request->context()->throttler_manager(); |
- if (throttler_manager) { |
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. |
- tracked_objects::ScopedTracker tracking_profile1( |
- FROM_HERE_WITH_EXPLICIT_FUNCTION( |
- "423948 URLFetcherCore::OnReadCompleted1")); |
- |
- url_throttler_entry_ = throttler_manager->RegisterRequestUrl(url_); |
- } |
- |
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. |
- tracked_objects::ScopedTracker tracking_profile2( |
- FROM_HERE_WITH_EXPLICIT_FUNCTION( |
- "423948 URLFetcherCore::OnReadCompleted2")); |
- |
- do { |
- if (!request_->status().is_success() || bytes_read <= 0) |
- break; |
- |
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. |
- tracked_objects::ScopedTracker tracking_profile3( |
- FROM_HERE_WITH_EXPLICIT_FUNCTION( |
- "423948 URLFetcherCore::OnReadCompleted3")); |
- |
- current_response_bytes_ += bytes_read; |
- InformDelegateDownloadProgress(); |
- |
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. |
- tracked_objects::ScopedTracker tracking_profile4( |
- FROM_HERE_WITH_EXPLICIT_FUNCTION( |
- "423948 URLFetcherCore::OnReadCompleted4")); |
- |
- const int result = |
- WriteBuffer(new DrainableIOBuffer(buffer_.get(), bytes_read)); |
- if (result < 0) { |
- // Write failed or waiting for write completion. |
- return; |
- } |
- } while (request_->Read(buffer_.get(), kBufferSize, &bytes_read)); |
- |
- const URLRequestStatus status = request_->status(); |
- |
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. |
- tracked_objects::ScopedTracker tracking_profile5( |
- FROM_HERE_WITH_EXPLICIT_FUNCTION( |
- "423948 URLFetcherCore::OnReadCompleted5")); |
- |
- if (status.is_success()) |
- request_->GetResponseCookies(&cookies_); |
- |
- // See comments re: HEAD requests in ReadResponse(). |
- if (!status.is_io_pending() || request_type_ == URLFetcher::HEAD) { |
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. |
- tracked_objects::ScopedTracker tracking_profile6( |
- FROM_HERE_WITH_EXPLICIT_FUNCTION( |
- "423948 URLFetcherCore::OnReadCompleted6")); |
- |
- status_ = status; |
- ReleaseRequest(); |
- |
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. |
- tracked_objects::ScopedTracker tracking_profile7( |
- FROM_HERE_WITH_EXPLICIT_FUNCTION( |
- "423948 URLFetcherCore::OnReadCompleted7")); |
- |
- // No more data to write. |
- const int result = response_writer_->Finish( |
- base::Bind(&URLFetcherCore::DidFinishWriting, this)); |
- |
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. |
- tracked_objects::ScopedTracker tracking_profile8( |
- FROM_HERE_WITH_EXPLICIT_FUNCTION( |
- "423948 URLFetcherCore::OnReadCompleted8")); |
- |
- if (result != ERR_IO_PENDING) |
- DidFinishWriting(result); |
- } |
-} |
- |
-void URLFetcherCore::CancelAll() { |
- g_registry.Get().CancelAll(); |
-} |
- |
-int URLFetcherCore::GetNumFetcherCores() { |
- return g_registry.Get().size(); |
-} |
- |
-void URLFetcherCore::SetIgnoreCertificateRequests(bool ignored) { |
- g_ignore_certificate_requests = ignored; |
-} |
- |
-URLFetcherCore::~URLFetcherCore() { |
- // |request_| should be NULL. If not, it's unsafe to delete it here since we |
- // may not be on the IO thread. |
- DCHECK(!request_.get()); |
-} |
- |
-void URLFetcherCore::StartOnIOThread() { |
- // TODO(pkasting): Remove ScopedTracker below once crbug.com/456327 is fixed. |
- tracked_objects::ScopedTracker tracking_profile( |
- FROM_HERE_WITH_EXPLICIT_FUNCTION( |
- "456327 URLFetcherCore::StartOnIOThread")); |
- DCHECK(network_task_runner_->BelongsToCurrentThread()); |
- |
- if (!response_writer_) |
- response_writer_.reset(new URLFetcherStringWriter); |
- |
- const int result = response_writer_->Initialize( |
- base::Bind(&URLFetcherCore::DidInitializeWriter, this)); |
- if (result != ERR_IO_PENDING) |
- DidInitializeWriter(result); |
-} |
- |
-void URLFetcherCore::StartURLRequest() { |
- // TODO(pkasting): Remove ScopedTracker below once crbug.com/456327 is fixed. |
- tracked_objects::ScopedTracker tracking_profile( |
- FROM_HERE_WITH_EXPLICIT_FUNCTION( |
- "456327 URLFetcherCore::StartURLRequest")); |
- DCHECK(network_task_runner_->BelongsToCurrentThread()); |
- |
- if (was_cancelled_) { |
- // Since StartURLRequest() is posted as a *delayed* task, it may |
- // run after the URLFetcher was already stopped. |
- return; |
- } |
- |
- DCHECK(request_context_getter_.get()); |
- DCHECK(!request_.get()); |
- |
- g_registry.Get().AddURLFetcherCore(this); |
- current_response_bytes_ = 0; |
- request_ = request_context_getter_->GetURLRequestContext()->CreateRequest( |
- original_url_, DEFAULT_PRIORITY, this, NULL); |
- request_->set_stack_trace(stack_trace_); |
- int flags = request_->load_flags() | load_flags_; |
- |
- if (is_chunked_upload_) |
- request_->EnableChunkedUpload(); |
- request_->SetLoadFlags(flags); |
- request_->SetReferrer(referrer_); |
- request_->set_referrer_policy(referrer_policy_); |
- request_->set_first_party_for_cookies(first_party_for_cookies_.is_empty() ? |
- original_url_ : first_party_for_cookies_); |
- if (url_request_data_key_ && !url_request_create_data_callback_.is_null()) { |
- request_->SetUserData(url_request_data_key_, |
- url_request_create_data_callback_.Run()); |
- } |
- |
- switch (request_type_) { |
- case URLFetcher::GET: |
- break; |
- |
- case URLFetcher::POST: |
- case URLFetcher::PUT: |
- case URLFetcher::PATCH: |
- // Upload content must be set. |
- DCHECK(is_chunked_upload_ || upload_content_set_); |
- |
- request_->set_method( |
- request_type_ == URLFetcher::POST ? "POST" : |
- request_type_ == URLFetcher::PUT ? "PUT" : "PATCH"); |
- if (!upload_content_type_.empty()) { |
- extra_request_headers_.SetHeader(HttpRequestHeaders::kContentType, |
- upload_content_type_); |
- } |
- if (!upload_content_.empty()) { |
- scoped_ptr<UploadElementReader> reader(new UploadBytesElementReader( |
- upload_content_.data(), upload_content_.size())); |
- request_->set_upload( |
- ElementsUploadDataStream::CreateWithReader(reader.Pass(), 0)); |
- } else if (!upload_file_path_.empty()) { |
- scoped_ptr<UploadElementReader> reader( |
- new UploadFileElementReader(upload_file_task_runner_.get(), |
- upload_file_path_, |
- upload_range_offset_, |
- upload_range_length_, |
- base::Time())); |
- request_->set_upload( |
- ElementsUploadDataStream::CreateWithReader(reader.Pass(), 0)); |
- } else if (!upload_stream_factory_.is_null()) { |
- scoped_ptr<UploadDataStream> stream = upload_stream_factory_.Run(); |
- DCHECK(stream); |
- request_->set_upload(stream.Pass()); |
- } |
- |
- current_upload_bytes_ = -1; |
- // TODO(kinaba): http://crbug.com/118103. Implement upload callback in the |
- // layer and avoid using timer here. |
- upload_progress_checker_timer_.reset( |
- new base::RepeatingTimer<URLFetcherCore>()); |
- upload_progress_checker_timer_->Start( |
- FROM_HERE, |
- base::TimeDelta::FromMilliseconds(kUploadProgressTimerInterval), |
- this, |
- &URLFetcherCore::InformDelegateUploadProgress); |
- break; |
- |
- case URLFetcher::HEAD: |
- request_->set_method("HEAD"); |
- break; |
- |
- case URLFetcher::DELETE_REQUEST: |
- request_->set_method("DELETE"); |
- break; |
- |
- default: |
- NOTREACHED(); |
- } |
- |
- if (!extra_request_headers_.IsEmpty()) |
- request_->SetExtraRequestHeaders(extra_request_headers_); |
- |
- request_->Start(); |
-} |
- |
-void URLFetcherCore::DidInitializeWriter(int result) { |
- if (result != OK) { |
- CancelURLRequest(result); |
- delegate_task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this)); |
- return; |
- } |
- StartURLRequestWhenAppropriate(); |
-} |
- |
-void URLFetcherCore::StartURLRequestWhenAppropriate() { |
- DCHECK(network_task_runner_->BelongsToCurrentThread()); |
- |
- if (was_cancelled_) |
- return; |
- |
- DCHECK(request_context_getter_.get()); |
- |
- int64 delay = 0; |
- if (!original_url_throttler_entry_.get()) { |
- // TODO(pkasting): Remove ScopedTracker below once crbug.com/456327 is |
- // fixed. |
- tracked_objects::ScopedTracker tracking_profile1( |
- FROM_HERE_WITH_EXPLICIT_FUNCTION( |
- "456327 URLFetcherCore::StartURLRequestWhenAppropriate1")); |
- URLRequestThrottlerManager* manager = |
- request_context_getter_->GetURLRequestContext()->throttler_manager(); |
- if (manager) { |
- original_url_throttler_entry_ = |
- manager->RegisterRequestUrl(original_url_); |
- } |
- } |
- if (original_url_throttler_entry_.get()) { |
- // TODO(pkasting): Remove ScopedTracker below once crbug.com/456327 is |
- // fixed. |
- tracked_objects::ScopedTracker tracking_profile2( |
- FROM_HERE_WITH_EXPLICIT_FUNCTION( |
- "456327 URLFetcherCore::StartURLRequestWhenAppropriate2")); |
- delay = original_url_throttler_entry_->ReserveSendingTimeForNextRequest( |
- GetBackoffReleaseTime()); |
- } |
- |
- if (delay == 0) { |
- StartURLRequest(); |
- } else { |
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
- FROM_HERE, base::Bind(&URLFetcherCore::StartURLRequest, this), |
- base::TimeDelta::FromMilliseconds(delay)); |
- } |
-} |
- |
-void URLFetcherCore::CancelURLRequest(int error) { |
- DCHECK(network_task_runner_->BelongsToCurrentThread()); |
- |
- if (request_.get()) { |
- request_->CancelWithError(error); |
- ReleaseRequest(); |
- } |
- |
- // Set the error manually. |
- // Normally, calling URLRequest::CancelWithError() results in calling |
- // OnReadCompleted() with bytes_read = -1 via an asynchronous task posted by |
- // URLRequestJob::NotifyDone(). But, because the request was released |
- // immediately after being canceled, the request could not call |
- // OnReadCompleted() which overwrites |status_| with the error status. |
- status_.set_status(URLRequestStatus::CANCELED); |
- status_.set_error(error); |
- |
- // Release the reference to the request context. There could be multiple |
- // references to URLFetcher::Core at this point so it may take a while to |
- // delete the object, but we cannot delay the destruction of the request |
- // context. |
- request_context_getter_ = NULL; |
- first_party_for_cookies_ = GURL(); |
- url_request_data_key_ = NULL; |
- url_request_create_data_callback_.Reset(); |
- was_cancelled_ = true; |
-} |
- |
-void URLFetcherCore::OnCompletedURLRequest( |
- base::TimeDelta backoff_delay) { |
- DCHECK(delegate_task_runner_->BelongsToCurrentThread()); |
- |
- // Save the status and backoff_delay so that delegates can read it. |
- if (delegate_) { |
- backoff_delay_ = backoff_delay; |
- InformDelegateFetchIsComplete(); |
- } |
-} |
- |
-void URLFetcherCore::InformDelegateFetchIsComplete() { |
- DCHECK(delegate_task_runner_->BelongsToCurrentThread()); |
- if (delegate_) |
- delegate_->OnURLFetchComplete(fetcher_); |
-} |
- |
-void URLFetcherCore::NotifyMalformedContent() { |
- DCHECK(network_task_runner_->BelongsToCurrentThread()); |
- if (url_throttler_entry_.get()) { |
- int status_code = response_code_; |
- if (status_code == URLFetcher::RESPONSE_CODE_INVALID) { |
- // The status code will generally be known by the time clients |
- // call the |ReceivedContentWasMalformed()| function (which ends up |
- // calling the current function) but if it's not, we need to assume |
- // the response was successful so that the total failure count |
- // used to calculate exponential back-off goes up. |
- status_code = 200; |
- } |
- url_throttler_entry_->ReceivedContentWasMalformed(status_code); |
- } |
-} |
- |
-void URLFetcherCore::DidFinishWriting(int result) { |
- if (result != OK) { |
- CancelURLRequest(result); |
- delegate_task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this)); |
- return; |
- } |
- // If the file was successfully closed, then the URL request is complete. |
- RetryOrCompleteUrlFetch(); |
-} |
- |
-void URLFetcherCore::RetryOrCompleteUrlFetch() { |
- DCHECK(network_task_runner_->BelongsToCurrentThread()); |
- base::TimeDelta backoff_delay; |
- |
- // Checks the response from server. |
- if (response_code_ >= 500 || |
- status_.error() == ERR_TEMPORARILY_THROTTLED) { |
- // When encountering a server error, we will send the request again |
- // after backoff time. |
- ++num_retries_on_5xx_; |
- |
- // Note that backoff_delay may be 0 because (a) the |
- // URLRequestThrottlerManager and related code does not |
- // necessarily back off on the first error, (b) it only backs off |
- // on some of the 5xx status codes, (c) not all URLRequestContexts |
- // have a throttler manager. |
- base::TimeTicks backoff_release_time = GetBackoffReleaseTime(); |
- backoff_delay = backoff_release_time - base::TimeTicks::Now(); |
- if (backoff_delay < base::TimeDelta()) |
- backoff_delay = base::TimeDelta(); |
- |
- if (automatically_retry_on_5xx_ && |
- num_retries_on_5xx_ <= max_retries_on_5xx_) { |
- StartOnIOThread(); |
- return; |
- } |
- } else { |
- backoff_delay = base::TimeDelta(); |
- } |
- |
- // Retry if the request failed due to network changes. |
- if (status_.error() == ERR_NETWORK_CHANGED && |
- num_retries_on_network_changes_ < max_retries_on_network_changes_) { |
- ++num_retries_on_network_changes_; |
- |
- // Retry soon, after flushing all the current tasks which may include |
- // further network change observers. |
- network_task_runner_->PostTask( |
- FROM_HERE, base::Bind(&URLFetcherCore::StartOnIOThread, this)); |
- return; |
- } |
- |
- request_context_getter_ = NULL; |
- first_party_for_cookies_ = GURL(); |
- url_request_data_key_ = NULL; |
- url_request_create_data_callback_.Reset(); |
- bool posted = delegate_task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind(&URLFetcherCore::OnCompletedURLRequest, this, backoff_delay)); |
- |
- // If the delegate message loop does not exist any more, then the delegate |
- // should be gone too. |
- DCHECK(posted || !delegate_); |
-} |
- |
-void URLFetcherCore::ReleaseRequest() { |
- upload_progress_checker_timer_.reset(); |
- request_.reset(); |
- g_registry.Get().RemoveURLFetcherCore(this); |
-} |
- |
-base::TimeTicks URLFetcherCore::GetBackoffReleaseTime() { |
- DCHECK(network_task_runner_->BelongsToCurrentThread()); |
- |
- if (!original_url_throttler_entry_.get()) |
- return base::TimeTicks(); |
- |
- base::TimeTicks original_url_backoff = |
- original_url_throttler_entry_->GetExponentialBackoffReleaseTime(); |
- base::TimeTicks destination_url_backoff; |
- if (url_throttler_entry_.get() && |
- original_url_throttler_entry_.get() != url_throttler_entry_.get()) { |
- destination_url_backoff = |
- url_throttler_entry_->GetExponentialBackoffReleaseTime(); |
- } |
- |
- return original_url_backoff > destination_url_backoff ? |
- original_url_backoff : destination_url_backoff; |
-} |
- |
-void URLFetcherCore::CompleteAddingUploadDataChunk( |
- const std::string& content, bool is_last_chunk) { |
- if (was_cancelled_) { |
- // Since CompleteAddingUploadDataChunk() is posted as a *delayed* task, it |
- // may run after the URLFetcher was already stopped. |
- return; |
- } |
- DCHECK(is_chunked_upload_); |
- DCHECK(request_.get()); |
- DCHECK(!content.empty()); |
- request_->AppendChunkToUpload(content.data(), |
- static_cast<int>(content.length()), |
- is_last_chunk); |
-} |
- |
-int URLFetcherCore::WriteBuffer(scoped_refptr<DrainableIOBuffer> data) { |
- while (data->BytesRemaining() > 0) { |
- const int result = response_writer_->Write( |
- data.get(), |
- data->BytesRemaining(), |
- base::Bind(&URLFetcherCore::DidWriteBuffer, this, data)); |
- if (result < 0) { |
- if (result != ERR_IO_PENDING) |
- DidWriteBuffer(data, result); |
- return result; |
- } |
- data->DidConsume(result); |
- } |
- return OK; |
-} |
- |
-void URLFetcherCore::DidWriteBuffer(scoped_refptr<DrainableIOBuffer> data, |
- int result) { |
- if (result < 0) { // Handle errors. |
- CancelURLRequest(result); |
- response_writer_->Finish(base::Bind(&EmptyCompletionCallback)); |
- delegate_task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this)); |
- return; |
- } |
- |
- // Continue writing. |
- data->DidConsume(result); |
- if (WriteBuffer(data) < 0) |
- return; |
- |
- // Finished writing buffer_. Read some more, unless the request has been |
- // cancelled and deleted. |
- DCHECK_EQ(0, data->BytesRemaining()); |
- if (request_.get()) |
- ReadResponse(); |
-} |
- |
-void URLFetcherCore::ReadResponse() { |
- // Some servers may treat HEAD requests as GET requests. To free up the |
- // network connection as soon as possible, signal that the request has |
- // completed immediately, without trying to read any data back (all we care |
- // about is the response code and headers, which we already have). |
- int bytes_read = 0; |
- if (request_->status().is_success() && |
- (request_type_ != URLFetcher::HEAD)) { |
- if (!request_->Read(buffer_.get(), kBufferSize, &bytes_read)) |
- bytes_read = -1; // Match OnReadCompleted() interface contract. |
- } |
- OnReadCompleted(request_.get(), bytes_read); |
-} |
- |
-void URLFetcherCore::InformDelegateUploadProgress() { |
- DCHECK(network_task_runner_->BelongsToCurrentThread()); |
- if (request_.get()) { |
- int64 current = request_->GetUploadProgress().position(); |
- if (current_upload_bytes_ != current) { |
- current_upload_bytes_ = current; |
- int64 total = -1; |
- if (!is_chunked_upload_) { |
- total = static_cast<int64>(request_->GetUploadProgress().size()); |
- // Total may be zero if the UploadDataStream::Init has not been called |
- // yet. Don't send the upload progress until the size is initialized. |
- if (!total) |
- return; |
- } |
- delegate_task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind( |
- &URLFetcherCore::InformDelegateUploadProgressInDelegateThread, |
- this, current, total)); |
- } |
- } |
-} |
- |
-void URLFetcherCore::InformDelegateUploadProgressInDelegateThread( |
- int64 current, int64 total) { |
- DCHECK(delegate_task_runner_->BelongsToCurrentThread()); |
- if (delegate_) |
- delegate_->OnURLFetchUploadProgress(fetcher_, current, total); |
-} |
- |
-void URLFetcherCore::InformDelegateDownloadProgress() { |
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. |
- tracked_objects::ScopedTracker tracking_profile1( |
- FROM_HERE_WITH_EXPLICIT_FUNCTION( |
- "423948 URLFetcherCore::InformDelegateDownloadProgress1")); |
- |
- DCHECK(network_task_runner_->BelongsToCurrentThread()); |
- |
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. |
- tracked_objects::ScopedTracker tracking_profile2( |
- FROM_HERE_WITH_EXPLICIT_FUNCTION( |
- "423948 URLFetcherCore::InformDelegateDownloadProgress2")); |
- |
- delegate_task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind( |
- &URLFetcherCore::InformDelegateDownloadProgressInDelegateThread, |
- this, current_response_bytes_, total_response_bytes_)); |
-} |
- |
-void URLFetcherCore::InformDelegateDownloadProgressInDelegateThread( |
- int64 current, int64 total) { |
- DCHECK(delegate_task_runner_->BelongsToCurrentThread()); |
- if (delegate_) |
- delegate_->OnURLFetchDownloadProgress(fetcher_, current, total); |
-} |
- |
-void URLFetcherCore::AssertHasNoUploadData() const { |
- DCHECK(!upload_content_set_); |
- DCHECK(upload_content_.empty()); |
- DCHECK(upload_file_path_.empty()); |
- DCHECK(upload_stream_factory_.is_null()); |
-} |
- |
-} // namespace net |