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"
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"
25 // Fills in |raw_name| for all |entries| using |encoding|. Returns network
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
;
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
);
52 base::Callback
<bool(void)> callback
;
53 FtpServerType server_type
;
56 base::Bind(&ParseFtpDirectoryListingLs
, lines
, current_time
, entries
),
60 base::Bind(&ParseFtpDirectoryListingWindows
, lines
, entries
),
64 base::Bind(&ParseFtpDirectoryListingVms
, lines
, entries
),
69 for (size_t i
= 0; i
< arraysize(parsers
); i
++) {
71 if (parsers
[i
].callback
.Run()) {
72 *server_type
= parsers
[i
].server_type
;
73 return FillInRawName(encoding
, entries
);
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
,
98 base::OnStringConversionError::FAIL
,
100 for (size_t j
= 0; j
< arraysize(kNewlineSeparators
); j
++) {
101 int rv
= ParseListing(converted_text
,
102 base::ASCIIToUTF16(kNewlineSeparators
[j
]),
114 *server_type
= SERVER_UNKNOWN
;
115 return ERR_UNRECOGNIZED_FTP_DIRECTORY_LISTING_FORMAT
;
120 FtpDirectoryListingEntry::FtpDirectoryListingEntry()
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
);