This is a multi-part message in MIME format.
--------------57FB272A4CCACD4365ED94
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Here is a updated and tested version of my body processing patch.
* pump/pass modules is NOT used anymore.
* Request bodies are available to the protocols by using
clientReadBody(request, buffer, len, callback, data), which is used in a
way similar to file_read(). clientReadBody uses a new request variable
named body_connection, and this variable can be checked as a boolean for
presence of a body.
The callback is called like
  callback(buffer, read_len, data)
  read_len == 0 on end of request body
  read_len == -1 on errors/abort.
* All request reading is done in clientReadRequest, which properly
understands about aborted, half-closed & persistent client connections.
Please test this patch, and tell me what you think.
/Henrik
--------------57FB272A4CCACD4365ED94
Content-Type: text/plain; charset=us-ascii; name="squid-1.2.beta22.request_body_processing.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="squid-1.2.beta22.request_body_processing.patch"
Index: squid/ChangeLog
===================================================================
RCS file: /usr/src/CVS/squid/ChangeLog,v
retrieving revision 1.1.1.22
retrieving revision 1.1.1.22.2.1
diff -u -r1.1.1.22 -r1.1.1.22.2.1
--- ChangeLog	1998/06/03 22:21:04	1.1.1.22
+++ ChangeLog	1998/06/03 23:16:03	1.1.1.22.2.1
@@ -1,3 +1,10 @@
+	- Reworked how request bodies are passed down to the protocols.
+	  Now all client side processing is inside client_side.c, and
+	  the pass and pump modules is no longer used.
+	- Abort if the client aborts in the middle of a request.
+	- FTP PUT data channel now opened in the same way as RETR/LIST data
+ 	  channels with respect to PORT/PASV/default.
+
 Changes to squid-1.2.beta22 (June 1, 1998):
 
         - do not cut off "; parameter" from "digitized" Content-Type 
Index: squid/src/HttpRequest.c
===================================================================
RCS file: /usr/src/CVS/squid/src/HttpRequest.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -u -r1.1.1.2 -r1.1.1.2.2.1
--- HttpRequest.c	1998/06/03 22:21:59	1.1.1.2
+++ HttpRequest.c	1998/06/03 23:16:12	1.1.1.2.2.1
@@ -52,7 +52,8 @@
 #if OLD_CODE
     safe_free(req->prefix);
 #endif
-    safe_free(req->body);
+    if (req->body_connection)
+	clientAbortBody(req);
     stringClean(&req->urlpath);
     httpHeaderClean(&req->header);
     if (req->cache_control)
Index: squid/src/client_side.c
===================================================================
RCS file: /usr/src/CVS/squid/src/client_side.c,v
retrieving revision 1.1.1.22
retrieving revision 1.1.1.22.2.1
diff -u -r1.1.1.22 -r1.1.1.22.2.1
--- client_side.c	1998/06/03 22:22:04	1.1.1.22
+++ client_side.c	1998/06/03 23:16:12	1.1.1.22.2.1
@@ -73,8 +73,9 @@
 static HttpReply *clientConstructProxyAuthReply(clientHttpRequest * http);
 static int clientCachable(clientHttpRequest * http);
 static int clientHierarchical(clientHttpRequest * http);
-static int clientCheckContentLength(request_t * r);
+static int clientCheckContentLength(request_t * r, int content_length);
 static int httpAcceptDefer(void);
+static void clientProcessBody(ConnStateData *conn);
 
 static int
 checkAccelOnly(clientHttpRequest * http)
@@ -233,10 +234,9 @@
 #endif
         new_request->client_addr = old_request->client_addr;
         EBIT_SET(new_request->flags, REQ_REDIRECTED);
