| Index: net/ftp/ftp_directory_listing_parser_ls.cc
|
| diff --git a/net/ftp/ftp_directory_listing_parser_ls.cc b/net/ftp/ftp_directory_listing_parser_ls.cc
|
| index d6d147ab77a3d9a534977204e2fe15d4d206cf34..7aa1e12217b9f6157e34f50212268e5a6bfaec79 100644
|
| --- a/net/ftp/ftp_directory_listing_parser_ls.cc
|
| +++ b/net/ftp/ftp_directory_listing_parser_ls.cc
|
| @@ -1,4 +1,4 @@
|
| -// Copyright (c) 2010 The Chromium Authors. All rights reserved.
|
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| @@ -9,7 +9,9 @@
|
| #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 {
|
| @@ -100,136 +102,125 @@ bool DetectColumnOffset(const std::vector<string16>& columns,
|
|
|
| namespace net {
|
|
|
| -FtpDirectoryListingParserLs::FtpDirectoryListingParserLs(
|
| - const base::Time& current_time)
|
| - : received_total_line_(false),
|
| - current_time_(current_time) {
|
| -}
|
| -
|
| -FtpDirectoryListingParserLs::~FtpDirectoryListingParserLs() {}
|
| +bool ParseFtpDirectoryListingLs(
|
| + const std::vector<string16>& lines,
|
| + const base::Time& current_time,
|
| + std::vector<FtpDirectoryListingEntry>* entries) {
|
| + // True after we have received a "total n" listing header, where n is an
|
| + // integer. Only one such header is allowed per listing.
|
| + bool received_total_line = false;
|
| +
|
| + for (size_t i = 0; i < lines.size(); i++) {
|
| + if (lines[i].empty())
|
| + continue;
|
| +
|
| + std::vector<string16> columns;
|
| + base::SplitString(CollapseWhitespace(lines[i], false), ' ', &columns);
|
| +
|
| + // Some FTP servers put a "total n" line at the beginning of the listing
|
| + // (n is an integer). Allow such a line, but only once, and only if it's
|
| + // the first non-empty line. Do not match the word exactly, because it may
|
| + // be in different languages (at least English and German have been seen
|
| + // in the field).
|
| + if (columns.size() == 2 && !received_total_line) {
|
| + received_total_line = true;
|
| +
|
| + int total_number;
|
| + if (!base::StringToInt(columns[1], &total_number))
|
| + return false;
|
| + if (total_number < 0)
|
| + return false;
|
| +
|
| + continue;
|
| + }
|
| +
|
| + int column_offset;
|
| + if (!DetectColumnOffset(columns, current_time, &column_offset)) {
|
| + // If we can't recognize a normal listing line, maybe it's an error?
|
| + // In that case, just ignore the error, but still recognize the data
|
| + // as valid listing.
|
| + if (LooksLikePermissionDeniedError(lines[i]))
|
| + continue;
|
|
|
| -FtpServerType FtpDirectoryListingParserLs::GetServerType() const {
|
| - return SERVER_LS;
|
| -}
|
| -
|
| -bool FtpDirectoryListingParserLs::ConsumeLine(const string16& line) {
|
| - if (line.empty())
|
| - return true;
|
| -
|
| - std::vector<string16> columns;
|
| - base::SplitString(CollapseWhitespace(line, false), ' ', &columns);
|
| -
|
| - // Some FTP servers put a "total n" line at the beginning of the listing
|
| - // (n is an integer). Allow such a line, but only once, and only if it's
|
| - // the first non-empty line. Do not match the word exactly, because it may be
|
| - // in different languages (at least English and German have been seen in the
|
| - // field).
|
| - if (columns.size() == 2 && !received_total_line_) {
|
| - received_total_line_ = true;
|
| -
|
| - int total_number;
|
| - if (!base::StringToInt(columns[1], &total_number))
|
| return false;
|
| - if (total_number < 0)
|
| + }
|
| +
|
| + // We may receive file names containing spaces, which can make the number of
|
| + // columns arbitrarily large. We will handle that later. For now just make
|
| + // sure we have all the columns that should normally be there:
|
| + //
|
| + // 1. permission listing
|
| + // 2. number of links (optional)
|
| + // 3. owner name
|
| + // 4. group name (optional)
|
| + // 5. size in bytes
|
| + // 6. month
|
| + // 7. day of month
|
| + // 8. year or time
|
| + //
|
| + // The number of optional columns is stored in |column_offset|
|
| + // and is between 0 and 2 (inclusive).
|
| + if (columns.size() < 6U + column_offset)
|
| return false;
|
|
|
| - return true;
|
| - }
|
| -
|
| - int column_offset;
|
| - if (!DetectColumnOffset(columns, current_time_, &column_offset)) {
|
| - // If we can't recognize a normal listing line, maybe it's an error?
|
| - // In that case, just ignore the error, but still recognize the data
|
| - // as valid listing.
|
| - return LooksLikePermissionDeniedError(line);
|
| - }
|
| -
|
| - // We may receive file names containing spaces, which can make the number of
|
| - // columns arbitrarily large. We will handle that later. For now just make
|
| - // sure we have all the columns that should normally be there:
|
| - //
|
| - // 1. permission listing
|
| - // 2. number of links (optional)
|
| - // 3. owner name
|
| - // 4. group name (optional)
|
| - // 5. size in bytes
|
| - // 6. month
|
| - // 7. day of month
|
| - // 8. year or time
|
| - //
|
| - // The number of optional columns is stored in |column_offset|
|
| - // and is between 0 and 2 (inclusive).
|
| - if (columns.size() < 6U + column_offset)
|
| - return false;
|
| -
|
| - if (!LooksLikeUnixPermissionsListing(columns[0]))
|
| - return false;
|
| + if (!LooksLikeUnixPermissionsListing(columns[0]))
|
| + return false;
|
|
|
| - FtpDirectoryListingEntry entry;
|
| - if (columns[0][0] == 'l') {
|
| - entry.type = FtpDirectoryListingEntry::SYMLINK;
|
| - } else if (columns[0][0] == 'd') {
|
| - entry.type = FtpDirectoryListingEntry::DIRECTORY;
|
| - } else {
|
| - entry.type = FtpDirectoryListingEntry::FILE;
|
| - }
|
| + FtpDirectoryListingEntry entry;
|
| + if (columns[0][0] == 'l') {
|
| + entry.type = FtpDirectoryListingEntry::SYMLINK;
|
| + } else if (columns[0][0] == 'd') {
|
| + entry.type = FtpDirectoryListingEntry::DIRECTORY;
|
| + } else {
|
| + entry.type = FtpDirectoryListingEntry::FILE;
|
| + }
|
| +
|
| + if (!base::StringToInt64(columns[2 + column_offset], &entry.size)) {
|
| + // Some FTP servers do not separate owning group name from file size,
|
| + // like "group1234". We still want to display the file name for that
|
| + // entry, but can't really get the size (What if the group is named
|
| + // "group1", and the size is in fact 234? We can't distinguish between
|
| + // that and "group" with size 1234). Use a dummy value for the size.
|
| + // TODO(phajdan.jr): Use a value that means "unknown" instead of 0 bytes.
|
| + entry.size = 0;
|
| + }
|
| + if (entry.size < 0)
|
| + return false;
|
| + if (entry.type != FtpDirectoryListingEntry::FILE)
|
| + entry.size = -1;
|
| +
|
| + if (!FtpUtil::LsDateListingToTime(columns[3 + column_offset],
|
| + columns[4 + column_offset],
|
| + columns[5 + column_offset],
|
| + current_time,
|
| + &entry.last_modified)) {
|
| + return false;
|
| + }
|
|
|
| - if (!base::StringToInt64(columns[2 + column_offset], &entry.size)) {
|
| - // Some FTP servers do not separate owning group name from file size,
|
| - // like "group1234". We still want to display the file name for that entry,
|
| - // but can't really get the size (What if the group is named "group1",
|
| - // and the size is in fact 234? We can't distinguish between that
|
| - // and "group" with size 1234). Use a dummy value for the size.
|
| - // TODO(phajdan.jr): Use a value that means "unknown" instead of 0 bytes.
|
| - entry.size = 0;
|
| - }
|
| - if (entry.size < 0)
|
| - return false;
|
| - if (entry.type != FtpDirectoryListingEntry::FILE)
|
| - entry.size = -1;
|
| -
|
| - if (!FtpUtil::LsDateListingToTime(columns[3 + column_offset],
|
| - columns[4 + column_offset],
|
| - columns[5 + column_offset],
|
| - current_time_,
|
| - &entry.last_modified)) {
|
| - return false;
|
| - }
|
| + entry.name = FtpUtil::GetStringPartAfterColumns(lines[i],
|
| + 6 + column_offset);
|
|
|
| - entry.name = FtpUtil::GetStringPartAfterColumns(line, 6 + column_offset);
|
| + if (entry.name.empty()) {
|
| + // Some FTP servers send listing entries with empty names.
|
| + // It's not obvious how to display such an entry, so ignore them.
|
| + // We don't want to make the parsing fail at this point though.
|
| + // Other entries can still be useful.
|
| + continue;
|
| + }
|
|
|
| - if (entry.name.empty()) {
|
| - // Some FTP servers send listing entries with empty names. It's not obvious
|
| - // how to display such an entry, so we ignore them. We don't want to make
|
| - // the parsing fail at this point though. Other entries can still be useful.
|
| - return true;
|
| - }
|
| + if (entry.type == FtpDirectoryListingEntry::SYMLINK) {
|
| + string16::size_type pos = entry.name.rfind(ASCIIToUTF16(" -> "));
|
|
|
| - if (entry.type == FtpDirectoryListingEntry::SYMLINK) {
|
| - string16::size_type pos = entry.name.rfind(ASCIIToUTF16(" -> "));
|
| + // We don't require the " -> " to be present. Some FTP servers don't send
|
| + // the symlink target, possibly for security reasons.
|
| + if (pos != string16::npos)
|
| + entry.name = entry.name.substr(0, pos);
|
| + }
|
|
|
| - // We don't require the " -> " to be present. Some FTP servers don't send
|
| - // the symlink target, possibly for security reasons.
|
| - if (pos != string16::npos)
|
| - entry.name = entry.name.substr(0, pos);
|
| + entries->push_back(entry);
|
| }
|
|
|
| - entries_.push(entry);
|
| - return true;
|
| -}
|
| -
|
| -bool FtpDirectoryListingParserLs::OnEndOfInput() {
|
| return true;
|
| }
|
|
|
| -bool FtpDirectoryListingParserLs::EntryAvailable() const {
|
| - return !entries_.empty();
|
| -}
|
| -
|
| -FtpDirectoryListingEntry FtpDirectoryListingParserLs::PopEntry() {
|
| - FtpDirectoryListingEntry entry = entries_.front();
|
| - entries_.pop();
|
| - return entry;
|
| -}
|
| -
|
| } // namespace net
|
|
|