1.2b22: New version of my body processing [patch]

From: Henrik Nordström <hno@dont-contact.us>
Date: Sun, 07 Jun 1998 18:20:53 +0200

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