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

Side by Side Diff: webkit/blob/blob_url_request_job.cc

Issue 6612051: In BlobURLRequestJob, open files asynchronously to avoid blocking the IO thread (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Store bytes_to_read_ in a member variable Created 9 years, 9 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 | « webkit/blob/blob_url_request_job.h ('k') | webkit/blob/blob_url_request_job_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 "webkit/blob/blob_url_request_job.h" 5 #include "webkit/blob/blob_url_request_job.h"
6 6
7 #include "base/compiler_specific.h" 7 #include "base/compiler_specific.h"
8 #include "base/file_path.h" 8 #include "base/file_path.h"
9 #include "base/file_util.h" 9 #include "base/file_util.h"
10 #include "base/file_util_proxy.h" 10 #include "base/file_util_proxy.h"
11 #include "base/message_loop.h" 11 #include "base/message_loop.h"
12 #include "base/message_loop_proxy.h" 12 #include "base/message_loop_proxy.h"
13 #include "base/string_number_conversions.h" 13 #include "base/string_number_conversions.h"
14 #include "net/base/file_stream.h"
14 #include "net/base/io_buffer.h" 15 #include "net/base/io_buffer.h"
15 #include "net/base/net_errors.h" 16 #include "net/base/net_errors.h"
16 #include "net/http/http_request_headers.h" 17 #include "net/http/http_request_headers.h"
17 #include "net/http/http_response_headers.h" 18 #include "net/http/http_response_headers.h"
18 #include "net/http/http_response_info.h" 19 #include "net/http/http_response_info.h"
19 #include "net/http/http_util.h" 20 #include "net/http/http_util.h"
20 #include "net/url_request/url_request.h" 21 #include "net/url_request/url_request.h"
21 #include "net/url_request/url_request_error_job.h" 22 #include "net/url_request/url_request_error_job.h"
22 #include "net/url_request/url_request_status.h" 23 #include "net/url_request/url_request_status.h"
23 24
24 namespace webkit_blob { 25 namespace webkit_blob {
25 26
26 static const int kHTTPOk = 200; 27 static const int kHTTPOk = 200;
27 static const int kHTTPPartialContent = 206; 28 static const int kHTTPPartialContent = 206;
28 static const int kHTTPNotAllowed = 403; 29 static const int kHTTPNotAllowed = 403;
29 static const int kHTTPNotFound = 404; 30 static const int kHTTPNotFound = 404;
30 static const int kHTTPMethodNotAllow = 405; 31 static const int kHTTPMethodNotAllow = 405;
31 static const int kHTTPRequestedRangeNotSatisfiable = 416; 32 static const int kHTTPRequestedRangeNotSatisfiable = 416;
32 static const int kHTTPInternalError = 500; 33 static const int kHTTPInternalError = 500;
33 34
34 static const char kHTTPOKText[] = "OK"; 35 static const char kHTTPOKText[] = "OK";
35 static const char kHTTPPartialContentText[] = "Partial Content"; 36 static const char kHTTPPartialContentText[] = "Partial Content";
36 static const char kHTTPNotAllowedText[] = "Not Allowed"; 37 static const char kHTTPNotAllowedText[] = "Not Allowed";
37 static const char kHTTPNotFoundText[] = "Not Found"; 38 static const char kHTTPNotFoundText[] = "Not Found";
38 static const char kHTTPMethodNotAllowText[] = "Method Not Allowed"; 39 static const char kHTTPMethodNotAllowText[] = "Method Not Allowed";
39 static const char kHTTPRequestedRangeNotSatisfiableText[] = 40 static const char kHTTPRequestedRangeNotSatisfiableText[] =
40 "Requested Range Not Satisfiable"; 41 "Requested Range Not Satisfiable";
41 static const char kHTTPInternalErrorText[] = "Internal Server Error"; 42 static const char kHTTPInternalErrorText[] = "Internal Server Error";
42 43
44 static const int kFileOpenFlags = base::PLATFORM_FILE_OPEN |
45 base::PLATFORM_FILE_READ |
46 base::PLATFORM_FILE_ASYNC;
47
43 BlobURLRequestJob::BlobURLRequestJob( 48 BlobURLRequestJob::BlobURLRequestJob(
44 net::URLRequest* request, 49 net::URLRequest* request,
45 BlobData* blob_data, 50 BlobData* blob_data,
46 base::MessageLoopProxy* file_thread_proxy) 51 base::MessageLoopProxy* file_thread_proxy)
47 : net::URLRequestJob(request), 52 : net::URLRequestJob(request),
48 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), 53 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
49 blob_data_(blob_data), 54 blob_data_(blob_data),
50 file_thread_proxy_(file_thread_proxy), 55 file_thread_proxy_(file_thread_proxy),
51 ALLOW_THIS_IN_INITIALIZER_LIST( 56 ALLOW_THIS_IN_INITIALIZER_LIST(
52 io_callback_(this, &BlobURLRequestJob::DidRead)), 57 io_callback_(this, &BlobURLRequestJob::DidRead)),
53 item_index_(0), 58 item_index_(0),
54 total_size_(0), 59 total_size_(0),
55 current_item_offset_(0), 60 current_item_offset_(0),
56 remaining_bytes_(0), 61 remaining_bytes_(0),
57 read_buf_offset_(0), 62 read_buf_offset_(0),
58 read_buf_size_(0), 63 read_buf_size_(0),
59 read_buf_remaining_bytes_(0), 64 read_buf_remaining_bytes_(0),
65 bytes_to_read_(0),
60 error_(false), 66 error_(false),
61 headers_set_(false), 67 headers_set_(false),
62 byte_range_set_(false), 68 byte_range_set_(false),
63 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { 69 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
64 } 70 }
65 71
66 BlobURLRequestJob::~BlobURLRequestJob() { 72 BlobURLRequestJob::~BlobURLRequestJob() {
73 // FileStream's destructor won't close it for us because we passed in our own
74 // file handle.
75 CloseStream();
67 } 76 }
68 77
69 void BlobURLRequestJob::Start() { 78 void BlobURLRequestJob::Start() {
70 // Continue asynchronously. 79 // Continue asynchronously.
71 MessageLoop::current()->PostTask( 80 MessageLoop::current()->PostTask(
72 FROM_HERE, 81 FROM_HERE,
73 method_factory_.NewRunnableMethod(&BlobURLRequestJob::DidStart)); 82 method_factory_.NewRunnableMethod(&BlobURLRequestJob::DidStart));
74 } 83 }
75 84
76 void BlobURLRequestJob::DidStart() { 85 void BlobURLRequestJob::DidStart() {
77 // We only support GET request per the spec. 86 // We only support GET request per the spec.
78 if (request()->method() != "GET") { 87 if (request()->method() != "GET") {
79 NotifyFailure(net::ERR_METHOD_NOT_SUPPORTED); 88 NotifyFailure(net::ERR_METHOD_NOT_SUPPORTED);
80 return; 89 return;
81 } 90 }
82 91
83 // If the blob data is not present, bail out. 92 // If the blob data is not present, bail out.
84 if (!blob_data_) { 93 if (!blob_data_) {
85 NotifyFailure(net::ERR_FILE_NOT_FOUND); 94 NotifyFailure(net::ERR_FILE_NOT_FOUND);
86 return; 95 return;
87 } 96 }
88 97
89 CountSize(); 98 CountSize();
90 } 99 }
91 100
101 void BlobURLRequestJob::CloseStream() {
102 if (stream_ != NULL) {
103 stream_->Close();
104 stream_.reset(NULL);
105 }
106 }
107
92 void BlobURLRequestJob::Kill() { 108 void BlobURLRequestJob::Kill() {
93 stream_.Close(); 109 CloseStream();
94 110
95 net::URLRequestJob::Kill(); 111 net::URLRequestJob::Kill();
96 callback_factory_.RevokeAll(); 112 callback_factory_.RevokeAll();
97 method_factory_.RevokeAll(); 113 method_factory_.RevokeAll();
98 } 114 }
99 115
100 void BlobURLRequestJob::ResolveFile(const FilePath& file_path) { 116 void BlobURLRequestJob::ResolveFile(const FilePath& file_path) {
michaeln 2011/03/11 06:03:47 nit: maybe DCHECK(file_thread_proxy_)
adamk 2011/03/14 17:42:14 Added that DCHECK to the constructor (that'll make
101 // If the file thread proxy is provided, we can use it get the file info. 117 base::FileUtilProxy::GetFileInfo(
102 if (file_thread_proxy_) { 118 file_thread_proxy_,
103 base::FileUtilProxy::GetFileInfo( 119 file_path,
104 file_thread_proxy_, 120 callback_factory_.NewCallback(&BlobURLRequestJob::DidResolve));
105 file_path,
106 callback_factory_.NewCallback(&BlobURLRequestJob::DidResolve));
107 return;
108 }
109
110 // Otherwise, we use current thread, i.e. IO thread, as this is the case when
111 // we run the unittest or test shell.
112 // TODO(jianli): Consider using the proxy of current thread.
113 base::PlatformFileInfo file_info;
114 bool exists = file_util::GetFileInfo(file_path, &file_info);
115
116 // Continue asynchronously.
117 MessageLoop::current()->PostTask(
118 FROM_HERE,
119 method_factory_.NewRunnableMethod(
120 &BlobURLRequestJob::DidResolve,
121 exists ? base::PLATFORM_FILE_OK : base::PLATFORM_FILE_ERROR_NOT_FOUND,
122 file_info));
123 } 121 }
124 122
125 void BlobURLRequestJob::DidResolve(base::PlatformFileError rv, 123 void BlobURLRequestJob::DidResolve(base::PlatformFileError rv,
126 const base::PlatformFileInfo& file_info) { 124 const base::PlatformFileInfo& file_info) {
127 // If an error occured, bail out. 125 // If an error occured, bail out.
128 if (rv == base::PLATFORM_FILE_ERROR_NOT_FOUND) { 126 if (rv == base::PLATFORM_FILE_ERROR_NOT_FOUND) {
129 NotifyFailure(net::ERR_FILE_NOT_FOUND); 127 NotifyFailure(net::ERR_FILE_NOT_FOUND);
130 return; 128 return;
131 } else if (rv != base::PLATFORM_FILE_OK) { 129 } else if (rv != base::PLATFORM_FILE_OK) {
132 NotifyFailure(net::ERR_FAILED); 130 NotifyFailure(net::ERR_FAILED);
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
247 // Read until we encounter an error or could not get the data immediately. 245 // Read until we encounter an error or could not get the data immediately.
248 while (remaining_bytes_ > 0 && read_buf_remaining_bytes_ > 0) { 246 while (remaining_bytes_ > 0 && read_buf_remaining_bytes_ > 0) {
249 if (!ReadItem()) 247 if (!ReadItem())
250 return false; 248 return false;
251 } 249 }
252 250
253 *bytes_read = ReadCompleted(); 251 *bytes_read = ReadCompleted();
254 return true; 252 return true;
255 } 253 }
256 254
255 int BlobURLRequestJob::ComputeBytesToRead() const {
256 int64 current_item_remaining_bytes =
257 item_length_list_[item_index_] - current_item_offset_;
258 int bytes_to_read = (read_buf_remaining_bytes_ > current_item_remaining_bytes)
259 ? static_cast<int>(current_item_remaining_bytes)
260 : read_buf_remaining_bytes_;
261 if (bytes_to_read > remaining_bytes_)
262 bytes_to_read = static_cast<int>(remaining_bytes_);
263 return bytes_to_read;
264 }
265
257 bool BlobURLRequestJob::ReadItem() { 266 bool BlobURLRequestJob::ReadItem() {
258 // Are we done with reading all the blob data? 267 // Are we done with reading all the blob data?
259 if (remaining_bytes_ == 0) 268 if (remaining_bytes_ == 0)
260 return true; 269 return true;
261 270
262 // If we get to the last item but still expect something to read, bail out 271 // If we get to the last item but still expect something to read, bail out
263 // since something is wrong. 272 // since something is wrong.
264 if (item_index_ >= blob_data_->items().size()) { 273 if (item_index_ >= blob_data_->items().size()) {
265 NotifyFailure(net::ERR_FAILED); 274 NotifyFailure(net::ERR_FAILED);
266 return false; 275 return false;
267 } 276 }
268 277
269 const BlobData::Item& item = blob_data_->items().at(item_index_);
270
271 // Compute the bytes to read for current item. 278 // Compute the bytes to read for current item.
272 int64 current_item_remaining_bytes = 279 bytes_to_read_ = ComputeBytesToRead();
273 item_length_list_[item_index_] - current_item_offset_;
274 int bytes_to_read = (read_buf_remaining_bytes_ > current_item_remaining_bytes)
275 ? static_cast<int>(current_item_remaining_bytes)
276 : read_buf_remaining_bytes_;
277 if (bytes_to_read > remaining_bytes_)
278 bytes_to_read = static_cast<int>(remaining_bytes_);
279 280
280 // If nothing to read for current item, advance to next item. 281 // If nothing to read for current item, advance to next item.
281 if (bytes_to_read == 0) { 282 if (bytes_to_read_ == 0) {
282 AdvanceItem(); 283 AdvanceItem();
283 return ReadItem(); 284 return ReadItem();
284 } 285 }
285 286
286 // Do the reading. 287 // Do the reading.
288 const BlobData::Item& item = blob_data_->items().at(item_index_);
287 switch (item.type()) { 289 switch (item.type()) {
288 case BlobData::TYPE_DATA: 290 case BlobData::TYPE_DATA:
289 return ReadBytes(item, bytes_to_read); 291 return ReadBytes(item);
290 case BlobData::TYPE_FILE: 292 case BlobData::TYPE_FILE:
291 return ReadFile(item, bytes_to_read); 293 return DispatchReadFile(item);
292 default: 294 default:
293 DCHECK(false); 295 DCHECK(false);
294 return false; 296 return false;
295 } 297 }
296 } 298 }
297 299
298 bool BlobURLRequestJob::ReadBytes(const BlobData::Item& item, 300 bool BlobURLRequestJob::ReadBytes(const BlobData::Item& item) {
299 int bytes_to_read) { 301 DCHECK(read_buf_remaining_bytes_ >= bytes_to_read_);
300 DCHECK(read_buf_remaining_bytes_ >= bytes_to_read);
301 302
302 memcpy(read_buf_->data() + read_buf_offset_, 303 memcpy(read_buf_->data() + read_buf_offset_,
303 &item.data().at(0) + item.offset() + current_item_offset_, 304 &item.data().at(0) + item.offset() + current_item_offset_,
304 bytes_to_read); 305 bytes_to_read_);
305 306
306 AdvanceBytesRead(bytes_to_read); 307 AdvanceBytesRead(bytes_to_read_);
307 return true; 308 return true;
308 } 309 }
309 310
310 bool BlobURLRequestJob::ReadFile(const BlobData::Item& item, 311 bool BlobURLRequestJob::DispatchReadFile(const BlobData::Item& item) {
311 int bytes_to_read) { 312 // If the stream already exists, keep reading from it.
312 DCHECK(read_buf_remaining_bytes_ >= bytes_to_read); 313 if (stream_ != NULL)
314 return ReadFile(item);
313 315
314 // Open the file if not yet. 316 base::FileUtilProxy::CreateOrOpen(
315 if (!stream_.IsOpen()) { 317 file_thread_proxy_, item.file_path(), kFileOpenFlags,
316 int rv = stream_.Open(item.file_path(), base::PLATFORM_FILE_OPEN | 318 callback_factory_.NewCallback(&BlobURLRequestJob::DidOpen));
317 base::PLATFORM_FILE_READ | base::PLATFORM_FILE_ASYNC); 319 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
318 if (rv != net::OK) { 320 return false;
319 NotifyFailure(net::ERR_FAILED); 321 }
320 return false;
321 }
322 322
323 // Seek the file if needed. 323 void BlobURLRequestJob::DidOpen(base::PlatformFileError rv,
324 int64 offset = current_item_offset_ + static_cast<int64>(item.offset()); 324 base::PassPlatformFile file,
325 if (offset > 0) { 325 bool created) {
326 if (offset != stream_.Seek(net::FROM_BEGIN, offset)) { 326 if (rv != base::PLATFORM_FILE_OK) {
327 NotifyFailure(net::ERR_FAILED); 327 NotifyFailure(net::ERR_FAILED);
328 return false; 328 return;
329 }
330 }
331 } 329 }
332 330
331 DCHECK(!stream_.get());
332 stream_.reset(new net::FileStream(file.ReleaseValue(), kFileOpenFlags));
333
334 // Seek the file if needed.
335 const BlobData::Item& item = blob_data_->items().at(item_index_);
336 int64 offset = current_item_offset_ + static_cast<int64>(item.offset());
337 if (offset > 0 && offset != stream_->Seek(net::FROM_BEGIN, offset)) {
338 NotifyFailure(net::ERR_FAILED);
339 return;
340 }
341
342 ReadFile(item);
343 }
344
345 bool BlobURLRequestJob::ReadFile(const BlobData::Item& item) {
346 DCHECK(stream_.get());
347 DCHECK(stream_->IsOpen());
348 DCHECK(read_buf_remaining_bytes_ >= bytes_to_read_);
349
333 // Start the asynchronous reading. 350 // Start the asynchronous reading.
334 int rv = stream_.Read(read_buf_->data() + read_buf_offset_, 351 int rv = stream_->Read(read_buf_->data() + read_buf_offset_,
335 bytes_to_read, 352 bytes_to_read_,
336 &io_callback_); 353 &io_callback_);
337 354
338 // If I/O pending error is returned, we just need to wait. 355 // If I/O pending error is returned, we just need to wait.
339 if (rv == net::ERR_IO_PENDING) { 356 if (rv == net::ERR_IO_PENDING) {
340 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); 357 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
341 return false; 358 return false;
342 } 359 }
343 360
344 // For all other errors, bail out. 361 // For all other errors, bail out.
345 if (rv < 0) { 362 if (rv < 0) {
346 NotifyFailure(net::ERR_FAILED); 363 NotifyFailure(net::ERR_FAILED);
347 return false; 364 return false;
348 } 365 }
349 366
350 // Otherwise, data is immediately available. 367 // Otherwise, data is immediately available.
351 AdvanceBytesRead(rv); 368 if (GetStatus().is_io_pending())
369 DidRead(rv);
michaeln 2011/03/11 06:03:47 ah... is this what your new large test is about...
adamk 2011/03/14 17:42:14 Added something to the CL description. There wasn
370 else
371 AdvanceBytesRead(rv);
372
352 return true; 373 return true;
353 } 374 }
354 375
355 void BlobURLRequestJob::DidRead(int result) { 376 void BlobURLRequestJob::DidRead(int result) {
356 if (result < 0) { 377 if (result < 0) {
357 NotifyFailure(net::ERR_FAILED); 378 NotifyFailure(net::ERR_FAILED);
358 return; 379 return;
359 } 380 }
360 SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status 381 SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status
361 382
362 AdvanceBytesRead(result); 383 AdvanceBytesRead(result);
363 384
364 // If the read buffer is completely filled, we're done. 385 // If the read buffer is completely filled, we're done.
365 if (!read_buf_remaining_bytes_) { 386 if (!read_buf_remaining_bytes_) {
366 int bytes_read = ReadCompleted(); 387 int bytes_read = ReadCompleted();
367 NotifyReadComplete(bytes_read); 388 NotifyReadComplete(bytes_read);
368 return; 389 return;
369 } 390 }
370 391
371 // Otherwise, continue the reading. 392 // Otherwise, continue the reading.
372 int bytes_read = 0; 393 int bytes_read = 0;
373 if (ReadLoop(&bytes_read)) 394 if (ReadLoop(&bytes_read))
374 NotifyReadComplete(bytes_read); 395 NotifyReadComplete(bytes_read);
375 } 396 }
376 397
377 void BlobURLRequestJob::AdvanceItem() { 398 void BlobURLRequestJob::AdvanceItem() {
378 // Close the stream if the current item is a file. 399 // Close the stream if the current item is a file.
379 if (stream_.IsOpen()) 400 CloseStream();
380 stream_.Close();
381 401
382 // Advance to the next item. 402 // Advance to the next item.
383 item_index_++; 403 item_index_++;
384 current_item_offset_ = 0; 404 current_item_offset_ = 0;
385 } 405 }
386 406
387 void BlobURLRequestJob::AdvanceBytesRead(int result) { 407 void BlobURLRequestJob::AdvanceBytesRead(int result) {
388 DCHECK_GT(result, 0); 408 DCHECK_GT(result, 0);
389 409
390 // Do we finish reading the current item? 410 // Do we finish reading the current item?
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
536 // We don't support multiple range requests in one single URL request, 556 // We don't support multiple range requests in one single URL request,
537 // because we need to do multipart encoding here. 557 // because we need to do multipart encoding here.
538 // TODO(jianli): Support multipart byte range requests. 558 // TODO(jianli): Support multipart byte range requests.
539 NotifyFailure(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE); 559 NotifyFailure(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE);
540 } 560 }
541 } 561 }
542 } 562 }
543 } 563 }
544 564
545 } // namespace webkit_blob 565 } // namespace webkit_blob
OLDNEW
« no previous file with comments | « webkit/blob/blob_url_request_job.h ('k') | webkit/blob/blob_url_request_job_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698