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