case AnyP::PROTO_FTP:
if (request->flags.ftpNative)
- ftpGatewayServerStart(this);
+ Ftp::StartRelay(this);
else
- ftpStart(this);
+ Ftp::StartGateway(this);
break;
case AnyP::PROTO_CACHE_OBJECT:
/// configures the channel with a descriptor and registers a close handler
void
-FtpChannel::opened(const Comm::ConnectionPointer &newConn,
+Ftp::Channel::opened(const Comm::ConnectionPointer &newConn,
const AsyncCall::Pointer &aCloser)
{
assert(!Comm::IsConnOpen(conn));
/// planned close: removes the close handler and calls comm_close
void
-FtpChannel::close()
+Ftp::Channel::close()
{
// channels with active listeners will be closed when the listener handler dies.
if (Comm::IsConnOpen(conn)) {
}
void
-FtpChannel::forget()
+Ftp::Channel::forget()
{
if (Comm::IsConnOpen(conn)) {
commUnsetConnTimeout(conn);
}
void
-FtpChannel::clear()
+Ftp::Channel::clear()
{
conn = NULL;
closer = NULL;
}
-ServerStateData::ServerStateData(FwdState *fwdState):
- AsyncJob("Ftp::ServerStateData"), ::ServerStateData(fwdState)
+Ftp::Client::Client(FwdState *fwdState):
+ AsyncJob("Ftp::Client"), ::ServerStateData(fwdState)
{
++statCounter.server.all.requests;
++statCounter.server.ftp.requests;
ctrl.buf = static_cast<char *>(memAllocBuf(4096, &ctrl.size));
ctrl.offset = 0;
- typedef CommCbMemFunT<ServerStateData, CommCloseCbParams> Dialer;
+ typedef CommCbMemFunT<Client, CommCloseCbParams> Dialer;
const AsyncCall::Pointer closer = JobCallback(9, 5, Dialer, this,
- ServerStateData::ctrlClosed);
+ Ftp::Client::ctrlClosed);
ctrl.opened(fwdState->serverConnection(), closer);
}
void
-ServerStateData::DataChannel::addr(const Ip::Address &import)
+Ftp::Client::DataChannel::addr(const Ip::Address &import)
{
static char addrBuf[MAX_IPSTRLEN];
import.toStr(addrBuf, sizeof(addrBuf));
port = import.port();
}
-ServerStateData::~ServerStateData()
+Ftp::Client::~Client()
{
if (data.opener != NULL) {
- data.opener->cancel("Ftp::ServerStateData destructed");
+ data.opener->cancel("Ftp::Client destructed");
data.opener = NULL;
}
data.close();
}
void
-ServerStateData::start()
+Ftp::Client::start()
{
scheduleReadControlReply(0);
}
void
-ServerStateData::initReadBuf()
+Ftp::Client::initReadBuf()
{
if (data.readBuf == NULL) {
data.readBuf = new MemBuf;
* Close the FTP server connection(s). Used by serverComplete().
*/
void
-ServerStateData::closeServer()
+Ftp::Client::closeServer()
{
if (Comm::IsConnOpen(ctrl.conn)) {
debugs(9,3, HERE << "closing FTP server FD " << ctrl.conn->fd << ", this " << this);
\retval false Either control channel or data is still active.
*/
bool
-ServerStateData::doneWithServer() const
+Ftp::Client::doneWithServer() const
{
return !Comm::IsConnOpen(ctrl.conn) && !Comm::IsConnOpen(data.conn);
}
void
-ServerStateData::failed(err_type error, int xerrno)
+Ftp::Client::failed(err_type error, int xerrno)
{
debugs(9,3,HERE << "entry-null=" << (entry?entry->isEmpty():0) << ", entry=" << entry);
}
Http::StatusCode
-ServerStateData::failedHttpStatus(err_type &error)
+Ftp::Client::failedHttpStatus(err_type &error)
{
if (error == ERR_NONE)
error = ERR_FTP_FAILURE;
* buffered_ok=1. Perhaps it can be removed at some point.
*/
void
-ServerStateData::scheduleReadControlReply(int buffered_ok)
+Ftp::Client::scheduleReadControlReply(int buffered_ok)
{
debugs(9, 3, HERE << ctrl.conn);
commUnsetConnTimeout(data.conn);
}
- typedef CommCbMemFunT<ServerStateData, CommTimeoutCbParams> TimeoutDialer;
- AsyncCall::Pointer timeoutCall = JobCallback(9, 5, TimeoutDialer, this, ServerStateData::timeout);
+ typedef CommCbMemFunT<Client, CommTimeoutCbParams> TimeoutDialer;
+ AsyncCall::Pointer timeoutCall = JobCallback(9, 5, TimeoutDialer, this, Ftp::Client::timeout);
commSetConnTimeout(ctrl.conn, Config.Timeout.read, timeoutCall);
- typedef CommCbMemFunT<ServerStateData, CommIoCbParams> Dialer;
- AsyncCall::Pointer reader = JobCallback(9, 5, Dialer, this, ServerStateData::readControlReply);
+ typedef CommCbMemFunT<Client, CommIoCbParams> Dialer;
+ AsyncCall::Pointer reader = JobCallback(9, 5, Dialer, this, Ftp::Client::readControlReply);
comm_read(ctrl.conn, ctrl.buf + ctrl.offset, ctrl.size - ctrl.offset, reader);
}
}
void
-ServerStateData::readControlReply(const CommIoCbParams &io)
+Ftp::Client::readControlReply(const CommIoCbParams &io)
{
debugs(9, 3, HERE << "FD " << io.fd << ", Read " << io.size << " bytes");
}
void
-ServerStateData::handleControlReply()
+Ftp::Client::handleControlReply()
{
debugs(9, 3, HERE);
}
bool
-ServerStateData::handlePasvReply(Ip::Address &srvAddr)
+Ftp::Client::handlePasvReply(Ip::Address &srvAddr)
{
int code = ctrl.replycode;
char *buf;
}
bool
-ServerStateData::handleEpsvReply(Ip::Address &remoteAddr)
+Ftp::Client::handleEpsvReply(Ip::Address &remoteAddr)
{
int code = ctrl.replycode;
char *buf;
}
// The server-side EPRT and PORT commands are not yet implemented.
-// The ServerStateData::sendEprt() will fail because of the unimplemented
+// The Ftp::Client::sendEprt() will fail because of the unimplemented
// openListenSocket() or sendPort() methods
bool
-ServerStateData::sendEprt()
+Ftp::Client::sendEprt()
{
if (!Config.Ftp.eprt) {
/* Disabled. Switch immediately to attempting old PORT command. */
}
bool
-ServerStateData::sendPort()
+Ftp::Client::sendPort()
{
failed(ERR_FTP_FAILURE, 0);
return false;
}
bool
-ServerStateData::sendPassive()
+Ftp::Client::sendPassive()
{
debugs(9, 3, HERE);
void
-ServerStateData::connectDataChannel()
+Ftp::Client::connectDataChannel()
{
safe_free(ctrl.last_command);
debugs(9, 3, HERE << "connecting to " << conn->remote);
- data.opener = commCbCall(9,3, "Ftp::ServerStateData::dataChannelConnected",
- CommConnectCbPtrFun(ServerStateData::dataChannelConnected, this));
+ data.opener = commCbCall(9,3, "Ftp::Client::dataChannelConnected",
+ CommConnectCbPtrFun(Ftp::Client::dataChannelConnected, this));
Comm::ConnOpener *cs = new Comm::ConnOpener(conn, data.opener, Config.Timeout.connect);
cs->setHost(data.host);
AsyncJob::Start(cs);
}
void
-ServerStateData::dataChannelConnected(const Comm::ConnectionPointer &conn, Comm::Flag status, int xerrno, void *data)
+Ftp::Client::dataChannelConnected(const Comm::ConnectionPointer &conn, Comm::Flag status, int xerrno, void *data)
{
- ServerStateData *ftpState = static_cast<ServerStateData *>(data);
+ Client *ftpState = static_cast<Client *>(data);
ftpState->dataChannelConnected(conn, status, xerrno);
}
bool
-ServerStateData::openListenSocket()
+Ftp::Client::openListenSocket()
{
return false;
}
/// creates a data channel Comm close callback
AsyncCall::Pointer
-ServerStateData::dataCloser()
+Ftp::Client::dataCloser()
{
- typedef CommCbMemFunT<ServerStateData, CommCloseCbParams> Dialer;
- return JobCallback(9, 5, Dialer, this, ServerStateData::dataClosed);
+ typedef CommCbMemFunT<Client, CommCloseCbParams> Dialer;
+ return JobCallback(9, 5, Dialer, this, Ftp::Client::dataClosed);
}
/// handler called by Comm when FTP data channel is closed unexpectedly
void
-ServerStateData::dataClosed(const CommCloseCbParams &io)
+Ftp::Client::dataClosed(const CommCloseCbParams &io)
{
debugs(9, 4, HERE);
if (data.listenConn != NULL) {
}
void
-ServerStateData::writeCommand(const char *buf)
+Ftp::Client::writeCommand(const char *buf)
{
char *ebuf;
/* trace FTP protocol communications at level 2 */
return;
}
- typedef CommCbMemFunT<ServerStateData, CommIoCbParams> Dialer;
+ typedef CommCbMemFunT<Client, CommIoCbParams> Dialer;
AsyncCall::Pointer call = JobCallback(9, 5, Dialer, this,
- ServerStateData::writeCommandCallback);
+ Ftp::Client::writeCommandCallback);
Comm::Write(ctrl.conn, ctrl.last_command, strlen(ctrl.last_command), call, NULL);
scheduleReadControlReply(0);
}
void
-ServerStateData::writeCommandCallback(const CommIoCbParams &io)
+Ftp::Client::writeCommandCallback(const CommIoCbParams &io)
{
debugs(9, 5, HERE << "wrote " << io.size << " bytes");
/// handler called by Comm when FTP control channel is closed unexpectedly
void
-ServerStateData::ctrlClosed(const CommCloseCbParams &io)
+Ftp::Client::ctrlClosed(const CommCloseCbParams &io)
{
debugs(9, 4, HERE);
ctrl.clear();
- mustStop("Ftp::ServerStateData::ctrlClosed");
+ mustStop("Ftp::Client::ctrlClosed");
}
void
-ServerStateData::timeout(const CommTimeoutCbParams &io)
+Ftp::Client::timeout(const CommTimeoutCbParams &io)
{
debugs(9, 4, HERE << io.conn << ": '" << entry->url() << "'" );
}
const Comm::ConnectionPointer &
-ServerStateData::dataConnection() const
+Ftp::Client::dataConnection() const
{
return data.conn;
}
void
-ServerStateData::maybeReadVirginBody()
+Ftp::Client::maybeReadVirginBody()
{
// too late to read
if (!Comm::IsConnOpen(data.conn) || fd_table[data.conn->fd].closing())
data.read_pending = true;
- typedef CommCbMemFunT<ServerStateData, CommTimeoutCbParams> TimeoutDialer;
+ typedef CommCbMemFunT<Client, CommTimeoutCbParams> TimeoutDialer;
AsyncCall::Pointer timeoutCall = JobCallback(9, 5,
- TimeoutDialer, this, ServerStateData::timeout);
+ TimeoutDialer, this, Ftp::Client::timeout);
commSetConnTimeout(data.conn, Config.Timeout.read, timeoutCall);
debugs(9,5,HERE << "queueing read on FD " << data.conn->fd);
- typedef CommCbMemFunT<ServerStateData, CommIoCbParams> Dialer;
+ typedef CommCbMemFunT<Client, CommIoCbParams> Dialer;
entry->delayAwareRead(data.conn, data.readBuf->space(), read_sz,
- JobCallback(9, 5, Dialer, this, ServerStateData::dataRead));
+ JobCallback(9, 5, Dialer, this, Ftp::Client::dataRead));
}
void
-ServerStateData::dataRead(const CommIoCbParams &io)
+Ftp::Client::dataRead(const CommIoCbParams &io)
{
int j;
int bin;
}
void
-ServerStateData::dataComplete()
+Ftp::Client::dataComplete()
{
debugs(9, 3,HERE);
* including canceling close handlers
*/
void
-ServerStateData::abortTransaction(const char *reason)
+Ftp::Client::abortTransaction(const char *reason)
{
debugs(9, 3, HERE << "aborting transaction for " << reason <<
"; FD " << (ctrl.conn!=NULL?ctrl.conn->fd:-1) << ", Data FD " << (data.conn!=NULL?data.conn->fd:-1) << ", this " << this);
}
fwd->handleUnregisteredServerEnd();
- mustStop("ServerStateData::abortTransaction");
+ mustStop("Ftp::Client::abortTransaction");
}
/**
* on the data socket
*/
void
-ServerStateData::switchTimeoutToDataChannel()
+Ftp::Client::switchTimeoutToDataChannel()
{
commUnsetConnTimeout(ctrl.conn);
- typedef CommCbMemFunT<ServerStateData, CommTimeoutCbParams> TimeoutDialer;
+ typedef CommCbMemFunT<Client, CommTimeoutCbParams> TimeoutDialer;
AsyncCall::Pointer timeoutCall = JobCallback(9, 5, TimeoutDialer, this,
- ServerStateData::timeout);
+ Ftp::Client::timeout);
commSetConnTimeout(data.conn, Config.Timeout.read, timeoutCall);
}
void
-ServerStateData::sentRequestBody(const CommIoCbParams &io)
+Ftp::Client::sentRequestBody(const CommIoCbParams &io)
{
if (io.size > 0)
kb_incr(&(statCounter.server.ftp.kbytes_out), io.size);
* called after we wrote the last byte of the request body
*/
void
-ServerStateData::doneSendingRequestBody()
+Ftp::Client::doneSendingRequestBody()
{
::ServerStateData::doneSendingRequestBody();
debugs(9,3, HERE);
/// Parses FTP server control response into ctrl structure fields,
/// setting bytesUsed and returning true on success.
bool
-ServerStateData::parseControlReply(size_t &bytesUsed)
+Ftp::Client::parseControlReply(size_t &bytesUsed)
{
char *s;
char *sbuf;
*
*/
-#ifndef SQUID_FTP_SERVER_H
-#define SQUID_FTP_SERVER_H
+#ifndef SQUID_FTP_CLIENT_H
+#define SQUID_FTP_CLIENT_H
#include "Server.h"
extern const char *const crlf;
/// common code for FTP server control and data channels
-/// does not own the channel descriptor, which is managed by FtpStateData
-class FtpChannel
+/// does not own the channel descriptor, which is managed by Ftp::Client
+class Channel
{
public:
/// called after the socket is opened, sets up close handler
AsyncCall::Pointer closer; ///< Comm close handler callback
};
-/// Base class for FTP over HTTP and FTP Gateway server state.
-class ServerStateData: public ::ServerStateData
+/// Base class for FTP Gateway and FTP Native client classes.
+class Client: public ::ServerStateData
{
public:
- ServerStateData(FwdState *fwdState);
- virtual ~ServerStateData();
+ explicit Client(FwdState *fwdState);
+ virtual ~Client();
+ /// handle a fatal transaction error, closing the control connection
virtual void failed(err_type error = ERR_NONE, int xerrno = 0);
+
+ /// read timeout handler
virtual void timeout(const CommTimeoutCbParams &io);
- virtual const Comm::ConnectionPointer & dataConnection() const;
- virtual void abortTransaction(const char *reason);
+
+ /* ServerStateData API */
+ virtual void maybeReadVirginBody();
+
void writeCommand(const char *buf);
/// extracts remoteAddr from PASV response, validates it,
bool sendPassive();
void connectDataChannel();
bool openListenSocket();
- virtual void maybeReadVirginBody();
void switchTimeoutToDataChannel();
// \todo: optimize ctrl and data structs member order, to minimize size
/// FTP control channel info; the channel is opened once per transaction
- struct CtrlChannel: public FtpChannel {
+ struct CtrlChannel: public Ftp::Channel {
char *buf;
size_t size;
size_t offset;
} ctrl;
/// FTP data channel info; the channel may be opened/closed a few times
- struct DataChannel: public FtpChannel {
+ struct DataChannel: public Ftp::Channel {
MemBuf *readBuf;
char *host;
unsigned short port;
char *old_reply;
protected:
+ /* AsyncJob API */
virtual void start();
- void initReadBuf();
+ /* ServerStateData API */
virtual void closeServer();
virtual bool doneWithServer() const;
+ virtual const Comm::ConnectionPointer & dataConnection() const;
+ virtual void abortTransaction(const char *reason);
+
virtual Http::StatusCode failedHttpStatus(err_type &error);
void ctrlClosed(const CommCloseCbParams &io);
void scheduleReadControlReply(int buffered_ok);
void dataComplete();
AsyncCall::Pointer dataCloser();
virtual void dataClosed(const CommCloseCbParams &io);
+ void initReadBuf();
// sending of the request body to the server
virtual void sentRequestBody(const CommIoCbParams &io);
private:
bool parseControlReply(size_t &bytesUsed);
- CBDATA_CLASS2(ServerStateData);
+ CBDATA_CLASS2(Client);
};
-/// parses and validates "A1,A2,A3,A4,P1,P2" IP,port sequence
-bool ParseIpPort(const char *buf, const char *forceIp, Ip::Address &addr);
-/// parses and validates EPRT "<d><net-prt><d><net-addr><d><tcp-port><d>" proto,ip,port sequence
-bool ParseProtoIpPort(const char *buf, Ip::Address &addr);
-/// parses a ftp quoted quote-escaped path
-const char *unescapeDoubleQuoted(const char *quotedPath);
} // namespace Ftp
-#endif /* SQUID_FTP_SERVER_H */
+#endif /* SQUID_FTP_CLIENT_H */
#include "squid.h"
#include "acl/FilledChecklist.h"
+#include "clients/forward.h"
#include "clients/FtpClient.h"
#include "comm.h"
#include "comm/ConnOpener.h"
#include <cerrno>
+namespace Ftp {
+
/**
\defgroup ServerProtocolFTPInternal Server-Side FTP Internals
\ingroup ServerProtocolFTPAPI
*/
-#define CTRL_BUFLEN 1024
-/// \ingroup ServerProtocolFTPInternal
-static char cbuf[CTRL_BUFLEN];
-
/// \ingroup ServerProtocolFTPInternal
-struct _ftp_flags {
+struct GatewayFlags {
/* passive mode */
bool pasv_supported; ///< PASV command is allowed
bool completed_forwarding;
};
-class FtpStateData;
+class Gateway;
/// \ingroup ServerProtocolFTPInternal
-typedef void (FTPSM) (FtpStateData *);
+typedef void (StateMethod)(Ftp::Gateway *);
/// \ingroup ServerProtocolFTPInternal
-class FtpStateData : public Ftp::ServerStateData
+/// FTP Gateway: An FTP client that takes an HTTP request with an ftp:// URI,
+/// converts it into one or more FTP commands, and then
+/// converts one or more FTP responses into the final HTTP response.
+class Gateway : public Ftp::Client
{
public:
- FtpStateData(FwdState *);
- virtual ~FtpStateData();
+ Gateway(FwdState *);
+ virtual ~Gateway();
char user[MAX_URL];
char password[MAX_URL];
int password_url;
char typecode;
MemBuf listing; ///< FTP directory listing in HTML format.
- struct _ftp_flags flags;
+ GatewayFlags flags;
public:
// these should all be private
void loginParser(const char *, int escaped);
int restartable();
void appendSuccessHeader();
- void hackShortcut(FTPSM * nextState);
+ void hackShortcut(StateMethod *nextState);
void unhack();
void readStor();
void parseListing();
// BodyConsumer for HTTP: consume request body.
virtual void handleRequestBodyProducerAborted();
- CBDATA_CLASS2(FtpStateData);
+ CBDATA_CLASS2(Gateway);
};
-CBDATA_CLASS_INIT(FtpStateData);
+} // namespace Ftp
+
+typedef Ftp::StateMethod FTPSM; // to avoid lots of non-changes
+
+CBDATA_NAMESPACED_CLASS_INIT(Ftp, Gateway);
/// \ingroup ServerProtocolFTPInternal
typedef struct {
/// \ingroup ServerProtocolFTPInternal
#define FTP_LOGIN_NOT_ESCAPED 0
+#define CTRL_BUFLEN 1024
+/// \ingroup ServerProtocolFTPInternal
+static char cbuf[CTRL_BUFLEN];
+
/*
* State machine functions
* send == state transition
/// handler called by Comm when FTP data channel is closed unexpectedly
void
-FtpStateData::dataClosed(const CommCloseCbParams &io)
+Ftp::Gateway::dataClosed(const CommCloseCbParams &io)
{
- Ftp::ServerStateData::dataClosed(io);
+ Ftp::Client::dataClosed(io);
failed(ERR_FTP_FAILURE, 0);
/* failed closes ctrl.conn and frees ftpState */
*/
}
-FtpStateData::FtpStateData(FwdState *fwdState): AsyncJob("FtpStateData"),
- Ftp::ServerStateData(fwdState)
+Ftp::Gateway::Gateway(FwdState *fwdState):
+ AsyncJob("FtpStateData"),
+ Ftp::Client(fwdState)
{
const char *url = entry->url();
debugs(9, 3, HERE << "'" << url << "'" );
initReadBuf();
}
-FtpStateData::~FtpStateData()
+Ftp::Gateway::~Gateway()
{
debugs(9, 3, HERE << entry->url() );
* Produces filled member variables user, password, password_url if anything found.
*/
void
-FtpStateData::loginParser(const char *login, int escaped)
+Ftp::Gateway::loginParser(const char *login, int escaped)
{
const char *u = NULL; // end of the username sub-string
int len; // length of the current sub-string to handle.
}
void
-FtpStateData::listenForDataChannel(const Comm::ConnectionPointer &conn)
+Ftp::Gateway::listenForDataChannel(const Comm::ConnectionPointer &conn)
{
assert(!Comm::IsConnOpen(data.conn));
- typedef CommCbMemFunT<FtpStateData, CommAcceptCbParams> AcceptDialer;
+ typedef CommCbMemFunT<Gateway, CommAcceptCbParams> AcceptDialer;
typedef AsyncCallT<AcceptDialer> AcceptCall;
- RefCount<AcceptCall> call = static_cast<AcceptCall*>(JobCallback(11, 5, AcceptDialer, this, FtpStateData::ftpAcceptDataConnection));
+ RefCount<AcceptCall> call = static_cast<AcceptCall*>(JobCallback(11, 5, AcceptDialer, this, Ftp::Gateway::ftpAcceptDataConnection));
Subscription::Pointer sub = new CallSubscription<AcceptCall>(call);
const char *note = entry->url();
}
void
-FtpStateData::timeout(const CommTimeoutCbParams &io)
+Ftp::Gateway::timeout(const CommTimeoutCbParams &io)
{
if (SENT_PASV == state) {
/* stupid ftp.netscape.com, of FTP server behind stupid firewall rules */
data.close();
}
- Ftp::ServerStateData::timeout(io);
+ Ftp::Client::timeout(io);
}
/// \ingroup ServerProtocolFTPInternal
/// \ingroup ServerProtocolFTPInternal
static ftpListParts *
-ftpListParseParts(const char *buf, struct _ftp_flags flags)
+ftpListParseParts(const char *buf, struct Ftp::GatewayFlags flags)
{
ftpListParts *p = NULL;
char *t = NULL;
}
MemBuf *
-FtpStateData::htmlifyListEntry(const char *line)
+Ftp::Gateway::htmlifyListEntry(const char *line)
{
char icon[2048];
char href[2048 + 40];
}
void
-FtpStateData::parseListing()
+Ftp::Gateway::parseListing()
{
char *buf = data.readBuf->content();
char *sbuf; /* NULL-terminated copy of termedBuf */
}
void
-FtpStateData::processReplyBody()
+Ftp::Gateway::processReplyBody()
{
- debugs(9, 3, HERE << "FtpStateData::processReplyBody starting.");
+ debugs(9, 3, HERE << "Ftp::Gateway::processReplyBody starting.");
if (request->method == Http::METHOD_HEAD && (flags.isdir || theSize != -1)) {
serverComplete();
#if USE_ADAPTATION
if (adaptationAccessCheckPending) {
- debugs(9,3, HERE << "returning from FtpStateData::processReplyBody due to adaptationAccessCheckPending");
+ debugs(9,3, HERE << "returning from Ftp::Gateway::processReplyBody due to adaptationAccessCheckPending");
return;
}
\retval 0 if something is missing.
*/
int
-FtpStateData::checkAuth(const HttpHeader * req_hdr)
+Ftp::Gateway::checkAuth(const HttpHeader * req_hdr)
{
/* default username */
xstrncpy(user, "anonymous", MAX_URL);
static String str_type_eq;
void
-FtpStateData::checkUrlpath()
+Ftp::Gateway::checkUrlpath()
{
int l;
size_t t;
}
void
-FtpStateData::buildTitleUrl()
+Ftp::Gateway::buildTitleUrl()
{
title_url = "ftp://";
base_href.append("/");
}
-/// \ingroup ServerProtocolFTPAPI
void
-ftpStart(FwdState * fwd)
-{
- AsyncJob::Start(new FtpStateData(fwd));
-}
-
-void
-FtpStateData::start()
+Ftp::Gateway::start()
{
if (!checkAuth(&request->header)) {
/* create appropriate reply */
state = BEGIN;
- Ftp::ServerStateData::start();
+ Ftp::Client::start();
}
/* ====================================================================== */
void
-FtpStateData::handleControlReply()
+Ftp::Gateway::handleControlReply()
{
- Ftp::ServerStateData::handleControlReply();
+ Ftp::Client::handleControlReply();
if (ctrl.message == NULL)
return; // didn't get complete reply yet
/// \ingroup ServerProtocolFTPInternal
static void
-ftpReadWelcome(FtpStateData * ftpState)
+ftpReadWelcome(Ftp::Gateway * ftpState)
{
int code = ftpState->ctrl.replycode;
debugs(9, 3, HERE);
* its NOT a general failure. But a correct FTP response type.
*/
void
-FtpStateData::loginFailed()
+Ftp::Gateway::loginFailed()
{
ErrorState *err = NULL;
const char *command, *reply;
}
const char *
-FtpStateData::ftpRealm()
+Ftp::Gateway::ftpRealm()
{
static char realm[8192];
/// \ingroup ServerProtocolFTPInternal
static void
-ftpSendUser(FtpStateData * ftpState)
+ftpSendUser(Ftp::Gateway * ftpState)
{
/* check the server control channel is still available */
if (!ftpState || !ftpState->haveControlChannel("ftpSendUser"))
ftpState->writeCommand(cbuf);
- ftpState->state = Ftp::ServerStateData::SENT_USER;
+ ftpState->state = Ftp::Client::SENT_USER;
}
/// \ingroup ServerProtocolFTPInternal
static void
-ftpReadUser(FtpStateData * ftpState)
+ftpReadUser(Ftp::Gateway * ftpState)
{
int code = ftpState->ctrl.replycode;
debugs(9, 3, HERE);
/// \ingroup ServerProtocolFTPInternal
static void
-ftpSendPass(FtpStateData * ftpState)
+ftpSendPass(Ftp::Gateway * ftpState)
{
/* check the server control channel is still available */
if (!ftpState || !ftpState->haveControlChannel("ftpSendPass"))
snprintf(cbuf, CTRL_BUFLEN, "PASS %s\r\n", ftpState->password);
ftpState->writeCommand(cbuf);
- ftpState->state = Ftp::ServerStateData::SENT_PASS;
+ ftpState->state = Ftp::Client::SENT_PASS;
}
/// \ingroup ServerProtocolFTPInternal
static void
-ftpReadPass(FtpStateData * ftpState)
+ftpReadPass(Ftp::Gateway * ftpState)
{
int code = ftpState->ctrl.replycode;
debugs(9, 3, HERE << "code=" << code);
/// \ingroup ServerProtocolFTPInternal
static void
-ftpSendType(FtpStateData * ftpState)
+ftpSendType(Ftp::Gateway * ftpState)
{
const char *t;
const char *filename;
ftpState->writeCommand(cbuf);
- ftpState->state = Ftp::ServerStateData::SENT_TYPE;
+ ftpState->state = Ftp::Client::SENT_TYPE;
}
/// \ingroup ServerProtocolFTPInternal
static void
-ftpReadType(FtpStateData * ftpState)
+ftpReadType(Ftp::Gateway * ftpState)
{
int code = ftpState->ctrl.replycode;
char *path;
/// \ingroup ServerProtocolFTPInternal
static void
-ftpTraverseDirectory(FtpStateData * ftpState)
+ftpTraverseDirectory(Ftp::Gateway * ftpState)
{
wordlist *w;
debugs(9, 4, HERE << (ftpState->filepath ? ftpState->filepath : "<NULL>"));
/// \ingroup ServerProtocolFTPInternal
static void
-ftpSendCwd(FtpStateData * ftpState)
+ftpSendCwd(Ftp::Gateway * ftpState)
{
char *path = NULL;
ftpState->writeCommand(cbuf);
- ftpState->state = Ftp::ServerStateData::SENT_CWD;
+ ftpState->state = Ftp::Client::SENT_CWD;
}
/// \ingroup ServerProtocolFTPInternal
static void
-ftpReadCwd(FtpStateData * ftpState)
+ftpReadCwd(Ftp::Gateway * ftpState)
{
int code = ftpState->ctrl.replycode;
debugs(9, 3, HERE);
/// \ingroup ServerProtocolFTPInternal
static void
-ftpSendMkdir(FtpStateData * ftpState)
+ftpSendMkdir(Ftp::Gateway * ftpState)
{
char *path = NULL;
debugs(9, 3, HERE << "with path=" << path);
snprintf(cbuf, CTRL_BUFLEN, "MKD %s\r\n", path);
ftpState->writeCommand(cbuf);
- ftpState->state = Ftp::ServerStateData::SENT_MKDIR;
+ ftpState->state = Ftp::Client::SENT_MKDIR;
}
/// \ingroup ServerProtocolFTPInternal
static void
-ftpReadMkdir(FtpStateData * ftpState)
+ftpReadMkdir(Ftp::Gateway * ftpState)
{
char *path = ftpState->filepath;
int code = ftpState->ctrl.replycode;
/// \ingroup ServerProtocolFTPInternal
static void
-ftpGetFile(FtpStateData * ftpState)
+ftpGetFile(Ftp::Gateway * ftpState)
{
assert(*ftpState->filepath != '\0');
ftpState->flags.isdir = 0;
/// \ingroup ServerProtocolFTPInternal
static void
-ftpListDir(FtpStateData * ftpState)
+ftpListDir(Ftp::Gateway * ftpState)
{
if (ftpState->flags.dir_slash) {
debugs(9, 3, HERE << "Directory path did not end in /");
/// \ingroup ServerProtocolFTPInternal
static void
-ftpSendMdtm(FtpStateData * ftpState)
+ftpSendMdtm(Ftp::Gateway * ftpState)
{
/* check the server control channel is still available */
if (!ftpState || !ftpState->haveControlChannel("ftpSendMdtm"))
assert(*ftpState->filepath != '\0');
snprintf(cbuf, CTRL_BUFLEN, "MDTM %s\r\n", ftpState->filepath);
ftpState->writeCommand(cbuf);
- ftpState->state = Ftp::ServerStateData::SENT_MDTM;
+ ftpState->state = Ftp::Client::SENT_MDTM;
}
/// \ingroup ServerProtocolFTPInternal
static void
-ftpReadMdtm(FtpStateData * ftpState)
+ftpReadMdtm(Ftp::Gateway * ftpState)
{
int code = ftpState->ctrl.replycode;
debugs(9, 3, HERE);
/// \ingroup ServerProtocolFTPInternal
static void
-ftpSendSize(FtpStateData * ftpState)
+ftpSendSize(Ftp::Gateway * ftpState)
{
/* check the server control channel is still available */
if (!ftpState || !ftpState->haveControlChannel("ftpSendSize"))
assert(*ftpState->filepath != '\0');
snprintf(cbuf, CTRL_BUFLEN, "SIZE %s\r\n", ftpState->filepath);
ftpState->writeCommand(cbuf);
- ftpState->state = Ftp::ServerStateData::SENT_SIZE;
+ ftpState->state = Ftp::Client::SENT_SIZE;
} else
/* Skip to next state no non-binary transfers */
ftpSendPassive(ftpState);
/// \ingroup ServerProtocolFTPInternal
static void
-ftpReadSize(FtpStateData * ftpState)
+ftpReadSize(Ftp::Gateway * ftpState)
{
int code = ftpState->ctrl.replycode;
debugs(9, 3, HERE);
\ingroup ServerProtocolFTPInternal
*/
static void
-ftpReadEPSV(FtpStateData* ftpState)
+ftpReadEPSV(Ftp::Gateway* ftpState)
{
Ip::Address srvAddr; // unused
if (ftpState->handleEpsvReply(srvAddr)) {
* The failover mechanism should check for previous state and re-call with alternates on failure.
*/
static void
-ftpSendPassive(FtpStateData * ftpState)
+ftpSendPassive(Ftp::Gateway * ftpState)
{
/** Checks the server control channel is still available before running. */
if (!ftpState || !ftpState->haveControlChannel("ftpSendPassive"))
debugs(9, 3, HERE);
/** \par
- * Checks for 'HEAD' method request and passes off for special handling by FtpStateData::processHeadResponse(). */
+ * Checks for 'HEAD' method request and passes off for special handling by Ftp::Gateway::processHeadResponse(). */
if (ftpState->request->method == Http::METHOD_HEAD && (ftpState->flags.isdir || ftpState->theSize != -1)) {
ftpState->processHeadResponse(); // may call serverComplete
return;
if (ftpState->sendPassive()) {
// SENT_EPSV_ALL blocks other non-EPSV connections being attempted
- if (ftpState->state == Ftp::ServerStateData::SENT_EPSV_ALL)
+ if (ftpState->state == Ftp::Client::SENT_EPSV_ALL)
ftpState->flags.epsv_all_sent = true;
}
}
void
-FtpStateData::processHeadResponse()
+Ftp::Gateway::processHeadResponse()
{
debugs(9, 5, HERE << "handling HEAD response");
ftpSendQuit(this);
/// \ingroup ServerProtocolFTPInternal
static void
-ftpReadPasv(FtpStateData * ftpState)
+ftpReadPasv(Ftp::Gateway * ftpState)
{
Ip::Address srvAddr; // unused
if (ftpState->handlePasvReply(srvAddr))
}
void
-FtpStateData::dataChannelConnected(const Comm::ConnectionPointer &conn, Comm::Flag err, int xerrno)
+Ftp::Gateway::dataChannelConnected(const Comm::ConnectionPointer &conn, Comm::Flag err, int xerrno)
{
debugs(9, 3, HERE);
data.opener = NULL;
/// \ingroup ServerProtocolFTPInternal
static void
-ftpOpenListenSocket(FtpStateData * ftpState, int fallback)
+ftpOpenListenSocket(Ftp::Gateway * ftpState, int fallback)
{
/// Close old data channels, if any. We may open a new one below.
if (ftpState->data.conn != NULL) {
/// \ingroup ServerProtocolFTPInternal
static void
-ftpSendPORT(FtpStateData * ftpState)
+ftpSendPORT(Ftp::Gateway * ftpState)
{
/* check the server control channel is still available */
if (!ftpState || !ftpState->haveControlChannel("ftpSendPort"))
addrptr[0], addrptr[1], addrptr[2], addrptr[3],
portptr[0], portptr[1]);
ftpState->writeCommand(cbuf);
- ftpState->state = Ftp::ServerStateData::SENT_PORT;
+ ftpState->state = Ftp::Client::SENT_PORT;
Ip::Address::FreeAddrInfo(AI);
}
/// \ingroup ServerProtocolFTPInternal
static void
-ftpReadPORT(FtpStateData * ftpState)
+ftpReadPORT(Ftp::Gateway * ftpState)
{
int code = ftpState->ctrl.replycode;
debugs(9, 3, HERE);
/// \ingroup ServerProtocolFTPInternal
static void
-ftpSendEPRT(FtpStateData * ftpState)
+ftpSendEPRT(Ftp::Gateway * ftpState)
{
if (Config.Ftp.epsv_all && ftpState->flags.epsv_all_sent) {
debugs(9, DBG_IMPORTANT, "FTP does not allow EPRT method after 'EPSV ALL' has been sent.");
ftpState->data.listenConn->local.port() );
ftpState->writeCommand(cbuf);
- ftpState->state = Ftp::ServerStateData::SENT_EPRT;
+ ftpState->state = Ftp::Client::SENT_EPRT;
}
static void
-ftpReadEPRT(FtpStateData * ftpState)
+ftpReadEPRT(Ftp::Gateway * ftpState)
{
int code = ftpState->ctrl.replycode;
debugs(9, 3, HERE);
\param io comm accept(2) callback parameters
*/
void
-FtpStateData::ftpAcceptDataConnection(const CommAcceptCbParams &io)
+Ftp::Gateway::ftpAcceptDataConnection(const CommAcceptCbParams &io)
{
debugs(9, 3, HERE);
/// \ingroup ServerProtocolFTPInternal
static void
-ftpRestOrList(FtpStateData * ftpState)
+ftpRestOrList(Ftp::Gateway * ftpState)
{
debugs(9, 3, HERE);
/// \ingroup ServerProtocolFTPInternal
static void
-ftpSendStor(FtpStateData * ftpState)
+ftpSendStor(Ftp::Gateway * ftpState)
{
/* check the server control channel is still available */
if (!ftpState || !ftpState->haveControlChannel("ftpSendStor"))
/* Plain file upload */
snprintf(cbuf, CTRL_BUFLEN, "STOR %s\r\n", ftpState->filepath);
ftpState->writeCommand(cbuf);
- ftpState->state = Ftp::ServerStateData::SENT_STOR;
+ ftpState->state = Ftp::Client::SENT_STOR;
} else if (ftpState->request->header.getInt64(HDR_CONTENT_LENGTH) > 0) {
/* File upload without a filename. use STOU to generate one */
snprintf(cbuf, CTRL_BUFLEN, "STOU\r\n");
ftpState->writeCommand(cbuf);
- ftpState->state = Ftp::ServerStateData::SENT_STOR;
+ ftpState->state = Ftp::Client::SENT_STOR;
} else {
/* No file to transfer. Only create directories if needed */
ftpSendReply(ftpState);
/// \ingroup ServerProtocolFTPInternal
/// \deprecated use ftpState->readStor() instead.
static void
-ftpReadStor(FtpStateData * ftpState)
+ftpReadStor(Ftp::Gateway * ftpState)
{
ftpState->readStor();
}
-void FtpStateData::readStor()
+void Ftp::Gateway::readStor()
{
int code = ctrl.replycode;
debugs(9, 3, HERE);
/// \ingroup ServerProtocolFTPInternal
static void
-ftpSendRest(FtpStateData * ftpState)
+ftpSendRest(Ftp::Gateway * ftpState)
{
/* check the server control channel is still available */
if (!ftpState || !ftpState->haveControlChannel("ftpSendRest"))
snprintf(cbuf, CTRL_BUFLEN, "REST %" PRId64 "\r\n", ftpState->restart_offset);
ftpState->writeCommand(cbuf);
- ftpState->state = Ftp::ServerStateData::SENT_REST;
+ ftpState->state = Ftp::Client::SENT_REST;
}
int
-FtpStateData::restartable()
+Ftp::Gateway::restartable()
{
if (restart_offset > 0)
return 1;
/// \ingroup ServerProtocolFTPInternal
static void
-ftpReadRest(FtpStateData * ftpState)
+ftpReadRest(Ftp::Gateway * ftpState)
{
int code = ftpState->ctrl.replycode;
debugs(9, 3, HERE);
/// \ingroup ServerProtocolFTPInternal
static void
-ftpSendList(FtpStateData * ftpState)
+ftpSendList(Ftp::Gateway * ftpState)
{
/* check the server control channel is still available */
if (!ftpState || !ftpState->haveControlChannel("ftpSendList"))
}
ftpState->writeCommand(cbuf);
- ftpState->state = Ftp::ServerStateData::SENT_LIST;
+ ftpState->state = Ftp::Client::SENT_LIST;
}
/// \ingroup ServerProtocolFTPInternal
static void
-ftpSendNlst(FtpStateData * ftpState)
+ftpSendNlst(Ftp::Gateway * ftpState)
{
/* check the server control channel is still available */
if (!ftpState || !ftpState->haveControlChannel("ftpSendNlst"))
}
ftpState->writeCommand(cbuf);
- ftpState->state = Ftp::ServerStateData::SENT_NLST;
+ ftpState->state = Ftp::Client::SENT_NLST;
}
/// \ingroup ServerProtocolFTPInternal
static void
-ftpReadList(FtpStateData * ftpState)
+ftpReadList(Ftp::Gateway * ftpState)
{
int code = ftpState->ctrl.replycode;
debugs(9, 3, HERE);
debugs(9, 3, HERE << "begin data transfer from " << ftpState->data.conn->remote << " (" << ftpState->data.conn->local << ")");
ftpState->switchTimeoutToDataChannel();
ftpState->maybeReadVirginBody();
- ftpState->state = Ftp::ServerStateData::READING_DATA;
+ ftpState->state = Ftp::Client::READING_DATA;
return;
} else if (code == 150) {
/* Accept data channel */
/// \ingroup ServerProtocolFTPInternal
static void
-ftpSendRetr(FtpStateData * ftpState)
+ftpSendRetr(Ftp::Gateway * ftpState)
{
/* check the server control channel is still available */
if (!ftpState || !ftpState->haveControlChannel("ftpSendRetr"))
assert(ftpState->filepath != NULL);
snprintf(cbuf, CTRL_BUFLEN, "RETR %s\r\n", ftpState->filepath);
ftpState->writeCommand(cbuf);
- ftpState->state = Ftp::ServerStateData::SENT_RETR;
+ ftpState->state = Ftp::Client::SENT_RETR;
}
/// \ingroup ServerProtocolFTPInternal
static void
-ftpReadRetr(FtpStateData * ftpState)
+ftpReadRetr(Ftp::Gateway * ftpState)
{
int code = ftpState->ctrl.replycode;
debugs(9, 3, HERE);
debugs(9, 3, HERE << "begin data transfer from " << ftpState->data.conn->remote << " (" << ftpState->data.conn->local << ")");
ftpState->switchTimeoutToDataChannel();
ftpState->maybeReadVirginBody();
- ftpState->state = Ftp::ServerStateData::READING_DATA;
+ ftpState->state = Ftp::Client::READING_DATA;
} else if (code == 150) {
/* Accept data channel */
ftpState->listenForDataChannel(ftpState->data.conn);
* directory listing display.
*/
void
-FtpStateData::completedListing()
+Ftp::Gateway::completedListing()
{
assert(entry);
- entry->lock("FtpStateData");
+ entry->lock("Ftp::Gateway");
ErrorState ferr(ERR_DIR_LISTING, Http::scOkay, request);
ferr.ftp.listing = &listing;
ferr.ftp.cwd_msg = xstrdup(cwd_message.size()? cwd_message.termedBuf() : "");
entry->replaceHttpReply( ferr.BuildHttpReply() );
EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
entry->flush();
- entry->unlock("FtpStateData");
+ entry->unlock("Ftp::Gateway");
}
/// \ingroup ServerProtocolFTPInternal
static void
-ftpReadTransferDone(FtpStateData * ftpState)
+ftpReadTransferDone(Ftp::Gateway * ftpState)
{
int code = ftpState->ctrl.replycode;
debugs(9, 3, HERE);
// premature end of the request body
void
-FtpStateData::handleRequestBodyProducerAborted()
+Ftp::Gateway::handleRequestBodyProducerAborted()
{
ServerStateData::handleRequestBodyProducerAborted();
debugs(9, 3, HERE << "ftpState=" << this);
/// \ingroup ServerProtocolFTPInternal
static void
-ftpWriteTransferDone(FtpStateData * ftpState)
+ftpWriteTransferDone(Ftp::Gateway * ftpState)
{
int code = ftpState->ctrl.replycode;
debugs(9, 3, HERE);
/// \ingroup ServerProtocolFTPInternal
static void
-ftpSendQuit(FtpStateData * ftpState)
+ftpSendQuit(Ftp::Gateway * ftpState)
{
/* check the server control channel is still available */
if (!ftpState || !ftpState->haveControlChannel("ftpSendQuit"))
snprintf(cbuf, CTRL_BUFLEN, "QUIT\r\n");
ftpState->writeCommand(cbuf);
- ftpState->state = Ftp::ServerStateData::SENT_QUIT;
+ ftpState->state = Ftp::Client::SENT_QUIT;
}
/**
* generated and stored in the entry field by the code issuing QUIT.
*/
static void
-ftpReadQuit(FtpStateData * ftpState)
+ftpReadQuit(Ftp::Gateway * ftpState)
{
ftpState->serverComplete();
}
/// \ingroup ServerProtocolFTPInternal
static void
-ftpTrySlashHack(FtpStateData * ftpState)
+ftpTrySlashHack(Ftp::Gateway * ftpState)
{
char *path;
ftpState->flags.try_slash_hack = 1;
* Forget hack status. Next error is shown to the user
*/
void
-FtpStateData::unhack()
+Ftp::Gateway::unhack()
{
debugs(9, 3, HERE);
}
void
-FtpStateData::hackShortcut(FTPSM * nextState)
+Ftp::Gateway::hackShortcut(FTPSM * nextState)
{
/* Clear some unwanted state */
setCurrentOffset(0);
/// \ingroup ServerProtocolFTPInternal
static void
-ftpFail(FtpStateData *ftpState)
+ftpFail(Ftp::Gateway *ftpState)
{
debugs(9, 6, HERE << "flags(" <<
(ftpState->flags.isdir?"IS_DIR,":"") <<
switch (ftpState->state) {
- case Ftp::ServerStateData::SENT_CWD:
+ case Ftp::Client::SENT_CWD:
- case Ftp::ServerStateData::SENT_RETR:
+ case Ftp::Client::SENT_RETR:
/* Try the / hack */
ftpState->hackShortcut(ftpTrySlashHack);
return;
}
Http::StatusCode
-FtpStateData::failedHttpStatus(err_type &error)
+Ftp::Gateway::failedHttpStatus(err_type &error)
{
if (error == ERR_NONE) {
switch (state) {
break;
}
}
- return Ftp::ServerStateData::failedHttpStatus(error);
+ return Ftp::Client::failedHttpStatus(error);
}
/// \ingroup ServerProtocolFTPInternal
static void
-ftpSendReply(FtpStateData * ftpState)
+ftpSendReply(Ftp::Gateway * ftpState)
{
int code = ftpState->ctrl.replycode;
Http::StatusCode http_code;
}
void
-FtpStateData::appendSuccessHeader()
+Ftp::Gateway::appendSuccessHeader()
{
const char *mime_type = NULL;
const char *mime_enc = NULL;
}
void
-FtpStateData::haveParsedReplyHeaders()
+Ftp::Gateway::haveParsedReplyHeaders()
{
ServerStateData::haveParsedReplyHeaders();
}
HttpReply *
-FtpStateData::ftpAuthRequired(HttpRequest * request, const char *realm)
+Ftp::Gateway::ftpAuthRequired(HttpRequest * request, const char *realm)
{
ErrorState err(ERR_CACHE_ACCESS_DENIED, Http::scUnauthorized, request);
HttpReply *newrep = err.BuildHttpReply();
* ftp:host:port/%2froot/path AKA 'the FTP %2f hack'.
*/
const char *
-ftpUrlWith2f(HttpRequest * request)
+Ftp::UrlWith2f(HttpRequest * request)
{
String newbuf = "%2f";
}
void
-FtpStateData::printfReplyBody(const char *fmt, ...)
+Ftp::Gateway::printfReplyBody(const char *fmt, ...)
{
va_list args;
va_start (args, fmt);
* which should be sent to either StoreEntry, or to ICAP...
*/
void
-FtpStateData::writeReplyBody(const char *dataToWrite, size_t dataLength)
+Ftp::Gateway::writeReplyBody(const char *dataToWrite, size_t dataLength)
{
debugs(9, 5, HERE << "writing " << dataLength << " bytes to the reply");
addVirginReplyBody(dataToWrite, dataLength);
/**
* A hack to ensure we do not double-complete on the forward entry.
*
- \todo FtpStateData logic should probably be rewritten to avoid
+ \todo Ftp::Gateway logic should probably be rewritten to avoid
* double-completion or FwdState should be rewritten to allow it.
*/
void
-FtpStateData::completeForwarding()
+Ftp::Gateway::completeForwarding()
{
if (fwd == NULL || flags.completed_forwarding) {
debugs(9, 3, HERE << "completeForwarding avoids " <<
\retval false The server control channel is not available.
*/
bool
-FtpStateData::haveControlChannel(const char *caller_name) const
+Ftp::Gateway::haveControlChannel(const char *caller_name) const
{
if (doneWithServer())
return false;
return true;
}
+
+AsyncJob::Pointer
+Ftp::StartGateway(FwdState *const fwdState)
+{
+ return AsyncJob::Start(new Ftp::Gateway(fwdState));
+}
#include "anyp/PortCfg.h"
#include "client_side.h"
+#include "clients/forward.h"
#include "clients/FtpClient.h"
#include "ftp/Parsing.h"
#include "HttpHdrCc.h"
namespace Ftp {
-namespace Gateway {
-
-class ServerStateData: public Ftp::ServerStateData
+/// An FTP client receiving native FTP commands from our FTP server
+/// (Ftp::Server), forwarding them to the next FTP hop,
+/// and then relaying FTP replies back to our FTP server.
+class Relay: public Ftp::Client
{
public:
- ServerStateData(FwdState *const fwdState);
- ~ServerStateData();
-
- virtual void processReplyBody();
+ explicit Relay(FwdState *const fwdState);
+ virtual ~Relay();
protected:
- virtual void start();
-
const Ftp::MasterState &master() const;
Ftp::MasterState &updateMaster();
Ftp::ServerState clientState() const;
void clientState(Ftp::ServerState newState);
- virtual void serverComplete();
+ /* Ftp::Client API */
virtual void failed(err_type error = ERR_NONE, int xerrno = 0);
+
+ /* ServerStateData API */
+ virtual void serverComplete();
virtual void handleControlReply();
+ virtual void processReplyBody();
virtual void handleRequestBodyProducerAborted();
virtual bool mayReadVirginReplyBody() const;
virtual void completeForwarding();
+
+ /* AsyncJob API */
+ virtual void start();
+
void forwardReply();
void forwardError(err_type error = ERR_NONE, int xerrno = 0);
void failedErrorMessage(err_type error, int xerrno);
void stopDirTracking();
bool weAreTrackingDir() const {return savedReply.message != NULL;}
- typedef void (ServerStateData::*PreliminaryCb)();
+ typedef void (Relay::*PreliminaryCb)();
void forwardPreliminaryReply(const PreliminaryCb cb);
void proceedAfterPreliminaryReply();
PreliminaryCb thePreliminaryCb;
- typedef void (ServerStateData::*SM_FUNC)();
+ typedef void (Relay::*SM_FUNC)();
static const SM_FUNC SM_FUNCS[];
void readGreeting();
void sendCommand();
int replyCode; ///< the reply status
} savedReply; ///< set and delayed while we are tracking using PWD
- CBDATA_CLASS2(ServerStateData);
+ CBDATA_CLASS2(Relay);
};
-CBDATA_CLASS_INIT(ServerStateData);
+} // namespace Ftp
-const ServerStateData::SM_FUNC ServerStateData::SM_FUNCS[] = {
- &ServerStateData::readGreeting, // BEGIN
- &ServerStateData::readUserOrPassReply, // SENT_USER
- &ServerStateData::readUserOrPassReply, // SENT_PASS
- NULL,/*&ServerStateData::readReply*/ // SENT_TYPE
- NULL,/*&ServerStateData::readReply*/ // SENT_MDTM
- NULL,/*&ServerStateData::readReply*/ // SENT_SIZE
+CBDATA_NAMESPACED_CLASS_INIT(Ftp, Relay);
+
+const Ftp::Relay::SM_FUNC Ftp::Relay::SM_FUNCS[] = {
+ &Ftp::Relay::readGreeting, // BEGIN
+ &Ftp::Relay::readUserOrPassReply, // SENT_USER
+ &Ftp::Relay::readUserOrPassReply, // SENT_PASS
+ NULL,/*&Ftp::Relay::readReply*/ // SENT_TYPE
+ NULL,/*&Ftp::Relay::readReply*/ // SENT_MDTM
+ NULL,/*&Ftp::Relay::readReply*/ // SENT_SIZE
NULL, // SENT_EPRT
NULL, // SENT_PORT
- &ServerStateData::readEpsvReply, // SENT_EPSV_ALL
- &ServerStateData::readEpsvReply, // SENT_EPSV_1
- &ServerStateData::readEpsvReply, // SENT_EPSV_2
- &ServerStateData::readPasvReply, // SENT_PASV
- &ServerStateData::readCwdOrCdupReply, // SENT_CWD
- NULL,/*&ServerStateData::readDataReply,*/ // SENT_LIST
- NULL,/*&ServerStateData::readDataReply,*/ // SENT_NLST
- NULL,/*&ServerStateData::readReply*/ // SENT_REST
- NULL,/*&ServerStateData::readDataReply*/ // SENT_RETR
- NULL,/*&ServerStateData::readReply*/ // SENT_STOR
- NULL,/*&ServerStateData::readReply*/ // SENT_QUIT
- &ServerStateData::readTransferDoneReply, // READING_DATA
- &ServerStateData::readReply, // WRITING_DATA
- NULL,/*&ServerStateData::readReply*/ // SENT_MKDIR
- &ServerStateData::readFeatReply, // SENT_FEAT
- NULL,/*&ServerStateData::readPwdReply*/ // SENT_PWD
- &ServerStateData::readCwdOrCdupReply, // SENT_CDUP
- &ServerStateData::readDataReply,// SENT_DATA_REQUEST
- &ServerStateData::readReply, // SENT_COMMAND
+ &Ftp::Relay::readEpsvReply, // SENT_EPSV_ALL
+ &Ftp::Relay::readEpsvReply, // SENT_EPSV_1
+ &Ftp::Relay::readEpsvReply, // SENT_EPSV_2
+ &Ftp::Relay::readPasvReply, // SENT_PASV
+ &Ftp::Relay::readCwdOrCdupReply, // SENT_CWD
+ NULL,/*&Ftp::Relay::readDataReply,*/ // SENT_LIST
+ NULL,/*&Ftp::Relay::readDataReply,*/ // SENT_NLST
+ NULL,/*&Ftp::Relay::readReply*/ // SENT_REST
+ NULL,/*&Ftp::Relay::readDataReply*/ // SENT_RETR
+ NULL,/*&Ftp::Relay::readReply*/ // SENT_STOR
+ NULL,/*&Ftp::Relay::readReply*/ // SENT_QUIT
+ &Ftp::Relay::readTransferDoneReply, // READING_DATA
+ &Ftp::Relay::readReply, // WRITING_DATA
+ NULL,/*&Ftp::Relay::readReply*/ // SENT_MKDIR
+ &Ftp::Relay::readFeatReply, // SENT_FEAT
+ NULL,/*&Ftp::Relay::readPwdReply*/ // SENT_PWD
+ &Ftp::Relay::readCwdOrCdupReply, // SENT_CDUP
+ &Ftp::Relay::readDataReply,// SENT_DATA_REQUEST
+ &Ftp::Relay::readReply, // SENT_COMMAND
NULL
};
-ServerStateData::ServerStateData(FwdState *const fwdState):
- AsyncJob("Ftp::Gateway::ServerStateData"), Ftp::ServerStateData(fwdState),
- forwardingCompleted(false)
+Ftp::Relay::Relay(FwdState *const fwdState):
+ AsyncJob("Ftp::Relay"),
+ Ftp::Client(fwdState),
+ forwardingCompleted(false)
{
savedReply.message = NULL;
savedReply.lastCommand = NULL;
entry->releaseRequest();
}
-ServerStateData::~ServerStateData()
+Ftp::Relay::~Relay()
{
closeServer(); // TODO: move to Server.cc?
if (savedReply.message)
}
void
-ServerStateData::start()
+Ftp::Relay::start()
{
if (!master().clientReadGreeting)
- Ftp::ServerStateData::start();
+ Ftp::Client::start();
else
if (clientState() == fssHandleDataRequest ||
clientState() == fssHandleUploadRequest)
/// Keep control connection for future requests, after we are done with it.
/// Similar to COMPLETE_PERSISTENT_MSG handling in http.cc.
void
-ServerStateData::serverComplete()
+Ftp::Relay::serverComplete()
{
CbcPointer<ConnStateData> &mgr = fwd->request->clientConnectionManager;
if (mgr.valid()) {
}
}
}
- Ftp::ServerStateData::serverComplete();
+ Ftp::Client::serverComplete();
}
Ftp::MasterState &
-ServerStateData::updateMaster()
+Ftp::Relay::updateMaster()
{
CbcPointer<ConnStateData> &mgr = fwd->request->clientConnectionManager;
if (mgr.valid()) {
}
const Ftp::MasterState &
-ServerStateData::master() const
+Ftp::Relay::master() const
{
- return const_cast<Ftp::Gateway::ServerStateData*>(this)->updateMaster();
+ return const_cast<Ftp::Relay*>(this)->updateMaster();
}
Ftp::ServerState
-ServerStateData::clientState() const
+Ftp::Relay::clientState() const
{
return master().serverState;
}
void
-ServerStateData::clientState(Ftp::ServerState newState)
+Ftp::Relay::clientState(Ftp::ServerState newState)
{
// XXX: s/client/server/g
Ftp::ServerState &cltState = updateMaster().serverState;
\todo Rewrite FwdState to ignore double completion?
*/
void
-ServerStateData::completeForwarding()
+Ftp::Relay::completeForwarding()
{
debugs(9, 5, forwardingCompleted);
if (forwardingCompleted)
return;
forwardingCompleted = true;
- Ftp::ServerStateData::completeForwarding();
+ Ftp::Client::completeForwarding();
}
void
-ServerStateData::failed(err_type error, int xerrno)
+Ftp::Relay::failed(err_type error, int xerrno)
{
if (!doneWithServer())
clientState(fssError);
if (entry->isEmpty())
failedErrorMessage(error, xerrno); // as a reply
- Ftp::ServerStateData::failed(error, xerrno);
+ Ftp::Client::failed(error, xerrno);
}
void
-ServerStateData::failedErrorMessage(err_type error, int xerrno)
+Ftp::Relay::failedErrorMessage(err_type error, int xerrno)
{
const Http::StatusCode httpStatus = failedHttpStatus(error);
HttpReply *const reply = createHttpReply(httpStatus);
}
void
-ServerStateData::processReplyBody()
+Ftp::Relay::processReplyBody()
{
debugs(9, 3, HERE << "starting");
}
void
-ServerStateData::handleControlReply()
+Ftp::Relay::handleControlReply()
{
if (!request->clientConnectionManager.valid()) {
debugs(9, 5, "client connection gone");
return;
}
- Ftp::ServerStateData::handleControlReply();
+ Ftp::Client::handleControlReply();
if (ctrl.message == NULL)
return; // didn't get complete reply yet
}
void
-ServerStateData::handleRequestBodyProducerAborted()
+Ftp::Relay::handleRequestBodyProducerAborted()
{
::ServerStateData::handleRequestBodyProducerAborted();
}
bool
-ServerStateData::mayReadVirginReplyBody() const
+Ftp::Relay::mayReadVirginReplyBody() const
{
// TODO: move this method to the regular FTP server?
return Comm::IsConnOpen(data.conn);
}
void
-ServerStateData::forwardReply()
+Ftp::Relay::forwardReply()
{
assert(entry->isEmpty());
EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
}
void
-ServerStateData::forwardPreliminaryReply(const PreliminaryCb cb)
+Ftp::Relay::forwardPreliminaryReply(const PreliminaryCb cb)
{
debugs(9, 5, HERE << "Forwarding preliminary reply to client");
const HttpReply::Pointer reply = createHttpReply(Http::scContinue);
// the Sink will use this to call us back after writing 1xx to the client
- typedef NullaryMemFunT<ServerStateData> CbDialer;
+ typedef NullaryMemFunT<Relay> CbDialer;
const AsyncCall::Pointer call = JobCallback(11, 3, CbDialer, this,
- ServerStateData::proceedAfterPreliminaryReply);
+ Ftp::Relay::proceedAfterPreliminaryReply);
CallJobHere1(9, 4, request->clientConnectionManager, ConnStateData,
ConnStateData::sendControlMsg, HttpControlMsg(reply, call));
}
void
-ServerStateData::proceedAfterPreliminaryReply()
+Ftp::Relay::proceedAfterPreliminaryReply()
{
debugs(9, 5, HERE << "Proceeding after preliminary reply to client");
}
void
-ServerStateData::forwardError(err_type error, int xerrno)
+Ftp::Relay::forwardError(err_type error, int xerrno)
{
failed(error, xerrno);
}
HttpReply *
-ServerStateData::createHttpReply(const Http::StatusCode httpStatus, const int clen)
+Ftp::Relay::createHttpReply(const Http::StatusCode httpStatus, const int clen)
{
HttpReply *const reply = new HttpReply;
reply->sline.set(Http::ProtocolVersion(1, 1), httpStatus);
}
void
-ServerStateData::handleDataRequest()
+Ftp::Relay::handleDataRequest()
{
data.addr(master().clientDataAddr);
connectDataChannel();
}
void
-ServerStateData::startDataDownload()
+Ftp::Relay::startDataDownload()
{
assert(Comm::IsConnOpen(data.conn));
}
void
-ServerStateData::startDataUpload()
+Ftp::Relay::startDataUpload()
{
assert(Comm::IsConnOpen(data.conn));
}
void
-ServerStateData::readGreeting()
+Ftp::Relay::readGreeting()
{
assert(!master().clientReadGreeting);
case 120:
if (NULL != ctrl.message)
debugs(9, DBG_IMPORTANT, "FTP server is busy: " << ctrl.message->key);
- forwardPreliminaryReply(&ServerStateData::scheduleReadControlReply);
+ forwardPreliminaryReply(&Ftp::Relay::scheduleReadControlReply);
break;
default:
failed();
}
void
-ServerStateData::sendCommand()
+Ftp::Relay::sendCommand()
{
if (!fwd->request->header.has(HDR_FTP_COMMAND)) {
abortTransaction("Internal error: FTP gateway request with no command");
}
void
-ServerStateData::readReply()
+Ftp::Relay::readReply()
{
assert(clientState() == fssConnected ||
clientState() == fssHandleUploadRequest);
if (100 <= ctrl.replycode && ctrl.replycode < 200)
- forwardPreliminaryReply(&ServerStateData::scheduleReadControlReply);
+ forwardPreliminaryReply(&Ftp::Relay::scheduleReadControlReply);
else
forwardReply();
}
void
-ServerStateData::readFeatReply()
+Ftp::Relay::readFeatReply()
{
assert(clientState() == fssHandleFeat);
}
void
-ServerStateData::readPasvReply()
+Ftp::Relay::readPasvReply()
{
assert(clientState() == fssHandlePasv || clientState() == fssHandleEpsv || clientState() == fssHandlePort || clientState() == fssHandleEprt);
}
void
-ServerStateData::readEpsvReply()
+Ftp::Relay::readEpsvReply()
{
if (100 <= ctrl.replycode && ctrl.replycode < 200)
return; // ignore preliminary replies
}
void
-ServerStateData::readDataReply()
+Ftp::Relay::readDataReply()
{
assert(clientState() == fssHandleDataRequest ||
clientState() == fssHandleUploadRequest);
if (ctrl.replycode == 125 || ctrl.replycode == 150) {
if (clientState() == fssHandleDataRequest)
- forwardPreliminaryReply(&ServerStateData::startDataDownload);
+ forwardPreliminaryReply(&Ftp::Relay::startDataDownload);
else // clientState() == fssHandleUploadRequest
- forwardPreliminaryReply(&ServerStateData::startDataUpload);
+ forwardPreliminaryReply(&Ftp::Relay::startDataUpload);
} else
forwardReply();
}
bool
-ServerStateData::startDirTracking()
+Ftp::Relay::startDirTracking()
{
if (!fwd->request->clientConnectionManager->port->ftp_track_dirs)
return false;
}
void
-ServerStateData::stopDirTracking()
+Ftp::Relay::stopDirTracking()
{
debugs(9, 5, "Got code from pwd: " << ctrl.replycode << ", msg: " << ctrl.last_reply);
}
void
-ServerStateData::readCwdOrCdupReply()
+Ftp::Relay::readCwdOrCdupReply()
{
assert(clientState() == fssHandleCwd ||
clientState() == fssHandleCdup);
}
void
-ServerStateData::readUserOrPassReply()
+Ftp::Relay::readUserOrPassReply()
{
if (100 <= ctrl.replycode && ctrl.replycode < 200)
return; //Just ignore
}
void
-ServerStateData::readTransferDoneReply()
+Ftp::Relay::readTransferDoneReply()
{
debugs(9, 3, HERE);
}
void
-ServerStateData::dataChannelConnected(const Comm::ConnectionPointer &conn, Comm::Flag err, int xerrno)
+Ftp::Relay::dataChannelConnected(const Comm::ConnectionPointer &conn, Comm::Flag err, int xerrno)
{
debugs(9, 3, HERE);
data.opener = NULL;
}
void
-ServerStateData::scheduleReadControlReply()
+Ftp::Relay::scheduleReadControlReply()
{
- Ftp::ServerStateData::scheduleReadControlReply(0);
+ Ftp::Client::scheduleReadControlReply(0);
}
-}; // namespace Gateway
-
-}; // namespace Ftp
-
-void
-ftpGatewayServerStart(FwdState *const fwdState)
+AsyncJob::Pointer
+Ftp::StartRelay(FwdState *const fwdState)
{
- AsyncJob::Start(new Ftp::Gateway::ServerStateData(fwdState));
+ return AsyncJob::Start(new Ftp::Relay(fwdState));
}
FtpClient.cc \
FtpClient.h \
FtpGateway.cc \
- FtpNative.cc \
+ FtpRelay.cc \
\
forward.h
class FwdState;
class HttpRequest;
+class AsyncJob;
+template <class Cbc> class CbcPointer;
+typedef CbcPointer<AsyncJob> AsyncJobPointer;
+
+namespace Ftp {
+
+/// A new FTP Gateway job
+AsyncJobPointer StartGateway(FwdState *const fwdState);
+
+/// A new FTP Relay job
+AsyncJobPointer StartRelay(FwdState *const fwdState);
+
/**
* \defgroup ServerProtocolFTPAPI Server-Side FTP API
* \ingroup ServerProtocol
*/
/// \ingroup ServerProtocolFTPAPI
-void ftpStart(FwdState *);
-/// \ingroup ServerProtocolFTPAPI
-const char *ftpUrlWith2f(HttpRequest *);
+const char *UrlWith2f(HttpRequest *);
-void ftpGatewayServerStart(FwdState *const);
+} // namespace Ftp
#endif /* SQUID_CLIENTS_FORWARD_H */
case 'B':
if (building_deny_info_url) break;
- p = request ? ftpUrlWith2f(request) : "[no URL]";
+ p = request ? Ftp::UrlWith2f(request) : "[no URL]";
break;
case 'c':
namespace Ftp {
-// TODO: Document
+/// parses and validates "A1,A2,A3,A4,P1,P2" IP,port sequence
bool ParseIpPort(const char *buf, const char *forceIp, Ip::Address &addr);
+
+/// parses and validates EPRT "<d><net-prt><d><net-addr><d><tcp-port><d>"
+/// proto,IP,port sequence
bool ParseProtoIpPort(const char *buf, Ip::Address &addr);
+
+/// parses an FTP-quoted quote-escaped path
const char *UnescapeDoubleQuoted(const char *quotedPath);
} // namespace Ftp