]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Done moving FTP code around. Polished moved code to match new locations.
authorAlex Rousskov <rousskov@measurement-factory.com>
Tue, 5 Aug 2014 00:17:16 +0000 (18:17 -0600)
committerAlex Rousskov <rousskov@measurement-factory.com>
Tue, 5 Aug 2014 00:17:16 +0000 (18:17 -0600)
src/clients/FtpNative is now src/clients/FtpRelay. It was awkward to use a
non-noun "Native" as a class name, and the class was already described as
"relaying FTP".

src/FwdState.cc
src/clients/FtpClient.cc
src/clients/FtpClient.h
src/clients/FtpGateway.cc
src/clients/FtpRelay.cc [moved from src/clients/FtpNative.cc with 78% similarity]
src/clients/Makefile.am
src/clients/forward.h
src/errorpage.cc
src/ftp/Parsing.h

index 081f4326ab67841b771c82222120bac6b2f79da8..7cfffb7116103cf95c142aea0fbfb0ac2be5a3db 100644 (file)
@@ -1001,9 +1001,9 @@ FwdState::dispatch()
 
         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:
index 0f15040e1700e89ac1968116d9d0fd738733937e..166c0f2d62896fea50b344da886eb8575783e7af 100644 (file)
@@ -61,7 +61,7 @@ escapeIAC(const char *buf)
 
 /// 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));
@@ -77,7 +77,7 @@ FtpChannel::opened(const Comm::ConnectionPointer &newConn,
 
 /// 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)) {
@@ -88,7 +88,7 @@ FtpChannel::close()
 }
 
 void
-FtpChannel::forget()
+Ftp::Channel::forget()
 {
     if (Comm::IsConnOpen(conn)) {
         commUnsetConnTimeout(conn);
@@ -98,14 +98,14 @@ FtpChannel::forget()
 }
 
 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;
@@ -114,14 +114,14 @@ ServerStateData::ServerStateData(FwdState *fwdState):
     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));
@@ -130,10 +130,10 @@ ServerStateData::DataChannel::addr(const Ip::Address &import)
      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();
@@ -162,13 +162,13 @@ ServerStateData::~ServerStateData()
 }
 
 void
-ServerStateData::start()
+Ftp::Client::start()
 {
     scheduleReadControlReply(0);
 }
 
 void
-ServerStateData::initReadBuf()
+Ftp::Client::initReadBuf()
 {
     if (data.readBuf == NULL) {
         data.readBuf = new MemBuf;
@@ -180,7 +180,7 @@ ServerStateData::initReadBuf()
  * 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);
@@ -203,13 +203,13 @@ ServerStateData::closeServer()
  \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);
 
@@ -247,7 +247,7 @@ ServerStateData::failed(err_type error, int xerrno)
 }
 
 Http::StatusCode
-ServerStateData::failedHttpStatus(err_type &error)
+Ftp::Client::failedHttpStatus(err_type &error)
 {
     if (error == ERR_NONE)
         error = ERR_FTP_FAILURE;
@@ -261,7 +261,7 @@ ServerStateData::failedHttpStatus(err_type &error)
  * 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);
 
@@ -277,18 +277,18 @@ ServerStateData::scheduleReadControlReply(int buffered_ok)
             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");
 
@@ -345,7 +345,7 @@ ServerStateData::readControlReply(const CommIoCbParams &io)
 }
 
 void
-ServerStateData::handleControlReply()
+Ftp::Client::handleControlReply()
 {
     debugs(9, 3, HERE);
 
@@ -381,7 +381,7 @@ ServerStateData::handleControlReply()
 }
 
 bool
-ServerStateData::handlePasvReply(Ip::Address &srvAddr)
+Ftp::Client::handlePasvReply(Ip::Address &srvAddr)
 {
     int code = ctrl.replycode;
     char *buf;
@@ -412,7 +412,7 @@ ServerStateData::handlePasvReply(Ip::Address &srvAddr)
 }
 
 bool
-ServerStateData::handleEpsvReply(Ip::Address &remoteAddr)
+Ftp::Client::handleEpsvReply(Ip::Address &remoteAddr)
 {
     int code = ctrl.replycode;
     char *buf;
@@ -517,10 +517,10 @@ ServerStateData::handleEpsvReply(Ip::Address &remoteAddr)
 }
 
 // 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. */
@@ -559,14 +559,14 @@ ServerStateData::sendEprt()
 }
 
 bool
-ServerStateData::sendPort()
+Ftp::Client::sendPort()
 {
     failed(ERR_FTP_FAILURE, 0);
     return false;
 }
 
 bool
