From 253caccb08f5a5a23ec0c9b89272145213c09ec0 Mon Sep 17 00:00:00 2001
From: wessels <>
Date: Thu, 26 Jan 2006 00:41:23 +0000
Subject: [PATCH] The purpose of this change is to add ICAP RESPMOD support for
FTP responses.
I created a "ServerStateData" class which has common elements of both
HttpStateData and FtpStateData. It becomes a base class for both
of them. ICAP now uses the ServerStateData methods.
---
src/ICAP/ICAPClientRespmodPrecache.cc | 38 +-
src/ICAP/ICAPClientRespmodPrecache.h | 12 +-
src/Makefile.am | 4 +-
src/ftp.cc | 522 ++++++++++++++++++++------
src/http.cc | 49 +--
src/http.h | 18 +-
6 files changed, 438 insertions(+), 205 deletions(-)
diff --git a/src/ICAP/ICAPClientRespmodPrecache.cc b/src/ICAP/ICAPClientRespmodPrecache.cc
index ed9bc50fa0..fcc6672c69 100644
--- a/src/ICAP/ICAPClientRespmodPrecache.cc
+++ b/src/ICAP/ICAPClientRespmodPrecache.cc
@@ -12,7 +12,7 @@
CBDATA_CLASS_INIT(ICAPClientRespmodPrecache);
-ICAPClientRespmodPrecache::ICAPClientRespmodPrecache(ICAPServiceRep::Pointer aService): service(aService), httpState(NULL), virgin(NULL), adapted(NULL)
+ICAPClientRespmodPrecache::ICAPClientRespmodPrecache(ICAPServiceRep::Pointer aService): service(aService), serverState(NULL), virgin(NULL), adapted(NULL)
{
debug(93,5)("ICAPClientRespmodPrecache constructed, this=%p\n", this);
}
@@ -20,7 +20,7 @@ ICAPClientRespmodPrecache::ICAPClientRespmodPrecache(ICAPServiceRep::Pointer aSe
ICAPClientRespmodPrecache::~ICAPClientRespmodPrecache()
{
stop(notifyNone);
- cbdataReferenceDone(httpState);
+ cbdataReferenceDone(serverState);
debug(93,5)("ICAPClientRespmodPrecache destructed, this=%p\n", this);
if (virgin != NULL)
@@ -32,9 +32,9 @@ ICAPClientRespmodPrecache::~ICAPClientRespmodPrecache()
service = NULL;
}
-void ICAPClientRespmodPrecache::startRespMod(HttpStateData *anHttpState, HttpRequest *request, HttpReply *reply)
+void ICAPClientRespmodPrecache::startRespMod(ServerStateData *anServerState, HttpRequest *request, HttpReply *reply)
{
- httpState = cbdataReference(anHttpState);
+ serverState = cbdataReference(anServerState);
virgin = new MsgPipe("virgin"); // this is the place to create a refcount ptr
virgin->source = this;
@@ -62,6 +62,8 @@ void ICAPClientRespmodPrecache::startRespMod(HttpStateData *anHttpState, HttpReq
void ICAPClientRespmodPrecache::sendMoreData(StoreIOBuffer buf)
{
debug(93,5)("ICAPClientRespmodPrecache::sendMoreData() called\n");
+ //debugs(93,0,HERE << "appending " << buf.length << " bytes");
+ //debugs(93,0,HERE << "body.contentSize = " << virgin->data->body->contentSize());
//buf.dump();
/*
* The caller is responsible for not giving us more data
@@ -81,7 +83,7 @@ ICAPClientRespmodPrecache::potentialSpaceSize()
return (int) virgin->data->body->potentialSpaceSize();
}
-// HttpStateData says we have the entire HTTP message
+// ServerStateData says we have the entire HTTP message
void ICAPClientRespmodPrecache::doneSending()
{
debug(93,5)("ICAPClientRespmodPrecache::doneSending() called\n");
@@ -98,7 +100,7 @@ void ICAPClientRespmodPrecache::doneSending()
#endif
}
-// HttpStateData tells us to abort
+// ServerStateData tells us to abort
void ICAPClientRespmodPrecache::ownerAbort()
{
debug(93,5)("ICAPClientRespmodPrecache::ownerAbort() called\n");
@@ -111,7 +113,7 @@ void ICAPClientRespmodPrecache::noteSinkNeed(MsgPipe *p)
debug(93,5)("ICAPClientRespmodPrecache::noteSinkNeed() called\n");
if (virgin->data->body->potentialSpaceSize())
- httpState->icapSpaceAvailable();
+ serverState->icapSpaceAvailable();
}
// ICAP client aborting
@@ -144,7 +146,7 @@ void ICAPClientRespmodPrecache::noteSourceStart(MsgPipe *p)
ssize_t dummy;
bool expect_body = reply->expectingBody(virgin->data->cause->method, dummy);
- httpState->takeAdaptedHeaders(reply);
+ serverState->takeAdaptedHeaders(reply);
if (expect_body)
noteSourceProgress(p);
@@ -156,10 +158,12 @@ void ICAPClientRespmodPrecache::noteSourceStart(MsgPipe *p)
void ICAPClientRespmodPrecache::noteSourceProgress(MsgPipe *p)
{
debug(93,5)("ICAPClientRespmodPrecache::noteSourceProgress() called\n");
- //tell HttpStateData to store a fresh portion of the adapted response
+ //tell ServerStateData to store a fresh portion of the adapted response
+
+ assert(serverState);
if (p->data->body->hasContent()) {
- httpState->takeAdaptedBody(p->data->body);
+ serverState->takeAdaptedBody(p->data->body);
}
}
@@ -167,8 +171,8 @@ void ICAPClientRespmodPrecache::noteSourceProgress(MsgPipe *p)
void ICAPClientRespmodPrecache::noteSourceFinish(MsgPipe *p)
{
debug(93,5)("ICAPClientRespmodPrecache::noteSourceFinish() called\n");
- //tell HttpStateData that we expect no more response data
- httpState->doneAdapting();
+ //tell ServerStateData that we expect no more response data
+ serverState->doneAdapting();
stop(notifyNone);
}
@@ -200,14 +204,14 @@ void ICAPClientRespmodPrecache::stop(Notify notify)
freeAdapted();
}
- if (httpState) {
+ if (serverState) {
if (notify == notifyOwner)
- // tell HttpStateData that we are aborting prematurely
- httpState->abortAdapting();
+ // tell ServerStateData that we are aborting prematurely
+ serverState->abortAdapting();
- cbdataReferenceDone(httpState);
+ cbdataReferenceDone(serverState);
- // httpState is now NULL, will not call it any more
+ // serverState is now NULL, will not call it any more
}
}
diff --git a/src/ICAP/ICAPClientRespmodPrecache.h b/src/ICAP/ICAPClientRespmodPrecache.h
index f8e165a1d7..e13324ddb0 100644
--- a/src/ICAP/ICAPClientRespmodPrecache.h
+++ b/src/ICAP/ICAPClientRespmodPrecache.h
@@ -1,6 +1,6 @@
/*
- * $Id: ICAPClientRespmodPrecache.h,v 1.2 2005/12/22 22:26:31 wessels Exp $
+ * $Id: ICAPClientRespmodPrecache.h,v 1.3 2006/01/25 17:41:23 wessels Exp $
*
*
* SQUID Web Proxy Cache http://www.squid-cache.org/
@@ -40,10 +40,10 @@
#include "ICAPServiceRep.h"
/* The ICAP Anchor implements message pipe sink and source interfaces. It
- * helps HttpStateData to marshall the incoming/virgin HTTP message (being
+ * helps ServerStateData to marshall the incoming/virgin HTTP message (being
* recieved from the HTTP server) to Squid's ICAP client module, using the
* MsgPipe interface. The same interface is used to get the adapted HTTP
- * message back from the ICAP client. HttpStateData is the "owner" of the
+ * message back from the ICAP client. ServerStateData is the "owner" of the
* ICAPClientRespmodPrecache.
*/
@@ -58,8 +58,8 @@ public:
ICAPClientRespmodPrecache(ICAPServiceRep::Pointer);
virtual ~ICAPClientRespmodPrecache();
- // synchronous calls called by HttpStateData
- void startRespMod(HttpStateData *anHttpState, HttpRequest *request, HttpReply *reply);
+ // synchronous calls called by ServerStateData
+ void startRespMod(ServerStateData *anServerState, HttpRequest *request, HttpReply *reply);
void sendMoreData(StoreIOBuffer buf);
void doneSending();
void ownerAbort();
@@ -77,7 +77,7 @@ public:
public:
ICAPServiceRep::Pointer service;
- HttpStateData *httpState;
+ ServerStateData *serverState;
MsgPipe::Pointer virgin;
MsgPipe::Pointer adapted;
diff --git a/src/Makefile.am b/src/Makefile.am
index 78453d7d7f..504f812e70 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,7 +1,7 @@
#
# Makefile for the Squid Object Cache server
#
-# $Id: Makefile.am,v 1.126 2006/01/14 00:06:19 wessels Exp $
+# $Id: Makefile.am,v 1.127 2006/01/25 17:41:23 wessels Exp $
#
# Uncomment and customize the following to suit your needs:
#
@@ -523,6 +523,8 @@ squid_SOURCES = \
StoreSearch.h \
StoreSwapLogData.cc \
StoreSwapLogData.h \
+ Server.h \
+ Server.cc \
structs.h \
SwapDir.cc \
SwapDir.h \
diff --git a/src/ftp.cc b/src/ftp.cc
index a27b9fbde0..8a14da8712 100644
--- a/src/ftp.cc
+++ b/src/ftp.cc
@@ -1,6 +1,6 @@
/*
- * $Id: ftp.cc,v 1.381 2006/01/24 17:40:11 wessels Exp $
+ * $Id: ftp.cc,v 1.382 2006/01/25 17:41:23 wessels Exp $
*
* DEBUG: section 9 File Transfer Protocol (FTP)
* AUTHOR: Harvest Derived
@@ -48,6 +48,15 @@
#endif
#include "ConnectionDetail.h"
#include "forward.h"
+#include "Server.h"
+#include "MemBuf.h"
+
+#if ICAP_CLIENT
+#include "ICAP/ICAPClientRespmodPrecache.h"
+#include "ICAP/ICAPConfig.h"
+extern ICAPConfig TheICAPConfig;
+static void icapAclCheckDoneWrapper(ICAPServiceRep::Pointer service, void *data);
+#endif
static const char *const crlf = "\r\n";
static char cbuf[1024];
@@ -93,12 +102,13 @@ struct _ftp_flags
bool put;
bool put_mkdir;
bool listformat_unknown;
+ bool listing_started;
};
class FtpStateData;
typedef void (FTPSM) (FtpStateData *);
-class FtpStateData
+class FtpStateData : public ServerStateData
{
public:
@@ -106,8 +116,6 @@ public:
void operator delete (void *);
FtpStateData(FwdState *);
~FtpStateData();
- StoreEntry *entry;
- HttpRequest *request;
char user[MAX_URL];
char password[MAX_URL];
int password_url;
@@ -152,22 +160,21 @@ public:
struct
{
int fd;
- char *buf;
- size_t size;
- off_t offset;
+ MemBuf *readBuf;
char *host;
u_short port;
+ bool read_pending;
}
data;
struct _ftp_flags flags;
- FwdState::Pointer fwd;
private:
CBDATA_CLASS(FtpStateData);
public:
+ // these should all be private
void start();
void loginParser(const char *, int escaped);
int restartable();
@@ -187,6 +194,11 @@ public:
int checkAuth(const HttpHeader * req_hdr);
void checkUrlpath();
void buildTitleUrl();
+ void writeReplyBody(const char *, int len);
+ void printfReplyBody(const char *fmt, ...);
+ void maybeReadData();
+ void transactionComplete();
+ void processReplyBody();
static PF ftpSocketClosed;
static CNCB ftpPasvCallback;
@@ -199,6 +211,19 @@ public:
static HttpReply *ftpAuthRequired(HttpRequest * request, const char *realm);
static void ftpRequestBody(char *buf, ssize_t size, void *data);
static wordlist *ftpParseControlReply(char *, size_t, int *, int *);
+
+#if ICAP_CLIENT
+
+public:
+ void icapAclCheckDone(ICAPServiceRep::Pointer);
+ void takeAdaptedHeaders(HttpReply *);
+ void takeAdaptedBody(MemBuf *);
+ void doneAdapting();
+ void abortAdapting();
+ void icapSpaceAvailable();
+ bool icapAccessCheckPending;
+#endif
+
};
CBDATA_CLASS_INIT(FtpStateData);
@@ -336,18 +361,12 @@ FtpStateData::ftpSocketClosed(int fdnotused, void *data)
delete ftpState;
}
-FtpStateData::FtpStateData(FwdState *theFwdState)
+FtpStateData::FtpStateData(FwdState *theFwdState) : ServerStateData(theFwdState)
{
- request = theFwdState->request;
- entry = theFwdState->entry;
- storeLockObject(entry);
- fwd = theFwdState;
const char *url = storeUrl(entry);
-
debug(9, 3) ("ftpStart: '%s'\n", url);
statCounter.server.all.requests++;
statCounter.server.ftp.requests++;
- request = requestLink(request);
ctrl.fd = theFwdState->server_fd;
data.fd = -1;
size = -1;
@@ -370,15 +389,11 @@ FtpStateData::~FtpStateData()
storeUnregisterAbort(entry);
- storeUnlockObject(entry);
-
if (reply_hdr) {
memFree(reply_hdr, MEM_8K_BUF);
reply_hdr = NULL;
}
- requestUnlink(request);
-
if (data.fd > -1) {
int fd = data.fd;
data.fd = -1;
@@ -390,10 +405,10 @@ FtpStateData::~FtpStateData()
ctrl.buf = NULL;
}
- if (data.buf) {
- memFreeBuf(data.size, data.buf);
- data.buf = NULL;
- }
+ if (!data.readBuf->isNull())
+ data.readBuf->clean();
+
+ delete data.readBuf;
if (pathcomps)
wordlistDestroy(&pathcomps);
@@ -474,108 +489,111 @@ FtpStateData::ftpTimeout(int fd, void *data)
void
FtpStateData::listingStart()
{
+ debugs(9,3,HERE << "listingStart()");
wordlist *w;
char *dirup;
int i, j, k;
const char *title = title_url.buf();
- storeAppendPrintf(entry, "\n");
- storeAppendPrintf(entry, "\n",
- version_string);
- storeAppendPrintf(entry, "\n", mkrfc1123(squid_curtime));
- storeAppendPrintf(entry, "
\n");
+ flags.listing_started = true;
+ printfReplyBody("\n");
+ printfReplyBody("\n",
+ version_string);
+ printfReplyBody("\n", mkrfc1123(squid_curtime));
+ printfReplyBody("\n");
{
char *t = xstrdup(title);
rfc1738_unescape(t);
- storeAppendPrintf(entry, "FTP Directory: %s\n", html_quote(t));
+ printfReplyBody("FTP Directory: %s\n", html_quote(t));
xfree(t);
}
- storeAppendPrintf(entry, "\n");
- storeAppendPrintf(entry, "\n");
+ printfReplyBody("\n");
+ printfReplyBody("\n");
if (flags.need_base_href)
- storeAppendPrintf(entry, "\n",
- html_quote(base_href.buf()));
+ printfReplyBody("\n",
+ html_quote(base_href.buf()));
- storeAppendPrintf(entry, "\n");
+ printfReplyBody("\n");
if (cwd_message) {
- storeAppendPrintf(entry, "\n");
+ printfReplyBody("\n");
for (w = cwd_message; w; w = w->next)
- storeAppendPrintf(entry, "%s\n", html_quote(w->key));
+ printfReplyBody("%s\n", html_quote(w->key));
- storeAppendPrintf(entry, "
\n");
+ printfReplyBody("
\n");
- storeAppendPrintf(entry, "
\n");
+ printfReplyBody("
\n");
wordlistDestroy(&cwd_message);
}
- storeAppendPrintf(entry, "\n");
+ printfReplyBody("\n");
dirup = htmlifyListEntry("");
- storeAppend(entry, dirup, strlen(dirup));
+ writeReplyBody(dirup, strlen(dirup));
flags.html_header_sent = 1;
}
void
FtpStateData::listingFinish()
{
+ debugs(9,3,HERE << "listingFinish()");
storeBuffer(entry);
- storeAppendPrintf(entry, "
\n");
+ printfReplyBody("\n");
if (flags.listformat_unknown && !flags.tried_nlst) {
- storeAppendPrintf(entry, "[As plain directory]\n",
- flags.dir_slash ? rfc1738_escape_part(old_filepath) : ".");
+ printfReplyBody("[As plain directory]\n",
+ flags.dir_slash ? rfc1738_escape_part(old_filepath) : ".");
} else if (typecode == 'D') {
const char *path = flags.dir_slash ? filepath : ".";
- storeAppendPrintf(entry, "[As extended directory]\n", html_quote(path));
+ printfReplyBody("[As extended directory]\n", html_quote(path));
}
- storeAppendPrintf(entry, "
\n");
- storeAppendPrintf(entry, "\n");
- storeAppendPrintf(entry, "Generated %s by %s (%s)\n",
- mkrfc1123(squid_curtime),
- getMyHostname(),
- visible_appname_string);
- storeAppendPrintf(entry, "\n");
+ printfReplyBody("
\n");
+ printfReplyBody("\n");
+ printfReplyBody("Generated %s by %s (%s)\n",
+ mkrfc1123(squid_curtime),
+ getMyHostname(),
+ visible_appname_string);
+ printfReplyBody("\n");
}
static const char *Month[] =
@@ -1061,7 +1079,7 @@ FtpStateData::htmlifyListEntry(const char *line)
void
FtpStateData::parseListing()
{
- char *buf = data.buf;
+ char *buf = data.readBuf->content();
char *sbuf; /* NULL-terminated copy of buf */
char *end;
char *line;
@@ -1070,7 +1088,7 @@ FtpStateData::parseListing()
size_t linelen;
size_t usable;
StoreEntry *e = entry;
- size_t len = data.offset;
+ size_t len = data.readBuf->contentSize();
/*
* We need a NULL-terminated buffer for scanning, ick
*/
@@ -1119,25 +1137,22 @@ FtpStateData::parseListing()
assert(t != NULL);
- storeAppend(e, t, strlen(t));
- }
-
- assert(usable <= len);
-
- if (usable < len) {
- /* must copy partial line to beginning of buf */
- linelen = len - usable;
-
- if (linelen > 4096)
- linelen = 4096;
+#if ICAP_CLIENT
- xstrncpy(line, end, linelen);
+ if (icap) {
+ if ((int)strlen(t) > icap->potentialSpaceSize()) {
+ debugs(0,0,HERE << "WARNING avoid overwhelming ICAP with data!");
+ usable = s - sbuf;
+ break;
+ }
+ }
- xstrncpy(data.buf, line, data.size);
+#endif
- data.offset = strlen(data.buf);
+ writeReplyBody(t, strlen(t));
}
+ data.readBuf->consume(usable);
memFree(line, MEM_4K_BUF);
xfree(sbuf);
}
@@ -1165,17 +1180,51 @@ void
FtpStateData::dataReadWrapper(int fd, char *buf, size_t len, comm_err_t errflag, int xerrno, void *data)
{
FtpStateData *ftpState = (FtpStateData *)data;
+ ftpState->data.read_pending = false;
ftpState->dataRead(fd, buf, len, errflag, xerrno);
}
+void
+FtpStateData::maybeReadData()
+{
+ if (data.fd < 0)
+ return;
+
+ if (data.read_pending)
+ return;
+
+ int read_sz = data.readBuf->spaceSize();
+
+#if ICAP_CLIENT
+
+ if (icap) {
+ int icap_space = icap->potentialSpaceSize();
+
+ if (icap_space < read_sz)
+ read_sz = icap_space;
+ }
+
+#endif
+
+ debugs(11,9, HERE << "FTP may read up to " << read_sz << " bytes");
+
+ if (read_sz < 2) // see http.cc
+ return;
+
+ data.read_pending = true;
+
+ debugs(9,5,HERE << "queueing read on FD " << data.fd);
+
+ entry->delayAwareRead(data.fd, data.readBuf->space(), read_sz, dataReadWrapper, this);
+}
+
void
FtpStateData::dataRead(int fd, char *buf, size_t len, comm_err_t errflag, int xerrno)
{
int j;
int bin;
- size_t read_sz;
- debug(9, 5) ("ftpDataRead: FD %d, Read %d bytes\n", fd, (unsigned int)len);
+ debugs(9, 3, HERE << "ftpDataRead: FD " << fd << " Read " << len << " bytes");
if (len > 0) {
kb_incr(&statCounter.server.all.kbytes_in, len);
@@ -1203,11 +1252,18 @@ FtpStateData::dataRead(int fd, char *buf, size_t len, comm_err_t errflag, int xe
delayId.bytesIn(len);
#endif
- data.offset += len;
}
if (errflag == COMM_OK && len > 0) {
+ debugs(9,5,HERE << "appended " << len << " bytes to readBuf");
+ data.readBuf->appended(len);
+#if DELAY_POOLS
+
+ DelayId delayId = entry->mem_obj->mostBytesAllowed();
+ delayId.bytesIn(len);
+#endif
+
IOStats.Ftp.reads++;
for (j = len - 1, bin = 0; j; bin++)
@@ -1216,25 +1272,12 @@ FtpStateData::dataRead(int fd, char *buf, size_t len, comm_err_t errflag, int xe
IOStats.Ftp.read_hist[bin]++;
}
- if (!flags.http_header_sent && len >= 0) {
- appendSuccessHeader();
-
- if (flags.isdir)
- listingStart();
- }
-
if (errflag != COMM_OK || len < 0) {
debug(50, ignoreErrno(xerrno) ? 3 : 1) ("ftpDataRead: read error: %s\n", xstrerr(xerrno));
if (ignoreErrno(xerrno)) {
/* XXX what about Config.Timeout.read? */
- read_sz = data.size - data.offset;
-#if DELAY_POOLS
-
- read_sz = delayId.bytesWanted(1, read_sz);
-#endif
-
- comm_read(fd, data.buf + data.offset, read_sz, dataReadWrapper, this);
+ maybeReadData();
} else {
if (!flags.http_header_sent && !fwd->ftpPasvFailed() && flags.pasv_supported) {
fwd->dontRetry(false); /* this is a retryable error */
@@ -1247,27 +1290,41 @@ FtpStateData::dataRead(int fd, char *buf, size_t len, comm_err_t errflag, int xe
}
} else if (len == 0) {
dataComplete();
- } else {
- if (flags.isdir) {
- parseListing();
- } else {
- storeAppend(entry, data.buf, len);
- data.offset = 0;
- }
+ }
- storeBufferFlush(entry);
+ processReplyBody();
+}
- /* XXX what about Config.Timeout.read? */
- read_sz = data.size - data.offset;
+void
+FtpStateData::processReplyBody()
+{
+ if (!flags.http_header_sent && data.readBuf->contentSize() >= 0)
+ appendSuccessHeader();
-#if DELAY_POOLS
+#if ICAP_CLIENT
- read_sz = delayId.bytesWanted(1, read_sz);
+ if (icapAccessCheckPending) {
+ debugs(9,3,HERE << "returning from dataRead due to icapAccessCheckPending");
+ return;
+ }
#endif
- comm_read(fd, data.buf + data.offset, read_sz, dataReadWrapper, this);
+ if (flags.isdir && !flags.listing_started)
+ listingStart();
+
+ if (flags.isdir) {
+ parseListing();
+ } else {
+ writeReplyBody(data.readBuf->content(), data.readBuf->contentSize());
+ debugs(9,5,HERE << "consuming " << data.readBuf->contentSize() << " bytes of readBuf");
+ data.readBuf->consume(data.readBuf->contentSize());
}
+
+ storeBufferFlush(entry);
+
+ /* XXX what about Config.Timeout.read? */
+ maybeReadData();
}
/*
@@ -1429,7 +1486,8 @@ FtpStateData::start()
ctrl.last_command = xstrdup("Connect to server");
ctrl.buf = (char *)memAllocBuf(4096, &ctrl.size);
ctrl.offset = 0;
- data.buf = (char *)memAllocBuf(SQUID_TCP_SO_RCVBUF, &data.size);
+ data.readBuf = new MemBuf;
+ data.readBuf->init(4096, SQUID_TCP_SO_RCVBUF);
scheduleReadControlReply(0);
}
@@ -2611,8 +2669,7 @@ ftpReadList(FtpStateData * ftpState)
if (code == 125 || (code == 150 && ftpState->data.host)) {
/* Begin data transfer */
/* XXX what about Config.Timeout.read? */
- assert(ftpState->data.offset == 0);
- ftpState->entry->delayAwareRead(ftpState->data.fd, ftpState->data.buf, ftpState->data.size, FtpStateData::dataReadWrapper, ftpState);
+ ftpState->maybeReadData();
ftpState->state = READING_DATA;
/*
* Cancel the timeout on the Control socket and establish one
@@ -2658,10 +2715,7 @@ ftpReadRetr(FtpStateData * ftpState)
/* Begin data transfer */
debug(9, 3) ("ftpReadRetr: reading data channel\n");
/* XXX what about Config.Timeout.read? */
- size_t read_sz = ftpState->data.size - ftpState->data.offset;
-
- ftpState->entry->delayAwareRead(ftpState->data.fd, ftpState->data.buf + ftpState->data.offset, read_sz, FtpStateData::dataReadWrapper, ftpState);
-
+ ftpState->maybeReadData();
ftpState->state = READING_DATA;
/*
* Cancel the timeout on the Control socket and establish one
@@ -2704,11 +2758,7 @@ ftpReadTransferDone(FtpStateData * ftpState)
if (ftpState->flags.html_header_sent)
ftpState->listingFinish();
- ftpState->fwd->unregister(ftpState->ctrl.fd);
-
- ftpState->fwd->complete();
-
- ftpSendQuit(ftpState);
+ ftpState->transactionComplete();
} else { /* != 226 */
debug(9, 1) ("ftpReadTransferDone: Got code %d after reading data\n",
code);
@@ -2724,7 +2774,6 @@ FtpStateData::ftpRequestBody(char *buf, ssize_t size, void *data)
{
FtpStateData *ftpState = (FtpStateData *) data;
debug(9, 3) ("ftpRequestBody: buf=%p size=%d ftpState=%p\n", buf, (int) size, data);
- ftpState->data.offset = size;
if (size > 0) {
/* DataWrite */
@@ -2750,7 +2799,11 @@ FtpStateData::ftpDataWriteCallback(int fd, char *buf, size_t size, comm_err_t er
if (!err) {
/* Shedule the rest of the request */
- clientReadBody(ftpState->request, ftpState->data.buf, ftpState->data.size, ftpRequestBody, ftpState);
+ clientReadBody(ftpState->request,
+ ftpState->data.readBuf->content(),
+ ftpState->data.readBuf->contentSize(),
+ ftpRequestBody,
+ ftpState);
} else {
debug(9, 1) ("ftpDataWriteCallback: write error: %s\n", xstrerr(xerrno));
ftpState->failed(ERR_WRITE_ERROR, xerrno);
@@ -2763,7 +2816,11 @@ FtpStateData::ftpDataWrite(int ftp, void *data)
FtpStateData *ftpState = (FtpStateData *) data;
debug(9, 3) ("ftpDataWrite\n");
/* This starts the body transfer */
- clientReadBody(ftpState->request, ftpState->data.buf, ftpState->data.size, ftpRequestBody, ftpState);
+ clientReadBody(ftpState->request,
+ ftpState->data.readBuf->content(),
+ ftpState->data.readBuf->contentSize(),
+ ftpRequestBody,
+ ftpState);
}
static void
@@ -3032,7 +3089,11 @@ FtpStateData::appendSuccessHeader()
const char *filename = NULL;
const char *t = NULL;
StoreEntry *e = entry;
- HttpReply *reply = new HttpReply;
+ HttpReply *newrep = new HttpReply;
+
+ reply = newrep->lock()
+
+ ;
if (flags.http_header_sent)
return;
@@ -3090,6 +3151,23 @@ FtpStateData::appendSuccessHeader()
if (mime_enc)
httpHeaderPutStr(&reply->header, HDR_CONTENT_ENCODING, mime_enc);
+#if ICAP_CLIENT
+
+ if (TheICAPConfig.onoff) {
+ ICAPAccessCheck *icap_access_check = new ICAPAccessCheck(ICAP::methodRespmod,
+ ICAP::pointPreCache,
+ request,
+ reply,
+ icapAclCheckDoneWrapper,
+ this);
+
+ icapAccessCheckPending = true;
+ icap_access_check->check(); // will eventually delete self
+ return;
+ }
+
+#endif
+
storeEntryReplaceObject(e, reply);
storeTimestampsSet(e);
@@ -3157,3 +3235,197 @@ ftpUrlWith2f(const HttpRequest * request)
return buf;
}
+
+void
+FtpStateData::printfReplyBody(const char *fmt, ...)
+{
+ va_list args;
+ va_start (args, fmt);
+ static char buf[4096];
+ buf[0] = '\0';
+ vsnprintf(buf, 4096, fmt, args);
+ writeReplyBody(buf, strlen(buf));
+}
+
+/*
+ * Call this when there is data from the origin server
+ * which should be sent to either StoreEntry, or to ICAP...
+ */
+void
+FtpStateData::writeReplyBody(const char *data, int len)
+{
+#if ICAP_CLIENT
+
+ if (icap) {
+ debugs(9,5,HERE << "writing " << len << " bytes to ICAP");
+ icap->sendMoreData (StoreIOBuffer(len, 0, (char*)data));
+ return;
+ }
+
+#endif
+
+ debugs(9,5,HERE << "writing " << len << " bytes to StoreEntry");
+
+ storeAppend(entry, data, len);
+}
+
+
+void
+FtpStateData::transactionComplete()
+{
+ debugs(9,5,HERE << "transactionComplete FD " << ctrl.fd << " this " << this);
+
+ fwd->unregister(ctrl.fd);
+
+ ftpSendQuit(this);
+
+#if ICAP_CLIENT
+
+ if (icap) {
+ icap->doneSending();
+ return;
+ }
+
+#endif
+
+ fwd->complete();
+}
+
+#if ICAP_CLIENT
+
+static void
+icapAclCheckDoneWrapper(ICAPServiceRep::Pointer service, void *data)
+{
+ FtpStateData *ftpState = (FtpStateData *)data;
+ ftpState->icapAclCheckDone(service);
+}
+
+void
+FtpStateData::icapAclCheckDone(ICAPServiceRep::Pointer service)
+{
+ icapAccessCheckPending = false;
+
+ if (service == NULL) {
+ // handle case where no service is selected;
+ debugs(0,0,HERE << "write me");
+ processReplyBody();
+ return;
+ }
+
+ if (doIcap(service) < 0) {
+ /*
+ * XXX Maybe instead of an error page we should
+ * handle the reply normally (without ICAP).
+ */
+ ErrorState *err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
+ err->xerrno = errno;
+ err->request = requestLink(request);
+ errorAppendEntry(entry, err);
+ comm_close(ctrl.fd);
+ return;
+ }
+
+ icap->startRespMod(this, request, reply);
+ processReplyBody();
+}
+
+/*
+ * Called by ICAPClientRespmodPrecache when it has space available for us.
+ */
+void
+FtpStateData::icapSpaceAvailable()
+{
+ debug(11,5)("FtpStateData::icapSpaceAvailable() called\n");
+ maybeReadData();
+}
+
+void
+FtpStateData::takeAdaptedHeaders(HttpReply *rep)
+{
+ debug(11,5)("FtpStateData::takeAdaptedHeaders() called\n");
+
+ if (!entry->isAccepting()) {
+ debug(11,5)("\toops, entry is not Accepting!\n");
+ icap->ownerAbort();
+ return;
+ }
+
+ assert (rep);
+ storeEntryReplaceObject(entry, rep);
+ reply->unlock();
+
+ reply = rep->lock()
+
+ ;
+
+ debug(11,5)("FtpStateData::takeAdaptedHeaders() finished\n");
+}
+
+void
+FtpStateData::takeAdaptedBody(MemBuf *buf)
+{
+ debug(11,5)("FtpStateData::takeAdaptedBody() called\n");
+ debug(11,5)("\t%d bytes\n", (int) buf->contentSize());
+
+ if (!entry->isAccepting()) {
+ debug(11,5)("\toops, entry is not Accepting!\n");
+ icap->ownerAbort();
+ return;
+ }
+
+ storeAppend(entry, buf->content(), buf->contentSize());
+ buf->consume(buf->contentSize()); // consume everything written
+}
+
+void
+FtpStateData::doneAdapting()
+{
+ debug(11,5)("FtpStateData::doneAdapting() called\n");
+
+ if (!entry->isAccepting()) {
+ debug(11,5)("\toops, entry is not Accepting!\n");
+ icap->ownerAbort();
+ } else {
+ fwd->complete();
+ }
+
+ /*
+ * ICAP is done, so we don't need this any more.
+ */
+ delete icap;
+
+ cbdataReferenceDone(icap);
+
+ if (ctrl.fd >= 0)
+ comm_close(ctrl.fd);
+ else
+ delete this;
+}
+
+void
+FtpStateData::abortAdapting()
+{
+ debug(11,5)("FtpStateData::abortAdapting() called\n");
+
+ /*
+ * ICAP has given up, we're done with it too
+ */
+ delete icap;
+ cbdataReferenceDone(icap);
+
+ if (entry->isEmpty()) {
+ ErrorState *err;
+ err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
+ err->request = requestLink((HttpRequest *) request);
+ err->xerrno = errno;
+ fwd->fail(err);
+ fwd->dontRetry(true);
+ }
+
+ if (ctrl.fd >= 0)
+ comm_close(ctrl.fd);
+ else
+ delete this;
+}
+
+#endif
diff --git a/src/http.cc b/src/http.cc
index 9cc390508a..7d1769241a 100644
--- a/src/http.cc
+++ b/src/http.cc
@@ -1,6 +1,6 @@
/*
- * $Id: http.cc,v 1.483 2006/01/23 20:04:24 wessels Exp $
+ * $Id: http.cc,v 1.484 2006/01/25 17:41:23 wessels Exp $
*
* DEBUG: section 11 Hypertext Transfer Protocol (HTTP)
* AUTHOR: Harvest Derived
@@ -74,14 +74,11 @@ static void copyOneHeaderFromClientsideRequestToUpstreamRequest(const HttpHeader
static void icapAclCheckDoneWrapper(ICAPServiceRep::Pointer service, void *data);
#endif
-HttpStateData::HttpStateData(FwdState *theFwdState)
+HttpStateData::HttpStateData(FwdState *theFwdState) : ServerStateData(theFwdState)
{
debugs(11,5,HERE << "HttpStateData " << this << " created");
ignoreCacheControl = false;
surrogateNoStore = false;
- fwd = theFwdState;
- entry = fwd->entry;
- storeLockObject(entry);
fd = fwd->server_fd;
readBuf = new MemBuf;
readBuf->init(4096, SQUID_TCP_SO_RCVBUF);
@@ -111,6 +108,8 @@ HttpStateData::HttpStateData(FwdState *theFwdState)
proxy_req->flags.proxying = 1;
+ requestUnlink(request);
+
request = requestLink(proxy_req);
/*
@@ -127,8 +126,6 @@ HttpStateData::HttpStateData(FwdState *theFwdState)
#endif
- } else {
- request = requestLink(orig_request);
}
/*
@@ -139,6 +136,10 @@ HttpStateData::HttpStateData(FwdState *theFwdState)
HttpStateData::~HttpStateData()
{
+ /*
+ * don't forget about ~ServerStateData()
+ */
+
if (request_body_buf) {
if (orig_request->body_connection.getRaw()) {
clientAbortBody(orig_request);
@@ -150,34 +151,15 @@ HttpStateData::~HttpStateData()
}
}
- storeUnlockObject(entry);
-
if (!readBuf->isNull())
readBuf->clean();
delete readBuf;
- requestUnlink(request);
-
requestUnlink(orig_request);
- request = NULL;
-
orig_request = NULL;
- fwd = NULL; // refcounted
-
- if (reply)
- reply->unlock();
-
-#if ICAP_CLIENT
-
- if (icap) {
- delete icap;
- cbdataReferenceDone(icap);
- }
-
-#endif
debugs(11,5,HERE << "HttpStateData " << this << " destroyed");
}
@@ -2042,21 +2024,6 @@ HttpStateData::icapAclCheckDone(ICAPServiceRep::Pointer service)
processReplyBody();
}
-/*
- * Initiate an ICAP transaction. Return 0 if all is well, or -1 upon error.
- * Caller will handle error condition by generating a Squid error message
- * or take other action.
- */
-int
-HttpStateData::doIcap(ICAPServiceRep::Pointer service)
-{
- debug(11,5)("HttpStateData::doIcap() called\n");
- assert(NULL == icap);
- icap = new ICAPClientRespmodPrecache(service);
- (void) cbdataReference(icap);
- return 0;
-}
-
/*
* Called by ICAPClientRespmodPrecache when it has space available for us.
*/
diff --git a/src/http.h b/src/http.h
index cd9dc822b4..7868944eb8 100644
--- a/src/http.h
+++ b/src/http.h
@@ -1,6 +1,6 @@
/*
- * $Id: http.h,v 1.19 2006/01/23 20:04:24 wessels Exp $
+ * $Id: http.h,v 1.20 2006/01/25 17:41:23 wessels Exp $
*
*
* SQUID Web Proxy Cache http://www.squid-cache.org/
@@ -37,6 +37,7 @@
#include "StoreIOBuffer.h"
#include "comm.h"
#include "forward.h"
+#include "Server.h"
#if ICAP_CLIENT
#include "ICAP/ICAPServiceRep.h"
@@ -46,7 +47,7 @@ class ICAPClientRespmodPrecache;
class ICAPAccessCheck;
#endif
-class HttpStateData
+class HttpStateData : public ServerStateData
{
public:
@@ -79,14 +80,11 @@ public:
void icapSpaceAvailable();
#endif
- StoreEntry *entry;
- HttpRequest *request;
peer *_peer; /* peer request made to */
int eof; /* reached end-of-object? */
HttpRequest *orig_request;
int fd;
http_state_flags flags;
- FwdState::Pointer fwd;
char *request_body_buf;
off_t currentOffset;
size_t read_sz;
@@ -115,12 +113,6 @@ const HttpReply * getReply() const { return reply ? reply : entry->getReply(); }
#endif
private:
- /*
- * HttpReply is now shared (locked) among multiple classes,
- * including HttpStateData, StoreEntry, and ICAP.
- */
- HttpReply *reply;
-
enum ConnectionStatus {
INCOMPLETE_MSG,
COMPLETE_PERSISTENT_MSG,
@@ -143,10 +135,6 @@ private:
MemBuf * mb,
http_state_flags flags);
static bool decideIfWeDoRanges (HttpRequest * orig_request);
-#if ICAP_CLIENT
-
- int doIcap(ICAPServiceRep::Pointer);
-#endif
private:
CBDATA_CLASS2(HttpStateData);
--
2.39.5