url_fetcher_core.cc revision 3551c9c881056c480085172ff9840cab31610854
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 // Intentionally calling a file_writer_ method directly without posting 362 // the task to network_task_runner_. 363 // 364 // This is for correctly handling the case when file_writer_->DisownFile() 365 // is soon followed by URLFetcherCore::Stop(). We have to make sure that 366 // DisownFile takes effect before Stop deletes file_writer_. 367 // 368 // This direct call should be thread-safe, since DisownFile itself does no 369 // file operation. It just flips the state to be referred in destruction. 370 file_writer_->DisownFile(); 371 } 372 return true; 373} 374 375void URLFetcherCore::OnReceivedRedirect(URLRequest* request, 376 const GURL& new_url, 377 bool* defer_redirect) { 378 DCHECK_EQ(request, request_.get()); 379 DCHECK(network_task_runner_->BelongsToCurrentThread()); 380 if (stop_on_redirect_) { 381 stopped_on_redirect_ = true; 382 url_ = new_url; 383 response_code_ = request_->GetResponseCode(); 384 was_fetched_via_proxy_ = request_->was_fetched_via_proxy(); 385 request->Cancel(); 386 OnReadCompleted(request, 0); 387 } 388} 389 390void URLFetcherCore::OnResponseStarted(URLRequest* request) { 391 DCHECK_EQ(request, request_.get()); 392 DCHECK(network_task_runner_->BelongsToCurrentThread()); 393 if (request_->status().is_success()) { 394 response_code_ = request_->GetResponseCode(); 395 response_headers_ = request_->response_headers(); 396 socket_address_ = request_->GetSocketAddress(); 397 was_fetched_via_proxy_ = request_->was_fetched_via_proxy(); 398 total_response_bytes_ = request_->GetExpectedContentSize(); 399 } 400 401 ReadResponse(); 402} 403 404void URLFetcherCore::OnCertificateRequested( 405 URLRequest* request, 406 SSLCertRequestInfo* cert_request_info) { 407 DCHECK_EQ(request, request_.get()); 408 DCHECK(network_task_runner_->BelongsToCurrentThread()); 409 410 if (g_ignore_certificate_requests) { 411 request->ContinueWithCertificate(NULL); 412 } else { 413 request->Cancel(); 414 } 415} 416 417void URLFetcherCore::OnReadCompleted(URLRequest* request, 418 int bytes_read) { 419 DCHECK(request == request_); 420 DCHECK(network_task_runner_->BelongsToCurrentThread()); 421 422 if (!stopped_on_redirect_) 423 url_ = request->url(); 424 URLRequestThrottlerManager* throttler_manager = 425 request->context()->throttler_manager(); 426 if (throttler_manager) { 427 url_throttler_entry_ = throttler_manager->RegisterRequestUrl(url_); 428 } 429 430 bool waiting_on_write = false; 431 do { 432 if (!request_->status().is_success() || bytes_read <= 0) 433 break; 434 435 current_response_bytes_ += bytes_read; 436 InformDelegateDownloadProgress(); 437 InformDelegateDownloadDataIfNecessary(bytes_read); 438 439 const int result = 440 WriteBuffer(new DrainableIOBuffer(buffer_.get(), bytes_read)); 441 if (result < 0) { 442 // Write failed or waiting for write completion. 443 if (result == ERR_IO_PENDING) 444 waiting_on_write = true; 445 break; 446 } 447 } while (request_->Read(buffer_.get(), kBufferSize, &bytes_read)); 448 449 const URLRequestStatus status = request_->status(); 450 451 if (status.is_success()) 452 request_->GetResponseCookies(&cookies_); 453 454 // See comments re: HEAD requests in ReadResponse(). 455 if ((!status.is_io_pending() && !waiting_on_write) || 456 (request_type_ == URLFetcher::HEAD)) { 457 status_ = status; 458 ReleaseRequest(); 459 460 // No more data to write. 461 const int result = response_writer_->Finish( 462 base::Bind(&URLFetcherCore::DidFinishWriting, this)); 463 if (result != ERR_IO_PENDING) 464 DidFinishWriting(result); 465 } 466} 467 468void URLFetcherCore::CancelAll() { 469 g_registry.Get().CancelAll(); 470} 471 472int URLFetcherCore::GetNumFetcherCores() { 473 return g_registry.Get().size(); 474} 475 476void URLFetcherCore::SetEnableInterceptionForTests(bool enabled) { 477 g_interception_enabled = enabled; 478} 479 480void URLFetcherCore::SetIgnoreCertificateRequests(bool ignored) { 481 g_ignore_certificate_requests = ignored; 482} 483 484URLFetcherCore::~URLFetcherCore() { 485 // |request_| should be NULL. If not, it's unsafe to delete it here since we 486 // may not be on the IO thread. 487 DCHECK(!request_.get()); 488} 489 490void URLFetcherCore::StartOnIOThread() { 491 DCHECK(network_task_runner_->BelongsToCurrentThread()); 492 493 switch (response_destination_) { 494 case STRING: 495 response_writer_.reset(new URLFetcherStringWriter(&data_)); 496 break; 497 498 case PERMANENT_FILE: 499 case TEMP_FILE: 500 DCHECK(file_task_runner_.get()) 501 << "Need to set the file task runner."; 502 503 file_writer_ = new URLFetcherFileWriter(file_task_runner_); 504 505 // If the file is successfully created, 506 // URLFetcherCore::StartURLRequestWhenAppropriate() will be called. 507 if (response_destination_ == PERMANENT_FILE) { 508 file_writer_->set_destination_file_path( 509 response_destination_file_path_); 510 } 511 response_writer_.reset(file_writer_); 512 break; 513 514 default: 515 NOTREACHED(); 516 } 517 DCHECK(response_writer_); 518 const int result = response_writer_->Initialize( 519 base::Bind(&URLFetcherCore::DidInitializeWriter, this)); 520 if (result != ERR_IO_PENDING) 521 DidInitializeWriter(result); 522} 523 524void URLFetcherCore::StartURLRequest() { 525 DCHECK(network_task_runner_->BelongsToCurrentThread()); 526 527 if (was_cancelled_) { 528 // Since StartURLRequest() is posted as a *delayed* task, it may 529 // run after the URLFetcher was already stopped. 530 return; 531 } 532 533 DCHECK(request_context_getter_.get()); 534 DCHECK(!request_.get()); 535 536 g_registry.Get().AddURLFetcherCore(this); 537 current_response_bytes_ = 0; 538 request_.reset(request_context_getter_->GetURLRequestContext()->CreateRequest( 539 original_url_, this)); 540 request_->set_stack_trace(stack_trace_); 541 int flags = request_->load_flags() | load_flags_; 542 if (!g_interception_enabled) 543 flags = flags | LOAD_DISABLE_INTERCEPT; 544 545 if (is_chunked_upload_) 546 request_->EnableChunkedUpload(); 547 request_->set_load_flags(flags); 548 request_->SetReferrer(referrer_); 549 request_->set_first_party_for_cookies(first_party_for_cookies_.is_empty() ? 550 original_url_ : first_party_for_cookies_); 551 if (url_request_data_key_ && !url_request_create_data_callback_.is_null()) { 552 request_->SetUserData(url_request_data_key_, 553 url_request_create_data_callback_.Run()); 554 } 555 556 switch (request_type_) { 557 case URLFetcher::GET: 558 break; 559 560 case URLFetcher::POST: 561 case URLFetcher::PUT: 562 case URLFetcher::PATCH: 563 // Upload content must be set. 564 DCHECK(is_chunked_upload_ || upload_content_set_); 565 566 request_->set_method( 567 request_type_ == URLFetcher::POST ? "POST" : 568 request_type_ == URLFetcher::PUT ? "PUT" : "PATCH"); 569 if (!upload_content_type_.empty()) { 570 extra_request_headers_.SetHeader(HttpRequestHeaders::kContentType, 571 upload_content_type_); 572 } 573 if (!upload_content_.empty()) { 574 scoped_ptr<UploadElementReader> reader(new UploadBytesElementReader( 575 upload_content_.data(), upload_content_.size())); 576 request_->set_upload(make_scoped_ptr( 577 UploadDataStream::CreateWithReader(reader.Pass(), 0))); 578 } else if (!upload_file_path_.empty()) { 579 scoped_ptr<UploadElementReader> reader( 580 new UploadFileElementReader(upload_file_task_runner_.get(), 581 upload_file_path_, 582 upload_range_offset_, 583 upload_range_length_, 584 base::Time())); 585 request_->set_upload(make_scoped_ptr( 586 UploadDataStream::CreateWithReader(reader.Pass(), 0))); 587 } 588 589 current_upload_bytes_ = -1; 590 // TODO(kinaba): http://crbug.com/118103. Implement upload callback in the 591 // layer and avoid using timer here. 592 upload_progress_checker_timer_.reset( 593 new base::RepeatingTimer<URLFetcherCore>()); 594 upload_progress_checker_timer_->Start( 595 FROM_HERE, 596 base::TimeDelta::FromMilliseconds(kUploadProgressTimerInterval), 597 this, 598 &URLFetcherCore::InformDelegateUploadProgress); 599 break; 600 601 case URLFetcher::HEAD: 602 request_->set_method("HEAD"); 603 break; 604 605 case URLFetcher::DELETE_REQUEST: 606 request_->set_method("DELETE"); 607 break; 608 609 default: 610 NOTREACHED(); 611 } 612 613 if (!extra_request_headers_.IsEmpty()) 614 request_->SetExtraRequestHeaders(extra_request_headers_); 615 616 // There might be data left over from a previous request attempt. 617 data_.clear(); 618 619 // If we are writing the response to a file, the only caller 620 // of this function should have created it and not written yet. 621 DCHECK(!file_writer_ || file_writer_->total_bytes_written() == 0); 622 623 request_->Start(); 624} 625 626void URLFetcherCore::DidInitializeWriter(int result) { 627 if (result != OK) { 628 delegate_task_runner_->PostTask( 629 FROM_HERE, 630 base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this)); 631 return; 632 } 633 StartURLRequestWhenAppropriate(); 634} 635 636void URLFetcherCore::StartURLRequestWhenAppropriate() { 637 DCHECK(network_task_runner_->BelongsToCurrentThread()); 638 639 if (was_cancelled_) 640 return; 641 642 DCHECK(request_context_getter_.get()); 643 644 int64 delay = 0LL; 645 if (original_url_throttler_entry_.get() == NULL) { 646 URLRequestThrottlerManager* manager = 647 request_context_getter_->GetURLRequestContext()->throttler_manager(); 648 if (manager) { 649 original_url_throttler_entry_ = 650 manager->RegisterRequestUrl(original_url_); 651 } 652 } 653 if (original_url_throttler_entry_.get() != NULL) { 654 delay = original_url_throttler_entry_->ReserveSendingTimeForNextRequest( 655 GetBackoffReleaseTime()); 656 } 657 658 if (delay == 0) { 659 StartURLRequest(); 660 } else { 661 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( 662 FROM_HERE, base::Bind(&URLFetcherCore::StartURLRequest, this), 663 base::TimeDelta::FromMilliseconds(delay)); 664 } 665} 666 667void URLFetcherCore::CancelURLRequest() { 668 DCHECK(network_task_runner_->BelongsToCurrentThread()); 669 670 if (request_.get()) { 671 request_->Cancel(); 672 ReleaseRequest(); 673 } 674 // Release the reference to the request context. There could be multiple 675 // references to URLFetcher::Core at this point so it may take a while to 676 // delete the object, but we cannot delay the destruction of the request 677 // context. 678 request_context_getter_ = NULL; 679 first_party_for_cookies_ = GURL(); 680 url_request_data_key_ = NULL; 681 url_request_create_data_callback_.Reset(); 682 was_cancelled_ = true; 683 response_writer_.reset(); 684 file_writer_ = NULL; 685} 686 687void URLFetcherCore::OnCompletedURLRequest( 688 base::TimeDelta backoff_delay) { 689 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 690 691 // Save the status and backoff_delay so that delegates can read it. 692 if (delegate_) { 693 backoff_delay_ = backoff_delay; 694 InformDelegateFetchIsComplete(); 695 } 696} 697 698void URLFetcherCore::InformDelegateFetchIsComplete() { 699 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 700 if (delegate_) 701 delegate_->OnURLFetchComplete(fetcher_); 702} 703 704void URLFetcherCore::NotifyMalformedContent() { 705 DCHECK(network_task_runner_->BelongsToCurrentThread()); 706 if (url_throttler_entry_.get() != NULL) { 707 int status_code = response_code_; 708 if (status_code == URLFetcher::RESPONSE_CODE_INVALID) { 709 // The status code will generally be known by the time clients 710 // call the |ReceivedContentWasMalformed()| function (which ends up 711 // calling the current function) but if it's not, we need to assume 712 // the response was successful so that the total failure count 713 // used to calculate exponential back-off goes up. 714 status_code = 200; 715 } 716 url_throttler_entry_->ReceivedContentWasMalformed(status_code); 717 } 718} 719 720void URLFetcherCore::DidFinishWriting(int result) { 721 if (result != OK) { 722 delegate_task_runner_->PostTask( 723 FROM_HERE, 724 base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this)); 725 return; 726 } 727 // If the file was successfully closed, then the URL request is complete. 728 RetryOrCompleteUrlFetch(); 729} 730 731void URLFetcherCore::RetryOrCompleteUrlFetch() { 732 DCHECK(network_task_runner_->BelongsToCurrentThread()); 733 base::TimeDelta backoff_delay; 734 735 // Checks the response from server. 736 if (response_code_ >= 500 || 737 status_.error() == ERR_TEMPORARILY_THROTTLED) { 738 // When encountering a server error, we will send the request again 739 // after backoff time. 740 ++num_retries_on_5xx_; 741 742 // Note that backoff_delay may be 0 because (a) the 743 // URLRequestThrottlerManager and related code does not 744 // necessarily back off on the first error, (b) it only backs off 745 // on some of the 5xx status codes, (c) not all URLRequestContexts 746 // have a throttler manager. 747 base::TimeTicks backoff_release_time = GetBackoffReleaseTime(); 748 backoff_delay = backoff_release_time - base::TimeTicks::Now(); 749 if (backoff_delay < base::TimeDelta()) 750 backoff_delay = base::TimeDelta(); 751 752 if (automatically_retry_on_5xx_ && 753 num_retries_on_5xx_ <= max_retries_on_5xx_) { 754 StartOnIOThread(); 755 return; 756 } 757 } else { 758 backoff_delay = base::TimeDelta(); 759 } 760 761 // Retry if the request failed due to network changes. 762 if (status_.error() == ERR_NETWORK_CHANGED && 763 num_retries_on_network_changes_ < max_retries_on_network_changes_) { 764 ++num_retries_on_network_changes_; 765 766 // Retry soon, after flushing all the current tasks which may include 767 // further network change observers. 768 network_task_runner_->PostTask( 769 FROM_HERE, base::Bind(&URLFetcherCore::StartOnIOThread, this)); 770 return; 771 } 772 773 request_context_getter_ = NULL; 774 first_party_for_cookies_ = GURL(); 775 url_request_data_key_ = NULL; 776 url_request_create_data_callback_.Reset(); 777 bool posted = delegate_task_runner_->PostTask( 778 FROM_HERE, 779 base::Bind(&URLFetcherCore::OnCompletedURLRequest, this, backoff_delay)); 780 781 // If the delegate message loop does not exist any more, then the delegate 782 // should be gone too. 783 DCHECK(posted || !delegate_); 784} 785 786void URLFetcherCore::ReleaseRequest() { 787 upload_progress_checker_timer_.reset(); 788 request_.reset(); 789 g_registry.Get().RemoveURLFetcherCore(this); 790} 791 792base::TimeTicks URLFetcherCore::GetBackoffReleaseTime() { 793 DCHECK(network_task_runner_->BelongsToCurrentThread()); 794 795 if (original_url_throttler_entry_.get()) { 796 base::TimeTicks original_url_backoff = 797 original_url_throttler_entry_->GetExponentialBackoffReleaseTime(); 798 base::TimeTicks destination_url_backoff; 799 if (url_throttler_entry_.get() != NULL && 800 original_url_throttler_entry_.get() != url_throttler_entry_.get()) { 801 destination_url_backoff = 802 url_throttler_entry_->GetExponentialBackoffReleaseTime(); 803 } 804 805 return original_url_backoff > destination_url_backoff ? 806 original_url_backoff : destination_url_backoff; 807 } else { 808 return base::TimeTicks(); 809 } 810} 811 812void URLFetcherCore::CompleteAddingUploadDataChunk( 813 const std::string& content, bool is_last_chunk) { 814 if (was_cancelled_) { 815 // Since CompleteAddingUploadDataChunk() is posted as a *delayed* task, it 816 // may run after the URLFetcher was already stopped. 817 return; 818 } 819 DCHECK(is_chunked_upload_); 820 DCHECK(request_.get()); 821 DCHECK(!content.empty()); 822 request_->AppendChunkToUpload(content.data(), 823 static_cast<int>(content.length()), 824 is_last_chunk); 825} 826 827int URLFetcherCore::WriteBuffer(scoped_refptr<DrainableIOBuffer> data) { 828 while (data->BytesRemaining() > 0) { 829 const int result = response_writer_->Write( 830 data.get(), 831 data->BytesRemaining(), 832 base::Bind(&URLFetcherCore::DidWriteBuffer, this, data)); 833 if (result < 0) 834 return result; 835 data->DidConsume(result); 836 } 837 return OK; 838} 839 840void URLFetcherCore::DidWriteBuffer(scoped_refptr<DrainableIOBuffer> data, 841 int result) { 842 if (result >= 0) { // Continue writing. 843 data->DidConsume(result); 844 result = WriteBuffer(data); 845 if (result == ERR_IO_PENDING) 846 return; 847 } 848 849 if (result < 0) { // Handle errors. 850 delegate_task_runner_->PostTask( 851 FROM_HERE, 852 base::Bind(&URLFetcherCore::InformDelegateFetchIsComplete, this)); 853 return; 854 } 855 // Finished writing buffer_. Read some more. 856 DCHECK_EQ(0, data->BytesRemaining()); 857 ReadResponse(); 858} 859 860void URLFetcherCore::ReadResponse() { 861 // Some servers may treat HEAD requests as GET requests. To free up the 862 // network connection as soon as possible, signal that the request has 863 // completed immediately, without trying to read any data back (all we care 864 // about is the response code and headers, which we already have). 865 int bytes_read = 0; 866 if (request_->status().is_success() && 867 (request_type_ != URLFetcher::HEAD)) 868 request_->Read(buffer_.get(), kBufferSize, &bytes_read); 869 OnReadCompleted(request_.get(), bytes_read); 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