1.2b20-1: Reworked client body processing [patch]

From: Henrik Nordstrom <hno@dont-contact.us>
Date: Sun, 26 Apr 1998 03:56:50 +0200

This is a multi-part message in MIME format.

--------------CD94657B23F41D293E1882
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Here is a updated vesion of my client body processing.

The idea behind this patch is that all client side request processing
should be driven by clientReadRequest, and handed down to each protocol
in a well-defined way.

How it works:
When a request with a body is received, the connection changes state to
"body processing", and the request marked with a linked to the client
connection.

The protocols then use clientReadBody to get the request-body content,
in a way similar to read_file or comm_write. End-of-body is indicated by
read length 0, aborts/failure with length -1.

/Henrik

--------------CD94657B23F41D293E1882
Content-Type: text/plain; charset=us-ascii; name="squid-1.2.beta20-1.request_body.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="squid-1.2.beta20-1.request_body.patch"

Index: squid/ChangeLog
--- squid/ChangeLog:1.1.1.19.2.2 1998/04/25 20:31:40
+++ squid/ChangeLog 1998/04/26 01:22:59
@@ -1,3 +1,9 @@
+ - 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.
+ - 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.
         - Honor server (Proxy-)Connection: replies on persistent connections
         - Changed icon URL style again, to allow the first Squid cache
           in the cache hierarchy to decide on what to do.
Index: squid/src/Makefile.in
diff -u squid/src/Makefile.in:1.1.1.18 squid/src/Makefile.in:1.1.1.18.2.1
--- squid/src/Makefile.in:1.1.1.18 Sat Apr 25 14:47:43 1998
+++ squid/src/Makefile.in Sun Apr 26 03:10:18 1998
@@ -127,12 +127,10 @@
                 net_db.o \
                 cache_manager.o \
                 Packer.o \
- pass.o \
                 pconn.o \
                 peer_digest.o \
                 peer_select.o \
                 proto.o \
- pump.o \
                 redirect.o \
                 refresh.o \
                 send-announce.o \
Index: squid/src/cf.data.pre
diff -u squid/src/cf.data.pre:1.1.1.17 squid/src/cf.data.pre:1.1.1.17.2.1
--- squid/src/cf.data.pre:1.1.1.17 Sat Apr 25 14:47:45 1998
+++ squid/src/cf.data.pre Sun Apr 26 03:10:19 1998
@@ -2134,3 +2134,17 @@
 DOC_END
 
 EOF
+
+NAME: client_half_closes
+COMMENT: on|off
+TYPE: onoff
+DEFAULT: on
+LOC: Config.client_half_closes
+DOC_START
+ If you have no clients that use half-side closes when sending
+ requests you can turn off support for this and gain instant
+ abort detection.
+
+client_half_closes on
+DOC_END
+
Index: squid/src/client_side.c
diff -u squid/src/client_side.c:1.1.1.19.2.1 squid/src/client_side.c:1.1.1.19.2.2
--- squid/src/client_side.c:1.1.1.19.2.1 Sat Apr 25 19:14:54 1998
+++ squid/src/client_side.c Sun Apr 26 03:10:19 1998
@@ -70,6 +70,7 @@
 static int clientCachable(clientHttpRequest * http);
 static int clientHierarchical(clientHttpRequest * http);
 static int clientCheckContentLength(request_t * r);
+static void clientProcessBody(ConnStateData *conn);
 
 static int
 checkAccelOnly(clientHttpRequest * http)
@@ -253,10 +254,9 @@
         new_request->headers_sz = old_request->headers_sz;
         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);
@@ -682,6 +682,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);
@@ -739,6 +741,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)
@@ -858,10 +861,16 @@
     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;
@@ -902,14 +911,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;
@@ -1226,7 +1239,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().
          */
@@ -1577,10 +1590,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);
     }
@@ -1921,6 +1921,7 @@
     clientHttpRequest *http = NULL;
     clientHttpRequest **H = NULL;
     char *headers;
+ char *content_length;
     size_t headers_sz;
     ErrorState *err = NULL;
     fde *F = &fd_table[fd];
@@ -1936,9 +1937,36 @@
      * lame half-close detection
      */
     commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, conn, 0);
