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. 4 5 #include "net/ftp/ftp_directory_listing_parser.h" 6 7 #include "base/i18n/icu_encoding_detection.h" 8 #include "base/i18n/icu_string_conversions.h" 9 #include "base/stl_util-inl.h" 10 #include "base/string_split.h" 11 #include "base/string_util.h" 12 #include "net/base/net_errors.h" 13 #include "net/ftp/ftp_directory_listing_parser_ls.h" 14 #include "net/ftp/ftp_directory_listing_parser_netware.h" 15 #include "net/ftp/ftp_directory_listing_parser_vms.h" 16 #include "net/ftp/ftp_directory_listing_parser_windows.h" 17 #include "net/ftp/ftp_server_type_histograms.h" 18 19 namespace net { 20 21 namespace { 22 23 // Fills in |raw_name| for all |entries| using |encoding|. Returns network 24 // error code. 25 int FillInRawName(const std::string& encoding, 26 std::vector<FtpDirectoryListingEntry>* entries) { 27 for (size_t i = 0; i < entries->size(); i++) { 28 if (!base::UTF16ToCodepage(entries->at(i).name, encoding.c_str(), 29 base::OnStringConversionError::FAIL, 30 &entries->at(i).raw_name)) { 31 return ERR_ENCODING_CONVERSION_FAILED; 32 } 33 } 34 35 return OK; 36 } 37 38 // Parses |text| as an FTP directory listing. Fills in |entries| 39 // and |server_type| and returns network error code. 40 int ParseListing(const string16& text, 41 const std::string& encoding, 42 const base::Time& current_time, 43 std::vector<FtpDirectoryListingEntry>* entries, 44 FtpServerType* server_type) { 45 std::vector<string16> lines; 46 base::SplitString(text, '\n', &lines); 47 48 // TODO(phajdan.jr): Use a table of callbacks instead of repeating code. 49 50 entries->clear(); 51 if (ParseFtpDirectoryListingLs(lines, current_time, entries)) { 52 *server_type = SERVER_LS; 53 return FillInRawName(encoding, entries); 54 } 55 56 entries->clear(); 57 if (ParseFtpDirectoryListingWindows(lines, entries)) { 58 *server_type = SERVER_WINDOWS; 59 return FillInRawName(encoding, entries); 60 } 61 62 entries->clear(); 63 if (ParseFtpDirectoryListingVms(lines, entries)) { 64 *server_type = SERVER_VMS; 65 return FillInRawName(encoding, entries); 66 } 67 68 entries->clear(); 69 if (ParseFtpDirectoryListingNetware(lines, current_time, entries)) { 70 *server_type = SERVER_NETWARE; 71 return FillInRawName(encoding, entries); 72 } 73 74 entries->clear(); 75 return ERR_UNRECOGNIZED_FTP_DIRECTORY_LISTING_FORMAT; 76 } 77 78 // Detects encoding of |text| and parses it as an FTP directory listing. 79 // Fills in |entries| and |server_type| and returns network error code. 80 int DecodeAndParse(const std::string& text, 81 const base::Time& current_time, 82 std::vector<FtpDirectoryListingEntry>* entries, 83 FtpServerType* server_type) { 84 std::vector<std::string> encodings; 85 if (!base::DetectAllEncodings(text, &encodings)) 86 return ERR_ENCODING_DETECTION_FAILED; 87 88 // Use first encoding that can be used to decode the text. 89 for (size_t i = 0; i < encodings.size(); i++) { 90 string16 converted_text; 91 if (base::CodepageToUTF16(text, 92 encodings[i].c_str(), 93 base::OnStringConversionError::FAIL, 94 &converted_text)) { 95 int rv = ParseListing(converted_text, 96 encodings[i], 97 current_time, 98 entries, 99 server_type); 100 if (rv == OK) 101 return rv; 102 } 103 } 104 105 entries->clear(); 106 *server_type = SERVER_UNKNOWN; 107 return ERR_UNRECOGNIZED_FTP_DIRECTORY_LISTING_FORMAT; 108 } 109 110 } // namespace 111 112 FtpDirectoryListingEntry::FtpDirectoryListingEntry() { 113 } 114 115 int ParseFtpDirectoryListing(const std::string& text, 116 const base::Time& current_time, 117 std::vector<FtpDirectoryListingEntry>* entries) { 118 FtpServerType server_type = SERVER_UNKNOWN; 119 int rv = DecodeAndParse(text, current_time, entries, &server_type); 120 UpdateFtpServerTypeHistograms(server_type); 121 return rv; 122 } 123 124 } // namespace net 125