Home | History | Annotate | Download | only in ftp
      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