diff options
author | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-07 09:30:20 +0000 |
---|---|---|
committer | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-07 09:30:20 +0000 |
commit | 6373cf4d71577e2e690fed377959d79056908291 (patch) | |
tree | be34056807c1394603dec332e13f08e3f008be81 | |
parent | 5e6c1e4a641a9668c70e713f3e559ebde15c775c (diff) | |
download | chromium_src-6373cf4d71577e2e690fed377959d79056908291.zip chromium_src-6373cf4d71577e2e690fed377959d79056908291.tar.gz chromium_src-6373cf4d71577e2e690fed377959d79056908291.tar.bz2 |
Use the new FTP LIST parsing code in the browser.
Fall back to the old parsing code on errors.
TEST=none
BUG=25520
Review URL: http://codereview.chromium.org/343073
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@31379 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | net/ftp/ftp_directory_listing_buffer.cc | 7 | ||||
-rw-r--r-- | net/ftp/ftp_directory_listing_buffer.h | 17 | ||||
-rw-r--r-- | net/ftp/ftp_directory_listing_parsers.h | 5 | ||||
-rw-r--r-- | webkit/glue/ftp_directory_listing_response_delegate.cc | 141 | ||||
-rw-r--r-- | webkit/glue/ftp_directory_listing_response_delegate.h | 14 |
5 files changed, 132 insertions, 52 deletions
diff --git a/net/ftp/ftp_directory_listing_buffer.cc b/net/ftp/ftp_directory_listing_buffer.cc index 8e3ee39..e41cb9e 100644 --- a/net/ftp/ftp_directory_listing_buffer.cc +++ b/net/ftp/ftp_directory_listing_buffer.cc @@ -67,6 +67,9 @@ int FtpDirectoryListingBuffer::ProcessRemainingData() { if (rv != OK) return rv; + if (!buffer_.empty()) + return ERR_INVALID_RESPONSE; + return ParseLines(); } @@ -79,6 +82,10 @@ FtpDirectoryListingEntry FtpDirectoryListingBuffer::PopEntry() { return current_parser_->PopEntry(); } +FtpServerType FtpDirectoryListingBuffer::GetServerType() const { + return (current_parser_ ? current_parser_->GetServerType() : SERVER_UNKNOWN); +} + bool FtpDirectoryListingBuffer::ConvertToDetectedEncoding( const std::string& from, string16* to) { std::string encoding(encoding_.empty() ? "ascii" : encoding_); diff --git a/net/ftp/ftp_directory_listing_buffer.h b/net/ftp/ftp_directory_listing_buffer.h index eaa237e..9489135 100644 --- a/net/ftp/ftp_directory_listing_buffer.h +++ b/net/ftp/ftp_directory_listing_buffer.h @@ -12,16 +12,17 @@ #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: FtpDirectoryListingBuffer(); - + ~FtpDirectoryListingBuffer(); // Called when data is received from the data socket. Returns network @@ -38,9 +39,13 @@ class FtpDirectoryListingBuffer { // 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; + private: typedef std::set<FtpDirectoryListingParser*> ParserSet; - + // Converts the string |from| to detected encoding and stores it in |to|. // Returns true on success. bool ConvertToDetectedEncoding(const std::string& from, string16* to); @@ -60,11 +65,11 @@ class FtpDirectoryListingBuffer { // 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_; diff --git a/net/ftp/ftp_directory_listing_parsers.h b/net/ftp/ftp_directory_listing_parsers.h index 62a23cf..6906861 100644 --- a/net/ftp/ftp_directory_listing_parsers.h +++ b/net/ftp/ftp_directory_listing_parsers.h @@ -33,6 +33,8 @@ 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; @@ -50,6 +52,7 @@ class FtpLsDirectoryListingParser : public FtpDirectoryListingParser { FtpLsDirectoryListingParser(); // FtpDirectoryListingParser methods: + virtual FtpServerType GetServerType() const { return SERVER_LSL; } virtual bool ConsumeLine(const string16& line); virtual bool EntryAvailable() const; virtual FtpDirectoryListingEntry PopEntry(); @@ -67,6 +70,7 @@ class FtpWindowsDirectoryListingParser : public FtpDirectoryListingParser { FtpWindowsDirectoryListingParser(); // FtpDirectoryListingParser methods: + virtual FtpServerType GetServerType() const { return SERVER_DOS; } virtual bool ConsumeLine(const string16& line); virtual bool EntryAvailable() const; virtual FtpDirectoryListingEntry PopEntry(); @@ -83,6 +87,7 @@ class FtpVmsDirectoryListingParser : public FtpDirectoryListingParser { FtpVmsDirectoryListingParser(); // FtpDirectoryListingParser methods: + virtual FtpServerType GetServerType() const { return SERVER_VMS; } virtual bool ConsumeLine(const string16& line); virtual bool EntryAvailable() const; virtual FtpDirectoryListingEntry PopEntry(); diff --git a/webkit/glue/ftp_directory_listing_response_delegate.cc b/webkit/glue/ftp_directory_listing_response_delegate.cc index 093973e..9f7f062 100644 --- a/webkit/glue/ftp_directory_listing_response_delegate.cc +++ b/webkit/glue/ftp_directory_listing_response_delegate.cc @@ -12,7 +12,9 @@ #include "base/sys_string_conversions.h" #include "base/time.h" #include "net/base/escape.h" +#include "net/base/net_errors.h" #include "net/base/net_util.h" +#include "net/ftp/ftp_directory_listing_parsers.h" #include "net/ftp/ftp_server_type_histograms.h" #include "unicode/ucsdet.h" #include "webkit/api/public/WebURL.h" @@ -119,14 +121,85 @@ FtpDirectoryListingResponseDelegate::FtpDirectoryListingResponseDelegate( const WebURLResponse& response) : client_(client), loader_(loader), - original_response_(response) { + original_response_(response), + parser_fallback_(false) { Init(); } void FtpDirectoryListingResponseDelegate::OnReceivedData(const char* data, int data_len) { + // Keep the raw data in case we have to use the old parser later. input_buffer_.append(data, data_len); + if (!parser_fallback_) { + if (buffer_.ConsumeData(data, data_len) == net::OK) + return; + parser_fallback_ = true; + } + + FeedFallbackParser(); + SendResponseBufferToClient(); +} + +void FtpDirectoryListingResponseDelegate::OnCompletedRequest() { + if (!parser_fallback_) { + if (buffer_.ProcessRemainingData() == net::OK) { + while (buffer_.EntryAvailable()) + AppendEntryToResponseBuffer(buffer_.PopEntry()); + SendResponseBufferToClient(); + net::UpdateFtpServerTypeHistograms(buffer_.GetServerType()); + return; + } + parser_fallback_ = true; + } + + FeedFallbackParser(); + SendResponseBufferToClient(); + + // Only log the server type if we got enough data to reliably detect it. + if (parse_state_.parsed_one) + LogFtpServerType(parse_state_.lstyle); +} + +void FtpDirectoryListingResponseDelegate::Init() { + memset(&parse_state_, 0, sizeof(parse_state_)); + + GURL response_url(original_response_.url()); + UnescapeRule::Type unescape_rules = UnescapeRule::SPACES | + UnescapeRule::URL_SPECIAL_CHARS; + std::string unescaped_path = UnescapeURLComponent(response_url.path(), + unescape_rules); + string16 path_utf16; + // Per RFC 2640, FTP servers should use UTF-8 or its proper subset ASCII, + // but many old FTP servers use legacy encodings. Try UTF-8 first and + // detect the encoding. + if (IsStringUTF8(unescaped_path)) { + path_utf16 = UTF8ToUTF16(unescaped_path); + } else { + std::string encoding = DetectEncoding(unescaped_path); + // Try the detected encoding. If it fails, resort to the + // OS native encoding. + if (encoding.empty() || + !base::CodepageToUTF16(unescaped_path, encoding.c_str(), + base::OnStringConversionError::SUBSTITUTE, + &path_utf16)) + path_utf16 = WideToUTF16Hack(base::SysNativeMBToWide(unescaped_path)); + } + + response_buffer_ = net::GetDirectoryListingHeader(path_utf16); + + // If this isn't top level directory (i.e. the path isn't "/",) + // add a link to the parent directory. + if (response_url.path().length() > 1) { + response_buffer_.append( + net::GetDirectoryListingEntry(ASCIIToUTF16(".."), + std::string(), + false, 0, + base::Time())); + } +} + +void FtpDirectoryListingResponseDelegate::FeedFallbackParser() { // If all we've seen so far is ASCII, encoding_ is empty. Try to detect the // encoding. We don't do the separate UTF-8 check here because the encoding // detection with a longer chunk (as opposed to the relatively short path @@ -198,53 +271,29 @@ void FtpDirectoryListingResponseDelegate::OnReceivedData(const char* data, break; } } - - SendResponseBufferToClient(); } -void FtpDirectoryListingResponseDelegate::OnCompletedRequest() { - SendResponseBufferToClient(); - - // Only log the server type if we got enough data to reliably detect it. - if (parse_state_.parsed_one) - LogFtpServerType(parse_state_.lstyle); -} - -void FtpDirectoryListingResponseDelegate::Init() { - memset(&parse_state_, 0, sizeof(parse_state_)); - - GURL response_url(original_response_.url()); - UnescapeRule::Type unescape_rules = UnescapeRule::SPACES | - UnescapeRule::URL_SPECIAL_CHARS; - std::string unescaped_path = UnescapeURLComponent(response_url.path(), - unescape_rules); - string16 path_utf16; - // Per RFC 2640, FTP servers should use UTF-8 or its proper subset ASCII, - // but many old FTP servers use legacy encodings. Try UTF-8 first and - // detect the encoding. - if (IsStringUTF8(unescaped_path)) { - path_utf16 = UTF8ToUTF16(unescaped_path); - } else { - std::string encoding = DetectEncoding(unescaped_path); - // Try the detected encoding. If it fails, resort to the - // OS native encoding. - if (encoding.empty() || - !base::CodepageToUTF16(unescaped_path, encoding.c_str(), - base::OnStringConversionError::SUBSTITUTE, - &path_utf16)) - path_utf16 = WideToUTF16Hack(base::SysNativeMBToWide(unescaped_path)); - } - - response_buffer_ = net::GetDirectoryListingHeader(path_utf16); - - // If this isn't top level directory (i.e. the path isn't "/",) - // add a link to the parent directory. - if (response_url.path().length() > 1) { - response_buffer_.append( - net::GetDirectoryListingEntry(ASCIIToUTF16(".."), - std::string(), - false, 0, - base::Time())); +void FtpDirectoryListingResponseDelegate::AppendEntryToResponseBuffer( + const net::FtpDirectoryListingEntry& entry) { + switch (entry.type) { + case net::FtpDirectoryListingEntry::FILE: + response_buffer_.append( + net::GetDirectoryListingEntry(entry.name, std::string(), false, + entry.size, entry.last_modified)); + break; + case net::FtpDirectoryListingEntry::DIRECTORY: + response_buffer_.append( + net::GetDirectoryListingEntry(entry.name, std::string(), true, + 0, entry.last_modified)); + break; + case net::FtpDirectoryListingEntry::SYMLINK: + response_buffer_.append( + net::GetDirectoryListingEntry(entry.name, std::string(), false, + 0, entry.last_modified)); + break; + default: + NOTREACHED(); + break; } } diff --git a/webkit/glue/ftp_directory_listing_response_delegate.h b/webkit/glue/ftp_directory_listing_response_delegate.h index 1ca42d7..82d955c 100644 --- a/webkit/glue/ftp_directory_listing_response_delegate.h +++ b/webkit/glue/ftp_directory_listing_response_delegate.h @@ -10,6 +10,7 @@ #include <string> +#include "net/ftp/ftp_directory_listing_buffer.h" #include "net/third_party/parseftp/ParseFTPList.h" #include "webkit/api/public/WebURLResponse.h" @@ -33,6 +34,11 @@ class FtpDirectoryListingResponseDelegate { private: void Init(); + // Use the old parser to process received listing data. + void FeedFallbackParser(); + + void AppendEntryToResponseBuffer(const net::FtpDirectoryListingEntry& entry); + void SendResponseBufferToClient(); // Pointers to the client and associated loader so we can make callbacks as @@ -44,6 +50,14 @@ class FtpDirectoryListingResponseDelegate { // starting point for each parts response. WebKit::WebURLResponse original_response_; + // Data buffer also responsible for parsing the listing data (the new parser). + // TODO(phajdan.jr): Use only the new parser, when it is more compatible. + net::FtpDirectoryListingBuffer buffer_; + + // True if the new parser couldn't recognize the received listing format + // and we switched to the old parser. + bool parser_fallback_; + // State kept between parsing each line of the response. struct net::list_state parse_state_; |