OLD | NEW |
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 Loading... |
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 DidCreateTemporaryFile(base::PlatformFileError error_code, |
| 106 base::PassPlatformFile file_handle, |
| 107 FilePath file_path); |
| 108 |
| 109 // Record |num_bytes_| response bytes in |core_->buffer_| to the file. |
| 110 void WriteBuffer(int num_bytes); |
| 111 |
| 112 // Called when a write has been done. Continues writing if there are |
| 113 // any more bytes to write. Otherwise, initiates a read in core_. |
| 114 void ContinueWrite(base::PlatformFileError error_code, |
| 115 int bytes_written); |
| 116 |
| 117 // Drop ownership of the file at path |temp_file_|. This class |
| 118 // will not delete it or write to it again. |
| 119 void DisownTempFile(); |
| 120 |
| 121 // Remove any file created. |
| 122 void Destroy(); |
| 123 |
| 124 const FilePath& temp_file() const { return temp_file_; } |
| 125 int64 total_bytes_written() { return total_bytes_written_; } |
| 126 base::PlatformFileError error_code() const { return error_code_; } |
| 127 |
| 128 private: |
| 129 // The URLFetcher::Core which instantiated this class. |
| 130 URLFetcher::Core* core_; |
| 131 |
| 132 // The last error encountered on a file operation. base::PLATFORM_FILE_OK |
| 133 // if no error occurred. |
| 134 base::PlatformFileError error_code_; |
| 135 |
| 136 // Callbacks are created for use with base::FileUtilProxy. |
| 137 base::ScopedCallbackFactory<URLFetcher::Core::TempFileWriter> |
| 138 callback_factory_; |
| 139 |
| 140 // Message loop on which file opperations should happen. |
| 141 scoped_refptr<base::MessageLoopProxy> file_message_loop_proxy_; |
| 142 |
| 143 // Path to the temporary file. This path is empty when there |
| 144 // is no temp file. |
| 145 FilePath temp_file_; |
| 146 |
| 147 // Handle to the temp file. |
| 148 base::PlatformFile temp_file_handle_; |
| 149 |
| 150 // We always append to the file. Track the total number of bytes |
| 151 // written, so that writes know the offset to give. |
| 152 int64 total_bytes_written_; |
| 153 |
| 154 // How many bytes did the last Write() try to write? Needed so |
| 155 // that if not all the bytes get written on a Write(), we can |
| 156 // call Write() again with the rest. |
| 157 int pending_bytes_; |
| 158 |
| 159 // When writing, how many bytes from the buffer have been successfully |
| 160 // written so far? |
| 161 int buffer_offset_; |
| 162 }; |
| 163 |
89 virtual ~Core(); | 164 virtual ~Core(); |
90 | 165 |
91 // Wrapper functions that allow us to ensure actions happen on the right | 166 // Wrapper functions that allow us to ensure actions happen on the right |
92 // thread. | 167 // thread. |
93 void StartURLRequest(); | 168 void StartURLRequest(); |
94 void StartURLRequestWhenAppropriate(); | 169 void StartURLRequestWhenAppropriate(); |
95 void CancelURLRequest(); | 170 void CancelURLRequest(); |
96 void OnCompletedURLRequest(const net::URLRequestStatus& status); | 171 void OnCompletedURLRequest(const net::URLRequestStatus& status); |
| 172 void InformDelegateFetchIsComplete(); |
97 void NotifyMalformedContent(); | 173 void NotifyMalformedContent(); |
98 | 174 |
99 // Deletes the request, removes it from the registry, and removes the | 175 // Deletes the request, removes it from the registry, and removes the |
100 // destruction observer. | 176 // destruction observer. |
101 void ReleaseRequest(); | 177 void ReleaseRequest(); |
102 | 178 |
103 // Returns the max value of exponential back-off release time for | 179 // Returns the max value of exponential back-off release time for |
104 // |original_url_| and |url_|. | 180 // |original_url_| and |url_|. |
105 base::TimeTicks GetBackoffReleaseTime(); | 181 base::TimeTicks GetBackoffReleaseTime(); |
106 | 182 |
107 void CompleteAddingUploadDataChunk(const std::string& data, | 183 void CompleteAddingUploadDataChunk(const std::string& data, |
108 bool is_last_chunk); | 184 bool is_last_chunk); |
109 | 185 |
110 // Adds a block of data to be uploaded in a POST body. This can only be called | 186 // Adds a block of data to be uploaded in a POST body. This can only be |
111 // after Start(). | 187 // called after Start(). |
112 void AppendChunkToUpload(const std::string& data, bool is_last_chunk); | 188 void AppendChunkToUpload(const std::string& data, bool is_last_chunk); |
113 | 189 |
| 190 // Store the response bytes in |buffer_| in the container indicated by |
| 191 // |fetcher_->response_destination_|. Return true if the write has been |
| 192 // done, and another read can overwrite |buffer_|. If this function |
| 193 // returns false, it will post a task that will read more bytes once the |
| 194 // write is complete. |
| 195 bool WriteBuffer(int num_bytes); |
| 196 |
| 197 // Read response bytes from the request. |
| 198 void ReadResponse(); |
| 199 |
114 URLFetcher* fetcher_; // Corresponding fetcher object | 200 URLFetcher* fetcher_; // Corresponding fetcher object |
115 GURL original_url_; // The URL we were asked to fetch | 201 GURL original_url_; // The URL we were asked to fetch |
116 GURL url_; // The URL we eventually wound up at | 202 GURL url_; // The URL we eventually wound up at |
117 RequestType request_type_; // What type of request is this? | 203 RequestType request_type_; // What type of request is this? |
| 204 net::URLRequestStatus status_; // Status of the request |
118 URLFetcher::Delegate* delegate_; // Object to notify on completion | 205 URLFetcher::Delegate* delegate_; // Object to notify on completion |
119 scoped_refptr<base::MessageLoopProxy> delegate_loop_proxy_; | 206 scoped_refptr<base::MessageLoopProxy> delegate_loop_proxy_; |
120 // Message loop proxy of the creating | 207 // Message loop proxy of the creating |
121 // thread. | 208 // thread. |
122 scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_; | 209 scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_; |
123 // The message loop proxy for the thread | 210 // The message loop proxy for the thread |
124 // on which the request IO happens. | 211 // on which the request IO happens. |
| 212 scoped_refptr<base::MessageLoopProxy> file_message_loop_proxy_; |
| 213 // The message loop proxy for the thread |
| 214 // on which file access happens. |
125 scoped_ptr<net::URLRequest> request_; // The actual request this wraps | 215 scoped_ptr<net::URLRequest> request_; // The actual request this wraps |
126 int load_flags_; // Flags for the load operation | 216 int load_flags_; // Flags for the load operation |
127 int response_code_; // HTTP status code for the request | 217 int response_code_; // HTTP status code for the request |
128 std::string data_; // Results of the request | 218 std::string data_; // Results of the request, when we are |
| 219 // storing the response as a string. |
129 scoped_refptr<net::IOBuffer> buffer_; | 220 scoped_refptr<net::IOBuffer> buffer_; |
130 // Read buffer | 221 // Read buffer |
131 scoped_refptr<net::URLRequestContextGetter> request_context_getter_; | 222 scoped_refptr<net::URLRequestContextGetter> request_context_getter_; |
132 // Cookie/cache info for the request | 223 // Cookie/cache info for the request |
133 net::ResponseCookies cookies_; // Response cookies | 224 net::ResponseCookies cookies_; // Response cookies |
134 net::HttpRequestHeaders extra_request_headers_; | 225 net::HttpRequestHeaders extra_request_headers_; |
135 scoped_refptr<net::HttpResponseHeaders> response_headers_; | 226 scoped_refptr<net::HttpResponseHeaders> response_headers_; |
136 bool was_fetched_via_proxy_; | 227 bool was_fetched_via_proxy_; |
137 net::HostPortPair socket_address_; | 228 net::HostPortPair socket_address_; |
138 | 229 |
(...skipping 20 matching lines...) Expand all Loading... |
159 // specified by the owner URLFetcher instance, we'll give up. | 250 // specified by the owner URLFetcher instance, we'll give up. |
160 int num_retries_; | 251 int num_retries_; |
161 | 252 |
162 // True if the URLFetcher has been cancelled. | 253 // True if the URLFetcher has been cancelled. |
163 bool was_cancelled_; | 254 bool was_cancelled_; |
164 | 255 |
165 // Since GetBackoffReleaseTime() can only be called on the IO thread, we cache | 256 // Since GetBackoffReleaseTime() can only be called on the IO thread, we cache |
166 // its value to be used by OnCompletedURLRequest on the creating thread. | 257 // its value to be used by OnCompletedURLRequest on the creating thread. |
167 base::TimeTicks backoff_release_time_; | 258 base::TimeTicks backoff_release_time_; |
168 | 259 |
| 260 // If writing results to a file, |temp_file_writer_| will manage creation, |
| 261 // writing, and destruction of that file. |
| 262 scoped_ptr<TempFileWriter> temp_file_writer_; |
| 263 |
169 static base::LazyInstance<Registry> g_registry; | 264 static base::LazyInstance<Registry> g_registry; |
170 | 265 |
171 friend class URLFetcher; | 266 friend class URLFetcher; |
172 DISALLOW_COPY_AND_ASSIGN(Core); | 267 DISALLOW_COPY_AND_ASSIGN(Core); |
173 }; | 268 }; |
174 | 269 |
175 URLFetcher::Core::Registry::Registry() {} | 270 URLFetcher::Core::Registry::Registry() {} |
176 URLFetcher::Core::Registry::~Registry() {} | 271 URLFetcher::Core::Registry::~Registry() {} |
177 | 272 |
178 void URLFetcher::Core::Registry::AddURLFetcherCore(Core* core) { | 273 void URLFetcher::Core::Registry::AddURLFetcherCore(Core* core) { |
179 DCHECK(!ContainsKey(fetchers_, core)); | 274 DCHECK(!ContainsKey(fetchers_, core)); |
180 fetchers_.insert(core); | 275 fetchers_.insert(core); |
181 } | 276 } |
182 | 277 |
183 void URLFetcher::Core::Registry::RemoveURLFetcherCore(Core* core) { | 278 void URLFetcher::Core::Registry::RemoveURLFetcherCore(Core* core) { |
184 DCHECK(ContainsKey(fetchers_, core)); | 279 DCHECK(ContainsKey(fetchers_, core)); |
185 fetchers_.erase(core); | 280 fetchers_.erase(core); |
186 } | 281 } |
187 | 282 |
188 void URLFetcher::Core::Registry::CancelAll() { | 283 void URLFetcher::Core::Registry::CancelAll() { |
189 while (!fetchers_.empty()) | 284 while (!fetchers_.empty()) |
190 (*fetchers_.begin())->CancelURLRequest(); | 285 (*fetchers_.begin())->CancelURLRequest(); |
191 } | 286 } |
192 | 287 |
193 // static | 288 // static |
194 base::LazyInstance<URLFetcher::Core::Registry> | 289 base::LazyInstance<URLFetcher::Core::Registry> |
195 URLFetcher::Core::g_registry(base::LINKER_INITIALIZED); | 290 URLFetcher::Core::g_registry(base::LINKER_INITIALIZED); |
196 | 291 |
| 292 URLFetcher::Core::TempFileWriter::TempFileWriter( |
| 293 URLFetcher::Core* core, |
| 294 scoped_refptr<base::MessageLoopProxy> file_message_loop_proxy) |
| 295 : core_(core), |
| 296 error_code_(base::PLATFORM_FILE_OK), |
| 297 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), |
| 298 file_message_loop_proxy_(file_message_loop_proxy) { |
| 299 } |
| 300 |
| 301 URLFetcher::Core::TempFileWriter::~TempFileWriter() { |
| 302 Destroy(); |
| 303 } |
| 304 |
| 305 void URLFetcher::Core::TempFileWriter::CreateTempFile() { |
| 306 CHECK(file_message_loop_proxy_.get()); |
| 307 base::FileUtilProxy::CreateTemporary( |
| 308 file_message_loop_proxy_, |
| 309 callback_factory_.NewCallback( |
| 310 &URLFetcher::Core::TempFileWriter::DidCreateTemporaryFile)); |
| 311 } |
| 312 |
| 313 void URLFetcher::Core::TempFileWriter::DidCreateTemporaryFile( |
| 314 base::PlatformFileError error_code, |
| 315 base::PassPlatformFile file_handle, |
| 316 FilePath file_path) { |
| 317 if (base::PLATFORM_FILE_OK != error_code) { |
| 318 error_code_ = error_code; |
| 319 core_->InformDelegateFetchIsComplete(); |
| 320 return; |
| 321 } |
| 322 |
| 323 temp_file_handle_ = file_handle.ReleaseValue(); |
| 324 temp_file_ = file_path; |
| 325 total_bytes_written_ = 0; |
| 326 |
| 327 core_->io_message_loop_proxy_->PostTask( |
| 328 FROM_HERE, |
| 329 NewRunnableMethod(core_, &Core::StartURLRequestWhenAppropriate)); |
| 330 } |
| 331 |
| 332 void URLFetcher::Core::TempFileWriter::WriteBuffer(int num_bytes) { |
| 333 // Start writing to the temp file by setting the initial state |
| 334 // of |pending_bytes_| and |buffer_offset_| to indicate that the |
| 335 // entire buffer has not yet been written. |
| 336 pending_bytes_ = num_bytes; |
| 337 buffer_offset_ = 0; |
| 338 ContinueWrite(base::PLATFORM_FILE_OK, 0); |
| 339 } |
| 340 |
| 341 void URLFetcher::Core::TempFileWriter::ContinueWrite( |
| 342 base::PlatformFileError error_code, |
| 343 int bytes_written) { |
| 344 if (base::PLATFORM_FILE_OK != error_code) { |
| 345 error_code_ = error_code; |
| 346 core_->InformDelegateFetchIsComplete(); |
| 347 return; |
| 348 } |
| 349 |
| 350 total_bytes_written_ += bytes_written; |
| 351 buffer_offset_ += bytes_written; |
| 352 pending_bytes_ -= bytes_written; |
| 353 |
| 354 if (pending_bytes_ > 0) { |
| 355 base::FileUtilProxy::Write( |
| 356 file_message_loop_proxy_, |
| 357 temp_file_handle_, |
| 358 total_bytes_written_, // Append to the end |
| 359 (core_->buffer_->data() + buffer_offset_), |
| 360 pending_bytes_, |
| 361 callback_factory_.NewCallback( |
| 362 &URLFetcher::Core::TempFileWriter::ContinueWrite)); |
| 363 } else { |
| 364 // Finished writing core_->buffer_ to the file. Read some more. |
| 365 core_->ReadResponse(); |
| 366 } |
| 367 } |
| 368 |
| 369 void URLFetcher::Core::TempFileWriter::DisownTempFile() { |
| 370 // Forget about any temp file by reseting the path. |
| 371 temp_file_ = FilePath(); |
| 372 } |
| 373 |
| 374 void URLFetcher::Core::TempFileWriter::Destroy() { |
| 375 if (!temp_file_.empty()) { |
| 376 base::FileUtilProxy::Delete( |
| 377 file_message_loop_proxy_, |
| 378 temp_file_, |
| 379 false, // No need to recurse, as the path is to a file. |
| 380 NULL); // No callback. |
| 381 } |
| 382 temp_file_ = FilePath(); |
| 383 } |
| 384 |
197 // static | 385 // static |
198 URLFetcher::Factory* URLFetcher::factory_ = NULL; | 386 URLFetcher::Factory* URLFetcher::factory_ = NULL; |
199 | 387 |
| 388 void URLFetcher::Delegate::OnURLFetchComplete( |
| 389 const URLFetcher* source, |
| 390 const GURL& url, |
| 391 const net::URLRequestStatus& status, |
| 392 int response_code, |
| 393 const net::ResponseCookies& cookies, |
| 394 const std::string& data) { |
| 395 NOTREACHED() << "If you don't implemnt this, the no-params version " |
| 396 << "should also be implemented, in which case this " |
| 397 << "method won't be called..."; |
| 398 } |
| 399 |
| 400 // TODO(skerner): This default implementation will be removed, and the |
| 401 // method made pure virtual, once all users of URLFetcher are updated |
| 402 // to not expect response data as a string argument. |
| 403 void URLFetcher::Delegate::OnURLFetchComplete(const URLFetcher* source) { |
| 404 // A delegate that did not override this method is using the old |
| 405 // parameter list to OnURLFetchComplete(). If a user asked to save |
| 406 // the response to a file, they must use the new parameter list, |
| 407 // in which case we can not get here. |
| 408 std::string data; |
| 409 CHECK(source->GetResponseAsString(&data)); |
| 410 |
| 411 // To avoid updating all callers, thunk to the old prototype for now. |
| 412 OnURLFetchComplete(source, |
| 413 source->url(), |
| 414 source->status(), |
| 415 source->response_code(), |
| 416 source->cookies(), |
| 417 data); |
| 418 } |
| 419 |
200 // static | 420 // static |
201 bool URLFetcher::g_interception_enabled = false; | 421 bool URLFetcher::g_interception_enabled = false; |
202 | 422 |
203 URLFetcher::URLFetcher(const GURL& url, | 423 URLFetcher::URLFetcher(const GURL& url, |
204 RequestType request_type, | 424 RequestType request_type, |
205 Delegate* d) | 425 Delegate* d) |
206 : ALLOW_THIS_IN_INITIALIZER_LIST( | 426 : ALLOW_THIS_IN_INITIALIZER_LIST( |
207 core_(new Core(this, url, request_type, d))), | 427 core_(new Core(this, url, request_type, d))), |
208 automatically_retry_on_5xx_(true), | 428 automatically_retry_on_5xx_(true), |
209 max_retries_(0) { | 429 max_retries_(0), |
| 430 response_destination_(STRING) { |
210 } | 431 } |
211 | 432 |
212 URLFetcher::~URLFetcher() { | 433 URLFetcher::~URLFetcher() { |
213 core_->Stop(); | 434 core_->Stop(); |
214 } | 435 } |
215 | 436 |
216 // static | 437 // static |
217 URLFetcher* URLFetcher::Create(int id, const GURL& url, | 438 URLFetcher* URLFetcher::Create(int id, const GURL& url, |
218 RequestType request_type, Delegate* d) { | 439 RequestType request_type, Delegate* d) { |
219 return factory_ ? factory_->CreateURLFetcher(id, url, request_type, d) : | 440 return factory_ ? factory_->CreateURLFetcher(id, url, request_type, d) : |
220 new URLFetcher(url, request_type, d); | 441 new URLFetcher(url, request_type, d); |
221 } | 442 } |
222 | 443 |
223 URLFetcher::Core::Core(URLFetcher* fetcher, | 444 URLFetcher::Core::Core(URLFetcher* fetcher, |
224 const GURL& original_url, | 445 const GURL& original_url, |
225 RequestType request_type, | 446 RequestType request_type, |
226 URLFetcher::Delegate* d) | 447 URLFetcher::Delegate* d) |
227 : fetcher_(fetcher), | 448 : fetcher_(fetcher), |
228 original_url_(original_url), | 449 original_url_(original_url), |
229 request_type_(request_type), | 450 request_type_(request_type), |
230 delegate_(d), | 451 delegate_(d), |
231 delegate_loop_proxy_(base::MessageLoopProxy::CreateForCurrentThread()), | 452 delegate_loop_proxy_( |
| 453 base::MessageLoopProxy::CreateForCurrentThread()), |
232 request_(NULL), | 454 request_(NULL), |
233 load_flags_(net::LOAD_NORMAL), | 455 load_flags_(net::LOAD_NORMAL), |
234 response_code_(-1), | 456 response_code_(URLFetcher::kInvalidHttpResponseCode), |
235 buffer_(new net::IOBuffer(kBufferSize)), | 457 buffer_(new net::IOBuffer(kBufferSize)), |
236 is_chunked_upload_(false), | 458 is_chunked_upload_(false), |
237 num_retries_(0), | 459 num_retries_(0), |
238 was_cancelled_(false) { | 460 was_cancelled_(false) { |
239 } | 461 } |
240 | 462 |
241 URLFetcher::Core::~Core() { | 463 URLFetcher::Core::~Core() { |
242 // |request_| should be NULL. If not, it's unsafe to delete it here since we | 464 // |request_| should be NULL. If not, it's unsafe to delete it here since we |
243 // may not be on the IO thread. | 465 // may not be on the IO thread. |
244 DCHECK(!request_.get()); | 466 DCHECK(!request_.get()); |
245 } | 467 } |
246 | 468 |
247 void URLFetcher::Core::Start() { | 469 void URLFetcher::Core::Start() { |
248 DCHECK(delegate_loop_proxy_); | 470 DCHECK(delegate_loop_proxy_); |
249 CHECK(request_context_getter_) << "We need an URLRequestContext!"; | 471 CHECK(request_context_getter_) << "We need an URLRequestContext!"; |
250 io_message_loop_proxy_ = request_context_getter_->GetIOMessageLoopProxy(); | 472 io_message_loop_proxy_ = request_context_getter_->GetIOMessageLoopProxy(); |
251 CHECK(io_message_loop_proxy_.get()) << "We need an IO message loop proxy"; | 473 CHECK(io_message_loop_proxy_.get()) << "We need an IO message loop proxy"; |
252 | 474 |
253 io_message_loop_proxy_->PostTask( | 475 switch (fetcher_->response_destination_) { |
254 FROM_HERE, | 476 case STRING: |
255 NewRunnableMethod(this, &Core::StartURLRequestWhenAppropriate)); | 477 io_message_loop_proxy_->PostTask( |
| 478 FROM_HERE, |
| 479 NewRunnableMethod(this, &Core::StartURLRequestWhenAppropriate)); |
| 480 break; |
| 481 |
| 482 case TEMP_FILE: |
| 483 CHECK(file_message_loop_proxy_.get()) |
| 484 << "Need to set the file message loop proxy."; |
| 485 temp_file_writer_.reset( |
| 486 new TempFileWriter(this, file_message_loop_proxy_)); |
| 487 // CreateTempFile() will invoke Core::StartURLRequestWhenAppropriate |
| 488 // once the file is created. |
| 489 temp_file_writer_->CreateTempFile(); |
| 490 break; |
| 491 |
| 492 default: |
| 493 NOTREACHED(); |
| 494 } |
256 } | 495 } |
257 | 496 |
258 void URLFetcher::Core::Stop() { | 497 void URLFetcher::Core::Stop() { |
259 DCHECK(delegate_loop_proxy_->BelongsToCurrentThread()); | 498 DCHECK(delegate_loop_proxy_->BelongsToCurrentThread()); |
260 delegate_ = NULL; | 499 delegate_ = NULL; |
261 fetcher_ = NULL; | 500 fetcher_ = NULL; |
262 if (io_message_loop_proxy_.get()) { | 501 if (io_message_loop_proxy_.get()) { |
263 io_message_loop_proxy_->PostTask( | 502 io_message_loop_proxy_->PostTask( |
264 FROM_HERE, NewRunnableMethod(this, &Core::CancelURLRequest)); | 503 FROM_HERE, NewRunnableMethod(this, &Core::CancelURLRequest)); |
265 } | 504 } |
(...skipping 14 matching lines...) Expand all Loading... |
280 void URLFetcher::Core::OnResponseStarted(net::URLRequest* request) { | 519 void URLFetcher::Core::OnResponseStarted(net::URLRequest* request) { |
281 DCHECK_EQ(request, request_.get()); | 520 DCHECK_EQ(request, request_.get()); |
282 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 521 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
283 if (request_->status().is_success()) { | 522 if (request_->status().is_success()) { |
284 response_code_ = request_->GetResponseCode(); | 523 response_code_ = request_->GetResponseCode(); |
285 response_headers_ = request_->response_headers(); | 524 response_headers_ = request_->response_headers(); |
286 socket_address_ = request_->GetSocketAddress(); | 525 socket_address_ = request_->GetSocketAddress(); |
287 was_fetched_via_proxy_ = request_->was_fetched_via_proxy(); | 526 was_fetched_via_proxy_ = request_->was_fetched_via_proxy(); |
288 } | 527 } |
289 | 528 |
290 int bytes_read = 0; | 529 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 } | 530 } |
299 | 531 |
300 void URLFetcher::Core::CompleteAddingUploadDataChunk( | 532 void URLFetcher::Core::CompleteAddingUploadDataChunk( |
301 const std::string& content, bool is_last_chunk) { | 533 const std::string& content, bool is_last_chunk) { |
302 DCHECK(is_chunked_upload_); | 534 DCHECK(is_chunked_upload_); |
303 DCHECK(request_.get()); | 535 DCHECK(request_.get()); |
304 DCHECK(!content.empty()); | 536 DCHECK(!content.empty()); |
305 request_->AppendChunkToUpload(content.data(), | 537 request_->AppendChunkToUpload(content.data(), |
306 static_cast<int>(content.length()), | 538 static_cast<int>(content.length()), |
307 is_last_chunk); | 539 is_last_chunk); |
308 } | 540 } |
309 | 541 |
310 void URLFetcher::Core::AppendChunkToUpload(const std::string& content, | 542 void URLFetcher::Core::AppendChunkToUpload(const std::string& content, |
311 bool is_last_chunk) { | 543 bool is_last_chunk) { |
312 DCHECK(delegate_loop_proxy_); | 544 DCHECK(delegate_loop_proxy_); |
313 CHECK(io_message_loop_proxy_.get()); | 545 CHECK(io_message_loop_proxy_.get()); |
314 io_message_loop_proxy_->PostTask( | 546 io_message_loop_proxy_->PostTask( |
315 FROM_HERE, | 547 FROM_HERE, |
316 NewRunnableMethod(this, &Core::CompleteAddingUploadDataChunk, content, | 548 NewRunnableMethod(this, &Core::CompleteAddingUploadDataChunk, content, |
317 is_last_chunk)); | 549 is_last_chunk)); |
318 } | 550 } |
319 | 551 |
| 552 // Return true if the write was done and reading may continue. |
| 553 // Return false if the write is pending, and the next read will |
| 554 // be done later. |
| 555 bool URLFetcher::Core::WriteBuffer(int num_bytes) { |
| 556 bool write_complete = false; |
| 557 switch (fetcher_->response_destination_) { |
| 558 case STRING: |
| 559 data_.append(buffer_->data(), num_bytes); |
| 560 write_complete = true; |
| 561 break; |
| 562 |
| 563 case TEMP_FILE: |
| 564 temp_file_writer_->WriteBuffer(num_bytes); |
| 565 // WriteBuffer() sends a request the file thread. |
| 566 // The write is not done yet. |
| 567 write_complete = false; |
| 568 break; |
| 569 |
| 570 default: |
| 571 NOTREACHED(); |
| 572 } |
| 573 return write_complete; |
| 574 } |
| 575 |
320 void URLFetcher::Core::OnReadCompleted(net::URLRequest* request, | 576 void URLFetcher::Core::OnReadCompleted(net::URLRequest* request, |
321 int bytes_read) { | 577 int bytes_read) { |
322 DCHECK(request == request_); | 578 DCHECK(request == request_); |
323 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 579 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
324 | 580 |
325 url_ = request->url(); | 581 url_ = request->url(); |
326 url_throttler_entry_ = | 582 url_throttler_entry_ = |
327 net::URLRequestThrottlerManager::GetInstance()->RegisterRequestUrl(url_); | 583 net::URLRequestThrottlerManager::GetInstance()->RegisterRequestUrl(url_); |
328 | 584 |
| 585 bool waiting_on_write = false; |
329 do { | 586 do { |
330 if (!request_->status().is_success() || bytes_read <= 0) | 587 if (!request_->status().is_success() || bytes_read <= 0) |
331 break; | 588 break; |
332 data_.append(buffer_->data(), bytes_read); | 589 |
| 590 if (!WriteBuffer(bytes_read)) { |
| 591 // If WriteBuffer() returns false, we have a pending write to |
| 592 // wait on before reading further. |
| 593 waiting_on_write = true; |
| 594 break; |
| 595 } |
333 } while (request_->Read(buffer_, kBufferSize, &bytes_read)); | 596 } while (request_->Read(buffer_, kBufferSize, &bytes_read)); |
334 | 597 |
335 if (request_->status().is_success()) | 598 if (request_->status().is_success()) |
336 request_->GetResponseCookies(&cookies_); | 599 request_->GetResponseCookies(&cookies_); |
337 | 600 |
338 // See comments re: HEAD requests in OnResponseStarted(). | 601 // See comments re: HEAD requests in ReadResponse(). |
339 if (!request_->status().is_io_pending() || (request_type_ == HEAD)) { | 602 if ((!request_->status().is_io_pending() && !waiting_on_write) || |
| 603 (request_type_ == HEAD)) { |
340 backoff_release_time_ = GetBackoffReleaseTime(); | 604 backoff_release_time_ = GetBackoffReleaseTime(); |
341 | 605 |
342 bool posted = delegate_loop_proxy_->PostTask( | 606 bool posted = delegate_loop_proxy_->PostTask( |
343 FROM_HERE, | 607 FROM_HERE, |
344 NewRunnableMethod(this, | 608 NewRunnableMethod(this, |
345 &Core::OnCompletedURLRequest, | 609 &Core::OnCompletedURLRequest, |
346 request_->status())); | 610 request_->status())); |
347 // If the delegate message loop does not exist any more, then the delegate | 611 // If the delegate message loop does not exist any more, then the delegate |
348 // should be gone too. | 612 // should be gone too. |
349 DCHECK(posted || !delegate_); | 613 DCHECK(posted || !delegate_); |
350 ReleaseRequest(); | 614 ReleaseRequest(); |
351 } | 615 } |
352 } | 616 } |
353 | 617 |
| 618 void URLFetcher::Core::ReadResponse() { |
| 619 // Some servers may treat HEAD requests as GET requests. To free up the |
| 620 // network connection as soon as possible, signal that the request has |
| 621 // completed immediately, without trying to read any data back (all we care |
| 622 // about is the response code and headers, which we already have). |
| 623 int bytes_read = 0; |
| 624 if (request_->status().is_success() && (request_type_ != HEAD)) |
| 625 request_->Read(buffer_, kBufferSize, &bytes_read); |
| 626 OnReadCompleted(request_.get(), bytes_read); |
| 627 } |
| 628 |
354 void URLFetcher::Core::StartURLRequest() { | 629 void URLFetcher::Core::StartURLRequest() { |
355 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 630 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
356 | 631 |
357 if (was_cancelled_) { | 632 if (was_cancelled_) { |
358 // Since StartURLRequest() is posted as a *delayed* task, it may | 633 // Since StartURLRequest() is posted as a *delayed* task, it may |
359 // run after the URLFetcher was already stopped. | 634 // run after the URLFetcher was already stopped. |
360 return; | 635 return; |
361 } | 636 } |
362 | 637 |
363 CHECK(request_context_getter_); | 638 CHECK(request_context_getter_); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
399 default: | 674 default: |
400 NOTREACHED(); | 675 NOTREACHED(); |
401 } | 676 } |
402 | 677 |
403 if (!extra_request_headers_.IsEmpty()) | 678 if (!extra_request_headers_.IsEmpty()) |
404 request_->SetExtraRequestHeaders(extra_request_headers_); | 679 request_->SetExtraRequestHeaders(extra_request_headers_); |
405 | 680 |
406 // There might be data left over from a previous request attempt. | 681 // There might be data left over from a previous request attempt. |
407 data_.clear(); | 682 data_.clear(); |
408 | 683 |
| 684 // If we are writing the response to a file, the only caller |
| 685 // of this function should have created it and not written yet. |
| 686 CHECK(!temp_file_writer_.get() || |
| 687 temp_file_writer_->total_bytes_written() == 0); |
| 688 |
409 request_->Start(); | 689 request_->Start(); |
410 } | 690 } |
411 | 691 |
412 void URLFetcher::Core::StartURLRequestWhenAppropriate() { | 692 void URLFetcher::Core::StartURLRequestWhenAppropriate() { |
413 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 693 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
414 | 694 |
415 if (was_cancelled_) | 695 if (was_cancelled_) |
416 return; | 696 return; |
417 | 697 |
418 if (original_url_throttler_entry_ == NULL) { | 698 if (original_url_throttler_entry_ == NULL) { |
(...skipping 20 matching lines...) Expand all Loading... |
439 if (request_.get()) { | 719 if (request_.get()) { |
440 request_->Cancel(); | 720 request_->Cancel(); |
441 ReleaseRequest(); | 721 ReleaseRequest(); |
442 } | 722 } |
443 // Release the reference to the request context. There could be multiple | 723 // 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 | 724 // 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 | 725 // delete the object, but we cannot delay the destruction of the request |
446 // context. | 726 // context. |
447 request_context_getter_ = NULL; | 727 request_context_getter_ = NULL; |
448 was_cancelled_ = true; | 728 was_cancelled_ = true; |
| 729 temp_file_writer_.reset(); |
449 } | 730 } |
450 | 731 |
451 void URLFetcher::Core::OnCompletedURLRequest( | 732 void URLFetcher::Core::OnCompletedURLRequest( |
452 const net::URLRequestStatus& status) { | 733 const net::URLRequestStatus& status) { |
453 DCHECK(delegate_loop_proxy_->BelongsToCurrentThread()); | 734 DCHECK(delegate_loop_proxy_->BelongsToCurrentThread()); |
454 | 735 |
| 736 // Save the status so that delegates can read it. |
| 737 status_ = status; |
| 738 |
455 // Checks the response from server. | 739 // Checks the response from server. |
456 if (response_code_ >= 500 || | 740 if (response_code_ >= 500 || |
457 status.os_error() == net::ERR_TEMPORARILY_THROTTLED) { | 741 status.os_error() == net::ERR_TEMPORARILY_THROTTLED) { |
458 // When encountering a server error, we will send the request again | 742 // When encountering a server error, we will send the request again |
459 // after backoff time. | 743 // after backoff time. |
460 ++num_retries_; | 744 ++num_retries_; |
461 // Restarts the request if we still need to notify the delegate. | 745 // Restarts the request if we still need to notify the delegate. |
462 if (delegate_) { | 746 if (delegate_) { |
463 fetcher_->backoff_delay_ = backoff_release_time_ - base::TimeTicks::Now(); | 747 fetcher_->backoff_delay_ = backoff_release_time_ - base::TimeTicks::Now(); |
464 if (fetcher_->backoff_delay_ < base::TimeDelta()) | 748 if (fetcher_->backoff_delay_ < base::TimeDelta()) |
465 fetcher_->backoff_delay_ = base::TimeDelta(); | 749 fetcher_->backoff_delay_ = base::TimeDelta(); |
466 | 750 |
467 if (fetcher_->automatically_retry_on_5xx_ && | 751 if (fetcher_->automatically_retry_on_5xx_ && |
468 num_retries_ <= fetcher_->max_retries()) { | 752 num_retries_ <= fetcher_->max_retries()) { |
469 io_message_loop_proxy_->PostTask( | 753 io_message_loop_proxy_->PostTask( |
470 FROM_HERE, | 754 FROM_HERE, |
471 NewRunnableMethod(this, &Core::StartURLRequestWhenAppropriate)); | 755 NewRunnableMethod(this, &Core::StartURLRequestWhenAppropriate)); |
472 } else { | 756 } else { |
473 delegate_->OnURLFetchComplete(fetcher_, url_, status, response_code_, | 757 InformDelegateFetchIsComplete(); |
474 cookies_, data_); | |
475 } | 758 } |
476 } | 759 } |
477 } else { | 760 } else { |
478 if (delegate_) { | 761 if (delegate_) { |
479 fetcher_->backoff_delay_ = base::TimeDelta(); | 762 fetcher_->backoff_delay_ = base::TimeDelta(); |
480 delegate_->OnURLFetchComplete(fetcher_, url_, status, response_code_, | 763 InformDelegateFetchIsComplete(); |
481 cookies_, data_); | |
482 } | 764 } |
483 } | 765 } |
484 } | 766 } |
485 | 767 |
| 768 void URLFetcher::Core::InformDelegateFetchIsComplete() { |
| 769 delegate_->OnURLFetchComplete(fetcher_); |
| 770 } |
| 771 |
486 void URLFetcher::Core::NotifyMalformedContent() { | 772 void URLFetcher::Core::NotifyMalformedContent() { |
487 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 773 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
488 if (url_throttler_entry_ != NULL) | 774 if (url_throttler_entry_ != NULL) |
489 url_throttler_entry_->ReceivedContentWasMalformed(); | 775 url_throttler_entry_->ReceivedContentWasMalformed(); |
490 } | 776 } |
491 | 777 |
492 void URLFetcher::Core::ReleaseRequest() { | 778 void URLFetcher::Core::ReleaseRequest() { |
493 request_.reset(); | 779 request_.reset(); |
494 g_registry.Get().RemoveURLFetcherCore(this); | 780 g_registry.Get().RemoveURLFetcherCore(this); |
495 } | 781 } |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
553 const std::string& extra_request_headers) { | 839 const std::string& extra_request_headers) { |
554 core_->extra_request_headers_.Clear(); | 840 core_->extra_request_headers_.Clear(); |
555 core_->extra_request_headers_.AddHeadersFromString(extra_request_headers); | 841 core_->extra_request_headers_.AddHeadersFromString(extra_request_headers); |
556 } | 842 } |
557 | 843 |
558 void URLFetcher::set_request_context( | 844 void URLFetcher::set_request_context( |
559 net::URLRequestContextGetter* request_context_getter) { | 845 net::URLRequestContextGetter* request_context_getter) { |
560 core_->request_context_getter_ = request_context_getter; | 846 core_->request_context_getter_ = request_context_getter; |
561 } | 847 } |
562 | 848 |
| 849 void URLFetcher::set_file_message_loop_proxy( |
| 850 scoped_refptr<base::MessageLoopProxy> file_message_loop_proxy) { |
| 851 core_->file_message_loop_proxy_ = file_message_loop_proxy; |
| 852 } |
| 853 |
563 void URLFetcher::set_automatically_retry_on_5xx(bool retry) { | 854 void URLFetcher::set_automatically_retry_on_5xx(bool retry) { |
564 automatically_retry_on_5xx_ = retry; | 855 automatically_retry_on_5xx_ = retry; |
565 } | 856 } |
566 | 857 |
| 858 void URLFetcher::SaveResponseToTemporaryFile() { |
| 859 response_destination_ = TEMP_FILE; |
| 860 } |
| 861 |
567 net::HttpResponseHeaders* URLFetcher::response_headers() const { | 862 net::HttpResponseHeaders* URLFetcher::response_headers() const { |
568 return core_->response_headers_; | 863 return core_->response_headers_; |
569 } | 864 } |
570 | 865 |
571 // TODO(panayiotis): socket_address_ is written in the IO thread, | 866 // 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. | 867 // 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. | 868 // Same for response_headers_ above and was_fetched_via_proxy_ below. |
574 net::HostPortPair URLFetcher::socket_address() const { | 869 net::HostPortPair URLFetcher::socket_address() const { |
575 return core_->socket_address_; | 870 return core_->socket_address_; |
576 } | 871 } |
577 | 872 |
578 bool URLFetcher::was_fetched_via_proxy() const { | 873 bool URLFetcher::was_fetched_via_proxy() const { |
579 return core_->was_fetched_via_proxy_; | 874 return core_->was_fetched_via_proxy_; |
580 } | 875 } |
581 | 876 |
582 void URLFetcher::Start() { | 877 void URLFetcher::Start() { |
583 core_->Start(); | 878 core_->Start(); |
584 } | 879 } |
585 | 880 |
586 const GURL& URLFetcher::url() const { | 881 const GURL& URLFetcher::url() const { |
587 return core_->url_; | 882 return core_->url_; |
588 } | 883 } |
589 | 884 |
| 885 const net::URLRequestStatus& URLFetcher::status() const { |
| 886 return core_->status_; |
| 887 } |
| 888 |
| 889 int URLFetcher::response_code() const { |
| 890 return core_->response_code_; |
| 891 } |
| 892 |
| 893 const net::ResponseCookies& URLFetcher::cookies() const { |
| 894 return core_->cookies_; |
| 895 } |
| 896 |
| 897 bool URLFetcher::FileErrorOccurred( |
| 898 base::PlatformFileError* out_error_code) const { |
| 899 |
| 900 // Can't have a file error if no file is being created or written to. |
| 901 if (!core_->temp_file_writer_.get()) { |
| 902 return false; |
| 903 } |
| 904 |
| 905 base::PlatformFileError error_code = core_->temp_file_writer_->error_code(); |
| 906 if (error_code == base::PLATFORM_FILE_OK) |
| 907 return false; |
| 908 |
| 909 *out_error_code = error_code; |
| 910 return true; |
| 911 } |
| 912 |
590 void URLFetcher::ReceivedContentWasMalformed() { | 913 void URLFetcher::ReceivedContentWasMalformed() { |
591 core_->ReceivedContentWasMalformed(); | 914 core_->ReceivedContentWasMalformed(); |
592 } | 915 } |
593 | 916 |
| 917 bool URLFetcher::GetResponseAsString(std::string* out_response_string) const { |
| 918 if (response_destination_ != STRING) |
| 919 return false; |
| 920 |
| 921 *out_response_string = core_->data_; |
| 922 return true; |
| 923 } |
| 924 |
| 925 bool URLFetcher::GetResponseAsFilePath(bool take_ownership, |
| 926 FilePath* out_response_path) const { |
| 927 if (response_destination_ != TEMP_FILE || !core_->temp_file_writer_.get()) |
| 928 return false; |
| 929 |
| 930 *out_response_path = core_->temp_file_writer_->temp_file(); |
| 931 |
| 932 if (take_ownership) |
| 933 core_->temp_file_writer_->DisownTempFile(); |
| 934 |
| 935 return true; |
| 936 } |
| 937 |
594 // static | 938 // static |
595 void URLFetcher::CancelAll() { | 939 void URLFetcher::CancelAll() { |
596 Core::CancelAll(); | 940 Core::CancelAll(); |
597 } | 941 } |
598 | 942 |
599 // static | 943 // static |
600 int URLFetcher::GetNumFetcherCores() { | 944 int URLFetcher::GetNumFetcherCores() { |
601 return Core::g_registry.Get().size(); | 945 return Core::g_registry.Get().size(); |
602 } | 946 } |
603 | 947 |
604 URLFetcher::Delegate* URLFetcher::delegate() const { | 948 URLFetcher::Delegate* URLFetcher::delegate() const { |
605 return core_->delegate(); | 949 return core_->delegate(); |
606 } | 950 } |
OLD | NEW |