-ServerStateData::sendPassive()
+Ftp::Client::sendPassive()
 {
     debugs(9, 3, HERE);
 
@@ -687,7 +687,7 @@ ServerStateData::sendPassive()
 
 
 void
-ServerStateData::connectDataChannel()
+Ftp::Client::connectDataChannel()
 {
     safe_free(ctrl.last_command);
 
@@ -705,37 +705,37 @@ ServerStateData::connectDataChannel()
 
     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) {
@@ -747,7 +747,7 @@ ServerStateData::dataClosed(const CommCloseCbParams &io)
 }
 
 void
-ServerStateData::writeCommand(const char *buf)
+Ftp::Client::writeCommand(const char *buf)
 {
     char *ebuf;
     /* trace FTP protocol communications at level 2 */
@@ -770,16 +770,16 @@ ServerStateData::writeCommand(const char *buf)
         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");
@@ -803,15 +803,15 @@ ServerStateData::writeCommandCallback(const CommIoCbParams &io)
 
 /// 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() << "'" );
 
@@ -823,13 +823,13 @@ ServerStateData::timeout(const CommTimeoutCbParams &io)
 }
 
 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())
@@ -849,20 +849,20 @@ ServerStateData::maybeReadVirginBody()
 
     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;
@@ -931,7 +931,7 @@ ServerStateData::dataRead(const CommIoCbParams &io)
 }
 
 void
-ServerStateData::dataComplete()
+Ftp::Client::dataComplete()
 {
     debugs(9, 3,HERE);
 
@@ -966,7 +966,7 @@ ServerStateData::dataComplete()
  *     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);
@@ -976,7 +976,7 @@ ServerStateData::abortTransaction(const char *reason)
     }
 
     fwd->handleUnregisteredServerEnd();
-    mustStop("ServerStateData::abortTransaction");
+    mustStop("Ftp::Client::abortTransaction");
 }
 
 /**
@@ -984,18 +984,18 @@ ServerStateData::abortTransaction(const char *reason)
  * 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);
@@ -1006,7 +1006,7 @@ ServerStateData::sentRequestBody(const CommIoCbParams &io)
  * called after we wrote the last byte of the request body
  */
 void
-ServerStateData::doneSendingRequestBody()
+Ftp::Client::doneSendingRequestBody()
 {
     ::ServerStateData::doneSendingRequestBody();
     debugs(9,3, HERE);
@@ -1020,7 +1020,7 @@ ServerStateData::doneSendingRequestBody()
 /// 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;
index b2fc76971f93938663a75c42445a069e9547225c..ab90b3dbbf51d9c2b3fd9d852eea6eca83b0ef20 100644 (file)
@@ -3,8 +3,8 @@
  *
  */
 
-#ifndef SQUID_FTP_SERVER_H
-#define SQUID_FTP_SERVER_H
+#ifndef SQUID_FTP_CLIENT_H
+#define SQUID_FTP_CLIENT_H
 
 #include "Server.h"
 
@@ -14,8 +14,8 @@ namespace Ftp {
 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
@@ -44,17 +44,22 @@ private:
     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,
@@ -67,12 +72,11 @@ public:
     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;
@@ -83,7 +87,7 @@ public:
     } 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;
@@ -128,11 +132,15 @@ public:
     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);
@@ -145,6 +153,7 @@ protected:
     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);
@@ -153,15 +162,9 @@ protected:
 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 */
index d32216e50065069d4814322baaddce5045cbff0d..ecab7987716454b46a23d60a65a4fae49a057270 100644 (file)
@@ -32,6 +32,7 @@
 
 #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
@@ -113,17 +112,20 @@ struct _ftp_flags {
     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;
@@ -147,7 +149,7 @@ public:
     char typecode;
     MemBuf listing;            ///< FTP directory listing in HTML format.
 
-    struct _ftp_flags flags;
+    GatewayFlags flags;
 
 public:
     // these should all be private
@@ -156,7 +158,7 @@ public:
     void loginParser(const char *, int escaped);
     int restartable();
     void appendSuccessHeader();
-    void hackShortcut(FTPSM * nextState);
+    void hackShortcut(StateMethod *nextState);
     void unhack();
     void readStor();
     void parseListing();
@@ -198,10 +200,14 @@ private:
     // 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 {
@@ -219,6 +225,10 @@ 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
@@ -342,9 +352,9 @@ FTPSM *FTP_SM_FUNCS[] = {
 
 /// 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 */
 
@@ -354,8 +364,9 @@ FtpStateData::dataClosed(const CommCloseCbParams &io)
      */
 }
 
-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 << "'" );
@@ -373,7 +384,7 @@ FtpStateData::FtpStateData(FwdState *fwdState): AsyncJob("FtpStateData"),
     initReadBuf();
 }
 
