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