| 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;
|
| }
|
|
|