mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-12-01 01:36:09 +03:00
212 lines
6.6 KiB
C++
212 lines
6.6 KiB
C++
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "net/url_request/url_request_file_dir_job.h"
|
|
|
|
#include "base/bind.h"
|
|
#include "base/compiler_specific.h"
|
|
#include "base/files/file_util.h"
|
|
#include "base/location.h"
|
|
#include "base/single_thread_task_runner.h"
|
|
#include "base/strings/sys_string_conversions.h"
|
|
#include "base/strings/utf_string_conversions.h"
|
|
#include "base/task/post_task.h"
|
|
#include "base/threading/thread_task_runner_handle.h"
|
|
#include "base/time/time.h"
|
|
#include "build/build_config.h"
|
|
#include "net/base/directory_listing.h"
|
|
#include "net/base/io_buffer.h"
|
|
#include "net/url_request/url_request_status.h"
|
|
#include "url/gurl.h"
|
|
|
|
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
|
|
#include <sys/stat.h>
|
|
#endif
|
|
|
|
namespace net {
|
|
|
|
URLRequestFileDirJob::URLRequestFileDirJob(URLRequest* request,
|
|
NetworkDelegate* network_delegate,
|
|
const base::FilePath& dir_path)
|
|
: URLRequestJob(request, network_delegate),
|
|
lister_(dir_path, this),
|
|
dir_path_(dir_path),
|
|
canceled_(false),
|
|
list_complete_(false),
|
|
wrote_header_(false),
|
|
read_pending_(false),
|
|
read_buffer_length_(0),
|
|
weak_factory_(this) {}
|
|
|
|
void URLRequestFileDirJob::StartAsync() {
|
|
base::PostTaskWithTraitsAndReplyWithResult(
|
|
FROM_HERE,
|
|
{base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
|
|
base::Bind(&base::MakeAbsoluteFilePath, dir_path_),
|
|
base::Bind(&URLRequestFileDirJob::DidMakeAbsolutePath,
|
|
weak_factory_.GetWeakPtr()));
|
|
}
|
|
|
|
void URLRequestFileDirJob::Start() {
|
|
// Start reading asynchronously so that all error reporting and data
|
|
// callbacks happen as they would for network requests.
|
|
base::ThreadTaskRunnerHandle::Get()->PostTask(
|
|
FROM_HERE, base::Bind(&URLRequestFileDirJob::StartAsync,
|
|
weak_factory_.GetWeakPtr()));
|
|
}
|
|
|
|
void URLRequestFileDirJob::Kill() {
|
|
if (canceled_)
|
|
return;
|
|
|
|
canceled_ = true;
|
|
|
|
if (!list_complete_)
|
|
lister_.Cancel();
|
|
|
|
URLRequestJob::Kill();
|
|
|
|
weak_factory_.InvalidateWeakPtrs();
|
|
}
|
|
|
|
int URLRequestFileDirJob::ReadRawData(IOBuffer* buf, int buf_size) {
|
|
int result = ReadBuffer(buf->data(), buf_size);
|
|
if (result == ERR_IO_PENDING) {
|
|
// We are waiting for more data
|
|
read_pending_ = true;
|
|
read_buffer_ = buf;
|
|
read_buffer_length_ = buf_size;
|
|
return ERR_IO_PENDING;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool URLRequestFileDirJob::GetMimeType(std::string* mime_type) const {
|
|
*mime_type = "text/html";
|
|
return true;
|
|
}
|
|
|
|
bool URLRequestFileDirJob::GetCharset(std::string* charset) {
|
|
// All the filenames are converted to UTF-8 before being added.
|
|
*charset = "utf-8";
|
|
return true;
|
|
}
|
|
|
|
void URLRequestFileDirJob::OnListFile(
|
|
const DirectoryLister::DirectoryListerData& data) {
|
|
// We wait to write out the header until we get the first file, so that we
|
|
// can catch errors from DirectoryLister and show an error page.
|
|
if (!wrote_header_) {
|
|
wrote_header_ = true;
|
|
|
|
#if defined(OS_WIN)
|
|
const base::string16& title = dir_path_.value();
|
|
#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
|
|
// TODO(jungshik): Add SysNativeMBToUTF16 to sys_string_conversions.
|
|
// On Mac, need to add NFKC->NFC conversion either here or in file_path.
|
|
// On Linux, the file system encoding is not defined, but we assume that
|
|
// SysNativeMBToWide takes care of it at least for now. We can try something
|
|
// more sophisticated if necessary later.
|
|
const base::string16& title = base::WideToUTF16(
|
|
base::SysNativeMBToWide(dir_path_.value()));
|
|
#endif
|
|
data_.append(GetDirectoryListingHeader(title));
|
|
|
|
// If this isn't top level directory, add a link to the parent directory.
|
|
// To figure this out, first normalize |dir_path_| by stripping it of
|
|
// trailing separators. Then compare the resulting |stripped_dir_path| to
|
|
// its DirName(). For the top level directory, e.g. "/" or "c:\\", the
|
|
// normalized path is equal to its DirName().
|
|
base::FilePath stripped_dir_path = dir_path_.StripTrailingSeparators();
|
|
if (stripped_dir_path != stripped_dir_path.DirName()) {
|
|
data_.append(GetParentDirectoryLink());
|
|
}
|
|
}
|
|
|
|
// Skip the current and parent directory entries in the listing.
|
|
// GetParentDirectoryLink() takes care of them.
|
|
base::FilePath filename = data.info.GetName();
|
|
if (filename.value() != base::FilePath::kCurrentDirectory &&
|
|
filename.value() != base::FilePath::kParentDirectory) {
|
|
#if defined(OS_WIN)
|
|
std::string raw_bytes; // Empty on Windows means UTF-8 encoded name.
|
|
#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
|
|
// TODO(jungshik): The same issue as for the directory name.
|
|
const std::string& raw_bytes = filename.value();
|
|
#endif
|
|
data_.append(GetDirectoryListingEntry(
|
|
filename.LossyDisplayName(), raw_bytes, data.info.IsDirectory(),
|
|
data.info.GetSize(), data.info.GetLastModifiedTime()));
|
|
}
|
|
|
|
// TODO(darin): coalesce more?
|
|
CompleteRead(OK);
|
|
}
|
|
|
|
void URLRequestFileDirJob::OnListDone(int error) {
|
|
DCHECK(!canceled_);
|
|
DCHECK_LE(error, OK);
|
|
|
|
list_complete_ = true;
|
|
list_complete_result_ = static_cast<Error>(error);
|
|
CompleteRead(list_complete_result_);
|
|
}
|
|
|
|
URLRequestFileDirJob::~URLRequestFileDirJob() = default;
|
|
|
|
void URLRequestFileDirJob::DidMakeAbsolutePath(
|
|
const base::FilePath& absolute_path) {
|
|
if (network_delegate() && !network_delegate()->CanAccessFile(
|
|
*request(), dir_path_, absolute_path)) {
|
|
NotifyStartError(URLRequestStatus::FromError(ERR_ACCESS_DENIED));
|
|
return;
|
|
}
|
|
|
|
lister_.Start();
|
|
NotifyHeadersComplete();
|
|
}
|
|
|
|
void URLRequestFileDirJob::CompleteRead(Error error) {
|
|
DCHECK_LE(error, OK);
|
|
DCHECK_NE(error, ERR_IO_PENDING);
|
|
|
|
// Do nothing if there is no read pending.
|
|
if (!read_pending_)
|
|
return;
|
|
|
|
int result = error;
|
|
if (error == OK) {
|
|
result = ReadBuffer(read_buffer_->data(), read_buffer_length_);
|
|
if (result >= 0) {
|
|
// We completed the read, so reset the read buffer.
|
|
read_buffer_ = nullptr;
|
|
read_buffer_length_ = 0;
|
|
} else {
|
|
NOTREACHED();
|
|
// TODO: Better error code.
|
|
result = ERR_FAILED;
|
|
}
|
|
}
|
|
|
|
read_pending_ = false;
|
|
ReadRawDataComplete(result);
|
|
}
|
|
|
|
int URLRequestFileDirJob::ReadBuffer(char* buf, int buf_size) {
|
|
int count = std::min(buf_size, static_cast<int>(data_.size()));
|
|
if (count) {
|
|
memcpy(buf, &data_[0], count);
|
|
data_.erase(0, count);
|
|
return count;
|
|
}
|
|
if (list_complete_) {
|
|
// EOF
|
|
return list_complete_result_;
|
|
}
|
|
return ERR_IO_PENDING;
|
|
}
|
|
|
|
} // namespace net
|