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