+ if (size < 0) {
+ if (!ignoreErrno(errno)) {
+ debug(50, 2) ("clientReadRequest: FD %d: %s\n", fd, xstrerror());
+ comm_close(fd);
+ return;
+ } else if (conn->in.offset == 0) {
+ debug(50, 2) ("clientReadRequest: FD %d: no data to process (%s)\n", fd, xstrerror());
+ return;
+ }
+ /* Continue to process previously read data */
+ size = 0;
+ }
+ conn->in.offset += size;
+ if(conn->body.size_left == 0) {
+ /* 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--;
+ }
+ }
     if (size == 0) {
         if (conn->chr == NULL) {
             /* no current or pending requests */
+ debug(33, 4) ("clientReadRequest: FD %d closed\n", fd);
+ comm_close(fd);
+ return;
+ }
+ if (conn->in.offset > 0 || conn->body.size_left > 0 || !Config.onoff.client_half_closes) {
+ /* In the middle of a request */
+ debug(33, 3) ("clientReadRequest: FD %d aborted\n", fd);
             comm_close(fd);
             return;
         }
@@ -1948,22 +1976,13 @@
         conn->defer.until = squid_curtime + 1;
         conn->defer.n++;
         fd_note(fd, "half-closed");
- return;
- } else if (size < 0) {
- if (!ignoreErrno(errno)) {
- debug(50, 2) ("clientReadRequest: FD %d: %s\n", fd, xstrerror());
- comm_close(fd);
- return;
- } else if (conn->in.offset == 0) {
- debug(50, 2) ("clientReadRequest: FD %d: no data to process (%s)\n", fd, xstrerror());
- return;
- }
         /* Continue to process previously read data */
- size = 0;
     }
- conn->in.offset += size;
- conn->in.buf[conn->in.offset] = '\0'; /* Terminate the string */
- while (conn->in.offset > 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;
         /* Limit the number of concurrent requests to 2 */
         for (H = &conn->chr, nrequests = 0; *H; H = &(*H)->next, nrequests++);
@@ -1973,6 +1992,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,
@@ -2028,7 +2050,7 @@
                 errorAppendEntry(http->entry, err);
                 break;
             }
- if (0 == clientCheckContentLength(request)) {
+ if (!clientCheckContentLength(request)) {
                 err = errorCon(ERR_INVALID_REQ, HTTP_LENGTH_REQUIRED);
                 err->src_addr = conn->peer.sin_addr;
                 err->request = requestLink(request);
@@ -2038,22 +2060,15 @@
                 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? */
+ content_length=mime_get_header(request->headers, "Content-Length");
+ if (content_length != NULL) {
+ conn->body.size_left = atoi(content_length);
+ if (conn->body.size_left > 0)
+ 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()
@@ -2083,7 +2098,119 @@
             }
             break;
         }
+ } /* while offset > 0 && conn->body.size_left == 0 */
+}
+
+/* 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\n");
+ 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) ("clientReadBodyHandler: 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) ("clientReadBodyHandler: 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
diff -u squid/src/enums.h:1.1.1.17 squid/src/enums.h:1.1.1.17.2.1
--- squid/src/enums.h:1.1.1.17 Sat Apr 25 14:47:47 1998
+++ squid/src/enums.h Sun Apr 26 03:10:20 1998
@@ -422,7 +422,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
diff -u squid/src/ftp.c:1.1.1.18 squid/src/ftp.c:1.1.1.18.2.1
--- squid/src/ftp.c:1.1.1.18 Sat Apr 25 14:47:48 1998
+++ squid/src/ftp.c Sun Apr 26 03:10:20 1998
@@ -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,16 @@
 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 ftpDataTransferDone;
 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 +206,22 @@
 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
+DataWrite* RequestPutBody**
+WriteTransferDone DataTransferDone
 DataTransferDone Quit
 Quit -
 ************************************************/
@@ -238,7 +244,7 @@
     ftpReadStor,
     ftpReadQuit,
     ftpReadTransferDone,
- ftpSendReply,
+ ftpWriteTransferDone,
     ftpReadMkdir
 };
 
@@ -760,17 +766,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");
+ /* Data channel done*/
+ if (ftpState->data.fd >= 0) {
+ debug(9, 3) ("ftpDataComplete: closing data channel");
+ comm_close(ftpState->data.fd);
+ ftpState->data.fd = -1;
+ }
     if (EBIT_TEST(ftpState->flags, FTP_HTML_HEADER_SENT))
         ftpListingFinish(ftpState);
- if (!EBIT_TEST(ftpState->flags, FTP_PUT)) {
- storeTimestampsSet(ftpState->entry);
- storeComplete(ftpState->entry);
- }
     /* expect the "transfer complete" message on the control socket */
     commSetSelect(ftpState->ctrl.fd,
         COMM_SELECT_READ,
@@ -779,6 +787,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)
 {
@@ -787,11 +807,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;
@@ -813,7 +831,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,
@@ -821,12 +839,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 (EBIT_TEST(ftpState->flags, FTP_ISDIR)) {
             if (!EBIT_TEST(ftpState->flags, FTP_HTML_HEADER_SENT))
@@ -836,14 +852,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);
     }
 }
 
