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