summaryrefslogtreecommitdiffstats
path: root/net/ftp
diff options
context:
space:
mode:
authorwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-11 17:01:17 +0000
committerwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-11 17:01:17 +0000
commit581e0d06dc3599bec309d34203b6b5693446fe7f (patch)
treec8c11535827d0b5302d07b257c12d998f8a9edb3 /net/ftp
parenta63bd1137e938034873b318355731c656caf05fe (diff)
downloadchromium_src-581e0d06dc3599bec309d34203b6b5693446fe7f.zip
chromium_src-581e0d06dc3599bec309d34203b6b5693446fe7f.tar.gz
chromium_src-581e0d06dc3599bec309d34203b6b5693446fe7f.tar.bz2
FTP Transaction code for new Portable FTP code.
The patch is contributed by Ibrar Ahmed <ibrar.ahmad@gmail.com>. Original review: http://codereview.chromium.org/39130 R=wtc http://crbug.com/4965 TEST=None. Work in progress. Review URL: http://codereview.chromium.org/115137 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15760 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/ftp')
-rw-r--r--net/ftp/ftp_network_layer.cc9
-rw-r--r--net/ftp/ftp_network_layer.h4
-rw-r--r--net/ftp/ftp_network_transaction.cc653
-rw-r--r--net/ftp/ftp_network_transaction.h129
-rw-r--r--net/ftp/ftp_request_info.h12
-rw-r--r--net/ftp/ftp_response_info.h15
-rw-r--r--net/ftp/ftp_transaction.h9
-rw-r--r--net/ftp/ftp_transaction_factory.h4
8 files changed, 754 insertions, 81 deletions
diff --git a/net/ftp/ftp_network_layer.cc b/net/ftp/ftp_network_layer.cc
index 06884ce..e05b67f 100644
--- a/net/ftp/ftp_network_layer.cc
+++ b/net/ftp/ftp_network_layer.cc
@@ -18,6 +18,11 @@ FtpNetworkLayer::FtpNetworkLayer()
FtpNetworkLayer::~FtpNetworkLayer() {
}
+// static
+FtpTransactionFactory* FtpNetworkLayer::CreateFactory() {
+ return new FtpNetworkLayer();
+}
+
FtpTransaction* FtpNetworkLayer::CreateTransaction() {
if (suspended_)
return NULL;
@@ -26,10 +31,6 @@ FtpTransaction* FtpNetworkLayer::CreateTransaction() {
session_, ClientSocketFactory::GetDefaultFactory());
}
-FtpAuthCache* FtpNetworkLayer::GetAuthCache() {
- return session_->auth_cache();
-}
-
void FtpNetworkLayer::Suspend(bool suspend) {
suspended_ = suspend;
diff --git a/net/ftp/ftp_network_layer.h b/net/ftp/ftp_network_layer.h
index fa5c430..71bd3b9 100644
--- a/net/ftp/ftp_network_layer.h
+++ b/net/ftp/ftp_network_layer.h
@@ -11,15 +11,17 @@
namespace net {
class FtpNetworkSession;
+class FtpAuthCache;
class FtpNetworkLayer : public FtpTransactionFactory {
public:
FtpNetworkLayer();
~FtpNetworkLayer();
+ static FtpTransactionFactory* CreateFactory();
+
// FtpTransactionFactory methods:
virtual FtpTransaction* CreateTransaction();
- virtual FtpAuthCache* GetAuthCache();
virtual void Suspend(bool suspend);
private:
diff --git a/net/ftp/ftp_network_transaction.cc b/net/ftp/ftp_network_transaction.cc
index 3ace779..d8e5a82 100644
--- a/net/ftp/ftp_network_transaction.cc
+++ b/net/ftp/ftp_network_transaction.cc
@@ -5,32 +5,52 @@
#include "net/ftp/ftp_network_transaction.h"
#include "base/compiler_specific.h"
-#include "base/logging.h"
+#include "base/string_util.h"
#include "net/base/client_socket.h"
+#include "net/base/client_socket_factory.h"
+#include "net/base/connection_type_histograms.h"
+#include "net/base/dns_resolution_observer.h"
#include "net/base/net_errors.h"
#include "net/ftp/ftp_network_session.h"
+#include "net/ftp/ftp_request_info.h"
+
+// TODO(ibrar): Try to avoid sscanf.
+#if !defined(COMPILER_MSVC)
+#define sscanf_s sscanf
+#endif
+
+const char kCRLF[] = "\r\n";
+
+const int kCtrlBufLen = 1024;
namespace net {
FtpNetworkTransaction::FtpNetworkTransaction(
- FtpNetworkSession* session, ClientSocketFactory* socket_factory)
- : ALLOW_THIS_IN_INITIALIZER_LIST(io_callback_(this,
- &FtpNetworkTransaction::OnIOComplete)),
+ FtpNetworkSession* session,
+ ClientSocketFactory* socket_factory)
+ : command_sent_(COMMAND_NONE),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ io_callback_(this, &FtpNetworkTransaction::OnIOComplete)),
user_callback_(NULL),
session_(session),
+ request_(NULL),
+ read_ctrl_buf_size_(kCtrlBufLen),
+ response_message_buf_len_(0),
+ read_data_buf_len_(0),
+ file_data_len_(0),
+ last_error_(OK),
+ data_connection_port_(0),
socket_factory_(socket_factory),
next_state_(STATE_NONE) {
+ read_ctrl_buf_ = new IOBuffer(kCtrlBufLen);
+ response_message_buf_ = new IOBuffer(kCtrlBufLen);
}
FtpNetworkTransaction::~FtpNetworkTransaction() {
}
-void FtpNetworkTransaction::Destroy() {
- delete this;
-}
-
-int FtpNetworkTransaction::Start(
- const FtpRequestInfo* request_info, CompletionCallback* callback) {
+int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info,
+ CompletionCallback* callback) {
request_ = request_info;
next_state_ = STATE_CTRL_INIT;
@@ -40,19 +60,50 @@ int FtpNetworkTransaction::Start(
return rv;
}
-int FtpNetworkTransaction::RestartWithAuth(
- const std::wstring& username, const std::wstring& password,
- CompletionCallback* callback) {
+int FtpNetworkTransaction::Stop(int error) {
+ next_state_ = STATE_CTRL_WRITE_QUIT;
+ last_error_ = error;
+ return OK;
+}
+
+int FtpNetworkTransaction::RestartWithAuth(const std::wstring& username,
+ const std::wstring& password,
+ CompletionCallback* callback) {
return ERR_FAILED;
}
-int FtpNetworkTransaction::Read(
- char* buf, int buf_len, CompletionCallback* callback) {
+int FtpNetworkTransaction::RestartIgnoringLastError(
+ CompletionCallback* callback) {
return ERR_FAILED;
}
+int FtpNetworkTransaction::Read(IOBuffer* buf,
+ int buf_len,
+ CompletionCallback* callback) {
+ DCHECK(buf);
+ DCHECK(buf_len > 0);
+
+ if (data_socket_ == NULL)
+ return 0; // Data socket closed, no more data left.
+
+ if (!data_socket_->IsConnected())
+ return 0; // Data socket disconnected, no more data left.
+
+ read_data_buf_ = buf;
+ read_data_buf_len_ = buf_len;
+
+ next_state_ = STATE_DATA_READ;
+
+ int rv = DoLoop(OK);
+ if (rv == ERR_IO_PENDING)
+ user_callback_ = callback;
+ else if (rv == 0)
+ data_socket_->Disconnect();
+ return rv;
+}
+
const FtpResponseInfo* FtpNetworkTransaction::GetResponseInfo() const {
- return NULL;
+ return &response_;
}
LoadState FtpNetworkTransaction::GetLoadState() const {
@@ -63,6 +114,77 @@ uint64 FtpNetworkTransaction::GetUploadProgress() const {
return 0;
}
+// Used to prepare and send FTP commad.
+int FtpNetworkTransaction::SendFtpCommand(const std::string& command,
+ Command cmd) {
+ response_message_buf_len_ = 0;
+ command_sent_ = cmd;
+ DLOG(INFO) << " >> " << command;
+ const char* buf = command.c_str();
+ int buf_len = command.size();
+ DCHECK(!write_buf_);
+ write_buf_ = new IOBuffer(buf_len + 2);
+ memcpy(write_buf_->data(), buf, buf_len);
+ memcpy(write_buf_->data() + buf_len, kCRLF, 2);
+
+ // TODO(ibrar): Handle the completion of Write and release write_buf_.
+ return ctrl_socket_->Write(write_buf_, buf_len, &io_callback_);
+}
+
+int FtpNetworkTransaction::GetRespnseCode() {
+ std::string str(response_message_buf_->data(), 3);
+ return StringToInt(str);
+}
+
+int FtpNetworkTransaction::ProcessResponse(int response_code) {
+ int rv = OK;
+ switch (command_sent_) {
+ case COMMAND_NONE:
+ next_state_ = STATE_CTRL_WRITE_USER;
+ break;
+ case COMMAND_USER:
+ rv = ProcessResponseUSER(response_code);
+ break;
+ case COMMAND_PASS:
+ rv = ProcessResponsePASS(response_code);
+ break;
+ case COMMAND_ACCT:
+ rv = ProcessResponseACCT(response_code);
+ break;
+ case COMMAND_SYST:
+ rv = ProcessResponseSYST(response_code);
+ break;
+ case COMMAND_PWD:
+ rv = ProcessResponsePWD(response_code);
+ break;
+ case COMMAND_TYPE:
+ rv = ProcessResponseTYPE(response_code);
+ break;
+ case COMMAND_PASV:
+ rv = ProcessResponsePASV(response_code);
+ break;
+ case COMMAND_SIZE:
+ rv = ProcessResponseSIZE(response_code);
+ break;
+ case COMMAND_RETR:
+ rv = ProcessResponseRETR(response_code);
+ break;
+ case COMMAND_CWD:
+ rv = ProcessResponseCWD(response_code);
+ break;
+ case COMMAND_LIST:
+ rv = ProcessResponseLIST(response_code);
+ break;
+ case COMMAND_QUIT:
+ rv = ProcessResponseQUIT(response_code);
+ break;
+ default:
+ DLOG(INFO) << "Missing Command response handling!";
+ return ERR_FAILED;
+ }
+ return rv;
+}
+
void FtpNetworkTransaction::DoCallback(int rv) {
DCHECK(rv != ERR_IO_PENDING);
DCHECK(user_callback_);
@@ -108,20 +230,58 @@ int FtpNetworkTransaction::DoLoop(int result) {
case STATE_CTRL_CONNECT_COMPLETE:
rv = DoCtrlConnectComplete(rv);
break;
- case STATE_CTRL_WRITE:
- DCHECK(rv == OK);
- rv = DoCtrlWrite();
- break;
- case STATE_CTRL_WRITE_COMPLETE:
- rv = DoCtrlWriteComplete(rv);
- break;
case STATE_CTRL_READ:
- DCHECK(rv == OK);
rv = DoCtrlRead();
break;
case STATE_CTRL_READ_COMPLETE:
rv = DoCtrlReadComplete(rv);
break;
+ case STATE_CTRL_WRITE_USER:
+ DCHECK(rv == OK);
+ rv = DoCtrlWriteUSER();
+ break;
+ case STATE_CTRL_WRITE_PASS:
+ DCHECK(rv == OK);
+ rv = DoCtrlWritePASS();
+ break;
+ case STATE_CTRL_WRITE_SYST:
+ DCHECK(rv == OK);
+ rv = DoCtrlWriteSYST();
+ break;
+ case STATE_CTRL_WRITE_ACCT:
+ DCHECK(rv == OK);
+ rv = DoCtrlWriteACCT();
+ break;
+ case STATE_CTRL_WRITE_PWD:
+ DCHECK(rv == OK);
+ rv = DoCtrlWritePWD();
+ break;
+ case STATE_CTRL_WRITE_TYPE:
+ DCHECK(rv == OK);
+ rv = DoCtrlWriteTYPE();
+ break;
+ case STATE_CTRL_WRITE_PASV:
+ DCHECK(rv == OK);
+ rv = DoCtrlWritePASV();
+ break;
+ case STATE_CTRL_WRITE_RETR:
+ DCHECK(rv == OK);
+ rv = DoCtrlWriteRETR();
+ break;
+ case STATE_CTRL_WRITE_SIZE:
+ DCHECK(rv == OK);
+ rv = DoCtrlWriteSIZE();
+ break;
+ case STATE_CTRL_WRITE_CWD:
+ rv = DoCtrlWriteCWD();
+ break;
+ case STATE_CTRL_WRITE_LIST:
+ rv = DoCtrlWriteLIST();
+ break;
+ case STATE_CTRL_WRITE_QUIT:
+ rv = DoCtrlWriteQUIT();
+ break;
+
case STATE_DATA_CONNECT:
DCHECK(rv == OK);
rv = DoDataConnect();
@@ -130,7 +290,6 @@ int FtpNetworkTransaction::DoLoop(int result) {
rv = DoDataConnectComplete(rv);
break;
case STATE_DATA_READ:
- DCHECK(rv == OK);
rv = DoDataRead();
break;
case STATE_DATA_READ_COMPLETE:
@@ -142,64 +301,470 @@ int FtpNetworkTransaction::DoLoop(int result) {
break;
}
} while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
-
return rv;
}
+// TODO(ibrar): Yet to see if we need any intialization
int FtpNetworkTransaction::DoCtrlInit() {
- return ERR_FAILED; // TODO(darin): implement me
+ next_state_ = STATE_CTRL_INIT_COMPLETE;
+ return OK;
}
int FtpNetworkTransaction::DoCtrlInitComplete(int result) {
- return ERR_FAILED; // TODO(darin): implement me
+ next_state_ = STATE_CTRL_RESOLVE_HOST;
+ return OK;
}
int FtpNetworkTransaction::DoCtrlResolveHost() {
- return ERR_FAILED; // TODO(darin): implement me
+ next_state_ = STATE_CTRL_RESOLVE_HOST_COMPLETE;
+
+ std::string host;
+ int port;
+
+ host = request_->url.host();
+ port = request_->url.EffectiveIntPort();
+
+ DidStartDnsResolution(host, this);
+ return resolver_.Resolve(host, port, &addresses_, &io_callback_);
}
int FtpNetworkTransaction::DoCtrlResolveHostComplete(int result) {
- return ERR_FAILED; // TODO(darin): implement me
+ bool ok = (result == OK);
+ DidFinishDnsResolutionWithStatus(ok, GURL(), this);
+ if (ok) {
+ next_state_ = STATE_CTRL_CONNECT;
+ return result;
+ }
+ return ERR_FAILED;
}
int FtpNetworkTransaction::DoCtrlConnect() {
- return ERR_FAILED; // TODO(darin): implement me
+ next_state_ = STATE_CTRL_CONNECT_COMPLETE;
+ ctrl_socket_.reset(socket_factory_->CreateTCPClientSocket(addresses_));
+ return ctrl_socket_->Connect(&io_callback_);
}
int FtpNetworkTransaction::DoCtrlConnectComplete(int result) {
- return ERR_FAILED; // TODO(darin): implement me
+ next_state_ = STATE_CTRL_READ;
+ return result;
+}
+
+int FtpNetworkTransaction::DoCtrlRead() {
+ next_state_ = STATE_CTRL_READ_COMPLETE;
+ read_ctrl_buf_->data()[0] = 0;
+ return ctrl_socket_->Read(read_ctrl_buf_, read_ctrl_buf_size_ - 1,
+ &io_callback_);
}
-int FtpNetworkTransaction::DoCtrlWrite() {
- return ERR_FAILED; // TODO(darin): implement me
+int FtpNetworkTransaction::DoCtrlReadComplete(int result) {
+ if (result < 0)
+ return Stop(ERR_FAILED);
+ int response_code;
+ // Null termination added, now we can treat this as string.
+ read_ctrl_buf_->data()[result] = 0;
+ memcpy(response_message_buf_->data() + response_message_buf_len_,
+ read_ctrl_buf_->data(), result);
+
+ response_message_buf_len_ = response_message_buf_len_ + result;
+ for (int i = 0; i < response_message_buf_len_; i++) {
+ if (response_message_buf_->data()[i] == '\r' &&
+ response_message_buf_->data()[i + 1] == '\n') {
+ if (response_message_buf_len_ > 3 &&
+ response_message_buf_->data()[3] == ' ') {
+ response_message_buf_->data()[response_message_buf_len_ - 2] = 0;
+ response_code = GetRespnseCode();
+ return ProcessResponse(response_code);
+ }
+ response_message_buf_len_ -= (i + 2);
+ memcpy(response_message_buf_->data(),
+ response_message_buf_->data() + i + 2,
+ response_message_buf_len_);
+ i = 0;
+ }
+ }
+ next_state_ = STATE_CTRL_READ;
+ return OK;
}
-int FtpNetworkTransaction::DoCtrlWriteComplete(int result) {
- return ERR_FAILED; // TODO(darin): implement me
+// FTP Commands and responses
+
+// USER Command.
+int FtpNetworkTransaction::DoCtrlWriteUSER() {
+ std::string command = "USER ";
+ if (request_->url.has_username()) {
+ command.append(request_->url.username());
+ } else {
+ command.append("anonymous");
+ }
+ next_state_ = STATE_CTRL_READ;
+ return SendFtpCommand(command, COMMAND_USER);
}
-int FtpNetworkTransaction::DoCtrlRead() {
- return ERR_FAILED; // TODO(darin): implement me
+int FtpNetworkTransaction::ProcessResponseUSER(int response_code) {
+ switch (GetErrorClass(response_code)) {
+ case ERROR_CLASS_INITIATED:
+ case ERROR_CLASS_OK:
+ next_state_ = STATE_CTRL_WRITE_USER;
+ break;
+ case ERROR_CLASS_PENDING:
+ next_state_ = STATE_CTRL_WRITE_PASS;
+ break;
+ case ERROR_CLASS_ERROR_RETRY:
+ if (response_code == 421)
+ return Stop(ERR_FAILED);
+ break;
+ case ERROR_CLASS_ERROR:
+ return Stop(ERR_FAILED);
+ default:
+ return Stop(ERR_FAILED);
+ }
+ return OK;
}
-int FtpNetworkTransaction::DoCtrlReadComplete(int result) {
- return ERR_FAILED; // TODO(darin): implement me
+// PASS command.
+int FtpNetworkTransaction::DoCtrlWritePASS() {
+ std::string command = "PASS ";
+ if (request_->url.has_password()) {
+ command.append(request_->url.password());
+ } else {
+ command.append("IEUser@");
+ }
+ next_state_ = STATE_CTRL_READ;
+ return SendFtpCommand(command, COMMAND_PASS);
+}
+
+int FtpNetworkTransaction::ProcessResponsePASS(int response_code) {
+ switch (GetErrorClass(response_code)) {
+ case ERROR_CLASS_INITIATED:
+ case ERROR_CLASS_OK:
+ next_state_ = STATE_CTRL_WRITE_SYST;
+ break;
+ case ERROR_CLASS_PENDING:
+ next_state_ = STATE_CTRL_WRITE_ACCT;
+ break;
+ case ERROR_CLASS_ERROR_RETRY:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_ERROR:
+ if (response_code == 503) {
+ next_state_ = STATE_CTRL_WRITE_PASS;
+ } else {
+ return Stop(ERR_FAILED);
+ }
+ break;
+ default:
+ return Stop(ERR_FAILED);
+ }
+ return OK;
+}
+
+// ACCT command.
+int FtpNetworkTransaction::DoCtrlWriteACCT() {
+ std::string command = "ACCT noaccount";
+ next_state_ = STATE_CTRL_READ;
+ return SendFtpCommand(command, COMMAND_ACCT);
+}
+
+int FtpNetworkTransaction::ProcessResponseACCT(int response_code) {
+ switch (GetErrorClass(response_code)) {
+ case ERROR_CLASS_INITIATED:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_OK:
+ next_state_ = STATE_CTRL_WRITE_SYST;
+ break;
+ case ERROR_CLASS_PENDING:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_ERROR_RETRY:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_ERROR:
+ return Stop(ERR_FAILED);
+ default:
+ return Stop(ERR_FAILED);
+ }
+ return OK;
+}
+
+// SYST command.
+int FtpNetworkTransaction::DoCtrlWriteSYST() {
+ std::string command = "SYST";
+ next_state_ = STATE_CTRL_READ;
+ return SendFtpCommand(command, COMMAND_SYST);
+}
+
+int FtpNetworkTransaction::ProcessResponseSYST(int response_code) {
+ next_state_ = STATE_CTRL_WRITE_PWD;
+ return OK;
+}
+
+// PWD command.
+int FtpNetworkTransaction::DoCtrlWritePWD() {
+ std::string command = "PWD";
+ next_state_ = STATE_CTRL_READ;
+ return SendFtpCommand(command, COMMAND_PWD);
+}
+
+int FtpNetworkTransaction::ProcessResponsePWD(int response_code) {
+ switch (GetErrorClass(response_code)) {
+ case ERROR_CLASS_INITIATED:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_OK:
+ next_state_ = STATE_CTRL_WRITE_TYPE;
+ break;
+ case ERROR_CLASS_PENDING:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_ERROR_RETRY:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_ERROR:
+ return Stop(ERR_FAILED);
+ default:
+ return Stop(ERR_FAILED);
+ }
+ return OK;
+}
+
+// TYPE command.
+int FtpNetworkTransaction::DoCtrlWriteTYPE() {
+ std::string command = "TYPE I";
+ next_state_ = STATE_CTRL_READ;
+ return SendFtpCommand(command, COMMAND_TYPE);
}
+int FtpNetworkTransaction::ProcessResponseTYPE(int response_code) {
+ switch (GetErrorClass(response_code)) {
+ case ERROR_CLASS_INITIATED:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_OK:
+ next_state_ = STATE_CTRL_WRITE_PASV;
+ break;
+ case ERROR_CLASS_PENDING:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_ERROR_RETRY:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_ERROR:
+ return Stop(ERR_FAILED);
+ default:
+ return Stop(ERR_FAILED);
+ }
+ return OK;
+}
+
+// PASV command
+int FtpNetworkTransaction::DoCtrlWritePASV() {
+ std::string command = "PASV ";
+ next_state_ = STATE_CTRL_READ;
+ return SendFtpCommand(command, COMMAND_PASV);
+}
+
+// There are two way we can receive IP address and port.
+// (127,0,0,1,23,21) IP address and port encapsulate in ().
+// 127,0,0,1,23,21 IP address and port without ().
+int FtpNetworkTransaction::ProcessResponsePASV(int response_code) {
+ switch (GetErrorClass(response_code)) {
+ case ERROR_CLASS_INITIATED:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_OK:
+ char* ptr;
+ int i0, i1, i2, i3, p0, p1;
+ ptr = read_ctrl_buf_->data(); // Try with bracket.
+ while (*ptr && *ptr != '(')
+ ++ptr;
+ if (*ptr) {
+ ++ptr;
+ } else {
+ ptr = read_ctrl_buf_->data(); // Try without bracket.
+ while (*ptr && *ptr != ',')
+ ++ptr;
+ while (*ptr && *ptr != ' ')
+ --ptr;
+ }
+ if (sscanf_s(ptr, "%d,%d,%d,%d,%d,%d",
+ &i0, &i1, &i2, &i3, &p0, &p1) == 6) {
+ data_connection_ip_ = StringPrintf("%d.%d.%d.%d", i0, i1, i2, i3);
+ data_connection_port_ = (p0 << 8) + p1;
+ next_state_ = STATE_DATA_CONNECT;
+ } else {
+ return Stop(ERR_FAILED);
+ }
+ break;
+ case ERROR_CLASS_PENDING:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_ERROR_RETRY:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_ERROR:
+ return Stop(ERR_FAILED);
+ default:
+ return Stop(ERR_FAILED);
+ }
+ return OK;
+}
+
+// SIZE command
+int FtpNetworkTransaction::DoCtrlWriteSIZE() {
+ std::string command = "SIZE ";
+ if (request_->url.has_path())
+ command.append(request_->url.path());
+ next_state_ = STATE_CTRL_READ;
+ return SendFtpCommand(command, COMMAND_SIZE);
+}
+
+int FtpNetworkTransaction::ProcessResponseSIZE(int response_code) {
+ switch (GetErrorClass(response_code)) {
+ case ERROR_CLASS_INITIATED:
+ next_state_ = STATE_CTRL_WRITE_LIST;
+ break;
+ case ERROR_CLASS_OK:
+ next_state_ = STATE_CTRL_WRITE_RETR;
+ if (!StringToInt(read_ctrl_buf_->data() + 4, &file_data_len_))
+ return Stop(ERR_FAILED);
+ break;
+ case ERROR_CLASS_PENDING:
+ next_state_ = STATE_CTRL_WRITE_LIST;
+ break;
+ case ERROR_CLASS_ERROR_RETRY:
+ next_state_ = STATE_CTRL_WRITE_LIST;
+ break;
+ case ERROR_CLASS_ERROR:
+ next_state_ = STATE_CTRL_WRITE_LIST;
+ break;
+ default:
+ return Stop(ERR_FAILED);
+ }
+ return OK;
+}
+
+// RETR command
+int FtpNetworkTransaction::DoCtrlWriteRETR() {
+ std::string command = "RETR ";
+ if (request_->url.has_path())
+ command.append(request_->url.path());
+ next_state_ = STATE_CTRL_READ;
+ return SendFtpCommand(command, COMMAND_RETR);
+}
+
+int FtpNetworkTransaction::ProcessResponseRETR(int response_code) {
+ switch (GetErrorClass(response_code)) {
+ case ERROR_CLASS_INITIATED:
+ next_state_ = STATE_CTRL_WRITE_QUIT;
+ ctrl_socket_->Disconnect();
+ break;
+ case ERROR_CLASS_OK:
+ break; // FTP Done
+ case ERROR_CLASS_PENDING:
+ next_state_ = STATE_CTRL_WRITE_PASV;
+ break;
+ case ERROR_CLASS_ERROR_RETRY:
+ if (response_code == 421 || response_code == 425 || response_code == 426)
+ return Stop(ERR_FAILED);
+ return ERR_FAILED; // TODO(ibrar): Retry here.
+ case ERROR_CLASS_ERROR:
+ next_state_ = STATE_CTRL_WRITE_CWD;
+ break;
+ default:
+ return Stop(ERR_FAILED);
+ }
+ return OK;
+}
+
+// CWD command
+int FtpNetworkTransaction::DoCtrlWriteCWD() {
+ std::string command = "CWD";
+ next_state_ = STATE_CTRL_READ;
+ return SendFtpCommand(command, COMMAND_CWD);
+}
+
+int FtpNetworkTransaction::ProcessResponseCWD(int response_code) {
+ switch (GetErrorClass(response_code)) {
+ case ERROR_CLASS_INITIATED:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_OK:
+ next_state_ = STATE_CTRL_WRITE_LIST;
+ case ERROR_CLASS_PENDING:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_ERROR_RETRY:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_ERROR:
+ return Stop(ERR_FAILED);
+ default:
+ return Stop(ERR_FAILED);
+ }
+ return OK;
+}
+
+// LIST command
+int FtpNetworkTransaction::DoCtrlWriteLIST() {
+ std::string command = "LIST ";
+ if (request_->url.has_path())
+ command.append(request_->url.path());
+ next_state_ = STATE_CTRL_READ;
+ return SendFtpCommand(command, COMMAND_LIST);
+}
+
+int FtpNetworkTransaction::ProcessResponseLIST(int response_code) {
+ switch (GetErrorClass(response_code)) {
+ case ERROR_CLASS_INITIATED:
+ next_state_ = STATE_CTRL_WRITE_QUIT;
+ response_.is_directory_listing = true;
+ break;
+ case ERROR_CLASS_OK:
+ next_state_ = STATE_CTRL_WRITE_QUIT;
+ response_.is_directory_listing = true;
+ break;
+ case ERROR_CLASS_PENDING:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_ERROR_RETRY:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_ERROR:
+ return Stop(ERR_FAILED);
+ default:
+ return Stop(ERR_FAILED);
+ }
+ return OK;
+}
+
+// Quit command
+int FtpNetworkTransaction::DoCtrlWriteQUIT() {
+ std::string command = "QUIT";
+ next_state_ = STATE_CTRL_READ;
+ return SendFtpCommand(command, COMMAND_QUIT);
+}
+
+int FtpNetworkTransaction::ProcessResponseQUIT(int response_code) {
+ ctrl_socket_->Disconnect();
+ return last_error_;
+}
+
+// Data Connection
int FtpNetworkTransaction::DoDataConnect() {
- return ERR_FAILED; // TODO(darin): implement me
+ next_state_ = STATE_DATA_CONNECT_COMPLETE;
+ AddressList adr;
+ // TODO(ibrar): Call resolver_.Resolve in asynchronous mode, with a non-null
+ // callback.
+ int err = resolver_.Resolve(data_connection_ip_,
+ data_connection_port_, &adr, NULL);
+ if (err != OK)
+ return err;
+ data_socket_.reset(socket_factory_->CreateTCPClientSocket(adr));
+ return data_socket_->Connect(&io_callback_);
}
int FtpNetworkTransaction::DoDataConnectComplete(int result) {
- return ERR_FAILED; // TODO(darin): implement me
+ next_state_ = STATE_CTRL_WRITE_SIZE;
+ return result;
}
int FtpNetworkTransaction::DoDataRead() {
- return ERR_FAILED; // TODO(darin): implement me
+ DCHECK(read_data_buf_);
+ DCHECK(read_data_buf_len_ > 0);
+
+ next_state_ = STATE_DATA_READ_COMPLETE;
+ read_data_buf_->data()[0] = 0;
+ return data_socket_->Read(read_data_buf_, read_data_buf_len_,
+ &io_callback_);
}
int FtpNetworkTransaction::DoDataReadComplete(int result) {
- return ERR_FAILED; // TODO(darin): implement me
+ DLOG(INFO) << read_data_buf_->data(); // The read_data_buf_ is NULL
+ // terminated string.
+ return result;
}
} // namespace net
diff --git a/net/ftp/ftp_network_transaction.h b/net/ftp/ftp_network_transaction.h
index c7f59cd..67ddaeb 100644
--- a/net/ftp/ftp_network_transaction.h
+++ b/net/ftp/ftp_network_transaction.h
@@ -5,8 +5,12 @@
#ifndef NET_FTP_FTP_NETWORK_TRANSACTION_H_
#define NET_FTP_FTP_NETWORK_TRANSACTION_H_
+#include <string>
+
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
+#include "net/base/address_list.h"
+#include "net/base/host_resolver.h"
#include "net/ftp/ftp_response_info.h"
#include "net/ftp/ftp_transaction.h"
@@ -18,25 +22,65 @@ class FtpNetworkSession;
class FtpNetworkTransaction : public FtpTransaction {
public:
- FtpNetworkTransaction(
- FtpNetworkSession* session, ClientSocketFactory* socket_factory);
- ~FtpNetworkTransaction();
+ FtpNetworkTransaction(FtpNetworkSession* session,
+ ClientSocketFactory* socket_factory);
+ virtual ~FtpNetworkTransaction();
// FtpTransaction methods:
- virtual void Destroy();
- virtual int Start(
- const FtpRequestInfo* request_info, CompletionCallback* callback);
- virtual int RestartWithAuth(
- const std::wstring& username, const std::wstring& password,
- CompletionCallback* callback);
- virtual int Read(char* buf, int buf_len, CompletionCallback* callback);
+ virtual int Start(const FtpRequestInfo* request_info,
+ CompletionCallback* callback);
+ virtual int Stop(int error);
+ virtual int RestartWithAuth(const std::wstring& username,
+ const std::wstring& password,
+ CompletionCallback* callback);
+ virtual int RestartIgnoringLastError(CompletionCallback* callback);
+ virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
virtual const FtpResponseInfo* GetResponseInfo() const;
virtual LoadState GetLoadState() const;
virtual uint64 GetUploadProgress() const;
private:
+ enum Command {
+ COMMAND_NONE,
+ COMMAND_USER,
+ COMMAND_PASS,
+ COMMAND_ACCT,
+ COMMAND_SYST,
+ COMMAND_TYPE,
+ COMMAND_PASV,
+ COMMAND_PWD,
+ COMMAND_SIZE,
+ COMMAND_RETR,
+ COMMAND_CWD,
+ COMMAND_LIST,
+ COMMAND_QUIT
+ };
+
+ enum ErrorClass {
+ ERROR_CLASS_INITIATED = 1, // The requested action was initiated.
+ ERROR_CLASS_OK, // The requested action successfully completed.
+ ERROR_CLASS_PENDING, // The command accepted, but the
+ // request on hold.
+ ERROR_CLASS_ERROR_RETRY, // The command was not accepted and the
+ // requested action did not take place,
+ // but the error condition is temporary and the
+ // action may be requested again.
+ ERROR_CLASS_ERROR, // The command was not accepted and
+ // the requested action did not take place.
+ };
+
void DoCallback(int result);
void OnIOComplete(int result);
+ int GetRespnseCode();
+ int ProcessResponse(int response_code);
+ int ParsePasvResponse();
+
+ int SendFtpCommand(const std::string& command, Command cmd);
+
+ // TODO(ibrar): Use C++ static_cast.
+ ErrorClass GetErrorClass(int response_code) {
+ return (ErrorClass)(response_code / 100);
+ }
// Runs the state transition loop.
int DoLoop(int result);
@@ -51,15 +95,40 @@ class FtpNetworkTransaction : public FtpTransaction {
int DoCtrlResolveHostComplete(int result);
int DoCtrlConnect();
int DoCtrlConnectComplete(int result);
- int DoCtrlWrite();
- int DoCtrlWriteComplete(int result);
int DoCtrlRead();
int DoCtrlReadComplete(int result);
+ int DoCtrlWriteUSER();
+ int ProcessResponseUSER(int response_code);
+ int DoCtrlWritePASS();
+ int ProcessResponsePASS(int response_code);
+ int DoCtrlWriteACCT();
+ int ProcessResponseACCT(int response_code);
+ int DoCtrlWriteSYST();
+ int ProcessResponseSYST(int response_code);
+ int DoCtrlWritePWD();
+ int ProcessResponsePWD(int response_code);
+ int DoCtrlWriteTYPE();
+ int ProcessResponseTYPE(int response_code);
+ int DoCtrlWritePASV();
+ int ProcessResponsePASV(int response_code);
+ int DoCtrlWriteRETR();
+ int ProcessResponseRETR(int response_code);
+ int DoCtrlWriteSIZE();
+ int ProcessResponseSIZE(int response_code);
+ int DoCtrlWriteCWD();
+ int ProcessResponseCWD(int response_code);
+ int DoCtrlWriteLIST();
+ int ProcessResponseLIST(int response_code);
+ int DoCtrlWriteQUIT();
+ int ProcessResponseQUIT(int response_code);
+
int DoDataConnect();
int DoDataConnectComplete(int result);
int DoDataRead();
int DoDataReadComplete(int result);
+ Command command_sent_;
+
CompletionCallbackImpl<FtpNetworkTransaction> io_callback_;
CompletionCallback* user_callback_;
@@ -68,7 +137,29 @@ class FtpNetworkTransaction : public FtpTransaction {
const FtpRequestInfo* request_;
FtpResponseInfo response_;
+ HostResolver resolver_;
+ AddressList addresses_;
+
+ // User buffer and length passed to the Read method.
+ scoped_refptr<IOBuffer> read_ctrl_buf_;
+ int read_ctrl_buf_size_;
+
+ scoped_refptr<IOBuffer> response_message_buf_;
+ int response_message_buf_len_;
+
+ scoped_refptr<IOBuffer> read_data_buf_;
+ int read_data_buf_len_;
+ int file_data_len_;
+
+ scoped_refptr<IOBuffer> write_buf_;
+
+ int last_error_;
+
+ std::string data_connection_ip_;
+ int data_connection_port_;
+
ClientSocketFactory* socket_factory_;
+
scoped_ptr<ClientSocket> ctrl_socket_;
scoped_ptr<ClientSocket> data_socket_;
@@ -80,10 +171,20 @@ class FtpNetworkTransaction : public FtpTransaction {
STATE_CTRL_RESOLVE_HOST_COMPLETE,
STATE_CTRL_CONNECT,
STATE_CTRL_CONNECT_COMPLETE,
- STATE_CTRL_WRITE,
- STATE_CTRL_WRITE_COMPLETE,
STATE_CTRL_READ,
STATE_CTRL_READ_COMPLETE,
+ STATE_CTRL_WRITE_USER,
+ STATE_CTRL_WRITE_PASS,
+ STATE_CTRL_WRITE_ACCT,
+ STATE_CTRL_WRITE_SYST,
+ STATE_CTRL_WRITE_TYPE,
+ STATE_CTRL_WRITE_PASV,
+ STATE_CTRL_WRITE_PWD,
+ STATE_CTRL_WRITE_RETR,
+ STATE_CTRL_WRITE_SIZE,
+ STATE_CTRL_WRITE_CWD,
+ STATE_CTRL_WRITE_LIST,
+ STATE_CTRL_WRITE_QUIT,
// Data connection states:
STATE_DATA_CONNECT,
STATE_DATA_CONNECT_COMPLETE,
diff --git a/net/ftp/ftp_request_info.h b/net/ftp/ftp_request_info.h
index 235a264..a2e90c6 100644
--- a/net/ftp/ftp_request_info.h
+++ b/net/ftp/ftp_request_info.h
@@ -5,16 +5,16 @@
#ifndef NET_FTP_FTP_REQUEST_INFO_H_
#define NET_FTP_FTP_REQUEST_INFO_H_
+#include "googleurl/src/gurl.h"
+
+namespace net {
+
class FtpRequestInfo {
public:
// The requested URL.
GURL url;
-
- // Any upload data.
- scoped_refptr<UploadData> upload_data;
-
- // Any load flags (see load_flags.h).
- int load_flags;
};
+} // namespace net
+
#endif // NET_FTP_FTP_REQUEST_INFO_H_
diff --git a/net/ftp/ftp_response_info.h b/net/ftp/ftp_response_info.h
index 398f050..b3c3361 100644
--- a/net/ftp/ftp_response_info.h
+++ b/net/ftp/ftp_response_info.h
@@ -11,17 +11,22 @@ namespace net {
class FtpResponseInfo {
public:
+ FtpResponseInfo() : is_directory_listing(false) {
+ }
+
// Non-null when authentication is required.
scoped_refptr<AuthChallengeInfo> auth_challenge;
- // The length of the response. -1 means unspecified.
- int64 content_length;
+ // The time at which the request was made that resulted in this response.
+ // For cached responses, this time could be "far" in the past.
+ base::Time request_time;
+
+ // The time at which the response headers were received. For cached
+ // responses, this time could be "far" in the past.
+ base::Time response_time;
// True if the response data is of a directory listing.
bool is_directory_listing;
-
- FtpResponseInfo() : content_length(-1), is_directory_listing(false) {
- }
};
} // namespace net
diff --git a/net/ftp/ftp_transaction.h b/net/ftp/ftp_transaction.h
index 90fbf25..a0798ea 100644
--- a/net/ftp/ftp_transaction.h
+++ b/net/ftp/ftp_transaction.h
@@ -6,6 +6,7 @@
#define NET_FTP_FTP_TRANSACTION_H_
#include "net/base/completion_callback.h"
+#include "net/base/io_buffer.h"
#include "net/base/load_states.h"
namespace net {
@@ -17,7 +18,7 @@ class FtpResponseInfo;
class FtpTransaction {
public:
// Stops any pending IO and destroys the transaction object.
- virtual void Destroy() = 0;
+ virtual ~FtpTransaction() {}
// Starts the FTP transaction (i.e., sends the FTP request).
//
@@ -54,7 +55,9 @@ class FtpTransaction {
//
// NOTE: The transaction is not responsible for deleting the callback object.
//
- virtual int Read(char* buf, int buf_len, CompletionCallback* callback) = 0;
+ virtual int Read(IOBuffer* buf,
+ int buf_len,
+ CompletionCallback* callback) = 0;
// Returns the response info for this transaction or NULL if the response
// info is not available.
@@ -64,7 +67,7 @@ class FtpTransaction {
virtual LoadState GetLoadState() const = 0;
// Returns the upload progress in bytes. If there is no upload data,
- // zero will be returned. This does not include the request headers.
+ // zero will be returned.
virtual uint64 GetUploadProgress() const = 0;
};
diff --git a/net/ftp/ftp_transaction_factory.h b/net/ftp/ftp_transaction_factory.h
index f4cc53a..7e39026 100644
--- a/net/ftp/ftp_transaction_factory.h
+++ b/net/ftp/ftp_transaction_factory.h
@@ -7,7 +7,6 @@
namespace net {
-class FtpAuthCache;
class FtpTransaction;
// An interface to a class that can create FtpTransaction objects.
@@ -18,9 +17,6 @@ class FtpTransactionFactory {
// Creates a FtpTransaction object.
virtual FtpTransaction* CreateTransaction() = 0;
- // Returns the associated FTP auth cache if any (may be NULL).
- virtual FtpAuthCache* GetAuthCache() = 0;
-
// Suspends the creation of new transactions. If |suspend| is false, creation
// of new transactions is resumed.
virtual void Suspend(bool suspend) = 0;