url_fetcher_core.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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_.get()); 102 DCHECK(request_context_getter_.get()) << "We need an URLRequestContext!"; 103 if (network_task_runner_.get()) { 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_.get()) // 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_.get()); 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_.get()); 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_.get(); 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 = 435 WriteBuffer(new DrainableIOBuffer(buffer_.get(), bytes_read)); 436 if (result < 0) { 437 // Write failed or waiting for write completion. 438 if (result == ERR_IO_PENDING) 439 waiting_on_write = true; 440 break; 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() && !waiting_on_write) || 451 (request_type_ == URLFetcher::HEAD)) { 452 status_ = status; 453 ReleaseRequest(); 454 455 // No more data to write. 456 const int result = response_writer_->Finish( 457 base::Bind(&URLFetcherCore::DidFinishWriting, this)); 458 if (result != ERR_IO_PENDING) 459 DidFinishWriting(result); 460 } 461} 462 463void URLFetcherCore::CancelAll() { 464 g_registry.Get().CancelAll(); 465} 466 467int URLFetcherCore::GetNumFetcherCores() { 468 return g_registry.Get().size(); 469} 470 471void URLFetcherCore::SetEnableInterceptionForTests(bool enabled) { 472 g_interception_enabled = enabled; 473} 474 475void URLFetcherCore::SetIgnoreCertificateRequests(bool ignored) { 476 g_ignore_certificate_requests = ignored; 477} 478 479URLFetcherCore::~URLFetcherCore() { 480 // |request_| should be NULL. If not, it's unsafe to delete it here since we 481 // may not be on the IO thread. 482 DCHECK(!request_.get()); 483} 484 485void URLFetcherCore::StartOnIOThread() { 486 DCHECK(network_task_runner_->BelongsToCurrentThread()); 487 488 switch (response_destination_) { 489 case STRING: 490 response_writer_.reset(new URLFetcherStringWriter(&data_)); 491 break; 492 493 case PERMANENT_FILE: 494 case TEMP_FILE: 495 DCHECK(file_task_runner_.get()) 496 << "Need to set the file task runner."; 497 498 file_writer_ = new URLFetcherFileWriter(file_task_runner_); 499 500 // If the file is successfully created, 501 // URLFetcherCore::StartURLRequestWhenAppropriate() will be called. 502 if (response_destination_ == PERMANENT_FILE) { 503 file_writer_->set_destination_file_path( 504 response_destination_file_path_); 505 } 506 response_writer_.reset(file_writer_); 507 break; 508 509 default: 510 NOTREACHED(); 511 } 512 DCHECK(response_writer_); 513 const int result = response_writer_->Initialize( 514 base::Bind(&URLFetcherCore::DidInitializeWriter, this)); 515 if (result != ERR_IO_PENDING) 516 DidInitializeWriter(result); 517} 518 519void URLFetcherCore::StartURLRequest() { 520 DCHECK(network_task_runner_->BelongsToCurrentThread()); 521 522 if (was_cancelled_) { 523 // Since StartURLRequest() is posted as a *delayed* task, it may 524 // run after the URLFetcher was already stopped. 525 return; 526 } 527 528 DCHECK(request_context_getter_.get()); 529 DCHECK(!request_.get()); 530 531 g_registry.Get().AddURLFetcherCore(this); 532 current_response_bytes_ = 0; 533 request_.reset(request_context_getter_->GetURLRequestContext()->CreateRequest( 534 original_url_, this)); 535 request_->set_stack_trace(stack_trace_); 536 int flags = request_->load_flags() | load_flags_; 537 if (!g_interception_enabled) 538 flags = flags | LOAD_DISABLE_INTERCEPT; 539 540 if (is_chunked_upload_) 541 request_->EnableChunkedUpload(); 542 request_->set_load_flags(flags); 543 request_->SetReferrer(referrer_); 544 request_->set_first_party_for_cookies(first_party_for_cookies_.is_empty() ? 545 original_url_ : first_party_for_cookies_); 546 if (url_request_data_key_ && !url_request_create_data_callback_.is_null()) { 547 request_->SetUserData(url_request_data_key_, 548 url_request_create_data_callback_.Run()); 549 } 550 551 switch (request_type_) { 552 case URLFetcher::GET: 553 break; 554 555 case URLFetcher::POST: 556 case URLFetcher::PUT: 557 case URLFetcher::PATCH: 558 // Upload content must be set. 559 DCHECK(is_chunked_upload_ || upload_content_set_); 560 561 request_->set_method( 562 request_type_ == URLFetcher::POST ? "POST" : 563 request_type_ == URLFetcher::PUT ? "PUT" : "PATCH"); 564 extra_request_headers_.SetHeader(HttpRequestHeaders::kContentType, 565 upload_content_type_); 566 if (!upload_content_type_.empty()) { 567 extra_request_headers_.SetHeader(HttpRequestHeaders::kContentType, 568 upload_content_type_); 569 } 570 if (!upload_content_.empty()) { 571 scoped_ptr<UploadElementReader> reader(new UploadBytesElementReader( 572 upload_content_.data(), upload_content_.size())); 573 request_->set_upload(make_scoped_ptr( 574 UploadDataStream::CreateWithReader(reader.Pass(), 0))); 575 } else if (!upload_file_path_.empty()) { 576 scoped_ptr<UploadElementReader> reader( 577 new UploadFileElementReader(upload_file_task_runner_.get(), 578 upload_file_path_, 579 upload_range_offset_, 580 upload_range_length_, 581 base::Time())); 582 request_->set_upload(make_scoped_ptr( 583 UploadDataStream::CreateWithReader(reader.Pass(), 0))); 584 } 585 586 current_upload_bytes_ = -1; 587 // TODO(kinaba): http://crbug.com/118103. Implement upload callback in the 588 // layer and avoid using timer here. 589 upload_progress_checker_timer_.reset( 590 new base::RepeatingTimer<URLFetcherCore>()); 591 upload_progress_checker_timer_->Start( 592 FROM_HERE, 593 base::TimeDelta::FromMilliseconds(kUploadProgressTimerInterval), 594 this, 595 &URLFetcherCore::InformDelegateUploadProgress); 596 break; 597 598 case URLFetcher::HEAD: 599 request_->set_method("HEAD"); 600 break; 601 602 case URLFetcher::DELETE_REQUEST: 603 request_->set_method("DELETE"); 604 break; 605 606 default: 607 NOTREACHED(); 608 } 609 610 if (!extra_request_headers_.IsEmpty()) 611 request_->SetExtraRequestHeaders(extra_request_headers_); 612 613 // There might be data left over from a previous request attempt. 614 data_.clear(); 615 616 // If we are writing the response to a file, the only caller 617 // of this function should have created it and not written yet. 618 DCHECK(!file_writer_ || file_writer_->total_bytes_written() == 0); 619 620 request_->Start(); 621} 622 623void URLFetcherCore::DidInitializeWriter(int result) { 624 if (result != OK) { 625 delegate_task_runner_->PostTask( 626 FROM_HERE, 627 base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this)); 628 return; 629 } 630 StartURLRequestWhenAppropriate(); 631} 632 633void URLFetcherCore::StartURLRequestWhenAppropriate() { 634 DCHECK(network_task_runner_->BelongsToCurrentThread()); 635 636 if (was_cancelled_) 637 return; 638 639 DCHECK(request_context_getter_.get()); 640 641 int64 delay = 0LL; 642 if (original_url_throttler_entry_.get() == NULL) { 643 URLRequestThrottlerManager* manager = 644 request_context_getter_->GetURLRequestContext()->throttler_manager(); 645 if (manager) { 646 original_url_throttler_entry_ = 647 manager->RegisterRequestUrl(original_url_); 648 } 649 } 650 if (original_url_throttler_entry_.get() != NULL) { 651 delay = original_url_throttler_entry_->ReserveSendingTimeForNextRequest( 652 GetBackoffReleaseTime()); 653 } 654 655 if (delay == 0) { 656 StartURLRequest(); 657 } else { 658 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( 659 FROM_HERE, base::Bind(&URLFetcherCore::StartURLRequest, this), 660 base::TimeDelta::FromMilliseconds(delay)); 661 } 662} 663 664void URLFetcherCore::CancelURLRequest() { 665 DCHECK(network_task_runner_->BelongsToCurrentThread()); 666 667 if (request_.get()) { 668 request_->Cancel(); 669 ReleaseRequest(); 670 } 671 // Release the reference to the request context. There could be multiple 672 // references to URLFetcher::Core at this point so it may take a while to 673 // delete the object, but we cannot delay the destruction of the request 674 // context. 675 request_context_getter_ = NULL; 676 first_party_for_cookies_ = GURL(); 677 url_request_data_key_ = NULL; 678 url_request_create_data_callback_.Reset(); 679 was_cancelled_ = true; 680 response_writer_.reset(); 681 file_writer_ = NULL; 682} 683 684void URLFetcherCore::OnCompletedURLRequest( 685 base::TimeDelta backoff_delay) { 686 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 687 688 // Save the status and backoff_delay so that delegates can read it. 689 if (delegate_) { 690 backoff_delay_ = backoff_delay; 691 InformDelegateFetchIsComplete(); 692 } 693} 694 695void URLFetcherCore::InformDelegateFetchIsComplete() { 696 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 697 if (delegate_) 698 delegate_->OnURLFetchComplete(fetcher_); 699} 700 701void URLFetcherCore::NotifyMalformedContent() { 702 DCHECK(network_task_runner_->BelongsToCurrentThread()); 703 if (url_throttler_entry_.get() != NULL) { 704 int status_code = response_code_; 705 if (status_code == URLFetcher::RESPONSE_CODE_INVALID) { 706 // The status code will generally be known by the time clients 707 // call the |ReceivedContentWasMalformed()| function (which ends up 708 // calling the current function) but if it's not, we need to assume 709 // the response was successful so that the total failure count 710 // used to calculate exponential back-off goes up. 711 status_code = 200; 712 } 713 url_throttler_entry_->ReceivedContentWasMalformed(status_code); 714 } 715} 716 717void URLFetcherCore::DidFinishWriting(int result) { 718 if (result != OK) { 719 delegate_task_runner_->PostTask( 720 FROM_HERE, 721 base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this)); 722 return; 723 } 724 // If the file was successfully closed, then the URL request is complete. 725 RetryOrCompleteUrlFetch(); 726} 727 728void URLFetcherCore::RetryOrCompleteUrlFetch() { 729 DCHECK(network_task_runner_->BelongsToCurrentThread()); 730 base::TimeDelta backoff_delay; 731 732 // Checks the response from server. 733 if (response_code_ >= 500 || 734 status_.error() == ERR_TEMPORARILY_THROTTLED) { 735 // When encountering a server error, we will send the request again 736 // after backoff time. 737 ++num_retries_on_5xx_; 738 739 // Note that backoff_delay may be 0 because (a) the 740 // URLRequestThrottlerManager and related code does not 741 // necessarily back off on the first error, (b) it only backs off 742 // on some of the 5xx status codes, (c) not all URLRequestContexts 743 // have a throttler manager. 744 base::TimeTicks backoff_release_time = GetBackoffReleaseTime(); 745 backoff_delay = backoff_release_time - base::TimeTicks::Now(); 746 if (backoff_delay < base::TimeDelta()) 747 backoff_delay = base::TimeDelta(); 748 749 if (automatically_retry_on_5xx_ && 750 num_retries_on_5xx_ <= max_retries_on_5xx_) { 751 StartOnIOThread(); 752 return; 753 } 754 } else { 755 backoff_delay = base::TimeDelta(); 756 } 757 758 // Retry if the request failed due to network changes. 759 if (status_.error() == ERR_NETWORK_CHANGED && 760 num_retries_on_network_changes_ < max_retries_on_network_changes_) { 761 ++num_retries_on_network_changes_; 762 763 // Retry soon, after flushing all the current tasks which may include 764 // further network change observers. 765 network_task_runner_->PostTask( 766 FROM_HERE, base::Bind(&URLFetcherCore::StartOnIOThread, this)); 767 return; 768 } 769 770 request_context_getter_ = NULL; 771 first_party_for_cookies_ = GURL(); 772 url_request_data_key_ = NULL; 773 url_request_create_data_callback_.Reset(); 774 bool posted = delegate_task_runner_->PostTask( 775 FROM_HERE, 776 base::Bind(&URLFetcherCore::OnCompletedURLRequest, this, backoff_delay)); 777 778 // If the delegate message loop does not exist any more, then the delegate 779 // should be gone too. 780 DCHECK(posted || !delegate_); 781} 782 783void URLFetcherCore::ReleaseRequest() { 784 upload_progress_checker_timer_.reset(); 785 request_.reset(); 786 g_registry.Get().RemoveURLFetcherCore(this); 787} 788 789base::TimeTicks URLFetcherCore::GetBackoffReleaseTime() { 790 DCHECK(network_task_runner_->BelongsToCurrentThread()); 791 792 if (original_url_throttler_entry_.get()) { 793 base::TimeTicks original_url_backoff = 794 original_url_throttler_entry_->GetExponentialBackoffReleaseTime(); 795 base::TimeTicks destination_url_backoff; 796 if (url_throttler_entry_.get() != NULL && 797 original_url_throttler_entry_.get() != url_throttler_entry_.get()) { 798 destination_url_backoff = 799 url_throttler_entry_->GetExponentialBackoffReleaseTime(); 800 } 801 802 return original_url_backoff > destination_url_backoff ? 803 original_url_backoff : destination_url_backoff; 804 } else { 805 return base::TimeTicks(); 806 } 807} 808 809void URLFetcherCore::CompleteAddingUploadDataChunk( 810 const std::string& content, bool is_last_chunk) { 811 if (was_cancelled_) { 812 // Since CompleteAddingUploadDataChunk() is posted as a *delayed* task, it 813 // may run after the URLFetcher was already stopped. 814 return; 815 } 816 DCHECK(is_chunked_upload_); 817 DCHECK(request_.get()); 818 DCHECK(!content.empty()); 819 request_->AppendChunkToUpload(content.data(), 820 static_cast<int>(content.length()), 821 is_last_chunk); 822} 823 824int URLFetcherCore::WriteBuffer(scoped_refptr<DrainableIOBuffer> data) { 825 while (data->BytesRemaining() > 0) { 826 const int result = response_writer_->Write( 827 data.get(), 828 data->BytesRemaining(), 829 base::Bind(&URLFetcherCore::DidWriteBuffer, this, data)); 830 if (result < 0) 831 return result; 832 data->DidConsume(result); 833 } 834 return OK; 835} 836 837void URLFetcherCore::DidWriteBuffer(scoped_refptr<DrainableIOBuffer> data, 838 int result) { 839 if (result >= 0) { // Continue writing. 840 data->DidConsume(result); 841 result = WriteBuffer(data); 842 if (result == ERR_IO_PENDING) 843 return; 844 } 845 846 if (result < 0) { // Handle errors. 847 delegate_task_runner_->PostTask( 848 FROM_HERE, 849 base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this)); 850 return; 851 } 852 // Finished writing buffer_. Read some more. 853 DCHECK_EQ(0, data->BytesRemaining()); 854 ReadResponse(); 855} 856 857void URLFetcherCore::ReadResponse() { 858 // Some servers may treat HEAD requests as GET requests. To free up the 859 // network connection as soon as possible, signal that the request has 860 // completed immediately, without trying to read any data back (all we care 861 // about is the response code and headers, which we already have). 862 int bytes_read = 0; 863 if (request_->status().is_success() && 864 (request_type_ != URLFetcher::HEAD)) 865 request_->Read(buffer_.get(), kBufferSize, &bytes_read); 866 OnReadCompleted(request_.get(), bytes_read); 867} 868 869void URLFetcherCore::DisownFile() { 870 DCHECK(file_writer_); 871 file_writer_->DisownFile(); 872} 873 874void URLFetcherCore::InformDelegateUploadProgress() { 875 DCHECK(network_task_runner_->BelongsToCurrentThread()); 876 if (request_.get()) { 877 int64 current = request_->GetUploadProgress().position(); 878 if (current_upload_bytes_ != current) { 879 current_upload_bytes_ = current; 880 int64 total = -1; 881 if (!is_chunked_upload_) { 882 total = static_cast<int64>(request_->GetUploadProgress().size()); 883 // Total may be zero if the UploadDataStream::Init has not been called 884 // yet. Don't send the upload progress until the size is initialized. 885 if (!total) 886 return; 887 } 888 delegate_task_runner_->PostTask( 889 FROM_HERE, 890 base::Bind( 891 &URLFetcherCore::InformDelegateUploadProgressInDelegateThread, 892 this, current, total)); 893 } 894 } 895} 896 897void URLFetcherCore::InformDelegateUploadProgressInDelegateThread( 898 int64 current, int64 total) { 899 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 900 if (delegate_) 901 delegate_->OnURLFetchUploadProgress(fetcher_, current, total); 902} 903 904void URLFetcherCore::InformDelegateDownloadProgress() { 905 DCHECK(network_task_runner_->BelongsToCurrentThread()); 906 delegate_task_runner_->PostTask( 907 FROM_HERE, 908 base::Bind( 909 &URLFetcherCore::InformDelegateDownloadProgressInDelegateThread, 910 this, current_response_bytes_, total_response_bytes_)); 911} 912 913void URLFetcherCore::InformDelegateDownloadProgressInDelegateThread( 914 int64 current, int64 total) { 915 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 916 if (delegate_) 917 delegate_->OnURLFetchDownloadProgress(fetcher_, current, total); 918} 919 920void URLFetcherCore::InformDelegateDownloadDataIfNecessary(int bytes_read) { 921 DCHECK(network_task_runner_->BelongsToCurrentThread()); 922 if (delegate_ && delegate_->ShouldSendDownloadData()) { 923 scoped_ptr<std::string> download_data( 924 new std::string(buffer_->data(), bytes_read)); 925 delegate_task_runner_->PostTask( 926 FROM_HERE, 927 base::Bind( 928 &URLFetcherCore::InformDelegateDownloadDataInDelegateThread, 929 this, base::Passed(&download_data))); 930 } 931} 932 933void URLFetcherCore::InformDelegateDownloadDataInDelegateThread( 934 scoped_ptr<std::string> download_data) { 935 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 936 if (delegate_) 937 delegate_->OnURLFetchDownloadData(fetcher_, download_data.Pass()); 938} 939 940} // namespace net 941