@@ -1075,7 +1088,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;
@@ -1149,7 +1162,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,
@@ -1404,15 +1417,15 @@
         ftpTraverseDirectory(ftpState);
     } else {
         /* CWD FAILED */
- if (!EBIT_TEST(ftpState->flags, FTP_PUT))
- ftpFail(ftpState);
+ if (EBIT_TEST(ftpState->flags, FTP_PUT))
+ ftpSendMkdir(ftpState);
         else
- ftpTryMkdir(ftpState);
+ ftpFail(ftpState);
     }
 }
 
 static void
-ftpTryMkdir(FtpStateData * ftpState)
+ftpSendMkdir(FtpStateData * ftpState)
 {
     char *path = ftpState->filepath;
     debug(9, 3) ("ftpTryMkdir: with path=%s\n", path);
@@ -1432,7 +1445,7 @@
         ftpSendCwd(ftpState);
     } else if (code == 550) { /* dir exists */
         if (EBIT_TEST(ftpState->flags, FTP_PUT_MKDIR)) {
- EBIT_SET(ftpState->flags, FTP_PUT_MKDIR);
+ EBIT_CLR(ftpState->flags, FTP_PUT_MKDIR);
             ftpSendCwd(ftpState);
         } else
             ftpSendReply(ftpState);
@@ -1749,7 +1762,7 @@
      * 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);
 }
 
@@ -1758,14 +1771,16 @@
 {
 
     debug(9, 3) ("This is ftpRestOrList\n");
- if (EBIT_TEST(ftpState->flags, FTP_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') {
         EBIT_SET(ftpState->flags, FTP_ISDIR);
         EBIT_SET(ftpState->flags, FTP_USE_BASE);
+ if (EBIT_TEST(ftpState->flags, FTP_PUT))
+ ftpSendMkdir(ftpState); /* PUT name;type=d */
+ else
+ ftpSendNlst(ftpState); /* GET name;type=d sec 3.2.2 of RFC 1738 */
+ } else if (EBIT_TEST(ftpState->flags, FTP_PUT)) {
+ debug(9, 3) ("ftpRestOrList: Sending STOR request...\n");
+ ftpSendStor(ftpState);
     } else if (EBIT_TEST(ftpState->flags, FTP_ISDIR))
         ftpSendList(ftpState);
     else if (ftpState->restart_offset > 0)
@@ -1788,24 +1803,40 @@
 {
     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");
+ ftpAppendSuccessHeader(ftpState);
+ commSetSelect(ftpState->data.fd,
+ COMM_SELECT_WRITE,
+ ftpDataWrite,
+ ftpState,
+ Config.Timeout.read);
+ commSetDefer(ftpState->data.fd, NULL, NULL);
+ ftpState->state = READING_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,14 +2007,61 @@
     ftpDataTransferDone(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 body */
+ 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 (size > 0) {
+ /* 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);
     }
+}
+
+static void
+ftpDataWrite(int ftp, void *data)
+{
+ FtpStateData * ftpState = (FtpStateData *)data;
+ debug(9, 3) ("ftpDataWrite\n");
+ /* This starts the body transfer */
+ ftpDataWriteCallback(-1,NULL,-1,0,ftpState);
+}
+
+static void
+ftpWriteTransferDone(FtpStateData * ftpState)
+{
+ debug(9, 3) ("This is ftpWriteTransferDone\n");
+ ftpSendReply(ftpState);
+}
+
+static void
+ftpDataTransferDone(FtpStateData * ftpState)
+{
+ storeTimestampsSet(ftpState->entry);
+ storeComplete(ftpState->entry);
     ftpSendQuit(ftpState);
 }
 
@@ -2112,25 +2190,6 @@
         err->ftp.reply = ftpState->ctrl.last_reply;
     errorAppendEntry(ftpState->entry, err);
     comm_close(ftpState->ctrl.fd);
-}
-
-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 = (FtpStateData *) data;
- if (ftpState->data.fd >= 0) {
- comm_close(ftpState->data.fd);
- ftpState->data.fd = -1;
- }
- ftpReadComplete(ftpState);
 }
 
 static void
Index: squid/src/http.c
diff -u squid/src/http.c:1.1.1.16.2.3 squid/src/http.c:1.1.1.16.2.4
--- squid/src/http.c:1.1.1.16.2.3 Sat Apr 25 22:49:47 1998
+++ squid/src/http.c Sun Apr 26 03:10:20 1998
@@ -318,6 +318,7 @@
         room = 8191 - hdr_len;
         strncat(httpState->reply_hdr, buf, room < size ? room : size);
         hdr_len += room < size ? room : size;
+ /* XXX: What happens if the first packet is only part of this? */
         if (hdr_len > 4 && strncmp(httpState->reply_hdr, "HTTP/", 5)) {
             debug(11, 3) ("httpProcessReplyHeader: Non-HTTP-compliant header: '%s'\n", httpState->reply_hdr);
             httpState->reply_hdr_state += 2;
@@ -754,7 +755,8 @@
         buflen += req->headers_sz + 1;
     buflen += 512; /* lots of extra */
 
- if (pumpMethod(req->method))
+ /* Do we have a body to process? */
+ if (req->body_connection)
         sendHeaderDone = httpSendRequestEntry;
     else
         sendHeaderDone = httpSendComplete;
@@ -908,9 +910,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;
 }
 
@@ -919,11 +924,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, 1) ("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);
@@ -985,6 +985,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;
@@ -1007,5 +1025,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/protos.h
diff -u squid/src/protos.h:1.1.1.19.2.1 squid/src/protos.h:1.1.1.19.2.2
--- squid/src/protos.h:1.1.1.19.2.1 Sat Apr 25 19:14:54 1998
+++ squid/src/protos.h Sun Apr 26 03:10:21 1998
@@ -90,6 +90,8 @@
 extern StoreEntry *clientCreateStoreEntry(clientHttpRequest *, method_t, int);
 extern int isTcpHit(log_type);
 extern int handleConnectionHeader(int flag, char *where, char *what);
+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);
@@ -550,7 +552,6 @@
 extern void start_announce(void *unused);
 extern void sslStart(int fd, const char *, request_t *, size_t * sz);
 extern void waisStart(request_t *, StoreEntry *);
-extern void passStart(int, const char *, request_t *, size_t *);
 extern void identStart(int, ConnStateData *, IDCB * callback, void *);
 
 extern void statInit(void);
@@ -820,11 +821,6 @@
 extern void releaseServerSockets(void);
 extern void PrintRusage(void);
 extern void dumpMallocStats(void);
-
-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 *);
 
 extern void unlinkdInit(void);
 extern void unlinkdClose(void);
