1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "webkit/glue/ftp_directory_listing_response_delegate.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <vector>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/i18n/icu_encoding_detection.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/i18n/icu_string_conversions.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/sys_string_conversions.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/time.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/escape.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_errors.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_util.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/ftp/ftp_directory_listing_parser.h"
2072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "third_party/WebKit/Source/WebKit/chromium/public/WebURL.h"
2172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "third_party/WebKit/Source/WebKit/chromium/public/WebURLLoaderClient.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing net::FtpDirectoryListingEntry;
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebURLLoader;
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebURLLoaderClient;
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebURLResponse;
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstring16 ConvertPathToUTF16(const std::string& path) {
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Per RFC 2640, FTP servers should use UTF-8 or its proper subset ASCII,
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // but many old FTP servers use legacy encodings. Try UTF-8 first.
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (IsStringUTF8(path))
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return UTF8ToUTF16(path);
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Try detecting the encoding. The sample is rather small though, so it may
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // fail.
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string encoding;
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (base::DetectEncoding(path, &encoding) && !encoding.empty()) {
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    string16 path_utf16;
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (base::CodepageToUTF16(path, encoding.c_str(),
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              base::OnStringConversionError::SUBSTITUTE,
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              &path_utf16)) {
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return path_utf16;
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Use system native encoding as the last resort.
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return WideToUTF16Hack(base::SysNativeMBToWide(path));
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace webkit_glue {
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochFtpDirectoryListingResponseDelegate::FtpDirectoryListingResponseDelegate(
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    WebURLLoaderClient* client,
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    WebURLLoader* loader,
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const WebURLResponse& response)
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : client_(client),
62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      loader_(loader) {
63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Init(response.url());
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid FtpDirectoryListingResponseDelegate::OnReceivedData(const char* data,
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                         int data_len) {
68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  buffer_.append(data, data_len);
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid FtpDirectoryListingResponseDelegate::OnCompletedRequest() {
72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<FtpDirectoryListingEntry> entries;
73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int rv = net::ParseFtpDirectoryListing(buffer_, base::Time::Now(), &entries);
74ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (rv != net::OK) {
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SendDataToClient("<script>onListingParsingError();</script>\n");
76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < entries.size(); i++) {
79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    FtpDirectoryListingEntry entry = entries[i];
80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Skip the current and parent directory entries in the listing. Our header
82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // always includes them.
83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (EqualsASCII(entry.name, ".") || EqualsASCII(entry.name, ".."))
84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      continue;
85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    bool is_directory = (entry.type == FtpDirectoryListingEntry::DIRECTORY);
87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int64 size = entry.size;
88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (entry.type != FtpDirectoryListingEntry::FILE)
89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      size = 0;
90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SendDataToClient(net::GetDirectoryListingEntry(
91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        entry.name, entry.raw_name, is_directory, size, entry.last_modified));
92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FtpDirectoryListingResponseDelegate::Init(const GURL& response_url) {
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UnescapeRule::Type unescape_rules = UnescapeRule::SPACES |
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      UnescapeRule::URL_SPECIAL_CHARS;
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string unescaped_path = UnescapeURLComponent(response_url.path(),
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                    unescape_rules);
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SendDataToClient(net::GetDirectoryListingHeader(
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       ConvertPathToUTF16(unescaped_path)));
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If this isn't top level directory (i.e. the path isn't "/",)
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // add a link to the parent directory.
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (response_url.path().length() > 1) {
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SendDataToClient(net::GetDirectoryListingEntry(
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ASCIIToUTF16(".."), std::string(), false, 0, base::Time()));
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid FtpDirectoryListingResponseDelegate::SendDataToClient(
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& data) {
113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  client_->didReceiveData(loader_, data.data(), data.length(), -1);
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace webkit_glue
117