url_request_file_dir_job.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)// found in the LICENSE file.
493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "net/url_request/url_request_file_dir_job.h"
693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "base/bind.h"
893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "base/compiler_specific.h"
993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "base/message_loop/message_loop.h"
1093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "base/strings/sys_string_conversions.h"
1193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "base/strings/utf_string_conversions.h"
1293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "base/time/time.h"
1393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "net/base/io_buffer.h"
1493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "net/base/net_errors.h"
1593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "net/base/net_util.h"
1693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "net/url_request/url_request_status.h"
1793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "url/gurl.h"
1893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
1993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#if defined(OS_POSIX)
2093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include <sys/stat.h>
2193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#endif
2293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
2393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)namespace net {
2493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
2593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)URLRequestFileDirJob::URLRequestFileDirJob(URLRequest* request,
2693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                                           NetworkDelegate* network_delegate,
2793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                                           const base::FilePath& dir_path)
2893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    : URLRequestJob(request, network_delegate),
2993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)      lister_(dir_path, this),
3093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)      dir_path_(dir_path),
3193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)      canceled_(false),
3293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)      list_complete_(false),
3393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)      wrote_header_(false),
3493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)      read_pending_(false),
3593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)      read_buffer_length_(0),
3693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)      weak_factory_(this) {
3793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)}
3893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
39c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)void URLRequestFileDirJob::StartAsync() {
4093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  lister_.Start();
41e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)
4293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  NotifyHeadersComplete();
4393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)}
4493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
4593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)void URLRequestFileDirJob::Start() {
4693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  // Start reading asynchronously so that all error reporting and data
4793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  // callbacks happen as they would for network requests.
4893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
4993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)      FROM_HERE,
5093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)      base::Bind(&URLRequestFileDirJob::StartAsync,
5193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                 weak_factory_.GetWeakPtr()));
5293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)}
5393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
5493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)void URLRequestFileDirJob::Kill() {
5593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  if (canceled_)
5693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    return;
5793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
5893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  canceled_ = true;
5993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
6093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  if (!list_complete_)
6109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    lister_.Cancel();
6293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
6309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)  URLRequestJob::Kill();
6493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
6593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  weak_factory_.InvalidateWeakPtrs();
6609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
6709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
6893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)bool URLRequestFileDirJob::ReadRawData(IOBuffer* buf, int buf_size,
6993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                                       int* bytes_read) {
7093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  DCHECK(bytes_read);
7193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  *bytes_read = 0;
7293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
7309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)  if (is_done())
7409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    return true;
7593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
7609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)  if (FillReadBuffer(buf->data(), buf_size, bytes_read))
777242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    return true;
7893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
7993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  // We are waiting for more data
8093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  read_pending_ = true;
81e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)  read_buffer_ = buf;
8293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  read_buffer_length_ = buf_size;
8393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
8451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)  return false;
8593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)}
8693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
87bool URLRequestFileDirJob::GetMimeType(std::string* mime_type) const {
88  *mime_type = "text/html";
89  return true;
90}
91
92bool URLRequestFileDirJob::GetCharset(std::string* charset) {
93  // All the filenames are converted to UTF-8 before being added.
94  *charset = "utf-8";
95  return true;
96}
97
98void URLRequestFileDirJob::OnListFile(
99    const DirectoryLister::DirectoryListerData& data) {
100  // We wait to write out the header until we get the first file, so that we
101  // can catch errors from DirectoryLister and show an error page.
102  if (!wrote_header_) {
103#if defined(OS_WIN)
104    const base::string16& title = dir_path_.value();
105#elif defined(OS_POSIX)
106    // TODO(jungshik): Add SysNativeMBToUTF16 to sys_string_conversions.
107    // On Mac, need to add NFKC->NFC conversion either here or in file_path.
108    // On Linux, the file system encoding is not defined, but we assume that
109    // SysNativeMBToWide takes care of it at least for now. We can try something
110    // more sophisticated if necessary later.
111    const base::string16& title = WideToUTF16(
112        base::SysNativeMBToWide(dir_path_.value()));
113#endif
114    data_.append(GetDirectoryListingHeader(title));
115    wrote_header_ = true;
116  }
117
118#if defined(OS_WIN)
119  std::string raw_bytes;  // Empty on Windows means UTF-8 encoded name.
120#elif defined(OS_POSIX)
121  // TOOD(jungshik): The same issue as for the directory name.
122  base::FilePath filename = data.info.GetName();
123  const std::string& raw_bytes = filename.value();
124#endif
125  data_.append(GetDirectoryListingEntry(
126      data.info.GetName().LossyDisplayName(),
127      raw_bytes,
128      data.info.IsDirectory(),
129      data.info.GetSize(),
130      data.info.GetLastModifiedTime()));
131
132  // TODO(darin): coalesce more?
133  CompleteRead();
134}
135
136void URLRequestFileDirJob::OnListDone(int error) {
137  DCHECK(!canceled_);
138  if (error != OK) {
139    read_pending_ = false;
140    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, error));
141  } else {
142    list_complete_ = true;
143    CompleteRead();
144  }
145}
146
147URLRequestFileDirJob::~URLRequestFileDirJob() {}
148
149void URLRequestFileDirJob::CompleteRead() {
150  if (read_pending_) {
151    int bytes_read;
152    if (FillReadBuffer(read_buffer_->data(), read_buffer_length_,
153                       &bytes_read)) {
154      // We completed the read, so reset the read buffer.
155      read_pending_ = false;
156      read_buffer_ = NULL;
157      read_buffer_length_ = 0;
158
159      SetStatus(URLRequestStatus());
160      NotifyReadComplete(bytes_read);
161    } else {
162      NOTREACHED();
163      // TODO: Better error code.
164      NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, 0));
165    }
166  }
167}
168
169bool URLRequestFileDirJob::FillReadBuffer(char* buf, int buf_size,
170                                          int* bytes_read) {
171  DCHECK(bytes_read);
172
173  *bytes_read = 0;
174
175  int count = std::min(buf_size, static_cast<int>(data_.size()));
176  if (count) {
177    memcpy(buf, &data_[0], count);
178    data_.erase(0, count);
179    *bytes_read = count;
180    return true;
181  } else if (list_complete_) {
182    // EOF
183    return true;
184  }
185  return false;
186}
187
188}  // namespace net
189