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