url_request_file_dir_job.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_file_dir_job.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
99ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/sys_string_conversions.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/io_buffer.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_status.h"
177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_POSIX)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/stat.h>
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)URLRequestFileDirJob::URLRequestFileDirJob(URLRequest* request,
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           NetworkDelegate* network_delegate,
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                           const base::FilePath& dir_path)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : URLRequestJob(request, network_delegate),
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      lister_(dir_path, this),
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dir_path_(dir_path),
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      canceled_(false),
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      list_complete_(false),
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wrote_header_(false),
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      read_pending_(false),
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      read_buffer_length_(0),
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_factory_(this) {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLRequestFileDirJob::StartAsync() {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  lister_.Start();
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyHeadersComplete();
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLRequestFileDirJob::Start() {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start reading asynchronously so that all error reporting and data
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // callbacks happen as they would for network requests.
4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&URLRequestFileDirJob::StartAsync,
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 weak_factory_.GetWeakPtr()));
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLRequestFileDirJob::Kill() {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (canceled_)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  canceled_ = true;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!list_complete_)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    lister_.Cancel();
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRequestJob::Kill();
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  weak_factory_.InvalidateWeakPtrs();
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLRequestFileDirJob::ReadRawData(IOBuffer* buf, int buf_size,
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       int* bytes_read) {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(bytes_read);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *bytes_read = 0;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_done())
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FillReadBuffer(buf->data(), buf_size, bytes_read))
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We are waiting for more data
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  read_pending_ = true;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  read_buffer_ = buf;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  read_buffer_length_ = buf_size;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLRequestFileDirJob::GetMimeType(std::string* mime_type) const {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *mime_type = "text/html";
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLRequestFileDirJob::GetCharset(std::string* charset) {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // All the filenames are converted to UTF-8 before being added.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *charset = "utf-8";
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLRequestFileDirJob::OnListFile(
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const DirectoryLister::DirectoryListerData& data) {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We wait to write out the header until we get the first file, so that we
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // can catch errors from DirectoryLister and show an error page.
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!wrote_header_) {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::string16& title = dir_path_.value();
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_POSIX)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(jungshik): Add SysNativeMBToUTF16 to sys_string_conversions.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // On Mac, need to add NFKC->NFC conversion either here or in file_path.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // On Linux, the file system encoding is not defined, but we assume that
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // SysNativeMBToWide takes care of it at least for now. We can try something
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // more sophisticated if necessary later.
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::string16& title = WideToUTF16(
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::SysNativeMBToWide(dir_path_.value()));
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data_.append(GetDirectoryListingHeader(title));
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    wrote_header_ = true;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::string raw_bytes;  // Empty on Windows means UTF-8 encoded name.
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_POSIX)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TOOD(jungshik): The same issue as for the directory name.
1221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  base::FilePath filename = data.info.GetName();
1231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  const std::string& raw_bytes = filename.value();
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  data_.append(GetDirectoryListingEntry(
126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      data.info.GetName().LossyDisplayName(),
127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      raw_bytes,
128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      data.info.IsDirectory(),
129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      data.info.GetSize(),
130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      data.info.GetLastModifiedTime()));
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(darin): coalesce more?
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CompleteRead();
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLRequestFileDirJob::OnListDone(int error) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!canceled_);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (error != OK) {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    read_pending_ = false;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, error));
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    list_complete_ = true;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CompleteRead();
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)URLRequestFileDirJob::~URLRequestFileDirJob() {}
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLRequestFileDirJob::CompleteRead() {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (read_pending_) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int bytes_read;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FillReadBuffer(read_buffer_->data(), read_buffer_length_,
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       &bytes_read)) {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We completed the read, so reset the read buffer.
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      read_pending_ = false;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      read_buffer_ = NULL;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      read_buffer_length_ = 0;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SetStatus(URLRequestStatus());
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NotifyReadComplete(bytes_read);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO: Better error code.
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, 0));
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLRequestFileDirJob::FillReadBuffer(char* buf, int buf_size,
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          int* bytes_read) {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(bytes_read);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *bytes_read = 0;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int count = std::min(buf_size, static_cast<int>(data_.size()));
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (count) {
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memcpy(buf, &data_[0], count);
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data_.erase(0, count);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *bytes_read = count;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (list_complete_) {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // EOF
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
189