ftp_directory_listing_response_delegate.cc revision 116680a4aac90f2aa7413d9095a592090648e557
1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 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) 5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/child/ftp_directory_listing_response_delegate.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/icu_encoding_detection.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/icu_string_conversions.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 125e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h" 13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/sys_string_conversions.h" 14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/escape.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/ftp/ftp_directory_listing_parser.h" 20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/WebKit/public/platform/WebURL.h" 21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/WebKit/public/platform/WebURLLoaderClient.h" 22ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "webkit/child/weburlresponse_extradata_impl.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebURLLoader; 25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebURLLoaderClient; 26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebURLResponse; 27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)using net::FtpDirectoryListingEntry; 28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)using webkit_glue::WebURLResponseExtraDataImpl; 29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)base::string16 ConvertPathToUTF16(const std::string& path) { 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Per RFC 2640, FTP servers should use UTF-8 or its proper subset ASCII, 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // but many old FTP servers use legacy encodings. Try UTF-8 first. 35010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (base::IsStringUTF8(path)) 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return base::UTF8ToUTF16(path); 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Try detecting the encoding. The sample is rather small though, so it may 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // fail. 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string encoding; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base::DetectEncoding(path, &encoding) && !encoding.empty()) { 42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::string16 path_utf16; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base::CodepageToUTF16(path, encoding.c_str(), 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::OnStringConversionError::SUBSTITUTE, 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &path_utf16)) { 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return path_utf16; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Use system native encoding as the last resort. 515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return base::WideToUTF16(base::SysNativeMBToWide(path)); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace content { 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FtpDirectoryListingResponseDelegate::FtpDirectoryListingResponseDelegate( 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebURLLoaderClient* client, 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebURLLoader* loader, 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const WebURLResponse& response) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : client_(client), 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) loader_(loader) { 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (response.extraData()) { 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // extraData can be NULL during tests. 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebURLResponseExtraDataImpl* extra_data = 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<WebURLResponseExtraDataImpl*>(response.extraData()); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extra_data->set_is_ftp_directory_listing(true); 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(response.url()); 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void FtpDirectoryListingResponseDelegate::Cancel() { 74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_ = NULL; 75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) loader_ = NULL; 76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FtpDirectoryListingResponseDelegate::OnReceivedData(const char* data, 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int data_len) { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer_.append(data, data_len); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FtpDirectoryListingResponseDelegate::OnCompletedRequest() { 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<FtpDirectoryListingEntry> entries; 85116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch int rv = -1; 86116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#if !defined(DISABLE_FTP_SUPPORT) 87116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch rv = net::ParseFtpDirectoryListing(buffer_, base::Time::Now(), &entries); 88116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rv != net::OK) { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendDataToClient("<script>onListingParsingError();</script>\n"); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < entries.size(); i++) { 945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const FtpDirectoryListingEntry& entry = entries[i]; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Skip the current and parent directory entries in the listing. Our header 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // always includes them. 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (EqualsASCII(entry.name, ".") || EqualsASCII(entry.name, "..")) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_directory = (entry.type == FtpDirectoryListingEntry::DIRECTORY); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 size = entry.size; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (entry.type != FtpDirectoryListingEntry::FILE) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size = 0; 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendDataToClient(net::GetDirectoryListingEntry( 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry.name, entry.raw_name, is_directory, size, entry.last_modified)); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FtpDirectoryListingResponseDelegate::Init(const GURL& response_url) { 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::UnescapeRule::Type unescape_rules = net::UnescapeRule::SPACES | 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::UnescapeRule::URL_SPECIAL_CHARS; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string unescaped_path = net::UnescapeURLComponent(response_url.path(), 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unescape_rules); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendDataToClient(net::GetDirectoryListingHeader( 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConvertPathToUTF16(unescaped_path))); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If this isn't top level directory (i.e. the path isn't "/",) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // add a link to the parent directory. 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (response_url.path().length() > 1) { 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendDataToClient(net::GetDirectoryListingEntry( 1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::ASCIIToUTF16(".."), std::string(), false, 0, base::Time())); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FtpDirectoryListingResponseDelegate::SendDataToClient( 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& data) { 128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (client_) 129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_->didReceiveData(loader_, data.data(), data.length(), -1); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} // namespace content 133