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