1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be 3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file. 4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// For loading files, we make use of overlapped i/o to ensure that reading from 6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// the filesystem (e.g., a network filesystem) does not block the calling 7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// thread. An alternative approach would be to use a background thread or pool 8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// of threads, but it seems better to leverage the operating system's ability 9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// to do background file reads for us. 10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Since overlapped reads require a 'static' buffer for the duration of the 12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// asynchronous read, the URLRequestFileJob keeps a buffer as a member var. In 13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// URLRequestFileJob::Read, data is simply copied from the object's buffer into 14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// the given buffer. If there is no data to copy, the URLRequestFileJob 15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// attempts to read more from the file to fill its buffer. If reading from the 16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// file does not complete synchronously, then the URLRequestFileJob waits for a 17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// signal from the OS that the overlapped read has completed. It does so by 18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// leveraging the MessageLoop::WatchObject API. 19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/url_request/url_request_file_job.h" 21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/compiler_specific.h" 23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/message_loop.h" 24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/platform_file.h" 25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/string_util.h" 2672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/synchronization/lock.h" 273f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/worker_pool.h" 283f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread_restrictions.h" 293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "build/build_config.h" 30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "googleurl/src/gurl.h" 31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/io_buffer.h" 32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/load_flags.h" 33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/mime_util.h" 34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/net_errors.h" 35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/net_util.h" 36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_util.h" 37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/url_request/url_request.h" 384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "net/url_request/url_request_error_job.h" 39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/url_request/url_request_file_dir_job.h" 40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 4121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsennamespace net { 4221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#if defined(OS_WIN) 444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochclass URLRequestFileJob::AsyncResolver 454a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch : public base::RefCountedThreadSafe<URLRequestFileJob::AsyncResolver> { 46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public: 47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott explicit AsyncResolver(URLRequestFileJob* owner) 48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott : owner_(owner), owner_loop_(MessageLoop::current()) { 49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott void Resolve(const FilePath& file_path) { 523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick base::PlatformFileInfo file_info; 53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott bool exists = file_util::GetFileInfo(file_path, &file_info); 5472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::AutoLock locked(lock_); 55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (owner_loop_) { 56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott owner_loop_->PostTask(FROM_HERE, NewRunnableMethod( 57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott this, &AsyncResolver::ReturnResults, exists, file_info)); 58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott void Cancel() { 62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott owner_ = NULL; 63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 6472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::AutoLock locked(lock_); 65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott owner_loop_ = NULL; 66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private: 69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott friend class base::RefCountedThreadSafe<URLRequestFileJob::AsyncResolver>; 70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ~AsyncResolver() {} 72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick void ReturnResults(bool exists, const base::PlatformFileInfo& file_info) { 74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (owner_) 75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott owner_->DidResolve(exists, file_info); 76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott URLRequestFileJob* owner_; 79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 8072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::Lock lock_; 81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott MessageLoop* owner_loop_; 82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}; 83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif 84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 8572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenURLRequestFileJob::URLRequestFileJob(URLRequest* request, 8672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const FilePath& file_path) 8772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen : URLRequestJob(request), 8872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen file_path_(file_path), 8972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ALLOW_THIS_IN_INITIALIZER_LIST( 9072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen io_callback_(this, &URLRequestFileJob::DidRead)), 9172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen is_directory_(false), 9272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen remaining_bytes_(0), 9372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { 9472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 9572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 9721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenURLRequestJob* URLRequestFileJob::Factory(URLRequest* request, 9821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const std::string& scheme) { 994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott FilePath file_path; 10121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const bool is_file = FileURLToFilePath(request->url(), &file_path); 1024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#if defined(OS_CHROMEOS) 1044a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // Check file access. 1054a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (AccessDisabled(file_path)) 10621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return new URLRequestErrorJob(request, ERR_ACCESS_DENIED); 1074a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#endif 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We need to decide whether to create URLRequestFileJob for file access or 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // URLRequestFileDirJob for directory access. To avoid accessing the 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // filesystem, we only look at the path string here. 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The code in the URLRequestFileJob::Start() method discovers that a path, 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // which doesn't end with a slash, should really be treated as a directory, 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // and it then redirects to the URLRequestFileDirJob. 1154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (is_file && 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_util::EndsWithSeparator(file_path) && 117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott file_path.IsAbsolute()) 118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return new URLRequestFileDirJob(request, file_path); 119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Use a regular file request job for all non-directories (including invalid 121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // file names). 122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return new URLRequestFileJob(request, file_path); 123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 12572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#if defined(OS_CHROMEOS) 12672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstatic const char* const kLocalAccessWhiteList[] = { 12772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen "/home/chronos/user/Downloads", 12872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen "/media", 129dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen "/opt/oem", 13072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen "/usr/share/chromeos-assets", 13172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen "/tmp", 13272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen "/var/log", 13372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}; 134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 13572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// static 13672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool URLRequestFileJob::AccessDisabled(const FilePath& file_path) { 13772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (URLRequest::IsFileAccessAllowed()) { // for tests. 13872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return false; 13972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 14072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 14172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen for (size_t i = 0; i < arraysize(kLocalAccessWhiteList); ++i) { 14272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const FilePath white_listed_path(kLocalAccessWhiteList[i]); 14372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // FilePath::operator== should probably handle trailing seperators. 14472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (white_listed_path == file_path.StripTrailingSeparators() || 14572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen white_listed_path.IsParent(file_path)) { 14672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return false; 14772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 14872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 14972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return true; 150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 15172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#endif 152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid URLRequestFileJob::Start() { 154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#if defined(OS_WIN) 155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Resolve UNC paths on a background thread. 156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!file_path_.value().compare(0, 2, L"\\\\")) { 157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(!async_resolver_); 158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott async_resolver_ = new AsyncResolver(this); 1593f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen base::WorkerPool::PostTask(FROM_HERE, NewRunnableMethod( 160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott async_resolver_.get(), &AsyncResolver::Resolve, file_path_), true); 161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif 164513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 165513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // URL requests should not block on the disk! 166513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // http://code.google.com/p/chromium/issues/detail?id=59849 167513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch bool exists; 1683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick base::PlatformFileInfo file_info; 169513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch { 170513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch base::ThreadRestrictions::ScopedAllowIO allow_io; 171513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch exists = file_util::GetFileInfo(file_path_, &file_info); 172513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch } 173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Continue asynchronously. 17521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen MessageLoop::current()->PostTask( 17621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen FROM_HERE, 17721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen method_factory_.NewRunnableMethod( 17821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen &URLRequestFileJob::DidResolve, exists, file_info)); 179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid URLRequestFileJob::Kill() { 182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott stream_.Close(); 183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#if defined(OS_WIN) 185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (async_resolver_) { 186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott async_resolver_->Cancel(); 187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott async_resolver_ = NULL; 188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif 190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott URLRequestJob::Kill(); 19221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen method_factory_.RevokeAll(); 193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 19521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool URLRequestFileJob::ReadRawData(IOBuffer* dest, int dest_size, 196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int *bytes_read) { 197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK_NE(dest_size, 0); 198c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(bytes_read); 199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK_GE(remaining_bytes_, 0); 200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 201c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (remaining_bytes_ < dest_size) 202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott dest_size = static_cast<int>(remaining_bytes_); 203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // If we should copy zero bytes because |remaining_bytes_| is zero, short 205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // circuit here. 206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!dest_size) { 207c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *bytes_read = 0; 208c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 209c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int rv = stream_.Read(dest->data(), dest_size, &io_callback_); 212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (rv >= 0) { 213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Data is immediately available. 214c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *bytes_read = rv; 215c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott remaining_bytes_ -= rv; 216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK_GE(remaining_bytes_, 0); 217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 218c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 219c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 220c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Otherwise, a read error occured. We may just need to wait... 22121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (rv == ERR_IO_PENDING) { 222c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); 223c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else { 224c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv)); 225c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 226c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 227c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 228c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 22972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool URLRequestFileJob::IsRedirectResponse(GURL* location, 23072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen int* http_status_code) { 23172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (is_directory_) { 23272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // This happens when we discovered the file is a directory, so needs a 23372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // slash at the end of the path. 23472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen std::string new_path = request_->url().path(); 23572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen new_path.push_back('/'); 23672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen GURL::Replacements replacements; 23772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen replacements.SetPathStr(new_path); 23872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 23972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen *location = request_->url().ReplaceComponents(replacements); 24072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen *http_status_code = 301; // simulate a permanent redirect 24172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return true; 24272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 24372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 24472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#if defined(OS_WIN) 24572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Follow a Windows shortcut. 24672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // We just resolve .lnk file, ignore others. 24772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!LowerCaseEqualsASCII(file_path_.Extension(), ".lnk")) 24872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return false; 24972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 25072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen FilePath new_path = file_path_; 25172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen bool resolved; 25272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen resolved = file_util::ResolveShortcut(&new_path); 25372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 25472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // If shortcut is not resolved succesfully, do not redirect. 25572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!resolved) 25672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return false; 25772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 25872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen *location = FilePathToFileURL(new_path); 25972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen *http_status_code = 301; 26072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return true; 26172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#else 26272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return false; 26372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#endif 26472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 26572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 266ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenFilter* URLRequestFileJob::SetupFilter() const { 267c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Bug 9936 - .svgz files needs to be decompressed. 268ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return LowerCaseEqualsASCII(file_path_.Extension(), ".svgz") 269ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ? Filter::GZipFactory() : NULL; 270c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 271c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 272c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool URLRequestFileJob::GetMimeType(std::string* mime_type) const { 273513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // URL requests should not block on the disk! On Windows this goes to the 274513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // registry. 275513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // http://code.google.com/p/chromium/issues/detail?id=59849 276513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch base::ThreadRestrictions::ScopedAllowIO allow_io; 277c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(request_); 27821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return GetMimeTypeFromFile(file_path_, mime_type); 279c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 280c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid URLRequestFileJob::SetExtraRequestHeaders( 28221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const HttpRequestHeaders& headers) { 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string range_header; 28421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (headers.GetHeader(HttpRequestHeaders::kRange, &range_header)) { 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We only care about "Range" header here. 28621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen std::vector<HttpByteRange> ranges; 28721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (HttpUtil::ParseRangeHeader(range_header, &ranges)) { 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (ranges.size() == 1) { 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch byte_range_ = ranges[0]; 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We don't support multiple range requests in one single URL request, 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // because we need to do multipart encoding here. 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(hclam): decide whether we want to support multiple range 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // requests. 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, 29621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen ERR_REQUEST_RANGE_NOT_SATISFIABLE)); 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 298c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 299c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 300c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 301c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 30272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenURLRequestFileJob::~URLRequestFileJob() { 30372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#if defined(OS_WIN) 30472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen DCHECK(!async_resolver_); 30572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#endif 30672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 30772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 308c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid URLRequestFileJob::DidResolve( 3093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bool exists, const base::PlatformFileInfo& file_info) { 310c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#if defined(OS_WIN) 311c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott async_resolver_ = NULL; 312c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif 313c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 314c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // We may have been orphaned... 315c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!request_) 316c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 317c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_directory_ = file_info.is_directory; 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 32021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen int rv = OK; 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We use URLRequestFileJob to handle files as well as directories without 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // trailing slash. 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If a directory does not exist, we return ERR_FILE_NOT_FOUND. Otherwise, 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // we will append trailing slash and redirect to FileDirJob. 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // A special case is "\" on Windows. We should resolve as invalid. 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // However, Windows resolves "\" to "C:\", thus reports it as existent. 327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // So what happens is we append it with trailing slash and redirect it to 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // FileDirJob where it is resolved as invalid. 329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!exists) { 33021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen rv = ERR_FILE_NOT_FOUND; 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (!is_directory_) { 332513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // URL requests should not block on the disk! 333513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // http://code.google.com/p/chromium/issues/detail?id=59849 334513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch base::ThreadRestrictions::ScopedAllowIO allow_io; 335513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 336c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int flags = base::PLATFORM_FILE_OPEN | 337c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott base::PLATFORM_FILE_READ | 338c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott base::PLATFORM_FILE_ASYNC; 339c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott rv = stream_.Open(file_path_, flags); 340c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 341c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 34221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (rv != OK) { 343c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv)); 344c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 345c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 346c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 347c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!byte_range_.ComputeBounds(file_info.size)) { 348c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, 34921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen ERR_REQUEST_RANGE_NOT_SATISFIABLE)); 350c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 351c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 352c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 353c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott remaining_bytes_ = byte_range_.last_byte_position() - 354c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott byte_range_.first_byte_position() + 1; 355c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK_GE(remaining_bytes_, 0); 356c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 357ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // URL requests should not block on the disk! 358ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // http://code.google.com/p/chromium/issues/detail?id=59849 359ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen { 360ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::ThreadRestrictions::ScopedAllowIO allow_io; 361ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Do the seek at the beginning of the request. 362ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (remaining_bytes_ > 0 && 363ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen byte_range_.first_byte_position() != 0 && 364ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen byte_range_.first_byte_position() != 365ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen stream_.Seek(FROM_BEGIN, byte_range_.first_byte_position())) { 366ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, 367ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ERR_REQUEST_RANGE_NOT_SATISFIABLE)); 368ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return; 369ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 370c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 371c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 372c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott set_expected_content_size(remaining_bytes_); 373c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NotifyHeadersComplete(); 374c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 375c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 376c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid URLRequestFileJob::DidRead(int result) { 377c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (result > 0) { 378c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SetStatus(URLRequestStatus()); // Clear the IO_PENDING status 379c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else if (result == 0) { 380c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NotifyDone(URLRequestStatus()); 381c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else { 382c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result)); 383c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 384c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 385c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott remaining_bytes_ -= result; 386c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK_GE(remaining_bytes_, 0); 387c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 388c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NotifyReadComplete(result); 389c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 390c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 39121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen} // namespace net 392