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