• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
FillInRawName(const std::string & encoding,std::vector<FtpDirectoryListingEntry> * entries)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.
ParseListing(const string16 & text,const std::string & encoding,const base::Time & current_time,std::vector<FtpDirectoryListingEntry> * entries,FtpServerType * server_type)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.
DecodeAndParse(const std::string & text,const base::Time & current_time,std::vector<FtpDirectoryListingEntry> * entries,FtpServerType * server_type)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 
FtpDirectoryListingEntry()112 FtpDirectoryListingEntry::FtpDirectoryListingEntry() {
113 }
114 
ParseFtpDirectoryListing(const std::string & text,const base::Time & current_time,std::vector<FtpDirectoryListingEntry> * entries)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