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

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

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