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