url_fetcher.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
1// Copyright (c) 2011 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 "chrome/common/net/url_fetcher.h" 6 7#include <set> 8 9#include "base/compiler_specific.h" 10#include "base/lazy_instance.h" 11#include "base/message_loop_proxy.h" 12#include "base/scoped_ptr.h" 13#include "base/stl_util-inl.h" 14#include "base/string_util.h" 15#include "base/threading/thread.h" 16#include "chrome/common/net/url_request_context_getter.h" 17#include "googleurl/src/gurl.h" 18#include "net/base/load_flags.h" 19#include "net/base/io_buffer.h" 20#include "net/base/net_errors.h" 21#include "net/http/http_request_headers.h" 22#include "net/http/http_response_headers.h" 23#include "net/url_request/url_request.h" 24#include "net/url_request/url_request_context.h" 25#include "net/url_request/url_request_throttler_manager.h" 26 27#ifdef ANDROID 28#include "android/autofill/url_fetcher_proxy.h" 29#endif 30 31static const int kBufferSize = 4096; 32 33bool URLFetcher::g_interception_enabled = false; 34 35class URLFetcher::Core 36 : public base::RefCountedThreadSafe<URLFetcher::Core>, 37 public net::URLRequest::Delegate { 38 public: 39 // For POST requests, set |content_type| to the MIME type of the content 40 // and set |content| to the data to upload. |flags| are flags to apply to 41 // the load operation--these should be one or more of the LOAD_* flags 42 // defined in url_request.h. 43 Core(URLFetcher* fetcher, 44 const GURL& original_url, 45 RequestType request_type, 46 URLFetcher::Delegate* d); 47 48 // Starts the load. It's important that this not happen in the constructor 49 // because it causes the IO thread to begin AddRef()ing and Release()ing 50 // us. If our caller hasn't had time to fully construct us and take a 51 // reference, the IO thread could interrupt things, run a task, Release() 52 // us, and destroy us, leaving the caller with an already-destroyed object 53 // when construction finishes. 54 void Start(); 55 56 // Stops any in-progress load and ensures no callback will happen. It is 57 // safe to call this multiple times. 58 void Stop(); 59 60 // Reports that the received content was malformed. 61 void ReceivedContentWasMalformed(); 62 63 // Overridden from net::URLRequest::Delegate: 64 virtual void OnResponseStarted(net::URLRequest* request); 65 virtual void OnReadCompleted(net::URLRequest* request, int bytes_read); 66 67 URLFetcher::Delegate* delegate() const { return delegate_; } 68 69 static void CancelAll(); 70 71 private: 72 friend class base::RefCountedThreadSafe<URLFetcher::Core>; 73 74 class Registry { 75 public: 76 Registry(); 77 ~Registry(); 78 79 void AddURLFetcherCore(Core* core); 80 void RemoveURLFetcherCore(Core* core); 81 82 void CancelAll(); 83 84 private: 85 std::set<Core*> fetchers_; 86 87 DISALLOW_COPY_AND_ASSIGN(Registry); 88 }; 89 90 ~Core(); 91 92 // Wrapper functions that allow us to ensure actions happen on the right 93 // thread. 94 void StartURLRequest(); 95 void StartURLRequestWhenAppropriate(); 96 void CancelURLRequest(); 97 void OnCompletedURLRequest(const net::URLRequestStatus& status); 98 void NotifyMalformedContent(); 99 100 // Deletes the request, removes it from the registry, and removes the 101 // destruction observer. 102 void ReleaseRequest(); 103 104 // Returns the max value of exponential back-off release time for 105 // |original_url_| and |url_|. 106 base::TimeTicks GetBackoffReleaseTime(); 107 108 void CompleteAddingUploadDataChunk(const std::string& data); 109 110 // Adds a block of data to be uploaded in a POST body. This can only be called 111 // after Start(). 112 void AppendChunkToUpload(const std::string& data); 113 114 URLFetcher* fetcher_; // Corresponding fetcher object 115 GURL original_url_; // The URL we were asked to fetch 116 GURL url_; // The URL we eventually wound up at 117 RequestType request_type_; // What type of request is this? 118 URLFetcher::Delegate* delegate_; // Object to notify on completion 119 scoped_refptr<base::MessageLoopProxy> delegate_loop_proxy_; 120 // Message loop proxy of the creating 121 // thread. 122 scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_; 123 // The message loop proxy for the thread 124 // on which the request IO happens. 125 scoped_ptr<net::URLRequest> request_; // The actual request this wraps 126 int load_flags_; // Flags for the load operation 127 int response_code_; // HTTP status code for the request 128 std::string data_; // Results of the request 129 scoped_refptr<net::IOBuffer> buffer_; 130 // Read buffer 131 scoped_refptr<URLRequestContextGetter> request_context_getter_; 132 // Cookie/cache info for the request 133 ResponseCookies cookies_; // Response cookies 134 net::HttpRequestHeaders extra_request_headers_; 135 scoped_refptr<net::HttpResponseHeaders> response_headers_; 136 137 std::string upload_content_; // HTTP POST payload 138 std::string upload_content_type_; // MIME type of POST payload 139 std::string referrer_; // HTTP Referer header value 140 bool is_chunked_upload_; // True if using chunked transfer encoding 141 142 // Used to determine how long to wait before making a request or doing a 143 // retry. 144 // Both of them can only be accessed on the IO thread. 145 // We need not only the throttler entry for |original_URL|, but also the one 146 // for |url|. For example, consider the case that URL A redirects to URL B, 147 // for which the server returns a 500 response. In this case, the exponential 148 // back-off release time of URL A won't increase. If we retry without 149 // considering the back-off constraint of URL B, we may send out too many 150 // requests for URL A in a short period of time. 151 scoped_refptr<net::URLRequestThrottlerEntryInterface> 152 original_url_throttler_entry_; 153 scoped_refptr<net::URLRequestThrottlerEntryInterface> url_throttler_entry_; 154 155 // |num_retries_| indicates how many times we've failed to successfully 156 // fetch this URL. Once this value exceeds the maximum number of retries 157 // specified by the owner URLFetcher instance, we'll give up. 158 int num_retries_; 159 160 // True if the URLFetcher has been cancelled. 161 bool was_cancelled_; 162 163 // Since GetBackoffReleaseTime() can only be called on the IO thread, we cache 164 // its value to be used by OnCompletedURLRequest on the creating thread. 165 base::TimeTicks backoff_release_time_; 166 167 static base::LazyInstance<Registry> g_registry; 168 169 friend class URLFetcher; 170 DISALLOW_COPY_AND_ASSIGN(Core); 171}; 172 173URLFetcher::Core::Registry::Registry() {} 174URLFetcher::Core::Registry::~Registry() {} 175 176void URLFetcher::Core::Registry::AddURLFetcherCore(Core* core) { 177 DCHECK(!ContainsKey(fetchers_, core)); 178 fetchers_.insert(core); 179} 180 181void URLFetcher::Core::Registry::RemoveURLFetcherCore(Core* core) { 182 DCHECK(ContainsKey(fetchers_, core)); 183 fetchers_.erase(core); 184} 185 186void URLFetcher::Core::Registry::CancelAll() { 187 std::set<Core*> fetchers; 188 fetchers.swap(fetchers_); 189 190 for (std::set<Core*>::iterator it = fetchers.begin(); 191 it != fetchers.end(); ++it) 192 (*it)->CancelURLRequest(); 193} 194 195// static 196base::LazyInstance<URLFetcher::Core::Registry> 197 URLFetcher::Core::g_registry(base::LINKER_INITIALIZED); 198 199// static 200URLFetcher::Factory* URLFetcher::factory_ = NULL; 201 202URLFetcher::URLFetcher(const GURL& url, 203 RequestType request_type, 204 Delegate* d) 205 : ALLOW_THIS_IN_INITIALIZER_LIST( 206 core_(new Core(this, url, request_type, d))), 207 automatically_retry_on_5xx_(true), 208 max_retries_(0) { 209} 210 211URLFetcher::~URLFetcher() { 212 core_->Stop(); 213} 214 215// static 216URLFetcher* URLFetcher::Create(int id, const GURL& url, 217 RequestType request_type, Delegate* d) { 218#ifdef ANDROID 219 // TODO: Upstream. 220 return new URLFetcherProxy(url, request_type, d); 221#else 222 return factory_ ? factory_->CreateURLFetcher(id, url, request_type, d) : 223 new URLFetcher(url, request_type, d); 224#endif 225} 226 227URLFetcher::Core::Core(URLFetcher* fetcher, 228 const GURL& original_url, 229 RequestType request_type, 230 URLFetcher::Delegate* d) 231 : fetcher_(fetcher), 232 original_url_(original_url), 233 request_type_(request_type), 234 delegate_(d), 235 delegate_loop_proxy_(base::MessageLoopProxy::CreateForCurrentThread()), 236 request_(NULL), 237 load_flags_(net::LOAD_NORMAL), 238 response_code_(-1), 239 buffer_(new net::IOBuffer(kBufferSize)), 240 is_chunked_upload_(false), 241 num_retries_(0), 242 was_cancelled_(false) { 243} 244 245URLFetcher::Core::~Core() { 246 // |request_| should be NULL. If not, it's unsafe to delete it here since we 247 // may not be on the IO thread. 248 DCHECK(!request_.get()); 249} 250 251void URLFetcher::Core::Start() { 252 DCHECK(delegate_loop_proxy_); 253 CHECK(request_context_getter_) << "We need an URLRequestContext!"; 254 io_message_loop_proxy_ = request_context_getter_->GetIOMessageLoopProxy(); 255 CHECK(io_message_loop_proxy_.get()) << "We need an IO message loop proxy"; 256 257 io_message_loop_proxy_->PostTask( 258 FROM_HERE, 259 NewRunnableMethod(this, &Core::StartURLRequestWhenAppropriate)); 260} 261 262void URLFetcher::Core::Stop() { 263 DCHECK(delegate_loop_proxy_->BelongsToCurrentThread()); 264 delegate_ = NULL; 265 fetcher_ = NULL; 266 if (io_message_loop_proxy_.get()) { 267 io_message_loop_proxy_->PostTask( 268 FROM_HERE, NewRunnableMethod(this, &Core::CancelURLRequest)); 269 } 270} 271 272void URLFetcher::Core::ReceivedContentWasMalformed() { 273 DCHECK(delegate_loop_proxy_->BelongsToCurrentThread()); 274 if (io_message_loop_proxy_.get()) { 275 io_message_loop_proxy_->PostTask( 276 FROM_HERE, NewRunnableMethod(this, &Core::NotifyMalformedContent)); 277 } 278} 279 280void URLFetcher::Core::CancelAll() { 281 g_registry.Get().CancelAll(); 282} 283 284void URLFetcher::Core::OnResponseStarted(net::URLRequest* request) { 285 DCHECK_EQ(request, request_.get()); 286 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); 287 if (request_->status().is_success()) { 288 response_code_ = request_->GetResponseCode(); 289 response_headers_ = request_->response_headers(); 290 } 291 292 int bytes_read = 0; 293 // Some servers may treat HEAD requests as GET requests. To free up the 294 // network connection as soon as possible, signal that the request has 295 // completed immediately, without trying to read any data back (all we care 296 // about is the response code and headers, which we already have). 297 if (request_->status().is_success() && (request_type_ != HEAD)) 298 request_->Read(buffer_, kBufferSize, &bytes_read); 299 OnReadCompleted(request_.get(), bytes_read); 300} 301 302void URLFetcher::Core::CompleteAddingUploadDataChunk( 303 const std::string& content) { 304 DCHECK(is_chunked_upload_); 305 DCHECK(request_.get()); 306 if (content.length()) { 307 request_->AppendChunkToUpload(content.data(), 308 static_cast<int>(content.length())); 309 } else { 310 request_->MarkEndOfChunks(); 311 } 312} 313 314void URLFetcher::Core::AppendChunkToUpload(const std::string& content) { 315 DCHECK(delegate_loop_proxy_); 316 CHECK(io_message_loop_proxy_.get()); 317 io_message_loop_proxy_->PostTask( 318 FROM_HERE, 319 NewRunnableMethod(this, &Core::CompleteAddingUploadDataChunk, content)); 320} 321 322void URLFetcher::Core::OnReadCompleted(net::URLRequest* request, 323 int bytes_read) { 324 DCHECK(request == request_); 325 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); 326 327 url_ = request->url(); 328 url_throttler_entry_ = 329 net::URLRequestThrottlerManager::GetInstance()->RegisterRequestUrl(url_); 330 331 do { 332 if (!request_->status().is_success() || bytes_read <= 0) 333 break; 334 data_.append(buffer_->data(), bytes_read); 335 } while (request_->Read(buffer_, kBufferSize, &bytes_read)); 336 337 if (request_->status().is_success()) 338 request_->GetResponseCookies(&cookies_); 339 340 // See comments re: HEAD requests in OnResponseStarted(). 341 if (!request_->status().is_io_pending() || (request_type_ == HEAD)) { 342 backoff_release_time_ = GetBackoffReleaseTime(); 343 344 bool posted = delegate_loop_proxy_->PostTask( 345 FROM_HERE, 346 NewRunnableMethod(this, 347 &Core::OnCompletedURLRequest, 348 request_->status())); 349 // If the delegate message loop does not exist any more, then the delegate 350 // should be gone too. 351 DCHECK(posted || !delegate_); 352 ReleaseRequest(); 353 } 354} 355 356void URLFetcher::Core::StartURLRequest() { 357 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); 358 359 if (was_cancelled_) { 360 // Since StartURLRequest() is posted as a *delayed* task, it may 361 // run after the URLFetcher was already stopped. 362 return; 363 } 364 365 CHECK(request_context_getter_); 366 DCHECK(!request_.get()); 367 368 g_registry.Get().AddURLFetcherCore(this); 369 request_.reset(new net::URLRequest(original_url_, this)); 370 int flags = request_->load_flags() | load_flags_; 371 if (!g_interception_enabled) { 372 flags = flags | net::LOAD_DISABLE_INTERCEPT; 373 } 374 if (is_chunked_upload_) 375 request_->EnableChunkedUpload(); 376 request_->set_load_flags(flags); 377 request_->set_context(request_context_getter_->GetURLRequestContext()); 378 request_->set_referrer(referrer_); 379 380 switch (request_type_) { 381 case GET: 382 break; 383 384 case POST: 385 DCHECK(!upload_content_.empty() || is_chunked_upload_); 386 DCHECK(!upload_content_type_.empty()); 387 388 request_->set_method("POST"); 389 extra_request_headers_.SetHeader(net::HttpRequestHeaders::kContentType, 390 upload_content_type_); 391 if (!upload_content_.empty()) { 392 request_->AppendBytesToUpload( 393 upload_content_.data(), static_cast<int>(upload_content_.length())); 394 } 395 break; 396 397 case HEAD: 398 request_->set_method("HEAD"); 399 break; 400 401 default: 402 NOTREACHED(); 403 } 404 405 if (!extra_request_headers_.IsEmpty()) 406 request_->SetExtraRequestHeaders(extra_request_headers_); 407 408 // There might be data left over from a previous request attempt. 409 data_.clear(); 410 411 request_->Start(); 412} 413 414void URLFetcher::Core::StartURLRequestWhenAppropriate() { 415 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); 416 417 if (was_cancelled_) 418 return; 419 420 if (original_url_throttler_entry_ == NULL) { 421 original_url_throttler_entry_ = 422 net::URLRequestThrottlerManager::GetInstance()->RegisterRequestUrl( 423 original_url_); 424 } 425 426 int64 delay = original_url_throttler_entry_->ReserveSendingTimeForNextRequest( 427 GetBackoffReleaseTime()); 428 if (delay == 0) { 429 StartURLRequest(); 430 } else { 431 MessageLoop::current()->PostDelayedTask( 432 FROM_HERE, 433 NewRunnableMethod(this, &Core::StartURLRequest), 434 delay); 435 } 436} 437 438void URLFetcher::Core::CancelURLRequest() { 439 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); 440 441 if (request_.get()) { 442 request_->Cancel(); 443 ReleaseRequest(); 444 } 445 // Release the reference to the request context. There could be multiple 446 // references to URLFetcher::Core at this point so it may take a while to 447 // delete the object, but we cannot delay the destruction of the request 448 // context. 449 request_context_getter_ = NULL; 450 was_cancelled_ = true; 451} 452 453void URLFetcher::Core::OnCompletedURLRequest( 454 const net::URLRequestStatus& status) { 455 DCHECK(delegate_loop_proxy_->BelongsToCurrentThread()); 456 457 // Checks the response from server. 458 if (response_code_ >= 500 || 459 status.os_error() == net::ERR_TEMPORARILY_THROTTLED) { 460 // When encountering a server error, we will send the request again 461 // after backoff time. 462 ++num_retries_; 463 // Restarts the request if we still need to notify the delegate. 464 if (delegate_) { 465 fetcher_->backoff_delay_ = backoff_release_time_ - base::TimeTicks::Now(); 466 if (fetcher_->backoff_delay_ < base::TimeDelta()) 467 fetcher_->backoff_delay_ = base::TimeDelta(); 468 469 if (fetcher_->automatically_retry_on_5xx_ && 470 num_retries_ <= fetcher_->max_retries()) { 471 io_message_loop_proxy_->PostTask( 472 FROM_HERE, 473 NewRunnableMethod(this, &Core::StartURLRequestWhenAppropriate)); 474 } else { 475 delegate_->OnURLFetchComplete(fetcher_, url_, status, response_code_, 476 cookies_, data_); 477 } 478 } 479 } else { 480 if (delegate_) { 481 fetcher_->backoff_delay_ = base::TimeDelta(); 482 delegate_->OnURLFetchComplete(fetcher_, url_, status, response_code_, 483 cookies_, data_); 484 } 485 } 486} 487 488void URLFetcher::Core::NotifyMalformedContent() { 489 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); 490 if (url_throttler_entry_ != NULL) 491 url_throttler_entry_->ReceivedContentWasMalformed(); 492} 493 494void URLFetcher::Core::ReleaseRequest() { 495 request_.reset(); 496 g_registry.Get().RemoveURLFetcherCore(this); 497} 498 499base::TimeTicks URLFetcher::Core::GetBackoffReleaseTime() { 500 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); 501 DCHECK(original_url_throttler_entry_ != NULL); 502 503 base::TimeTicks original_url_backoff = 504 original_url_throttler_entry_->GetExponentialBackoffReleaseTime(); 505 base::TimeTicks destination_url_backoff; 506 if (url_throttler_entry_ != NULL && 507 original_url_throttler_entry_ != url_throttler_entry_) { 508 destination_url_backoff = 509 url_throttler_entry_->GetExponentialBackoffReleaseTime(); 510 } 511 512 return original_url_backoff > destination_url_backoff ? 513 original_url_backoff : destination_url_backoff; 514} 515 516void URLFetcher::set_upload_data(const std::string& upload_content_type, 517 const std::string& upload_content) { 518 DCHECK(!core_->is_chunked_upload_); 519 core_->upload_content_type_ = upload_content_type; 520 core_->upload_content_ = upload_content; 521} 522 523void URLFetcher::set_chunked_upload(const std::string& content_type) { 524 DCHECK(core_->is_chunked_upload_ || 525 (core_->upload_content_type_.empty() && 526 core_->upload_content_.empty())); 527 core_->upload_content_type_ = content_type; 528 core_->upload_content_.clear(); 529 core_->is_chunked_upload_ = true; 530} 531 532void URLFetcher::AppendChunkToUpload(const std::string& data) { 533 DCHECK(data.length()); 534 core_->AppendChunkToUpload(data); 535} 536 537void URLFetcher::MarkEndOfChunks() { 538 core_->AppendChunkToUpload(std::string()); 539} 540 541const std::string& URLFetcher::upload_data() const { 542 return core_->upload_content_; 543} 544 545void URLFetcher::set_referrer(const std::string& referrer) { 546 core_->referrer_ = referrer; 547} 548 549void URLFetcher::set_load_flags(int load_flags) { 550 core_->load_flags_ = load_flags; 551} 552 553int URLFetcher::load_flags() const { 554 return core_->load_flags_; 555} 556 557void URLFetcher::set_extra_request_headers( 558 const std::string& extra_request_headers) { 559 core_->extra_request_headers_.Clear(); 560 core_->extra_request_headers_.AddHeadersFromString(extra_request_headers); 561} 562 563void URLFetcher::set_request_context( 564 URLRequestContextGetter* request_context_getter) { 565 core_->request_context_getter_ = request_context_getter; 566} 567 568#ifdef ANDROID 569URLRequestContextGetter* URLFetcher::request_context() { 570 return core_->request_context_getter_; 571} 572#endif 573 574void URLFetcher::set_automatically_retry_on_5xx(bool retry) { 575 automatically_retry_on_5xx_ = retry; 576} 577 578net::HttpResponseHeaders* URLFetcher::response_headers() const { 579 return core_->response_headers_; 580} 581 582void URLFetcher::Start() { 583 core_->Start(); 584} 585 586const GURL& URLFetcher::url() const { 587 return core_->url_; 588} 589 590void URLFetcher::ReceivedContentWasMalformed() { 591 core_->ReceivedContentWasMalformed(); 592} 593 594// static 595void URLFetcher::CancelAll() { 596 Core::CancelAll(); 597} 598 599URLFetcher::Delegate* URLFetcher::delegate() const { 600 return core_->delegate(); 601} 602