]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
The purpose of this change is to add ICAP RESPMOD support for FTP responses.
authorwessels <>
Thu, 26 Jan 2006 00:41:23 +0000 (00:41 +0000)
committerwessels <>
Thu, 26 Jan 2006 00:41:23 +0000 (00:41 +0000)
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
src/ICAP/ICAPClientRespmodPrecache.h
src/Makefile.am
src/ftp.cc
src/http.cc
src/http.h

index ed9bc50fa06284e6abbf08d29011c93620fc2a97..fcc6672c6947755aa7ab9e4febbdf1e5b58550d4 100644 (file)
@@ -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
     }
 }
 
index f8e165a1d7261099dcd555234cfaa726ec041da8..e13324ddb013af8fb25d47a9e949371756360e5a 100644 (file)
@@ -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/
 #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;
 
index 78453d7d7f8ad8a2a4334076f9ba9eaf8843198d..504f812e705a04fd2c922092832498734a4335b4 100644 (file)
@@ -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 \
index a27b9fbde04fc14eabd4b2dca0afa609d91fb436..8a14da8712df78f1b0c66d37ca2f828d23408e38 100644 (file)
@@ -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
 #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, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n");
-    storeAppendPrintf(entry, "<!-- HTML listing generated by Squid %s -->\n",
-                      version_string);
-    storeAppendPrintf(entry, "<!-- %s -->\n", mkrfc1123(squid_curtime));
-    storeAppendPrintf(entry, "<HTML><HEAD><TITLE>\n");
+    flags.listing_started = true;
+    printfReplyBody("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n");
+    printfReplyBody("<!-- HTML listing generated by Squid %s -->\n",
+                    version_string);
+    printfReplyBody("<!-- %s -->\n", mkrfc1123(squid_curtime));
+    printfReplyBody("<HTML><HEAD><TITLE>\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, "</TITLE>\n");
-    storeAppendPrintf(entry, "<STYLE type=\"text/css\"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}--></STYLE>\n");
+    printfReplyBody("</TITLE>\n");
+    printfReplyBody("<STYLE type=\"text/css\"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}--></STYLE>\n");
 
     if (flags.need_base_href)
-        storeAppendPrintf(entry, "<BASE HREF=\"%s\">\n",
-                          html_quote(base_href.buf()));
+        printfReplyBody("<BASE HREF=\"%s\">\n",
+                        html_quote(base_href.buf()));
 
-    storeAppendPrintf(entry, "</HEAD><BODY>\n");
+    printfReplyBody("</HEAD><BODY>\n");
 
     if (cwd_message) {
-        storeAppendPrintf(entry, "<PRE>\n");
+        printfReplyBody("<PRE>\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, "</PRE>\n");
+        printfReplyBody("</PRE>\n");
 
-        storeAppendPrintf(entry, "<HR noshade size=\"1px\">\n");
+        printfReplyBody("<HR noshade size=\"1px\">\n");
 
         wordlistDestroy(&cwd_message);
     }
 
-    storeAppendPrintf(entry, "<H2>\n");
-    storeAppendPrintf(entry, "FTP Directory: ");
+    printfReplyBody("<H2>\n");
+    printfReplyBody("FTP Directory: ");
     /* "ftp://" == 6 characters */
     assert(title_url.size() >= 6);
     k = 6 + strcspn(&title[6], "/");
 
     for (i = 6, j = 0; title[i]; j = i) {
-        storeAppendPrintf(entry, "<A HREF=\"");
+        printfReplyBody("<A HREF=\"");
         i += strcspn(&title[i], "/");
 
         if (i > j) {
             char *url = xstrdup(title);
             url[i] = '\0';
-            storeAppendPrintf(entry, "%s", html_quote(url + k));
-            storeAppendPrintf(entry, "/");
-            storeAppendPrintf(entry, "\">");
+            printfReplyBody("%s", html_quote(url + k));
+            printfReplyBody("/");
+            printfReplyBody("\">");
             rfc1738_unescape(url + j);
-            storeAppendPrintf(entry, "%s", html_quote(url + j));
+            printfReplyBody("%s", html_quote(url + j));
             safe_free(url);
-            storeAppendPrintf(entry, "</A>");
+            printfReplyBody("</A>");
         }
 
-        storeAppendPrintf(entry, "/");
+        printfReplyBody("/");
 
         if (title[i] == '/')
             i++;
 
         if (i == j) {
             /* Error guard, or "assert" */
-            storeAppendPrintf(entry, "ERROR: Failed to parse URL: %s\n",
-                              html_quote(title));
+            printfReplyBody("ERROR: Failed to parse URL: %s\n",
+                            html_quote(title));
             debug(9, 0) ("Failed to parse URL: %s\n", title);
             break;
         }
     }
 
-    storeAppendPrintf(entry, "</H2>\n");
-    storeAppendPrintf(entry, "<PRE>\n");
+    printfReplyBody("</H2>\n");
+    printfReplyBody("<PRE>\n");
     dirup = htmlifyListEntry("<internal-dirup>");
-    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, "</PRE>\n");
+    printfReplyBody("</PRE>\n");
 
     if (flags.listformat_unknown && !flags.tried_nlst) {
-        storeAppendPrintf(entry, "<A HREF=\"%s/;type=d\">[As plain directory]</A>\n",
-                          flags.dir_slash ? rfc1738_escape_part(old_filepath) : ".");
+        printfReplyBody("<A HREF=\"%s/;type=d\">[As plain directory]</A>\n",
+                        flags.dir_slash ? rfc1738_escape_part(old_filepath) : ".");
     } else if (typecode == 'D') {
         const char *path = flags.dir_slash ? filepath : ".";
-        storeAppendPrintf(entry, "<A HREF=\"%s/\">[As extended directory]</A>\n", html_quote(path));
+        printfReplyBody("<A HREF=\"%s/\">[As extended directory]</A>\n", html_quote(path));
     }
 
-    storeAppendPrintf(entry, "<HR noshade size=\"1px\">\n");
-    storeAppendPrintf(entry, "<ADDRESS>\n");
-    storeAppendPrintf(entry, "Generated %s by %s (%s)\n",
-                      mkrfc1123(squid_curtime),
-                      getMyHostname(),
-                      visible_appname_string);
-    storeAppendPrintf(entry, "</ADDRESS></BODY></HTML>\n");
+    printfReplyBody("<HR noshade size=\"1px\">\n");
+    printfReplyBody("<ADDRESS>\n");
+    printfReplyBody("Generated %s by %s (%s)\n",
+                    mkrfc1123(squid_curtime),
+                    getMyHostname(),
+                    visible_appname_string);
+    printfReplyBody("</ADDRESS></BODY></HTML>\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
index 9cc390508ab97e644b98c1e8b0323959c9c4ff8b..7d1769241a92283c9cabcdefc0ee5a060ce6f7df 100644 (file)
@@ -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.
  */
index cd9dc822b4fe85315e3e1ba26cf6f239ff68d6dd..7868944eb816a3ab90bd4a42458221ab9af1bc06 100644 (file)
@@ -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);