url_fetcher_core.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
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_(base::ThreadTaskRunnerHandle::Get()), 73 load_flags_(LOAD_NORMAL), 74 response_code_(URLFetcher::RESPONSE_CODE_INVALID), 75 buffer_(new IOBuffer(kBufferSize)), 76 url_request_data_key_(NULL), 77 was_fetched_via_proxy_(false), 78 upload_content_set_(false), 79 upload_range_offset_(0), 80 upload_range_length_(0), 81 is_chunked_upload_(false), 82 was_cancelled_(false), 83 file_writer_(NULL), 84 response_destination_(STRING), 85 stop_on_redirect_(false), 86 stopped_on_redirect_(false), 87 automatically_retry_on_5xx_(true), 88 num_retries_on_5xx_(0), 89 max_retries_on_5xx_(0), 90 num_retries_on_network_changes_(0), 91 max_retries_on_network_changes_(0), 92 current_upload_bytes_(-1), 93 current_response_bytes_(0), 94 total_response_bytes_(-1) { 95 CHECK(original_url_.is_valid()); 96} 97 98void URLFetcherCore::Start() { 99 DCHECK(delegate_task_runner_.get()); 100 DCHECK(request_context_getter_.get()) << "We need an URLRequestContext!"; 101 if (network_task_runner_.get()) { 102 DCHECK_EQ(network_task_runner_, 103 request_context_getter_->GetNetworkTaskRunner()); 104 } else { 105 network_task_runner_ = request_context_getter_->GetNetworkTaskRunner(); 106 } 107 DCHECK(network_task_runner_.get()) << "We need an IO task runner"; 108 109 network_task_runner_->PostTask( 110 FROM_HERE, base::Bind(&URLFetcherCore::StartOnIOThread, this)); 111} 112 113void URLFetcherCore::Stop() { 114 if (delegate_task_runner_.get()) // May be NULL in tests. 115 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 116 117 delegate_ = NULL; 118 fetcher_ = NULL; 119 if (!network_task_runner_.get()) 120 return; 121 if (network_task_runner_->RunsTasksOnCurrentThread()) { 122 CancelURLRequest(); 123 } else { 124 network_task_runner_->PostTask( 125 FROM_HERE, base::Bind(&URLFetcherCore::CancelURLRequest, this)); 126 } 127} 128 129void URLFetcherCore::SetUploadData(const std::string& upload_content_type, 130 const std::string& upload_content) { 131 DCHECK(!is_chunked_upload_); 132 DCHECK(!upload_content_set_); 133 DCHECK(upload_content_.empty()); 134 DCHECK(upload_file_path_.empty()); 135 DCHECK(upload_content_type_.empty()); 136 137 // Empty |upload_content_type| is allowed iff the |upload_content| is empty. 138 DCHECK(upload_content.empty() || !upload_content_type.empty()); 139 140 upload_content_type_ = upload_content_type; 141 upload_content_ = upload_content; 142 upload_content_set_ = true; 143} 144 145void URLFetcherCore::SetUploadFilePath( 146 const std::string& upload_content_type, 147 const base::FilePath& file_path, 148 uint64 range_offset, 149 uint64 range_length, 150 scoped_refptr<base::TaskRunner> file_task_runner) { 151 DCHECK(!is_chunked_upload_); 152 DCHECK(!upload_content_set_); 153 DCHECK(upload_content_.empty()); 154 DCHECK(upload_file_path_.empty()); 155 DCHECK_EQ(upload_range_offset_, 0ULL); 156 DCHECK_EQ(upload_range_length_, 0ULL); 157 DCHECK(upload_content_type_.empty()); 158 DCHECK(!upload_content_type.empty()); 159 160 upload_content_type_ = upload_content_type; 161 upload_file_path_ = file_path; 162 upload_range_offset_ = range_offset; 163 upload_range_length_ = range_length; 164 upload_file_task_runner_ = file_task_runner; 165 upload_content_set_ = true; 166} 167 168void URLFetcherCore::SetChunkedUpload(const std::string& content_type) { 169 DCHECK(is_chunked_upload_ || 170 (upload_content_type_.empty() && 171 upload_content_.empty())); 172 173 // Empty |content_type| is not allowed here, because it is impossible 174 // to ensure non-empty upload content as it is not yet supplied. 175 DCHECK(!content_type.empty()); 176 177 upload_content_type_ = content_type; 178 upload_content_.clear(); 179 is_chunked_upload_ = true; 180} 181 182void URLFetcherCore::AppendChunkToUpload(const std::string& content, 183 bool is_last_chunk) { 184 DCHECK(delegate_task_runner_.get()); 185 DCHECK(network_task_runner_.get()); 186 network_task_runner_->PostTask( 187 FROM_HERE, 188 base::Bind(&URLFetcherCore::CompleteAddingUploadDataChunk, this, content, 189 is_last_chunk)); 190} 191 192void URLFetcherCore::SetLoadFlags(int load_flags) { 193 load_flags_ = load_flags; 194} 195 196int URLFetcherCore::GetLoadFlags() const { 197 return load_flags_; 198} 199 200void URLFetcherCore::SetReferrer(const std::string& referrer) { 201 referrer_ = referrer; 202} 203 204void URLFetcherCore::SetExtraRequestHeaders( 205 const std::string& extra_request_headers) { 206 extra_request_headers_.Clear(); 207 extra_request_headers_.AddHeadersFromString(extra_request_headers); 208} 209 210void URLFetcherCore::AddExtraRequestHeader(const std::string& header_line) { 211 extra_request_headers_.AddHeaderFromString(header_line); 212} 213 214void URLFetcherCore::GetExtraRequestHeaders( 215 HttpRequestHeaders* headers) const { 216 headers->CopyFrom(extra_request_headers_); 217} 218 219void URLFetcherCore::SetRequestContext( 220 URLRequestContextGetter* request_context_getter) { 221 DCHECK(!request_context_getter_.get()); 222 DCHECK(request_context_getter); 223 request_context_getter_ = request_context_getter; 224} 225 226void URLFetcherCore::SetFirstPartyForCookies( 227 const GURL& first_party_for_cookies) { 228 DCHECK(first_party_for_cookies_.is_empty()); 229 first_party_for_cookies_ = first_party_for_cookies; 230} 231 232void URLFetcherCore::SetURLRequestUserData( 233 const void* key, 234 const URLFetcher::CreateDataCallback& create_data_callback) { 235 DCHECK(key); 236 DCHECK(!create_data_callback.is_null()); 237 url_request_data_key_ = key; 238 url_request_create_data_callback_ = create_data_callback; 239} 240 241void URLFetcherCore::SetStopOnRedirect(bool stop_on_redirect) { 242 stop_on_redirect_ = stop_on_redirect; 243} 244 245void URLFetcherCore::SetAutomaticallyRetryOn5xx(bool retry) { 246 automatically_retry_on_5xx_ = retry; 247} 248 249void URLFetcherCore::SetMaxRetriesOn5xx(int max_retries) { 250 max_retries_on_5xx_ = max_retries; 251} 252 253int URLFetcherCore::GetMaxRetriesOn5xx() const { 254 return max_retries_on_5xx_; 255} 256 257base::TimeDelta URLFetcherCore::GetBackoffDelay() const { 258 return backoff_delay_; 259} 260 261void URLFetcherCore::SetAutomaticallyRetryOnNetworkChanges(int max_retries) { 262 max_retries_on_network_changes_ = max_retries; 263} 264 265void URLFetcherCore::SaveResponseToFileAtPath( 266 const base::FilePath& file_path, 267 scoped_refptr<base::TaskRunner> file_task_runner) { 268 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 269 file_task_runner_ = file_task_runner; 270 response_destination_ = URLFetcherCore::PERMANENT_FILE; 271 response_destination_file_path_ = file_path; 272} 273 274void URLFetcherCore::SaveResponseToTemporaryFile( 275 scoped_refptr<base::TaskRunner> file_task_runner) { 276 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 277 file_task_runner_ = file_task_runner; 278 response_destination_ = URLFetcherCore::TEMP_FILE; 279} 280 281HttpResponseHeaders* URLFetcherCore::GetResponseHeaders() const { 282 return response_headers_.get(); 283} 284 285// TODO(panayiotis): socket_address_ is written in the IO thread, 286// if this is accessed in the UI thread, this could result in a race. 287// Same for response_headers_ above and was_fetched_via_proxy_ below. 288HostPortPair URLFetcherCore::GetSocketAddress() const { 289 return socket_address_; 290} 291 292bool URLFetcherCore::WasFetchedViaProxy() const { 293 return was_fetched_via_proxy_; 294} 295 296const GURL& URLFetcherCore::GetOriginalURL() const { 297 return original_url_; 298} 299 300const GURL& URLFetcherCore::GetURL() const { 301 return url_; 302} 303 304const URLRequestStatus& URLFetcherCore::GetStatus() const { 305 return status_; 306} 307 308int URLFetcherCore::GetResponseCode() const { 309 return response_code_; 310} 311 312const ResponseCookies& URLFetcherCore::GetCookies() const { 313 return cookies_; 314} 315 316bool URLFetcherCore::FileErrorOccurred(int* out_error_code) const { 317 // Can't have a file error if no file is being created or written to. 318 if (!file_writer_) 319 return false; 320 321 int error_code = file_writer_->error_code(); 322 if (error_code == OK) 323 return false; 324 325 *out_error_code = error_code; 326 return true; 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 if (response_destination_ != URLFetcherCore::STRING) 340 return false; 341 342 *out_response_string = data_; 343 UMA_HISTOGRAM_MEMORY_KB("UrlFetcher.StringResponseSize", 344 (data_.length() / 1024)); 345 346 return true; 347} 348 349bool URLFetcherCore::GetResponseAsFilePath(bool take_ownership, 350 base::FilePath* out_response_path) { 351 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 352 const bool destination_is_file = 353 response_destination_ == URLFetcherCore::TEMP_FILE || 354 response_destination_ == URLFetcherCore::PERMANENT_FILE; 355 if (!destination_is_file || !file_writer_) 356 return false; 357 358 *out_response_path = file_writer_->file_path(); 359 360 if (take_ownership) { 361 network_task_runner_->PostTask( 362 FROM_HERE, 363 base::Bind(&URLFetcherCore::DisownFile, this)); 364 } 365 return true; 366} 367 368void URLFetcherCore::OnReceivedRedirect(URLRequest* request, 369 const GURL& new_url, 370 bool* defer_redirect) { 371 DCHECK_EQ(request, request_.get()); 372 DCHECK(network_task_runner_->BelongsToCurrentThread()); 373 if (stop_on_redirect_) { 374 stopped_on_redirect_ = true; 375 url_ = new_url; 376 response_code_ = request_->GetResponseCode(); 377 was_fetched_via_proxy_ = request_->was_fetched_via_proxy(); 378 request->Cancel(); 379 OnReadCompleted(request, 0); 380 } 381} 382 383void URLFetcherCore::OnResponseStarted(URLRequest* request) { 384 DCHECK_EQ(request, request_.get()); 385 DCHECK(network_task_runner_->BelongsToCurrentThread()); 386 if (request_->status().is_success()) { 387 response_code_ = request_->GetResponseCode(); 388 response_headers_ = request_->response_headers(); 389 socket_address_ = request_->GetSocketAddress(); 390 was_fetched_via_proxy_ = request_->was_fetched_via_proxy(); 391 total_response_bytes_ = request_->GetExpectedContentSize(); 392 } 393 394 ReadResponse(); 395} 396 397void URLFetcherCore::OnCertificateRequested( 398 URLRequest* request, 399 SSLCertRequestInfo* cert_request_info) { 400 DCHECK_EQ(request, request_.get()); 401 DCHECK(network_task_runner_->BelongsToCurrentThread()); 402 403 if (g_ignore_certificate_requests) { 404 request->ContinueWithCertificate(NULL); 405 } else { 406 request->Cancel(); 407 } 408} 409 410void URLFetcherCore::OnReadCompleted(URLRequest* request, 411 int bytes_read) { 412 DCHECK(request == request_); 413 DCHECK(network_task_runner_->BelongsToCurrentThread()); 414 415 if (!stopped_on_redirect_) 416 url_ = request->url(); 417 URLRequestThrottlerManager* throttler_manager = 418 request->context()->throttler_manager(); 419 if (throttler_manager) { 420 url_throttler_entry_ = throttler_manager->RegisterRequestUrl(url_); 421 } 422 423 bool waiting_on_write = false; 424 do { 425 if (!request_->status().is_success() || bytes_read <= 0) 426 break; 427 428 current_response_bytes_ += bytes_read; 429 InformDelegateDownloadProgress(); 430 InformDelegateDownloadDataIfNecessary(bytes_read); 431 432 const int result = 433 WriteBuffer(new DrainableIOBuffer(buffer_.get(), bytes_read)); 434 if (result < 0) { 435 // Write failed or waiting for write completion. 436 if (result == ERR_IO_PENDING) 437 waiting_on_write = true; 438 break; 439 } 440 } while (request_->Read(buffer_.get(), kBufferSize, &bytes_read)); 441 442 const URLRequestStatus status = request_->status(); 443 444 if (status.is_success()) 445 request_->GetResponseCookies(&cookies_); 446 447 // See comments re: HEAD requests in ReadResponse(). 448 if ((!status.is_io_pending() && !waiting_on_write) || 449 (request_type_ == URLFetcher::HEAD)) { 450 status_ = status; 451 ReleaseRequest(); 452 453 // No more data to write. 454 const int result = response_writer_->Finish( 455 base::Bind(&URLFetcherCore::DidFinishWriting, this)); 456 if (result != ERR_IO_PENDING) 457 DidFinishWriting(result); 458 } 459} 460 461void URLFetcherCore::CancelAll() { 462 g_registry.Get().CancelAll(); 463} 464 465int URLFetcherCore::GetNumFetcherCores() { 466 return g_registry.Get().size(); 467} 468 469void URLFetcherCore::SetEnableInterceptionForTests(bool enabled) { 470 g_interception_enabled = enabled; 471} 472 473void URLFetcherCore::SetIgnoreCertificateRequests(bool ignored) { 474 g_ignore_certificate_requests = ignored; 475} 476 477URLFetcherCore::~URLFetcherCore() { 478 // |request_| should be NULL. If not, it's unsafe to delete it here since we 479 // may not be on the IO thread. 480 DCHECK(!request_.get()); 481} 482 483void URLFetcherCore::StartOnIOThread() { 484 DCHECK(network_task_runner_->BelongsToCurrentThread()); 485 486 switch (response_destination_) { 487 case STRING: 488 response_writer_.reset(new URLFetcherStringWriter(&data_)); 489 break; 490 491 case PERMANENT_FILE: 492 case TEMP_FILE: 493 DCHECK(file_task_runner_.get()) 494 << "Need to set the file task runner."; 495 496 file_writer_ = new URLFetcherFileWriter(file_task_runner_); 497 498 // If the file is successfully created, 499 // URLFetcherCore::StartURLRequestWhenAppropriate() will be called. 500 if (response_destination_ == PERMANENT_FILE) { 501 file_writer_->set_destination_file_path( 502 response_destination_file_path_); 503 } 504 response_writer_.reset(file_writer_); 505 break; 506 507 default: 508 NOTREACHED(); 509 } 510 DCHECK(response_writer_); 511 const int result = response_writer_->Initialize( 512 base::Bind(&URLFetcherCore::DidInitializeWriter, this)); 513 if (result != ERR_IO_PENDING) 514 DidInitializeWriter(result); 515} 516 517void URLFetcherCore::StartURLRequest() { 518 DCHECK(network_task_runner_->BelongsToCurrentThread()); 519 520 if (was_cancelled_) { 521 // Since StartURLRequest() is posted as a *delayed* task, it may 522 // run after the URLFetcher was already stopped. 523 return; 524 } 525 526 DCHECK(request_context_getter_.get()); 527 DCHECK(!request_.get()); 528 529 g_registry.Get().AddURLFetcherCore(this); 530 current_response_bytes_ = 0; 531 request_.reset(request_context_getter_->GetURLRequestContext()->CreateRequest( 532 original_url_, this)); 533 request_->set_stack_trace(stack_trace_); 534 int flags = request_->load_flags() | load_flags_; 535 if (!g_interception_enabled) 536 flags = flags | LOAD_DISABLE_INTERCEPT; 537 538 if (is_chunked_upload_) 539 request_->EnableChunkedUpload(); 540 request_->set_load_flags(flags); 541 request_->SetReferrer(referrer_); 542 request_->set_first_party_for_cookies(first_party_for_cookies_.is_empty() ? 543 original_url_ : first_party_for_cookies_); 544 if (url_request_data_key_ && !url_request_create_data_callback_.is_null()) { 545 request_->SetUserData(url_request_data_key_, 546 url_request_create_data_callback_.Run()); 547 } 548 549 switch (request_type_) { 550 case URLFetcher::GET: 551 break; 552 553 case URLFetcher::POST: 554 case URLFetcher::PUT: 555 case URLFetcher::PATCH: 556 // Upload content must be set. 557 DCHECK(is_chunked_upload_ || upload_content_set_); 558 559 request_->set_method( 560 request_type_ == URLFetcher::POST ? "POST" : 561 request_type_ == URLFetcher::PUT ? "PUT" : "PATCH"); 562 extra_request_headers_.SetHeader(HttpRequestHeaders::kContentType, 563 upload_content_type_); 564 if (!upload_content_type_.empty()) { 565 extra_request_headers_.SetHeader(HttpRequestHeaders::kContentType, 566 upload_content_type_); 567 } 568 if (!upload_content_.empty()) { 569 scoped_ptr<UploadElementReader> reader(new UploadBytesElementReader( 570 upload_content_.data(), upload_content_.size())); 571 request_->set_upload(make_scoped_ptr( 572 UploadDataStream::CreateWithReader(reader.Pass(), 0))); 573 } else if (!upload_file_path_.empty()) { 574 scoped_ptr<UploadElementReader> reader( 575 new UploadFileElementReader(upload_file_task_runner_.get(), 576 upload_file_path_, 577 upload_range_offset_, 578 upload_range_length_, 579 base::Time())); 580 request_->set_upload(make_scoped_ptr( 581 UploadDataStream::CreateWithReader(reader.Pass(), 0))); 582 } 583 584 current_upload_bytes_ = -1; 585 // TODO(kinaba): http://crbug.com/118103. Implement upload callback in the 586 // layer and avoid using timer here. 587 upload_progress_checker_timer_.reset( 588 new base::RepeatingTimer<URLFetcherCore>()); 589 upload_progress_checker_timer_->Start( 590 FROM_HERE, 591 base::TimeDelta::FromMilliseconds(kUploadProgressTimerInterval), 592 this, 593 &URLFetcherCore::InformDelegateUploadProgress); 594 break; 595 596 case URLFetcher::HEAD: 597 request_->set_method("HEAD"); 598 break; 599 600 case URLFetcher::DELETE_REQUEST: 601 request_->set_method("DELETE"); 602 break; 603 604 default: 605 NOTREACHED(); 606 } 607 608 if (!extra_request_headers_.IsEmpty()) 609 request_->SetExtraRequestHeaders(extra_request_headers_); 610 611 // There might be data left over from a previous request attempt. 612 data_.clear(); 613 614 // If we are writing the response to a file, the only caller 615 // of this function should have created it and not written yet. 616 DCHECK(!file_writer_ || file_writer_->total_bytes_written() == 0); 617 618 request_->Start(); 619} 620 621void URLFetcherCore::DidInitializeWriter(int result) { 622 if (result != OK) { 623 delegate_task_runner_->PostTask( 624 FROM_HERE, 625 base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this)); 626 return; 627 } 628 StartURLRequestWhenAppropriate(); 629} 630 631void URLFetcherCore::StartURLRequestWhenAppropriate() { 632 DCHECK(network_task_runner_->BelongsToCurrentThread()); 633 634 if (was_cancelled_) 635 return; 636 637 DCHECK(request_context_getter_.get()); 638 639 int64 delay = 0LL; 640 if (original_url_throttler_entry_.get() == NULL) { 641 URLRequestThrottlerManager* manager = 642 request_context_getter_->GetURLRequestContext()->throttler_manager(); 643 if (manager) { 644 original_url_throttler_entry_ = 645 manager->RegisterRequestUrl(original_url_); 646 } 647 } 648 if (original_url_throttler_entry_.get() != NULL) { 649 delay = original_url_throttler_entry_->ReserveSendingTimeForNextRequest( 650 GetBackoffReleaseTime()); 651 } 652 653 if (delay == 0) { 654 StartURLRequest(); 655 } else { 656 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( 657 FROM_HERE, base::Bind(&URLFetcherCore::StartURLRequest, this), 658 base::TimeDelta::FromMilliseconds(delay)); 659 } 660} 661 662void URLFetcherCore::CancelURLRequest() { 663 DCHECK(network_task_runner_->BelongsToCurrentThread()); 664 665 if (request_.get()) { 666 request_->Cancel(); 667 ReleaseRequest(); 668 } 669 // Release the reference to the request context. There could be multiple 670 // references to URLFetcher::Core at this point so it may take a while to 671 // delete the object, but we cannot delay the destruction of the request 672 // context. 673 request_context_getter_ = NULL; 674 first_party_for_cookies_ = GURL(); 675 url_request_data_key_ = NULL; 676 url_request_create_data_callback_.Reset(); 677 was_cancelled_ = true; 678 response_writer_.reset(); 679 file_writer_ = NULL; 680} 681 682void URLFetcherCore::OnCompletedURLRequest( 683 base::TimeDelta backoff_delay) { 684 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 685 686 // Save the status and backoff_delay so that delegates can read it. 687 if (delegate_) { 688 backoff_delay_ = backoff_delay; 689 InformDelegateFetchIsComplete(); 690 } 691} 692 693void URLFetcherCore::InformDelegateFetchIsComplete() { 694 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 695 if (delegate_) 696 delegate_->OnURLFetchComplete(fetcher_); 697} 698 699void URLFetcherCore::NotifyMalformedContent() { 700 DCHECK(network_task_runner_->BelongsToCurrentThread()); 701 if (url_throttler_entry_.get() != NULL) { 702 int status_code = response_code_; 703 if (status_code == URLFetcher::RESPONSE_CODE_INVALID) { 704 // The status code will generally be known by the time clients 705 // call the |ReceivedContentWasMalformed()| function (which ends up 706 // calling the current function) but if it's not, we need to assume 707 // the response was successful so that the total failure count 708 // used to calculate exponential back-off goes up. 709 status_code = 200; 710 } 711 url_throttler_entry_->ReceivedContentWasMalformed(status_code); 712 } 713} 714 715void URLFetcherCore::DidFinishWriting(int result) { 716 if (result != OK) { 717 delegate_task_runner_->PostTask( 718 FROM_HERE, 719 base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this)); 720 return; 721 } 722 // If the file was successfully closed, then the URL request is complete. 723 RetryOrCompleteUrlFetch(); 724} 725 726void URLFetcherCore::RetryOrCompleteUrlFetch() { 727 DCHECK(network_task_runner_->BelongsToCurrentThread()); 728 base::TimeDelta backoff_delay; 729 730 // Checks the response from server. 731 if (response_code_ >= 500 || 732 status_.error() == ERR_TEMPORARILY_THROTTLED) { 733 // When encountering a server error, we will send the request again 734 // after backoff time. 735 ++num_retries_on_5xx_; 736 737 // Note that backoff_delay may be 0 because (a) the 738 // URLRequestThrottlerManager and related code does not 739 // necessarily back off on the first error, (b) it only backs off 740 // on some of the 5xx status codes, (c) not all URLRequestContexts 741 // have a throttler manager. 742 base::TimeTicks backoff_release_time = GetBackoffReleaseTime(); 743 backoff_delay = backoff_release_time - base::TimeTicks::Now(); 744 if (backoff_delay < base::TimeDelta()) 745 backoff_delay = base::TimeDelta(); 746 747 if (automatically_retry_on_5xx_ && 748 num_retries_on_5xx_ <= max_retries_on_5xx_) { 749 StartOnIOThread(); 750 return; 751 } 752 } else { 753 backoff_delay = base::TimeDelta(); 754 } 755 756 // Retry if the request failed due to network changes. 757 if (status_.error() == ERR_NETWORK_CHANGED && 758 num_retries_on_network_changes_ < max_retries_on_network_changes_) { 759 ++num_retries_on_network_changes_; 760 761 // Retry soon, after flushing all the current tasks which may include 762 // further network change observers. 763 network_task_runner_->PostTask( 764 FROM_HERE, base::Bind(&URLFetcherCore::StartOnIOThread, this)); 765 return; 766 } 767 768 request_context_getter_ = NULL; 769 first_party_for_cookies_ = GURL(); 770 url_request_data_key_ = NULL; 771 url_request_create_data_callback_.Reset(); 772 bool posted = delegate_task_runner_->PostTask( 773 FROM_HERE, 774 base::Bind(&URLFetcherCore::OnCompletedURLRequest, this, backoff_delay)); 775 776 // If the delegate message loop does not exist any more, then the delegate 777 // should be gone too. 778 DCHECK(posted || !delegate_); 779} 780 781void URLFetcherCore::ReleaseRequest() { 782 upload_progress_checker_timer_.reset(); 783 request_.reset(); 784 g_registry.Get().RemoveURLFetcherCore(this); 785} 786 787base::TimeTicks URLFetcherCore::GetBackoffReleaseTime() { 788 DCHECK(network_task_runner_->BelongsToCurrentThread()); 789 790 if (original_url_throttler_entry_.get()) { 791 base::TimeTicks original_url_backoff = 792 original_url_throttler_entry_->GetExponentialBackoffReleaseTime(); 793 base::TimeTicks destination_url_backoff; 794 if (url_throttler_entry_.get() != NULL && 795 original_url_throttler_entry_.get() != url_throttler_entry_.get()) { 796 destination_url_backoff = 797 url_throttler_entry_->GetExponentialBackoffReleaseTime(); 798 } 799 800 return original_url_backoff > destination_url_backoff ? 801 original_url_backoff : destination_url_backoff; 802 } else { 803 return base::TimeTicks(); 804 } 805} 806 807void URLFetcherCore::CompleteAddingUploadDataChunk( 808 const std::string& content, bool is_last_chunk) { 809 if (was_cancelled_) { 810 // Since CompleteAddingUploadDataChunk() is posted as a *delayed* task, it 811 // may run after the URLFetcher was already stopped. 812 return; 813 } 814 DCHECK(is_chunked_upload_); 815 DCHECK(request_.get()); 816 DCHECK(!content.empty()); 817 request_->AppendChunkToUpload(content.data(), 818 static_cast<int>(content.length()), 819 is_last_chunk); 820} 821 822int URLFetcherCore::WriteBuffer(scoped_refptr<DrainableIOBuffer> data) { 823 while (data->BytesRemaining() > 0) { 824 const int result = response_writer_->Write( 825 data.get(), 826 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_.get(), 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