-FtpStateData::~FtpStateData()
+Ftp::Gateway::~Gateway()
 {
     debugs(9, 3, HERE << entry->url()  );
 
@@ -408,7 +419,7 @@ FtpStateData::~FtpStateData()
  * 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.
@@ -461,13 +472,13 @@ FtpStateData::loginParser(const char *login, int escaped)
 }
 
 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();
 
@@ -493,7 +504,7 @@ FtpStateData::listenForDataChannel(const Comm::ConnectionPointer &conn)
 }
 
 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 */
@@ -508,7 +519,7 @@ FtpStateData::timeout(const CommTimeoutCbParams &io)
         data.close();
     }
 
-    Ftp::ServerStateData::timeout(io);
+    Ftp::Client::timeout(io);
 }
 
 /// \ingroup ServerProtocolFTPInternal
@@ -546,7 +557,7 @@ ftpListPartsFree(ftpListParts ** parts)
 
 /// \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;
@@ -776,7 +787,7 @@ found:
 }
 
 MemBuf *
-FtpStateData::htmlifyListEntry(const char *line)
+Ftp::Gateway::htmlifyListEntry(const char *line)
 {
     char icon[2048];
     char href[2048 + 40];
@@ -913,7 +924,7 @@ FtpStateData::htmlifyListEntry(const char *line)
 }
 
 void
-FtpStateData::parseListing()
+Ftp::Gateway::parseListing()
 {
     char *buf = data.readBuf->content();
     char *sbuf;                        /* NULL-terminated copy of termedBuf */
@@ -996,9 +1007,9 @@ FtpStateData::parseListing()
 }
 
 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();
@@ -1021,7 +1032,7 @@ FtpStateData::processReplyBody()
 #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;
     }
 
@@ -1063,7 +1074,7 @@ FtpStateData::processReplyBody()
  \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);
@@ -1108,7 +1119,7 @@ FtpStateData::checkAuth(const HttpHeader * req_hdr)
 
 static String str_type_eq;
 void
-FtpStateData::checkUrlpath()
+Ftp::Gateway::checkUrlpath()
 {
     int l;
     size_t t;
@@ -1146,7 +1157,7 @@ FtpStateData::checkUrlpath()
 }
 
 void
