// Copyright (c) 2008 The Chromium Authors. All rights reserved. Use of this
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
#ifndef NET_FTP_FTP_NETWORK_TRANSACTION_H_
#define NET_FTP_FTP_NETWORK_TRANSACTION_H_
#include <string>
#include <queue>
#include <utility>
#include <vector>
#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_ctrl_response_buffer.h"
#include "net/ftp/ftp_response_info.h"
#include "net/ftp/ftp_transaction.h"
namespace net {
class ClientSocket;
class ClientSocketFactory;
class FtpNetworkSession;
class FtpNetworkTransaction : public FtpTransaction {
public:
FtpNetworkTransaction(FtpNetworkSession* session,
ClientSocketFactory* socket_factory);
virtual ~FtpNetworkTransaction();
// FtpTransaction methods:
virtual int Start(const FtpRequestInfo* request_info,
CompletionCallback* callback,
LoadLog* load_log);
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_MLSD,
COMMAND_LIST,
COMMAND_MDTM,
COMMAND_QUIT
};
enum ErrorClass {
// The requested action was initiated. The client should expect another
// reply before issuing the next command.
ERROR_CLASS_INITIATED,
// The requested action has been successfully completed.
ERROR_CLASS_OK,
// The command has been accepted, but to complete the operation, more
// information must be sent by the client.
ERROR_CLASS_INFO_NEEDED,
// The command was not accepted and the requested action did not take place.
// This condition is temporary, and the client is encouraged to restart the
// command sequence.
ERROR_CLASS_TRANSIENT_ERROR,
// The command was not accepted and the requested action did not take place.
// This condition is rather permanent, and the client is discouraged from
// repeating the exact request.
ERROR_CLASS_PERMANENT_ERROR,
};
// Major categories of remote system types, as returned by SYST command.
enum SystemType {
SYSTEM_TYPE_UNKNOWN,
SYSTEM_TYPE_UNIX,
SYSTEM_TYPE_WINDOWS,
SYSTEM_TYPE_OS2,
SYSTEM_TYPE_VMS,
};
// Resets the members of the transaction so it can be restarted.
void ResetStateForRestart();
void DoCallback(int result);
void OnIOComplete(int result);
// Executes correct ProcessResponse + command_name function based on last
// issued command. Returns error code.
int ProcessCtrlResponse();
int SendFtpCommand(const std::string& command, Command cmd);
// Return the error class for given response code. You should validate the
// code to be in range 100-599.
static ErrorClass GetErrorClass(int response_code);
// Returns request path suitable to be included in an FTP command. If the path
// will be used as a directory, |is_directory| should be true.
std::string GetRequestPathForFtpCommand(bool is_directory) const;
// Runs the state transition loop.
int DoLoop(int result);
// Each of these methods corresponds to a State value. Those with an input
// argument receive the result from the previous state. If a method returns
// ERR_IO_PENDING, then the result from OnIOComplete will be passed to the
// next state method as the result arg.
int DoCtrlInit();
int DoCtrlInitComplete(int result);
int DoCtrlResolveHost();
int DoCtrlResolveHostComplete(int result);
int DoCtrlConnect();
int DoCtrlConnectComplete(int result);
int DoCtrlRead();
int DoCtrlReadComplete(int result);
int DoCtrlWrite();
int DoCtrlWriteComplete(int result);
int DoCtrlWriteUSER();
int ProcessResponseUSER(const FtpCtrlResponse& response);
int DoCtrlWritePASS();
int ProcessResponsePASS(const FtpCtrlResponse& response);
int DoCtrlWriteACCT();
int ProcessResponseACCT(const FtpCtrlResponse& response);
int DoCtrlWriteSYST();
int ProcessResponseSYST(const FtpCtrlResponse& response);
int DoCtrlWritePWD();
int ProcessResponsePWD(const FtpCtrlResponse& response);
int DoCtrlWriteTYPE();
int ProcessResponseTYPE(const FtpCtrlResponse& response);
int DoCtrlWritePASV();
int ProcessResponsePASV(const FtpCtrlResponse& response);
int DoCtrlWriteRETR();
int ProcessResponseRETR(const FtpCtrlResponse& response);
int DoCtrlWriteSIZE();
int ProcessResponseSIZE(const FtpCtrlResponse& response);
int DoCtrlWriteCWD();
int ProcessResponseCWD(const FtpCtrlResponse& response);
int DoCtrlWriteMLSD();
int ProcessResponseMLSD(const FtpCtrlResponse& response);
int DoCtrlWriteLIST();
int ProcessResponseLIST(const FtpCtrlResponse& response);
int DoCtrlWriteMDTM();
int ProcessResponseMDTM(const FtpCtrlResponse& response);
int DoCtrlWriteQUIT();
int ProcessResponseQUIT(const FtpCtrlResponse& response);
int DoDataConnect();
int DoDataConnectComplete(int result);
int DoDataRead();
int DoDataReadComplete(int result);
void RecordDataConnectionError(int result);
Command command_sent_;
CompletionCallbackImpl<FtpNetworkTransaction> io_callback_;
CompletionCallback* user_callback_;
scoped_refptr<FtpNetworkSession> session_;
scoped_refptr<LoadLog> load_log_;
const FtpRequestInfo* request_;
FtpResponseInfo response_;
// Cancels the outstanding request on destruction.
SingleRequestHostResolver resolver_;
AddressList addresses_;
// User buffer passed to the Read method for control socket.
scoped_refptr<IOBuffer> read_ctrl_buf_;
scoped_ptr<FtpCtrlResponseBuffer> ctrl_response_buffer_;
scoped_refptr<IOBuffer> read_data_buf_;
int read_data_buf_len_;
int file_data_len_;
// Buffer holding the command line to be written to the control socket.
scoped_refptr<IOBufferWithSize> write_command_buf_;
// Buffer passed to the Write method of control socket. It actually writes
// to the write_command_buf_ at correct offset.
scoped_refptr<DrainableIOBuffer> write_buf_;
int last_error_;
SystemType system_type_;
// We get username and password as wstrings in RestartWithAuth, so they are
// also kept as wstrings here.
std::wstring username_;
std::wstring password_;
// Current directory on the remote server, as returned by last PWD command,
// with any trailing slash removed.
std::string current_remote_directory_;
bool retr_failed_;
int data_connection_port_;
ClientSocketFactory* socket_factory_;
scoped_ptr<ClientSocket> ctrl_socket_;
scoped_ptr<ClientSocket> data_socket_;
enum State {
// Control connection states:
STATE_CTRL_INIT,
STATE_CTRL_INIT_COMPLETE,
STATE_CTRL_RESOLVE_HOST,
STATE_CTRL_RESOLVE_HOST_COMPLETE,
STATE_CTRL_CONNECT,
STATE_CTRL_CONNECT_COMPLETE,
STATE_CTRL_READ,
STATE_CTRL_READ_COMPLETE,
STATE_CTRL_WRITE,
STATE_CTRL_WRITE_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_MLSD,
STATE_CTRL_WRITE_LIST,
STATE_CTRL_WRITE_MDTM,
STATE_CTRL_WRITE_QUIT,
// Data connection states:
STATE_DATA_CONNECT,
STATE_DATA_CONNECT_COMPLETE,
STATE_DATA_READ,
STATE_DATA_READ_COMPLETE,
STATE_NONE
};
State next_state_;
};
} // namespace net
#endif // NET_FTP_FTP_NETWORK_TRANSACTION_H_