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