Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / ftp / ftp_directory_listing_parser.cc
bloba1aabf3f971f39fe6d898b7681e97ae600cc99e1
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/ftp/ftp_directory_listing_parser.h"
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/i18n/icu_encoding_detection.h"
10 #include "base/i18n/icu_string_conversions.h"
11 #include "base/stl_util.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/string_split.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "net/base/net_errors.h"
16 #include "net/ftp/ftp_directory_listing_parser_ls.h"
17 #include "net/ftp/ftp_directory_listing_parser_vms.h"
18 #include "net/ftp/ftp_directory_listing_parser_windows.h"
19 #include "net/ftp/ftp_server_type_histograms.h"
21 namespace net {
23 namespace {
25 // Fills in |raw_name| for all |entries| using |encoding|. Returns network
26 // error code.
27 int FillInRawName(const std::string& encoding,
28 std::vector<FtpDirectoryListingEntry>* entries) {
29 for (size_t i = 0; i < entries->size(); i++) {
30 if (!base::UTF16ToCodepage(entries->at(i).name, encoding.c_str(),
31 base::OnStringConversionError::FAIL,
32 &entries->at(i).raw_name)) {
33 return ERR_ENCODING_CONVERSION_FAILED;
37 return OK;
40 // Parses |text| as an FTP directory listing. Fills in |entries|
41 // and |server_type| and returns network error code.
42 int ParseListing(const base::string16& text,
43 const base::string16& newline_separator,
44 const std::string& encoding,
45 const base::Time& current_time,
46 std::vector<FtpDirectoryListingEntry>* entries,
47 FtpServerType* server_type) {
48 std::vector<base::string16> lines;
49 base::SplitStringUsingSubstr(text, newline_separator, &lines);
51 struct {
52 base::Callback<bool(void)> callback;
53 FtpServerType server_type;
54 } parsers[] = {
56 base::Bind(&ParseFtpDirectoryListingLs, lines, current_time, entries),
57 SERVER_LS
60 base::Bind(&ParseFtpDirectoryListingWindows, lines, entries),
61 SERVER_WINDOWS
64 base::Bind(&ParseFtpDirectoryListingVms, lines, entries),
65 SERVER_VMS
69 for (size_t i = 0; i < arraysize(parsers); i++) {
70 entries->clear();
71 if (parsers[i].callback.Run()) {
72 *server_type = parsers[i].server_type;
73 return FillInRawName(encoding, entries);
77 entries->clear();
78 return ERR_UNRECOGNIZED_FTP_DIRECTORY_LISTING_FORMAT;
81 // Detects encoding of |text| and parses it as an FTP directory listing.
82 // Fills in |entries| and |server_type| and returns network error code.
83 int DecodeAndParse(const std::string& text,
84 const base::Time& current_time,
85 std::vector<FtpDirectoryListingEntry>* entries,
86 FtpServerType* server_type) {
87 const char* const kNewlineSeparators[] = { "\n", "\r\n" };
89 std::vector<std::string> encodings;
90 if (!base::DetectAllEncodings(text, &encodings))
91 return ERR_ENCODING_DETECTION_FAILED;
93 // Use first encoding that can be used to decode the text.
94 for (size_t i = 0; i < encodings.size(); i++) {
95 base::string16 converted_text;
96 if (base::CodepageToUTF16(text,
97 encodings[i].c_str(),
98 base::OnStringConversionError::FAIL,
99 &converted_text)) {
100 for (size_t j = 0; j < arraysize(kNewlineSeparators); j++) {
101 int rv = ParseListing(converted_text,
102 base::ASCIIToUTF16(kNewlineSeparators[j]),
103 encodings[i],
104 current_time,
105 entries,
106 server_type);
107 if (rv == OK)
108 return rv;
113 entries->clear();
114 *server_type = SERVER_UNKNOWN;
115 return ERR_UNRECOGNIZED_FTP_DIRECTORY_LISTING_FORMAT;
118 } // namespace
120 FtpDirectoryListingEntry::FtpDirectoryListingEntry()
121 : type(UNKNOWN),
122 size(-1) {
125 int ParseFtpDirectoryListing(const std::string& text,
126 const base::Time& current_time,
127 std::vector<FtpDirectoryListingEntry>* entries) {
128 FtpServerType server_type = SERVER_UNKNOWN;
129 int rv = DecodeAndParse(text, current_time, entries, &server_type);
130 UpdateFtpServerTypeHistograms(server_type);
131 return rv;
134 } // namespace net