Index: net/ftp/ftp_network_transaction.cc |
diff --git a/net/ftp/ftp_network_transaction.cc b/net/ftp/ftp_network_transaction.cc |
index 5a908853b9ebd2e552ab85c8c3e429881c6af56d..79ad77e5426a52f6444518238b228e6d313359c4 100644 |
--- a/net/ftp/ftp_network_transaction.cc |
+++ b/net/ftp/ftp_network_transaction.cc |
@@ -13,6 +13,7 @@ |
#include "net/base/net_util.h" |
#include "net/ftp/ftp_network_session.h" |
#include "net/ftp/ftp_request_info.h" |
+#include "net/ftp/ftp_util.h" |
#include "net/socket/client_socket.h" |
#include "net/socket/client_socket_factory.h" |
@@ -60,6 +61,7 @@ FtpNetworkTransaction::FtpNetworkTransaction( |
file_data_len_(0), |
write_command_buf_written_(0), |
last_error_(OK), |
+ system_type_(SYSTEM_TYPE_UNKNOWN), |
retr_failed_(false), |
data_connection_port_(0), |
socket_factory_(socket_factory), |
@@ -323,13 +325,28 @@ void FtpNetworkTransaction::OnIOComplete(int result) { |
DoCallback(rv); |
} |
-std::string FtpNetworkTransaction::GetRequestPathForFtpCommand() const { |
- std::string path = (request_->url.has_path() ? request_->url.path() : "/"); |
+std::string FtpNetworkTransaction::GetRequestPathForFtpCommand( |
+ bool is_directory) const { |
+ std::string path(current_remote_directory_); |
+ if (request_->url.has_path()) |
+ path.append(request_->url.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] == '/') |
+ path.erase(path.length() - 1); |
UnescapeRule::Type unescape_rules = UnescapeRule::SPACES | |
UnescapeRule::URL_SPECIAL_CHARS; |
// This may unescape to non-ASCII characters, but we allow that. See the |
// comment for IsValidFTPCommandString. |
path = UnescapeURLComponent(path, unescape_rules); |
+ |
+ if (system_type_ == SYSTEM_TYPE_VMS) { |
+ if (is_directory) |
+ path = FtpUtil::UnixDirectoryPathToVMS(path); |
+ else |
+ path = FtpUtil::UnixFilePathToVMS(path); |
+ } |
+ |
DCHECK(IsValidFTPCommandString(path)); |
return path; |
} |
@@ -634,10 +651,32 @@ int FtpNetworkTransaction::ProcessResponseSYST( |
switch (GetErrorClass(response.status_code)) { |
case ERROR_CLASS_INITIATED: |
return Stop(ERR_INVALID_RESPONSE); |
- case ERROR_CLASS_OK: |
- // TODO(ibrar): Process SYST response properly. |
+ case ERROR_CLASS_OK: { |
+ // All important info should be on the first line. |
+ std::string line = response.lines[0]; |
+ // The response should be ASCII, which allows us to do case-insensitive |
+ // comparisons easily. If it is not ASCII, we leave the system type |
+ // as unknown. |
+ if (IsStringASCII(line)) { |
+ line = StringToLowerASCII(line); |
+ // The "magic" strings we test for below have been gathered by an |
+ // empirical study. |
+ if (line.find("l8") != std::string::npos || |
+ line.find("unix") != std::string::npos || |
+ line.find("bsd") != std::string::npos) { |
+ system_type_ = SYSTEM_TYPE_UNIX; |
+ } else if (line.find("win32") != std::string::npos || |
+ line.find("windows") != std::string::npos) { |
+ system_type_ = SYSTEM_TYPE_WINDOWS; |
+ } else if (line.find("os/2") != std::string::npos) { |
+ system_type_ = SYSTEM_TYPE_OS2; |
+ } else if (line.find("vms") != std::string::npos) { |
+ system_type_ = SYSTEM_TYPE_VMS; |
+ } |
+ } |
next_state_ = STATE_CTRL_WRITE_PWD; |
break; |
+ } |
case ERROR_CLASS_INFO_NEEDED: |
return Stop(ERR_INVALID_RESPONSE); |
case ERROR_CLASS_TRANSIENT_ERROR: |
@@ -664,9 +703,27 @@ int FtpNetworkTransaction::ProcessResponsePWD(const FtpCtrlResponse& response) { |
switch (GetErrorClass(response.status_code)) { |
case ERROR_CLASS_INITIATED: |
return Stop(ERR_INVALID_RESPONSE); |
- case ERROR_CLASS_OK: |
+ case ERROR_CLASS_OK: { |
+ // The info we look for should be on the first line. |
+ std::string line = response.lines[0]; |
+ if (line.empty()) |
+ return Stop(ERR_INVALID_RESPONSE); |
+ std::string::size_type quote_pos = line.find('"'); |
+ if (quote_pos != std::string::npos) { |
+ line = line.substr(quote_pos + 1); |
+ quote_pos = line.find('"'); |
+ if (quote_pos == std::string::npos) |
+ return Stop(ERR_INVALID_RESPONSE); |
+ line = line.substr(0, quote_pos); |
+ } |
+ if (system_type_ == SYSTEM_TYPE_VMS) |
+ line = FtpUtil::VMSPathToUnix(line); |
+ if (line[line.length() - 1] == '/') |
+ line.erase(line.length() - 1); |
+ current_remote_directory_ = line; |
next_state_ = STATE_CTRL_WRITE_TYPE; |
break; |
+ } |
case ERROR_CLASS_INFO_NEEDED: |
return Stop(ERR_INVALID_RESPONSE); |
case ERROR_CLASS_TRANSIENT_ERROR: |
@@ -800,7 +857,7 @@ int FtpNetworkTransaction::ProcessResponsePASV( |
// SIZE command |
int FtpNetworkTransaction::DoCtrlWriteSIZE() { |
- std::string command = "SIZE " + GetRequestPathForFtpCommand(); |
+ std::string command = "SIZE " + GetRequestPathForFtpCommand(false); |
next_state_ = STATE_CTRL_READ; |
return SendFtpCommand(command, COMMAND_SIZE); |
} |
@@ -834,7 +891,7 @@ int FtpNetworkTransaction::ProcessResponseSIZE( |
// RETR command |
int FtpNetworkTransaction::DoCtrlWriteRETR() { |
- std::string command = "RETR " + GetRequestPathForFtpCommand(); |
+ std::string command = "RETR " + GetRequestPathForFtpCommand(false); |
next_state_ = STATE_CTRL_READ; |
return SendFtpCommand(command, COMMAND_RETR); |
} |
@@ -881,7 +938,7 @@ int FtpNetworkTransaction::ProcessResponseRETR( |
// MDMT command |
int FtpNetworkTransaction::DoCtrlWriteMDTM() { |
- std::string command = "MDTM " + GetRequestPathForFtpCommand(); |
+ std::string command = "MDTM " + GetRequestPathForFtpCommand(false); |
next_state_ = STATE_CTRL_READ; |
return SendFtpCommand(command, COMMAND_MDTM); |
} |
@@ -911,7 +968,7 @@ int FtpNetworkTransaction::ProcessResponseMDTM( |
// CWD command |
int FtpNetworkTransaction::DoCtrlWriteCWD() { |
- std::string command = "CWD " + GetRequestPathForFtpCommand(); |
+ std::string command = "CWD " + GetRequestPathForFtpCommand(true); |
next_state_ = STATE_CTRL_READ; |
return SendFtpCommand(command, COMMAND_CWD); |
} |
@@ -945,7 +1002,7 @@ int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) { |
// LIST command |
int FtpNetworkTransaction::DoCtrlWriteLIST() { |
- std::string command = "LIST"; |
+ std::string command(system_type_ == SYSTEM_TYPE_VMS ? "LIST *.*;0" : "LIST"); |
next_state_ = STATE_CTRL_READ; |
return SendFtpCommand(command, COMMAND_LIST); |
} |