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_netware.h"
18 #include "net/ftp/ftp_directory_listing_parser_os2.h"
19 #include "net/ftp/ftp_directory_listing_parser_vms.h"
20 #include "net/ftp/ftp_directory_listing_parser_windows.h"
21 #include "net/ftp/ftp_server_type_histograms.h"
27 // Fills in |raw_name| for all |entries| using |encoding|. Returns network
29 int FillInRawName(const std::string
& encoding
,
30 std::vector
<FtpDirectoryListingEntry
>* entries
) {
31 for (size_t i
= 0; i
< entries
->size(); i
++) {
32 if (!base::UTF16ToCodepage(entries
->at(i
).name
, encoding
.c_str(),
33 base::OnStringConversionError::FAIL
,
34 &entries
->at(i
).raw_name
)) {
35 return ERR_ENCODING_CONVERSION_FAILED
;
42 // Parses |text| as an FTP directory listing. Fills in |entries|
43 // and |server_type| and returns network error code.
44 int ParseListing(const base::string16
& text
,
45 const base::string16
& newline_separator
,
46 const std::string
& encoding
,
47 const base::Time
& current_time
,
48 std::vector
<FtpDirectoryListingEntry
>* entries
,
49 FtpServerType
* server_type
) {
50 std::vector
<base::string16
> lines
;
51 base::SplitStringUsingSubstr(text
, newline_separator
, &lines
);
54 base::Callback
<bool(void)> callback
;
55 FtpServerType server_type
;
58 base::Bind(&ParseFtpDirectoryListingLs
, lines
, current_time
, entries
),
62 base::Bind(&ParseFtpDirectoryListingWindows
, lines
, entries
),
66 base::Bind(&ParseFtpDirectoryListingVms
, lines
, entries
),
70 base::Bind(&ParseFtpDirectoryListingNetware
,
71 lines
, current_time
, entries
),
75 base::Bind(&ParseFtpDirectoryListingOS2
, lines
, entries
),
80 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(parsers
); i
++) {
82 if (parsers
[i
].callback
.Run()) {
83 *server_type
= parsers
[i
].server_type
;
84 return FillInRawName(encoding
, entries
);
89 return ERR_UNRECOGNIZED_FTP_DIRECTORY_LISTING_FORMAT
;
92 // Detects encoding of |text| and parses it as an FTP directory listing.
93 // Fills in |entries| and |server_type| and returns network error code.
94 int DecodeAndParse(const std::string
& text
,
95 const base::Time
& current_time
,
96 std::vector
<FtpDirectoryListingEntry
>* entries
,
97 FtpServerType
* server_type
) {
98 const char* kNewlineSeparators
[] = { "\n", "\r\n" };
100 std::vector
<std::string
> encodings
;
101 if (!base::DetectAllEncodings(text
, &encodings
))
102 return ERR_ENCODING_DETECTION_FAILED
;
104 // Use first encoding that can be used to decode the text.
105 for (size_t i
= 0; i
< encodings
.size(); i
++) {
106 base::string16 converted_text
;
107 if (base::CodepageToUTF16(text
,
108 encodings
[i
].c_str(),
109 base::OnStringConversionError::FAIL
,
111 for (size_t j
= 0; j
< arraysize(kNewlineSeparators
); j
++) {
112 int rv
= ParseListing(converted_text
,
113 base::ASCIIToUTF16(kNewlineSeparators
[j
]),
125 *server_type
= SERVER_UNKNOWN
;
126 return ERR_UNRECOGNIZED_FTP_DIRECTORY_LISTING_FORMAT
;
131 FtpDirectoryListingEntry::FtpDirectoryListingEntry()
136 int ParseFtpDirectoryListing(const std::string
& text
,
137 const base::Time
& current_time
,
138 std::vector
<FtpDirectoryListingEntry
>* entries
) {
139 FtpServerType server_type
= SERVER_UNKNOWN
;
140 int rv
= DecodeAndParse(text
, current_time
, entries
, &server_type
);
141 UpdateFtpServerTypeHistograms(server_type
);