| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this |
| 2 // source code is governed by a BSD-style license that can be found in the | 2 // source code is governed by a BSD-style license that can be found in the |
| 3 // LICENSE file. | 3 // LICENSE file. |
| 4 | 4 |
| 5 #include "net/ftp/ftp_directory_listing_parser_ls.h" | 5 #include "net/ftp/ftp_directory_listing_parser_ls.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
| 10 #include "net/ftp/ftp_util.h" | 10 #include "net/ftp/ftp_util.h" |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 50 last = i; | 50 last = i; |
| 51 if (++columns_so_far == columns) | 51 if (++columns_so_far == columns) |
| 52 break; | 52 break; |
| 53 } | 53 } |
| 54 } | 54 } |
| 55 string16 result(text.substr(last)); | 55 string16 result(text.substr(last)); |
| 56 TrimWhitespace(result, TRIM_ALL, &result); | 56 TrimWhitespace(result, TRIM_ALL, &result); |
| 57 return result; | 57 return result; |
| 58 } | 58 } |
| 59 | 59 |
| 60 bool UnixDateListingToTime(const std::vector<string16>& columns, | |
| 61 base::Time* time) { | |
| 62 DCHECK_LE(9U, columns.size()); | |
| 63 | |
| 64 base::Time::Exploded time_exploded = { 0 }; | |
| 65 | |
| 66 if (!net::FtpUtil::ThreeLetterMonthToNumber(columns[5], &time_exploded.month)) | |
| 67 return false; | |
| 68 | |
| 69 if (!StringToInt(columns[6], &time_exploded.day_of_month)) | |
| 70 return false; | |
| 71 | |
| 72 if (!StringToInt(columns[7], &time_exploded.year)) { | |
| 73 // Maybe it's time. Does it look like time (MM:HH)? | |
| 74 if (columns[7].length() != 5 || columns[7][2] != ':') | |
| 75 return false; | |
| 76 | |
| 77 if (!StringToInt(columns[7].substr(0, 2), &time_exploded.hour)) | |
| 78 return false; | |
| 79 | |
| 80 if (!StringToInt(columns[7].substr(3, 2), &time_exploded.minute)) | |
| 81 return false; | |
| 82 | |
| 83 // Use current year. | |
| 84 base::Time::Exploded now_exploded; | |
| 85 base::Time::Now().LocalExplode(&now_exploded); | |
| 86 time_exploded.year = now_exploded.year; | |
| 87 } | |
| 88 | |
| 89 // We don't know the time zone of the server, so just use local time. | |
| 90 *time = base::Time::FromLocalExploded(time_exploded); | |
| 91 return true; | |
| 92 } | |
| 93 | |
| 94 } // namespace | 60 } // namespace |
| 95 | 61 |
| 96 namespace net { | 62 namespace net { |
| 97 | 63 |
| 98 FtpDirectoryListingParserLs::FtpDirectoryListingParserLs() | 64 FtpDirectoryListingParserLs::FtpDirectoryListingParserLs() |
| 99 : received_nonempty_line_(false) { | 65 : received_nonempty_line_(false), |
| 66 received_total_line_(false) { |
| 100 } | 67 } |
| 101 | 68 |
| 102 bool FtpDirectoryListingParserLs::ConsumeLine(const string16& line) { | 69 bool FtpDirectoryListingParserLs::ConsumeLine(const string16& line) { |
| 103 if (StartsWith(line, ASCIIToUTF16("total "), true) || | |
| 104 StartsWith(line, ASCIIToUTF16("Gesamt "), true)) { | |
| 105 // Some FTP servers put a "total n" line at the beginning of the listing | |
| 106 // (n is an integer). Allow such a line, but only once, and only if it's | |
| 107 // the first non-empty line. | |
| 108 // | |
| 109 // Note: "Gesamt" is a German word for "total". The case is important here: | |
| 110 // for "ls -l" style listings, "total" will be lowercase, and Gesamt will be | |
| 111 // capitalized. This helps us distinguish that from a VMS-style listing, | |
| 112 // which would use "Total" (note the uppercase first letter). | |
| 113 | |
| 114 if (received_nonempty_line_) | |
| 115 return false; | |
| 116 | |
| 117 received_nonempty_line_ = true; | |
| 118 return true; | |
| 119 } | |
| 120 if (line.empty() && !received_nonempty_line_) { | 70 if (line.empty() && !received_nonempty_line_) { |
| 121 // Allow empty lines only at the beginning of the listing. For example VMS | 71 // Allow empty lines only at the beginning of the listing. For example VMS |
| 122 // systems in Unix emulation mode add an empty line before the first listing | 72 // systems in Unix emulation mode add an empty line before the first listing |
| 123 // entry. | 73 // entry. |
| 124 return true; | 74 return true; |
| 125 } | 75 } |
| 126 received_nonempty_line_ = true; | 76 received_nonempty_line_ = true; |
| 127 | 77 |
| 128 std::vector<string16> columns; | 78 std::vector<string16> columns; |
| 129 SplitString(CollapseWhitespace(line, false), ' ', &columns); | 79 SplitString(CollapseWhitespace(line, false), ' ', &columns); |
| 130 | 80 |
| 81 // Some FTP servers put a "total n" line at the beginning of the listing |
| 82 // (n is an integer). Allow such a line, but only once, and only if it's |
| 83 // the first non-empty line. Do not match the word exactly, because it may be |
| 84 // in different languages (at least English and German have been seen in the |
| 85 // field). |
| 86 if (columns.size() == 2 && !received_total_line_) { |
| 87 received_total_line_ = true; |
| 88 |
| 89 int total_number; |
| 90 if (!StringToInt(columns[1], &total_number)) |
| 91 return false; |
| 92 if (total_number < 0) |
| 93 return false; |
| 94 |
| 95 return true; |
| 96 } |
| 97 |
| 131 // We may receive file names containing spaces, which can make the number of | 98 // We may receive file names containing spaces, which can make the number of |
| 132 // columns arbitrarily large. We will handle that later. For now just make | 99 // columns arbitrarily large. We will handle that later. For now just make |
| 133 // sure we have all the columns that should normally be there. | 100 // sure we have all the columns that should normally be there. |
| 134 if (columns.size() < 9) | 101 if (columns.size() < 9) |
| 135 return false; | 102 return false; |
| 136 | 103 |
| 137 if (!LooksLikeUnixPermissionsListing(columns[0])) | 104 if (!LooksLikeUnixPermissionsListing(columns[0])) |
| 138 return false; | 105 return false; |
| 139 | 106 |
| 140 FtpDirectoryListingEntry entry; | 107 FtpDirectoryListingEntry entry; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 152 if (number_of_links < 0) | 119 if (number_of_links < 0) |
| 153 return false; | 120 return false; |
| 154 | 121 |
| 155 if (!StringToInt64(columns[4], &entry.size)) | 122 if (!StringToInt64(columns[4], &entry.size)) |
| 156 return false; | 123 return false; |
| 157 if (entry.size < 0) | 124 if (entry.size < 0) |
| 158 return false; | 125 return false; |
| 159 if (entry.type != FtpDirectoryListingEntry::FILE) | 126 if (entry.type != FtpDirectoryListingEntry::FILE) |
| 160 entry.size = -1; | 127 entry.size = -1; |
| 161 | 128 |
| 162 if (!UnixDateListingToTime(columns, &entry.last_modified)) | 129 if (!FtpUtil::LsDateListingToTime(columns[5], columns[6], columns[7], |
| 130 &entry.last_modified)) { |
| 163 return false; | 131 return false; |
| 132 } |
| 164 | 133 |
| 165 entry.name = GetStringPartAfterColumns(line, 8); | 134 entry.name = GetStringPartAfterColumns(line, 8); |
| 166 if (entry.type == FtpDirectoryListingEntry::SYMLINK) { | 135 if (entry.type == FtpDirectoryListingEntry::SYMLINK) { |
| 167 string16::size_type pos = entry.name.rfind(ASCIIToUTF16(" -> ")); | 136 string16::size_type pos = entry.name.rfind(ASCIIToUTF16(" -> ")); |
| 168 if (pos == string16::npos) | 137 if (pos == string16::npos) |
| 169 return false; | 138 return false; |
| 170 entry.name = entry.name.substr(0, pos); | 139 entry.name = entry.name.substr(0, pos); |
| 171 } | 140 } |
| 172 | 141 |
| 173 entries_.push(entry); | 142 entries_.push(entry); |
| 174 return true; | 143 return true; |
| 175 } | 144 } |
| 176 | 145 |
| 177 bool FtpDirectoryListingParserLs::OnEndOfInput() { | 146 bool FtpDirectoryListingParserLs::OnEndOfInput() { |
| 178 return true; | 147 return true; |
| 179 } | 148 } |
| 180 | 149 |
| 181 bool FtpDirectoryListingParserLs::EntryAvailable() const { | 150 bool FtpDirectoryListingParserLs::EntryAvailable() const { |
| 182 return !entries_.empty(); | 151 return !entries_.empty(); |
| 183 } | 152 } |
| 184 | 153 |
| 185 FtpDirectoryListingEntry FtpDirectoryListingParserLs::PopEntry() { | 154 FtpDirectoryListingEntry FtpDirectoryListingParserLs::PopEntry() { |
| 186 FtpDirectoryListingEntry entry = entries_.front(); | 155 FtpDirectoryListingEntry entry = entries_.front(); |
| 187 entries_.pop(); | 156 entries_.pop(); |
| 188 return entry; | 157 return entry; |
| 189 } | 158 } |
| 190 | 159 |
| 191 } // namespace net | 160 } // namespace net |
| OLD | NEW |