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