url_fetcher_core.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "net/url_request/url_fetcher_core.h" 6 7#include <stdint.h> 8 9#include "base/bind.h" 10#include "base/logging.h" 11#include "base/metrics/histogram.h" 12#include "base/sequenced_task_runner.h" 13#include "base/single_thread_task_runner.h" 14#include "base/stl_util.h" 15#include "base/thread_task_runner_handle.h" 16#include "base/tracked_objects.h" 17#include "net/base/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" 31 32namespace { 33 34const int kBufferSize = 4096; 35const int kUploadProgressTimerInterval = 100; 36bool g_interception_enabled = false; 37bool g_ignore_certificate_requests = false; 38 39void EmptyCompletionCallback(int result) {} 40 41} // namespace 42 43namespace net { 44 45// URLFetcherCore::Registry --------------------------------------------------- 46 47URLFetcherCore::Registry::Registry() {} 48URLFetcherCore::Registry::~Registry() {} 49 50void URLFetcherCore::Registry::AddURLFetcherCore(URLFetcherCore* core) { 51 DCHECK(!ContainsKey(fetchers_, core)); 52 fetchers_.insert(core); 53} 54 55void URLFetcherCore::Registry::RemoveURLFetcherCore(URLFetcherCore* core) { 56 DCHECK(ContainsKey(fetchers_, core)); 57 fetchers_.erase(core); 58} 59 60void URLFetcherCore::Registry::CancelAll() { 61 while (!fetchers_.empty()) 62 (*fetchers_.begin())->CancelURLRequest(ERR_ABORTED); 63} 64 65// URLFetcherCore ------------------------------------------------------------- 66 67// static 68base::LazyInstance<URLFetcherCore::Registry> 69 URLFetcherCore::g_registry = LAZY_INSTANCE_INITIALIZER; 70 71URLFetcherCore::URLFetcherCore(URLFetcher* fetcher, 72 const GURL& original_url, 73 URLFetcher::RequestType request_type, 74 URLFetcherDelegate* d) 75 : fetcher_(fetcher), 76 original_url_(original_url), 77 request_type_(request_type), 78 delegate_(d), 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), 88 referrer_policy_( 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()); 103} 104 105void 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()); 111 } else { 112 network_task_runner_ = request_context_getter_->GetNetworkTaskRunner(); 113 } 114 DCHECK(network_task_runner_.get()) << "We need an IO task runner"; 115 116 network_task_runner_->PostTask( 117 FROM_HERE, base::Bind(&URLFetcherCore::StartOnIOThread, this)); 118} 119 120void URLFetcherCore::Stop() { 121 if (delegate_task_runner_.get()) // May be NULL in tests. 122 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 123 124 delegate_ = NULL; 125 fetcher_ = NULL; 126 if (!network_task_runner_.get()) 127 return; 128 if (network_task_runner_->RunsTasksOnCurrentThread()) { 129 CancelURLRequest(ERR_ABORTED); 130 } else { 131 network_task_runner_->PostTask( 132 FROM_HERE, 133 base::Bind(&URLFetcherCore::CancelURLRequest, this, ERR_ABORTED)); 134 } 135} 136 137void 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()); 144 145 // Empty |upload_content_type| is allowed iff the |upload_content| is empty. 146 DCHECK(upload_content.empty() || !upload_content_type.empty()); 147 148 upload_content_type_ = upload_content_type; 149 upload_content_ = upload_content; 150 upload_content_set_ = true; 151} 152 153void URLFetcherCore::SetUploadFilePath( 154 const std::string& upload_content_type, 155 const base::FilePath& file_path, 156 uint64 range_offset, 157 uint64 range_length, 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()); 167 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; 174} 175 176void URLFetcherCore::SetChunkedUpload(const std::string& content_type) { 177 DCHECK(is_chunked_upload_ || 178 (upload_content_type_.empty() && 179 upload_content_.empty())); 180 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()); 184 185 upload_content_type_ = content_type; 186 upload_content_.clear(); 187 is_chunked_upload_ = true; 188} 189 190void 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( 195 FROM_HERE, 196 base::Bind(&URLFetcherCore::CompleteAddingUploadDataChunk, this, content, 197 is_last_chunk)); 198} 199 200void URLFetcherCore::SetLoadFlags(int load_flags) { 201 load_flags_ = load_flags; 202} 203 204int URLFetcherCore::GetLoadFlags() const { 205 return load_flags_; 206} 207 208void URLFetcherCore::SetReferrer(const std::string& referrer) { 209 referrer_ = referrer; 210} 211 212void URLFetcherCore::SetReferrerPolicy( 213 URLRequest::ReferrerPolicy referrer_policy) { 214 referrer_policy_ = referrer_policy; 215} 216 217void URLFetcherCore::SetExtraRequestHeaders( 218 const std::string& extra_request_headers) { 219 extra_request_headers_.Clear(); 220 extra_request_headers_.AddHeadersFromString(extra_request_headers); 221} 222 223void URLFetcherCore::AddExtraRequestHeader(const std::string& header_line) { 224 extra_request_headers_.AddHeaderFromString(header_line); 225} 226 227void 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; 232} 233 234void 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; 238} 239 240void URLFetcherCore::SetURLRequestUserData( 241 const void* key, 242 const URLFetcher::CreateDataCallback& create_data_callback) { 243 DCHECK(key); 244 DCHECK(!create_data_callback.is_null()); 245 url_request_data_key_ = key; 246 url_request_create_data_callback_ = create_data_callback; 247} 248 249void URLFetcherCore::SetStopOnRedirect(bool stop_on_redirect) { 250 stop_on_redirect_ = stop_on_redirect; 251} 252 253void URLFetcherCore::SetAutomaticallyRetryOn5xx(bool retry) { 254 automatically_retry_on_5xx_ = retry; 255} 256 257void URLFetcherCore::SetMaxRetriesOn5xx(int max_retries) { 258 max_retries_on_5xx_ = max_retries; 259} 260 261int URLFetcherCore::GetMaxRetriesOn5xx() const { 262 return max_retries_on_5xx_; 263} 264 265base::TimeDelta URLFetcherCore::GetBackoffDelay() const { 266 return backoff_delay_; 267} 268 269void URLFetcherCore::SetAutomaticallyRetryOnNetworkChanges(int max_retries) { 270 max_retries_on_network_changes_ = max_retries; 271} 272 273void 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))); 279} 280 281void 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()))); 286} 287 288void URLFetcherCore::SaveResponseWithWriter( 289 scoped_ptr<URLFetcherResponseWriter> response_writer) { 290 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 291 response_writer_ = response_writer.Pass(); 292} 293 294HttpResponseHeaders* URLFetcherCore::GetResponseHeaders() const { 295 return response_headers_.get(); 296} 297 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. 301HostPortPair URLFetcherCore::GetSocketAddress() const { 302 return socket_address_; 303} 304 305bool URLFetcherCore::WasFetchedViaProxy() const { 306 return was_fetched_via_proxy_; 307} 308 309const GURL& URLFetcherCore::GetOriginalURL() const { 310 return original_url_; 311} 312 313const GURL& URLFetcherCore::GetURL() const { 314 return url_; 315} 316 317const URLRequestStatus& URLFetcherCore::GetStatus() const { 318 return status_; 319} 320 321int URLFetcherCore::GetResponseCode() const { 322 return response_code_; 323} 324 325const ResponseCookies& URLFetcherCore::GetCookies() const { 326 return cookies_; 327} 328 329void 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)); 334 } 335} 336 337bool URLFetcherCore::GetResponseAsString( 338 std::string* out_response_string) const { 339 URLFetcherStringWriter* string_writer = 340 response_writer_ ? response_writer_->AsStringWriter() : NULL; 341 if (!string_writer) 342 return false; 343 344 *out_response_string = string_writer->data(); 345 UMA_HISTOGRAM_MEMORY_KB("UrlFetcher.StringResponseSize", 346 (string_writer->data().length() / 1024)); 347 return true; 348} 349 350bool URLFetcherCore::GetResponseAsFilePath(bool take_ownership, 351 base::FilePath* out_response_path) { 352 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 353 354 URLFetcherFileWriter* file_writer = 355 response_writer_ ? response_writer_->AsFileWriter() : NULL; 356 if (!file_writer) 357 return false; 358 359 *out_response_path = file_writer->file_path(); 360 361 if (take_ownership) { 362 // Intentionally calling a file_writer_ method directly without posting 363 // the task to network_task_runner_. 364 // 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_. 368 // 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(); 372 } 373 return true; 374} 375 376void 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(); 386 request->Cancel(); 387 OnReadCompleted(request, 0); 388 } 389} 390 391void 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(); 400 } 401 402 ReadResponse(); 403} 404 405void URLFetcherCore::OnCertificateRequested( 406 URLRequest* request, 407 SSLCertRequestInfo* cert_request_info) { 408 DCHECK_EQ(request, request_.get()); 409 DCHECK(network_task_runner_->BelongsToCurrentThread()); 410 411 if (g_ignore_certificate_requests) { 412 request->ContinueWithCertificate(NULL); 413 } else { 414 request->Cancel(); 415 } 416} 417 418void URLFetcherCore::OnReadCompleted(URLRequest* request, 419 int bytes_read) { 420 DCHECK(request == request_); 421 DCHECK(network_task_runner_->BelongsToCurrentThread()); 422 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_); 429 } 430 431 do { 432 if (!request_->status().is_success() || bytes_read <= 0) 433 break; 434 435 current_response_bytes_ += bytes_read; 436 InformDelegateDownloadProgress(); 437 438 const int result = 439 WriteBuffer(new DrainableIOBuffer(buffer_.get(), bytes_read)); 440 if (result < 0) { 441 // Write failed or waiting for write completion. 442 return; 443 } 444 } while (request_->Read(buffer_.get(), kBufferSize, &bytes_read)); 445 446 const URLRequestStatus status = request_->status(); 447 448 if (status.is_success()) 449 request_->GetResponseCookies(&cookies_); 450 451 // See comments re: HEAD requests in ReadResponse(). 452 if (!status.is_io_pending() || request_type_ == URLFetcher::HEAD) { 453 status_ = status; 454 ReleaseRequest(); 455 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); 461 } 462} 463 464void URLFetcherCore::CancelAll() { 465 g_registry.Get().CancelAll(); 466} 467 468int URLFetcherCore::GetNumFetcherCores() { 469 return g_registry.Get().size(); 470} 471 472void URLFetcherCore::SetEnableInterceptionForTests(bool enabled) { 473 g_interception_enabled = enabled; 474} 475 476void URLFetcherCore::SetIgnoreCertificateRequests(bool ignored) { 477 g_ignore_certificate_requests = ignored; 478} 479 480URLFetcherCore::~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()); 484} 485 486void URLFetcherCore::StartOnIOThread() { 487 DCHECK(network_task_runner_->BelongsToCurrentThread()); 488 489 if (!response_writer_) 490 response_writer_.reset(new URLFetcherStringWriter); 491 492 const int result = response_writer_->Initialize( 493 base::Bind(&URLFetcherCore::DidInitializeWriter, this)); 494 if (result != ERR_IO_PENDING) 495 DidInitializeWriter(result); 496} 497 498void URLFetcherCore::StartURLRequest() { 499 DCHECK(network_task_runner_->BelongsToCurrentThread()); 500 501 if (was_cancelled_) { 502 // Since StartURLRequest() is posted as a *delayed* task, it may 503 // run after the URLFetcher was already stopped. 504 return; 505 } 506 507 DCHECK(request_context_getter_.get()); 508 DCHECK(!request_.get()); 509 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; 518 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()); 529 } 530 531 switch (request_type_) { 532 case URLFetcher::GET: 533 break; 534 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_); 540 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_); 547 } 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(), 556 upload_file_path_, 557 upload_range_offset_, 558 upload_range_length_, 559 base::Time())); 560 request_->set_upload(make_scoped_ptr( 561 UploadDataStream::CreateWithReader(reader.Pass(), 0))); 562 } 563 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( 570 FROM_HERE, 571 base::TimeDelta::FromMilliseconds(kUploadProgressTimerInterval), 572 this, 573 &URLFetcherCore::InformDelegateUploadProgress); 574 break; 575 576 case URLFetcher::HEAD: 577 request_->set_method("HEAD"); 578 break; 579 580 case URLFetcher::DELETE_REQUEST: 581 request_->set_method("DELETE"); 582 break; 583 584 default: 585 NOTREACHED(); 586 } 587 588 if (!extra_request_headers_.IsEmpty()) 589 request_->SetExtraRequestHeaders(extra_request_headers_); 590 591 request_->Start(); 592} 593 594void URLFetcherCore::DidInitializeWriter(int result) { 595 if (result != OK) { 596 CancelURLRequest(result); 597 delegate_task_runner_->PostTask( 598 FROM_HERE, 599 base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this)); 600 return; 601 } 602 StartURLRequestWhenAppropriate(); 603} 604 605void URLFetcherCore::StartURLRequestWhenAppropriate() { 606 DCHECK(network_task_runner_->BelongsToCurrentThread()); 607 608 if (was_cancelled_) 609 return; 610 611 DCHECK(request_context_getter_.get()); 612 613 int64 delay = INT64_C(0); 614 if (!original_url_throttler_entry_.get()) { 615 URLRequestThrottlerManager* manager = 616 request_context_getter_->GetURLRequestContext()->throttler_manager(); 617 if (manager) { 618 original_url_throttler_entry_ = 619 manager->RegisterRequestUrl(original_url_); 620 } 621 } 622 if (original_url_throttler_entry_.get()) { 623 delay = original_url_throttler_entry_->ReserveSendingTimeForNextRequest( 624 GetBackoffReleaseTime()); 625 } 626 627 if (delay == INT64_C(0)) { 628 StartURLRequest(); 629 } else { 630 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( 631 FROM_HERE, base::Bind(&URLFetcherCore::StartURLRequest, this), 632 base::TimeDelta::FromMilliseconds(delay)); 633 } 634} 635 636void URLFetcherCore::CancelURLRequest(int error) { 637 DCHECK(network_task_runner_->BelongsToCurrentThread()); 638 639 if (request_.get()) { 640 request_->CancelWithError(error); 641 ReleaseRequest(); 642 } 643 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); 652 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 656 // context. 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; 662} 663 664void URLFetcherCore::OnCompletedURLRequest( 665 base::TimeDelta backoff_delay) { 666 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 667 668 // Save the status and backoff_delay so that delegates can read it. 669 if (delegate_) { 670 backoff_delay_ = backoff_delay; 671 InformDelegateFetchIsComplete(); 672 } 673} 674 675void URLFetcherCore::InformDelegateFetchIsComplete() { 676 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 677 if (delegate_) 678 delegate_->OnURLFetchComplete(fetcher_); 679} 680 681void 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. 691 status_code = 200; 692 } 693 url_throttler_entry_->ReceivedContentWasMalformed(status_code); 694 } 695} 696 697void URLFetcherCore::DidFinishWriting(int result) { 698 if (result != OK) { 699 CancelURLRequest(result); 700 delegate_task_runner_->PostTask( 701 FROM_HERE, 702 base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this)); 703 return; 704 } 705 // If the file was successfully closed, then the URL request is complete. 706 RetryOrCompleteUrlFetch(); 707} 708 709void URLFetcherCore::RetryOrCompleteUrlFetch() { 710 DCHECK(network_task_runner_->BelongsToCurrentThread()); 711 base::TimeDelta backoff_delay; 712 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_; 719 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(); 729 730 if (automatically_retry_on_5xx_ && 731 num_retries_on_5xx_ <= max_retries_on_5xx_) { 732 StartOnIOThread(); 733 return; 734 } 735 } else { 736 backoff_delay = base::TimeDelta(); 737 } 738 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_; 743 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)); 748 return; 749 } 750 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( 756 FROM_HERE, 757 base::Bind(&URLFetcherCore::OnCompletedURLRequest, this, backoff_delay)); 758 759 // If the delegate message loop does not exist any more, then the delegate 760 // should be gone too. 761 DCHECK(posted || !delegate_); 762} 763 764void URLFetcherCore::ReleaseRequest() { 765 upload_progress_checker_timer_.reset(); 766 request_.reset(); 767 g_registry.Get().RemoveURLFetcherCore(this); 768} 769 770base::TimeTicks URLFetcherCore::GetBackoffReleaseTime() { 771 DCHECK(network_task_runner_->BelongsToCurrentThread()); 772 773 if (!original_url_throttler_entry_.get()) 774 return base::TimeTicks(); 775 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(); 783 } 784 785 return original_url_backoff > destination_url_backoff ? 786 original_url_backoff : destination_url_backoff; 787} 788 789void 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. 794 return; 795 } 796 DCHECK(is_chunked_upload_); 797 DCHECK(request_.get()); 798 DCHECK(!content.empty()); 799 request_->AppendChunkToUpload(content.data(), 800 static_cast<int>(content.length()), 801 is_last_chunk); 802} 803 804int URLFetcherCore::WriteBuffer(scoped_refptr<DrainableIOBuffer> data) { 805 while (data->BytesRemaining() > 0) { 806 const int result = response_writer_->Write( 807 data.get(), 808 data->BytesRemaining(), 809 base::Bind(&URLFetcherCore::DidWriteBuffer, this, data)); 810 if (result < 0) { 811 if (result != ERR_IO_PENDING) 812 DidWriteBuffer(data, result); 813 return result; 814 } 815 data->DidConsume(result); 816 } 817 return OK; 818} 819 820void URLFetcherCore::DidWriteBuffer(scoped_refptr<DrainableIOBuffer> data, 821 int result) { 822 if (result < 0) { // Handle errors. 823 CancelURLRequest(result); 824 response_writer_->Finish(base::Bind(&EmptyCompletionCallback)); 825 delegate_task_runner_->PostTask( 826 FROM_HERE, 827 base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this)); 828 return; 829 } 830 831 // Continue writing. 832 data->DidConsume(result); 833 if (WriteBuffer(data) < 0) 834 return; 835 836 // Finished writing buffer_. Read some more, unless the request has been 837 // cancelled and deleted. 838 DCHECK_EQ(0, data->BytesRemaining()); 839 if (request_.get()) 840 ReadResponse(); 841} 842 843void 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). 848 int bytes_read = 0; 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. 853 } 854 OnReadCompleted(request_.get(), bytes_read); 855} 856 857void 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; 863 int64 total = -1; 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. 868 if (!total) 869 return; 870 } 871 delegate_task_runner_->PostTask( 872 FROM_HERE, 873 base::Bind( 874 &URLFetcherCore::InformDelegateUploadProgressInDelegateThread, 875 this, current, total)); 876 } 877 } 878} 879 880void URLFetcherCore::InformDelegateUploadProgressInDelegateThread( 881 int64 current, int64 total) { 882 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 883 if (delegate_) 884 delegate_->OnURLFetchUploadProgress(fetcher_, current, total); 885} 886 887void URLFetcherCore::InformDelegateDownloadProgress() { 888 DCHECK(network_task_runner_->BelongsToCurrentThread()); 889 delegate_task_runner_->PostTask( 890 FROM_HERE, 891 base::Bind( 892 &URLFetcherCore::InformDelegateDownloadProgressInDelegateThread, 893 this, current_response_bytes_, total_response_bytes_)); 894} 895 896void URLFetcherCore::InformDelegateDownloadProgressInDelegateThread( 897 int64 current, int64 total) { 898 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 899 if (delegate_) 900 delegate_->OnURLFetchDownloadProgress(fetcher_, current, total); 901} 902 903} // namespace net 904