1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "webkit/glue/ftp_directory_listing_response_delegate.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <vector> 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/i18n/icu_encoding_detection.h" 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/i18n/icu_string_conversions.h" 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h" 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h" 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/sys_string_conversions.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h" 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/time.h" 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/escape.h" 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_errors.h" 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_util.h" 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/ftp/ftp_directory_listing_parser.h" 2072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "third_party/WebKit/Source/WebKit/chromium/public/WebURL.h" 2172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "third_party/WebKit/Source/WebKit/chromium/public/WebURLLoaderClient.h" 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing net::FtpDirectoryListingEntry; 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebURLLoader; 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebURLLoaderClient; 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebURLResponse; 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstring16 ConvertPathToUTF16(const std::string& path) { 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Per RFC 2640, FTP servers should use UTF-8 or its proper subset ASCII, 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // but many old FTP servers use legacy encodings. Try UTF-8 first. 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (IsStringUTF8(path)) 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return UTF8ToUTF16(path); 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Try detecting the encoding. The sample is rather small though, so it may 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // fail. 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string encoding; 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (base::DetectEncoding(path, &encoding) && !encoding.empty()) { 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch string16 path_utf16; 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (base::CodepageToUTF16(path, encoding.c_str(), 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch base::OnStringConversionError::SUBSTITUTE, 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &path_utf16)) { 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return path_utf16; 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Use system native encoding as the last resort. 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return WideToUTF16Hack(base::SysNativeMBToWide(path)); 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace webkit_glue { 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochFtpDirectoryListingResponseDelegate::FtpDirectoryListingResponseDelegate( 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WebURLLoaderClient* client, 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WebURLLoader* loader, 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const WebURLResponse& response) 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : client_(client), 62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen loader_(loader) { 63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Init(response.url()); 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid FtpDirectoryListingResponseDelegate::OnReceivedData(const char* data, 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int data_len) { 68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen buffer_.append(data, data_len); 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid FtpDirectoryListingResponseDelegate::OnCompletedRequest() { 72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::vector<FtpDirectoryListingEntry> entries; 73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen int rv = net::ParseFtpDirectoryListing(buffer_, base::Time::Now(), &entries); 74ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (rv != net::OK) { 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SendDataToClient("<script>onListingParsingError();</script>\n"); 76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return; 77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen for (size_t i = 0; i < entries.size(); i++) { 79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FtpDirectoryListingEntry entry = entries[i]; 80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Skip the current and parent directory entries in the listing. Our header 82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // always includes them. 83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (EqualsASCII(entry.name, ".") || EqualsASCII(entry.name, "..")) 84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen continue; 85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool is_directory = (entry.type == FtpDirectoryListingEntry::DIRECTORY); 87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen int64 size = entry.size; 88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (entry.type != FtpDirectoryListingEntry::FILE) 89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen size = 0; 90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen SendDataToClient(net::GetDirectoryListingEntry( 91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen entry.name, entry.raw_name, is_directory, size, entry.last_modified)); 92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FtpDirectoryListingResponseDelegate::Init(const GURL& response_url) { 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UnescapeRule::Type unescape_rules = UnescapeRule::SPACES | 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UnescapeRule::URL_SPECIAL_CHARS; 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string unescaped_path = UnescapeURLComponent(response_url.path(), 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch unescape_rules); 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SendDataToClient(net::GetDirectoryListingHeader( 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ConvertPathToUTF16(unescaped_path))); 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If this isn't top level directory (i.e. the path isn't "/",) 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // add a link to the parent directory. 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (response_url.path().length() > 1) { 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SendDataToClient(net::GetDirectoryListingEntry( 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ASCIIToUTF16(".."), std::string(), false, 0, base::Time())); 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid FtpDirectoryListingResponseDelegate::SendDataToClient( 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string& data) { 113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen client_->didReceiveData(loader_, data.data(), data.length(), -1); 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace webkit_glue 117