ftp_directory_listing_response_delegate.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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" 165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "content/child/weburlresponse_extradata_impl.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/escape.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/ftp/ftp_directory_listing_parser.h" 21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/WebKit/public/platform/WebURL.h" 22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/WebKit/public/platform/WebURLLoaderClient.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) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)base::string16 ConvertPathToUTF16(const std::string& path) { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Per RFC 2640, FTP servers should use UTF-8 or its proper subset ASCII, 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // but many old FTP servers use legacy encodings. Try UTF-8 first. 34010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (base::IsStringUTF8(path)) 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return base::UTF8ToUTF16(path); 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Try detecting the encoding. The sample is rather small though, so it may 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // fail. 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string encoding; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base::DetectEncoding(path, &encoding) && !encoding.empty()) { 41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::string16 path_utf16; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base::CodepageToUTF16(path, encoding.c_str(), 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::OnStringConversionError::SUBSTITUTE, 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &path_utf16)) { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return path_utf16; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Use system native encoding as the last resort. 505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return base::WideToUTF16(base::SysNativeMBToWide(path)); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace content { 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FtpDirectoryListingResponseDelegate::FtpDirectoryListingResponseDelegate( 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebURLLoaderClient* client, 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebURLLoader* loader, 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const WebURLResponse& response) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : client_(client), 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) loader_(loader) { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (response.extraData()) { 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // extraData can be NULL during tests. 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebURLResponseExtraDataImpl* extra_data = 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<WebURLResponseExtraDataImpl*>(response.extraData()); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extra_data->set_is_ftp_directory_listing(true); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(response.url()); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void FtpDirectoryListingResponseDelegate::Cancel() { 73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_ = NULL; 74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) loader_ = NULL; 75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FtpDirectoryListingResponseDelegate::OnReceivedData(const char* data, 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int data_len) { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer_.append(data, data_len); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FtpDirectoryListingResponseDelegate::OnCompletedRequest() { 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<FtpDirectoryListingEntry> entries; 84116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch int rv = -1; 85116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#if !defined(DISABLE_FTP_SUPPORT) 86116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch rv = net::ParseFtpDirectoryListing(buffer_, base::Time::Now(), &entries); 87116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rv != net::OK) { 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendDataToClient("<script>onListingParsingError();</script>\n"); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < entries.size(); i++) { 935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const FtpDirectoryListingEntry& entry = entries[i]; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Skip the current and parent directory entries in the listing. Our header 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // always includes them. 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (EqualsASCII(entry.name, ".") || EqualsASCII(entry.name, "..")) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_directory = (entry.type == FtpDirectoryListingEntry::DIRECTORY); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 size = entry.size; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (entry.type != FtpDirectoryListingEntry::FILE) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size = 0; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendDataToClient(net::GetDirectoryListingEntry( 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry.name, entry.raw_name, is_directory, size, entry.last_modified)); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FtpDirectoryListingResponseDelegate::Init(const GURL& response_url) { 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::UnescapeRule::Type unescape_rules = net::UnescapeRule::SPACES | 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::UnescapeRule::URL_SPECIAL_CHARS; 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string unescaped_path = net::UnescapeURLComponent(response_url.path(), 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unescape_rules); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendDataToClient(net::GetDirectoryListingHeader( 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConvertPathToUTF16(unescaped_path))); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If this isn't top level directory (i.e. the path isn't "/",) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // add a link to the parent directory. 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (response_url.path().length() > 1) { 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendDataToClient(net::GetDirectoryListingEntry( 1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::ASCIIToUTF16(".."), std::string(), false, 0, base::Time())); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FtpDirectoryListingResponseDelegate::SendDataToClient( 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& data) { 127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (client_) 128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_->didReceiveData(loader_, data.data(), data.length(), -1); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} // namespace content 132