| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/fileapi/file_system_url_request_job.h" | 5 #include "webkit/fileapi/file_system_url_request_job.h" |
| 6 | 6 |
| 7 #include <vector> | |
| 8 | |
| 9 #include "base/bind.h" | 7 #include "base/bind.h" |
| 10 #include "base/compiler_specific.h" | 8 #include "base/compiler_specific.h" |
| 11 #include "base/file_path.h" | 9 #include "base/file_path.h" |
| 12 #include "base/file_util_proxy.h" | 10 #include "base/file_util_proxy.h" |
| 13 #include "base/message_loop.h" | 11 #include "base/message_loop.h" |
| 14 #include "base/platform_file.h" | 12 #include "base/platform_file.h" |
| 15 #include "base/threading/thread_restrictions.h" | 13 #include "base/threading/thread_restrictions.h" |
| 14 #include "base/time.h" |
| 16 #include "build/build_config.h" | 15 #include "build/build_config.h" |
| 17 #include "googleurl/src/gurl.h" | 16 #include "googleurl/src/gurl.h" |
| 18 #include "net/base/file_stream.h" | 17 #include "net/base/file_stream.h" |
| 19 #include "net/base/io_buffer.h" | 18 #include "net/base/io_buffer.h" |
| 20 #include "net/base/mime_util.h" | 19 #include "net/base/mime_util.h" |
| 21 #include "net/base/net_errors.h" | 20 #include "net/base/net_errors.h" |
| 22 #include "net/base/net_util.h" | 21 #include "net/base/net_util.h" |
| 23 #include "net/http/http_response_headers.h" | 22 #include "net/http/http_response_headers.h" |
| 24 #include "net/http/http_response_info.h" | 23 #include "net/http/http_response_info.h" |
| 25 #include "net/http/http_util.h" | 24 #include "net/http/http_util.h" |
| 26 #include "net/url_request/url_request.h" | 25 #include "net/url_request/url_request.h" |
| 26 #include "webkit/blob/local_file_reader.h" |
| 27 #include "webkit/blob/shareable_file_reference.h" | 27 #include "webkit/blob/shareable_file_reference.h" |
| 28 #include "webkit/fileapi/file_system_context.h" | 28 #include "webkit/fileapi/file_system_context.h" |
| 29 #include "webkit/fileapi/file_system_operation.h" | 29 #include "webkit/fileapi/file_system_operation.h" |
| 30 #include "webkit/fileapi/file_system_util.h" | 30 #include "webkit/fileapi/file_system_util.h" |
| 31 | 31 |
| 32 using net::URLRequest; | 32 using net::URLRequest; |
| 33 using net::URLRequestJob; | 33 using net::URLRequestJob; |
| 34 using net::URLRequestStatus; | 34 using net::URLRequestStatus; |
| 35 using webkit_blob::LocalFileReader; |
| 35 | 36 |
| 36 namespace fileapi { | 37 namespace fileapi { |
| 37 | 38 |
| 38 static const int kFileFlags = base::PLATFORM_FILE_OPEN | | |
| 39 base::PLATFORM_FILE_READ | | |
| 40 base::PLATFORM_FILE_ASYNC; | |
| 41 | |
| 42 static net::HttpResponseHeaders* CreateHttpResponseHeaders() { | 39 static net::HttpResponseHeaders* CreateHttpResponseHeaders() { |
| 43 // HttpResponseHeaders expects its input string to be terminated by two NULs. | 40 // HttpResponseHeaders expects its input string to be terminated by two NULs. |
| 44 static const char kStatus[] = "HTTP/1.1 200 OK\0"; | 41 static const char kStatus[] = "HTTP/1.1 200 OK\0"; |
| 45 static const size_t kStatusLen = arraysize(kStatus); | 42 static const size_t kStatusLen = arraysize(kStatus); |
| 46 | 43 |
| 47 net::HttpResponseHeaders* headers = | 44 net::HttpResponseHeaders* headers = |
| 48 new net::HttpResponseHeaders(std::string(kStatus, kStatusLen)); | 45 new net::HttpResponseHeaders(std::string(kStatus, kStatusLen)); |
| 49 | 46 |
| 50 // Tell WebKit never to cache this content. | 47 // Tell WebKit never to cache this content. |
| 51 std::string cache_control(net::HttpRequestHeaders::kCacheControl); | 48 std::string cache_control(net::HttpRequestHeaders::kCacheControl); |
| 52 cache_control.append(": no-cache"); | 49 cache_control.append(": no-cache"); |
| 53 headers->AddHeader(cache_control); | 50 headers->AddHeader(cache_control); |
| 54 | 51 |
| 55 return headers; | 52 return headers; |
| 56 } | 53 } |
| 57 | 54 |
| 58 FileSystemURLRequestJob::FileSystemURLRequestJob( | 55 FileSystemURLRequestJob::FileSystemURLRequestJob( |
| 59 URLRequest* request, FileSystemContext* file_system_context, | 56 URLRequest* request, FileSystemContext* file_system_context, |
| 60 scoped_refptr<base::MessageLoopProxy> file_thread_proxy) | 57 scoped_refptr<base::MessageLoopProxy> file_thread_proxy) |
| 61 : URLRequestJob(request), | 58 : URLRequestJob(request), |
| 62 file_system_context_(file_system_context), | 59 file_system_context_(file_system_context), |
| 63 file_thread_proxy_(file_thread_proxy), | 60 file_thread_proxy_(file_thread_proxy), |
| 64 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), | 61 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), |
| 65 stream_(NULL), | |
| 66 is_directory_(false), | 62 is_directory_(false), |
| 67 remaining_bytes_(0) { | 63 remaining_bytes_(0) { |
| 68 } | 64 } |
| 69 | 65 |
| 70 FileSystemURLRequestJob::~FileSystemURLRequestJob() { | 66 FileSystemURLRequestJob::~FileSystemURLRequestJob() {} |
| 71 // Since we use the two-arg constructor of FileStream, we need to call Close() | |
| 72 // manually: ~FileStream won't call it for us. | |
| 73 if (stream_ != NULL) { | |
| 74 // Close() performs file IO: crbug.com/113300. | |
| 75 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
| 76 stream_->CloseSync(); | |
| 77 } | |
| 78 } | |
| 79 | 67 |
| 80 void FileSystemURLRequestJob::Start() { | 68 void FileSystemURLRequestJob::Start() { |
| 81 MessageLoop::current()->PostTask( | 69 MessageLoop::current()->PostTask( |
| 82 FROM_HERE, | 70 FROM_HERE, |
| 83 base::Bind(&FileSystemURLRequestJob::StartAsync, | 71 base::Bind(&FileSystemURLRequestJob::StartAsync, |
| 84 weak_factory_.GetWeakPtr())); | 72 weak_factory_.GetWeakPtr())); |
| 85 } | 73 } |
| 86 | 74 |
| 87 void FileSystemURLRequestJob::Kill() { | 75 void FileSystemURLRequestJob::Kill() { |
| 88 if (stream_ != NULL) { | 76 if (reader_.get() != NULL) |
| 89 // Close() performs file IO: crbug.com/113300. | 77 reader_.reset(); |
| 90 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
| 91 stream_->CloseSync(); | |
| 92 stream_.reset(NULL); | |
| 93 } | |
| 94 URLRequestJob::Kill(); | 78 URLRequestJob::Kill(); |
| 95 weak_factory_.InvalidateWeakPtrs(); | 79 weak_factory_.InvalidateWeakPtrs(); |
| 96 } | 80 } |
| 97 | 81 |
| 98 bool FileSystemURLRequestJob::ReadRawData(net::IOBuffer* dest, int dest_size, | 82 bool FileSystemURLRequestJob::ReadRawData(net::IOBuffer* dest, int dest_size, |
| 99 int *bytes_read) { | 83 int *bytes_read) { |
| 100 DCHECK_NE(dest_size, 0); | 84 DCHECK_NE(dest_size, 0); |
| 101 DCHECK(bytes_read); | 85 DCHECK(bytes_read); |
| 102 DCHECK_GE(remaining_bytes_, 0); | 86 DCHECK_GE(remaining_bytes_, 0); |
| 103 | 87 |
| 104 if (stream_ == NULL) | 88 if (reader_.get() == NULL) |
| 105 return false; | 89 return false; |
| 106 | 90 |
| 107 if (remaining_bytes_ < dest_size) | 91 if (remaining_bytes_ < dest_size) |
| 108 dest_size = static_cast<int>(remaining_bytes_); | 92 dest_size = static_cast<int>(remaining_bytes_); |
| 109 | 93 |
| 110 if (!dest_size) { | 94 if (!dest_size) { |
| 111 *bytes_read = 0; | 95 *bytes_read = 0; |
| 112 return true; | 96 return true; |
| 113 } | 97 } |
| 114 | 98 |
| 115 int rv = stream_->Read(dest, dest_size, | 99 const int rv = reader_->Read(dest, dest_size, |
| 116 base::Bind(&FileSystemURLRequestJob::DidRead, | 100 base::Bind(&FileSystemURLRequestJob::DidRead, |
| 117 base::Unretained(this))); | 101 base::Unretained(this))); |
| 118 if (rv >= 0) { | |
| 119 // Data is immediately available. | |
| 120 *bytes_read = rv; | |
| 121 remaining_bytes_ -= rv; | |
| 122 DCHECK_GE(remaining_bytes_, 0); | |
| 123 return true; | |
| 124 } | |
| 125 | |
| 126 // Otherwise, a read error occured. We may just need to wait... | |
| 127 if (rv == net::ERR_IO_PENDING) | 102 if (rv == net::ERR_IO_PENDING) |
| 128 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); | 103 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); |
| 129 else | 104 else |
| 130 NotifyFailed(rv); | 105 NotifyFailed(rv); |
| 131 return false; | 106 return false; |
| 132 } | 107 } |
| 133 | 108 |
| 134 bool FileSystemURLRequestJob::GetMimeType(std::string* mime_type) const { | 109 bool FileSystemURLRequestJob::GetMimeType(std::string* mime_type) const { |
| 135 DCHECK(request_); | 110 DCHECK(request_); |
| 136 FilePath virtual_path; | 111 FilePath virtual_path; |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 207 is_directory_ = file_info.is_directory; | 182 is_directory_ = file_info.is_directory; |
| 208 | 183 |
| 209 // Keep the reference (if it's non-null) so that the file won't go away. | 184 // Keep the reference (if it's non-null) so that the file won't go away. |
| 210 snapshot_ref_ = file_ref; | 185 snapshot_ref_ = file_ref; |
| 211 | 186 |
| 212 if (!byte_range_.ComputeBounds(file_info.size)) { | 187 if (!byte_range_.ComputeBounds(file_info.size)) { |
| 213 NotifyFailed(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE); | 188 NotifyFailed(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE); |
| 214 return; | 189 return; |
| 215 } | 190 } |
| 216 | 191 |
| 217 if (!is_directory_) { | 192 if (is_directory_) { |
| 218 base::FileUtilProxy::CreateOrOpen( | |
| 219 file_thread_proxy_, platform_path, kFileFlags, | |
| 220 base::Bind(&FileSystemURLRequestJob::DidOpen, | |
| 221 weak_factory_.GetWeakPtr())); | |
| 222 } else { | |
| 223 NotifyHeadersComplete(); | 193 NotifyHeadersComplete(); |
| 224 } | |
| 225 } | |
| 226 | |
| 227 void FileSystemURLRequestJob::DidOpen(base::PlatformFileError error_code, | |
| 228 base::PassPlatformFile file, | |
| 229 bool created) { | |
| 230 if (error_code != base::PLATFORM_FILE_OK) { | |
| 231 NotifyFailed(error_code); | |
| 232 return; | 194 return; |
| 233 } | 195 } |
| 234 | 196 |
| 235 stream_.reset(new net::FileStream(file.ReleaseValue(), kFileFlags, NULL)); | |
| 236 | |
| 237 remaining_bytes_ = byte_range_.last_byte_position() - | 197 remaining_bytes_ = byte_range_.last_byte_position() - |
| 238 byte_range_.first_byte_position() + 1; | 198 byte_range_.first_byte_position() + 1; |
| 239 DCHECK_GE(remaining_bytes_, 0); | 199 DCHECK_GE(remaining_bytes_, 0); |
| 240 | 200 |
| 241 // TODO(adamk): Please remove this ScopedAllowIO once we support async seek | 201 DCHECK(!reader_.get()); |
| 242 // on FileStream. crbug.com/113300 | 202 reader_.reset(new LocalFileReader( |
| 243 base::ThreadRestrictions::ScopedAllowIO allow_io; | 203 file_thread_proxy_, platform_path, |
| 244 // Do the seek at the beginning of the request. | 204 byte_range_.first_byte_position(), |
| 245 if (remaining_bytes_ > 0 && | 205 base::Time())); |
| 246 byte_range_.first_byte_position() != 0 && | |
| 247 byte_range_.first_byte_position() != | |
| 248 stream_->SeekSync(net::FROM_BEGIN, | |
| 249 byte_range_.first_byte_position())) { | |
| 250 NotifyFailed(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE); | |
| 251 return; | |
| 252 } | |
| 253 | 206 |
| 254 set_expected_content_size(remaining_bytes_); | 207 set_expected_content_size(remaining_bytes_); |
| 255 response_info_.reset(new net::HttpResponseInfo()); | 208 response_info_.reset(new net::HttpResponseInfo()); |
| 256 response_info_->headers = CreateHttpResponseHeaders(); | 209 response_info_->headers = CreateHttpResponseHeaders(); |
| 257 | |
| 258 NotifyHeadersComplete(); | 210 NotifyHeadersComplete(); |
| 259 } | 211 } |
| 260 | 212 |
| 261 void FileSystemURLRequestJob::DidRead(int result) { | 213 void FileSystemURLRequestJob::DidRead(int result) { |
| 262 if (result > 0) | 214 if (result > 0) |
| 263 SetStatus(URLRequestStatus()); // Clear the IO_PENDING status | 215 SetStatus(URLRequestStatus()); // Clear the IO_PENDING status |
| 264 else if (result == 0) | 216 else if (result == 0) |
| 265 NotifyDone(URLRequestStatus()); | 217 NotifyDone(URLRequestStatus()); |
| 266 else | 218 else |
| 267 NotifyFailed(result); | 219 NotifyFailed(result); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 287 } | 239 } |
| 288 | 240 |
| 289 return false; | 241 return false; |
| 290 } | 242 } |
| 291 | 243 |
| 292 void FileSystemURLRequestJob::NotifyFailed(int rv) { | 244 void FileSystemURLRequestJob::NotifyFailed(int rv) { |
| 293 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv)); | 245 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv)); |
| 294 } | 246 } |
| 295 | 247 |
| 296 } // namespace fileapi | 248 } // namespace fileapi |
| OLD | NEW |