OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 // For loading files, we make use of overlapped i/o to ensure that reading from | 5 // For loading files, we make use of overlapped i/o to ensure that reading from |
6 // the filesystem (e.g., a network filesystem) does not block the calling | 6 // the filesystem (e.g., a network filesystem) does not block the calling |
7 // thread. An alternative approach would be to use a background thread or pool | 7 // thread. An alternative approach would be to use a background thread or pool |
8 // of threads, but it seems better to leverage the operating system's ability | 8 // of threads, but it seems better to leverage the operating system's ability |
9 // to do background file reads for us. | 9 // to do background file reads for us. |
10 // | 10 // |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 owner_->DidResolve(exists, file_info); | 75 owner_->DidResolve(exists, file_info); |
76 } | 76 } |
77 | 77 |
78 URLRequestFileJob* owner_; | 78 URLRequestFileJob* owner_; |
79 | 79 |
80 base::Lock lock_; | 80 base::Lock lock_; |
81 MessageLoop* owner_loop_; | 81 MessageLoop* owner_loop_; |
82 }; | 82 }; |
83 #endif | 83 #endif |
84 | 84 |
| 85 URLRequestFileJob::URLRequestFileJob(URLRequest* request, |
| 86 const FilePath& file_path) |
| 87 : URLRequestJob(request), |
| 88 file_path_(file_path), |
| 89 ALLOW_THIS_IN_INITIALIZER_LIST( |
| 90 io_callback_(this, &URLRequestFileJob::DidRead)), |
| 91 is_directory_(false), |
| 92 remaining_bytes_(0), |
| 93 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { |
| 94 } |
| 95 |
85 // static | 96 // static |
86 URLRequestJob* URLRequestFileJob::Factory(URLRequest* request, | 97 URLRequestJob* URLRequestFileJob::Factory(URLRequest* request, |
87 const std::string& scheme) { | 98 const std::string& scheme) { |
88 | 99 |
89 FilePath file_path; | 100 FilePath file_path; |
90 const bool is_file = FileURLToFilePath(request->url(), &file_path); | 101 const bool is_file = FileURLToFilePath(request->url(), &file_path); |
91 | 102 |
92 #if defined(OS_CHROMEOS) | 103 #if defined(OS_CHROMEOS) |
93 // Check file access. | 104 // Check file access. |
94 if (AccessDisabled(file_path)) | 105 if (AccessDisabled(file_path)) |
95 return new URLRequestErrorJob(request, ERR_ACCESS_DENIED); | 106 return new URLRequestErrorJob(request, ERR_ACCESS_DENIED); |
96 #endif | 107 #endif |
97 | 108 |
98 // We need to decide whether to create URLRequestFileJob for file access or | 109 // We need to decide whether to create URLRequestFileJob for file access or |
99 // URLRequestFileDirJob for directory access. To avoid accessing the | 110 // URLRequestFileDirJob for directory access. To avoid accessing the |
100 // filesystem, we only look at the path string here. | 111 // filesystem, we only look at the path string here. |
101 // The code in the URLRequestFileJob::Start() method discovers that a path, | 112 // The code in the URLRequestFileJob::Start() method discovers that a path, |
102 // which doesn't end with a slash, should really be treated as a directory, | 113 // which doesn't end with a slash, should really be treated as a directory, |
103 // and it then redirects to the URLRequestFileDirJob. | 114 // and it then redirects to the URLRequestFileDirJob. |
104 if (is_file && | 115 if (is_file && |
105 file_util::EndsWithSeparator(file_path) && | 116 file_util::EndsWithSeparator(file_path) && |
106 file_path.IsAbsolute()) | 117 file_path.IsAbsolute()) |
107 return new URLRequestFileDirJob(request, file_path); | 118 return new URLRequestFileDirJob(request, file_path); |
108 | 119 |
109 // Use a regular file request job for all non-directories (including invalid | 120 // Use a regular file request job for all non-directories (including invalid |
110 // file names). | 121 // file names). |
111 return new URLRequestFileJob(request, file_path); | 122 return new URLRequestFileJob(request, file_path); |
112 } | 123 } |
113 | 124 |
114 URLRequestFileJob::URLRequestFileJob(URLRequest* request, | 125 #if defined(OS_CHROMEOS) |
115 const FilePath& file_path) | 126 static const char* const kLocalAccessWhiteList[] = { |
116 : URLRequestJob(request), | 127 "/home/chronos/user/Downloads", |
117 file_path_(file_path), | 128 "/media", |
118 ALLOW_THIS_IN_INITIALIZER_LIST( | 129 "/mnt/partner_partition", |
119 io_callback_(this, &URLRequestFileJob::DidRead)), | 130 "/usr/share/chromeos-assets", |
120 is_directory_(false), | 131 "/tmp", |
121 remaining_bytes_(0), | 132 "/var/log", |
122 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { | 133 }; |
| 134 |
| 135 // static |
| 136 bool URLRequestFileJob::AccessDisabled(const FilePath& file_path) { |
| 137 if (URLRequest::IsFileAccessAllowed()) { // for tests. |
| 138 return false; |
| 139 } |
| 140 |
| 141 for (size_t i = 0; i < arraysize(kLocalAccessWhiteList); ++i) { |
| 142 const FilePath white_listed_path(kLocalAccessWhiteList[i]); |
| 143 // FilePath::operator== should probably handle trailing seperators. |
| 144 if (white_listed_path == file_path.StripTrailingSeparators() || |
| 145 white_listed_path.IsParent(file_path)) { |
| 146 return false; |
| 147 } |
| 148 } |
| 149 return true; |
123 } | 150 } |
124 | |
125 URLRequestFileJob::~URLRequestFileJob() { | |
126 #if defined(OS_WIN) | |
127 DCHECK(!async_resolver_); | |
128 #endif | 151 #endif |
129 } | |
130 | 152 |
131 void URLRequestFileJob::Start() { | 153 void URLRequestFileJob::Start() { |
132 #if defined(OS_WIN) | 154 #if defined(OS_WIN) |
133 // Resolve UNC paths on a background thread. | 155 // Resolve UNC paths on a background thread. |
134 if (!file_path_.value().compare(0, 2, L"\\\\")) { | 156 if (!file_path_.value().compare(0, 2, L"\\\\")) { |
135 DCHECK(!async_resolver_); | 157 DCHECK(!async_resolver_); |
136 async_resolver_ = new AsyncResolver(this); | 158 async_resolver_ = new AsyncResolver(this); |
137 base::WorkerPool::PostTask(FROM_HERE, NewRunnableMethod( | 159 base::WorkerPool::PostTask(FROM_HERE, NewRunnableMethod( |
138 async_resolver_.get(), &AsyncResolver::Resolve, file_path_), true); | 160 async_resolver_.get(), &AsyncResolver::Resolve, file_path_), true); |
139 return; | 161 return; |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
197 | 219 |
198 // Otherwise, a read error occured. We may just need to wait... | 220 // Otherwise, a read error occured. We may just need to wait... |
199 if (rv == ERR_IO_PENDING) { | 221 if (rv == ERR_IO_PENDING) { |
200 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); | 222 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); |
201 } else { | 223 } else { |
202 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv)); | 224 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv)); |
203 } | 225 } |
204 return false; | 226 return false; |
205 } | 227 } |
206 | 228 |
| 229 bool URLRequestFileJob::IsRedirectResponse(GURL* location, |
| 230 int* http_status_code) { |
| 231 if (is_directory_) { |
| 232 // This happens when we discovered the file is a directory, so needs a |
| 233 // slash at the end of the path. |
| 234 std::string new_path = request_->url().path(); |
| 235 new_path.push_back('/'); |
| 236 GURL::Replacements replacements; |
| 237 replacements.SetPathStr(new_path); |
| 238 |
| 239 *location = request_->url().ReplaceComponents(replacements); |
| 240 *http_status_code = 301; // simulate a permanent redirect |
| 241 return true; |
| 242 } |
| 243 |
| 244 #if defined(OS_WIN) |
| 245 // Follow a Windows shortcut. |
| 246 // We just resolve .lnk file, ignore others. |
| 247 if (!LowerCaseEqualsASCII(file_path_.Extension(), ".lnk")) |
| 248 return false; |
| 249 |
| 250 FilePath new_path = file_path_; |
| 251 bool resolved; |
| 252 resolved = file_util::ResolveShortcut(&new_path); |
| 253 |
| 254 // If shortcut is not resolved succesfully, do not redirect. |
| 255 if (!resolved) |
| 256 return false; |
| 257 |
| 258 *location = FilePathToFileURL(new_path); |
| 259 *http_status_code = 301; |
| 260 return true; |
| 261 #else |
| 262 return false; |
| 263 #endif |
| 264 } |
| 265 |
207 bool URLRequestFileJob::GetContentEncodings( | 266 bool URLRequestFileJob::GetContentEncodings( |
208 std::vector<Filter::FilterType>* encoding_types) { | 267 std::vector<Filter::FilterType>* encoding_types) { |
209 DCHECK(encoding_types->empty()); | 268 DCHECK(encoding_types->empty()); |
210 | 269 |
211 // Bug 9936 - .svgz files needs to be decompressed. | 270 // Bug 9936 - .svgz files needs to be decompressed. |
212 if (LowerCaseEqualsASCII(file_path_.Extension(), ".svgz")) | 271 if (LowerCaseEqualsASCII(file_path_.Extension(), ".svgz")) |
213 encoding_types->push_back(Filter::FILTER_TYPE_GZIP); | 272 encoding_types->push_back(Filter::FILTER_TYPE_GZIP); |
214 | 273 |
215 return !encoding_types->empty(); | 274 return !encoding_types->empty(); |
216 } | 275 } |
(...skipping 21 matching lines...) Expand all Loading... |
238 // because we need to do multipart encoding here. | 297 // because we need to do multipart encoding here. |
239 // TODO(hclam): decide whether we want to support multiple range | 298 // TODO(hclam): decide whether we want to support multiple range |
240 // requests. | 299 // requests. |
241 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, | 300 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, |
242 ERR_REQUEST_RANGE_NOT_SATISFIABLE)); | 301 ERR_REQUEST_RANGE_NOT_SATISFIABLE)); |
243 } | 302 } |
244 } | 303 } |
245 } | 304 } |
246 } | 305 } |
247 | 306 |
| 307 URLRequestFileJob::~URLRequestFileJob() { |
| 308 #if defined(OS_WIN) |
| 309 DCHECK(!async_resolver_); |
| 310 #endif |
| 311 } |
| 312 |
248 void URLRequestFileJob::DidResolve( | 313 void URLRequestFileJob::DidResolve( |
249 bool exists, const base::PlatformFileInfo& file_info) { | 314 bool exists, const base::PlatformFileInfo& file_info) { |
250 #if defined(OS_WIN) | 315 #if defined(OS_WIN) |
251 async_resolver_ = NULL; | 316 async_resolver_ = NULL; |
252 #endif | 317 #endif |
253 | 318 |
254 // We may have been orphaned... | 319 // We may have been orphaned... |
255 if (!request_) | 320 if (!request_) |
256 return; | 321 return; |
257 | 322 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
316 } else { | 381 } else { |
317 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result)); | 382 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result)); |
318 } | 383 } |
319 | 384 |
320 remaining_bytes_ -= result; | 385 remaining_bytes_ -= result; |
321 DCHECK_GE(remaining_bytes_, 0); | 386 DCHECK_GE(remaining_bytes_, 0); |
322 | 387 |
323 NotifyReadComplete(result); | 388 NotifyReadComplete(result); |
324 } | 389 } |
325 | 390 |
326 bool URLRequestFileJob::IsRedirectResponse(GURL* location, | |
327 int* http_status_code) { | |
328 if (is_directory_) { | |
329 // This happens when we discovered the file is a directory, so needs a | |
330 // slash at the end of the path. | |
331 std::string new_path = request_->url().path(); | |
332 new_path.push_back('/'); | |
333 GURL::Replacements replacements; | |
334 replacements.SetPathStr(new_path); | |
335 | |
336 *location = request_->url().ReplaceComponents(replacements); | |
337 *http_status_code = 301; // simulate a permanent redirect | |
338 return true; | |
339 } | |
340 | |
341 #if defined(OS_WIN) | |
342 // Follow a Windows shortcut. | |
343 // We just resolve .lnk file, ignore others. | |
344 if (!LowerCaseEqualsASCII(file_path_.Extension(), ".lnk")) | |
345 return false; | |
346 | |
347 FilePath new_path = file_path_; | |
348 bool resolved; | |
349 resolved = file_util::ResolveShortcut(&new_path); | |
350 | |
351 // If shortcut is not resolved succesfully, do not redirect. | |
352 if (!resolved) | |
353 return false; | |
354 | |
355 *location = FilePathToFileURL(new_path); | |
356 *http_status_code = 301; | |
357 return true; | |
358 #else | |
359 return false; | |
360 #endif | |
361 } | |
362 | |
363 #if defined(OS_CHROMEOS) | |
364 static const char* const kLocalAccessWhiteList[] = { | |
365 "/home/chronos/user/Downloads", | |
366 "/media", | |
367 "/mnt/partner_partition", | |
368 "/usr/share/chromeos-assets", | |
369 "/tmp", | |
370 "/var/log", | |
371 }; | |
372 | |
373 // static | |
374 bool URLRequestFileJob::AccessDisabled(const FilePath& file_path) { | |
375 if (URLRequest::IsFileAccessAllowed()) { // for tests. | |
376 return false; | |
377 } | |
378 | |
379 for (size_t i = 0; i < arraysize(kLocalAccessWhiteList); ++i) { | |
380 const FilePath white_listed_path(kLocalAccessWhiteList[i]); | |
381 // FilePath::operator== should probably handle trailing seperators. | |
382 if (white_listed_path == file_path.StripTrailingSeparators() || | |
383 white_listed_path.IsParent(file_path)) { | |
384 return false; | |
385 } | |
386 } | |
387 return true; | |
388 } | |
389 #endif | |
390 | |
391 } // namespace net | 391 } // namespace net |
OLD | NEW |