-	if (old_request->body) {
-	    new_request->body = xmalloc(old_request->body_sz);
-	    xmemcpy(new_request->body, old_request->body, old_request->body_sz);
-	    new_request->body_sz = old_request->body_sz;
+	if (old_request->body_connection) {
+	    new_request->body_connection = old_request->body_connection;
+	    old_request->body_connection = NULL;
         }
         requestUnlink(old_request);
         http->request = requestLink(new_request);
@@ -611,6 +611,8 @@
     MemObject *mem = NULL;
     debug(33, 3) ("httpRequestFree: %s\n", storeUrl(entry));
     if (!clientCheckTransferDone(http)) {
+	if (request && request->body_connection)
+	    clientAbortBody(request);		/* abort body transter */
         if (entry)
             storeUnregister(entry, http);	/* unregister BEFORE abort */
         CheckQuickAbort(http);
@@ -676,6 +678,7 @@
     requestUnlink(http->request);
     assert(http != http->next);
     assert(http->conn->chr != NULL);
+    /* Unlink us from the clients request list */
     H = &http->conn->chr;
     while (*H) {
         if (*H == http)
@@ -826,28 +829,21 @@
 }
 
 static int
-clientCheckContentLength(request_t * r)
+clientCheckContentLength(request_t * r, int content_length)
 {
-#if OLD_CODE
-    char *t;
-    int len;
     /*
-     * We only require a content-length for "upload" methods
+     * We only require a content-length for POST/PUT methods
      */
-    if (0 == pumpMethod(r->method))
+    switch(r->method) {
+    case METHOD_PUT:
+    case METHOD_POST:
+	break;
+    default:
+	/* No content-length required */
         return 1;
-    t = mime_get_header(r->headers, "Content-Length");
-    if (NULL == t)
-	return 0;
-    len = atoi(t);
-    if (len < 0)
-	return 0;
-    return 1;
-#else
-    /* We only require a content-length for "upload" methods */
-    return !pumpMethod(r->method) ||
-	httpHeaderGetInt(&r->header, HDR_CONTENT_LENGTH) >= 0;
-#endif
+    }
+    /* Valid content length required */
+    return content_length >= 0;
 }
 
 static int
@@ -878,14 +874,18 @@
     if (req->protocol == PROTO_HTTP)
         return httpCachable(method);
     /* FTP is always cachable */
-    if (req->protocol == PROTO_GOPHER)
-	return gopherCachable(url);
     if (req->protocol == PROTO_WAIS)
         return 0;
     if (method == METHOD_CONNECT)
         return 0;
     if (method == METHOD_TRACE)
         return 0;
+    if (method == METHOD_PUT)
+	return 0;
+    if (method == METHOD_POST)
+	return 0; /* XXX POST may be cached sometimes.. ignored for now */
+    if (req->protocol == PROTO_GOPHER)
+	return gopherCachable(url);
     if (req->protocol == PROTO_CACHEOBJ)
         return 0;
     return 1;
@@ -1180,7 +1180,7 @@
         fd, storeUrl(entry), (int) http->out.offset);
     if (conn->chr != http) {
         /* there is another object in progress, defer this one */
-	debug(0, 0) ("clientSendMoreData: Deferring %s\n", storeUrl(entry));
+	debug(33, 2) ("clientSendMoreData: Deferring %s\n", storeUrl(entry));
         freefunc(buf);
         return;
     } else if (entry && entry->store_status == STORE_ABORTED) {
@@ -1313,7 +1313,7 @@
     conn->defer.until = 0;	/* Kick it to read a new request */
     httpRequestFree(http);
     if ((http = conn->chr) != NULL) {
-	debug(33, 1) ("clientKeepaliveNextRequest: FD %d Sending next\n",
+	debug(33, 3) ("clientKeepaliveNextRequest: FD %d Sending next\n",
             conn->fd);
         entry = http->entry;
         if (0 == storeClientCopyPending(entry, http)) {
@@ -1330,7 +1330,7 @@
     } else {
         debug(33, 5) ("clientWriteComplete: FD %d reading next request\n",
             conn->fd);
-	fd_note(conn->fd, "Reading next request");
+	fd_note(conn->fd, "Waiting for next request");
         /*
          * Set the timeout BEFORE calling clientReadRequest().
          */
@@ -1687,10 +1687,6 @@
         }
         /* yes, continue */
         http->log_type = LOG_TCP_MISS;
-    } else if (pumpMethod(r->method)) {
-	http->log_type = LOG_TCP_MISS;
-	/* XXX oof, POST can be cached! */
-	pumpInit(fd, r, http->uri);
     } else {
         http->log_type = clientProcessRequest2(http);
     }
@@ -2015,7 +2011,10 @@
 clientReadDefer(int fdnotused, void *data)
 {
     ConnStateData *conn = data;
-    return conn->defer.until > squid_curtime;
+    if (conn->body.size_left)
+	return conn->in.offset >= conn->in.size;
+    else
+	return conn->defer.until > squid_curtime;
 }
 
 static void
@@ -2033,12 +2032,9 @@
     ErrorState *err = NULL;
     fde *F = &fd_table[fd];
     int len = conn->in.size - conn->in.offset - 1;
+    int content_length;
     debug(33, 4) ("clientReadRequest: FD %d: reading request...\n", fd);
     size = read(fd, conn->in.buf + conn->in.offset, len);
-    if (size > 0) {
-	fd_bytes(fd, size, FD_READ);
-	kb_incr(&Counter.client_http.kbytes_in, size);
-    }
     /*
      * Don't reset the timeout value here.  The timeout value will be
      * set to Config.Timeout.request by httpAccept() and
@@ -2046,14 +2042,21 @@
      * whole, not individual read() calls.  Plus, it breaks our
      * lame half-close detection
      */
-    commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, conn, 0);
-    if (size == 0) {
-	if (conn->chr == NULL) {
+    if (size > 0) {
+	fd_bytes(fd, size, FD_READ);
+	kb_incr(&Counter.client_http.kbytes_in, size);
+	conn->in.offset += size;
+	conn->in.buf[conn->in.offset] = '\0';	/* Terminate the string */
+    } else if (size == 0 && len > 0) {
+	if (conn->chr == NULL && conn->in.offset == 0) {
             /* no current or pending requests */
+	    debug(33, 4) ("clientReadRequest: FD %d closed\n", fd);
             comm_close(fd);
             return;
-	} else if (!Config.onoff.half_closed_clients) {
+	}
+	if (!Config.onoff.half_closed_clients) {
             /* admin doesn't want to support half-closed client sockets */
+	    debug(33, 3) ("clientReadRequest: FD %d aborted (half_closed_clients disabled)\n", fd);
             comm_close(fd);
             return;
         }
@@ -2063,7 +2066,11 @@
         conn->defer.until = squid_curtime + 1;
         conn->defer.n++;
         fd_note(fd, "half-closed");
-	return;
+	/* There is one more close check at the end, to detect aborted
+	 * (partial) requests. At this point we can't tell if the request
+	 * is partial.
+	 */
+	/* Continue to process previously read data */
     } else if (size < 0) {
         if (!ignoreErrno(errno)) {
             debug(50, 2) ("clientReadRequest: FD %d: %s\n", fd, xstrerror());
@@ -2074,18 +2081,21 @@
             return;
         }
         /* Continue to process previously read data */
-	size = 0;
     }
-    conn->in.offset += size;
-    /* Skip leading (and trailing) whitespace */
-    while (conn->in.offset > 0 && isspace(conn->in.buf[0])) {
-	xmemmove(conn->in.buf, conn->in.buf + 1, conn->in.offset - 1);
-	conn->in.offset--;
-    }
-    conn->in.buf[conn->in.offset] = '\0';	/* Terminate the string */
-    while (conn->in.offset > 0) {
+    commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, conn, 0);
+    /* Process request body */
+    if (conn->in.offset > 0 && conn->body.callback != NULL)
+	clientProcessBody(conn);
+    /* Process new requests */
+    while (conn->in.offset > 0 && conn->body.size_left == 0) {
         int nrequests;
         size_t req_line_sz;
+	/* Skip leading (and trailing) whitespace */
+	if (isspace(conn->in.buf[0])) {
+	    xmemmove(conn->in.buf, conn->in.buf+1, conn->in.offset-1);
+	    conn->in.offset--;
+	    continue;
+	}
         /* Limit the number of concurrent requests to 2 */
         for (H = &conn->chr, nrequests = 0; *H; H = &(*H)->next, nrequests++);
         if (nrequests >= 2) {
@@ -2094,6 +2104,9 @@
             conn->defer.until = squid_curtime + 100;	/* Reset when a request is complete */
             break;
         }
+	conn->in.buf[conn->in.offset] = '\0';	/* Terminate the string */
+	if (nrequests == 0)
+	    fd_note(conn->fd,"Reading next request");
         /* Process request */
         http = parseHttpRequest(conn,
             &method,
@@ -2165,6 +2178,7 @@
             request->prefix = prefix;
             request->prefix_sz = http->req_sz;
 #endif
+	    content_length=httpHeaderGetInt(&request->header, HDR_CONTENT_LENGTH);
             if (!urlCheckRequest(request)) {
                 err = errorCon(ERR_UNSUP_REQ, HTTP_NOT_IMPLEMENTED);
                 err->src_addr = conn->peer.sin_addr;
@@ -2174,7 +2188,7 @@
                 errorAppendEntry(http->entry, err);
                 break;
             }
-	    if (0 == clientCheckContentLength(request)) {
+	    if (!clientCheckContentLength(request, content_length)) {
                 err = errorCon(ERR_INVALID_REQ, HTTP_LENGTH_REQUIRED);
                 err->src_addr = conn->peer.sin_addr;
                 err->request = requestLink(request);
@@ -2184,22 +2198,13 @@
                 break;
             }
             http->request = requestLink(request);
-	    clientAccessCheck(http);
-	    /*
-	     * break here for NON-GET because most likely there is a
-	     * reqeust body following and we don't want to parse it
-	     * as though it was new request
-	     */
-	    if (request->method != METHOD_GET) {
-		if (conn->in.offset) {
-		    request->body_sz = conn->in.offset;
-		    request->body = xmalloc(request->body_sz);
-		    xmemcpy(request->body, conn->in.buf, request->body_sz);
-		    conn->in.offset = 0;
-		}
-		break;
+	    /* Do we expect a request-body? */
+	    if (content_length > 0) {
+		conn->body.size_left =content_length;
+		request->body_connection = conn;
             }
-	    continue;		/* while offset > 0 */
+	    clientAccessCheck(http);
+	    continue;	/* while offset > 0 && body.size_left == 0 */
         } else if (parser_return_code == 0) {
             /*
              *    Partial request received; reschedule until parseHttpRequest()
@@ -2229,7 +2234,128 @@
             }
             break;
         }
+    } /* while offset > 0 && conn->body.size_left == 0 */
+    /* Check if a half-closed connection was aborted in the middle */
+    if (F->flags.socket_eof) {
+	if (conn->in.offset != conn->body.size_left) { /* != 0 when no request body */
+	    /* Partial request received. Abort client connection! */
+	    debug(33, 3) ("clientReadRequest: FD %d aborted\n", fd);
+	    comm_close(fd);
+	    return;
+	}
     }
+}
+
+/* file_read like function, for reading body content */
+void
+clientReadBody( request_t *request, char *buf, size_t size, CBCB *callback, void *cbdata)
+{
+    ConnStateData *conn = request->body_connection;
+    if (!conn) {
+	debug(33, 1) ("clientReadBody: no body to read, request=%p\n",request);
+	callback(buf,0,cbdata); /* Signal end of body */
+	return;
+    }
+    debug(33, 1) ("clientReadBody: start fd=%d body_size=%d in.offset=%d cb=%p req=%p\n", conn->fd, conn->body.size_left, conn->in.offset, callback, request);
+    conn->body.callback = callback;
+    conn->body.cbdata = cbdata;
+    conn->body.buf = buf;
+    conn->body.bufsize = size;
+    conn->body.request = requestLink(request);
+    if (conn->in.offset) {
+	/* Data available */
+	clientProcessBody(conn);
+    } else {
+	debug(33, 1) ("clientReadBody: fd %d wait for clientReadRequest\n", conn->fd);
+    }
+}
+
+/* Called by clientReadRequest to process body content */
+static void
+clientProcessBody(ConnStateData *conn)
+{
+    int size;
+    char *buf = conn->body.buf;
+    void *cbdata = conn->body.cbdata;
+    CBCB *callback = conn->body.callback;
+    request_t *request = conn->body.request;
+    debug(33, 1) ("clientProcessBody: start fd=%d body_size=%d in.offset=%d cb=%p req=%p\n", conn->fd, conn->body.size_left, conn->in.offset, callback, request);
+    /* Some sanity checks... */
+    assert(conn->body.size_left > 0);
+    assert(conn->in.offset > 0);
+    assert(callback != NULL);
+    assert(buf != NULL);
+    /* How much do we have to process? */
+    size = conn->in.offset;
+    if (size > conn->body.size_left) /* only process the body part */
+	size = conn->body.size_left;
+    if (size > conn->body.bufsize) /* don't copy more than requested */
+	size = conn->body.bufsize;
+    xmemcpy(buf, conn->in.buf, size);
+    conn->body.size_left -= size;
+    /* Move any remaining data */
+    conn->in.offset -= size;
+    if (conn->in.offset > 0)
+	xmemmove(conn->in.buf, conn->in.buf + size, conn->in.offset);
+    /* Remove request link if this is the last part of the body, as
+     * clientReadRequest automatically continues to process next request */
+    if (conn->body.size_left <= 0 && request != NULL)
+	request->body_connection = NULL;
+    /* Remove clientReadBody arguments (the call is completed)*/
+    conn->body.request = NULL;
+    conn->body.callback = NULL;
+    conn->body.buf = NULL;
+    conn->body.bufsize = 0;
+    /* Invoke callback function */
+    callback(buf, size, cbdata);
+    if (request != NULL)
+      requestUnlink(request);	/* Linked in clientReadBody */
+    debug(33, 1) ("clientProcessBody: end fd=%d size=%d body_size=%d in.offset=%d cb=%p req=%p\n", conn->fd, size, conn->body.size_left, conn->in.offset, callback, request);
+    return;
+}
+
+/* A dummy handler that throws away a request-body */
+static char bodyAbortBuf[SQUID_TCP_SO_RCVBUF];
+void
+clientReadBodyAbortHandler(char *buf, size_t size, void *data)
+{
+    ConnStateData *conn = (ConnStateData *)data;
+    debug(33, 1) ("clientReadBodyAbortHandler: fd=%d body_size=%d in.offset=%d\n", conn->fd, conn->body.size_left, conn->in.offset);
+    if (size != 0) {
+	debug(33, 3) ("clientReadBodyAbortHandler: fd=%d shedule next read\n", conn->fd);
+	conn->body.callback = clientReadBodyAbortHandler;
+	conn->body.buf = bodyAbortBuf;
+	conn->body.bufsize = sizeof(bodyAbortBuf);
+	conn->body.cbdata = data;
+    }
+}
+	
+/* Abort a body request */
+int
+clientAbortBody(request_t *request)
+{
+    ConnStateData *conn = request->body_connection;
+    char *buf;
+    CBCB *callback;
+    void *cbdata;
+    request->body_connection = NULL;
+    if (!conn || conn->body.size_left <= 0)
+	return 0; /* No body to abort */
+    if (conn->body.callback != NULL) {
+	buf = conn->body.buf;
+	callback = conn->body.callback;
+	cbdata = conn->body.cbdata;
+	assert(request == conn->body.request);
+	conn->body.buf = NULL;
+	conn->body.callback = NULL;
+	conn->body.cbdata = NULL;
+	conn->body.request = NULL;
+	callback(buf, -1, cbdata); /* Signal abort to clientReadBody caller */
+	requestUnlink(request);
+    }
+    clientReadBodyAbortHandler(NULL, -1, conn); /* Install abort handler */
+    /* clientProcessBody() */
+    return 1; /* Aborted */
 }
 
 /* general lifetime handler for HTTP requests */
Index: squid/src/enums.h
===================================================================
RCS file: /usr/src/CVS/squid/src/enums.h,v
retrieving revision 1.1.1.21
retrieving revision 1.1.1.21.2.1
diff -u -r1.1.1.21 -r1.1.1.21.2.1
--- enums.h	1998/06/03 22:22:06	1.1.1.21
+++ enums.h	1998/06/03 23:16:13	1.1.1.21.2.1
@@ -450,7 +450,8 @@
 
 enum {
     HTTP_PROXYING,
-    HTTP_KEEPALIVE
+    HTTP_KEEPALIVE,
+    HTTP_BODY_SENT	/* We have processed some of the request body, not restartable */
 };
 
 enum {
Index: squid/src/ftp.c
===================================================================
RCS file: /usr/src/CVS/squid/src/ftp.c,v
retrieving revision 1.1.1.20
retrieving revision 1.1.1.20.6.2
diff -u -r1.1.1.20 -r1.1.1.20.6.2
--- ftp.c	1998/05/28 12:12:28	1.1.1.20
+++ ftp.c	1998/06/07 12:25:16	1.1.1.20.6.2
@@ -138,6 +138,8 @@
 static CNCB ftpConnectDone;
 static CNCB ftpPasvCallback;
 static PF ftpDataRead;
+static PF ftpDataWrite;
+static CWCB ftpDataWriteCallback;
 static PF ftpStateFree;
 static PF ftpTimeout;
 static PF ftpReadControlReply;
@@ -148,8 +150,6 @@
 static void ftpAuthRequired(HttpReply * reply, request_t * request, const char *realm);
 static STABH ftpAbort;
 static void ftpHackShortcut(FtpStateData * ftpState, FTPSM * nextState);
-static void ftpPutStart(FtpStateData *);
-static CWCB ftpPutTransferDone;
 static void ftpUnhack(FtpStateData * ftpState);
 
 /* State machine functions
@@ -177,6 +177,7 @@
 static FTPSM ftpGetFile;
 static FTPSM ftpSendCwd;
 static FTPSM ftpReadCwd;
+static FTPSM ftpRestOrList;
 static FTPSM ftpSendList;
 static FTPSM ftpSendNlst;
 static FTPSM ftpReadList;
@@ -185,16 +186,15 @@
 static FTPSM ftpSendRetr;
 static FTPSM ftpReadRetr;
 static FTPSM ftpReadTransferDone;
-static FTPSM ftpSendQuit;
-static FTPSM ftpReadQuit;
-static FTPSM ftpFail;
-static FTPSM ftpDataTransferDone;
-static FTPSM ftpRestOrList;
 static FTPSM ftpSendStor;
 static FTPSM ftpReadStor;
+static FTPSM ftpWriteTransferDone;
 static FTPSM ftpSendReply;
-static FTPSM ftpTryMkdir;
+static FTPSM ftpSendMkdir;
 static FTPSM ftpReadMkdir;
+static FTPSM ftpFail;
+static FTPSM ftpSendQuit;
+static FTPSM ftpReadQuit;
 /************************************************
 ** State Machine Description (excluding hacks) **
 *************************************************
@@ -205,17 +205,21 @@
 Pass			Type
 Type			TraverseDirectory / GetFile
 TraverseDirectory	Cwd / GetFile / ListDir
-Cwd			TraverseDirectory
+Cwd			TraverseDirectory / Mkdir
 GetFile			Mdtm
 Mdtm			Size
 Size			Pasv
 ListDir			Pasv
-Pasv			RestOrList
-RestOrList		Rest / Retr / Nlst / List
+Pasv			FileOrList
+FileOrList		Rest / Retr / Nlst / List / Mkdir (PUT /xxx;type=d)
 Rest			Retr
-Retr / Nlst / List	(ftpDataRead on datachannel)
-(ftpDataRead)		ReadTransferDone
+Retr / Nlst / List	DataRead* (on datachannel)
+DataRead*		ReadTransferDone
 ReadTransferDone	DataTransferDone
+Stor			DataWrite* (on datachannel)
+DataWrite*		RequestPutBody** (from client)
+RequestPutBody**	DataWrite* / WriteTransferDone
+WriteTransferDone	DataTransferDone
 DataTransferDone	Quit
 Quit			-
 ************************************************/
@@ -237,8 +241,8 @@
     ftpReadRetr,
     ftpReadStor,
     ftpReadQuit,
-    ftpReadTransferDone,
-    ftpSendReply,
+    ftpReadTransferDone,	/* READING_DATA */
+    ftpWriteTransferDone,	/* WRITING_DATA */
     ftpReadMkdir
 };
 
@@ -759,17 +763,19 @@
     xfree(sbuf);
 }
 
+/* Datachannel complete */
 static void
-ftpReadComplete(FtpStateData * ftpState)
+ftpDataComplete(FtpStateData * ftpState)
 {
-    debug(9, 3) ("ftpReadComplete\n");
-    /* Connection closed; retrieval done. */
+    debug(9, 3) ("ftpDataComplete\n");
+    /* Connection closed; transfer done. */
+    if (ftpState->data.fd >= 0) {
+	debug(9, 3) ("ftpDataComplete: closing data channel");
+	comm_close(ftpState->data.fd);
+	ftpState->data.fd = -1;
+    }
     if (ftpState->flags.html_header_sent)
         ftpListingFinish(ftpState);
-    if (!ftpState->flags.put) {
-	storeTimestampsSet(ftpState->entry);
-	storeComplete(ftpState->entry);
-    }
     /* expect the "transfer complete" message on the control socket */
     commSetSelect(ftpState->ctrl.fd,
         COMM_SELECT_READ,
@@ -778,6 +784,18 @@
         Config.Timeout.read);
 }
 
+static void ftpDataFail(FtpStateData *ftpState)
+{
+    debug(9, 0) ("ftpDataFail not implemented\n");
+    ftpDataComplete(ftpState);
+}
+
+static void ftpDataAbort(FtpStateData *ftpState)
+{
+    debug(9, 0) ("ftpDataAbort not implemented\n");
+    ftpDataComplete(ftpState);
+}
+
 static void
 ftpDataRead(int fd, void *data)
 {
@@ -786,11 +804,9 @@
     int j;
     int bin;
     StoreEntry *entry = ftpState->entry;
-    MemObject *mem = entry->mem_obj;
     assert(fd == ftpState->data.fd);
     if (protoAbortFetch(entry)) {
-	storeAbort(entry, 0);
-	ftpDataTransferDone(ftpState);
+	ftpDataAbort(ftpState);
         return;
     }
     errno = 0;
@@ -812,7 +828,7 @@
         IOStats.Ftp.read_hist[bin]++;
     }
     if (len < 0) {
-	debug(50, 1) ("ftpDataRead: read error: %s\n", xstrerror());
+	debug(9, 1) ("ftpDataRead: read error: %s\n", xstrerror());
         if (ignoreErrno(errno)) {
             commSetSelect(fd,
                 COMM_SELECT_READ,
@@ -820,12 +836,10 @@
                 data,
                 Config.Timeout.read);
         } else {
-	    assert(mem->inmem_hi > 0);
-	    storeAbort(entry, 0);
-	    ftpDataTransferDone(ftpState);
+	    ftpDataFail(ftpState);
         }
     } else if (len == 0) {
-	ftpReadComplete(ftpState);
+	ftpDataComplete(ftpState);
     } else {
         if (ftpState->flags.isdir) {
             if (!ftpState->flags.html_header_sent)
@@ -835,14 +849,11 @@
             assert(ftpState->data.offset == 0);
             storeAppend(entry, ftpState->data.buf, len);
         }
-	if (ftpState->size > 0 && mem->inmem_hi >= ftpState->size + mem->reply->hdr_sz)
-	    ftpReadComplete(ftpState);
-	else
-	    commSetSelect(fd,
-		COMM_SELECT_READ,
-		ftpDataRead,
-		data,
-		Config.Timeout.read);
+	commSetSelect(fd,
+	    COMM_SELECT_READ,
+	    ftpDataRead,
+	    data,
+	    Config.Timeout.read);
     }
 }
 
@@ -1078,7 +1089,7 @@
     if (errflag == COMM_ERR_CLOSING)
         return;
     if (errflag) {
-	debug(50, 1) ("ftpWriteCommandCallback: FD %d: %s\n", fd, xstrerror());
+	debug(9, 1) ("ftpWriteCommandCallback: FD %d: %s\n", fd, xstrerror());
         if (entry->mem_obj->inmem_hi == 0) {
             err = errorCon(ERR_WRITE_ERROR, HTTP_SERVICE_UNAVAILABLE);
             err->xerrno = errno;
@@ -1152,7 +1163,7 @@
     }
     debug(9, 5) ("ftpReadControlReply: FD %d, Read %d bytes\n", fd, len);
     if (len < 0) {
-	debug(50, 1) ("ftpReadControlReply: read error: %s\n", xstrerror());
+	debug(9, 1) ("ftpReadControlReply: read error: %s\n", xstrerror());
         if (ignoreErrno(errno)) {
             commSetSelect(fd,
                 COMM_SELECT_READ,
@@ -1410,15 +1421,15 @@
         if (!ftpState->flags.put)
             ftpFail(ftpState);
         else
-	    ftpTryMkdir(ftpState);
+	    ftpSendMkdir(ftpState);
     }
 }
 
 static void
-ftpTryMkdir(FtpStateData * ftpState)
+ftpSendMkdir(FtpStateData * ftpState)
 {
     char *path = ftpState->filepath;
-    debug(9, 3) ("ftpTryMkdir: with path=%s\n", path);
+    debug(9, 3) ("ftpSendMkdir: with path=%s\n", path);
     snprintf(cbuf, 1024, "MKD %s\r\n", path);
     ftpWriteCommand(cbuf, ftpState);
     ftpState->state = SENT_MKDIR;
@@ -1752,23 +1763,25 @@
      *    host NULL -> not connected, port == local port
      *    host set  -> connected, port == remote port
      */
-    /* Restart state (SENT_NLST/LIST/RETR) */
+    /* Restart state (SENT_NLST/LIST/RETR/STOR) */
     FTP_SM_FUNCS[ftpState->state] (ftpState);
 }
 
 static void
 ftpRestOrList(FtpStateData * ftpState)
 {
-
     debug(9, 3) ("This is ftpRestOrList\n");
-    if (ftpState->flags.put) {
-	debug(9, 3) ("ftpRestOrList: Sending STOR request...\n");
-	ftpSendStor(ftpState);
-    } else if (ftpState->typecode == 'D') {
-	/* XXX This should NOT be here */
-	ftpSendNlst(ftpState);	/* sec 3.2.2 of RFC 1738 */
+    if (ftpState->typecode == 'D') {
         ftpState->flags.isdir = 1;
         ftpState->flags.use_base = 1;
+	if (ftpState->flags.put) {
+	    ftpSendMkdir(ftpState);	/* PUT name;type=d */
+	} else {
+	    ftpSendNlst(ftpState);	/* GET name;type=d  sec 3.2.2 of RFC 1738 */
+	}
+    } else if (ftpState->flags.put) {
+	debug(9, 3) ("ftpRestOrList: Sending STOR request...\n");
+	ftpSendStor(ftpState);
     } else if (ftpState->flags.isdir)
         ftpSendList(ftpState);
     else if (ftpState->restart_offset > 0)
@@ -1791,24 +1804,39 @@
 {
     int code = ftpState->ctrl.replycode;
     debug(9, 3) ("This is ftpReadStor\n");
-    if (code >= 100 && code < 200) {
+    if (code == 125 || (code == 150 && ftpState->data.host)) {
+	/* Begin data transfer */
+	debug(9, 3) ("ftpReadStor: starting data channel\n");
+	commSetSelect(ftpState->data.fd,
+	    COMM_SELECT_WRITE,
+	    ftpDataWrite,
+	    ftpState,
+	    Config.Timeout.read);
+	commSetDefer(ftpState->data.fd, NULL, NULL);
+	ftpState->state = WRITING_DATA;
         /*
-	 * Cancel the timeout on the Control socket, pumpStart will
-	 * establish one on the data socket.
+	 * Cancel the timeout on the Control socket and establish one
+	 * on the data socket
          */
         commSetTimeout(ftpState->ctrl.fd, -1, NULL, NULL);
-	ftpPutStart(ftpState);
-	debug(9, 3) ("ftpReadStor: writing data channel\n");
-	ftpState->state = WRITING_DATA;
-    } else if (code == 553) {
-	/* directory does not exist, have to create, sigh */
-#if WORK_IN_PROGRESS
-	ftpTraverseDirectory(ftpState);
-#endif
-	ftpSendReply(ftpState);
+	commSetTimeout(ftpState->data.fd, Config.Timeout.read, ftpTimeout,
+	    ftpState);
+    } else if (code == 150) {
+	/* Accept data channel */
+	commSetSelect(ftpState->data.fd,
+	    COMM_SELECT_WRITE,
+	    ftpAcceptDataConnection,
+	    ftpState,
+	    0);
+	/*
+	 * Cancel the timeout on the Control socket and establish one
+	 * on the data socket
+	 */
+	commSetTimeout(ftpState->ctrl.fd, -1, NULL, NULL);
+	commSetTimeout(ftpState->data.fd, Config.Timeout.read, ftpTimeout,
+	    ftpState);
     } else {
-	debug(9, 3) ("ftpReadStor: that's all folks\n");
-	ftpSendReply(ftpState);
+	ftpFail(ftpState);
     }
 }
 
@@ -1976,18 +2004,67 @@
         debug(9, 1) ("--> releasing '%s'\n", storeUrl(ftpState->entry));
         storeReleaseRequest(ftpState->entry);
     }
-    ftpDataTransferDone(ftpState);
+    storeTimestampsSet(ftpState->entry);
+    storeComplete(ftpState->entry);
+    ftpSendQuit(ftpState);
 }
 
+/* This will be called when there is data available to put */
 static void
-ftpDataTransferDone(FtpStateData * ftpState)
+ftpRequestBody(char *buf, size_t size, void *data)
 {
-    debug(9, 3) ("This is ftpDataTransferDone\n");
-    if (ftpState->data.fd > -1) {
-	comm_close(ftpState->data.fd);
-	ftpState->data.fd = -1;
+    FtpStateData *ftpState = (FtpStateData *)data;
+    debug(9, 3) ("ftpRequestBody: buf=%p size=%d ftpState=%p\n",buf,size,data);
+    ftpState->data.offset = size;
+    if (size > 0) {
+	/* DataWrite */
+	comm_write(ftpState->data.fd, buf, size, ftpDataWriteCallback, data, NULL);
+    } else if (size < 0) {
+	/* Error */
+	debug(9, 1) ("ftpRequestBody: request aborted");
+	ftpDataAbort(ftpState);
+    } else if (size == 0) {
+	/* End of transfer */
+	ftpDataComplete(ftpState);
+    }
+} 
+
+/* This will be called when the put write is completed */
+static void
+ftpDataWriteCallback(int fd, char *buf, size_t size, int err, void *data)
+{
+    FtpStateData *ftpState = (FtpStateData *)data;
+    if (!err) {
+	/* Shedule the rest of the request */
+	clientReadBody(ftpState->request, ftpState->data.buf, ftpState->data.size, ftpRequestBody, ftpState);
+    } else {
+	debug(9, 1) ("ftpDataWriteCallback: write error: %s\n", xstrerror());
+	ftpDataFail(ftpState);
     }
-    ftpSendQuit(ftpState);
+}
+
+static void
+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);
+}
+
+static void
+ftpWriteTransferDone(FtpStateData * ftpState)
+{
+    int code = ftpState->ctrl.replycode;
+    debug(9, 3) ("This is ftpWriteTransferDone\n");
+    if (code != 226) {
+	debug(9, 1) ("ftpReadTransferDone: Got code %d after sending data\n",
+	    code);
+	debug(9, 1) ("--> releasing '%s'\n", storeUrl(ftpState->entry));
+	storeReleaseRequest(ftpState->entry);
+    }
+    storeTimestampsSet(ftpState->entry); /* XXX Is this needed? */
+    ftpSendReply(ftpState);
 }
 
 static void
@@ -2118,25 +2195,6 @@
 }
 
 static void
-ftpPutStart(FtpStateData * ftpState)
-{
-    debug(9, 3) ("ftpPutStart\n");
-    pumpStart(ftpState->data.fd, ftpState->entry,
-	ftpState->request, ftpPutTransferDone, ftpState);
-}
-
-static void
-ftpPutTransferDone(int fd, char *bufnotused, size_t size, int errflag, void *data)
-{
-    FtpStateData *ftpState = data;
-    if (ftpState->data.fd >= 0) {
-	comm_close(ftpState->data.fd);
-	ftpState->data.fd = -1;
-    }
-    ftpReadComplete(ftpState);
-}
-
-static void
 ftpSendReply(FtpStateData * ftpState)
 {
     ErrorState *err;
@@ -2166,7 +2224,7 @@
         err->ftp.reply = ftpState->ctrl.last_reply;
     errorAppendEntry(ftpState->entry, err);
     storeBufferFlush(ftpState->entry);
-    comm_close(ftpState->ctrl.fd);
+    ftpSendQuit(ftpState);
 }
 
 static void
Index: squid/src/http.c
===================================================================
RCS file: /usr/src/CVS/squid/src/http.c,v
retrieving revision 1.1.1.19
retrieving revision 1.1.1.19.2.1
diff -u -r1.1.1.19 -r1.1.1.19.2.1
--- http.c	1998/06/03 22:22:09	1.1.1.19
+++ http.c	1998/06/03 23:16:15	1.1.1.19.2.1
@@ -466,6 +466,16 @@
             return;
         }
     }
+    if (!httpState->reply_hdr && len>0) {
+	/* Skip whitespace */
+	while(len > 0 && isspace(*buf))
+	    xmemmove(buf, buf+1, len--);
+	if (len == 0) {
+	    /* Continue to read... */
+	    commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
+	    return;
+	}
+    }
     if (len < 0) {
         debug(50, 2) ("httpReadReply: FD %d: read failure: %s.\n",
             fd, xstrerror());
@@ -776,7 +786,8 @@
 
     debug(11, 5) ("httpSendRequest: FD %d: httpState %p.\n", fd, httpState);
 
-    if (pumpMethod(req->method))
+    /* Do we have a body to process? */
+    if (req->body_connection)
         sendHeaderDone = httpSendRequestEntry;
     else
         sendHeaderDone = httpSendComplete;
@@ -916,9 +927,12 @@
      */
     if (fd_table[httpState->fd].uses < 2)
         return 0;
-    if (pumpMethod(httpState->orig_request->method))
-	if (0 == pumpRestart(httpState->orig_request))
-	    return 0;
+    /*
+     * We can't restart a request where we have sent
+     * all or part of the request-body.
+     */
+    if (EBIT_TEST(httpState->flags, HTTP_BODY_SENT))
+	return 0;
     return 1;
 }
 
@@ -927,11 +941,6 @@
 {
     /* restart a botched request from a persistent connection */
     debug(11, 2) ("Retrying HTTP request for %s\n", storeUrl(httpState->entry));
-    if (pumpMethod(httpState->orig_request->method)) {
-	debug(11, 3) ("Potential Coredump: httpRestart %s %s\n",
-	    RequestMethodStr[httpState->orig_request->method],
-	    storeUrl(httpState->entry));
-    }
     if (httpState->fd >= 0) {
         comm_remove_close_handler(httpState->fd, httpStateFree, httpState);
         comm_close(httpState->fd);
@@ -993,6 +1002,24 @@
 }
 
 static void
+httpRequestBodyHandler(char *buf, size_t size, void *data)
+{
+    HttpStateData *httpState = (HttpStateData *)data;
+    if ( size > 0 ) {
+	EBIT_SET(httpState->flags, HTTP_BODY_SENT);
+	comm_write(httpState->fd, buf, size, httpSendRequestEntry, data, memFree8K);
+    } else if (size == 0) {
+	/* End of body */
+	memFree8K(buf);
+	httpSendComplete(httpState->fd, NULL, 0, 0, data);
+    } else {
+	/* Failed to get whole body, probably aborted */
+	memFree8K(buf);
+	httpSendComplete(httpState->fd, NULL, 0, COMM_ERR_CLOSING, data);
+    }
+}
+
+static void
 httpSendRequestEntry(int fd, char *bufnotused, size_t size, int errflag, void *data)
 {
     HttpStateData *httpState = data;
@@ -1015,5 +1042,5 @@
         comm_close(fd);
         return;
     }
-    pumpStart(fd, entry, httpState->orig_request, httpSendComplete, httpState);
+    clientReadBody(httpState->orig_request, memAllocate(MEM_8K_BUF), 8192, httpRequestBodyHandler, httpState);
 }
Index: squid/src/pass.c
===================================================================
RCS file: /usr/src/CVS/squid/src/pass.c,v
retrieving revision 1.1.1.11
retrieving revision 1.1.1.11.8.1
diff -u -r1.1.1.11 -r1.1.1.11.8.1
--- pass.c	1998/05/25 21:04:11	1.1.1.11
+++ pass.c	1998/06/03 23:16:15	1.1.1.11.8.1
@@ -1,4 +1,4 @@
-
+#if OLD_CODE
 
 
 /*
@@ -478,3 +478,5 @@
     err->callback_data = passState;
     errorSend(passState->client.fd, err);
 }
+
+#endif
Index: squid/src/protos.h
===================================================================
RCS file: /usr/src/CVS/squid/src/protos.h,v
retrieving revision 1.1.1.22
retrieving revision 1.1.1.22.2.1
diff -u -r1.1.1.22 -r1.1.1.22.2.1
--- protos.h	1998/06/03 22:22:14	1.1.1.22
+++ protos.h	1998/06/03 23:16:16	1.1.1.22.2.1
@@ -90,6 +90,8 @@
 extern void clientHttpConnectionsClose(void);
 extern StoreEntry *clientCreateStoreEntry(clientHttpRequest *, method_t, int);
 extern int isTcpHit(log_type);
+extern void clientReadBody(request_t *req, char *buf, size_t size, CBCB *callback, void *data);
+extern int clientAbortBody(request_t *req);
 
 extern int commSetNonBlocking(int fd);
 extern void commSetCloseOnExec(int fd);
@@ -592,7 +594,9 @@
      extern void start_announce(void *unused);
      extern void sslStart(int fd, const char *, request_t *, size_t * sz);
      extern void waisStart(request_t *, StoreEntry *);
+#if OLD_CODE
      extern void passStart(int, const char *, request_t *, size_t *);
+#endif
      extern void identStart(int, ConnStateData *, IDCB * callback, void *);
 
      extern void statInit(void);
@@ -874,10 +878,12 @@
      extern void PrintRusage(void);
      extern void dumpMallocStats(void);
 
+#if OLD_CODE
      extern void pumpInit(int fd, request_t * r, char *uri);
      extern void pumpStart(int, StoreEntry *, request_t *, CWCB * callback, void *);
      extern int pumpMethod(method_t method);
      extern int pumpRestart(request_t *);
+#endif
 
      extern void unlinkdInit(void);
      extern void unlinkdClose(void);
Index: squid/src/pump.c
===================================================================
RCS file: /usr/src/CVS/squid/src/pump.c,v
retrieving revision 1.1.1.5
retrieving revision 1.1.1.5.6.1
diff -u -r1.1.1.5 -r1.1.1.5.6.1
--- pump.c	1998/05/28 12:12:34	1.1.1.5
+++ pump.c	1998/06/03 23:16:16	1.1.1.5.6.1
@@ -1,3 +1,4 @@
+#if OLD_CODE
 /*
  * $Id$
  *
@@ -472,3 +473,4 @@
     storeClientListAdd(p->request_entry, p);
     return 1;
 }
+#endif
Index: squid/src/structs.h
===================================================================
RCS file: /usr/src/CVS/squid/src/structs.h,v
retrieving revision 1.1.1.23
retrieving revision 1.1.1.23.2.1
diff -u -r1.1.1.23 -r1.1.1.23.2.1
--- structs.h	1998/06/03 22:22:20	1.1.1.23
+++ structs.h	1998/06/03 23:16:16	1.1.1.23.2.1
@@ -697,6 +697,14 @@
         off_t offset;
         size_t size;
     } in;
+    struct {
+	size_t size_left; /* How much body left to process */
+	request_t *request; /* Parameters passed to clientReadBody */
+	char *buf;
+	size_t bufsize;
+	CBCB *callback;
+	void *cbdata;
+    } body;
     clientHttpRequest *chr;
     struct sockaddr_in peer;
     struct sockaddr_in me;
@@ -1111,8 +1119,7 @@
 #else
     HttpHeader header;
 #endif
-    char *body;
-    size_t body_sz;
+    ConnStateData *body_connection; /* used by clientReadBody() */
     HierarchyLogEntry hier;
     err_type err_type;
 };
Index: squid/src/typedefs.h
===================================================================
RCS file: /usr/src/CVS/squid/src/typedefs.h,v
retrieving revision 1.1.1.14
retrieving revision 1.1.1.14.2.1
diff -u -r1.1.1.14 -r1.1.1.14.2.1
--- typedefs.h	1998/06/03 22:22:21	1.1.1.14
+++ typedefs.h	1998/06/03 23:16:17	1.1.1.14.2.1
@@ -146,6 +146,7 @@
 typedef void RH(void *data, char *);
 typedef void UH(void *data, wordlist *);
 typedef int DEFER(int fd, void *data);
+typedef void CBCB(char *buf, size_t size, void *data);
 
 typedef void SIH(int fd, void *);	/* swap in */
 typedef int QS(const void *, const void *);	/* qsort */
--------------57FB272A4CCACD4365ED94--
Received on Tue Jul 29 2003 - 13:15:50 MDT
This archive was generated by hypermail pre-2.1.9 : Tue Dec 09 2003 - 16:11:48 MST