url_request_file_job.cc revision 513209b27ff55e2841eac0e4120199c23acce758
1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2006-2010 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" 26513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "base/thread_restrictions.h" 273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "build/build_config.h" 28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "googleurl/src/gurl.h" 29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/io_buffer.h" 30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/load_flags.h" 31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/mime_util.h" 32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/net_errors.h" 33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/net_util.h" 34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_util.h" 35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/url_request/url_request.h" 36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/url_request/url_request_file_dir_job.h" 37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#if defined(OS_WIN) 393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/worker_pool.h" 403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#endif 413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#if defined(OS_WIN) 43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass URLRequestFileJob::AsyncResolver : 44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public base::RefCountedThreadSafe<URLRequestFileJob::AsyncResolver> { 45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public: 46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott explicit AsyncResolver(URLRequestFileJob* owner) 47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott : owner_(owner), owner_loop_(MessageLoop::current()) { 48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott void Resolve(const FilePath& file_path) { 513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick base::PlatformFileInfo file_info; 52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott bool exists = file_util::GetFileInfo(file_path, &file_info); 53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott AutoLock locked(lock_); 54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (owner_loop_) { 55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott owner_loop_->PostTask(FROM_HERE, NewRunnableMethod( 56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott this, &AsyncResolver::ReturnResults, exists, file_info)); 57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott void Cancel() { 61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott owner_ = NULL; 62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott AutoLock locked(lock_); 64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott owner_loop_ = NULL; 65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private: 68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott friend class base::RefCountedThreadSafe<URLRequestFileJob::AsyncResolver>; 69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ~AsyncResolver() {} 71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick void ReturnResults(bool exists, const base::PlatformFileInfo& file_info) { 73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (owner_) 74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott owner_->DidResolve(exists, file_info); 75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott URLRequestFileJob* owner_; 78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Lock lock_; 80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott MessageLoop* owner_loop_; 81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}; 82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif 83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottURLRequestJob* URLRequestFileJob::Factory( 86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott URLRequest* request, const std::string& scheme) { 87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott FilePath file_path; 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We need to decide whether to create URLRequestFileJob for file access or 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // URLRequestFileDirJob for directory access. To avoid accessing the 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // filesystem, we only look at the path string here. 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The code in the URLRequestFileJob::Start() method discovers that a path, 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // which doesn't end with a slash, should really be treated as a directory, 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // and it then redirects to the URLRequestFileDirJob. 95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (net::FileURLToFilePath(request->url(), &file_path) && 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_util::EndsWithSeparator(file_path) && 97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott file_path.IsAbsolute()) 98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return new URLRequestFileDirJob(request, file_path); 99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Use a regular file request job for all non-directories (including invalid 101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // file names). 102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return new URLRequestFileJob(request, file_path); 103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottURLRequestFileJob::URLRequestFileJob(URLRequest* request, 106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const FilePath& file_path) 107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott : URLRequestJob(request), 108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott file_path_(file_path), 109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ALLOW_THIS_IN_INITIALIZER_LIST( 110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott io_callback_(this, &URLRequestFileJob::DidRead)), 111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott is_directory_(false), 112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott remaining_bytes_(0) { 113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottURLRequestFileJob::~URLRequestFileJob() { 116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#if defined(OS_WIN) 117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(!async_resolver_); 118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif 119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid URLRequestFileJob::Start() { 122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#if defined(OS_WIN) 123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Resolve UNC paths on a background thread. 124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!file_path_.value().compare(0, 2, L"\\\\")) { 125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(!async_resolver_); 126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott async_resolver_ = new AsyncResolver(this); 127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott WorkerPool::PostTask(FROM_HERE, NewRunnableMethod( 128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott async_resolver_.get(), &AsyncResolver::Resolve, file_path_), true); 129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif 132513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 133513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // URL requests should not block on the disk! 134513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // http://code.google.com/p/chromium/issues/detail?id=59849 135513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch bool exists; 1363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick base::PlatformFileInfo file_info; 137513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch { 138513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch base::ThreadRestrictions::ScopedAllowIO allow_io; 139513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch exists = file_util::GetFileInfo(file_path_, &file_info); 140513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch } 141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Continue asynchronously. 143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( 144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott this, &URLRequestFileJob::DidResolve, exists, file_info)); 145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid URLRequestFileJob::Kill() { 148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott stream_.Close(); 149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#if defined(OS_WIN) 151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (async_resolver_) { 152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott async_resolver_->Cancel(); 153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott async_resolver_ = NULL; 154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif 156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott URLRequestJob::Kill(); 158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool URLRequestFileJob::ReadRawData(net::IOBuffer* dest, int dest_size, 161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int *bytes_read) { 162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK_NE(dest_size, 0); 163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(bytes_read); 164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK_GE(remaining_bytes_, 0); 165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (remaining_bytes_ < dest_size) 167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott dest_size = static_cast<int>(remaining_bytes_); 168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // If we should copy zero bytes because |remaining_bytes_| is zero, short 170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // circuit here. 171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!dest_size) { 172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *bytes_read = 0; 173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int rv = stream_.Read(dest->data(), dest_size, &io_callback_); 177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (rv >= 0) { 178c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Data is immediately available. 179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *bytes_read = rv; 180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott remaining_bytes_ -= rv; 181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK_GE(remaining_bytes_, 0); 182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Otherwise, a read error occured. We may just need to wait... 186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (rv == net::ERR_IO_PENDING) { 187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); 188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else { 189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv)); 190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool URLRequestFileJob::GetContentEncodings( 195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::vector<Filter::FilterType>* encoding_types) { 196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(encoding_types->empty()); 197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 198c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Bug 9936 - .svgz files needs to be decompressed. 199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (LowerCaseEqualsASCII(file_path_.Extension(), ".svgz")) 200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott encoding_types->push_back(Filter::FILTER_TYPE_GZIP); 201c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return !encoding_types->empty(); 203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool URLRequestFileJob::GetMimeType(std::string* mime_type) const { 206513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // URL requests should not block on the disk! On Windows this goes to the 207513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // registry. 208513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // http://code.google.com/p/chromium/issues/detail?id=59849 209513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch base::ThreadRestrictions::ScopedAllowIO allow_io; 210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(request_); 211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return net::GetMimeTypeFromFile(file_path_, mime_type); 212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid URLRequestFileJob::SetExtraRequestHeaders( 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const net::HttpRequestHeaders& headers) { 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string range_header; 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) { 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We only care about "Range" header here. 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<net::HttpByteRange> ranges; 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) { 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (ranges.size() == 1) { 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch byte_range_ = ranges[0]; 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We don't support multiple range requests in one single URL request, 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // because we need to do multipart encoding here. 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(hclam): decide whether we want to support multiple range 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // requests. 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch net::ERR_REQUEST_RANGE_NOT_SATISFIABLE)); 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 231c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 232c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 233c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 234c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 235c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid URLRequestFileJob::DidResolve( 2363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bool exists, const base::PlatformFileInfo& file_info) { 237c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#if defined(OS_WIN) 238c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott async_resolver_ = NULL; 239c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif 240c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 241c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // We may have been orphaned... 242c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!request_) 243c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 244c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_directory_ = file_info.is_directory; 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 247c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int rv = net::OK; 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We use URLRequestFileJob to handle files as well as directories without 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // trailing slash. 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If a directory does not exist, we return ERR_FILE_NOT_FOUND. Otherwise, 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // we will append trailing slash and redirect to FileDirJob. 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // A special case is "\" on Windows. We should resolve as invalid. 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // However, Windows resolves "\" to "C:\", thus reports it as existent. 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // So what happens is we append it with trailing slash and redirect it to 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // FileDirJob where it is resolved as invalid. 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!exists) { 257c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott rv = net::ERR_FILE_NOT_FOUND; 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (!is_directory_) { 259513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // URL requests should not block on the disk! 260513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // http://code.google.com/p/chromium/issues/detail?id=59849 261513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch base::ThreadRestrictions::ScopedAllowIO allow_io; 262513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 263c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int flags = base::PLATFORM_FILE_OPEN | 264c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott base::PLATFORM_FILE_READ | 265c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott base::PLATFORM_FILE_ASYNC; 266c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott rv = stream_.Open(file_path_, flags); 267c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 268c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 269c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (rv != net::OK) { 270c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv)); 271c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 272c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 273c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 274c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!byte_range_.ComputeBounds(file_info.size)) { 275c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, 276c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott net::ERR_REQUEST_RANGE_NOT_SATISFIABLE)); 277c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 278c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 279c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 280c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott remaining_bytes_ = byte_range_.last_byte_position() - 281c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott byte_range_.first_byte_position() + 1; 282c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK_GE(remaining_bytes_, 0); 283c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 284c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Do the seek at the beginning of the request. 285c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (remaining_bytes_ > 0 && 286c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott byte_range_.first_byte_position() != 0 && 287c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott byte_range_.first_byte_position() != 288c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott stream_.Seek(net::FROM_BEGIN, byte_range_.first_byte_position())) { 289c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, 290c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott net::ERR_REQUEST_RANGE_NOT_SATISFIABLE)); 291c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 292c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 293c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 294c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott set_expected_content_size(remaining_bytes_); 295c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NotifyHeadersComplete(); 296c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 297c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 298c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid URLRequestFileJob::DidRead(int result) { 299c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (result > 0) { 300c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SetStatus(URLRequestStatus()); // Clear the IO_PENDING status 301c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else if (result == 0) { 302c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NotifyDone(URLRequestStatus()); 303c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else { 304c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result)); 305c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 306c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 307c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott remaining_bytes_ -= result; 308c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK_GE(remaining_bytes_, 0); 309c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 310c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NotifyReadComplete(result); 311c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 312c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool URLRequestFileJob::IsRedirectResponse(GURL* location, 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int* http_status_code) { 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (is_directory_) { 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This happens when we discovered the file is a directory, so needs a 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // slash at the end of the path. 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string new_path = request_->url().path(); 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_path.push_back('/'); 320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL::Replacements replacements; 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch replacements.SetPathStr(new_path); 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *location = request_->url().ReplaceComponents(replacements); 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *http_status_code = 301; // simulate a permanent redirect 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 327c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN) 329c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Follow a Windows shortcut. 330c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // We just resolve .lnk file, ignore others. 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!LowerCaseEqualsASCII(file_path_.Extension(), ".lnk")) 332c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 333c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 334c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott FilePath new_path = file_path_; 335c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott bool resolved; 336c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott resolved = file_util::ResolveShortcut(&new_path); 337c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 338c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // If shortcut is not resolved succesfully, do not redirect. 339c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!resolved) 340c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 341c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 342c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *location = net::FilePathToFileURL(new_path); 343c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *http_status_code = 301; 344c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 345c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#else 346c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 347c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif 348c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 349