ftp_directory_listing_response_delegate.cc revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
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) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using net::FtpDirectoryListingEntry; 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebURLLoader; 27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebURLLoaderClient; 28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebURLResponse; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)using webkit_glue::WebURLResponseExtraDataImpl; 31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)base::string16 ConvertPathToUTF16(const std::string& path) { 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Per RFC 2640, FTP servers should use UTF-8 or its proper subset ASCII, 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // but many old FTP servers use legacy encodings. Try UTF-8 first. 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsStringUTF8(path)) 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return base::UTF8ToUTF16(path); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Try detecting the encoding. The sample is rather small though, so it may 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // fail. 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string encoding; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base::DetectEncoding(path, &encoding) && !encoding.empty()) { 44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::string16 path_utf16; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base::CodepageToUTF16(path, encoding.c_str(), 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::OnStringConversionError::SUBSTITUTE, 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &path_utf16)) { 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return path_utf16; 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Use system native encoding as the last resort. 535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return base::WideToUTF16(base::SysNativeMBToWide(path)); 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace content { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FtpDirectoryListingResponseDelegate::FtpDirectoryListingResponseDelegate( 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebURLLoaderClient* client, 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebURLLoader* loader, 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const WebURLResponse& response) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : client_(client), 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) loader_(loader) { 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (response.extraData()) { 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // extraData can be NULL during tests. 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebURLResponseExtraDataImpl* extra_data = 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<WebURLResponseExtraDataImpl*>(response.extraData()); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extra_data->set_is_ftp_directory_listing(true); 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(response.url()); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FtpDirectoryListingResponseDelegate::OnReceivedData(const char* data, 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int data_len) { 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer_.append(data, data_len); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FtpDirectoryListingResponseDelegate::OnCompletedRequest() { 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<FtpDirectoryListingEntry> entries; 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = net::ParseFtpDirectoryListing(buffer_, base::Time::Now(), &entries); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rv != net::OK) { 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendDataToClient("<script>onListingParsingError();</script>\n"); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < entries.size(); i++) { 885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const FtpDirectoryListingEntry& entry = entries[i]; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Skip the current and parent directory entries in the listing. Our header 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // always includes them. 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (EqualsASCII(entry.name, ".") || EqualsASCII(entry.name, "..")) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_directory = (entry.type == FtpDirectoryListingEntry::DIRECTORY); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 size = entry.size; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (entry.type != FtpDirectoryListingEntry::FILE) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size = 0; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendDataToClient(net::GetDirectoryListingEntry( 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry.name, entry.raw_name, is_directory, size, entry.last_modified)); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FtpDirectoryListingResponseDelegate::Init(const GURL& response_url) { 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::UnescapeRule::Type unescape_rules = net::UnescapeRule::SPACES | 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::UnescapeRule::URL_SPECIAL_CHARS; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string unescaped_path = net::UnescapeURLComponent(response_url.path(), 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unescape_rules); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendDataToClient(net::GetDirectoryListingHeader( 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConvertPathToUTF16(unescaped_path))); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If this isn't top level directory (i.e. the path isn't "/",) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // add a link to the parent directory. 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (response_url.path().length() > 1) { 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendDataToClient(net::GetDirectoryListingEntry( 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::ASCIIToUTF16(".."), std::string(), false, 0, base::Time())); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FtpDirectoryListingResponseDelegate::SendDataToClient( 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& data) { 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_->didReceiveData(loader_, data.data(), data.length(), -1); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} // namespace content 126