Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/common/net/url_fetcher.h" | 5 #include "chrome/common/net/url_fetcher.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 | 8 |
| 9 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
| 10 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
| 11 #include "base/lock.h" | 11 #include "base/lock.h" |
| 12 #include "base/message_loop_proxy.h" | 12 #include "base/message_loop_proxy.h" |
| 13 #include "base/scoped_ptr.h" | 13 #include "base/scoped_ptr.h" |
| 14 #include "base/stl_util-inl.h" | 14 #include "base/stl_util-inl.h" |
| 15 #include "base/string_util.h" | 15 #include "base/string_util.h" |
| 16 #include "base/thread.h" | 16 #include "base/thread.h" |
| 17 #include "chrome/common/net/url_fetcher_protect.h" | |
| 18 #include "chrome/common/net/url_request_context_getter.h" | 17 #include "chrome/common/net/url_request_context_getter.h" |
| 19 #include "googleurl/src/gurl.h" | 18 #include "googleurl/src/gurl.h" |
| 20 #include "net/base/load_flags.h" | 19 #include "net/base/load_flags.h" |
| 21 #include "net/base/io_buffer.h" | 20 #include "net/base/io_buffer.h" |
| 21 #include "net/base/net_errors.h" | |
| 22 #include "net/http/http_request_headers.h" | 22 #include "net/http/http_request_headers.h" |
| 23 #include "net/http/http_response_headers.h" | 23 #include "net/http/http_response_headers.h" |
| 24 #include "net/url_request/request_throttler_manager.h" | |
| 24 #include "net/url_request/url_request.h" | 25 #include "net/url_request/url_request.h" |
| 25 #include "net/url_request/url_request_context.h" | 26 #include "net/url_request/url_request_context.h" |
| 26 | 27 |
| 27 static const int kBufferSize = 4096; | 28 static const int kBufferSize = 4096; |
| 28 | 29 |
| 29 bool URLFetcher::g_interception_enabled = false; | 30 bool URLFetcher::g_interception_enabled = false; |
| 30 | 31 |
| 31 class URLFetcher::Core | 32 class URLFetcher::Core |
| 32 : public base::RefCountedThreadSafe<URLFetcher::Core>, | 33 : public base::RefCountedThreadSafe<URLFetcher::Core>, |
| 33 public URLRequest::Delegate { | 34 public URLRequest::Delegate { |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 109 // Read buffer | 110 // Read buffer |
| 110 scoped_refptr<URLRequestContextGetter> request_context_getter_; | 111 scoped_refptr<URLRequestContextGetter> request_context_getter_; |
| 111 // Cookie/cache info for the request | 112 // Cookie/cache info for the request |
| 112 ResponseCookies cookies_; // Response cookies | 113 ResponseCookies cookies_; // Response cookies |
| 113 net::HttpRequestHeaders extra_request_headers_; | 114 net::HttpRequestHeaders extra_request_headers_; |
| 114 scoped_refptr<net::HttpResponseHeaders> response_headers_; | 115 scoped_refptr<net::HttpResponseHeaders> response_headers_; |
| 115 | 116 |
| 116 std::string upload_content_; // HTTP POST payload | 117 std::string upload_content_; // HTTP POST payload |
| 117 std::string upload_content_type_; // MIME type of POST payload | 118 std::string upload_content_type_; // MIME type of POST payload |
| 118 | 119 |
| 119 // The overload protection entry for this URL. This is used to | |
| 120 // incrementally back off how rapidly we'll send requests to a particular | |
| 121 // URL, to avoid placing too much demand on the remote resource. We update | |
| 122 // this with the status of all requests as they return, and in turn use it | |
| 123 // to determine how long to wait before making another request. | |
| 124 URLFetcherProtectEntry* protect_entry_; | |
| 125 // |num_retries_| indicates how many times we've failed to successfully | 120 // |num_retries_| indicates how many times we've failed to successfully |
| 126 // fetch this URL. Once this value exceeds the maximum number of retries | 121 // fetch this URL. Once this value exceeds the maximum number of retries |
| 127 // specified by the protection manager, we'll give up. | 122 // specified by the owner URLFetcher instance, we'll give up. |
| 128 int num_retries_; | 123 int num_retries_; |
| 129 | 124 |
| 125 // Caches the pointer to the singleton object of RequestThrottlerManager. | |
| 126 // This is used to determine how long to wait before making a request or doing | |
| 127 // a retry. | |
| 128 RequestThrottlerManager* request_throttler_manager_; | |
| 129 | |
| 130 // True if the URLFetcher has been cancelled. | 130 // True if the URLFetcher has been cancelled. |
| 131 bool was_cancelled_; | 131 bool was_cancelled_; |
| 132 | 132 |
| 133 static base::LazyInstance<Registry> g_registry; | 133 static base::LazyInstance<Registry> g_registry; |
| 134 | 134 |
| 135 friend class URLFetcher; | 135 friend class URLFetcher; |
| 136 DISALLOW_COPY_AND_ASSIGN(Core); | 136 DISALLOW_COPY_AND_ASSIGN(Core); |
| 137 }; | 137 }; |
| 138 | 138 |
| 139 URLFetcher::Core::Registry::Registry() {} | 139 URLFetcher::Core::Registry::Registry() {} |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 163 URLFetcher::Core::g_registry(base::LINKER_INITIALIZED); | 163 URLFetcher::Core::g_registry(base::LINKER_INITIALIZED); |
| 164 | 164 |
| 165 // static | 165 // static |
| 166 URLFetcher::Factory* URLFetcher::factory_ = NULL; | 166 URLFetcher::Factory* URLFetcher::factory_ = NULL; |
| 167 | 167 |
| 168 URLFetcher::URLFetcher(const GURL& url, | 168 URLFetcher::URLFetcher(const GURL& url, |
| 169 RequestType request_type, | 169 RequestType request_type, |
| 170 Delegate* d) | 170 Delegate* d) |
| 171 : ALLOW_THIS_IN_INITIALIZER_LIST( | 171 : ALLOW_THIS_IN_INITIALIZER_LIST( |
| 172 core_(new Core(this, url, request_type, d))), | 172 core_(new Core(this, url, request_type, d))), |
| 173 automatically_retry_on_5xx_(true) { | 173 automatically_retry_on_5xx_(true), |
| 174 max_retries_(0) { | |
| 174 } | 175 } |
| 175 | 176 |
| 176 URLFetcher::~URLFetcher() { | 177 URLFetcher::~URLFetcher() { |
| 177 core_->Stop(); | 178 core_->Stop(); |
| 178 } | 179 } |
| 179 | 180 |
| 180 // static | 181 // static |
| 181 URLFetcher* URLFetcher::Create(int id, const GURL& url, | 182 URLFetcher* URLFetcher::Create(int id, const GURL& url, |
| 182 RequestType request_type, Delegate* d) { | 183 RequestType request_type, Delegate* d) { |
| 183 return factory_ ? factory_->CreateURLFetcher(id, url, request_type, d) : | 184 return factory_ ? factory_->CreateURLFetcher(id, url, request_type, d) : |
| 184 new URLFetcher(url, request_type, d); | 185 new URLFetcher(url, request_type, d); |
| 185 } | 186 } |
| 186 | 187 |
| 187 URLFetcher::Core::Core(URLFetcher* fetcher, | 188 URLFetcher::Core::Core(URLFetcher* fetcher, |
| 188 const GURL& original_url, | 189 const GURL& original_url, |
| 189 RequestType request_type, | 190 RequestType request_type, |
| 190 URLFetcher::Delegate* d) | 191 URLFetcher::Delegate* d) |
| 191 : fetcher_(fetcher), | 192 : fetcher_(fetcher), |
| 192 original_url_(original_url), | 193 original_url_(original_url), |
| 193 request_type_(request_type), | 194 request_type_(request_type), |
| 194 delegate_(d), | 195 delegate_(d), |
| 195 delegate_loop_(MessageLoop::current()), | 196 delegate_loop_(MessageLoop::current()), |
| 196 request_(NULL), | 197 request_(NULL), |
| 197 load_flags_(net::LOAD_NORMAL), | 198 load_flags_(net::LOAD_NORMAL), |
| 198 response_code_(-1), | 199 response_code_(-1), |
| 199 buffer_(new net::IOBuffer(kBufferSize)), | 200 buffer_(new net::IOBuffer(kBufferSize)), |
| 200 protect_entry_(URLFetcherProtectManager::GetInstance()->Register( | |
| 201 original_url_.host())), | |
| 202 num_retries_(0), | 201 num_retries_(0), |
| 202 request_throttler_manager_(Singleton<RequestThrottlerManager>::get()), | |
| 203 was_cancelled_(false) { | 203 was_cancelled_(false) { |
| 204 } | 204 } |
| 205 | 205 |
| 206 URLFetcher::Core::~Core() { | 206 URLFetcher::Core::~Core() { |
| 207 // |request_| should be NULL. If not, it's unsafe to delete it here since we | 207 // |request_| should be NULL. If not, it's unsafe to delete it here since we |
| 208 // may not be on the IO thread. | 208 // may not be on the IO thread. |
| 209 DCHECK(!request_.get()); | 209 DCHECK(!request_.get()); |
| 210 } | 210 } |
| 211 | 211 |
| 212 void URLFetcher::Core::Start() { | 212 void URLFetcher::Core::Start() { |
| 213 DCHECK(delegate_loop_); | 213 DCHECK(delegate_loop_); |
| 214 CHECK(request_context_getter_) << "We need an URLRequestContext!"; | 214 CHECK(request_context_getter_) << "We need an URLRequestContext!"; |
| 215 io_message_loop_proxy_ = request_context_getter_->GetIOMessageLoopProxy(); | 215 io_message_loop_proxy_ = request_context_getter_->GetIOMessageLoopProxy(); |
| 216 CHECK(io_message_loop_proxy_.get()) << "We need an IO message loop proxy"; | 216 CHECK(io_message_loop_proxy_.get()) << "We need an IO message loop proxy"; |
| 217 | |
| 218 scoped_refptr<RequestThrottlerEntryInterface> entry = | |
| 219 request_throttler_manager_->RegisterRequestUrl(original_url_); | |
| 217 io_message_loop_proxy_->PostDelayedTask( | 220 io_message_loop_proxy_->PostDelayedTask( |
| 218 FROM_HERE, | 221 FROM_HERE, |
| 219 NewRunnableMethod(this, &Core::StartURLRequest), | 222 NewRunnableMethod(this, &Core::StartURLRequest), |
| 220 protect_entry_->UpdateBackoff(URLFetcherProtectEntry::SEND)); | 223 entry->GetRecommendedDelayForNextRequest()); |
| 221 } | 224 } |
| 222 | 225 |
| 223 void URLFetcher::Core::Stop() { | 226 void URLFetcher::Core::Stop() { |
| 224 DCHECK_EQ(MessageLoop::current(), delegate_loop_); | 227 DCHECK_EQ(MessageLoop::current(), delegate_loop_); |
| 225 delegate_ = NULL; | 228 delegate_ = NULL; |
| 226 fetcher_ = NULL; | 229 fetcher_ = NULL; |
| 227 if (io_message_loop_proxy_.get()) { | 230 if (io_message_loop_proxy_.get()) { |
| 228 io_message_loop_proxy_->PostTask( | 231 io_message_loop_proxy_->PostTask( |
| 229 FROM_HERE, NewRunnableMethod(this, &Core::CancelURLRequest)); | 232 FROM_HERE, NewRunnableMethod(this, &Core::CancelURLRequest)); |
| 230 } | 233 } |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 337 // delete the object, but we cannot delay the destruction of the request | 340 // delete the object, but we cannot delay the destruction of the request |
| 338 // context. | 341 // context. |
| 339 request_context_getter_ = NULL; | 342 request_context_getter_ = NULL; |
| 340 was_cancelled_ = true; | 343 was_cancelled_ = true; |
| 341 } | 344 } |
| 342 | 345 |
| 343 void URLFetcher::Core::OnCompletedURLRequest(const URLRequestStatus& status) { | 346 void URLFetcher::Core::OnCompletedURLRequest(const URLRequestStatus& status) { |
| 344 DCHECK(MessageLoop::current() == delegate_loop_); | 347 DCHECK(MessageLoop::current() == delegate_loop_); |
| 345 | 348 |
| 346 // Checks the response from server. | 349 // Checks the response from server. |
| 347 if (response_code_ >= 500) { | 350 if (response_code_ >= 500 || |
| 351 status.os_error() == net::ERR_TEMPORARILY_THROTTLED_BY_DDOS) { | |
| 348 // When encountering a server error, we will send the request again | 352 // When encountering a server error, we will send the request again |
| 349 // after backoff time. | 353 // after backoff time. |
| 350 int64 back_off_time = | 354 scoped_refptr<RequestThrottlerEntryInterface> entry = |
| 351 protect_entry_->UpdateBackoff(URLFetcherProtectEntry::FAILURE); | 355 request_throttler_manager_->RegisterRequestUrl(url_); |
| 356 int64 back_off_time = entry->GetRecommendedDelayForNextRequest(); | |
|
Jói
2010/11/17 16:39:18
Doesn't this call to GetRecommendedDelayForNextReq
yzshen
2010/11/19 23:51:36
Since every retry is a new request, I think we nee
| |
| 352 if (delegate_) { | 357 if (delegate_) { |
| 353 fetcher_->backoff_delay_ = | 358 fetcher_->backoff_delay_ = |
| 354 base::TimeDelta::FromMilliseconds(back_off_time); | 359 base::TimeDelta::FromMilliseconds(back_off_time); |
| 355 } | 360 } |
| 356 ++num_retries_; | 361 ++num_retries_; |
| 357 // Restarts the request if we still need to notify the delegate. | 362 // Restarts the request if we still need to notify the delegate. |
| 358 if (delegate_) { | 363 if (delegate_) { |
| 359 if (fetcher_->automatically_retry_on_5xx_ && | 364 if (fetcher_->automatically_retry_on_5xx_ && |
| 360 num_retries_ <= protect_entry_->max_retries()) { | 365 num_retries_ <= fetcher_->max_retries()) { |
| 361 io_message_loop_proxy_->PostDelayedTask( | 366 io_message_loop_proxy_->PostDelayedTask( |
| 362 FROM_HERE, | 367 FROM_HERE, |
| 363 NewRunnableMethod(this, &Core::StartURLRequest), back_off_time); | 368 NewRunnableMethod(this, &Core::StartURLRequest), back_off_time); |
| 364 } else { | 369 } else { |
| 365 delegate_->OnURLFetchComplete(fetcher_, url_, status, response_code_, | 370 delegate_->OnURLFetchComplete(fetcher_, url_, status, response_code_, |
| 366 cookies_, data_); | 371 cookies_, data_); |
| 367 } | 372 } |
| 368 } | 373 } |
| 369 } else { | 374 } else { |
| 370 protect_entry_->UpdateBackoff(URLFetcherProtectEntry::SUCCESS); | |
| 371 if (delegate_) { | 375 if (delegate_) { |
| 372 fetcher_->backoff_delay_ = base::TimeDelta(); | 376 fetcher_->backoff_delay_ = base::TimeDelta(); |
| 373 delegate_->OnURLFetchComplete(fetcher_, url_, status, response_code_, | 377 delegate_->OnURLFetchComplete(fetcher_, url_, status, response_code_, |
| 374 cookies_, data_); | 378 cookies_, data_); |
| 375 } | 379 } |
| 376 } | 380 } |
| 377 } | 381 } |
| 378 | 382 |
| 379 void URLFetcher::Core::ReleaseRequest() { | 383 void URLFetcher::Core::ReleaseRequest() { |
| 380 request_.reset(); | 384 request_.reset(); |
| 381 g_registry.Get().RemoveURLFetcherCore(this); | 385 g_registry.Get().RemoveURLFetcherCore(this); |
| 382 } | 386 } |
| 383 | 387 |
| 384 void URLFetcher::set_upload_data(const std::string& upload_content_type, | 388 void URLFetcher::set_upload_data(const std::string& upload_content_type, |
| 385 const std::string& upload_content) { | 389 const std::string& upload_content) { |
| 386 core_->upload_content_type_ = upload_content_type; | 390 core_->upload_content_type_ = upload_content_type; |
| 387 core_->upload_content_ = upload_content; | 391 core_->upload_content_ = upload_content; |
| 388 } | 392 } |
| 389 | 393 |
| 390 const std::string& URLFetcher::upload_data() const { | 394 const std::string& URLFetcher::upload_data() const { |
| 391 return core_->upload_content_; | 395 return core_->upload_content_; |
| 392 } | 396 } |
| 393 | 397 |
| 394 void URLFetcher::set_load_flags(int load_flags) { | 398 void URLFetcher::set_load_flags(int load_flags) { |
| 395 core_->load_flags_ = load_flags; | 399 core_->load_flags_ = load_flags; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 427 } | 431 } |
| 428 | 432 |
| 429 // static | 433 // static |
| 430 void URLFetcher::CancelAll() { | 434 void URLFetcher::CancelAll() { |
| 431 Core::CancelAll(); | 435 Core::CancelAll(); |
| 432 } | 436 } |
| 433 | 437 |
| 434 URLFetcher::Delegate* URLFetcher::delegate() const { | 438 URLFetcher::Delegate* URLFetcher::delegate() const { |
| 435 return core_->delegate(); | 439 return core_->delegate(); |
| 436 } | 440 } |
| OLD | NEW |