summaryrefslogtreecommitdiff
path: root/chromium/net/ftp/ftp_directory_listing_parser.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/ftp/ftp_directory_listing_parser.cc')
-rw-r--r--chromium/net/ftp/ftp_directory_listing_parser.cc145
1 files changed, 145 insertions, 0 deletions
diff --git a/chromium/net/ftp/ftp_directory_listing_parser.cc b/chromium/net/ftp/ftp_directory_listing_parser.cc
new file mode 100644
index 00000000000..03b77bb8205
--- /dev/null
+++ b/chromium/net/ftp/ftp_directory_listing_parser.cc
@@ -0,0 +1,145 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/ftp/ftp_directory_listing_parser.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/i18n/icu_encoding_detection.h"
+#include "base/i18n/icu_string_conversions.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "base/strings/string_split.h"
+#include "base/strings/utf_string_conversions.h"
+#include "net/base/net_errors.h"
+#include "net/ftp/ftp_directory_listing_parser_ls.h"
+#include "net/ftp/ftp_directory_listing_parser_netware.h"
+#include "net/ftp/ftp_directory_listing_parser_os2.h"
+#include "net/ftp/ftp_directory_listing_parser_vms.h"
+#include "net/ftp/ftp_directory_listing_parser_windows.h"
+#include "net/ftp/ftp_server_type_histograms.h"
+
+namespace net {
+
+namespace {
+
+// Fills in |raw_name| for all |entries| using |encoding|. Returns network
+// error code.
+int FillInRawName(const std::string& encoding,
+ std::vector<FtpDirectoryListingEntry>* entries) {
+ for (size_t i = 0; i < entries->size(); i++) {
+ if (!base::UTF16ToCodepage(entries->at(i).name, encoding.c_str(),
+ base::OnStringConversionError::FAIL,
+ &entries->at(i).raw_name)) {
+ return ERR_ENCODING_CONVERSION_FAILED;
+ }
+ }
+
+ return OK;
+}
+
+// Parses |text| as an FTP directory listing. Fills in |entries|
+// and |server_type| and returns network error code.
+int ParseListing(const base::string16& text,
+ const base::string16& newline_separator,
+ const std::string& encoding,
+ const base::Time& current_time,
+ std::vector<FtpDirectoryListingEntry>* entries,
+ FtpServerType* server_type) {
+ std::vector<base::string16> lines;
+ base::SplitStringUsingSubstr(text, newline_separator, &lines);
+
+ struct {
+ base::Callback<bool(void)> callback;
+ FtpServerType server_type;
+ } parsers[] = {
+ {
+ base::Bind(&ParseFtpDirectoryListingLs, lines, current_time, entries),
+ SERVER_LS
+ },
+ {
+ base::Bind(&ParseFtpDirectoryListingWindows, lines, entries),
+ SERVER_WINDOWS
+ },
+ {
+ base::Bind(&ParseFtpDirectoryListingVms, lines, entries),
+ SERVER_VMS
+ },
+ {
+ base::Bind(&ParseFtpDirectoryListingNetware,
+ lines, current_time, entries),
+ SERVER_NETWARE
+ },
+ {
+ base::Bind(&ParseFtpDirectoryListingOS2, lines, entries),
+ SERVER_OS2
+ }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(parsers); i++) {
+ entries->clear();
+ if (parsers[i].callback.Run()) {
+ *server_type = parsers[i].server_type;
+ return FillInRawName(encoding, entries);
+ }
+ }
+
+ entries->clear();
+ return ERR_UNRECOGNIZED_FTP_DIRECTORY_LISTING_FORMAT;
+}
+
+// Detects encoding of |text| and parses it as an FTP directory listing.
+// Fills in |entries| and |server_type| and returns network error code.
+int DecodeAndParse(const std::string& text,
+ const base::Time& current_time,
+ std::vector<FtpDirectoryListingEntry>* entries,
+ FtpServerType* server_type) {
+ const char* kNewlineSeparators[] = { "\n", "\r\n" };
+
+ std::vector<std::string> encodings;
+ if (!base::DetectAllEncodings(text, &encodings))
+ return ERR_ENCODING_DETECTION_FAILED;
+
+ // Use first encoding that can be used to decode the text.
+ for (size_t i = 0; i < encodings.size(); i++) {
+ base::string16 converted_text;
+ if (base::CodepageToUTF16(text,
+ encodings[i].c_str(),
+ base::OnStringConversionError::FAIL,
+ &converted_text)) {
+ for (size_t j = 0; j < arraysize(kNewlineSeparators); j++) {
+ int rv = ParseListing(converted_text,
+ ASCIIToUTF16(kNewlineSeparators[j]),
+ encodings[i],
+ current_time,
+ entries,
+ server_type);
+ if (rv == OK)
+ return rv;
+ }
+ }
+ }
+
+ entries->clear();
+ *server_type = SERVER_UNKNOWN;
+ return ERR_UNRECOGNIZED_FTP_DIRECTORY_LISTING_FORMAT;
+}
+
+} // namespace
+
+FtpDirectoryListingEntry::FtpDirectoryListingEntry()
+ : type(UNKNOWN),
+ size(-1) {
+}
+
+int ParseFtpDirectoryListing(const std::string& text,
+ const base::Time& current_time,
+ std::vector<FtpDirectoryListingEntry>* entries) {
+ FtpServerType server_type = SERVER_UNKNOWN;
+ int rv = DecodeAndParse(text, current_time, entries, &server_type);
+ UpdateFtpServerTypeHistograms(server_type);
+ return rv;
+}
+
+} // namespace net