Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(266)

Side by Side Diff: chrome/common/net/url_fetcher.cc

Issue 4194001: Implement exponential back-off mechanism and enforce it at the URLRequestHttpJob level. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698