summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorphajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-07 09:30:20 +0000
committerphajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-07 09:30:20 +0000
commit6373cf4d71577e2e690fed377959d79056908291 (patch)
treebe34056807c1394603dec332e13f08e3f008be81
parent5e6c1e4a641a9668c70e713f3e559ebde15c775c (diff)
downloadchromium_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.cc7
-rw-r--r--net/ftp/ftp_directory_listing_buffer.h17
-rw-r--r--net/ftp/ftp_directory_listing_parsers.h5
-rw-r--r--webkit/glue/ftp_directory_listing_response_delegate.cc141
-rw-r--r--webkit/glue/ftp_directory_listing_response_delegate.h14
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_;