Index: net/url_request/url_request_new_ftp_job.cc |
diff --git a/net/url_request/url_request_new_ftp_job.cc b/net/url_request/url_request_new_ftp_job.cc |
index 83d1a9c85810b696a5c4567a1ac66895b16b10f2..c4c3782dd60a2fde13e757e8fb975c1f557a7b15 100644 |
--- a/net/url_request/url_request_new_ftp_job.cc |
+++ b/net/url_request/url_request_new_ftp_job.cc |
@@ -5,65 +5,18 @@ |
#include "net/url_request/url_request_new_ftp_job.h" |
#include "base/compiler_specific.h" |
-#include "base/file_version_info.h" |
#include "base/message_loop.h" |
-#include "base/sys_string_conversions.h" |
#include "net/base/auth.h" |
-#include "net/base/escape.h" |
#include "net/base/net_errors.h" |
#include "net/base/net_util.h" |
#include "net/ftp/ftp_response_info.h" |
-#include "net/ftp/ftp_server_type_histograms.h" |
#include "net/ftp/ftp_transaction_factory.h" |
-#include "net/third_party/parseftp/ParseFTPList.h" |
#include "net/url_request/url_request.h" |
#include "net/url_request/url_request_context.h" |
#include "net/url_request/url_request_error_job.h" |
-#include "unicode/ucsdet.h" |
- |
-namespace { |
- |
-// A very simple-minded character encoding detection. |
-// TODO(jungshik): We can apply more heuristics here (e.g. using various hints |
-// like TLD, the UI language/default encoding of a client, etc). In that case, |
-// this should be pulled out of here and moved somewhere in base because there |
-// can be other use cases. |
-std::string DetectEncoding(const char* input, size_t len) { |
- if (IsStringASCII(std::string(input, len))) |
- return std::string(); |
- UErrorCode status = U_ZERO_ERROR; |
- UCharsetDetector* detector = ucsdet_open(&status); |
- ucsdet_setText(detector, input, static_cast<int32_t>(len), &status); |
- const UCharsetMatch* match = ucsdet_detect(detector, &status); |
- const char* encoding = ucsdet_getName(match, &status); |
- // Should we check the quality of the match? A rather arbitrary number is |
- // assigned by ICU and it's hard to come up with a lower limit. |
- if (U_FAILURE(status)) |
- return std::string(); |
- return encoding; |
-} |
- |
-string16 RawByteSequenceToFilename(const char* raw_filename, |
- const std::string& encoding) { |
- if (encoding.empty()) |
- return ASCIIToUTF16(raw_filename); |
- |
- // Try the detected encoding before falling back to the native codepage. |
- // Using the native codepage does not make much sense, but we don't have |
- // much else to resort to. |
- string16 filename; |
- if (!CodepageToUTF16(raw_filename, encoding.c_str(), |
- OnStringUtilConversionError::SUBSTITUTE, &filename)) |
- filename = WideToUTF16Hack(base::SysNativeMBToWide(raw_filename)); |
- return filename; |
-} |
- |
-} // namespace |
URLRequestNewFtpJob::URLRequestNewFtpJob(URLRequest* request) |
: URLRequestJob(request), |
- response_info_(NULL), |
- dir_listing_buf_size_(0), |
ALLOW_THIS_IN_INITIALIZER_LIST( |
start_callback_(this, &URLRequestNewFtpJob::OnStartCompleted)), |
ALLOW_THIS_IN_INITIALIZER_LIST( |
@@ -90,6 +43,14 @@ URLRequestJob* URLRequestNewFtpJob::Factory(URLRequest* request, |
return new URLRequestNewFtpJob(request); |
} |
+bool URLRequestNewFtpJob::GetMimeType(std::string* mime_type) const { |
+ if (transaction_->GetResponseInfo()->is_directory_listing) { |
+ *mime_type = "text/vnd.chromium.ftp-dir"; |
+ return true; |
+ } |
+ return false; |
+} |
+ |
void URLRequestNewFtpJob::Start() { |
DCHECK(!transaction_.get()); |
request_info_.url = request_->url(); |
@@ -159,65 +120,13 @@ bool URLRequestNewFtpJob::ReadRawData(net::IOBuffer* buf, |
DCHECK_NE(buf_size, 0); |
DCHECK(bytes_read); |
DCHECK(!read_in_progress_); |
- if (response_info_ == NULL) { |
- response_info_ = transaction_->GetResponseInfo(); |
- if (response_info_->is_directory_listing) { |
- std::string escaped_path = |
- UnescapeURLComponent(request_->url().path(), |
- UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS); |
- 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(escaped_path)) { |
- path_utf16 = UTF8ToUTF16(escaped_path); |
- } else { |
- std::string encoding = DetectEncoding(escaped_path.c_str(), |
- escaped_path.size()); |
- // Try the detected encoding. If it fails, resort to the |
- // OS native encoding. |
- if (encoding.empty() || |
- !CodepageToUTF16(escaped_path, encoding.c_str(), |
- OnStringUtilConversionError::SUBSTITUTE, |
- &path_utf16)) |
- path_utf16 = WideToUTF16Hack(base::SysNativeMBToWide(escaped_path)); |
- } |
- |
- directory_html_ = 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 (request_->url().path().length() > 1) |
- directory_html_.append( |
- net::GetDirectoryListingEntry(ASCIIToUTF16(".."), |
- std::string(), |
- false, 0, |
- base::Time())); |
- } |
- } |
- if (!directory_html_.empty()) { |
- size_t bytes_to_copy = std::min(static_cast<size_t>(buf_size), |
- directory_html_.size()); |
- memcpy(buf->data(), directory_html_.c_str(), bytes_to_copy); |
- *bytes_read = bytes_to_copy; |
- directory_html_.erase(0, bytes_to_copy); |
- return true; |
- } |
int rv = transaction_->Read(buf, buf_size, &read_callback_); |
if (rv >= 0) { |
- if (response_info_->is_directory_listing) { |
- *bytes_read = ProcessFtpDir(buf, buf_size, rv); |
- } else { |
- *bytes_read = rv; |
- } |
+ *bytes_read = rv; |
return true; |
} |
- if (response_info_->is_directory_listing) { |
- dir_listing_buf_ = buf; |
- dir_listing_buf_size_ = buf_size; |
- } |
- |
if (rv == net::ERR_IO_PENDING) { |
read_in_progress_ = true; |
SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); |
@@ -227,130 +136,6 @@ bool URLRequestNewFtpJob::ReadRawData(net::IOBuffer* buf, |
return false; |
} |
-int URLRequestNewFtpJob::ProcessFtpDir(net::IOBuffer *buf, |
- int buf_size, |
- int bytes_read) { |
- std::string file_entry; |
- std::string line; |
- |
- // 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 |
- // component of the url) is unlikely to mistake UTF-8 for a legacy encoding. |
- // If it turns out to be wrong, a separate UTF-8 check has to be added. |
- // |
- // TODO(jungshik): UTF-8 has to be 'enforced' without any heuristics when |
- // we're talking to an FTP server compliant to RFC 2640 (that is, its response |
- // to FEAT command includes 'UTF8'). |
- // See http://wiki.filezilla-project.org/Character_Set |
- if (encoding_.empty()) |
- encoding_ = DetectEncoding(buf->data(), bytes_read); |
- |
- int64 file_size; |
- std::istringstream iss(std::string(buf->data(), bytes_read)); |
- struct net::list_state state; |
- memset(&state, 0, sizeof(state)); |
- while (getline(iss, line)) { |
- struct net::list_result result; |
- std::replace(line.begin(), line.end(), '\r', '\0'); |
- int line_type = net::ParseFTPList(line.c_str(), &state, &result); |
- |
- // The original code assumed months are in range 0-11 (PRExplodedTime), |
- // but our Time class expects a 1-12 range. Adjust it here, because |
- // the third-party parsing code uses bit-shifting on the month, |
- // and it'd be too easy to break that logic. |
- result.fe_time.month++; |
- DCHECK_LE(1, result.fe_time.month); |
- DCHECK_GE(12, result.fe_time.month); |
- |
- switch (line_type) { |
- case 'd': // Directory entry. |
- file_entry.append(net::GetDirectoryListingEntry( |
- RawByteSequenceToFilename(result.fe_fname, encoding_), |
- result.fe_fname, true, 0, |
- base::Time::FromLocalExploded(result.fe_time))); |
- break; |
- case 'f': // File entry. |
- if (StringToInt64(result.fe_size, &file_size)) |
- file_entry.append(net::GetDirectoryListingEntry( |
- RawByteSequenceToFilename(result.fe_fname, encoding_), |
- result.fe_fname, false, file_size, |
- base::Time::FromLocalExploded(result.fe_time))); |
- break; |
- case 'l': { // Symlink entry. |
- std::string filename(result.fe_fname, result.fe_fnlen); |
- |
- // Parsers for styles 'U' and 'W' handle " -> " themselves. |
- if (state.lstyle != 'U' && state.lstyle != 'W') { |
- std::string::size_type offset = filename.find(" -> "); |
- if (offset != std::string::npos) |
- filename = filename.substr(0, offset); |
- } |
- |
- if (StringToInt64(result.fe_size, &file_size)) { |
- file_entry.append(net::GetDirectoryListingEntry( |
- RawByteSequenceToFilename(filename.c_str(), encoding_), |
- filename, false, file_size, |
- base::Time::FromLocalExploded(result.fe_time))); |
- } |
- } |
- break; |
- case '?': // Junk entry. |
- case '"': // Comment entry. |
- break; |
- default: |
- NOTREACHED(); |
- break; |
- } |
- } |
- |
- // We can't recognize server type based on empty directory listings. Only log |
- // server type when we have enough data to recognize one. |
- if (state.parsed_one) |
- LogFtpServerType(state.lstyle); |
- |
- directory_html_.append(file_entry); |
- size_t bytes_to_copy = std::min(static_cast<size_t>(buf_size), |
- directory_html_.length()); |
- if (bytes_to_copy) { |
- memcpy(buf->data(), directory_html_.c_str(), bytes_to_copy); |
- directory_html_.erase(0, bytes_to_copy); |
- } |
- return bytes_to_copy; |
-} |
- |
-void URLRequestNewFtpJob::LogFtpServerType(char server_type) { |
- switch (server_type) { |
- case 'E': |
- net::UpdateFtpServerTypeHistograms(net::SERVER_EPLF); |
- break; |
- case 'V': |
- net::UpdateFtpServerTypeHistograms(net::SERVER_VMS); |
- break; |
- case 'C': |
- net::UpdateFtpServerTypeHistograms(net::SERVER_CMS); |
- break; |
- case 'W': |
- net::UpdateFtpServerTypeHistograms(net::SERVER_DOS); |
- break; |
- case 'O': |
- net::UpdateFtpServerTypeHistograms(net::SERVER_OS2); |
- break; |
- case 'U': |
- net::UpdateFtpServerTypeHistograms(net::SERVER_LSL); |
- break; |
- case 'w': |
- net::UpdateFtpServerTypeHistograms(net::SERVER_W16); |
- break; |
- case 'D': |
- net::UpdateFtpServerTypeHistograms(net::SERVER_DLS); |
- break; |
- default: |
- net::UpdateFtpServerTypeHistograms(net::SERVER_UNKNOWN); |
- break; |
- } |
-} |
- |
void URLRequestNewFtpJob::OnStartCompleted(int result) { |
// If the request was destroyed, then there is no more work to do. |
if (!request_ || !request_->delegate()) |
@@ -396,11 +181,6 @@ void URLRequestNewFtpJob::OnReadCompleted(int result) { |
} else if (result < 0) { |
NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result)); |
} else { |
- // TODO(ibrar): find the best place to delete dir_listing_buf_ |
- // Filter for Directory listing. |
- if (response_info_->is_directory_listing) |
- result = ProcessFtpDir(dir_listing_buf_, dir_listing_buf_size_, result); |
- |
// Clear the IO_PENDING status |
SetStatus(URLRequestStatus()); |
} |
@@ -410,8 +190,6 @@ void URLRequestNewFtpJob::OnReadCompleted(int result) { |
void URLRequestNewFtpJob::RestartTransactionWithAuth() { |
DCHECK(server_auth_ && server_auth_->state == net::AUTH_STATE_HAVE_AUTH); |
- response_info_ = NULL; |
- |
// No matter what, we want to report our status as IO pending since we will |
// be notifying our consumer asynchronously via OnStartCompleted. |
SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); |
@@ -457,5 +235,4 @@ void URLRequestNewFtpJob::DestroyTransaction() { |
DCHECK(transaction_.get()); |
transaction_.reset(); |
- response_info_ = NULL; |
} |