Index: squid/src/structs.h
diff -u squid/src/structs.h:1.1.1.20.2.1 squid/src/structs.h:1.1.1.20.2.2
--- squid/src/structs.h:1.1.1.20.2.1 Sat Apr 25 22:31:45 1998
+++ squid/src/structs.h Sun Apr 26 03:10:21 1998
@@ -319,6 +319,7 @@
         int accel_with_proxy;
         int mem_pools;
         int test_reachability;
+ int client_half_closes;
     } onoff;
     acl *aclList;
     struct {
@@ -689,6 +690,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;
@@ -1094,8 +1103,7 @@
     struct in_addr client_addr;
     char *headers;
     size_t headers_sz;
- char *body;
- size_t body_sz;
+ ConnStateData *body_connection; /* used by clientReadBody() */
     HierarchyLogEntry hier;
     err_type err_type;
 };
Index: squid/src/typedefs.h
diff -u squid/src/typedefs.h:1.1.1.13 squid/src/typedefs.h:1.1.1.13.2.1
--- squid/src/typedefs.h:1.1.1.13 Sat Apr 25 14:47:58 1998
+++ squid/src/typedefs.h Sun Apr 26 03:10:21 1998
@@ -145,6 +145,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 */
Index: squid/src/url.c
diff -u squid/src/url.c:1.1.1.15 squid/src/url.c:1.1.1.15.2.1
--- squid/src/url.c:1.1.1.15 Sat Apr 25 14:47:58 1998
+++ squid/src/url.c Sun Apr 26 03:10:22 1998
@@ -412,7 +412,8 @@
     if (request->link_count)
         return;
     safe_free(request->headers);
- safe_free(request->body);
+ if (request->body_connection != NULL)
+ clientAbortBody(request);
     stringClean(&request->urlpath);
     memFree(MEM_REQUEST_T, request);
 }

--------------CD94657B23F41D293E1882--
Received on Tue Jul 29 2003 - 13:15:48 MDT

This archive was generated by hypermail pre-2.1.9 : Tue Dec 09 2003 - 16:11:45 MST