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