//manipulation for Cache-Control: private header
bool hasPrivate() const {return isSet(CC_PRIVATE);}
const String &Private() const {return private_;}
- void Private(const String &v = "") {
+ void Private(const String &v) {
setMask(CC_PRIVATE,true);
+ if (!v.size())
+ return;
// uses append for multi-line headers
if (private_.size() > 0)
private_.append(",");
//manipulation for Cache-Control: no-cache header
bool hasNoCache() const {return isSet(CC_NO_CACHE);}
const String &noCache() const {return no_cache;}
- void noCache(String &v) {
+ void noCache(const String &v) {
setMask(CC_NO_CACHE,true);
+ if (!v.size())
+ return;
// uses append for multi-line headers
- if (no_cache.size() > 0)
+ if (no_cache.size() > 0 && v.size() > 0)
no_cache.append(",");
no_cache.append(v);
}
debugs(9, 3, "connecting to " << conn->remote);
- data.opener = commCbCall(9, 3, "Ftp::Client::dataChannelConnected",
- CommConnectCbPtrFun(Ftp::Client::dataChannelConnected, this));
+ typedef CommCbMemFunT<Client, CommConnectCbParams> Dialer;
+ data.opener = JobCallback(9, 3, Dialer, this, Ftp::Client::dataChannelConnected);
Comm::ConnOpener *cs = new Comm::ConnOpener(conn, data.opener, Config.Timeout.connect);
cs->setHost(data.host);
AsyncJob::Start(cs);
}
-void
-Ftp::Client::dataChannelConnected(const Comm::ConnectionPointer &conn, Comm::Flag status, int xerrno, void *data)
-{
- Client *ftpState = static_cast<Client *>(data);
- ftpState->dataChannelConnected(conn, status, xerrno);
-}
-
bool
Ftp::Client::openListenSocket()
{
bool read_pending;
};
-/// Base class for FTP Gateway and FTP Native client classes.
+/// FTP client functionality shared among FTP Gateway and Relay clients.
class Client: public ::ServerStateData
{
public:
void readControlReply(const CommIoCbParams &io);
virtual void handleControlReply();
void writeCommandCallback(const CommIoCbParams &io);
- static CNCB dataChannelConnected;
- virtual void dataChannelConnected(const Comm::ConnectionPointer &conn, Comm::Flag status, int xerrno) = 0;
+ virtual void dataChannelConnected(const CommConnectCbParams &io) = 0;
void dataRead(const CommIoCbParams &io);
void dataComplete();
AsyncCall::Pointer dataCloser();
void setCurrentOffset(int64_t offset) { currentOffset = offset; }
int64_t getCurrentOffset() const { return currentOffset; }
- virtual void dataChannelConnected(const Comm::ConnectionPointer &conn, Comm::Flag err, int xerrno);
+ virtual void dataChannelConnected(const CommConnectCbParams &io);
static PF ftpDataWrite;
virtual void timeout(const CommTimeoutCbParams &io);
void ftpAcceptDataConnection(const CommAcceptCbParams &io);
line = (char *)memAllocate(MEM_4K_BUF);
++end;
s = sbuf;
- s += strspn(s, Ftp::crlf);
+ s += strspn(s, crlf);
- for (; s < end; s += strcspn(s, Ftp::crlf), s += strspn(s, Ftp::crlf)) {
+ for (; s < end; s += strcspn(s, crlf), s += strspn(s, crlf)) {
debugs(9, 7, HERE << "s = {" << s << "}");
- linelen = strcspn(s, Ftp::crlf) + 1;
+ linelen = strcspn(s, crlf) + 1;
if (linelen < 2)
break;
}
void
-Ftp::Gateway::dataChannelConnected(const Comm::ConnectionPointer &conn, Comm::Flag err, int xerrno)
+Ftp::Gateway::dataChannelConnected(const CommConnectCbParams &io)
{
debugs(9, 3, HERE);
data.opener = NULL;
- if (err != Comm::OK) {
+ if (io.flag != Comm::OK) {
debugs(9, 2, HERE << "Failed to connect. Retrying via another method.");
// ABORT on timeouts. server may be waiting on a broken TCP link.
- if (err == Comm::TIMEOUT)
+ if (io.xerrno == Comm::TIMEOUT)
writeCommand("ABOR");
// try another connection attempt with some other method
return;
}
- data.opened(conn, dataCloser());
+ data.opened(io.conn, dataCloser());
ftpRestOrList(this);
}
#include "client_side.h"
#include "clients/forward.h"
#include "clients/FtpClient.h"
+#include "ftp/Elements.h"
#include "ftp/Parsing.h"
#include "HttpHdrCc.h"
#include "HttpRequest.h"
/* Ftp::Client API */
virtual void failed(err_type error = ERR_NONE, int xerrno = 0);
- virtual void dataChannelConnected(const Comm::ConnectionPointer &conn, Comm::Flag err, int xerrno);
+ virtual void dataChannelConnected(const CommConnectCbParams &io);
/* ServerStateData API */
virtual void serverComplete();
void forwardReply();
void forwardError(err_type error = ERR_NONE, int xerrno = 0);
void failedErrorMessage(err_type error, int xerrno);
- HttpReply *createHttpReply(const Http::StatusCode httpStatus, const int clen = 0);
+ HttpReply *createHttpReply(const Http::StatusCode httpStatus, const int64_t clen = 0);
void handleDataRequest();
void startDataDownload();
void startDataUpload();
}
HttpReply *
-Ftp::Relay::createHttpReply(const Http::StatusCode httpStatus, const int clen)
-{
- HttpReply *const reply = new HttpReply;
- reply->sline.set(Http::ProtocolVersion(1, 1), httpStatus);
- HttpHeader &header = reply->header;
- header.putTime(HDR_DATE, squid_curtime);
- {
- HttpHdrCc cc;
- cc.Private();
- header.putCc(&cc);
- }
- if (clen >= 0)
- header.putInt64(HDR_CONTENT_LENGTH, clen);
-
+Ftp::Relay::createHttpReply(const Http::StatusCode httpStatus, const int64_t clen)
+{
+ HttpReply *const reply = Ftp::HttpReplyWrapper(ctrl.replycode, ctrl.last_reply, httpStatus, clen);
if (ctrl.message) {
for (wordlist *W = ctrl.message; W && W->next; W = W->next)
- header.putStr(HDR_FTP_PRE, httpHeaderQuoteString(W->key).c_str());
+ reply->header.putStr(HDR_FTP_PRE, httpHeaderQuoteString(W->key).c_str());
+ // no hdrCacheInit() is needed for after HDR_FTP_PRE addition
}
- if (ctrl.replycode > 0)
- header.putInt(HDR_FTP_STATUS, ctrl.replycode);
- if (ctrl.last_reply)
- header.putStr(HDR_FTP_REASON, ctrl.last_reply);
-
- reply->hdrCacheInit();
-
return reply;
}
if (serverState() == fssBegin)
serverState(fssConnected);
- // Do not forward server greeting to the client because our client
- // side code has greeted the client already. Also, a greeting may
- // confuse a client that has changed the gateway destination mid-air.
+ // Do not forward server greeting to the user because our FTP Server
+ // has greeted the user already. Also, an original origin greeting may
+ // confuse a user that has changed the origin mid-air.
start();
break;
Ftp::Relay::sendCommand()
{
if (!fwd->request->header.has(HDR_FTP_COMMAND)) {
- abortTransaction("Internal error: FTP gateway request with no command");
+ abortTransaction("Internal error: FTP relay request with no command");
return;
}
}
void
-Ftp::Relay::dataChannelConnected(const Comm::ConnectionPointer &conn, Comm::Flag err, int xerrno)
+Ftp::Relay::dataChannelConnected(const CommConnectCbParams &io)
{
debugs(9, 3, status());
data.opener = NULL;
- if (err != Comm::OK) {
+ if (io.flag != Comm::OK) {
debugs(9, 2, "failed to connect FTP server data channel");
- forwardError(ERR_CONNECT_FAIL, xerrno);
+ forwardError(ERR_CONNECT_FAIL, io.xerrno);
return;
}
- debugs(9, 2, "connected FTP server data channel: " << conn);
+ debugs(9, 2, "connected FTP server data channel: " << io.conn);
- data.opened(conn, dataCloser());
+ data.opened(io.conn, dataCloser());
sendCommand();
}
#include "squid.h"
#include "ftp/Elements.h"
+#include "HttpHdrCc.h"
+#include "HttpReply.h"
#include "SBuf.h"
+HttpReply *
+Ftp::HttpReplyWrapper(const int ftpStatus, const char *ftpReason, const Http::StatusCode httpStatus, const int64_t clen)
+{
+ HttpReply *const reply = new HttpReply;
+ reply->sline.set(Http::ProtocolVersion(1, 1), httpStatus);
+ HttpHeader &header = reply->header;
+ header.putTime(HDR_DATE, squid_curtime);
+ {
+ HttpHdrCc cc;
+ cc.Private(String());
+ header.putCc(&cc);
+ }
+ if (ftpStatus > 0)
+ header.putInt(HDR_FTP_STATUS, ftpStatus);
+ if (ftpReason)
+ header.putStr(HDR_FTP_REASON, ftpReason);
+ if (clen >= 0)
+ header.putInt64(HDR_CONTENT_LENGTH, clen);
+ reply->hdrCacheInit();
+ return reply;
+}
+
const SBuf &
Ftp::cmdAppe()
{
#ifndef SQUID_FTP_ELEMENTS_H
#define SQUID_FTP_ELEMENTS_H
+#include "http/StatusCode.h"
+
class SBuf;
+class HttpReply;
namespace Ftp {
+/// Create an internal HttpReply structure to house FTP control response info.
+HttpReply *HttpReplyWrapper(const int ftpStatus, const char *ftpReason, const Http::StatusCode httpStatus, const int64_t clen);
+
/* FTP Commands used by Squid. ALLCAPS case. Safe for static initializaton. */
const SBuf &cmdAppe();
const SBuf &cmdAuth();
// if the server control connection is gone, reset state to login again
resetLogin("control connection closure");
- // XXX: Not enough. Gateway::ServerStateData::sendCommand() will not
- // re-login because clientState() is not ConnStateData::FTP_CONNECTED.
+ // XXX: Reseting is not enough. FtpRelay::sendCommand() will not re-login
+ // because FtpRelay::serverState() is not going to be fssConnected.
}
/// clear client and server login-related state after the old login is gone
if (master.clientReadGreeting)
oldUri = uri;
- master.workingDir = NULL;
+ master.workingDir.clear();
calcUri(NULL);
if (!master.clientReadGreeting) {
assert(http != NULL);
assert(http->storeEntry() == NULL);
- HttpReply *const reply = new HttpReply;
- reply->sline.set(Http::ProtocolVersion(1, 1), Http::scNoContent);
- HttpHeader &header = reply->header;
- header.putTime(HDR_DATE, squid_curtime);
- {
- HttpHdrCc cc;
- cc.Private();
- header.putCc(&cc);
- }
- header.putInt64(HDR_CONTENT_LENGTH, 0);
- header.putInt(HDR_FTP_STATUS, code);
- header.putStr(HDR_FTP_REASON, msg);
- reply->hdrCacheInit();
+ HttpReply *const reply = Ftp::HttpReplyWrapper(code, msg, Http::scNoContent, 0);
setLogUri(http, urlCanonicalClean(http->request));
http->storeEntry()->replaceHttpReply(reply);
}
-/// Whether Squid FTP gateway supports a given feature (e.g., a command).
+/// Whether Squid FTP Relay supports a named feature (e.g., a command).
static bool
Ftp::SupportedCommand(const SBuf &name)
{
static std::set<SBuf> BlackList;
if (BlackList.empty()) {
- /* Add FTP commands that Squid cannot gateway correctly */
+ /* Add FTP commands that Squid cannot relay correctly. */
- // we probably do not support AUTH TLS.* and AUTH SSL,
- // but let's disclaim all AUTH support to KISS, for now
+ // We probably do not support AUTH TLS.* and AUTH SSL,
+ // but let's disclaim all AUTH support to KISS, for now.
BlackList.insert(cmdAuth());
}
{
public:
Ip::Address clientDataAddr; ///< address of our FTP client data connection
- SBuf workingDir;
+ SBuf workingDir; ///< estimated current working directory for URI formation
ServerState serverState; ///< what our FTP server is doing
bool clientReadGreeting; ///< whether our FTP client read their FTP server greeting