file_system_dir_url_request_job.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "storage/browser/fileapi/file_system_dir_url_request_job.h"
6
7#include <algorithm>
8
9#include "base/bind.h"
10#include "base/compiler_specific.h"
11#include "base/message_loop/message_loop.h"
12#include "base/strings/sys_string_conversions.h"
13#include "base/strings/utf_string_conversions.h"
14#include "base/time/time.h"
15#include "build/build_config.h"
16#include "net/base/io_buffer.h"
17#include "net/base/net_errors.h"
18#include "net/base/net_util.h"
19#include "net/url_request/url_request.h"
20#include "storage/browser/fileapi/file_system_context.h"
21#include "storage/browser/fileapi/file_system_operation_runner.h"
22#include "storage/browser/fileapi/file_system_url.h"
23#include "storage/common/fileapi/directory_entry.h"
24#include "storage/common/fileapi/file_system_util.h"
25#include "url/gurl.h"
26
27using net::NetworkDelegate;
28using net::URLRequest;
29using net::URLRequestJob;
30using net::URLRequestStatus;
31
32namespace storage {
33
34FileSystemDirURLRequestJob::FileSystemDirURLRequestJob(
35    URLRequest* request,
36    NetworkDelegate* network_delegate,
37    const std::string& storage_domain,
38    FileSystemContext* file_system_context)
39    : URLRequestJob(request, network_delegate),
40      storage_domain_(storage_domain),
41      file_system_context_(file_system_context),
42      weak_factory_(this) {
43}
44
45FileSystemDirURLRequestJob::~FileSystemDirURLRequestJob() {
46}
47
48bool FileSystemDirURLRequestJob::ReadRawData(net::IOBuffer* dest, int dest_size,
49                                             int *bytes_read) {
50  int count = std::min(dest_size, static_cast<int>(data_.size()));
51  if (count > 0) {
52    memcpy(dest->data(), data_.data(), count);
53    data_.erase(0, count);
54  }
55  *bytes_read = count;
56  return true;
57}
58
59void FileSystemDirURLRequestJob::Start() {
60  base::MessageLoop::current()->PostTask(
61      FROM_HERE,
62      base::Bind(&FileSystemDirURLRequestJob::StartAsync,
63                 weak_factory_.GetWeakPtr()));
64}
65
66void FileSystemDirURLRequestJob::Kill() {
67  URLRequestJob::Kill();
68  weak_factory_.InvalidateWeakPtrs();
69}
70
71bool FileSystemDirURLRequestJob::GetMimeType(std::string* mime_type) const {
72  *mime_type = "text/html";
73  return true;
74}
75
76bool FileSystemDirURLRequestJob::GetCharset(std::string* charset) {
77  *charset = "utf-8";
78  return true;
79}
80
81void FileSystemDirURLRequestJob::StartAsync() {
82  if (!request_)
83    return;
84  url_ = file_system_context_->CrackURL(request_->url());
85  if (!url_.is_valid()) {
86    file_system_context_->AttemptAutoMountForURLRequest(
87        request_,
88        storage_domain_,
89        base::Bind(&FileSystemDirURLRequestJob::DidAttemptAutoMount,
90                   weak_factory_.GetWeakPtr()));
91    return;
92  }
93  if (!file_system_context_->CanServeURLRequest(url_)) {
94    // In incognito mode the API is not usable and there should be no data.
95    if (url_.is_valid() && VirtualPath::IsRootPath(url_.virtual_path())) {
96      // Return an empty directory if the filesystem root is queried.
97      DidReadDirectory(base::File::FILE_OK,
98                       std::vector<DirectoryEntry>(),
99                       false);
100      return;
101    }
102    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED,
103                                net::ERR_FILE_NOT_FOUND));
104    return;
105  }
106  file_system_context_->operation_runner()->ReadDirectory(
107      url_,
108      base::Bind(&FileSystemDirURLRequestJob::DidReadDirectory, this));
109}
110
111void FileSystemDirURLRequestJob::DidAttemptAutoMount(base::File::Error result) {
112  if (result >= 0 &&
113      file_system_context_->CrackURL(request_->url()).is_valid()) {
114    StartAsync();
115  } else {
116    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED,
117                                net::ERR_FILE_NOT_FOUND));
118  }
119}
120
121void FileSystemDirURLRequestJob::DidReadDirectory(
122    base::File::Error result,
123    const std::vector<DirectoryEntry>& entries,
124    bool has_more) {
125  if (result != base::File::FILE_OK) {
126    int rv = net::ERR_FILE_NOT_FOUND;
127    if (result == base::File::FILE_ERROR_INVALID_URL)
128      rv = net::ERR_INVALID_URL;
129    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv));
130    return;
131  }
132
133  if (!request_)
134    return;
135
136  if (data_.empty()) {
137    base::FilePath relative_path = url_.path();
138#if defined(OS_POSIX)
139    relative_path =
140        base::FilePath(FILE_PATH_LITERAL("/") + relative_path.value());
141#endif
142    const base::string16& title = relative_path.LossyDisplayName();
143    data_.append(net::GetDirectoryListingHeader(title));
144  }
145
146  typedef std::vector<DirectoryEntry>::const_iterator EntryIterator;
147  for (EntryIterator it = entries.begin(); it != entries.end(); ++it) {
148    const base::string16& name = base::FilePath(it->name).LossyDisplayName();
149    data_.append(net::GetDirectoryListingEntry(
150        name, std::string(), it->is_directory, it->size,
151        it->last_modified_time));
152  }
153
154  if (!has_more) {
155    set_expected_content_size(data_.size());
156    NotifyHeadersComplete();
157  }
158}
159
160}  // namespace storage
161