summaryrefslogtreecommitdiffstats
path: root/net/ftp/ftp_network_transaction.cc
diff options
context:
space:
mode:
Diffstat (limited to 'net/ftp/ftp_network_transaction.cc')
-rw-r--r--net/ftp/ftp_network_transaction.cc68
1 files changed, 54 insertions, 14 deletions
diff --git a/net/ftp/ftp_network_transaction.cc b/net/ftp/ftp_network_transaction.cc
index d9d2b88..651340a 100644
--- a/net/ftp/ftp_network_transaction.cc
+++ b/net/ftp/ftp_network_transaction.cc
@@ -62,7 +62,10 @@ FtpNetworkTransaction::FtpNetworkTransaction(
read_data_buf_len_(0),
last_error_(OK),
system_type_(SYSTEM_TYPE_UNKNOWN),
- retr_failed_(false),
+ // Use image (binary) transfer by default. It should always work,
+ // whereas the ascii transfer may damage binary data.
+ data_type_(DATA_TYPE_IMAGE),
+ resource_type_(RESOURCE_TYPE_UNKNOWN),
data_connection_port_(0),
socket_factory_(socket_factory),
next_state_(STATE_NONE) {
@@ -84,6 +87,8 @@ int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info,
password_ = L"chrome@example.com";
}
+ DetectTypecode();
+
next_state_ = STATE_CTRL_INIT;
int rv = DoLoop(OK);
if (rv == ERR_IO_PENDING)
@@ -311,7 +316,6 @@ void FtpNetworkTransaction::ResetStateForRestart() {
if (write_buf_)
write_buf_->SetOffset(0);
last_error_ = OK;
- retr_failed_ = false;
data_connection_port_ = 0;
ctrl_socket_.reset();
data_socket_.reset();
@@ -337,8 +341,16 @@ void FtpNetworkTransaction::OnIOComplete(int result) {
std::string FtpNetworkTransaction::GetRequestPathForFtpCommand(
bool is_directory) const {
std::string path(current_remote_directory_);
- if (request_->url.has_path())
- path.append(request_->url.path());
+ if (request_->url.has_path()) {
+ std::string gurl_path(request_->url.path());
+
+ // Get rid of the typecode, see RFC 1738 section 3.2.2. FTP url-path.
+ std::string::size_type pos = gurl_path.rfind(';');
+ if (pos != std::string::npos)
+ gurl_path.resize(pos);
+
+ path.append(gurl_path);
+ }
// Make sure that if the path is expected to be a file, it won't end
// with a trailing slash.
if (!is_directory && path.length() > 1 && path[path.length() - 1] == '/')
@@ -360,6 +372,27 @@ std::string FtpNetworkTransaction::GetRequestPathForFtpCommand(
return path;
}
+void FtpNetworkTransaction::DetectTypecode() {
+ if (!request_->url.has_path())
+ return;
+ std::string gurl_path(request_->url.path());
+
+ // Extract the typecode, see RFC 1738 section 3.2.2. FTP url-path.
+ std::string::size_type pos = gurl_path.rfind(';');
+ if (pos == std::string::npos)
+ return;
+ std::string typecode_string(gurl_path.substr(pos));
+ if (typecode_string == ";type=a") {
+ data_type_ = DATA_TYPE_ASCII;
+ resource_type_ = RESOURCE_TYPE_FILE;
+ } else if (typecode_string == ";type=i") {
+ data_type_ = DATA_TYPE_IMAGE;
+ resource_type_ = RESOURCE_TYPE_FILE;
+ } else if (typecode_string == ";type=d") {
+ resource_type_ = RESOURCE_TYPE_DIRECTORY;
+ }
+}
+
int FtpNetworkTransaction::DoLoop(int result) {
DCHECK(next_state_ != STATE_NONE);
@@ -760,7 +793,15 @@ int FtpNetworkTransaction::ProcessResponsePWD(const FtpCtrlResponse& response) {
// TYPE command.
int FtpNetworkTransaction::DoCtrlWriteTYPE() {
- std::string command = "TYPE I";
+ std::string command = "TYPE ";
+ if (data_type_ == DATA_TYPE_ASCII) {
+ command += "A";
+ } else if (data_type_ == DATA_TYPE_IMAGE) {
+ command += "I";
+ } else {
+ NOTREACHED();
+ return Stop(ERR_UNEXPECTED);
+ }
next_state_ = STATE_CTRL_READ;
return SendFtpCommand(command, COMMAND_TYPE);
}
@@ -945,10 +986,9 @@ int FtpNetworkTransaction::ProcessResponseRETR(
if (response.status_code != 550)
return Stop(ERR_FAILED);
- DCHECK(!retr_failed_); // Should not get here twice.
- retr_failed_ = true;
-
// It's possible that RETR failed because the path is a directory.
+ resource_type_ = RESOURCE_TYPE_DIRECTORY;
+
// We're going to try CWD next, but first send a PASV one more time,
// because some FTP servers, including FileZilla, require that.
// See http://crbug.com/25316.
@@ -1010,11 +1050,11 @@ int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) {
case ERROR_CLASS_TRANSIENT_ERROR:
return Stop(ERR_FAILED);
case ERROR_CLASS_PERMANENT_ERROR:
- if (retr_failed_ && response.status_code == 550) {
- // Both RETR and CWD failed with codes 550. That means that the path
- // we're trying to access is not a file, and not a directory. The most
- // probable interpretation is that it doesn't exist (with FTP we can't
- // be sure).
+ if (resource_type_ == RESOURCE_TYPE_DIRECTORY &&
+ response.status_code == 550) {
+ // We're assuming that the resource is a directory, but the server says
+ // it's not true. The most probable interpretation is that it doesn't
+ // exist (with FTP we can't be sure).
return Stop(ERR_FILE_NOT_FOUND);
}
return Stop(ERR_FAILED);
@@ -1124,7 +1164,7 @@ int FtpNetworkTransaction::DoDataConnect() {
int FtpNetworkTransaction::DoDataConnectComplete(int result) {
RecordDataConnectionError(result);
- if (retr_failed_) {
+ if (resource_type_ == RESOURCE_TYPE_DIRECTORY) {
next_state_ = STATE_CTRL_WRITE_CWD;
} else {
next_state_ = STATE_CTRL_WRITE_SIZE;