url_fetcher_core.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
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/single_thread_task_runner.h" 11#include "base/stl_util.h" 12#include "base/thread_task_runner_handle.h" 13#include "base/tracked_objects.h" 14#include "net/base/io_buffer.h" 15#include "net/base/load_flags.h" 16#include "net/base/net_errors.h" 17#include "net/base/upload_bytes_element_reader.h" 18#include "net/base/upload_data_stream.h" 19#include "net/base/upload_file_element_reader.h" 20#include "net/http/http_response_headers.h" 21#include "net/url_request/url_fetcher_delegate.h" 22#include "net/url_request/url_fetcher_response_writer.h" 23#include "net/url_request/url_request_context.h" 24#include "net/url_request/url_request_context_getter.h" 25#include "net/url_request/url_request_throttler_manager.h" 26 27namespace { 28 29const int kBufferSize = 4096; 30const int kUploadProgressTimerInterval = 100; 31bool g_interception_enabled = false; 32bool g_ignore_certificate_requests = false; 33 34} // namespace 35 36namespace net { 37 38// URLFetcherCore::Registry --------------------------------------------------- 39 40URLFetcherCore::Registry::Registry() {} 41URLFetcherCore::Registry::~Registry() {} 42 43void URLFetcherCore::Registry::AddURLFetcherCore(URLFetcherCore* core) { 44 DCHECK(!ContainsKey(fetchers_, core)); 45 fetchers_.insert(core); 46} 47 48void URLFetcherCore::Registry::RemoveURLFetcherCore(URLFetcherCore* core) { 49 DCHECK(ContainsKey(fetchers_, core)); 50 fetchers_.erase(core); 51} 52 53void URLFetcherCore::Registry::CancelAll() { 54 while (!fetchers_.empty()) 55 (*fetchers_.begin())->CancelURLRequest(); 56} 57 58// URLFetcherCore ------------------------------------------------------------- 59 60// static 61base::LazyInstance<URLFetcherCore::Registry> 62 URLFetcherCore::g_registry = LAZY_INSTANCE_INITIALIZER; 63 64URLFetcherCore::URLFetcherCore(URLFetcher* fetcher, 65 const GURL& original_url, 66 URLFetcher::RequestType request_type, 67 URLFetcherDelegate* d) 68 : fetcher_(fetcher), 69 original_url_(original_url), 70 request_type_(request_type), 71 delegate_(d), 72 delegate_task_runner_( 73 base::ThreadTaskRunnerHandle::Get()), 74 request_(NULL), 75 load_flags_(LOAD_NORMAL), 76 response_code_(URLFetcher::RESPONSE_CODE_INVALID), 77 buffer_(new IOBuffer(kBufferSize)), 78 url_request_data_key_(NULL), 79 was_fetched_via_proxy_(false), 80 upload_content_set_(false), 81 upload_range_offset_(0), 82 upload_range_length_(0), 83 is_chunked_upload_(false), 84 was_cancelled_(false), 85 file_writer_(NULL), 86 response_destination_(STRING), 87 stop_on_redirect_(false), 88 stopped_on_redirect_(false), 89 automatically_retry_on_5xx_(true), 90 num_retries_on_5xx_(0), 91 max_retries_on_5xx_(0), 92 num_retries_on_network_changes_(0), 93 max_retries_on_network_changes_(0), 94 current_upload_bytes_(-1), 95 current_response_bytes_(0), 96 total_response_bytes_(-1) { 97 CHECK(original_url_.is_valid()); 98} 99 100void URLFetcherCore::Start() { 101 DCHECK(delegate_task_runner_); 102 DCHECK(request_context_getter_) << "We need an URLRequestContext!"; 103 if (network_task_runner_) { 104 DCHECK_EQ(network_task_runner_, 105 request_context_getter_->GetNetworkTaskRunner()); 106 } else { 107 network_task_runner_ = request_context_getter_->GetNetworkTaskRunner(); 108 } 109 DCHECK(network_task_runner_.get()) << "We need an IO task runner"; 110 111 network_task_runner_->PostTask( 112 FROM_HERE, base::Bind(&URLFetcherCore::StartOnIOThread, this)); 113} 114 115void URLFetcherCore::Stop() { 116 if (delegate_task_runner_) // May be NULL in tests. 117 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 118 119 delegate_ = NULL; 120 fetcher_ = NULL; 121 if (!network_task_runner_.get()) 122 return; 123 if (network_task_runner_->RunsTasksOnCurrentThread()) { 124 CancelURLRequest(); 125 } else { 126 network_task_runner_->PostTask( 127 FROM_HERE, base::Bind(&URLFetcherCore::CancelURLRequest, this)); 128 } 129} 130 131void URLFetcherCore::SetUploadData(const std::string& upload_content_type, 132 const std::string& upload_content) { 133 DCHECK(!is_chunked_upload_); 134 DCHECK(!upload_content_set_); 135 DCHECK(upload_content_.empty()); 136 DCHECK(upload_file_path_.empty()); 137 DCHECK(upload_content_type_.empty()); 138 139 // Empty |upload_content_type| is allowed iff the |upload_content| is empty. 140 DCHECK(upload_content.empty() || !upload_content_type.empty()); 141 142 upload_content_type_ = upload_content_type; 143 upload_content_ = upload_content; 144 upload_content_set_ = true; 145} 146 147void URLFetcherCore::SetUploadFilePath( 148 const std::string& upload_content_type, 149 const base::FilePath& file_path, 150 uint64 range_offset, 151 uint64 range_length, 152 scoped_refptr<base::TaskRunner> file_task_runner) { 153 DCHECK(!is_chunked_upload_); 154 DCHECK(!upload_content_set_); 155 DCHECK(upload_content_.empty()); 156 DCHECK(upload_file_path_.empty()); 157 DCHECK_EQ(upload_range_offset_, 0ULL); 158 DCHECK_EQ(upload_range_length_, 0ULL); 159 DCHECK(upload_content_type_.empty()); 160 DCHECK(!upload_content_type.empty()); 161 162 upload_content_type_ = upload_content_type; 163 upload_file_path_ = file_path; 164 upload_range_offset_ = range_offset; 165 upload_range_length_ = range_length; 166 upload_file_task_runner_ = file_task_runner; 167 upload_content_set_ = true; 168} 169 170void URLFetcherCore::SetChunkedUpload(const std::string& content_type) { 171 DCHECK(is_chunked_upload_ || 172 (upload_content_type_.empty() && 173 upload_content_.empty())); 174 175 // Empty |content_type| is not allowed here, because it is impossible 176 // to ensure non-empty upload content as it is not yet supplied. 177 DCHECK(!content_type.empty()); 178 179 upload_content_type_ = content_type; 180 upload_content_.clear(); 181 is_chunked_upload_ = true; 182} 183 184void URLFetcherCore::AppendChunkToUpload(const std::string& content, 185 bool is_last_chunk) { 186 DCHECK(delegate_task_runner_); 187 DCHECK(network_task_runner_.get()); 188 network_task_runner_->PostTask( 189 FROM_HERE, 190 base::Bind(&URLFetcherCore::CompleteAddingUploadDataChunk, this, content, 191 is_last_chunk)); 192} 193 194void URLFetcherCore::SetLoadFlags(int load_flags) { 195 load_flags_ = load_flags; 196} 197 198int URLFetcherCore::GetLoadFlags() const { 199 return load_flags_; 200} 201 202void URLFetcherCore::SetReferrer(const std::string& referrer) { 203 referrer_ = referrer; 204} 205 206void URLFetcherCore::SetExtraRequestHeaders( 207 const std::string& extra_request_headers) { 208 extra_request_headers_.Clear(); 209 extra_request_headers_.AddHeadersFromString(extra_request_headers); 210} 211 212void URLFetcherCore::AddExtraRequestHeader(const std::string& header_line) { 213 extra_request_headers_.AddHeaderFromString(header_line); 214} 215 216void URLFetcherCore::GetExtraRequestHeaders( 217 HttpRequestHeaders* headers) const { 218 headers->CopyFrom(extra_request_headers_); 219} 220 221void URLFetcherCore::SetRequestContext( 222 URLRequestContextGetter* request_context_getter) { 223 DCHECK(!request_context_getter_); 224 DCHECK(request_context_getter); 225 request_context_getter_ = request_context_getter; 226} 227 228void URLFetcherCore::SetFirstPartyForCookies( 229 const GURL& first_party_for_cookies) { 230 DCHECK(first_party_for_cookies_.is_empty()); 231 first_party_for_cookies_ = first_party_for_cookies; 232} 233 234void URLFetcherCore::SetURLRequestUserData( 235 const void* key, 236 const URLFetcher::CreateDataCallback& create_data_callback) { 237 DCHECK(key); 238 DCHECK(!create_data_callback.is_null()); 239 url_request_data_key_ = key; 240 url_request_create_data_callback_ = create_data_callback; 241} 242 243void URLFetcherCore::SetStopOnRedirect(bool stop_on_redirect) { 244 stop_on_redirect_ = stop_on_redirect; 245} 246 247void URLFetcherCore::SetAutomaticallyRetryOn5xx(bool retry) { 248 automatically_retry_on_5xx_ = retry; 249} 250 251void URLFetcherCore::SetMaxRetriesOn5xx(int max_retries) { 252 max_retries_on_5xx_ = max_retries; 253} 254 255int URLFetcherCore::GetMaxRetriesOn5xx() const { 256 return max_retries_on_5xx_; 257} 258 259base::TimeDelta URLFetcherCore::GetBackoffDelay() const { 260 return backoff_delay_; 261} 262 263void URLFetcherCore::SetAutomaticallyRetryOnNetworkChanges(int max_retries) { 264 max_retries_on_network_changes_ = max_retries; 265} 266 267void URLFetcherCore::SaveResponseToFileAtPath( 268 const base::FilePath& file_path, 269 scoped_refptr<base::TaskRunner> file_task_runner) { 270 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 271 file_task_runner_ = file_task_runner; 272 response_destination_ = URLFetcherCore::PERMANENT_FILE; 273 response_destination_file_path_ = file_path; 274} 275 276void URLFetcherCore::SaveResponseToTemporaryFile( 277 scoped_refptr<base::TaskRunner> file_task_runner) { 278 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 279 file_task_runner_ = file_task_runner; 280 response_destination_ = URLFetcherCore::TEMP_FILE; 281} 282 283HttpResponseHeaders* URLFetcherCore::GetResponseHeaders() const { 284 return response_headers_; 285} 286 287// TODO(panayiotis): socket_address_ is written in the IO thread, 288// if this is accessed in the UI thread, this could result in a race. 289// Same for response_headers_ above and was_fetched_via_proxy_ below. 290HostPortPair URLFetcherCore::GetSocketAddress() const { 291 return socket_address_; 292} 293 294bool URLFetcherCore::WasFetchedViaProxy() const { 295 return was_fetched_via_proxy_; 296} 297 298const GURL& URLFetcherCore::GetOriginalURL() const { 299 return original_url_; 300} 301 302const GURL& URLFetcherCore::GetURL() const { 303 return url_; 304} 305 306const URLRequestStatus& URLFetcherCore::GetStatus() const { 307 return status_; 308} 309 310int URLFetcherCore::GetResponseCode() const { 311 return response_code_; 312} 313 314const ResponseCookies& URLFetcherCore::GetCookies() const { 315 return cookies_; 316} 317 318bool URLFetcherCore::FileErrorOccurred(int* out_error_code) const { 319 // Can't have a file error if no file is being created or written to. 320 if (!file_writer_) 321 return false; 322 323 int error_code = file_writer_->error_code(); 324 if (error_code == OK) 325 return false; 326 327 *out_error_code = error_code; 328 return true; 329} 330 331void URLFetcherCore::ReceivedContentWasMalformed() { 332 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 333 if (network_task_runner_.get()) { 334 network_task_runner_->PostTask( 335 FROM_HERE, base::Bind(&URLFetcherCore::NotifyMalformedContent, this)); 336 } 337} 338 339bool URLFetcherCore::GetResponseAsString( 340 std::string* out_response_string) const { 341 if (response_destination_ != URLFetcherCore::STRING) 342 return false; 343 344 *out_response_string = data_; 345 UMA_HISTOGRAM_MEMORY_KB("UrlFetcher.StringResponseSize", 346 (data_.length() / 1024)); 347 348 return true; 349} 350 351bool URLFetcherCore::GetResponseAsFilePath(bool take_ownership, 352 base::FilePath* out_response_path) { 353 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 354 const bool destination_is_file = 355 response_destination_ == URLFetcherCore::TEMP_FILE || 356 response_destination_ == URLFetcherCore::PERMANENT_FILE; 357 if (!destination_is_file || !file_writer_) 358 return false; 359 360 *out_response_path = file_writer_->file_path(); 361 362 if (take_ownership) { 363 network_task_runner_->PostTask( 364 FROM_HERE, 365 base::Bind(&URLFetcherCore::DisownFile, this)); 366 } 367 return true; 368} 369 370void URLFetcherCore::OnReceivedRedirect(URLRequest* request, 371 const GURL& new_url, 372 bool* defer_redirect) { 373 DCHECK_EQ(request, request_.get()); 374 DCHECK(network_task_runner_->BelongsToCurrentThread()); 375 if (stop_on_redirect_) { 376 stopped_on_redirect_ = true; 377 url_ = new_url; 378 response_code_ = request_->GetResponseCode(); 379 was_fetched_via_proxy_ = request_->was_fetched_via_proxy(); 380 request->Cancel(); 381 OnReadCompleted(request, 0); 382 } 383} 384 385void URLFetcherCore::OnResponseStarted(URLRequest* request) { 386 DCHECK_EQ(request, request_.get()); 387 DCHECK(network_task_runner_->BelongsToCurrentThread()); 388 if (request_->status().is_success()) { 389 response_code_ = request_->GetResponseCode(); 390 response_headers_ = request_->response_headers(); 391 socket_address_ = request_->GetSocketAddress(); 392 was_fetched_via_proxy_ = request_->was_fetched_via_proxy(); 393 total_response_bytes_ = request_->GetExpectedContentSize(); 394 } 395 396 ReadResponse(); 397} 398 399void URLFetcherCore::OnCertificateRequested( 400 URLRequest* request, 401 SSLCertRequestInfo* cert_request_info) { 402 DCHECK_EQ(request, request_.get()); 403 DCHECK(network_task_runner_->BelongsToCurrentThread()); 404 405 if (g_ignore_certificate_requests) { 406 request->ContinueWithCertificate(NULL); 407 } else { 408 request->Cancel(); 409 } 410} 411 412void URLFetcherCore::OnReadCompleted(URLRequest* request, 413 int bytes_read) { 414 DCHECK(request == request_); 415 DCHECK(network_task_runner_->BelongsToCurrentThread()); 416 417 if (!stopped_on_redirect_) 418 url_ = request->url(); 419 URLRequestThrottlerManager* throttler_manager = 420 request->context()->throttler_manager(); 421 if (throttler_manager) { 422 url_throttler_entry_ = throttler_manager->RegisterRequestUrl(url_); 423 } 424 425 bool waiting_on_write = false; 426 do { 427 if (!request_->status().is_success() || bytes_read <= 0) 428 break; 429 430 current_response_bytes_ += bytes_read; 431 InformDelegateDownloadProgress(); 432 InformDelegateDownloadDataIfNecessary(bytes_read); 433 434 const int result = WriteBuffer(new DrainableIOBuffer(buffer_, bytes_read)); 435 if (result < 0) { 436 // Write failed or waiting for write completion. 437 if (result == ERR_IO_PENDING) 438 waiting_on_write = true; 439 break; 440 } 441 } while (request_->Read(buffer_, kBufferSize, &bytes_read)); 442 443 const URLRequestStatus status = request_->status(); 444 445 if (status.is_success()) 446 request_->GetResponseCookies(&cookies_); 447 448 // See comments re: HEAD requests in ReadResponse(). 449 if ((!status.is_io_pending() && !waiting_on_write) || 450 (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 switch (response_destination_) { 488 case STRING: 489 response_writer_.reset(new URLFetcherStringWriter(&data_)); 490 break; 491 492 case PERMANENT_FILE: 493 case TEMP_FILE: 494 DCHECK(file_task_runner_.get()) 495 << "Need to set the file task runner."; 496 497 file_writer_ = new URLFetcherFileWriter(file_task_runner_); 498 499 // If the file is successfully created, 500 // URLFetcherCore::StartURLRequestWhenAppropriate() will be called. 501 if (response_destination_ == PERMANENT_FILE) { 502 file_writer_->set_destination_file_path( 503 response_destination_file_path_); 504 } 505 response_writer_.reset(file_writer_); 506 break; 507 508 default: 509 NOTREACHED(); 510 } 511 DCHECK(response_writer_); 512 const int result = response_writer_->Initialize( 513 base::Bind(&URLFetcherCore::DidInitializeWriter, this)); 514 if (result != ERR_IO_PENDING) 515 DidInitializeWriter(result); 516} 517 518void URLFetcherCore::StartURLRequest() { 519 DCHECK(network_task_runner_->BelongsToCurrentThread()); 520 521 if (was_cancelled_) { 522 // Since StartURLRequest() is posted as a *delayed* task, it may 523 // run after the URLFetcher was already stopped. 524 return; 525 } 526 527 DCHECK(request_context_getter_); 528 DCHECK(!request_.get()); 529 530 g_registry.Get().AddURLFetcherCore(this); 531 current_response_bytes_ = 0; 532 request_.reset(request_context_getter_->GetURLRequestContext()->CreateRequest( 533 original_url_, this)); 534 request_->set_stack_trace(stack_trace_); 535 int flags = request_->load_flags() | load_flags_; 536 if (!g_interception_enabled) 537 flags = flags | LOAD_DISABLE_INTERCEPT; 538 539 if (is_chunked_upload_) 540 request_->EnableChunkedUpload(); 541 request_->set_load_flags(flags); 542 request_->SetReferrer(referrer_); 543 request_->set_first_party_for_cookies(first_party_for_cookies_.is_empty() ? 544 original_url_ : first_party_for_cookies_); 545 if (url_request_data_key_ && !url_request_create_data_callback_.is_null()) { 546 request_->SetUserData(url_request_data_key_, 547 url_request_create_data_callback_.Run()); 548 } 549 550 switch (request_type_) { 551 case URLFetcher::GET: 552 break; 553 554 case URLFetcher::POST: 555 case URLFetcher::PUT: 556 case URLFetcher::PATCH: 557 // Upload content must be set. 558 DCHECK(is_chunked_upload_ || upload_content_set_); 559 560 request_->set_method( 561 request_type_ == URLFetcher::POST ? "POST" : 562 request_type_ == URLFetcher::PUT ? "PUT" : "PATCH"); 563 extra_request_headers_.SetHeader(HttpRequestHeaders::kContentType, 564 upload_content_type_); 565 if (!upload_content_type_.empty()) { 566 extra_request_headers_.SetHeader(HttpRequestHeaders::kContentType, 567 upload_content_type_); 568 } 569 if (!upload_content_.empty()) { 570 scoped_ptr<UploadElementReader> reader(new UploadBytesElementReader( 571 upload_content_.data(), upload_content_.size())); 572 request_->set_upload(make_scoped_ptr( 573 UploadDataStream::CreateWithReader(reader.Pass(), 0))); 574 } else if (!upload_file_path_.empty()) { 575 scoped_ptr<UploadElementReader> reader(new UploadFileElementReader( 576 upload_file_task_runner_, 577 upload_file_path_, 578 upload_range_offset_, 579 upload_range_length_, 580 base::Time())); 581 request_->set_upload(make_scoped_ptr( 582 UploadDataStream::CreateWithReader(reader.Pass(), 0))); 583 } 584 585 current_upload_bytes_ = -1; 586 // TODO(kinaba): http://crbug.com/118103. Implement upload callback in the 587 // layer and avoid using timer here. 588 upload_progress_checker_timer_.reset( 589 new base::RepeatingTimer<URLFetcherCore>()); 590 upload_progress_checker_timer_->Start( 591 FROM_HERE, 592 base::TimeDelta::FromMilliseconds(kUploadProgressTimerInterval), 593 this, 594 &URLFetcherCore::InformDelegateUploadProgress); 595 break; 596 597 case URLFetcher::HEAD: 598 request_->set_method("HEAD"); 599 break; 600 601 case URLFetcher::DELETE_REQUEST: 602 request_->set_method("DELETE"); 603 break; 604 605 default: 606 NOTREACHED(); 607 } 608 609 if (!extra_request_headers_.IsEmpty()) 610 request_->SetExtraRequestHeaders(extra_request_headers_); 611 612 // There might be data left over from a previous request attempt. 613 data_.clear(); 614 615 // If we are writing the response to a file, the only caller 616 // of this function should have created it and not written yet. 617 DCHECK(!file_writer_ || file_writer_->total_bytes_written() == 0); 618 619 request_->Start(); 620} 621 622void URLFetcherCore::DidInitializeWriter(int result) { 623 if (result != OK) { 624 delegate_task_runner_->PostTask( 625 FROM_HERE, 626 base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this)); 627 return; 628 } 629 StartURLRequestWhenAppropriate(); 630} 631 632void URLFetcherCore::StartURLRequestWhenAppropriate() { 633 DCHECK(network_task_runner_->BelongsToCurrentThread()); 634 635 if (was_cancelled_) 636 return; 637 638 DCHECK(request_context_getter_); 639 640 int64 delay = 0LL; 641 if (original_url_throttler_entry_ == NULL) { 642 URLRequestThrottlerManager* manager = 643 request_context_getter_->GetURLRequestContext()->throttler_manager(); 644 if (manager) { 645 original_url_throttler_entry_ = 646 manager->RegisterRequestUrl(original_url_); 647 } 648 } 649 if (original_url_throttler_entry_ != NULL) { 650 delay = original_url_throttler_entry_->ReserveSendingTimeForNextRequest( 651 GetBackoffReleaseTime()); 652 } 653 654 if (delay == 0) { 655 StartURLRequest(); 656 } else { 657 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( 658 FROM_HERE, base::Bind(&URLFetcherCore::StartURLRequest, this), 659 base::TimeDelta::FromMilliseconds(delay)); 660 } 661} 662 663void URLFetcherCore::CancelURLRequest() { 664 DCHECK(network_task_runner_->BelongsToCurrentThread()); 665 666 if (request_.get()) { 667 request_->Cancel(); 668 ReleaseRequest(); 669 } 670 // Release the reference to the request context. There could be multiple 671 // references to URLFetcher::Core at this point so it may take a while to 672 // delete the object, but we cannot delay the destruction of the request 673 // context. 674 request_context_getter_ = NULL; 675 first_party_for_cookies_ = GURL(); 676 url_request_data_key_ = NULL; 677 url_request_create_data_callback_.Reset(); 678 was_cancelled_ = true; 679 response_writer_.reset(); 680 file_writer_ = NULL; 681} 682 683void URLFetcherCore::OnCompletedURLRequest( 684 base::TimeDelta backoff_delay) { 685 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 686 687 // Save the status and backoff_delay so that delegates can read it. 688 if (delegate_) { 689 backoff_delay_ = backoff_delay; 690 InformDelegateFetchIsComplete(); 691 } 692} 693 694void URLFetcherCore::InformDelegateFetchIsComplete() { 695 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 696 if (delegate_) 697 delegate_->OnURLFetchComplete(fetcher_); 698} 699 700void URLFetcherCore::NotifyMalformedContent() { 701 DCHECK(network_task_runner_->BelongsToCurrentThread()); 702 if (url_throttler_entry_ != NULL) { 703 int status_code = response_code_; 704 if (status_code == URLFetcher::RESPONSE_CODE_INVALID) { 705 // The status code will generally be known by the time clients 706 // call the |ReceivedContentWasMalformed()| function (which ends up 707 // calling the current function) but if it's not, we need to assume 708 // the response was successful so that the total failure count 709 // used to calculate exponential back-off goes up. 710 status_code = 200; 711 } 712 url_throttler_entry_->ReceivedContentWasMalformed(status_code); 713 } 714} 715 716void URLFetcherCore::DidFinishWriting(int result) { 717 if (result != OK) { 718 delegate_task_runner_->PostTask( 719 FROM_HERE, 720 base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this)); 721 return; 722 } 723 // If the file was successfully closed, then the URL request is complete. 724 RetryOrCompleteUrlFetch(); 725} 726 727void URLFetcherCore::RetryOrCompleteUrlFetch() { 728 DCHECK(network_task_runner_->BelongsToCurrentThread()); 729 base::TimeDelta backoff_delay; 730 731 // Checks the response from server. 732 if (response_code_ >= 500 || 733 status_.error() == ERR_TEMPORARILY_THROTTLED) { 734 // When encountering a server error, we will send the request again 735 // after backoff time. 736 ++num_retries_on_5xx_; 737 738 // Note that backoff_delay may be 0 because (a) the 739 // URLRequestThrottlerManager and related code does not 740 // necessarily back off on the first error, (b) it only backs off 741 // on some of the 5xx status codes, (c) not all URLRequestContexts 742 // have a throttler manager. 743 base::TimeTicks backoff_release_time = GetBackoffReleaseTime(); 744 backoff_delay = backoff_release_time - base::TimeTicks::Now(); 745 if (backoff_delay < base::TimeDelta()) 746 backoff_delay = base::TimeDelta(); 747 748 if (automatically_retry_on_5xx_ && 749 num_retries_on_5xx_ <= max_retries_on_5xx_) { 750 StartOnIOThread(); 751 return; 752 } 753 } else { 754 backoff_delay = base::TimeDelta(); 755 } 756 757 // Retry if the request failed due to network changes. 758 if (status_.error() == ERR_NETWORK_CHANGED && 759 num_retries_on_network_changes_ < max_retries_on_network_changes_) { 760 ++num_retries_on_network_changes_; 761 762 // Retry soon, after flushing all the current tasks which may include 763 // further network change observers. 764 network_task_runner_->PostTask( 765 FROM_HERE, base::Bind(&URLFetcherCore::StartOnIOThread, this)); 766 return; 767 } 768 769 request_context_getter_ = NULL; 770 first_party_for_cookies_ = GURL(); 771 url_request_data_key_ = NULL; 772 url_request_create_data_callback_.Reset(); 773 bool posted = delegate_task_runner_->PostTask( 774 FROM_HERE, 775 base::Bind(&URLFetcherCore::OnCompletedURLRequest, this, backoff_delay)); 776 777 // If the delegate message loop does not exist any more, then the delegate 778 // should be gone too. 779 DCHECK(posted || !delegate_); 780} 781 782void URLFetcherCore::ReleaseRequest() { 783 upload_progress_checker_timer_.reset(); 784 request_.reset(); 785 g_registry.Get().RemoveURLFetcherCore(this); 786} 787 788base::TimeTicks URLFetcherCore::GetBackoffReleaseTime() { 789 DCHECK(network_task_runner_->BelongsToCurrentThread()); 790 791 if (original_url_throttler_entry_) { 792 base::TimeTicks original_url_backoff = 793 original_url_throttler_entry_->GetExponentialBackoffReleaseTime(); 794 base::TimeTicks destination_url_backoff; 795 if (url_throttler_entry_ != NULL && 796 original_url_throttler_entry_ != url_throttler_entry_) { 797 destination_url_backoff = 798 url_throttler_entry_->GetExponentialBackoffReleaseTime(); 799 } 800 801 return original_url_backoff > destination_url_backoff ? 802 original_url_backoff : destination_url_backoff; 803 } else { 804 return base::TimeTicks(); 805 } 806} 807 808void URLFetcherCore::CompleteAddingUploadDataChunk( 809 const std::string& content, bool is_last_chunk) { 810 if (was_cancelled_) { 811 // Since CompleteAddingUploadDataChunk() is posted as a *delayed* task, it 812 // may run after the URLFetcher was already stopped. 813 return; 814 } 815 DCHECK(is_chunked_upload_); 816 DCHECK(request_.get()); 817 DCHECK(!content.empty()); 818 request_->AppendChunkToUpload(content.data(), 819 static_cast<int>(content.length()), 820 is_last_chunk); 821} 822 823int URLFetcherCore::WriteBuffer(scoped_refptr<DrainableIOBuffer> data) { 824 while (data->BytesRemaining() > 0) { 825 const int result = response_writer_->Write( 826 data, data->BytesRemaining(), 827 base::Bind(&URLFetcherCore::DidWriteBuffer, this, data)); 828 if (result < 0) 829 return result; 830 data->DidConsume(result); 831 } 832 return OK; 833} 834 835void URLFetcherCore::DidWriteBuffer(scoped_refptr<DrainableIOBuffer> data, 836 int result) { 837 if (result >= 0) { // Continue writing. 838 data->DidConsume(result); 839 result = WriteBuffer(data); 840 if (result == ERR_IO_PENDING) 841 return; 842 } 843 844 if (result < 0) { // Handle errors. 845 delegate_task_runner_->PostTask( 846 FROM_HERE, 847 base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this)); 848 return; 849 } 850 // Finished writing buffer_. Read some more. 851 DCHECK_EQ(0, data->BytesRemaining()); 852 ReadResponse(); 853} 854 855void URLFetcherCore::ReadResponse() { 856 // Some servers may treat HEAD requests as GET requests. To free up the 857 // network connection as soon as possible, signal that the request has 858 // completed immediately, without trying to read any data back (all we care 859 // about is the response code and headers, which we already have). 860 int bytes_read = 0; 861 if (request_->status().is_success() && 862 (request_type_ != URLFetcher::HEAD)) 863 request_->Read(buffer_, kBufferSize, &bytes_read); 864 OnReadCompleted(request_.get(), bytes_read); 865} 866 867void URLFetcherCore::DisownFile() { 868 DCHECK(file_writer_); 869 file_writer_->DisownFile(); 870} 871 872void URLFetcherCore::InformDelegateUploadProgress() { 873 DCHECK(network_task_runner_->BelongsToCurrentThread()); 874 if (request_.get()) { 875 int64 current = request_->GetUploadProgress().position(); 876 if (current_upload_bytes_ != current) { 877 current_upload_bytes_ = current; 878 int64 total = -1; 879 if (!is_chunked_upload_) { 880 total = static_cast<int64>(request_->GetUploadProgress().size()); 881 // Total may be zero if the UploadDataStream::Init has not been called 882 // yet. Don't send the upload progress until the size is initialized. 883 if (!total) 884 return; 885 } 886 delegate_task_runner_->PostTask( 887 FROM_HERE, 888 base::Bind( 889 &URLFetcherCore::InformDelegateUploadProgressInDelegateThread, 890 this, current, total)); 891 } 892 } 893} 894 895void URLFetcherCore::InformDelegateUploadProgressInDelegateThread( 896 int64 current, int64 total) { 897 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 898 if (delegate_) 899 delegate_->OnURLFetchUploadProgress(fetcher_, current, total); 900} 901 902void URLFetcherCore::InformDelegateDownloadProgress() { 903 DCHECK(network_task_runner_->BelongsToCurrentThread()); 904 delegate_task_runner_->PostTask( 905 FROM_HERE, 906 base::Bind( 907 &URLFetcherCore::InformDelegateDownloadProgressInDelegateThread, 908 this, current_response_bytes_, total_response_bytes_)); 909} 910 911void URLFetcherCore::InformDelegateDownloadProgressInDelegateThread( 912 int64 current, int64 total) { 913 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 914 if (delegate_) 915 delegate_->OnURLFetchDownloadProgress(fetcher_, current, total); 916} 917 918void URLFetcherCore::InformDelegateDownloadDataIfNecessary(int bytes_read) { 919 DCHECK(network_task_runner_->BelongsToCurrentThread()); 920 if (delegate_ && delegate_->ShouldSendDownloadData()) { 921 scoped_ptr<std::string> download_data( 922 new std::string(buffer_->data(), bytes_read)); 923 delegate_task_runner_->PostTask( 924 FROM_HERE, 925 base::Bind( 926 &URLFetcherCore::InformDelegateDownloadDataInDelegateThread, 927 this, base::Passed(&download_data))); 928 } 929} 930 931void URLFetcherCore::InformDelegateDownloadDataInDelegateThread( 932 scoped_ptr<std::string> download_data) { 933 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 934 if (delegate_) 935 delegate_->OnURLFetchDownloadData(fetcher_, download_data.Pass()); 936} 937 938} // namespace net 939