summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/ftp/ftp_directory_listing_buffer.cc194
-rw-r--r--net/ftp/ftp_directory_listing_buffer.h101
-rw-r--r--net/ftp/ftp_directory_listing_parser.cc101
-rw-r--r--net/ftp/ftp_directory_listing_parser.h34
-rw-r--r--net/ftp/ftp_directory_listing_parser_ls.cc227
-rw-r--r--net/ftp/ftp_directory_listing_parser_ls.h45
-rw-r--r--net/ftp/ftp_directory_listing_parser_ls_unittest.cc76
-rw-r--r--net/ftp/ftp_directory_listing_parser_netware.cc121
-rw-r--r--net/ftp/ftp_directory_listing_parser_netware.h45
-rw-r--r--net/ftp/ftp_directory_listing_parser_netware_unittest.cc42
-rw-r--r--net/ftp/ftp_directory_listing_parser_unittest.cc (renamed from net/ftp/ftp_directory_listing_buffer_unittest.cc)30
-rw-r--r--net/ftp/ftp_directory_listing_parser_unittest.h26
-rw-r--r--net/ftp/ftp_directory_listing_parser_vms.cc220
-rw-r--r--net/ftp/ftp_directory_listing_parser_vms.h58
-rw-r--r--net/ftp/ftp_directory_listing_parser_vms_unittest.cc159
-rw-r--r--net/ftp/ftp_directory_listing_parser_windows.cc101
-rw-r--r--net/ftp/ftp_directory_listing_parser_windows.h27
-rw-r--r--net/ftp/ftp_directory_listing_parser_windows_unittest.cc59
-rw-r--r--net/net.gyp4
19 files changed, 691 insertions, 979 deletions
diff --git a/net/ftp/ftp_directory_listing_buffer.cc b/net/ftp/ftp_directory_listing_buffer.cc
deleted file mode 100644
index 58533b8..0000000
--- a/net/ftp/ftp_directory_listing_buffer.cc
+++ /dev/null
@@ -1,194 +0,0 @@
-// Copyright (c) 2009 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.
-
-#include "net/ftp/ftp_directory_listing_buffer.h"
-
-#include "base/i18n/icu_encoding_detection.h"
-#include "base/i18n/icu_string_conversions.h"
-#include "base/stl_util-inl.h"
-#include "base/string_util.h"
-#include "net/base/net_errors.h"
-#include "net/ftp/ftp_directory_listing_parser_ls.h"
-#include "net/ftp/ftp_directory_listing_parser_netware.h"
-#include "net/ftp/ftp_directory_listing_parser_vms.h"
-#include "net/ftp/ftp_directory_listing_parser_windows.h"
-
-namespace net {
-
-FtpDirectoryListingBuffer::FtpDirectoryListingBuffer(
- const base::Time& current_time)
- : current_parser_(NULL) {
- parsers_.insert(new FtpDirectoryListingParserLs(current_time));
- parsers_.insert(new FtpDirectoryListingParserNetware(current_time));
- parsers_.insert(new FtpDirectoryListingParserVms());
- parsers_.insert(new FtpDirectoryListingParserWindows());
-}
-
-FtpDirectoryListingBuffer::~FtpDirectoryListingBuffer() {
- STLDeleteElements(&parsers_);
-}
-
-int FtpDirectoryListingBuffer::ConsumeData(const char* data, int data_length) {
- buffer_.append(data, data_length);
-
- if (!encoding_.empty() || buffer_.length() > 1024) {
- int rv = ConsumeBuffer();
- if (rv != OK)
- return rv;
- }
-
- return ParseLines();
-}
-
-int FtpDirectoryListingBuffer::ProcessRemainingData() {
- int rv = ConsumeBuffer();
- if (rv != OK)
- return rv;
-
- DCHECK(buffer_.empty());
- if (!converted_buffer_.empty())
- return ERR_INVALID_RESPONSE;
-
- rv = ParseLines();
- if (rv != OK)
- return rv;
-
- rv = OnEndOfInput();
- if (rv != OK)
- return rv;
-
- return OK;
-}
-
-bool FtpDirectoryListingBuffer::EntryAvailable() const {
- return (current_parser_ ? current_parser_->EntryAvailable() : false);
-}
-
-FtpDirectoryListingEntry FtpDirectoryListingBuffer::PopEntry() {
- DCHECK(EntryAvailable());
- return current_parser_->PopEntry();
-}
-
-FtpServerType FtpDirectoryListingBuffer::GetServerType() const {
- return (current_parser_ ? current_parser_->GetServerType() : SERVER_UNKNOWN);
-}
-
-int FtpDirectoryListingBuffer::DecodeBufferUsingEncoding(
- const std::string& encoding) {
- string16 converted;
- if (!base::CodepageToUTF16(buffer_,
- encoding.c_str(),
- base::OnStringConversionError::FAIL,
- &converted))
- return ERR_ENCODING_CONVERSION_FAILED;
-
- buffer_.clear();
- converted_buffer_ += converted;
- return OK;
-}
-
-int FtpDirectoryListingBuffer::ConvertBufferToUTF16() {
- if (encoding_.empty()) {
- std::vector<std::string> encodings;
- if (!base::DetectAllEncodings(buffer_, &encodings))
- return ERR_ENCODING_DETECTION_FAILED;
-
- // Use first encoding that can be used to decode the buffer.
- for (size_t i = 0; i < encodings.size(); i++) {
- if (DecodeBufferUsingEncoding(encodings[i]) == OK) {
- encoding_ = encodings[i];
- return OK;
- }
- }
-
- return ERR_ENCODING_DETECTION_FAILED;
- }
-
- return DecodeBufferUsingEncoding(encoding_);
-}
-
-void FtpDirectoryListingBuffer::ExtractFullLinesFromBuffer() {
- int cut_pos = 0;
- // TODO(phajdan.jr): This code accepts all endlines matching \r*\n. Should it
- // be more strict, or enforce consistent line endings?
- for (size_t i = 0; i < converted_buffer_.length(); ++i) {
- if (converted_buffer_[i] != '\n')
- continue;
- int line_length = i - cut_pos;
- if (i >= 1 && converted_buffer_[i - 1] == '\r')
- line_length--;
- lines_.push_back(converted_buffer_.substr(cut_pos, line_length));
- cut_pos = i + 1;
- }
- converted_buffer_.erase(0, cut_pos);
-}
-
-int FtpDirectoryListingBuffer::ConsumeBuffer() {
- int rv = ConvertBufferToUTF16();
- if (rv != OK)
- return rv;
-
- ExtractFullLinesFromBuffer();
- return OK;
-}
-
-int FtpDirectoryListingBuffer::ParseLines() {
- while (!lines_.empty()) {
- string16 line = lines_.front();
- lines_.pop_front();
- if (current_parser_) {
- if (!current_parser_->ConsumeLine(line))
- return ERR_FAILED;
- } else {
- ParserSet::iterator i = parsers_.begin();
- while (i != parsers_.end()) {
- if ((*i)->ConsumeLine(line)) {
- i++;
- } else {
- delete *i;
- parsers_.erase(i++);
- }
- }
- if (parsers_.empty())
- return ERR_UNRECOGNIZED_FTP_DIRECTORY_LISTING_FORMAT;
- if (parsers_.size() == 1)
- current_parser_ = *parsers_.begin();
- }
- }
-
- return OK;
-}
-
-int FtpDirectoryListingBuffer::OnEndOfInput() {
- ParserSet::iterator i = parsers_.begin();
- while (i != parsers_.end()) {
- if ((*i)->OnEndOfInput()) {
- i++;
- } else {
- delete *i;
- parsers_.erase(i++);
- }
- }
-
- if (parsers_.size() != 1) {
- current_parser_ = NULL;
-
- // We may hit an ambiguity in case of listings which have no entries. That's
- // fine, as long as all remaining parsers agree that the listing is empty.
- bool all_listings_empty = true;
- for (ParserSet::iterator i = parsers_.begin(); i != parsers_.end(); ++i) {
- if ((*i)->EntryAvailable())
- all_listings_empty = false;
- }
- if (all_listings_empty)
- return OK;
-
- return ERR_UNRECOGNIZED_FTP_DIRECTORY_LISTING_FORMAT;
- }
-
- current_parser_ = *parsers_.begin();
- return OK;
-}
-
-} // namespace net
diff --git a/net/ftp/ftp_directory_listing_buffer.h b/net/ftp/ftp_directory_listing_buffer.h
deleted file mode 100644
index ea68932..0000000
--- a/net/ftp/ftp_directory_listing_buffer.h
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright (c) 2010 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.
-
-#ifndef NET_FTP_FTP_DIRECTORY_LISTING_BUFFER_H_
-#define NET_FTP_FTP_DIRECTORY_LISTING_BUFFER_H_
-#pragma once
-
-#include <deque>
-#include <set>
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/string16.h"
-#include "base/time.h"
-#include "net/ftp/ftp_server_type_histograms.h"
-
-namespace net {
-
-struct FtpDirectoryListingEntry;
-class FtpDirectoryListingParser;
-
-class FtpDirectoryListingBuffer {
- public:
- // Constructor. When the current time is needed to guess the year on partial
- // date strings, |current_time| will be used. This allows passing a specific
- // date during testing.
- explicit FtpDirectoryListingBuffer(const base::Time& current_time);
- ~FtpDirectoryListingBuffer();
-
- // Called when data is received from the data socket. Returns network
- // error code.
- int ConsumeData(const char* data, int data_length);
-
- // Called when all received data has been consumed by this buffer. Tells the
- // buffer to try to parse remaining raw data and returns network error code.
- int ProcessRemainingData();
-
- bool EntryAvailable() const;
-
- // Returns the next entry. It is an error to call this function
- // unless EntryAvailable returns true.
- FtpDirectoryListingEntry PopEntry();
-
- // Returns recognized server type. It is valid to call this function at any
- // time, although it will return SERVER_UNKNOWN if it doesn't know the answer.
- FtpServerType GetServerType() const;
-
- const std::string& encoding() const { return encoding_; }
-
- private:
- typedef std::set<FtpDirectoryListingParser*> ParserSet;
-
- // Decodes the raw buffer using specified |encoding|. On success
- // clears the raw buffer and appends data to |converted_buffer_|.
- // Returns network error code.
- int DecodeBufferUsingEncoding(const std::string& encoding);
-
- // Converts the raw buffer to UTF-16. Returns network error code.
- int ConvertBufferToUTF16();
-
- // Extracts lines from the converted buffer, and puts them in |lines_|.
- void ExtractFullLinesFromBuffer();
-
- // Consumes the raw buffer (i.e. does the character set conversion
- // and line splitting). Returns network error code.
- int ConsumeBuffer();
-
- // Tries to parse full lines stored in |lines_|. Returns network error code.
- int ParseLines();
-
- // Called when we received the entire input. Propagates that info to remaining
- // parsers. Returns network error code.
- int OnEndOfInput();
-
- // Detected encoding of the response (empty if unknown).
- std::string encoding_;
-
- // Buffer to keep data before character set conversion.
- std::string buffer_;
-
- // Buffer to keep data before line splitting.
- string16 converted_buffer_;
-
- // CRLF-delimited lines, without the CRLF, not yet consumed by parser.
- std::deque<string16> lines_;
-
- // A collection of parsers for different listing styles. The parsers are owned
- // by this FtpDirectoryListingBuffer.
- ParserSet parsers_;
-
- // When we're sure about the listing format, its parser is stored in
- // |current_parser_|.
- FtpDirectoryListingParser* current_parser_;
-
- DISALLOW_COPY_AND_ASSIGN(FtpDirectoryListingBuffer);
-};
-
-} // namespace net
-
-#endif // NET_FTP_FTP_DIRECTORY_LISTING_BUFFER_H_
diff --git a/net/ftp/ftp_directory_listing_parser.cc b/net/ftp/ftp_directory_listing_parser.cc
index 2f3eeca..8aa3696 100644
--- a/net/ftp/ftp_directory_listing_parser.cc
+++ b/net/ftp/ftp_directory_listing_parser.cc
@@ -1,12 +1,105 @@
-// Copyright (c) 2009 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.
+// 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.
#include "net/ftp/ftp_directory_listing_parser.h"
+#include "base/i18n/icu_encoding_detection.h"
+#include "base/i18n/icu_string_conversions.h"
+#include "base/stl_util-inl.h"
+#include "base/string_split.h"
+#include "base/string_util.h"
+#include "net/base/net_errors.h"
+#include "net/ftp/ftp_directory_listing_parser_ls.h"
+#include "net/ftp/ftp_directory_listing_parser_netware.h"
+#include "net/ftp/ftp_directory_listing_parser_vms.h"
+#include "net/ftp/ftp_directory_listing_parser_windows.h"
+#include "net/ftp/ftp_server_type_histograms.h"
+
+namespace {
+
+// Converts a string with unknown character encoding to UTF-16. On success
+// fills in |converted_text| and |encoding|. Returns network error code.
+int ConvertStringToUTF16(const std::string& text,
+ string16* converted_text,
+ std::string* encoding) {
+ std::vector<std::string> encodings;
+ if (!base::DetectAllEncodings(text, &encodings))
+ return net::ERR_ENCODING_DETECTION_FAILED;
+
+ // Use first encoding that can be used to decode the text.
+ for (size_t i = 0; i < encodings.size(); i++) {
+ if (base::CodepageToUTF16(text,
+ encodings[i].c_str(),
+ base::OnStringConversionError::FAIL,
+ converted_text)) {
+ *encoding = encodings[i];
+ return net::OK;
+ }
+ }
+
+ return net::ERR_ENCODING_DETECTION_FAILED;
+}
+
+int FillInRawName(const std::string& encoding,
+ std::vector<net::FtpDirectoryListingEntry>* entries) {
+ for (size_t i = 0; i < entries->size(); i++) {
+ if (!base::UTF16ToCodepage(entries->at(i).name, encoding.c_str(),
+ base::OnStringConversionError::FAIL,
+ &entries->at(i).raw_name)) {
+ return net::ERR_ENCODING_CONVERSION_FAILED;
+ }
+ }
+
+ return net::OK;
+}
+
+} // namespace
+
namespace net {
-FtpDirectoryListingParser::~FtpDirectoryListingParser() {
+int ParseFtpDirectoryListing(const std::string& text,
+ const base::Time& current_time,
+ std::vector<FtpDirectoryListingEntry>* entries) {
+ std::string encoding;
+
+ string16 converted_text;
+ int rv = ConvertStringToUTF16(text, &converted_text, &encoding);
+ if (rv != OK)
+ return rv;
+
+ std::vector<string16> lines;
+ base::SplitString(converted_text, '\n', &lines);
+
+ // TODO(phajdan.jr): Use a table of callbacks instead of repeating code.
+
+ entries->clear();
+ if (ParseFtpDirectoryListingLs(lines, current_time, entries)) {
+ UpdateFtpServerTypeHistograms(SERVER_LS);
+ return FillInRawName(encoding, entries);
+ }
+
+ entries->clear();
+ if (ParseFtpDirectoryListingWindows(lines, entries)) {
+ UpdateFtpServerTypeHistograms(SERVER_WINDOWS);
+ return FillInRawName(encoding, entries);
+ }
+
+ entries->clear();
+ if (ParseFtpDirectoryListingVms(lines, entries)) {
+ UpdateFtpServerTypeHistograms(SERVER_VMS);
+ return FillInRawName(encoding, entries);
+ }
+
+ entries->clear();
+ if (ParseFtpDirectoryListingNetware(lines, current_time, entries)) {
+ UpdateFtpServerTypeHistograms(SERVER_NETWARE);
+ return FillInRawName(encoding, entries);
+ }
+
+ entries->clear();
+ UpdateFtpServerTypeHistograms(SERVER_UNKNOWN);
+ return ERR_UNRECOGNIZED_FTP_DIRECTORY_LISTING_FORMAT;
}
} // namespace
diff --git a/net/ftp/ftp_directory_listing_parser.h b/net/ftp/ftp_directory_listing_parser.h
index 6373312..b6c95fe 100644
--- a/net/ftp/ftp_directory_listing_parser.h
+++ b/net/ftp/ftp_directory_listing_parser.h
@@ -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.
@@ -6,10 +6,12 @@
#define NET_FTP_FTP_DIRECTORY_LISTING_PARSER_H_
#pragma once
+#include <string>
+#include <vector>
+
#include "base/basictypes.h"
#include "base/string16.h"
#include "base/time.h"
-#include "net/ftp/ftp_server_type_histograms.h"
namespace net {
@@ -21,33 +23,19 @@ struct FtpDirectoryListingEntry {
};
Type type;
- string16 name;
+ string16 name; // Name (UTF-16-encoded).
+ std::string raw_name; // Name in original character encoding.
int64 size; // File size, in bytes. -1 if not applicable.
// Last modified time, in local time zone.
base::Time last_modified;
};
-class FtpDirectoryListingParser {
- public:
- virtual ~FtpDirectoryListingParser();
-
- virtual FtpServerType GetServerType() const = 0;
-
- // Adds |line| to the internal parsing buffer. Returns true on success.
- virtual bool ConsumeLine(const string16& line) = 0;
-
- // Called after all input has been consumed. Returns true if the parser
- // recognizes all received data as a valid listing.
- virtual bool OnEndOfInput() = 0;
-
- // Returns true if there is at least one FtpDirectoryListingEntry available.
- virtual bool EntryAvailable() const = 0;
-
- // Returns the next entry. It is an error to call this function unless
- // EntryAvailable returns true.
- virtual FtpDirectoryListingEntry PopEntry() = 0;
-};
+// Parses an FTP directory listing |text|. On success fills in |entries|.
+// Returns network error code.
+int ParseFtpDirectoryListing(const std::string& text,
+ const base::Time& current_time,
+ std::vector<FtpDirectoryListingEntry>* entries);
} // namespace net
diff --git a/net/ftp/ftp_directory_listing_parser_ls.cc b/net/ftp/ftp_directory_listing_parser_ls.cc
index d6d147a..7aa1e12 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
diff --git a/net/ftp/ftp_directory_listing_parser_ls.h b/net/ftp/ftp_directory_listing_parser_ls.h
index 49607092..d27bd91 100644
--- a/net/ftp/ftp_directory_listing_parser_ls.h
+++ b/net/ftp/ftp_directory_listing_parser_ls.h
@@ -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.
@@ -6,41 +6,22 @@
#define NET_FTP_FTP_DIRECTORY_LISTING_PARSER_LS_H_
#pragma once
-#include <queue>
+#include <vector>
-#include "base/time.h"
-#include "net/ftp/ftp_directory_listing_parser.h"
+#include "base/string16.h"
+
+namespace base {
+class Time;
+}
namespace net {
-// Parser for "ls -l"-style directory listing.
-class FtpDirectoryListingParserLs : public FtpDirectoryListingParser {
- public:
- // Constructor. When the current time is needed to guess the year on partial
- // date strings, |current_time| will be used. This allows passing a specific
- // date during testing.
- explicit FtpDirectoryListingParserLs(const base::Time& current_time);
- virtual ~FtpDirectoryListingParserLs();
-
- // FtpDirectoryListingParser methods:
- virtual FtpServerType GetServerType() const;
- virtual bool ConsumeLine(const string16& line);
- virtual bool OnEndOfInput();
- virtual bool EntryAvailable() const;
- virtual FtpDirectoryListingEntry PopEntry();
-
- private:
- // 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_;
-
- // Store the current time. We need it to correctly parse received dates.
- const base::Time current_time_;
-
- std::queue<FtpDirectoryListingEntry> entries_;
-
- DISALLOW_COPY_AND_ASSIGN(FtpDirectoryListingParserLs);
-};
+struct FtpDirectoryListingEntry;
+
+// Parses "ls -l" FTP directory listing. Returns true on success.
+bool ParseFtpDirectoryListingLs(const std::vector<string16>& lines,
+ const base::Time& current_time,
+ std::vector<FtpDirectoryListingEntry>* entries);
} // namespace net
diff --git a/net/ftp/ftp_directory_listing_parser_ls_unittest.cc b/net/ftp/ftp_directory_listing_parser_ls_unittest.cc
index 88bbecd..8a1fe95 100644
--- a/net/ftp/ftp_directory_listing_parser_ls_unittest.cc
+++ b/net/ftp/ftp_directory_listing_parser_ls_unittest.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,91 +9,97 @@
#include "base/stringprintf.h"
#include "net/ftp/ftp_directory_listing_parser_ls.h"
+namespace net {
+
namespace {
-typedef net::FtpDirectoryListingParserTest FtpDirectoryListingParserLsTest;
+typedef FtpDirectoryListingParserTest FtpDirectoryListingParserLsTest;
TEST_F(FtpDirectoryListingParserLsTest, Good) {
const struct SingleLineTestData good_cases[] = {
{ "-rw-r--r-- 1 ftp ftp 528 Nov 01 2007 README",
- net::FtpDirectoryListingEntry::FILE, "README", 528,
+ FtpDirectoryListingEntry::FILE, "README", 528,
2007, 11, 1, 0, 0 },
{ "drwxr-xr-x 3 ftp ftp 4096 May 15 18:11 directory",
- net::FtpDirectoryListingEntry::DIRECTORY, "directory", -1,
+ FtpDirectoryListingEntry::DIRECTORY, "directory", -1,
1994, 5, 15, 18, 11 },
{ "lrwxrwxrwx 1 0 0 26 Sep 18 2008 pub -> vol/1/.CLUSTER/var_ftp/pub",
- net::FtpDirectoryListingEntry::SYMLINK, "pub", -1,
+ FtpDirectoryListingEntry::SYMLINK, "pub", -1,
2008, 9, 18, 0, 0 },
{ "lrwxrwxrwx 1 0 0 3 Oct 12 13:37 mirror -> pub",
- net::FtpDirectoryListingEntry::SYMLINK, "mirror", -1,
+ FtpDirectoryListingEntry::SYMLINK, "mirror", -1,
1994, 10, 12, 13, 37 },
{ "drwxrwsr-x 4 501 501 4096 Feb 20 2007 pub",
- net::FtpDirectoryListingEntry::DIRECTORY, "pub", -1,
+ FtpDirectoryListingEntry::DIRECTORY, "pub", -1,
2007, 2, 20, 0, 0 },
{ "drwxr-xr-x 4 (?) (?) 4096 Apr 8 2007 jigdo",
- net::FtpDirectoryListingEntry::DIRECTORY, "jigdo", -1,
+ FtpDirectoryListingEntry::DIRECTORY, "jigdo", -1,
2007, 4, 8, 0, 0 },
{ "drwx-wx-wt 2 root wheel 512 Jul 1 02:15 incoming",
- net::FtpDirectoryListingEntry::DIRECTORY, "incoming", -1,
+ FtpDirectoryListingEntry::DIRECTORY, "incoming", -1,
1994, 7, 1, 2, 15 },
{ "-rw-r--r-- 1 2 3 3447432 May 18 2009 Foo - Manual.pdf",
- net::FtpDirectoryListingEntry::FILE, "Foo - Manual.pdf", 3447432,
+ FtpDirectoryListingEntry::FILE, "Foo - Manual.pdf", 3447432,
2009, 5, 18, 0, 0 },
{ "d-wx-wx-wt+ 4 ftp 989 512 Dec 8 15:54 incoming",
- net::FtpDirectoryListingEntry::DIRECTORY, "incoming", -1,
+ FtpDirectoryListingEntry::DIRECTORY, "incoming", -1,
1993, 12, 8, 15, 54 },
{ "drwxrwxrwx 1 owner group 0 Sep 13 0:30 audio",
- net::FtpDirectoryListingEntry::DIRECTORY, "audio", -1,
+ FtpDirectoryListingEntry::DIRECTORY, "audio", -1,
1994, 9, 13, 0, 30 },
{ "lrwxrwxrwx 1 0 0 26 Sep 18 2008 pub",
- net::FtpDirectoryListingEntry::SYMLINK, "pub", -1,
+ FtpDirectoryListingEntry::SYMLINK, "pub", -1,
2008, 9, 18, 0, 0 },
// Tests for the wu-ftpd variant:
{ "drwxr-xr-x 2 sys 512 Mar 27 2009 pub",
- net::FtpDirectoryListingEntry::DIRECTORY, "pub", -1,
+ FtpDirectoryListingEntry::DIRECTORY, "pub", -1,
2009, 3, 27, 0, 0 },
{ "lrwxrwxrwx 0 0 26 Sep 18 2008 pub -> vol/1/.CLUSTER/var_ftp/pub",
- net::FtpDirectoryListingEntry::SYMLINK, "pub", -1,
+ FtpDirectoryListingEntry::SYMLINK, "pub", -1,
2008, 9, 18, 0, 0 },
{ "drwxr-xr-x (?) (?) 4096 Apr 8 2007 jigdo",
- net::FtpDirectoryListingEntry::DIRECTORY, "jigdo", -1,
+ FtpDirectoryListingEntry::DIRECTORY, "jigdo", -1,
2007, 4, 8, 0, 0 },
{ "-rw-r--r-- 2 3 3447432 May 18 2009 Foo - Manual.pdf",
- net::FtpDirectoryListingEntry::FILE, "Foo - Manual.pdf", 3447432,
+ FtpDirectoryListingEntry::FILE, "Foo - Manual.pdf", 3447432,
2009, 5, 18, 0, 0 },
// Tests for "ls -l" style listings sent by an OS/2 server (FtpServer):
{ "-r--r--r-- 1 ftp -A--- 13274 Mar 1 2006 UpTime.exe",
- net::FtpDirectoryListingEntry::FILE, "UpTime.exe", 13274,
+ FtpDirectoryListingEntry::FILE, "UpTime.exe", 13274,
2006, 3, 1, 0, 0 },
{ "dr--r--r-- 1 ftp ----- 0 Nov 17 17:08 kernels",
- net::FtpDirectoryListingEntry::DIRECTORY, "kernels", -1,
+ FtpDirectoryListingEntry::DIRECTORY, "kernels", -1,
1993, 11, 17, 17, 8 },
// Tests for "ls -l" style listing sent by Xplain FTP Server.
{ "drwxr-xr-x folder 0 Jul 17 2006 online",
- net::FtpDirectoryListingEntry::DIRECTORY, "online", -1,
+ FtpDirectoryListingEntry::DIRECTORY, "online", -1,
2006, 7, 17, 0, 0 },
// Tests for "ls -l" style listing with owning group name
// not separated from file size (http://crbug.com/58963).
{ "-rw-r--r-- 1 ftpadmin ftpadmin125435904 Apr 9 2008 .pureftpd-upload",
- net::FtpDirectoryListingEntry::FILE, ".pureftpd-upload", 0,
+ FtpDirectoryListingEntry::FILE, ".pureftpd-upload", 0,
2008, 4, 9, 0, 0 },
// Tests for "ls -l" style listing with number of links
// not separated from permission listing (http://crbug.com/70394).
{ "drwxr-xr-x1732 266 111 90112 Jun 21 2001 .rda_2",
- net::FtpDirectoryListingEntry::DIRECTORY, ".rda_2", -1,
+ FtpDirectoryListingEntry::DIRECTORY, ".rda_2", -1,
2001, 6, 21, 0, 0 },
};
for (size_t i = 0; i < arraysize(good_cases); i++) {
SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
good_cases[i].input));
- net::FtpDirectoryListingParserLs parser(GetMockCurrentTime());
- RunSingleLineTestCase(&parser, good_cases[i]);
+ std::vector<FtpDirectoryListingEntry> entries;
+ EXPECT_TRUE(ParseFtpDirectoryListingLs(
+ GetSingleLineTestCase(good_cases[i].input),
+ GetMockCurrentTime(),
+ &entries));
+ VerifySingleLineTestCase(good_cases[i], entries);
}
}
@@ -114,11 +120,12 @@ TEST_F(FtpDirectoryListingParserLsTest, Ignored) {
SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
ignored_cases[i]));
- net::FtpDirectoryListingParserLs parser(GetMockCurrentTime());
- EXPECT_TRUE(parser.ConsumeLine(UTF8ToUTF16(ignored_cases[i])));
- EXPECT_FALSE(parser.EntryAvailable());
- EXPECT_TRUE(parser.OnEndOfInput());
- EXPECT_FALSE(parser.EntryAvailable());
+ std::vector<FtpDirectoryListingEntry> entries;
+ EXPECT_TRUE(ParseFtpDirectoryListingLs(
+ GetSingleLineTestCase(ignored_cases[i]),
+ GetMockCurrentTime(),
+ &entries));
+ EXPECT_EQ(0U, entries.size());
}
}
@@ -143,9 +150,16 @@ TEST_F(FtpDirectoryListingParserLsTest, Bad) {
"-qqqqqqqqq+ 2 sys 512 Mar 27 2009 pub",
};
for (size_t i = 0; i < arraysize(bad_cases); i++) {
- net::FtpDirectoryListingParserLs parser(GetMockCurrentTime());
- EXPECT_FALSE(parser.ConsumeLine(UTF8ToUTF16(bad_cases[i]))) << bad_cases[i];
+ SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
+ bad_cases[i]));
+
+ std::vector<FtpDirectoryListingEntry> entries;
+ EXPECT_FALSE(ParseFtpDirectoryListingLs(GetSingleLineTestCase(bad_cases[i]),
+ GetMockCurrentTime(),
+ &entries));
}
}
} // namespace
+
+} // namespace net
diff --git a/net/ftp/ftp_directory_listing_parser_netware.cc b/net/ftp/ftp_directory_listing_parser_netware.cc
index 1801a4a..1e8c80e 100644
--- a/net/ftp/ftp_directory_listing_parser_netware.cc
+++ b/net/ftp/ftp_directory_listing_parser_netware.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.
@@ -10,6 +10,7 @@
#include "base/string_split.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
+#include "net/ftp/ftp_directory_listing_parser.h"
#include "net/ftp/ftp_util.h"
namespace {
@@ -34,80 +35,60 @@ bool LooksLikeNetwarePermissionsListing(const string16& text) {
namespace net {
-FtpDirectoryListingParserNetware::FtpDirectoryListingParserNetware(
- const base::Time& current_time)
- : received_first_line_(false),
- current_time_(current_time) {
-}
-
-FtpDirectoryListingParserNetware::~FtpDirectoryListingParserNetware() {}
-
-FtpServerType FtpDirectoryListingParserNetware::GetServerType() const {
- return SERVER_NETWARE;
-}
-
-bool FtpDirectoryListingParserNetware::ConsumeLine(const string16& line) {
- if (!received_first_line_) {
- received_first_line_ = true;
-
- return StartsWith(line, ASCIIToUTF16("total "), true);
- }
-
- std::vector<string16> columns;
- base::SplitString(CollapseWhitespace(line, false), ' ', &columns);
-
- if (columns.size() != 8)
- return false;
-
- FtpDirectoryListingEntry entry;
-
- if (columns[0].length() != 1)
- return false;
- if (columns[0][0] == 'd') {
- entry.type = FtpDirectoryListingEntry::DIRECTORY;
- } else if (columns[0][0] == '-') {
- entry.type = FtpDirectoryListingEntry::FILE;
- } else {
- return false;
- }
-
- // Note: on older Netware systems the permissions listing is in the same
- // column as the entry type (just there is no space between them). We do not
- // support the older format here for simplicity.
- if (!LooksLikeNetwarePermissionsListing(columns[1]))
+bool ParseFtpDirectoryListingNetware(
+ const std::vector<string16>& lines,
+ const base::Time& current_time,
+ std::vector<FtpDirectoryListingEntry>* entries) {
+ if (!lines.empty() && !StartsWith(lines[0], ASCIIToUTF16("total "), true))
return false;
- if (!base::StringToInt64(columns[3], &entry.size))
- return false;
- if (entry.size < 0)
- return false;
- if (entry.type != FtpDirectoryListingEntry::FILE)
- entry.size = -1;
-
- // Netware uses the same date listing format as Unix "ls -l".
- if (!FtpUtil::LsDateListingToTime(columns[4], columns[5], columns[6],
- current_time_, &entry.last_modified)) {
- return false;
+ for (size_t i = 1U; i < lines.size(); i++) {
+ if (lines[i].empty())
+ continue;
+
+ std::vector<string16> columns;
+ base::SplitString(CollapseWhitespace(lines[i], false), ' ', &columns);
+
+ if (columns.size() != 8)
+ return false;
+
+ FtpDirectoryListingEntry entry;
+
+ if (columns[0].length() != 1)
+ return false;
+ if (columns[0][0] == 'd') {
+ entry.type = FtpDirectoryListingEntry::DIRECTORY;
+ } else if (columns[0][0] == '-') {
+ entry.type = FtpDirectoryListingEntry::FILE;
+ } else {
+ return false;
+ }
+
+ // Note: on older Netware systems the permissions listing is in the same
+ // column as the entry type (just there is no space between them). We do not
+ // support the older format here for simplicity.
+ if (!LooksLikeNetwarePermissionsListing(columns[1]))
+ return false;
+
+ if (!base::StringToInt64(columns[3], &entry.size))
+ return false;
+ if (entry.size < 0)
+ return false;
+ if (entry.type != FtpDirectoryListingEntry::FILE)
+ entry.size = -1;
+
+ // Netware uses the same date listing format as Unix "ls -l".
+ if (!FtpUtil::LsDateListingToTime(columns[4], columns[5], columns[6],
+ current_time, &entry.last_modified)) {
+ return false;
+ }
+
+ entry.name = columns[7];
+
+ entries->push_back(entry);
}
- entry.name = columns[7];
-
- entries_.push(entry);
return true;
}
-bool FtpDirectoryListingParserNetware::OnEndOfInput() {
- return true;
-}
-
-bool FtpDirectoryListingParserNetware::EntryAvailable() const {
- return !entries_.empty();
-}
-
-FtpDirectoryListingEntry FtpDirectoryListingParserNetware::PopEntry() {
- FtpDirectoryListingEntry entry = entries_.front();
- entries_.pop();
- return entry;
-}
-
} // namespace net
diff --git a/net/ftp/ftp_directory_listing_parser_netware.h b/net/ftp/ftp_directory_listing_parser_netware.h
index 48aebfc..b72a49f 100644
--- a/net/ftp/ftp_directory_listing_parser_netware.h
+++ b/net/ftp/ftp_directory_listing_parser_netware.h
@@ -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.
@@ -6,40 +6,23 @@
#define NET_FTP_FTP_DIRECTORY_LISTING_PARSER_NETWARE_H_
#pragma once
-#include <queue>
+#include <vector>
-#include "base/time.h"
-#include "net/ftp/ftp_directory_listing_parser.h"
+#include "base/string16.h"
+
+namespace base {
+class Time;
+}
namespace net {
-// Parser for Netware-style directory listing.
-class FtpDirectoryListingParserNetware : public FtpDirectoryListingParser {
- public:
- // Constructor. When the current time is needed to guess the year on partial
- // date strings, |current_time| will be used. This allows passing a specific
- // date during testing.
- explicit FtpDirectoryListingParserNetware(const base::Time& current_time);
- virtual ~FtpDirectoryListingParserNetware();
-
- // FtpDirectoryListingParser methods:
- virtual FtpServerType GetServerType() const;
- virtual bool ConsumeLine(const string16& line);
- virtual bool OnEndOfInput();
- virtual bool EntryAvailable() const;
- virtual FtpDirectoryListingEntry PopEntry();
-
- private:
- // True after we have received the first line of input.
- bool received_first_line_;
-
- // Store the current time. We need it to correctly parse received dates.
- const base::Time current_time_;
-
- std::queue<FtpDirectoryListingEntry> entries_;
-
- DISALLOW_COPY_AND_ASSIGN(FtpDirectoryListingParserNetware);
-};
+struct FtpDirectoryListingEntry;
+
+// Parses Netware FTP directory listing. Returns true on success.
+bool ParseFtpDirectoryListingNetware(
+ const std::vector<string16>& lines,
+ const base::Time& current_time,
+ std::vector<FtpDirectoryListingEntry>* entries);
} // namespace net
diff --git a/net/ftp/ftp_directory_listing_parser_netware_unittest.cc b/net/ftp/ftp_directory_listing_parser_netware_unittest.cc
index c02fb97..5f373ac 100644
--- a/net/ftp/ftp_directory_listing_parser_netware_unittest.cc
+++ b/net/ftp/ftp_directory_listing_parser_netware_unittest.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.
@@ -10,27 +10,35 @@
#include "base/utf_string_conversions.h"
#include "net/ftp/ftp_directory_listing_parser_netware.h"
+namespace net {
+
namespace {
-typedef net::FtpDirectoryListingParserTest FtpDirectoryListingParserNetwareTest;
+typedef FtpDirectoryListingParserTest FtpDirectoryListingParserNetwareTest;
TEST_F(FtpDirectoryListingParserNetwareTest, Good) {
const struct SingleLineTestData good_cases[] = {
{ "d [RWCEAFMS] ftpadmin 512 Jan 29 2004 pub",
- net::FtpDirectoryListingEntry::DIRECTORY, "pub", -1,
+ FtpDirectoryListingEntry::DIRECTORY, "pub", -1,
2004, 1, 29, 0, 0 },
{ "- [RW------] ftpadmin 123 Nov 11 18:25 afile",
- net::FtpDirectoryListingEntry::FILE, "afile", 123,
+ FtpDirectoryListingEntry::FILE, "afile", 123,
1994, 11, 11, 18, 25 },
};
for (size_t i = 0; i < arraysize(good_cases); i++) {
SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
good_cases[i].input));
- net::FtpDirectoryListingParserNetware parser(GetMockCurrentTime());
- // The parser requires a "total n" like before accepting regular input.
- ASSERT_TRUE(parser.ConsumeLine(UTF8ToUTF16("total 1")));
- RunSingleLineTestCase(&parser, good_cases[i]);
+ std::vector<string16> lines(GetSingleLineTestCase(good_cases[i].input));
+
+ // The parser requires a "total n" line before accepting regular input.
+ lines.insert(lines.begin(), ASCIIToUTF16("total 1"));
+
+ std::vector<FtpDirectoryListingEntry> entries;
+ EXPECT_TRUE(ParseFtpDirectoryListingNetware(lines,
+ GetMockCurrentTime(),
+ &entries));
+ VerifySingleLineTestCase(good_cases[i], entries);
}
}
@@ -45,11 +53,21 @@ TEST_F(FtpDirectoryListingParserNetwareTest, Bad) {
"l [RW------] ftpadmin 512 Jan 29 2004 pub",
};
for (size_t i = 0; i < arraysize(bad_cases); i++) {
- net::FtpDirectoryListingParserNetware parser(GetMockCurrentTime());
- // The parser requires a "total n" like before accepting regular input.
- ASSERT_TRUE(parser.ConsumeLine(UTF8ToUTF16("total 1")));
- EXPECT_FALSE(parser.ConsumeLine(UTF8ToUTF16(bad_cases[i]))) << bad_cases[i];
+ SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
+ bad_cases[i]));
+
+ std::vector<string16> lines(GetSingleLineTestCase(bad_cases[i]));
+
+ // The parser requires a "total n" line before accepting regular input.
+ lines.insert(lines.begin(), ASCIIToUTF16("total 1"));
+
+ std::vector<FtpDirectoryListingEntry> entries;
+ EXPECT_FALSE(ParseFtpDirectoryListingNetware(lines,
+ GetMockCurrentTime(),
+ &entries));
}
}
} // namespace
+
+} // namespace net
diff --git a/net/ftp/ftp_directory_listing_buffer_unittest.cc b/net/ftp/ftp_directory_listing_parser_unittest.cc
index 4c71008..b8f0851 100644
--- a/net/ftp/ftp_directory_listing_buffer_unittest.cc
+++ b/net/ftp/ftp_directory_listing_parser_unittest.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2009 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.
-#include "net/ftp/ftp_directory_listing_buffer.h"
+#include "net/ftp/ftp_directory_listing_parser.h"
#include "base/file_util.h"
#include "base/format_macros.h"
@@ -15,6 +15,8 @@
#include "net/ftp/ftp_directory_listing_parser.h"
#include "testing/gtest/include/gtest/gtest.h"
+namespace net {
+
namespace {
TEST(FtpDirectoryListingBufferTest, Parse) {
@@ -73,15 +75,14 @@ TEST(FtpDirectoryListingBufferTest, Parse) {
for (size_t i = 0; i < arraysize(test_files); i++) {
SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i, test_files[i]));
- net::FtpDirectoryListingBuffer buffer(mock_current_time);
-
std::string test_listing;
EXPECT_TRUE(file_util::ReadFileToString(test_dir.AppendASCII(test_files[i]),
&test_listing));
- EXPECT_EQ(net::OK, buffer.ConsumeData(test_listing.data(),
- test_listing.length()));
- EXPECT_EQ(net::OK, buffer.ProcessRemainingData());
+ std::vector<FtpDirectoryListingEntry> entries;
+ EXPECT_EQ(OK, ParseFtpDirectoryListing(test_listing,
+ mock_current_time,
+ &entries));
std::string expected_listing;
ASSERT_TRUE(file_util::ReadFileToString(
@@ -92,7 +93,8 @@ TEST(FtpDirectoryListingBufferTest, Parse) {
StringTokenizer tokenizer(expected_listing, "\r\n");
while (tokenizer.GetNext())
lines.push_back(tokenizer.token());
- ASSERT_EQ(0U, lines.size() % 8);
+
+ ASSERT_EQ(8 * entries.size(), lines.size());
for (size_t i = 0; i < lines.size() / 8; i++) {
std::string type(lines[8 * i]);
@@ -109,15 +111,14 @@ TEST(FtpDirectoryListingBufferTest, Parse) {
base::StringToInt(lines[8 * i + 6], &hour);
base::StringToInt(lines[8 * i + 7], &minute);
- ASSERT_TRUE(buffer.EntryAvailable());
- net::FtpDirectoryListingEntry entry = buffer.PopEntry();
+ const FtpDirectoryListingEntry& entry = entries[i];
if (type == "d") {
- EXPECT_EQ(net::FtpDirectoryListingEntry::DIRECTORY, entry.type);
+ EXPECT_EQ(FtpDirectoryListingEntry::DIRECTORY, entry.type);
} else if (type == "-") {
- EXPECT_EQ(net::FtpDirectoryListingEntry::FILE, entry.type);
+ EXPECT_EQ(FtpDirectoryListingEntry::FILE, entry.type);
} else if (type == "l") {
- EXPECT_EQ(net::FtpDirectoryListingEntry::SYMLINK, entry.type);
+ EXPECT_EQ(FtpDirectoryListingEntry::SYMLINK, entry.type);
} else {
ADD_FAILURE() << "invalid gold test data: " << type;
}
@@ -133,8 +134,9 @@ TEST(FtpDirectoryListingBufferTest, Parse) {
EXPECT_EQ(hour, time_exploded.hour);
EXPECT_EQ(minute, time_exploded.minute);
}
- EXPECT_FALSE(buffer.EntryAvailable());
}
}
} // namespace
+
+} // namespace net
diff --git a/net/ftp/ftp_directory_listing_parser_unittest.h b/net/ftp/ftp_directory_listing_parser_unittest.h
index 5f9d6f0..11eb75b 100644
--- a/net/ftp/ftp_directory_listing_parser_unittest.h
+++ b/net/ftp/ftp_directory_listing_parser_unittest.h
@@ -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.
@@ -6,6 +6,8 @@
#define NET_FTP_FTP_DIRECTORY_LISTING_PARSER_UNITTEST_H_
#pragma once
+#include <vector>
+
#include "base/utf_string_conversions.h"
#include "net/ftp/ftp_directory_listing_parser.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -29,11 +31,18 @@ class FtpDirectoryListingParserTest : public testing::Test {
protected:
FtpDirectoryListingParserTest() {}
- void RunSingleLineTestCase(FtpDirectoryListingParser* parser,
- const SingleLineTestData& test_case) {
- ASSERT_TRUE(parser->ConsumeLine(UTF8ToUTF16(test_case.input)));
- ASSERT_TRUE(parser->EntryAvailable());
- FtpDirectoryListingEntry entry = parser->PopEntry();
+ std::vector<string16> GetSingleLineTestCase(const std::string& text) {
+ std::vector<string16> lines;
+ lines.push_back(UTF8ToUTF16(text));
+ return lines;
+ }
+
+ void VerifySingleLineTestCase(
+ const SingleLineTestData& test_case,
+ const std::vector<FtpDirectoryListingEntry>& entries) {
+ ASSERT_FALSE(entries.empty());
+
+ FtpDirectoryListingEntry entry = entries[0];
EXPECT_EQ(test_case.type, entry.type);
EXPECT_EQ(UTF8ToUTF16(test_case.filename), entry.name);
EXPECT_EQ(test_case.size, entry.size);
@@ -47,6 +56,8 @@ class FtpDirectoryListingParserTest : public testing::Test {
EXPECT_EQ(test_case.day_of_month, time_exploded.day_of_month);
EXPECT_EQ(test_case.hour, time_exploded.hour);
EXPECT_EQ(test_case.minute, time_exploded.minute);
+
+ EXPECT_EQ(1U, entries.size());
}
base::Time GetMockCurrentTime() {
@@ -58,9 +69,6 @@ class FtpDirectoryListingParserTest : public testing::Test {
mock_current_time_exploded.minute = 45;
return base::Time::FromLocalExploded(mock_current_time_exploded);
}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(FtpDirectoryListingParserTest);
};
} // namespace net
diff --git a/net/ftp/ftp_directory_listing_parser_vms.cc b/net/ftp/ftp_directory_listing_parser_vms.cc
index 65a3161..9a8a2f7 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
diff --git a/net/ftp/ftp_directory_listing_parser_vms.h b/net/ftp/ftp_directory_listing_parser_vms.h
index 6f7fb73..8986fcb 100644
--- a/net/ftp/ftp_directory_listing_parser_vms.h
+++ b/net/ftp/ftp_directory_listing_parser_vms.h
@@ -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.
@@ -6,60 +6,18 @@
#define NET_FTP_FTP_DIRECTORY_LISTING_PARSER_VMS_H_
#pragma once
-#include <queue>
+#include <vector>
-#include "net/ftp/ftp_directory_listing_parser.h"
+#include "base/string16.h"
namespace net {
-// Parser for VMS-style directory listing (including variants).
-class FtpDirectoryListingParserVms : public FtpDirectoryListingParser {
- public:
- FtpDirectoryListingParserVms();
- virtual ~FtpDirectoryListingParserVms();
+struct FtpDirectoryListingEntry;
- // FtpDirectoryListingParser methods:
- virtual FtpServerType GetServerType() const;
- virtual bool ConsumeLine(const string16& line);
- virtual bool OnEndOfInput();
- virtual bool EntryAvailable() const;
- virtual FtpDirectoryListingEntry PopEntry();
-
- private:
- enum State {
- STATE_INITIAL,
-
- // Indicates that we have received the header, like this:
- // Directory SYS$SYSDEVICE:[ANONYMOUS]
- STATE_RECEIVED_HEADER,
-
- // Indicates that we have received the first listing entry, like this:
- // MADGOAT.DIR;1 2 9-MAY-2001 22:23:44.85
- STATE_ENTRIES,
-
- // Indicates that we have received the last listing entry.
- STATE_RECEIVED_LAST_ENTRY,
-
- // Indicates that we have successfully received all parts of the listing.
- STATE_END,
- };
-
- // Consumes listing line which is expected to be a directory listing entry
- // (and not a comment etc). Returns true on success.
- bool ConsumeEntryLine(const string16& line);
-
- State state_;
-
- // VMS can use two physical lines if the filename is long. The first line will
- // contain the filename, and the second line everything else. Store the
- // filename until we receive the next line.
- string16 last_filename_;
- bool last_is_directory_;
-
- std::queue<FtpDirectoryListingEntry> entries_;
-
- DISALLOW_COPY_AND_ASSIGN(FtpDirectoryListingParserVms);
-};
+// Parses VMS FTP directory listing. Returns true on success.
+bool ParseFtpDirectoryListingVms(
+ const std::vector<string16>& lines,
+ std::vector<FtpDirectoryListingEntry>* entries);
} // namespace net
diff --git a/net/ftp/ftp_directory_listing_parser_vms_unittest.cc b/net/ftp/ftp_directory_listing_parser_vms_unittest.cc
index eb1554d..6643e16 100644
--- a/net/ftp/ftp_directory_listing_parser_vms_unittest.cc
+++ b/net/ftp/ftp_directory_listing_parser_vms_unittest.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.
@@ -11,113 +11,154 @@
#include "base/utf_string_conversions.h"
#include "net/ftp/ftp_directory_listing_parser_vms.h"
+namespace net {
+
namespace {
-typedef net::FtpDirectoryListingParserTest FtpDirectoryListingParserVmsTest;
+typedef FtpDirectoryListingParserTest FtpDirectoryListingParserVmsTest;
TEST_F(FtpDirectoryListingParserVmsTest, Good) {
const struct SingleLineTestData good_cases[] = {
{ "README.TXT;4 2 18-APR-2000 10:40:39.90",
- net::FtpDirectoryListingEntry::FILE, "readme.txt", 1024,
+ FtpDirectoryListingEntry::FILE, "readme.txt", 1024,
2000, 4, 18, 10, 40 },
{ ".WELCOME;1 2 13-FEB-2002 23:32:40.47",
- net::FtpDirectoryListingEntry::FILE, ".welcome", 1024,
+ FtpDirectoryListingEntry::FILE, ".welcome", 1024,
2002, 2, 13, 23, 32 },
{ "FILE.;1 2 13-FEB-2002 23:32:40.47",
- net::FtpDirectoryListingEntry::FILE, "file.", 1024,
+ FtpDirectoryListingEntry::FILE, "file.", 1024,
2002, 2, 13, 23, 32 },
{ "EXAMPLE.TXT;1 1 4-NOV-2009 06:02 [JOHNDOE] (RWED,RWED,,)",
- net::FtpDirectoryListingEntry::FILE, "example.txt", 512,
+ FtpDirectoryListingEntry::FILE, "example.txt", 512,
2009, 11, 4, 6, 2 },
{ "ANNOUNCE.TXT;2 1/16 12-MAR-2005 08:44:57 [SYSTEM] (RWED,RWED,RE,RE)",
- net::FtpDirectoryListingEntry::FILE, "announce.txt", 512,
+ FtpDirectoryListingEntry::FILE, "announce.txt", 512,
2005, 3, 12, 8, 44 },
{ "TEST.DIR;1 1 4-MAR-1999 22:14:34 [UCX$NOBO,ANONYMOUS] (RWE,RWE,RWE,RWE)",
- net::FtpDirectoryListingEntry::DIRECTORY, "test", -1,
+ FtpDirectoryListingEntry::DIRECTORY, "test", -1,
1999, 3, 4, 22, 14 },
{ "ANNOUNCE.TXT;2 1 12-MAR-2005 08:44:57 [X] (,,,)",
- net::FtpDirectoryListingEntry::FILE, "announce.txt", 512,
+ FtpDirectoryListingEntry::FILE, "announce.txt", 512,
2005, 3, 12, 8, 44 },
{ "ANNOUNCE.TXT;2 1 12-MAR-2005 08:44:57 [X] (R,RW,RWD,RE)",
- net::FtpDirectoryListingEntry::FILE, "announce.txt", 512,
+ FtpDirectoryListingEntry::FILE, "announce.txt", 512,
2005, 3, 12, 8, 44 },
{ "ANNOUNCE.TXT;2 1 12-MAR-2005 08:44:57 [X] (ED,RED,WD,WED)",
- net::FtpDirectoryListingEntry::FILE, "announce.txt", 512,
+ FtpDirectoryListingEntry::FILE, "announce.txt", 512,
2005, 3, 12, 8, 44 },
};
for (size_t i = 0; i < arraysize(good_cases); i++) {
SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
good_cases[i].input));
- net::FtpDirectoryListingParserVms parser;
- ASSERT_TRUE(
- parser.ConsumeLine(ASCIIToUTF16("Directory ANONYMOUS_ROOT:[000000]")));
- RunSingleLineTestCase(&parser, good_cases[i]);
+ std::vector<string16> lines(GetSingleLineTestCase(good_cases[i].input));
+
+ // The parser requires a directory header before accepting regular input.
+ lines.insert(lines.begin(),
+ ASCIIToUTF16("Directory ANONYMOUS_ROOT:[000000]"));
+
+ // A valid listing must also have a "Total" line at the end.
+ lines.insert(lines.end(),
+ ASCIIToUTF16("Total of 1 file, 2 blocks."));
+
+ std::vector<FtpDirectoryListingEntry> entries;
+ EXPECT_TRUE(ParseFtpDirectoryListingVms(lines,
+ &entries));
+ VerifySingleLineTestCase(good_cases[i], entries);
}
}
TEST_F(FtpDirectoryListingParserVmsTest, Bad) {
const char* bad_cases[] = {
- "Directory ROOT|garbage",
+ "garbage",
// Missing file version number.
- "Directory ROOT|README.TXT 2 18-APR-2000 10:40:39",
+ "README.TXT 2 18-APR-2000 10:40:39",
// Missing extension.
- "Directory ROOT|README;1 2 18-APR-2000 10:40:39",
+ "README;1 2 18-APR-2000 10:40:39",
// Malformed file size.
- "Directory ROOT|README.TXT;1 garbage 18-APR-2000 10:40:39",
- "Directory ROOT|README.TXT;1 -2 18-APR-2000 10:40:39",
+ "README.TXT;1 garbage 18-APR-2000 10:40:39",
+ "README.TXT;1 -2 18-APR-2000 10:40:39",
// Malformed date.
- "Directory ROOT|README.TXT;1 2 APR-2000 10:40:39",
- "Directory ROOT|README.TXT;1 2 -18-APR-2000 10:40:39",
- "Directory ROOT|README.TXT;1 2 18-APR 10:40:39",
- "Directory ROOT|README.TXT;1 2 18-APR-2000 10",
- "Directory ROOT|README.TXT;1 2 18-APR-2000 10:40.25",
- "Directory ROOT|README.TXT;1 2 18-APR-2000 10:40.25.25",
-
- // Empty line inside the listing.
- "Directory ROOT|README.TXT;1 2 18-APR-2000 10:40:42"
- "||README.TXT;1 2 18-APR-2000 10:40:42",
-
- // Data after footer.
- "Directory ROOT|README.TXT;4 2 18-APR-2000 10:40:39"
- "||Total of 1 file|",
- "Directory ROOT|README.TXT;4 2 18-APR-2000 10:40:39"
- "||Total of 1 file|garbage",
- "Directory ROOT|README.TXT;4 2 18-APR-2000 10:40:39"
- "||Total of 1 file|Total of 1 file",
+ "README.TXT;1 2 APR-2000 10:40:39",
+ "README.TXT;1 2 -18-APR-2000 10:40:39",
+ "README.TXT;1 2 18-APR 10:40:39",
+ "README.TXT;1 2 18-APR-2000 10",
+ "README.TXT;1 2 18-APR-2000 10:40.25",
+ "README.TXT;1 2 18-APR-2000 10:40.25.25",
// Malformed security information.
- "Directory ROOT|X.TXT;2 1 12-MAR-2005 08:44:57 (RWED,RWED,RE,RE)",
- "Directory ROOT|X.TXT;2 1 12-MAR-2005 08:44:57 [SYSTEM]",
- "Directory ROOT|X.TXT;2 1 12-MAR-2005 08:44:57 (SYSTEM) (RWED,RWED,RE,RE)",
- "Directory ROOT|X.TXT;2 1 12-MAR-2005 08:44:57 [SYSTEM] [RWED,RWED,RE,RE]",
- "Directory ROOT|X.TXT;2 1 12-MAR-2005 08:44:57 [X] (RWED)",
- "Directory ROOT|X.TXT;2 1 12-MAR-2005 08:44:57 [X] (RWED,RWED,RE,RE,RE)",
- "Directory ROOT|X.TXT;2 1 12-MAR-2005 08:44:57 [X] (RWED,RWEDRWED,RE,RE)",
- "Directory ROOT|X.TXT;2 1 12-MAR-2005 08:44:57 [X] (RWED,DEWR,RE,RE)",
- "Directory ROOT|X.TXT;2 1 12-MAR-2005 08:44:57 [X] (RWED,RWED,Q,RE)",
- "Directory ROOT|X.TXT;2 1 12-MAR-2005 08:44:57 [X] (RWED,RRWWEEDD,RE,RE)",
+ "X.TXT;2 1 12-MAR-2005 08:44:57 (RWED,RWED,RE,RE)",
+ "X.TXT;2 1 12-MAR-2005 08:44:57 [SYSTEM]",
+ "X.TXT;2 1 12-MAR-2005 08:44:57 (SYSTEM) (RWED,RWED,RE,RE)",
+ "X.TXT;2 1 12-MAR-2005 08:44:57 [SYSTEM] [RWED,RWED,RE,RE]",
+ "X.TXT;2 1 12-MAR-2005 08:44:57 [X] (RWED)",
+ "X.TXT;2 1 12-MAR-2005 08:44:57 [X] (RWED,RWED,RE,RE,RE)",
+ "X.TXT;2 1 12-MAR-2005 08:44:57 [X] (RWED,RWEDRWED,RE,RE)",
+ "X.TXT;2 1 12-MAR-2005 08:44:57 [X] (RWED,DEWR,RE,RE)",
+ "X.TXT;2 1 12-MAR-2005 08:44:57 [X] (RWED,RWED,Q,RE)",
+ "X.TXT;2 1 12-MAR-2005 08:44:57 [X] (RWED,RRWWEEDD,RE,RE)",
};
for (size_t i = 0; i < arraysize(bad_cases); i++) {
SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i, bad_cases[i]));
- std::vector<std::string> lines;
- base::SplitString(bad_cases[i], '|', &lines);
- net::FtpDirectoryListingParserVms parser;
- bool failed = false;
- for (std::vector<std::string>::const_iterator i = lines.begin();
- i != lines.end(); ++i) {
- if (!parser.ConsumeLine(UTF8ToUTF16(*i))) {
- failed = true;
- break;
- }
+ std::vector<string16> lines(GetSingleLineTestCase(bad_cases[i]));
+
+ // The parser requires a directory header before accepting regular input.
+ lines.insert(lines.begin(),
+ ASCIIToUTF16("Directory ANONYMOUS_ROOT:[000000]"));
+
+ // A valid listing must also have a "Total" line at the end.
+ lines.insert(lines.end(),
+ ASCIIToUTF16("Total of 1 file, 2 blocks."));
+
+ std::vector<FtpDirectoryListingEntry> entries;
+ EXPECT_FALSE(ParseFtpDirectoryListingVms(lines,
+ &entries));
+ }
+}
+
+TEST_F(FtpDirectoryListingParserVmsTest, BadDataAfterFooter) {
+ const char* bad_cases[] = {
+ "garbage",
+ "Total of 1 file, 2 blocks.",
+ "Directory ANYNYMOUS_ROOT:[000000]",
+ };
+ for (size_t i = 0; i < arraysize(bad_cases); i++) {
+ SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i, bad_cases[i]));
+
+ std::vector<string16> lines(
+ GetSingleLineTestCase("README.TXT;4 2 18-APR-2000 10:40:39.90"));
+
+ // The parser requires a directory header before accepting regular input.
+ lines.insert(lines.begin(),
+ ASCIIToUTF16("Directory ANONYMOUS_ROOT:[000000]"));
+
+ // A valid listing must also have a "Total" line at the end.
+ lines.insert(lines.end(),
+ ASCIIToUTF16("Total of 1 file, 2 blocks."));
+
+ {
+ // Make sure the listing is valid before we add data after footer.
+ std::vector<FtpDirectoryListingEntry> entries;
+ EXPECT_TRUE(ParseFtpDirectoryListingVms(lines,
+ &entries));
+ }
+
+ {
+ // Insert a line at the end of the listing that should make it invalid.
+ lines.insert(lines.end(),
+ ASCIIToUTF16(bad_cases[i]));
+ std::vector<FtpDirectoryListingEntry> entries;
+ EXPECT_FALSE(ParseFtpDirectoryListingVms(lines,
+ &entries));
}
- EXPECT_TRUE(failed);
}
}
} // namespace
+
+} // namespace net
diff --git a/net/ftp/ftp_directory_listing_parser_windows.cc b/net/ftp/ftp_directory_listing_parser_windows.cc
index ef733d5..2317fa3 100644
--- a/net/ftp/ftp_directory_listing_parser_windows.cc
+++ b/net/ftp/ftp_directory_listing_parser_windows.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,6 +9,8 @@
#include "base/string_number_conversions.h"
#include "base/string_split.h"
#include "base/string_util.h"
+#include "base/time.h"
+#include "net/ftp/ftp_directory_listing_parser.h"
#include "net/ftp/ftp_util.h"
namespace {
@@ -72,68 +74,55 @@ bool WindowsDateListingToTime(const std::vector<string16>& columns,
namespace net {
-FtpDirectoryListingParserWindows::FtpDirectoryListingParserWindows() {}
-
-FtpDirectoryListingParserWindows::~FtpDirectoryListingParserWindows() {}
-
-FtpServerType FtpDirectoryListingParserWindows::GetServerType() const {
- return SERVER_WINDOWS;
-}
-
-bool FtpDirectoryListingParserWindows::ConsumeLine(const string16& line) {
- std::vector<string16> columns;
- base::SplitString(CollapseWhitespace(line, false), ' ', &columns);
-
- // Every line of the listing consists of the following:
- //
- // 1. date
- // 2. time
- // 3. size in bytes (or "<DIR>" for directories)
- // 4. filename (may be empty or contain spaces)
- //
- // For now, make sure we have 1-3, and handle 4 later.
- if (columns.size() < 3)
- return false;
-
- FtpDirectoryListingEntry entry;
- if (EqualsASCII(columns[2], "<DIR>")) {
- entry.type = FtpDirectoryListingEntry::DIRECTORY;
- entry.size = -1;
- } else {
- entry.type = FtpDirectoryListingEntry::FILE;
- if (!base::StringToInt64(columns[2], &entry.size))
+bool ParseFtpDirectoryListingWindows(
+ const std::vector<string16>& lines,
+ std::vector<FtpDirectoryListingEntry>* entries) {
+ 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);
+
+ // Every line of the listing consists of the following:
+ //
+ // 1. date
+ // 2. time
+ // 3. size in bytes (or "<DIR>" for directories)
+ // 4. filename (may be empty or contain spaces)
+ //
+ // For now, make sure we have 1-3, and handle 4 later.
+ if (columns.size() < 3)
return false;
- if (entry.size < 0)
+
+ FtpDirectoryListingEntry entry;
+ if (EqualsASCII(columns[2], "<DIR>")) {
+ entry.type = FtpDirectoryListingEntry::DIRECTORY;
+ entry.size = -1;
+ } else {
+ entry.type = FtpDirectoryListingEntry::FILE;
+ if (!base::StringToInt64(columns[2], &entry.size))
+ return false;
+ if (entry.size < 0)
+ return false;
+ }
+
+ if (!WindowsDateListingToTime(columns, &entry.last_modified))
return false;
- }
- if (!WindowsDateListingToTime(columns, &entry.last_modified))
- return false;
+ entry.name = FtpUtil::GetStringPartAfterColumns(lines[i], 3);
+ 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;
+ }
- entry.name = FtpUtil::GetStringPartAfterColumns(line, 3);
- 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;
+ entries->push_back(entry);
}
- entries_.push(entry);
- return true;
-}
-
-bool FtpDirectoryListingParserWindows::OnEndOfInput() {
return true;
}
-bool FtpDirectoryListingParserWindows::EntryAvailable() const {
- return !entries_.empty();
-}
-
-FtpDirectoryListingEntry FtpDirectoryListingParserWindows::PopEntry() {
- FtpDirectoryListingEntry entry = entries_.front();
- entries_.pop();
- return entry;
-}
-
} // namespace net
diff --git a/net/ftp/ftp_directory_listing_parser_windows.h b/net/ftp/ftp_directory_listing_parser_windows.h
index 1f029af..581e08c 100644
--- a/net/ftp/ftp_directory_listing_parser_windows.h
+++ b/net/ftp/ftp_directory_listing_parser_windows.h
@@ -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.
@@ -6,29 +6,18 @@
#define NET_FTP_FTP_DIRECTORY_LISTING_PARSER_WINDOWS_H_
#pragma once
-#include <queue>
+#include <vector>
-#include "net/ftp/ftp_directory_listing_parser.h"
+#include "base/string16.h"
namespace net {
-class FtpDirectoryListingParserWindows : public FtpDirectoryListingParser {
- public:
- FtpDirectoryListingParserWindows();
- virtual ~FtpDirectoryListingParserWindows();
+struct FtpDirectoryListingEntry;
- // FtpDirectoryListingParser methods:
- virtual FtpServerType GetServerType() const;
- virtual bool ConsumeLine(const string16& line);
- virtual bool OnEndOfInput();
- virtual bool EntryAvailable() const;
- virtual FtpDirectoryListingEntry PopEntry();
-
- private:
- std::queue<FtpDirectoryListingEntry> entries_;
-
- DISALLOW_COPY_AND_ASSIGN(FtpDirectoryListingParserWindows);
-};
+// Parses Windows FTP directory listing. Returns true on success.
+bool ParseFtpDirectoryListingWindows(
+ const std::vector<string16>& lines,
+ std::vector<FtpDirectoryListingEntry>* entries);
} // namespace net
diff --git a/net/ftp/ftp_directory_listing_parser_windows_unittest.cc b/net/ftp/ftp_directory_listing_parser_windows_unittest.cc
index aeb64e7..7517baf 100644
--- a/net/ftp/ftp_directory_listing_parser_windows_unittest.cc
+++ b/net/ftp/ftp_directory_listing_parser_windows_unittest.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,58 +9,63 @@
#include "base/stringprintf.h"
#include "net/ftp/ftp_directory_listing_parser_windows.h"
+namespace net {
+
namespace {
-typedef net::FtpDirectoryListingParserTest FtpDirectoryListingParserWindowsTest;
+typedef FtpDirectoryListingParserTest FtpDirectoryListingParserWindowsTest;
TEST_F(FtpDirectoryListingParserWindowsTest, Good) {
const struct SingleLineTestData good_cases[] = {
{ "11-02-09 05:32PM <DIR> NT",
- net::FtpDirectoryListingEntry::DIRECTORY, "NT", -1,
+ FtpDirectoryListingEntry::DIRECTORY, "NT", -1,
2009, 11, 2, 17, 32 },
{ "01-06-09 02:42PM 458 Readme.txt",
- net::FtpDirectoryListingEntry::FILE, "Readme.txt", 458,
+ FtpDirectoryListingEntry::FILE, "Readme.txt", 458,
2009, 1, 6, 14, 42 },
{ "01-06-09 02:42AM 1 Readme.txt",
- net::FtpDirectoryListingEntry::FILE, "Readme.txt", 1,
+ FtpDirectoryListingEntry::FILE, "Readme.txt", 1,
2009, 1, 6, 2, 42 },
{ "01-06-01 02:42AM 458 Readme.txt",
- net::FtpDirectoryListingEntry::FILE, "Readme.txt", 458,
+ FtpDirectoryListingEntry::FILE, "Readme.txt", 458,
2001, 1, 6, 2, 42 },
{ "01-06-00 02:42AM 458 Corner1.txt",
- net::FtpDirectoryListingEntry::FILE, "Corner1.txt", 458,
+ FtpDirectoryListingEntry::FILE, "Corner1.txt", 458,
2000, 1, 6, 2, 42 },
{ "01-06-99 02:42AM 458 Corner2.txt",
- net::FtpDirectoryListingEntry::FILE, "Corner2.txt", 458,
+ FtpDirectoryListingEntry::FILE, "Corner2.txt", 458,
1999, 1, 6, 2, 42 },
{ "01-06-80 02:42AM 458 Corner3.txt",
- net::FtpDirectoryListingEntry::FILE, "Corner3.txt", 458,
+ FtpDirectoryListingEntry::FILE, "Corner3.txt", 458,
1980, 1, 6, 2, 42 },
#if !defined(OS_LINUX)
// TODO(phajdan.jr): Re-enable when 2038-year problem is fixed on Linux.
{ "01-06-79 02:42AM 458 Corner4",
- net::FtpDirectoryListingEntry::FILE, "Corner4", 458,
+ FtpDirectoryListingEntry::FILE, "Corner4", 458,
2079, 1, 6, 2, 42 },
#endif // !defined (OS_LINUX)
{ "01-06-1979 02:42AM 458 Readme.txt",
- net::FtpDirectoryListingEntry::FILE, "Readme.txt", 458,
+ FtpDirectoryListingEntry::FILE, "Readme.txt", 458,
1979, 1, 6, 2, 42 },
{ "11-02-09 05:32PM <DIR> My Directory",
- net::FtpDirectoryListingEntry::DIRECTORY, "My Directory", -1,
+ FtpDirectoryListingEntry::DIRECTORY, "My Directory", -1,
2009, 11, 2, 17, 32 },
{ "12-25-10 12:00AM <DIR> Christmas Midnight",
- net::FtpDirectoryListingEntry::DIRECTORY, "Christmas Midnight", -1,
+ FtpDirectoryListingEntry::DIRECTORY, "Christmas Midnight", -1,
2010, 12, 25, 0, 0 },
{ "12-25-10 12:00PM <DIR> Christmas Midday",
- net::FtpDirectoryListingEntry::DIRECTORY, "Christmas Midday", -1,
+ FtpDirectoryListingEntry::DIRECTORY, "Christmas Midday", -1,
2010, 12, 25, 12, 0 },
};
for (size_t i = 0; i < arraysize(good_cases); i++) {
SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
good_cases[i].input));
- net::FtpDirectoryListingParserWindows parser;
- RunSingleLineTestCase(&parser, good_cases[i]);
+ std::vector<FtpDirectoryListingEntry> entries;
+ EXPECT_TRUE(ParseFtpDirectoryListingWindows(
+ GetSingleLineTestCase(good_cases[i].input),
+ &entries));
+ VerifySingleLineTestCase(good_cases[i], entries);
}
}
@@ -73,17 +78,16 @@ TEST_F(FtpDirectoryListingParserWindowsTest, Ignored) {
SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
ignored_cases[i]));
- net::FtpDirectoryListingParserWindows parser;
- EXPECT_TRUE(parser.ConsumeLine(UTF8ToUTF16(ignored_cases[i])));
- EXPECT_FALSE(parser.EntryAvailable());
- EXPECT_TRUE(parser.OnEndOfInput());
- EXPECT_FALSE(parser.EntryAvailable());
+ std::vector<FtpDirectoryListingEntry> entries;
+ EXPECT_TRUE(ParseFtpDirectoryListingWindows(
+ GetSingleLineTestCase(ignored_cases[i]),
+ &entries));
+ EXPECT_EQ(0U, entries.size());
}
}
TEST_F(FtpDirectoryListingParserWindowsTest, Bad) {
const char* bad_cases[] = {
- "",
"garbage",
"11-02-09 05:32PM <GARBAGE>",
"11-02-09 05:32PM <GARBAGE> NT",
@@ -107,9 +111,16 @@ TEST_F(FtpDirectoryListingParserWindowsTest, Bad) {
"12-25-10 12:00ZM 0 what does ZM mean",
};
for (size_t i = 0; i < arraysize(bad_cases); i++) {
- net::FtpDirectoryListingParserWindows parser;
- EXPECT_FALSE(parser.ConsumeLine(UTF8ToUTF16(bad_cases[i]))) << bad_cases[i];
+ SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
+ bad_cases[i]));
+
+ std::vector<FtpDirectoryListingEntry> entries;
+ EXPECT_FALSE(ParseFtpDirectoryListingWindows(
+ GetSingleLineTestCase(bad_cases[i]),
+ &entries));
}
}
} // namespace
+
+} // namespace net
diff --git a/net/net.gyp b/net/net.gyp
index 4bb30b5..e3837de 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -426,8 +426,6 @@
'ftp/ftp_auth_cache.h',
'ftp/ftp_ctrl_response_buffer.cc',
'ftp/ftp_ctrl_response_buffer.h',
- 'ftp/ftp_directory_listing_buffer.cc',
- 'ftp/ftp_directory_listing_buffer.h',
'ftp/ftp_directory_listing_parser.cc',
'ftp/ftp_directory_listing_parser.h',
'ftp/ftp_directory_listing_parser_ls.cc',
@@ -931,9 +929,9 @@
'disk_cache/storage_block_unittest.cc',
'ftp/ftp_auth_cache_unittest.cc',
'ftp/ftp_ctrl_response_buffer_unittest.cc',
- 'ftp/ftp_directory_listing_buffer_unittest.cc',
'ftp/ftp_directory_listing_parser_ls_unittest.cc',
'ftp/ftp_directory_listing_parser_netware_unittest.cc',
+ 'ftp/ftp_directory_listing_parser_unittest.cc',
'ftp/ftp_directory_listing_parser_vms_unittest.cc',
'ftp/ftp_directory_listing_parser_windows_unittest.cc',
'ftp/ftp_network_transaction_unittest.cc',