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 |