| // 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 "storage/browser/fileapi/file_system_dir_url_request_job.h" |
| |
| #include <stddef.h> |
| |
| #include <algorithm> |
| |
| #include "base/bind.h" |
| #include "base/compiler_specific.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/strings/sys_string_conversions.h" |
| #include "base/strings/utf_string_conversions.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.h" |
| #include "storage/browser/fileapi/file_system_context.h" |
| #include "storage/browser/fileapi/file_system_operation_runner.h" |
| #include "storage/common/fileapi/directory_entry.h" |
| #include "storage/common/fileapi/file_system_util.h" |
| #include "url/gurl.h" |
| |
| using net::NetworkDelegate; |
| using net::URLRequest; |
| using net::URLRequestJob; |
| using net::URLRequestStatus; |
| |
| namespace storage { |
| |
| FileSystemDirURLRequestJob::FileSystemDirURLRequestJob( |
| URLRequest* request, |
| NetworkDelegate* network_delegate, |
| const std::string& storage_domain, |
| FileSystemContext* file_system_context) |
| : URLRequestJob(request, network_delegate), |
| storage_domain_(storage_domain), |
| file_system_context_(file_system_context), |
| weak_factory_(this) { |
| } |
| |
| FileSystemDirURLRequestJob::~FileSystemDirURLRequestJob() { |
| } |
| |
| int FileSystemDirURLRequestJob::ReadRawData(net::IOBuffer* dest, |
| int dest_size) { |
| int count = std::min(dest_size, base::checked_cast<int>(data_.size())); |
| if (count > 0) { |
| memcpy(dest->data(), data_.data(), count); |
| data_.erase(0, count); |
| } |
| return count; |
| } |
| |
| void FileSystemDirURLRequestJob::Start() { |
| base::MessageLoop::current()->PostTask( |
| FROM_HERE, |
| base::Bind(&FileSystemDirURLRequestJob::StartAsync, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| void FileSystemDirURLRequestJob::Kill() { |
| URLRequestJob::Kill(); |
| weak_factory_.InvalidateWeakPtrs(); |
| } |
| |
| bool FileSystemDirURLRequestJob::GetMimeType(std::string* mime_type) const { |
| *mime_type = "text/html"; |
| return true; |
| } |
| |
| bool FileSystemDirURLRequestJob::GetCharset(std::string* charset) { |
| *charset = "utf-8"; |
| return true; |
| } |
| |
| void FileSystemDirURLRequestJob::StartAsync() { |
| if (!request_) |
| return; |
| url_ = file_system_context_->CrackURL(request_->url()); |
| if (!url_.is_valid()) { |
| file_system_context_->AttemptAutoMountForURLRequest( |
| request_, |
| storage_domain_, |
| base::Bind(&FileSystemDirURLRequestJob::DidAttemptAutoMount, |
| weak_factory_.GetWeakPtr())); |
| return; |
| } |
| if (!file_system_context_->CanServeURLRequest(url_)) { |
| // In incognito mode the API is not usable and there should be no data. |
| if (url_.is_valid() && VirtualPath::IsRootPath(url_.virtual_path())) { |
| // Return an empty directory if the filesystem root is queried. |
| DidReadDirectory(base::File::FILE_OK, |
| std::vector<DirectoryEntry>(), |
| false); |
| return; |
| } |
| NotifyStartError(URLRequestStatus::FromError(net::ERR_FILE_NOT_FOUND)); |
| return; |
| } |
| file_system_context_->operation_runner()->ReadDirectory( |
| url_, base::Bind(&FileSystemDirURLRequestJob::DidReadDirectory, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| void FileSystemDirURLRequestJob::DidAttemptAutoMount(base::File::Error result) { |
| if (result >= 0 && |
| file_system_context_->CrackURL(request_->url()).is_valid()) { |
| StartAsync(); |
| } else { |
| NotifyStartError(URLRequestStatus::FromError(net::ERR_FILE_NOT_FOUND)); |
| } |
| } |
| |
| void FileSystemDirURLRequestJob::DidReadDirectory( |
| base::File::Error result, |
| const std::vector<DirectoryEntry>& entries, |
| bool has_more) { |
| if (result != base::File::FILE_OK) { |
| int rv = net::ERR_FILE_NOT_FOUND; |
| if (result == base::File::FILE_ERROR_INVALID_URL) |
| rv = net::ERR_INVALID_URL; |
| NotifyStartError(URLRequestStatus::FromError(rv)); |
| return; |
| } |
| |
| if (!request_) |
| return; |
| |
| if (data_.empty()) { |
| base::FilePath relative_path = url_.path(); |
| #if defined(OS_POSIX) |
| relative_path = |
| base::FilePath(FILE_PATH_LITERAL("/") + relative_path.value()); |
| #endif |
| const base::string16& title = relative_path.LossyDisplayName(); |
| data_.append(net::GetDirectoryListingHeader(title)); |
| } |
| |
| entries_.insert(entries_.end(), entries.begin(), entries.end()); |
| |
| if (!has_more) { |
| if (entries_.size()) { |
| GetMetadata(0); |
| } else { |
| set_expected_content_size(data_.size()); |
| NotifyHeadersComplete(); |
| } |
| } |
| } |
| |
| void FileSystemDirURLRequestJob::GetMetadata(size_t index) { |
| const DirectoryEntry& entry = entries_[index]; |
| const FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL( |
| url_.origin(), url_.type(), |
| url_.path().Append(base::FilePath(entry.name))); |
| DCHECK(url.is_valid()); |
| file_system_context_->operation_runner()->GetMetadata( |
| url, FileSystemOperation::GET_METADATA_FIELD_SIZE | |
| FileSystemOperation::GET_METADATA_FIELD_LAST_MODIFIED, |
| base::Bind(&FileSystemDirURLRequestJob::DidGetMetadata, |
| weak_factory_.GetWeakPtr(), index)); |
| } |
| |
| void FileSystemDirURLRequestJob::DidGetMetadata( |
| size_t index, |
| base::File::Error result, |
| const base::File::Info& file_info) { |
| if (result != base::File::FILE_OK) { |
| int rv = net::ERR_FILE_NOT_FOUND; |
| if (result == base::File::FILE_ERROR_INVALID_URL) |
| rv = net::ERR_INVALID_URL; |
| NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, rv)); |
| } |
| |
| if (!request_) |
| return; |
| |
| const DirectoryEntry& entry = entries_[index]; |
| const base::string16& name = base::FilePath(entry.name).LossyDisplayName(); |
| data_.append(net::GetDirectoryListingEntry(name, std::string(), |
| entry.is_directory, file_info.size, |
| file_info.last_modified)); |
| |
| if (index < entries_.size() - 1) { |
| GetMetadata(index + 1); |
| } else { |
| set_expected_content_size(data_.size()); |
| NotifyHeadersComplete(); |
| } |
| } |
| |
| } // namespace storage |