Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(589)

Unified Diff: net/ftp/ftp_directory_listing_parser_vms.cc

Issue 6670085: FTP: Detect the character encoding only after the entire listing is received. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: test coverage Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/ftp/ftp_directory_listing_parser_vms.h ('k') | net/ftp/ftp_directory_listing_parser_vms_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/ftp/ftp_directory_listing_parser_vms.cc
diff --git a/net/ftp/ftp_directory_listing_parser_vms.cc b/net/ftp/ftp_directory_listing_parser_vms.cc
index 65a3161cd721d91c30bb892867201d96b565e0b6..9a8a2f7e7a6589bc67ccd0fc405185cf97890210 100644
--- a/net/ftp/ftp_directory_listing_parser_vms.cc
+++ b/net/ftp/ftp_directory_listing_parser_vms.cc
@@ -9,15 +9,19 @@
#include "base/string_number_conversions.h"
#include "base/string_split.h"
#include "base/string_util.h"
+#include "base/time.h"
#include "base/utf_string_conversions.h"
+#include "net/ftp/ftp_directory_listing_parser.h"
#include "net/ftp/ftp_util.h"
+namespace net {
+
namespace {
// Converts the filename component in listing to the filename we can display.
// Returns true on success.
bool ParseVmsFilename(const string16& raw_filename, string16* parsed_filename,
- bool* is_directory) {
+ FtpDirectoryListingEntry::Type* type) {
// On VMS, the files and directories are versioned. The version number is
// separated from the file name by a semicolon. Example: ANNOUNCE.TXT;2.
std::vector<string16> listing_parts;
@@ -40,10 +44,10 @@ bool ParseVmsFilename(const string16& raw_filename, string16* parsed_filename,
return false;
if (EqualsASCII(filename_parts[1], "DIR")) {
*parsed_filename = StringToLowerASCII(filename_parts[0]);
- *is_directory = true;
+ *type = FtpDirectoryListingEntry::DIRECTORY;
} else {
*parsed_filename = StringToLowerASCII(listing_parts[0]);
- *is_directory = false;
+ *type = FtpDirectoryListingEntry::FILE;
}
return true;
}
@@ -117,28 +121,42 @@ bool LooksLikeVmsUserIdentificationCode(const string16& input) {
return input[0] == '[' && input[input.length() - 1] == ']';
}
+bool LooksLikePermissionDeniedError(const string16& text) {
+ static const char* kPermissionDeniedMessages[] = {
+ "%RMS-E-PRV",
+ "privilege",
+ };
+
+ for (size_t i = 0; i < arraysize(kPermissionDeniedMessages); i++) {
+ if (text.find(ASCIIToUTF16(kPermissionDeniedMessages[i])) != string16::npos)
+ return true;
+ }
+
+ return false;
+}
+
bool VmsDateListingToTime(const std::vector<string16>& columns,
base::Time* time) {
- DCHECK_EQ(3U, columns.size());
+ DCHECK_EQ(4U, columns.size());
base::Time::Exploded time_exploded = { 0 };
// Date should be in format DD-MMM-YYYY.
std::vector<string16> date_parts;
- base::SplitString(columns[1], '-', &date_parts);
+ base::SplitString(columns[2], '-', &date_parts);
if (date_parts.size() != 3)
return false;
if (!base::StringToInt(date_parts[0], &time_exploded.day_of_month))
return false;
- if (!net::FtpUtil::AbbreviatedMonthToNumber(date_parts[1],
- &time_exploded.month))
+ if (!FtpUtil::AbbreviatedMonthToNumber(date_parts[1],
+ &time_exploded.month))
return false;
if (!base::StringToInt(date_parts[2], &time_exploded.year))
return false;
// Time can be in format HH:MM, HH:MM:SS, or HH:MM:SS.mm. Try to recognize the
// last type first. Do not parse the seconds, they will be ignored anyway.
- string16 time_column(columns[2]);
+ string16 time_column(columns[3]);
if (time_column.length() == 11 && time_column[8] == '.')
time_column = time_column.substr(0, 8);
if (time_column.length() == 8 && time_column[5] == ':')
@@ -161,144 +179,88 @@ bool VmsDateListingToTime(const std::vector<string16>& columns,
} // namespace
-namespace net {
-
-FtpDirectoryListingParserVms::FtpDirectoryListingParserVms()
- : state_(STATE_INITIAL),
- last_is_directory_(false) {
-}
-
-FtpDirectoryListingParserVms::~FtpDirectoryListingParserVms() {}
-
-FtpServerType FtpDirectoryListingParserVms::GetServerType() const {
- return SERVER_VMS;
-}
-
-bool FtpDirectoryListingParserVms::ConsumeLine(const string16& line) {
- switch (state_) {
- case STATE_INITIAL:
- DCHECK(last_filename_.empty());
- if (line.empty())
- return true;
- if (StartsWith(line, ASCIIToUTF16("Total of "), true)) {
- state_ = STATE_END;
- return true;
- }
- // We assume that the first non-empty line is the listing header. It often
- // starts with "Directory ", but not always.
- state_ = STATE_RECEIVED_HEADER;
- return true;
- case STATE_RECEIVED_HEADER:
- DCHECK(last_filename_.empty());
- if (line.empty())
- return true;
- state_ = STATE_ENTRIES;
- return ConsumeEntryLine(line);
- case STATE_ENTRIES:
- if (line.empty()) {
- if (!last_filename_.empty())
+bool ParseFtpDirectoryListingVms(
+ const std::vector<string16>& lines,
+ std::vector<FtpDirectoryListingEntry>* entries) {
+ // The first non-empty line is the listing header. It often
+ // starts with "Directory ", but not always. We set a flag after
+ // seing the header.
+ bool seen_header = false;
+
+ for (size_t i = 0; i < lines.size(); i++) {
+ if (lines[i].empty())
+ continue;
+
+ if (StartsWith(lines[i], ASCIIToUTF16("Total of "), true)) {
+ // After the "total" line, all following lines must be empty.
+ for (size_t j = i + 1; j < lines.size(); j++)
+ if (!lines[j].empty())
return false;
- state_ = STATE_RECEIVED_LAST_ENTRY;
- return true;
- }
- return ConsumeEntryLine(line);
- case STATE_RECEIVED_LAST_ENTRY:
- DCHECK(last_filename_.empty());
- if (line.empty())
- return true;
- if (!StartsWith(line, ASCIIToUTF16("Total of "), true))
- return false;
- state_ = STATE_END;
+
return true;
- case STATE_END:
- DCHECK(last_filename_.empty());
- return false;
- default:
- NOTREACHED();
- return false;
- }
-}
+ }
-bool FtpDirectoryListingParserVms::OnEndOfInput() {
- return (state_ == STATE_END);
-}
+ if (!seen_header) {
+ seen_header = true;
+ continue;
+ }
-bool FtpDirectoryListingParserVms::EntryAvailable() const {
- return !entries_.empty();
-}
+ if (LooksLikePermissionDeniedError(lines[i]))
+ continue;
-FtpDirectoryListingEntry FtpDirectoryListingParserVms::PopEntry() {
- FtpDirectoryListingEntry entry = entries_.front();
- entries_.pop();
- return entry;
-}
+ std::vector<string16> columns;
+ base::SplitString(CollapseWhitespace(lines[i], false), ' ', &columns);
-bool FtpDirectoryListingParserVms::ConsumeEntryLine(const string16& line) {
- std::vector<string16> columns;
- base::SplitString(CollapseWhitespace(line, false), ' ', &columns);
+ if (columns.size() == 1) {
+ // There can be no continuation if the current line is the last one.
+ if (i == lines.size() - 1)
+ return false;
- if (columns.size() == 1) {
- if (!last_filename_.empty())
+ // Join the current and next line and split them into columns.
+ columns.clear();
+ base::SplitString(
+ CollapseWhitespace(lines[i] + ASCIIToUTF16(" ") + lines[i + 1],
+ false),
+ ' ',
+ &columns);
+ i++;
+ }
+
+ FtpDirectoryListingEntry entry;
+ if (!ParseVmsFilename(columns[0], &entry.name, &entry.type))
return false;
- return ParseVmsFilename(columns[0], &last_filename_, &last_is_directory_);
- }
- // Recognize listing entries which generate "access denied" message even when
- // trying to list them. We don't display them in the final listing.
- static const char* kAccessDeniedMessages[] = {
- "%RMS-E-PRV",
- "privilege",
- };
- for (size_t i = 0; i < arraysize(kAccessDeniedMessages); i++) {
- if (line.find(ASCIIToUTF16(kAccessDeniedMessages[i])) != string16::npos) {
- last_filename_.clear();
- last_is_directory_ = false;
- return true;
+ // There are different variants of a VMS listing. Some display
+ // the protection listing and user identification code, some do not.
+ if (columns.size() == 6) {
+ if (!LooksLikeVmsFileProtectionListing(columns[5]))
+ return false;
+ if (!LooksLikeVmsUserIdentificationCode(columns[4]))
+ return false;
+
+ // Drop the unneeded data, so that the following code can always expect
+ // just four columns.
+ columns.resize(4);
}
- }
- string16 filename;
- bool is_directory = false;
- if (last_filename_.empty()) {
- if (!ParseVmsFilename(columns[0], &filename, &is_directory))
+ if (columns.size() != 4)
return false;
- columns.erase(columns.begin());
- } else {
- filename = last_filename_;
- is_directory = last_is_directory_;
- last_filename_.clear();
- last_is_directory_ = false;
- }
-
- if (columns.size() > 5)
- return false;
- if (columns.size() == 5) {
- if (!LooksLikeVmsFileProtectionListing(columns[4]))
+ if (!ParseVmsFilesize(columns[1], &entry.size))
return false;
- if (!LooksLikeVmsUserIdentificationCode(columns[3]))
+ if (entry.size < 0)
+ return false;
+ if (entry.type != FtpDirectoryListingEntry::FILE)
+ entry.size = -1;
+ if (!VmsDateListingToTime(columns, &entry.last_modified))
return false;
- columns.resize(3);
- }
-
- if (columns.size() != 3)
- return false;
- FtpDirectoryListingEntry entry;
- entry.name = filename;
- entry.type = is_directory ? FtpDirectoryListingEntry::DIRECTORY
- : FtpDirectoryListingEntry::FILE;
- if (!ParseVmsFilesize(columns[0], &entry.size))
- return false;
- if (entry.size < 0)
- return false;
- if (entry.type != FtpDirectoryListingEntry::FILE)
- entry.size = -1;
- if (!VmsDateListingToTime(columns, &entry.last_modified))
- return false;
+ entries->push_back(entry);
+ }
- entries_.push(entry);
- return true;
+ // The only place where we return true is after receiving the "Total" line,
+ // that should be present in every VMS listing.
+ return false;
}
} // namespace net
« no previous file with comments | « net/ftp/ftp_directory_listing_parser_vms.h ('k') | net/ftp/ftp_directory_listing_parser_vms_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698