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

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

Issue 7006005: Move UrlFetcher to content. I originally thought that it's only used by chrome code, but turns o... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: fix linux Created 9 years, 6 months 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
« no previous file with comments | « chrome/common/net/url_fetcher.h ('k') | chrome/common/net/url_fetcher_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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/file_path.h"
11 #include "base/file_util_proxy.h"
12 #include "base/lazy_instance.h"
13 #include "base/memory/scoped_callback_factory.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/message_loop_proxy.h"
16 #include "base/platform_file.h"
17 #include "base/stl_util-inl.h"
18 #include "base/string_util.h"
19 #include "base/threading/thread.h"
20 #include "content/browser/browser_thread.h"
21 #include "googleurl/src/gurl.h"
22 #include "net/base/load_flags.h"
23 #include "net/base/io_buffer.h"
24 #include "net/base/net_errors.h"
25 #include "net/base/host_port_pair.h"
26 #include "net/http/http_request_headers.h"
27 #include "net/http/http_response_headers.h"
28 #include "net/url_request/url_request.h"
29 #include "net/url_request/url_request_context.h"
30 #include "net/url_request/url_request_context_getter.h"
31 #include "net/url_request/url_request_throttler_manager.h"
32
33 static const int kBufferSize = 4096;
34 const int URLFetcher::kInvalidHttpResponseCode = -1;
35
36 class URLFetcher::Core
37 : public base::RefCountedThreadSafe<URLFetcher::Core>,
38 public net::URLRequest::Delegate {
39 public:
40 // For POST requests, set |content_type| to the MIME type of the content
41 // and set |content| to the data to upload. |flags| are flags to apply to
42 // the load operation--these should be one or more of the LOAD_* flags
43 // defined in net/base/load_flags.h.
44 Core(URLFetcher* fetcher,
45 const GURL& original_url,
46 RequestType request_type,
47 URLFetcher::Delegate* d);
48
49 // Starts the load. It's important that this not happen in the constructor
50 // because it causes the IO thread to begin AddRef()ing and Release()ing
51 // us. If our caller hasn't had time to fully construct us and take a
52 // reference, the IO thread could interrupt things, run a task, Release()
53 // us, and destroy us, leaving the caller with an already-destroyed object
54 // when construction finishes.
55 void Start();
56
57 // Stops any in-progress load and ensures no callback will happen. It is
58 // safe to call this multiple times.
59 void Stop();
60
61 // Reports that the received content was malformed (i.e. failed parsing
62 // or validation). This makes the throttling logic that does exponential
63 // back-off when servers are having problems treat the current request as
64 // a failure. Your call to this method will be ignored if your request is
65 // already considered a failure based on the HTTP response code or response
66 // headers.
67 void ReceivedContentWasMalformed();
68
69 // Overridden from net::URLRequest::Delegate:
70 virtual void OnResponseStarted(net::URLRequest* request);
71 virtual void OnReadCompleted(net::URLRequest* request, int bytes_read);
72
73 URLFetcher::Delegate* delegate() const { return delegate_; }
74 static void CancelAll();
75
76 private:
77 friend class base::RefCountedThreadSafe<URLFetcher::Core>;
78
79 class Registry {
80 public:
81 Registry();
82 ~Registry();
83
84 void AddURLFetcherCore(Core* core);
85 void RemoveURLFetcherCore(Core* core);
86
87 void CancelAll();
88
89 int size() const {
90 return fetchers_.size();
91 }
92
93 private:
94 std::set<Core*> fetchers_;
95
96 DISALLOW_COPY_AND_ASSIGN(Registry);
97 };
98
99 // Class TempFileWriter encapsulates all state involved in writing
100 // response bytes to a temporary file. It is only used if
101 // |Core::response_destination_| == TEMP_FILE.
102 class TempFileWriter {
103 public:
104 TempFileWriter(
105 URLFetcher::Core* core,
106 scoped_refptr<base::MessageLoopProxy> file_message_loop_proxy);
107
108 ~TempFileWriter();
109 void CreateTempFile();
110 void DidCreateTempFile(base::PlatformFileError error_code,
111 base::PassPlatformFile file_handle,
112 FilePath file_path);
113 void DidCloseTempFile(base::PlatformFileError error_code);
114 void DidReopenTempFile(base::PlatformFileError error_code,
115 base::PassPlatformFile file_handle,
116 bool created);
117
118 // Record |num_bytes_| response bytes in |core_->buffer_| to the file.
119 void WriteBuffer(int num_bytes);
120
121 // Called when a write has been done. Continues writing if there are
122 // any more bytes to write. Otherwise, initiates a read in core_.
123 void ContinueWrite(base::PlatformFileError error_code,
124 int bytes_written);
125
126 // Drop ownership of the file at path |temp_file_|. This class
127 // will not delete it or write to it again.
128 void DisownTempFile();
129
130 // Remove any file created.
131 void Destroy();
132
133 const FilePath& temp_file() const { return temp_file_; }
134 int64 total_bytes_written() { return total_bytes_written_; }
135 base::PlatformFileError error_code() const { return error_code_; }
136
137 private:
138 // The URLFetcher::Core which instantiated this class.
139 URLFetcher::Core* core_;
140
141 // The last error encountered on a file operation. base::PLATFORM_FILE_OK
142 // if no error occurred.
143 base::PlatformFileError error_code_;
144
145 // Callbacks are created for use with base::FileUtilProxy.
146 base::ScopedCallbackFactory<URLFetcher::Core::TempFileWriter>
147 callback_factory_;
148
149 // Message loop on which file opperations should happen.
150 scoped_refptr<base::MessageLoopProxy> file_message_loop_proxy_;
151
152 // Path to the temporary file. This path is empty when there
153 // is no temp file.
154 FilePath temp_file_;
155
156 // Handle to the temp file.
157 base::PlatformFile temp_file_handle_;
158
159 // We always append to the file. Track the total number of bytes
160 // written, so that writes know the offset to give.
161 int64 total_bytes_written_;
162
163 // How many bytes did the last Write() try to write? Needed so
164 // that if not all the bytes get written on a Write(), we can
165 // call Write() again with the rest.
166 int pending_bytes_;
167
168 // When writing, how many bytes from the buffer have been successfully
169 // written so far?
170 int buffer_offset_;
171 };
172
173 virtual ~Core();
174
175 // Wrapper functions that allow us to ensure actions happen on the right
176 // thread.
177 void StartURLRequest();
178 void StartURLRequestWhenAppropriate();
179 void CancelURLRequest();
180 void OnCompletedURLRequest(const net::URLRequestStatus& status);
181 void InformDelegateFetchIsComplete();
182 void NotifyMalformedContent();
183
184 // Deletes the request, removes it from the registry, and removes the
185 // destruction observer.
186 void ReleaseRequest();
187
188 // Returns the max value of exponential back-off release time for
189 // |original_url_| and |url_|.
190 base::TimeTicks GetBackoffReleaseTime();
191
192 void CompleteAddingUploadDataChunk(const std::string& data,
193 bool is_last_chunk);
194
195 // Adds a block of data to be uploaded in a POST body. This can only be
196 // called after Start().
197 void AppendChunkToUpload(const std::string& data, bool is_last_chunk);
198
199 // Store the response bytes in |buffer_| in the container indicated by
200 // |response_destination_|. Return true if the write has been
201 // done, and another read can overwrite |buffer_|. If this function
202 // returns false, it will post a task that will read more bytes once the
203 // write is complete.
204 bool WriteBuffer(int num_bytes);
205
206 // Read response bytes from the request.
207 void ReadResponse();
208
209 URLFetcher* fetcher_; // Corresponding fetcher object
210 GURL original_url_; // The URL we were asked to fetch
211 GURL url_; // The URL we eventually wound up at
212 RequestType request_type_; // What type of request is this?
213 net::URLRequestStatus status_; // Status of the request
214 URLFetcher::Delegate* delegate_; // Object to notify on completion
215 scoped_refptr<base::MessageLoopProxy> delegate_loop_proxy_;
216 // Message loop proxy of the creating
217 // thread.
218 scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
219 // The message loop proxy for the thread
220 // on which the request IO happens.
221 scoped_refptr<base::MessageLoopProxy> file_message_loop_proxy_;
222 // The message loop proxy for the thread
223 // on which file access happens.
224 scoped_ptr<net::URLRequest> request_; // The actual request this wraps
225 int load_flags_; // Flags for the load operation
226 int response_code_; // HTTP status code for the request
227 std::string data_; // Results of the request, when we are
228 // storing the response as a string.
229 scoped_refptr<net::IOBuffer> buffer_;
230 // Read buffer
231 scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
232 // Cookie/cache info for the request
233 net::ResponseCookies cookies_; // Response cookies
234 net::HttpRequestHeaders extra_request_headers_;
235 scoped_refptr<net::HttpResponseHeaders> response_headers_;
236 bool was_fetched_via_proxy_;
237 net::HostPortPair socket_address_;
238
239 std::string upload_content_; // HTTP POST payload
240 std::string upload_content_type_; // MIME type of POST payload
241 std::string referrer_; // HTTP Referer header value
242 bool is_chunked_upload_; // True if using chunked transfer encoding
243
244 // Used to determine how long to wait before making a request or doing a
245 // retry.
246 // Both of them can only be accessed on the IO thread.
247 // We need not only the throttler entry for |original_URL|, but also the one
248 // for |url|. For example, consider the case that URL A redirects to URL B,
249 // for which the server returns a 500 response. In this case, the exponential
250 // back-off release time of URL A won't increase. If we retry without
251 // considering the back-off constraint of URL B, we may send out too many
252 // requests for URL A in a short period of time.
253 scoped_refptr<net::URLRequestThrottlerEntryInterface>
254 original_url_throttler_entry_;
255 scoped_refptr<net::URLRequestThrottlerEntryInterface> url_throttler_entry_;
256
257 // |num_retries_| indicates how many times we've failed to successfully
258 // fetch this URL. Once this value exceeds the maximum number of retries
259 // specified by the owner URLFetcher instance, we'll give up.
260 int num_retries_;
261
262 // True if the URLFetcher has been cancelled.
263 bool was_cancelled_;
264
265 // Since GetBackoffReleaseTime() can only be called on the IO thread, we cache
266 // its value to be used by OnCompletedURLRequest on the creating thread.
267 base::TimeTicks backoff_release_time_;
268
269 // If writing results to a file, |temp_file_writer_| will manage creation,
270 // writing, and destruction of that file.
271 scoped_ptr<TempFileWriter> temp_file_writer_;
272
273 // Where should responses be saved?
274 ResponseDestinationType response_destination_;
275
276 static base::LazyInstance<Registry> g_registry;
277
278 friend class URLFetcher;
279 DISALLOW_COPY_AND_ASSIGN(Core);
280 };
281
282 URLFetcher::Core::Registry::Registry() {}
283 URLFetcher::Core::Registry::~Registry() {}
284
285 void URLFetcher::Core::Registry::AddURLFetcherCore(Core* core) {
286 DCHECK(!ContainsKey(fetchers_, core));
287 fetchers_.insert(core);
288 }
289
290 void URLFetcher::Core::Registry::RemoveURLFetcherCore(Core* core) {
291 DCHECK(ContainsKey(fetchers_, core));
292 fetchers_.erase(core);
293 }
294
295 void URLFetcher::Core::Registry::CancelAll() {
296 while (!fetchers_.empty())
297 (*fetchers_.begin())->CancelURLRequest();
298 }
299
300 // static
301 base::LazyInstance<URLFetcher::Core::Registry>
302 URLFetcher::Core::g_registry(base::LINKER_INITIALIZED);
303
304 URLFetcher::Core::TempFileWriter::TempFileWriter(
305 URLFetcher::Core* core,
306 scoped_refptr<base::MessageLoopProxy> file_message_loop_proxy)
307 : core_(core),
308 error_code_(base::PLATFORM_FILE_OK),
309 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
310 file_message_loop_proxy_(file_message_loop_proxy) {
311 }
312
313 URLFetcher::Core::TempFileWriter::~TempFileWriter() {
314 Destroy();
315 }
316
317 void URLFetcher::Core::TempFileWriter::CreateTempFile() {
318 CHECK(file_message_loop_proxy_.get());
319 base::FileUtilProxy::CreateTemporary(
320 file_message_loop_proxy_,
321 callback_factory_.NewCallback(
322 &URLFetcher::Core::TempFileWriter::DidCreateTempFile));
323 }
324
325 void URLFetcher::Core::TempFileWriter::DidCreateTempFile(
326 base::PlatformFileError error_code,
327 base::PassPlatformFile file_handle,
328 FilePath file_path) {
329 if (base::PLATFORM_FILE_OK != error_code) {
330 error_code_ = error_code;
331 core_->InformDelegateFetchIsComplete();
332 return;
333 }
334
335 temp_file_ = file_path;
336
337 // The file was opened with async writes enabled. FileUtilProxy::Write()
338 // treats a write that returns IO_PENDING as an error, and does not inform
339 // the caller. We need to close and reopen the file with asyncronus writes
340 // disabled.
341 // TODO(skerner): Make FileUtilProxy::Write() play nice with async IO.
342 base::FileUtilProxy::Close(
343 file_message_loop_proxy_,
344 file_handle.ReleaseValue(),
345 callback_factory_.NewCallback(
346 &URLFetcher::Core::TempFileWriter::DidCloseTempFile));
347 }
348
349 void URLFetcher::Core::TempFileWriter::DidCloseTempFile(
350 base::PlatformFileError error_code) {
351 if (base::PLATFORM_FILE_OK != error_code) {
352 error_code_ = error_code;
353 core_->InformDelegateFetchIsComplete();
354 return;
355 }
356
357 int file_flags =
358 base::PLATFORM_FILE_CREATE_ALWAYS |
359 base::PLATFORM_FILE_WRITE |
360 base::PLATFORM_FILE_TEMPORARY;
361
362 base::FileUtilProxy::CreateOrOpen(
363 file_message_loop_proxy_,
364 temp_file_,
365 file_flags,
366 callback_factory_.NewCallback(
367 &URLFetcher::Core::TempFileWriter::DidReopenTempFile));
368 }
369
370 void URLFetcher::Core::TempFileWriter::DidReopenTempFile(
371 base::PlatformFileError error_code,
372 base::PassPlatformFile file_handle,
373 bool created) {
374 if (base::PLATFORM_FILE_OK != error_code) {
375 error_code_ = error_code;
376 core_->InformDelegateFetchIsComplete();
377 return;
378 }
379
380 temp_file_handle_ = file_handle.ReleaseValue();
381 total_bytes_written_ = 0;
382
383 core_->io_message_loop_proxy_->PostTask(
384 FROM_HERE,
385 NewRunnableMethod(core_, &Core::StartURLRequestWhenAppropriate));
386 }
387
388 void URLFetcher::Core::TempFileWriter::WriteBuffer(int num_bytes) {
389 // Start writing to the temp file by setting the initial state
390 // of |pending_bytes_| and |buffer_offset_| to indicate that the
391 // entire buffer has not yet been written.
392 pending_bytes_ = num_bytes;
393 buffer_offset_ = 0;
394 ContinueWrite(base::PLATFORM_FILE_OK, 0);
395 }
396
397 void URLFetcher::Core::TempFileWriter::ContinueWrite(
398 base::PlatformFileError error_code,
399 int bytes_written) {
400 if (base::PLATFORM_FILE_OK != error_code) {
401 error_code_ = error_code;
402 core_->InformDelegateFetchIsComplete();
403 return;
404 }
405
406 total_bytes_written_ += bytes_written;
407 buffer_offset_ += bytes_written;
408 pending_bytes_ -= bytes_written;
409
410 if (pending_bytes_ > 0) {
411 base::FileUtilProxy::Write(
412 file_message_loop_proxy_,
413 temp_file_handle_,
414 total_bytes_written_, // Append to the end
415 (core_->buffer_->data() + buffer_offset_),
416 pending_bytes_,
417 callback_factory_.NewCallback(
418 &URLFetcher::Core::TempFileWriter::ContinueWrite));
419 } else {
420 // Finished writing core_->buffer_ to the file. Read some more.
421 core_->ReadResponse();
422 }
423 }
424
425 void URLFetcher::Core::TempFileWriter::DisownTempFile() {
426 // Forget about any temp file by reseting the path.
427 if (!temp_file_.empty()) {
428 base::FileUtilProxy::Close(
429 file_message_loop_proxy_,
430 temp_file_handle_,
431 NULL);
432 temp_file_ = FilePath();
433 }
434 }
435
436 void URLFetcher::Core::TempFileWriter::Destroy() {
437 if (!temp_file_.empty()) {
438 base::FileUtilProxy::Close(
439 file_message_loop_proxy_,
440 temp_file_handle_,
441 NULL);
442
443 base::FileUtilProxy::Delete(
444 file_message_loop_proxy_,
445 temp_file_,
446 false, // No need to recurse, as the path is to a file.
447 NULL); // No callback.
448 }
449 temp_file_ = FilePath();
450 }
451
452 // static
453 URLFetcher::Factory* URLFetcher::factory_ = NULL;
454
455 void URLFetcher::Delegate::OnURLFetchComplete(
456 const URLFetcher* source,
457 const GURL& url,
458 const net::URLRequestStatus& status,
459 int response_code,
460 const net::ResponseCookies& cookies,
461 const std::string& data) {
462 NOTREACHED() << "If you don't implemnt this, the no-params version "
463 << "should also be implemented, in which case this "
464 << "method won't be called...";
465 }
466
467 // TODO(skerner): This default implementation will be removed, and the
468 // method made pure virtual, once all users of URLFetcher are updated
469 // to not expect response data as a string argument. Once this is removed,
470 // the method URLFetcher::GetResponseStringRef() can be removed as well.
471 // crbug.com/83592 tracks this.
472 void URLFetcher::Delegate::OnURLFetchComplete(const URLFetcher* source) {
473 // A delegate that did not override this method is using the old
474 // parameter list to OnURLFetchComplete(). If a user asked to save
475 // the response to a file, they must use the new parameter list,
476 // in which case we can not get here.
477 // To avoid updating all callers, thunk to the old prototype for now.
478 OnURLFetchComplete(source,
479 source->url(),
480 source->status(),
481 source->response_code(),
482 source->cookies(),
483 source->GetResponseStringRef());
484 }
485
486 // static
487 bool URLFetcher::g_interception_enabled = false;
488
489 URLFetcher::URLFetcher(const GURL& url,
490 RequestType request_type,
491 Delegate* d)
492 : ALLOW_THIS_IN_INITIALIZER_LIST(
493 core_(new Core(this, url, request_type, d))),
494 automatically_retry_on_5xx_(true),
495 max_retries_(0) {
496 }
497
498 URLFetcher::~URLFetcher() {
499 core_->Stop();
500 }
501
502 // static
503 URLFetcher* URLFetcher::Create(int id, const GURL& url,
504 RequestType request_type, Delegate* d) {
505 return factory_ ? factory_->CreateURLFetcher(id, url, request_type, d) :
506 new URLFetcher(url, request_type, d);
507 }
508
509 URLFetcher::Core::Core(URLFetcher* fetcher,
510 const GURL& original_url,
511 RequestType request_type,
512 URLFetcher::Delegate* d)
513 : fetcher_(fetcher),
514 original_url_(original_url),
515 request_type_(request_type),
516 delegate_(d),
517 delegate_loop_proxy_(
518 base::MessageLoopProxy::CreateForCurrentThread()),
519 request_(NULL),
520 load_flags_(net::LOAD_NORMAL),
521 response_code_(URLFetcher::kInvalidHttpResponseCode),
522 buffer_(new net::IOBuffer(kBufferSize)),
523 is_chunked_upload_(false),
524 num_retries_(0),
525 was_cancelled_(false),
526 response_destination_(STRING) {
527 }
528
529 URLFetcher::Core::~Core() {
530 // |request_| should be NULL. If not, it's unsafe to delete it here since we
531 // may not be on the IO thread.
532 DCHECK(!request_.get());
533 }
534
535 void URLFetcher::Core::Start() {
536 DCHECK(delegate_loop_proxy_);
537 CHECK(request_context_getter_) << "We need an URLRequestContext!";
538 io_message_loop_proxy_ = request_context_getter_->GetIOMessageLoopProxy();
539 CHECK(io_message_loop_proxy_.get()) << "We need an IO message loop proxy";
540
541 switch (response_destination_) {
542 case STRING:
543 io_message_loop_proxy_->PostTask(
544 FROM_HERE,
545 NewRunnableMethod(this, &Core::StartURLRequestWhenAppropriate));
546 break;
547
548 case TEMP_FILE:
549 CHECK(file_message_loop_proxy_.get())
550 << "Need to set the file message loop proxy.";
551 temp_file_writer_.reset(
552 new TempFileWriter(this, file_message_loop_proxy_));
553 // CreateTempFile() will invoke Core::StartURLRequestWhenAppropriate
554 // once the file is created.
555 temp_file_writer_->CreateTempFile();
556 break;
557
558 default:
559 NOTREACHED();
560 }
561 }
562
563 void URLFetcher::Core::Stop() {
564 DCHECK(delegate_loop_proxy_->BelongsToCurrentThread());
565 delegate_ = NULL;
566 fetcher_ = NULL;
567 if (io_message_loop_proxy_.get()) {
568 io_message_loop_proxy_->PostTask(
569 FROM_HERE, NewRunnableMethod(this, &Core::CancelURLRequest));
570 }
571 }
572
573 void URLFetcher::Core::ReceivedContentWasMalformed() {
574 DCHECK(delegate_loop_proxy_->BelongsToCurrentThread());
575 if (io_message_loop_proxy_.get()) {
576 io_message_loop_proxy_->PostTask(
577 FROM_HERE, NewRunnableMethod(this, &Core::NotifyMalformedContent));
578 }
579 }
580
581 void URLFetcher::Core::CancelAll() {
582 g_registry.Get().CancelAll();
583 }
584
585 void URLFetcher::Core::OnResponseStarted(net::URLRequest* request) {
586 DCHECK_EQ(request, request_.get());
587 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
588 if (request_->status().is_success()) {
589 response_code_ = request_->GetResponseCode();
590 response_headers_ = request_->response_headers();
591 socket_address_ = request_->GetSocketAddress();
592 was_fetched_via_proxy_ = request_->was_fetched_via_proxy();
593 }
594
595 ReadResponse();
596 }
597
598 void URLFetcher::Core::CompleteAddingUploadDataChunk(
599 const std::string& content, bool is_last_chunk) {
600 DCHECK(is_chunked_upload_);
601 DCHECK(request_.get());
602 DCHECK(!content.empty());
603 request_->AppendChunkToUpload(content.data(),
604 static_cast<int>(content.length()),
605 is_last_chunk);
606 }
607
608 void URLFetcher::Core::AppendChunkToUpload(const std::string& content,
609 bool is_last_chunk) {
610 DCHECK(delegate_loop_proxy_);
611 CHECK(io_message_loop_proxy_.get());
612 io_message_loop_proxy_->PostTask(
613 FROM_HERE,
614 NewRunnableMethod(this, &Core::CompleteAddingUploadDataChunk, content,
615 is_last_chunk));
616 }
617
618 // Return true if the write was done and reading may continue.
619 // Return false if the write is pending, and the next read will
620 // be done later.
621 bool URLFetcher::Core::WriteBuffer(int num_bytes) {
622 bool write_complete = false;
623 switch (response_destination_) {
624 case STRING:
625 data_.append(buffer_->data(), num_bytes);
626 write_complete = true;
627 break;
628
629 case TEMP_FILE:
630 temp_file_writer_->WriteBuffer(num_bytes);
631 // WriteBuffer() sends a request the file thread.
632 // The write is not done yet.
633 write_complete = false;
634 break;
635
636 default:
637 NOTREACHED();
638 }
639 return write_complete;
640 }
641
642 void URLFetcher::Core::OnReadCompleted(net::URLRequest* request,
643 int bytes_read) {
644 DCHECK(request == request_);
645 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
646
647 url_ = request->url();
648 url_throttler_entry_ =
649 net::URLRequestThrottlerManager::GetInstance()->RegisterRequestUrl(url_);
650
651 bool waiting_on_write = false;
652 do {
653 if (!request_->status().is_success() || bytes_read <= 0)
654 break;
655
656 if (!WriteBuffer(bytes_read)) {
657 // If WriteBuffer() returns false, we have a pending write to
658 // wait on before reading further.
659 waiting_on_write = true;
660 break;
661 }
662 } while (request_->Read(buffer_, kBufferSize, &bytes_read));
663
664 if (request_->status().is_success())
665 request_->GetResponseCookies(&cookies_);
666
667 // See comments re: HEAD requests in ReadResponse().
668 if ((!request_->status().is_io_pending() && !waiting_on_write) ||
669 (request_type_ == HEAD)) {
670 backoff_release_time_ = GetBackoffReleaseTime();
671
672 bool posted = delegate_loop_proxy_->PostTask(
673 FROM_HERE,
674 NewRunnableMethod(this,
675 &Core::OnCompletedURLRequest,
676 request_->status()));
677 // If the delegate message loop does not exist any more, then the delegate
678 // should be gone too.
679 DCHECK(posted || !delegate_);
680 ReleaseRequest();
681 }
682 }
683
684 void URLFetcher::Core::ReadResponse() {
685 // Some servers may treat HEAD requests as GET requests. To free up the
686 // network connection as soon as possible, signal that the request has
687 // completed immediately, without trying to read any data back (all we care
688 // about is the response code and headers, which we already have).
689 int bytes_read = 0;
690 if (request_->status().is_success() && (request_type_ != HEAD))
691 request_->Read(buffer_, kBufferSize, &bytes_read);
692 OnReadCompleted(request_.get(), bytes_read);
693 }
694
695 void URLFetcher::Core::StartURLRequest() {
696 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
697
698 if (was_cancelled_) {
699 // Since StartURLRequest() is posted as a *delayed* task, it may
700 // run after the URLFetcher was already stopped.
701 return;
702 }
703
704 CHECK(request_context_getter_);
705 DCHECK(!request_.get());
706
707 g_registry.Get().AddURLFetcherCore(this);
708 request_.reset(new net::URLRequest(original_url_, this));
709 int flags = request_->load_flags() | load_flags_;
710 if (!g_interception_enabled) {
711 flags = flags | net::LOAD_DISABLE_INTERCEPT;
712 }
713 if (is_chunked_upload_)
714 request_->EnableChunkedUpload();
715 request_->set_load_flags(flags);
716 request_->set_context(request_context_getter_->GetURLRequestContext());
717 request_->set_referrer(referrer_);
718
719 switch (request_type_) {
720 case GET:
721 break;
722
723 case POST:
724 DCHECK(!upload_content_.empty() || is_chunked_upload_);
725 DCHECK(!upload_content_type_.empty());
726
727 request_->set_method("POST");
728 extra_request_headers_.SetHeader(net::HttpRequestHeaders::kContentType,
729 upload_content_type_);
730 if (!upload_content_.empty()) {
731 request_->AppendBytesToUpload(
732 upload_content_.data(), static_cast<int>(upload_content_.length()));
733 }
734 break;
735
736 case HEAD:
737 request_->set_method("HEAD");
738 break;
739
740 default:
741 NOTREACHED();
742 }
743
744 if (!extra_request_headers_.IsEmpty())
745 request_->SetExtraRequestHeaders(extra_request_headers_);
746
747 // There might be data left over from a previous request attempt.
748 data_.clear();
749
750 // If we are writing the response to a file, the only caller
751 // of this function should have created it and not written yet.
752 CHECK(!temp_file_writer_.get() ||
753 temp_file_writer_->total_bytes_written() == 0);
754
755 request_->Start();
756 }
757
758 void URLFetcher::Core::StartURLRequestWhenAppropriate() {
759 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
760
761 if (was_cancelled_)
762 return;
763
764 if (original_url_throttler_entry_ == NULL) {
765 original_url_throttler_entry_ =
766 net::URLRequestThrottlerManager::GetInstance()->RegisterRequestUrl(
767 original_url_);
768 }
769
770 int64 delay = original_url_throttler_entry_->ReserveSendingTimeForNextRequest(
771 GetBackoffReleaseTime());
772 if (delay == 0) {
773 StartURLRequest();
774 } else {
775 MessageLoop::current()->PostDelayedTask(
776 FROM_HERE,
777 NewRunnableMethod(this, &Core::StartURLRequest),
778 delay);
779 }
780 }
781
782 void URLFetcher::Core::CancelURLRequest() {
783 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
784
785 if (request_.get()) {
786 request_->Cancel();
787 ReleaseRequest();
788 }
789 // Release the reference to the request context. There could be multiple
790 // references to URLFetcher::Core at this point so it may take a while to
791 // delete the object, but we cannot delay the destruction of the request
792 // context.
793 request_context_getter_ = NULL;
794 was_cancelled_ = true;
795 temp_file_writer_.reset();
796 }
797
798 void URLFetcher::Core::OnCompletedURLRequest(
799 const net::URLRequestStatus& status) {
800 DCHECK(delegate_loop_proxy_->BelongsToCurrentThread());
801
802 // Save the status so that delegates can read it.
803 status_ = status;
804
805 // Checks the response from server.
806 if (response_code_ >= 500 ||
807 status.os_error() == net::ERR_TEMPORARILY_THROTTLED) {
808 // When encountering a server error, we will send the request again
809 // after backoff time.
810 ++num_retries_;
811 // Restarts the request if we still need to notify the delegate.
812 if (delegate_) {
813 // Note that backoff_delay_ may be 0 because (a) the URLRequestThrottler
814 // code does not necessarily back off on the first error, and (b) it
815 // only backs off on some of the 5xx status codes.
816 fetcher_->backoff_delay_ = backoff_release_time_ - base::TimeTicks::Now();
817 if (fetcher_->backoff_delay_ < base::TimeDelta())
818 fetcher_->backoff_delay_ = base::TimeDelta();
819
820 if (fetcher_->automatically_retry_on_5xx_ &&
821 num_retries_ <= fetcher_->max_retries()) {
822 io_message_loop_proxy_->PostTask(
823 FROM_HERE,
824 NewRunnableMethod(this, &Core::StartURLRequestWhenAppropriate));
825 } else {
826 InformDelegateFetchIsComplete();
827 }
828 }
829 } else {
830 if (delegate_) {
831 fetcher_->backoff_delay_ = base::TimeDelta();
832 InformDelegateFetchIsComplete();
833 }
834 }
835 }
836
837 void URLFetcher::Core::InformDelegateFetchIsComplete() {
838 delegate_->OnURLFetchComplete(fetcher_);
839 }
840
841 void URLFetcher::Core::NotifyMalformedContent() {
842 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
843 if (url_throttler_entry_ != NULL) {
844 int status_code = response_code_;
845 if (status_code == kInvalidHttpResponseCode) {
846 // The status code will generally be known by the time clients
847 // call the |ReceivedContentWasMalformed()| function (which ends up
848 // calling the current function) but if it's not, we need to assume
849 // the response was successful so that the total failure count
850 // used to calculate exponential back-off goes up.
851 status_code = 200;
852 }
853 url_throttler_entry_->ReceivedContentWasMalformed(status_code);
854 }
855 }
856
857 void URLFetcher::Core::ReleaseRequest() {
858 request_.reset();
859 g_registry.Get().RemoveURLFetcherCore(this);
860 }
861
862 base::TimeTicks URLFetcher::Core::GetBackoffReleaseTime() {
863 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
864 DCHECK(original_url_throttler_entry_ != NULL);
865
866 base::TimeTicks original_url_backoff =
867 original_url_throttler_entry_->GetExponentialBackoffReleaseTime();
868 base::TimeTicks destination_url_backoff;
869 if (url_throttler_entry_ != NULL &&
870 original_url_throttler_entry_ != url_throttler_entry_) {
871 destination_url_backoff =
872 url_throttler_entry_->GetExponentialBackoffReleaseTime();
873 }
874
875 return original_url_backoff > destination_url_backoff ?
876 original_url_backoff : destination_url_backoff;
877 }
878
879 void URLFetcher::set_upload_data(const std::string& upload_content_type,
880 const std::string& upload_content) {
881 DCHECK(!core_->is_chunked_upload_);
882 core_->upload_content_type_ = upload_content_type;
883 core_->upload_content_ = upload_content;
884 }
885
886 void URLFetcher::set_chunked_upload(const std::string& content_type) {
887 DCHECK(core_->is_chunked_upload_ ||
888 (core_->upload_content_type_.empty() &&
889 core_->upload_content_.empty()));
890 core_->upload_content_type_ = content_type;
891 core_->upload_content_.clear();
892 core_->is_chunked_upload_ = true;
893 }
894
895 void URLFetcher::AppendChunkToUpload(const std::string& data,
896 bool is_last_chunk) {
897 DCHECK(data.length());
898 core_->AppendChunkToUpload(data, is_last_chunk);
899 }
900
901 const std::string& URLFetcher::upload_data() const {
902 return core_->upload_content_;
903 }
904
905 void URLFetcher::set_referrer(const std::string& referrer) {
906 core_->referrer_ = referrer;
907 }
908
909 void URLFetcher::set_load_flags(int load_flags) {
910 core_->load_flags_ = load_flags;
911 }
912
913 int URLFetcher::load_flags() const {
914 return core_->load_flags_;
915 }
916
917 void URLFetcher::set_extra_request_headers(
918 const std::string& extra_request_headers) {
919 core_->extra_request_headers_.Clear();
920 core_->extra_request_headers_.AddHeadersFromString(extra_request_headers);
921 }
922
923 void URLFetcher::set_request_context(
924 net::URLRequestContextGetter* request_context_getter) {
925 core_->request_context_getter_ = request_context_getter;
926 }
927
928 void URLFetcher::set_automatically_retry_on_5xx(bool retry) {
929 automatically_retry_on_5xx_ = retry;
930 }
931
932 void URLFetcher::SaveResponseToTemporaryFile(
933 scoped_refptr<base::MessageLoopProxy> file_message_loop_proxy) {
934 core_->file_message_loop_proxy_ = file_message_loop_proxy;
935 core_->response_destination_ = TEMP_FILE;
936 }
937
938 net::HttpResponseHeaders* URLFetcher::response_headers() const {
939 return core_->response_headers_;
940 }
941
942 // TODO(panayiotis): socket_address_ is written in the IO thread,
943 // if this is accessed in the UI thread, this could result in a race.
944 // Same for response_headers_ above and was_fetched_via_proxy_ below.
945 net::HostPortPair URLFetcher::socket_address() const {
946 return core_->socket_address_;
947 }
948
949 bool URLFetcher::was_fetched_via_proxy() const {
950 return core_->was_fetched_via_proxy_;
951 }
952
953 void URLFetcher::Start() {
954 core_->Start();
955 }
956
957 const GURL& URLFetcher::url() const {
958 return core_->url_;
959 }
960
961 const net::URLRequestStatus& URLFetcher::status() const {
962 return core_->status_;
963 }
964
965 int URLFetcher::response_code() const {
966 return core_->response_code_;
967 }
968
969 const net::ResponseCookies& URLFetcher::cookies() const {
970 return core_->cookies_;
971 }
972
973 bool URLFetcher::FileErrorOccurred(
974 base::PlatformFileError* out_error_code) const {
975
976 // Can't have a file error if no file is being created or written to.
977 if (!core_->temp_file_writer_.get()) {
978 return false;
979 }
980
981 base::PlatformFileError error_code = core_->temp_file_writer_->error_code();
982 if (error_code == base::PLATFORM_FILE_OK)
983 return false;
984
985 *out_error_code = error_code;
986 return true;
987 }
988
989 void URLFetcher::ReceivedContentWasMalformed() {
990 core_->ReceivedContentWasMalformed();
991 }
992
993 bool URLFetcher::GetResponseAsString(std::string* out_response_string) const {
994 if (core_->response_destination_ != STRING)
995 return false;
996
997 *out_response_string = core_->data_;
998 return true;
999 }
1000
1001 const std::string& URLFetcher::GetResponseStringRef() const {
1002 CHECK(core_->response_destination_ == STRING);
1003 return core_->data_;
1004 }
1005
1006 void URLFetcher::SetResponseDestinationForTesting(
1007 ResponseDestinationType value) {
1008 core_->response_destination_ = value;
1009 }
1010
1011 URLFetcher::ResponseDestinationType
1012 URLFetcher::GetResponseDestinationForTesting() const {
1013 return core_->response_destination_;
1014 }
1015
1016 bool URLFetcher::GetResponseAsFilePath(bool take_ownership,
1017 FilePath* out_response_path) const {
1018 if (core_->response_destination_ != TEMP_FILE ||
1019 !core_->temp_file_writer_.get())
1020 return false;
1021
1022 *out_response_path = core_->temp_file_writer_->temp_file();
1023
1024 if (take_ownership)
1025 core_->temp_file_writer_->DisownTempFile();
1026
1027 return true;
1028 }
1029
1030 // static
1031 void URLFetcher::CancelAll() {
1032 Core::CancelAll();
1033 }
1034
1035 // static
1036 int URLFetcher::GetNumFetcherCores() {
1037 return Core::g_registry.Get().size();
1038 }
1039
1040 URLFetcher::Delegate* URLFetcher::delegate() const {
1041 return core_->delegate();
1042 }
OLDNEW
« no previous file with comments | « chrome/common/net/url_fetcher.h ('k') | chrome/common/net/url_fetcher_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698