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