-FtpStateData::buildTitleUrl()
+Ftp::Gateway::buildTitleUrl()
 {
     title_url = "ftp://";
 
@@ -1188,15 +1199,8 @@ FtpStateData::buildTitleUrl()
     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 */
@@ -1213,15 +1217,15 @@ FtpStateData::start()
 
     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
 
@@ -1240,7 +1244,7 @@ FtpStateData::handleControlReply()
 
 /// \ingroup ServerProtocolFTPInternal
 static void
-ftpReadWelcome(FtpStateData * ftpState)
+ftpReadWelcome(Ftp::Gateway * ftpState)
 {
     int code = ftpState->ctrl.replycode;
     debugs(9, 3, HERE);
@@ -1271,7 +1275,7 @@ ftpReadWelcome(FtpStateData * ftpState)
  * its NOT a general failure. But a correct FTP response type.
  */
 void
-FtpStateData::loginFailed()
+Ftp::Gateway::loginFailed()
 {
     ErrorState *err = NULL;
     const char *command, *reply;
@@ -1335,7 +1339,7 @@ FtpStateData::loginFailed()
 }
 
 const char *
-FtpStateData::ftpRealm()
+Ftp::Gateway::ftpRealm()
 {
     static char realm[8192];
 
@@ -1352,7 +1356,7 @@ FtpStateData::ftpRealm()
 
 /// \ingroup ServerProtocolFTPInternal
 static void
-ftpSendUser(FtpStateData * ftpState)
+ftpSendUser(Ftp::Gateway * ftpState)
 {
     /* check the server control channel is still available */
     if (!ftpState || !ftpState->haveControlChannel("ftpSendUser"))
@@ -1367,12 +1371,12 @@ ftpSendUser(FtpStateData * ftpState)
 
     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);
@@ -1388,7 +1392,7 @@ ftpReadUser(FtpStateData * ftpState)
 
 /// \ingroup ServerProtocolFTPInternal
 static void
-ftpSendPass(FtpStateData * ftpState)
+ftpSendPass(Ftp::Gateway * ftpState)
 {
     /* check the server control channel is still available */
     if (!ftpState || !ftpState->haveControlChannel("ftpSendPass"))
@@ -1396,12 +1400,12 @@ ftpSendPass(FtpStateData * ftpState)
 
     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);
@@ -1415,7 +1419,7 @@ ftpReadPass(FtpStateData * ftpState)
 
 /// \ingroup ServerProtocolFTPInternal
 static void
-ftpSendType(FtpStateData * ftpState)
+ftpSendType(Ftp::Gateway * ftpState)
 {
     const char *t;
     const char *filename;
@@ -1463,12 +1467,12 @@ ftpSendType(FtpStateData * ftpState)
 
     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;
@@ -1509,7 +1513,7 @@ ftpReadType(FtpStateData * ftpState)
 
 /// \ingroup ServerProtocolFTPInternal
 static void
-ftpTraverseDirectory(FtpStateData * ftpState)
+ftpTraverseDirectory(Ftp::Gateway * ftpState)
 {
     wordlist *w;
     debugs(9, 4, HERE << (ftpState->filepath ? ftpState->filepath : "<NULL>"));
@@ -1547,7 +1551,7 @@ ftpTraverseDirectory(FtpStateData * ftpState)
 
 /// \ingroup ServerProtocolFTPInternal
 static void
-ftpSendCwd(FtpStateData * ftpState)
+ftpSendCwd(Ftp::Gateway * ftpState)
 {
     char *path = NULL;
 
@@ -1569,12 +1573,12 @@ ftpSendCwd(FtpStateData * ftpState)
 
     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);
@@ -1605,7 +1609,7 @@ ftpReadCwd(FtpStateData * ftpState)
 
 /// \ingroup ServerProtocolFTPInternal
 static void
-ftpSendMkdir(FtpStateData * ftpState)
+ftpSendMkdir(Ftp::Gateway * ftpState)
 {
     char *path = NULL;
 
@@ -1617,12 +1621,12 @@ ftpSendMkdir(FtpStateData * ftpState)
     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;
@@ -1644,7 +1648,7 @@ ftpReadMkdir(FtpStateData * ftpState)
 
 /// \ingroup ServerProtocolFTPInternal
 static void
-ftpGetFile(FtpStateData * ftpState)
+ftpGetFile(Ftp::Gateway * ftpState)
 {
     assert(*ftpState->filepath != '\0');
     ftpState->flags.isdir = 0;
@@ -1653,7 +1657,7 @@ ftpGetFile(FtpStateData * ftpState)
 
 /// \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 /");
@@ -1666,7 +1670,7 @@ ftpListDir(FtpStateData * ftpState)
 
 /// \ingroup ServerProtocolFTPInternal
 static void
-ftpSendMdtm(FtpStateData * ftpState)
+ftpSendMdtm(Ftp::Gateway * ftpState)
 {
     /* check the server control channel is still available */
     if (!ftpState || !ftpState->haveControlChannel("ftpSendMdtm"))
@@ -1675,12 +1679,12 @@ ftpSendMdtm(FtpStateData * ftpState)
     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);
@@ -1698,7 +1702,7 @@ ftpReadMdtm(FtpStateData * ftpState)
 
 /// \ingroup ServerProtocolFTPInternal
 static void
-ftpSendSize(FtpStateData * ftpState)
+ftpSendSize(Ftp::Gateway * ftpState)
 {
     /* check the server control channel is still available */
     if (!ftpState || !ftpState->haveControlChannel("ftpSendSize"))
@@ -1712,7 +1716,7 @@ ftpSendSize(FtpStateData * ftpState)
         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);
@@ -1720,7 +1724,7 @@ ftpSendSize(FtpStateData * ftpState)
 
 /// \ingroup ServerProtocolFTPInternal
 static void
-ftpReadSize(FtpStateData * ftpState)
+ftpReadSize(Ftp::Gateway * ftpState)
 {
     int code = ftpState->ctrl.replycode;
     debugs(9, 3, HERE);
@@ -1747,7 +1751,7 @@ ftpReadSize(FtpStateData * ftpState)
  \ingroup ServerProtocolFTPInternal
  */
 static void
-ftpReadEPSV(FtpStateData* ftpState)
+ftpReadEPSV(Ftp::Gateway* ftpState)
 {
     Ip::Address srvAddr; // unused
     if (ftpState->handleEpsvReply(srvAddr)) {
@@ -1765,7 +1769,7 @@ ftpReadEPSV(FtpStateData* ftpState)
  * 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"))
@@ -1774,7 +1778,7 @@ ftpSendPassive(FtpStateData * ftpState)
     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;
@@ -1782,13 +1786,13 @@ ftpSendPassive(FtpStateData * ftpState)
 
     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);
@@ -1817,7 +1821,7 @@ FtpStateData::processHeadResponse()
 
 /// \ingroup ServerProtocolFTPInternal
 static void
-ftpReadPasv(FtpStateData * ftpState)
+ftpReadPasv(Ftp::Gateway * ftpState)
 {
     Ip::Address srvAddr; // unused
     if (ftpState->handlePasvReply(srvAddr))
@@ -1829,7 +1833,7 @@ ftpReadPasv(FtpStateData * ftpState)
 }
 
 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;
@@ -1852,7 +1856,7 @@ FtpStateData::dataChannelConnected(const Comm::ConnectionPointer &conn, Comm::Fl
 
 /// \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) {
@@ -1890,7 +1894,7 @@ ftpOpenListenSocket(FtpStateData * ftpState, int fallback)
 
 /// \ingroup ServerProtocolFTPInternal
 static void
-ftpSendPORT(FtpStateData * ftpState)
+ftpSendPORT(Ftp::Gateway * ftpState)
 {
     /* check the server control channel is still available */
     if (!ftpState || !ftpState->haveControlChannel("ftpSendPort"))
@@ -1930,14 +1934,14 @@ ftpSendPORT(FtpStateData * ftpState)
              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);
@@ -1953,7 +1957,7 @@ ftpReadPORT(FtpStateData * ftpState)
 
 /// \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.");
@@ -1988,11 +1992,11 @@ ftpSendEPRT(FtpStateData * ftpState)
              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);
@@ -2015,7 +2019,7 @@ ftpReadEPRT(FtpStateData * ftpState)
  \param io    comm accept(2) callback parameters
  */
 void
-FtpStateData::ftpAcceptDataConnection(const CommAcceptCbParams &io)
+Ftp::Gateway::ftpAcceptDataConnection(const CommAcceptCbParams &io)
 {
     debugs(9, 3, HERE);
 
@@ -2087,7 +2091,7 @@ FtpStateData::ftpAcceptDataConnection(const CommAcceptCbParams &io)
 
 /// \ingroup ServerProtocolFTPInternal
 static void
-ftpRestOrList(FtpStateData * ftpState)
+ftpRestOrList(Ftp::Gateway * ftpState)
 {
     debugs(9, 3, HERE);
 
@@ -2111,7 +2115,7 @@ ftpRestOrList(FtpStateData * ftpState)
 
 /// \ingroup ServerProtocolFTPInternal
 static void
-ftpSendStor(FtpStateData * ftpState)
+ftpSendStor(Ftp::Gateway * ftpState)
 {
     /* check the server control channel is still available */
     if (!ftpState || !ftpState->haveControlChannel("ftpSendStor"))
@@ -2123,12 +2127,12 @@ ftpSendStor(FtpStateData * ftpState)
         /* 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);
@@ -2138,12 +2142,12 @@ ftpSendStor(FtpStateData * 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);
@@ -2180,7 +2184,7 @@ void FtpStateData::readStor()
 
 /// \ingroup ServerProtocolFTPInternal
 static void
-ftpSendRest(FtpStateData * ftpState)
+ftpSendRest(Ftp::Gateway * ftpState)
 {
     /* check the server control channel is still available */
     if (!ftpState || !ftpState->haveControlChannel("ftpSendRest"))
@@ -2190,11 +2194,11 @@ ftpSendRest(FtpStateData * ftpState)
 
     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;
@@ -2222,7 +2226,7 @@ FtpStateData::restartable()
 
 /// \ingroup ServerProtocolFTPInternal
 static void
-ftpReadRest(FtpStateData * ftpState)
+ftpReadRest(Ftp::Gateway * ftpState)
 {
     int code = ftpState->ctrl.replycode;
     debugs(9, 3, HERE);
@@ -2242,7 +2246,7 @@ ftpReadRest(FtpStateData * ftpState)
 
 /// \ingroup ServerProtocolFTPInternal
 static void
-ftpSendList(FtpStateData * ftpState)
+ftpSendList(Ftp::Gateway * ftpState)
 {
     /* check the server control channel is still available */
     if (!ftpState || !ftpState->haveControlChannel("ftpSendList"))
@@ -2257,12 +2261,12 @@ ftpSendList(FtpStateData * ftpState)
     }
 
     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"))
@@ -2279,12 +2283,12 @@ ftpSendNlst(FtpStateData * ftpState)
     }
 
     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);
@@ -2294,7 +2298,7 @@ ftpReadList(FtpStateData * ftpState)
         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 */
@@ -2311,7 +2315,7 @@ ftpReadList(FtpStateData * ftpState)
 
 /// \ingroup ServerProtocolFTPInternal
 static void
-ftpSendRetr(FtpStateData * ftpState)
+ftpSendRetr(Ftp::Gateway * ftpState)
 {
     /* check the server control channel is still available */
     if (!ftpState || !ftpState->haveControlChannel("ftpSendRetr"))
@@ -2322,12 +2326,12 @@ ftpSendRetr(FtpStateData * ftpState)
     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);
@@ -2337,7 +2341,7 @@ ftpReadRetr(FtpStateData * ftpState)
         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);
@@ -2358,10 +2362,10 @@ ftpReadRetr(FtpStateData * ftpState)
  * 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() : "");
@@ -2370,12 +2374,12 @@ FtpStateData::completedListing()
     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);
@@ -2397,7 +2401,7 @@ ftpReadTransferDone(FtpStateData * ftpState)
 
 // premature end of the request body
 void
-FtpStateData::handleRequestBodyProducerAborted()
+Ftp::Gateway::handleRequestBodyProducerAborted()
 {
     ServerStateData::handleRequestBodyProducerAborted();
     debugs(9, 3, HERE << "ftpState=" << this);
@@ -2406,7 +2410,7 @@ FtpStateData::handleRequestBodyProducerAborted()
 
 /// \ingroup ServerProtocolFTPInternal
 static void
-ftpWriteTransferDone(FtpStateData * ftpState)
+ftpWriteTransferDone(Ftp::Gateway * ftpState)
 {
     int code = ftpState->ctrl.replycode;
     debugs(9, 3, HERE);
@@ -2423,7 +2427,7 @@ ftpWriteTransferDone(FtpStateData * ftpState)
 
 /// \ingroup ServerProtocolFTPInternal
 static void
-ftpSendQuit(FtpStateData * ftpState)
+ftpSendQuit(Ftp::Gateway * ftpState)
 {
     /* check the server control channel is still available */
     if (!ftpState || !ftpState->haveControlChannel("ftpSendQuit"))
@@ -2431,7 +2435,7 @@ ftpSendQuit(FtpStateData * ftpState)
 
     snprintf(cbuf, CTRL_BUFLEN, "QUIT\r\n");
     ftpState->writeCommand(cbuf);
-    ftpState->state = Ftp::ServerStateData::SENT_QUIT;
+    ftpState->state = Ftp::Client::SENT_QUIT;
 }
 
 /**
@@ -2441,14 +2445,14 @@ ftpSendQuit(FtpStateData * ftpState)
  *  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;
@@ -2476,7 +2480,7 @@ ftpTrySlashHack(FtpStateData * ftpState)
  * Forget hack status. Next error is shown to the user
  */
 void
-FtpStateData::unhack()
+Ftp::Gateway::unhack()
 {
     debugs(9, 3, HERE);
 
@@ -2487,7 +2491,7 @@ FtpStateData::unhack()
 }
 
 void
-FtpStateData::hackShortcut(FTPSM * nextState)
+Ftp::Gateway::hackShortcut(FTPSM * nextState)
 {
     /* Clear some unwanted state */
     setCurrentOffset(0);
@@ -2512,7 +2516,7 @@ FtpStateData::hackShortcut(FTPSM * nextState)
 
 /// \ingroup ServerProtocolFTPInternal
 static void
-ftpFail(FtpStateData *ftpState)
+ftpFail(Ftp::Gateway *ftpState)
 {
     debugs(9, 6, HERE << "flags(" <<
            (ftpState->flags.isdir?"IS_DIR,":"") <<
@@ -2528,9 +2532,9 @@ ftpFail(FtpStateData *ftpState)
 
         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;
@@ -2545,7 +2549,7 @@ ftpFail(FtpStateData *ftpState)
 }
 
 Http::StatusCode
-FtpStateData::failedHttpStatus(err_type &error)
+Ftp::Gateway::failedHttpStatus(err_type &error)
 {
     if (error == ERR_NONE) {
         switch (state) {
@@ -2570,12 +2574,12 @@ FtpStateData::failedHttpStatus(err_type &error)
             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;
@@ -2620,7 +2624,7 @@ ftpSendReply(FtpStateData * ftpState)
 }
 
 void
-FtpStateData::appendSuccessHeader()
+Ftp::Gateway::appendSuccessHeader()
 {
     const char *mime_type = NULL;
     const char *mime_enc = NULL;
@@ -2701,7 +2705,7 @@ FtpStateData::appendSuccessHeader()
 }
 
 void
-FtpStateData::haveParsedReplyHeaders()
+Ftp::Gateway::haveParsedReplyHeaders()
 {
     ServerStateData::haveParsedReplyHeaders();
 
@@ -2722,7 +2726,7 @@ FtpStateData::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();
@@ -2746,7 +2750,7 @@ FtpStateData::ftpAuthRequired(HttpRequest * request, const char *realm)
  *  ftp:host:port/%2froot/path  AKA 'the FTP %2f hack'.
  */
 const char *
-ftpUrlWith2f(HttpRequest * request)
+Ftp::UrlWith2f(HttpRequest * request)
 {
     String newbuf = "%2f";
 
@@ -2767,7 +2771,7 @@ ftpUrlWith2f(HttpRequest * request)
 }
 
 void
-FtpStateData::printfReplyBody(const char *fmt, ...)
+Ftp::Gateway::printfReplyBody(const char *fmt, ...)
 {
     va_list args;
     va_start (args, fmt);
@@ -2783,7 +2787,7 @@ FtpStateData::printfReplyBody(const char *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);
@@ -2792,11 +2796,11 @@ FtpStateData::writeReplyBody(const char *dataToWrite, size_t 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 " <<
@@ -2816,7 +2820,7 @@ FtpStateData::completeForwarding()
  \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;
@@ -2830,3 +2834,9 @@ FtpStateData::haveControlChannel(const char *caller_name) const
 
     return true;
 }
+
+AsyncJob::Pointer
+Ftp::StartGateway(FwdState *const fwdState)
+{
+    return AsyncJob::Start(new Ftp::Gateway(fwdState));
+}
similarity index 78%
rename from src/clients/FtpNative.cc
rename to src/clients/FtpRelay.cc
index e4a29cdea132b0f20c70b523d9c7bfd46e2585a1..fda91a8979afffbd89b07c610348989b6a370eb0 100644 (file)
@@ -7,6 +7,7 @@
 
 #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);
@@ -54,12 +60,12 @@ protected:
     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();
@@ -84,45 +90,48 @@ protected:
         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;
@@ -134,7 +143,7 @@ ServerStateData::ServerStateData(FwdState *const fwdState):
     entry->releaseRequest();
 }
 
-ServerStateData::~ServerStateData()
+Ftp::Relay::~Relay()
 {
     closeServer(); // TODO: move to Server.cc?
     if (savedReply.message)
@@ -145,10 +154,10 @@ ServerStateData::~ServerStateData()
 }
 
 void
-ServerStateData::start()
+Ftp::Relay::start()
 {
     if (!master().clientReadGreeting)
-        Ftp::ServerStateData::start();
+        Ftp::Client::start();
     else
     if (clientState() == fssHandleDataRequest ||
         clientState() == fssHandleUploadRequest)
@@ -160,7 +169,7 @@ ServerStateData::start()
 /// 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()) {
@@ -179,11 +188,11 @@ ServerStateData::serverComplete()
             }
         }
     }
-    Ftp::ServerStateData::serverComplete();
+    Ftp::Client::serverComplete();
 }
 
 Ftp::MasterState &
-ServerStateData::updateMaster()
+Ftp::Relay::updateMaster()
 {
     CbcPointer<ConnStateData> &mgr = fwd->request->clientConnectionManager;
     if (mgr.valid()) {
@@ -198,19 +207,19 @@ ServerStateData::updateMaster()
 }
 
 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;
@@ -227,17 +236,17 @@ ServerStateData::clientState(Ftp::ServerState newState)
  \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);
@@ -246,11 +255,11 @@ ServerStateData::failed(err_type error, int xerrno)
     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);
@@ -260,7 +269,7 @@ ServerStateData::failedErrorMessage(err_type error, int xerrno)
 }
 
 void
-ServerStateData::processReplyBody()
+Ftp::Relay::processReplyBody()
 {
     debugs(9, 3, HERE << "starting");
 
@@ -295,7 +304,7 @@ ServerStateData::processReplyBody()
 }
 
 void
-ServerStateData::handleControlReply()
+Ftp::Relay::handleControlReply()
 {
     if (!request->clientConnectionManager.valid()) {
         debugs(9, 5, "client connection gone");
@@ -303,7 +312,7 @@ ServerStateData::handleControlReply()
         return;
     }
 
-    Ftp::ServerStateData::handleControlReply();
+    Ftp::Client::handleControlReply();
     if (ctrl.message == NULL)
         return; // didn't get complete reply yet
 
@@ -313,7 +322,7 @@ ServerStateData::handleControlReply()
 }
 
 void
-ServerStateData::handleRequestBodyProducerAborted()
+Ftp::Relay::handleRequestBodyProducerAborted()
 {
     ::ServerStateData::handleRequestBodyProducerAborted();
 
@@ -321,14 +330,14 @@ 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);
@@ -342,7 +351,7 @@ ServerStateData::forwardReply()
 }
 
 void
-ServerStateData::forwardPreliminaryReply(const PreliminaryCb cb)
+Ftp::Relay::forwardPreliminaryReply(const PreliminaryCb cb)
 {
     debugs(9, 5, HERE << "Forwarding preliminary reply to client");
 
@@ -353,16 +362,16 @@ ServerStateData::forwardPreliminaryReply(const PreliminaryCb cb)
     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");
 
@@ -373,13 +382,13 @@ ServerStateData::proceedAfterPreliminaryReply()
 }
 
 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);
@@ -408,14 +417,14 @@ ServerStateData::createHttpReply(const Http::StatusCode httpStatus, const int cl
 }
 
 void
-ServerStateData::handleDataRequest()
+Ftp::Relay::handleDataRequest()
 {
     data.addr(master().clientDataAddr);
     connectDataChannel();
 }
 
 void
-ServerStateData::startDataDownload()
+Ftp::Relay::startDataDownload()
 {
     assert(Comm::IsConnOpen(data.conn));
 
@@ -432,7 +441,7 @@ ServerStateData::startDataDownload()
 }
 
 void
-ServerStateData::startDataUpload()
+Ftp::Relay::startDataUpload()
 {
     assert(Comm::IsConnOpen(data.conn));
 
@@ -448,7 +457,7 @@ ServerStateData::startDataUpload()
 }
 
 void
-ServerStateData::readGreeting()
+Ftp::Relay::readGreeting()
 {
     assert(!master().clientReadGreeting);
 
@@ -467,7 +476,7 @@ ServerStateData::readGreeting()
     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();
@@ -476,7 +485,7 @@ ServerStateData::readGreeting()
 }
 
 void
-ServerStateData::sendCommand()
+Ftp::Relay::sendCommand()
 {
     if (!fwd->request->header.has(HDR_FTP_COMMAND)) {
         abortTransaction("Internal error: FTP gateway request with no command");
@@ -523,19 +532,19 @@ ServerStateData::sendCommand()
 }
 
 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);
 
@@ -546,7 +555,7 @@ ServerStateData::readFeatReply()
 }
 
 void
-ServerStateData::readPasvReply()
+Ftp::Relay::readPasvReply()
 {
     assert(clientState() == fssHandlePasv || clientState() == fssHandleEpsv || clientState() == fssHandlePort || clientState() == fssHandleEprt);
 
@@ -560,7 +569,7 @@ ServerStateData::readPasvReply()
 }
 
 void
-ServerStateData::readEpsvReply()
+Ftp::Relay::readEpsvReply()
 {
     if (100 <= ctrl.replycode && ctrl.replycode < 200)
         return; // ignore preliminary replies
@@ -575,22 +584,22 @@ ServerStateData::readEpsvReply()
 }
 
 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;
@@ -610,7 +619,7 @@ ServerStateData::startDirTracking()
 }
 
 void
-ServerStateData::stopDirTracking()
+Ftp::Relay::stopDirTracking()
 {
     debugs(9, 5, "Got code from pwd: " << ctrl.replycode << ", msg: " << ctrl.last_reply);
 
@@ -632,7 +641,7 @@ ServerStateData::stopDirTracking()
 }
 
 void
-ServerStateData::readCwdOrCdupReply()
+Ftp::Relay::readCwdOrCdupReply()
 {
     assert(clientState() == fssHandleCwd ||
            clientState() == fssHandleCdup);
@@ -651,7 +660,7 @@ ServerStateData::readCwdOrCdupReply()
 }
 
 void
-ServerStateData::readUserOrPassReply()
+Ftp::Relay::readUserOrPassReply()
 {
     if (100 <= ctrl.replycode && ctrl.replycode < 200)
         return; //Just ignore
@@ -667,7 +676,7 @@ ServerStateData::readUserOrPassReply()
 }
 
 void
-ServerStateData::readTransferDoneReply()
+Ftp::Relay::readTransferDoneReply()
 {
     debugs(9, 3, HERE);
 
@@ -680,7 +689,7 @@ ServerStateData::readTransferDoneReply()
 }
 
 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;
@@ -699,17 +708,13 @@ ServerStateData::dataChannelConnected(const Comm::ConnectionPointer &conn, Comm:
 }
 
 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));
 }
index bd717863137efbf050aa19fe4e92fd157afc1954..af867511fd06fc150e9a8339689d486cb8561cc1 100644 (file)
@@ -6,6 +6,6 @@ libclients_la_SOURCES = \
        FtpClient.cc \
        FtpClient.h \
        FtpGateway.cc \
-       FtpNative.cc \
+       FtpRelay.cc \
        \
        forward.h
index e3d6e439a1fca1f4cbc52ebc0c4ab30470d0c57e..d32c4612dd957f037b24f6996d30091271822f36 100644 (file)
@@ -4,16 +4,26 @@
 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 */
index d5fde9e3abc125461b3f5ee0505dd077fa359e53..44d6d18d8fbde66a2b6dec95db1800a6938b8f37 100644 (file)
@@ -831,7 +831,7 @@ ErrorState::Convert(char token, bool building_deny_info_url, bool allowRecursion
 
     case 'B':
         if (building_deny_info_url) break;
-        p = request ? ftpUrlWith2f(request) : "[no URL]";
+        p = request ? Ftp::UrlWith2f(request) : "[no URL]";
         break;
 
     case 'c':
index 1363a88fb98e27d1f923d5e37a149ce63c1b677b..89dd64a138f0f001d05a81043bdb45d6d7ec6392 100644 (file)
@@ -5,9 +5,14 @@
 
 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