--------------------- PatchSet 118 Date: 2000/04/14 23:09:53 Author: hno Branch: ntlm Tag: (none) Log: Merged my old squid-1.2.beta23.request_body_processing.patch to have a saner processing model for request entities. I don't feel it is motivated to add yet another workaround to the pump.c module, and HTTP request message boumdary processing belongs in client_side.c/clientReadRequest, nowhere else. Members: ChangeLog:1.1.1.3->1.1.1.3.10.1 src/HttpRequest.c:1.1.1.3->1.1.1.3.10.1 src/client_side.c:1.1.1.3.4.1.2.2->1.1.1.3.4.1.2.3 src/forward.c:1.1.1.3->1.1.1.3.12.1 src/ftp.c:1.1.1.3.4.1->1.1.1.3.4.1.2.1 src/http.c:1.1.1.3.4.1->1.1.1.3.4.1.2.1 src/protos.h:1.1.1.3.12.1->1.1.1.3.12.2 src/pump.c:1.1.1.3->1.1.1.3.12.1(DEAD) src/structs.h:1.1.1.3.4.1.2.1->1.1.1.3.4.1.2.2 src/typedefs.h:1.1.1.3->1.1.1.3.12.1 Index: squid/ChangeLog =================================================================== RCS file: /cvsroot/squid-sf//squid/ChangeLog,v retrieving revision 1.1.1.3 retrieving revision 1.1.1.3.10.1 diff -u -r1.1.1.3 -r1.1.1.3.10.1 --- squid/ChangeLog 26 Jan 2000 03:25:00 -0000 1.1.1.3 +++ squid/ChangeLog 14 Apr 2000 23:09:53 -0000 1.1.1.3.10.1 @@ -1,3 +1,7 @@ + - 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. + Changes to Squid-2.3.STABLE1 (Jan 9, 2000): - Updated PAM authentication module from Henrik Nordstrom. Index: squid/src/HttpRequest.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/HttpRequest.c,v retrieving revision 1.1.1.3 retrieving revision 1.1.1.3.10.1 diff -u -r1.1.1.3 -r1.1.1.3.10.1 --- squid/src/HttpRequest.c 26 Jan 2000 03:25:01 -0000 1.1.1.3 +++ squid/src/HttpRequest.c 14 Apr 2000 23:09:53 -0000 1.1.1.3.10.1 @@ -1,6 +1,6 @@ /* - * $Id: HttpRequest.c,v 1.1.1.3 2000/01/26 03:25:01 hno Exp $ + * $Id: HttpRequest.c,v 1.1.1.3.10.1 2000/04/14 23:09:53 hno Exp $ * * DEBUG: section 73 HTTP Request * AUTHOR: Duane Wessels @@ -55,7 +55,8 @@ requestDestroy(request_t * req) { assert(req); - safe_free(req->body); + if (req->body_connection) + clientAbortBody(req); safe_free(req->canonical); stringClean(&req->urlpath); httpHeaderClean(&req->header); Index: squid/src/client_side.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/client_side.c,v retrieving revision 1.1.1.3.4.1.2.2 retrieving revision 1.1.1.3.4.1.2.3 diff -u -r1.1.1.3.4.1.2.2 -r1.1.1.3.4.1.2.3 --- squid/src/client_side.c 12 Feb 2000 00:42:52 -0000 1.1.1.3.4.1.2.2 +++ squid/src/client_side.c 14 Apr 2000 23:09:53 -0000 1.1.1.3.4.1.2.3 @@ -1,6 +1,6 @@ /* - * $Id: client_side.c,v 1.1.1.3.4.1.2.2 2000/02/12 00:42:52 asd Exp $ + * $Id: client_side.c,v 1.1.1.3.4.1.2.3 2000/04/14 23:09:53 hno Exp $ * * DEBUG: section 33 Client-side Routines * AUTHOR: Duane Wessels @@ -106,6 +106,7 @@ static log_type clientProcessRequest2(clientHttpRequest * http); static int clientReplyBodyTooLarge(int clen); static int clientRequestBodyTooLarge(int clen); +static void clientProcessBody(ConnStateData *conn); static int checkAccelOnly(clientHttpRequest * http) @@ -284,10 +285,9 @@ new_request->my_addr = old_request->my_addr; new_request->my_port = old_request->my_port; new_request->flags.redirected = 1; - 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; } new_request->content_length = old_request->content_length; requestUnlink(old_request); @@ -644,6 +644,8 @@ MemObject *mem = NULL; debug(33, 3) ("httpRequestFree: %s\n", storeUrl(http->entry)); if (!clientCheckTransferDone(http)) { + if (request && request->body_connection) + clientAbortBody(request); /* abort body transter */ if ((e = http->entry)) { http->entry = NULL; storeUnregister(e, http); @@ -713,6 +715,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) @@ -911,14 +914,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; @@ -1737,7 +1744,7 @@ if ((http = conn->chr) == NULL) { debug(33, 5) ("clientKeepaliveNextRequest: FD %d reading next req\n", conn->fd); - fd_note(conn->fd, "Reading next request"); + fd_note(conn->fd, "Waiting for next request"); /* * Set the timeout BEFORE calling clientReadRequest(). */ @@ -1958,10 +1965,6 @@ } /* yes, continue */ http->log_type = LOG_TCP_MISS; - } else if (r->content_length > 0) { - http->log_type = LOG_TCP_MISS; - /* XXX oof, POST can be cached! */ - pumpInit(fd, r, http->uri); } else { http->log_type = clientProcessRequest2(http); } @@ -2292,7 +2295,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 @@ -2324,14 +2330,19 @@ * 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) { + 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; } @@ -2341,7 +2352,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()); @@ -2352,13 +2367,17 @@ return; } /* Continue to process previously read data */ - size = 0; } conn->in.offset += size; - /* Skip leading (and trailing) whitespace */ - while (conn->in.offset > 0) { + commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, conn, 0); + /* Process request body if any */ + if (conn->in.offset > 0 && conn->body.callback != NULL) + clientProcessBody(conn); + /* Process next request */ + while (conn->in.offset > 0 && conn->body.size_left == 0) { int nrequests; size_t req_line_sz; + /* Skip leading (and trailing) whitespace */ while (conn->in.offset > 0 && xisspace(conn->in.buf[0])) { xmemmove(conn->in.buf, conn->in.buf + 1, conn->in.offset - 1); conn->in.offset--; @@ -2374,6 +2393,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, @@ -2461,7 +2483,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); @@ -2471,38 +2493,13 @@ break; } http->request = requestLink(request); - /* - * We need to set the keepalive flag before doing some - * hacks for POST/PUT requests below. Maybe we could - * set keepalive flag even earlier. - */ clientSetKeepaliveFlag(http); - /* - * break here if the request has a content-length - * because there is a reqeust body following and we - * don't want to parse it as though it was new request. - */ - if (request->content_length >= 0) { - int copy_len = XMIN(conn->in.offset, request->content_length); - if (copy_len > 0) { - assert(conn->in.offset >= copy_len); - request->body_sz = copy_len; - request->body = xmalloc(request->body_sz); - xmemcpy(request->body, conn->in.buf, request->body_sz); - conn->in.offset -= copy_len; - if (conn->in.offset) - xmemmove(conn->in.buf, conn->in.buf + copy_len, conn->in.offset); - } - /* - * if we didn't get the full body now, then more will - * be arriving on the client socket. Lets cancel - * the read handler until this request gets forwarded. - */ - if (request->body_sz < request->content_length) - commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0); - if (request->content_length < 0) - (void) 0; - else if (clientRequestBodyTooLarge(request->content_length)) { + /* Do we expect a request-body? */ + if (request->content_length > 0) { + conn->body.size_left = request->content_length; + request->body_connection = conn; + /* Is it too large? */ + if (clientRequestBodyTooLarge(request->content_length)) { err = errorCon(ERR_TOO_BIG, HTTP_REQUEST_ENTITY_TOO_LARGE); err->request = requestLink(request); http->entry = clientCreateStoreEntry(http, @@ -2512,7 +2509,7 @@ } } clientAccessCheck(http); - continue; /* while offset > 0 */ + continue; /* while offset > 0 && body.size_left == 0 */ } else if (parser_return_code == 0) { /* * Partial request received; reschedule until parseHttpRequest() @@ -2545,9 +2542,132 @@ } 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, 2) ("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, 2) ("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, 2) ("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; + /* Remember that we have touched the body, not restartable */ + request->flags.body_sent = 1; + /* Invoke callback function */ + callback(buf, size, cbdata); + if (request != NULL) + requestUnlink(request); /* Linked in clientReadBody */ + debug(33, 2) ("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, 2) ("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 */ static void requestTimeout(int fd, void *data) Index: squid/src/forward.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/forward.c,v retrieving revision 1.1.1.3 retrieving revision 1.1.1.3.12.1 diff -u -r1.1.1.3 -r1.1.1.3.12.1 --- squid/src/forward.c 26 Jan 2000 03:25:01 -0000 1.1.1.3 +++ squid/src/forward.c 14 Apr 2000 23:09:53 -0000 1.1.1.3.12.1 @@ -1,6 +1,6 @@ /* - * $Id: forward.c,v 1.1.1.3 2000/01/26 03:25:01 hno Exp $ + * $Id: forward.c,v 1.1.1.3.12.1 2000/04/14 23:09:53 hno Exp $ * * DEBUG: section 17 Request Forwarding * AUTHOR: Duane Wessels @@ -112,9 +112,8 @@ return 0; if (fwdState->flags.dont_retry) return 0; - if (fwdState->request->content_length >= 0) - if (0 == pumpRestart(fwdState->request)) - return 0; + if (fwdState->request->flags.body_sent) + return 0; return 1; } @@ -376,9 +375,8 @@ } if (fwdState->n_tries > 9) return 0; - if (fwdState->request->content_length >= 0) - if (0 == pumpRestart(fwdState->request)) - return 0; + if (fwdState->request->flags.body_sent) + return 0; assert(fs); fwdState->servers = fs->next; fwdServerFree(fs); Index: squid/src/ftp.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/ftp.c,v retrieving revision 1.1.1.3.4.1 retrieving revision 1.1.1.3.4.1.2.1 diff -u -r1.1.1.3.4.1 -r1.1.1.3.4.1.2.1 --- squid/src/ftp.c 4 Feb 2000 19:39:40 -0000 1.1.1.3.4.1 +++ squid/src/ftp.c 14 Apr 2000 23:09:53 -0000 1.1.1.3.4.1.2.1 @@ -1,6 +1,6 @@ /* - * $Id: ftp.c,v 1.1.1.3.4.1 2000/02/04 19:39:40 hno Exp $ + * $Id: ftp.c,v 1.1.1.3.4.1.2.1 2000/04/14 23:09:53 hno Exp $ * * DEBUG: section 9 File Transfer Protocol (FTP) * AUTHOR: Harvest Derived @@ -148,8 +148,9 @@ /* Local functions */ static CNCB ftpPasvCallback; static PF ftpDataRead; +static PF ftpDataWrite; +static CWCB ftpDataWriteCallback; static PF ftpStateFree; -static PF ftpPumpClosedData; static PF ftpTimeout; static PF ftpReadControlReply; static CWCB ftpWriteCommandCallback; @@ -159,8 +160,6 @@ static void ftpAppendSuccessHeader(FtpStateData * ftpState); static void ftpAuthRequired(HttpReply * reply, request_t * request, const char *realm); static void ftpHackShortcut(FtpStateData * ftpState, FTPSM * nextState); -static void ftpPutStart(FtpStateData *); -static CWCB ftpPutTransferDone; static void ftpUnhack(FtpStateData * ftpState); static void ftpScheduleReadControlReply(FtpStateData *, int); static void ftpHandleControlReply(FtpStateData *); @@ -194,6 +193,7 @@ static FTPSM ftpGetFile; static FTPSM ftpSendCwd; static FTPSM ftpReadCwd; +static FTPSM ftpRestOrList; static FTPSM ftpSendList; static FTPSM ftpSendNlst; static FTPSM ftpReadList; @@ -202,16 +202,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) ** ************************************************* @@ -222,17 +221,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 - ************************************************/ @@ -255,7 +258,8 @@ ftpReadStor, /* SENT_STOR */ ftpReadQuit, /* SENT_QUIT */ ftpReadTransferDone, /* READING_DATA (RETR,LIST,NLST) */ - ftpSendReply, /* WRITING_DATA (STOR) */ + ftpWriteTransferDone, /* WRITING_DATA (STOR) */ + ftpSendReply, /* WRITTEN_DATA? (STOR) */ ftpReadMkdir /* SENT_MKDIR */ }; @@ -834,10 +838,10 @@ } 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 > -1) { /* * close data socket so it does not occupy resources while @@ -858,7 +862,6 @@ int j; int bin; StoreEntry *entry = ftpState->entry; - MemObject *mem = entry->mem_obj; size_t read_sz; #if DELAY_POOLS delay_id delay_id = delayMostBytesAllowed(mem); @@ -896,7 +899,7 @@ ftpListingStart(ftpState); } 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, @@ -909,7 +912,7 @@ return; } } else if (len == 0) { - ftpReadComplete(ftpState); + ftpDataComplete(ftpState); } else { if (ftpState->flags.isdir) { ftpParseListing(ftpState); @@ -917,14 +920,11 @@ storeAppend(entry, ftpState->data.buf, len); ftpState->data.offset = 0; } - 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); } } @@ -1128,7 +1128,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()); ftpFailed(ftpState, ERR_WRITE_ERROR); /* ftpFailed closes ctrl.fd and frees ftpState */ return; @@ -1247,7 +1247,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)) { ftpScheduleReadControlReply(ftpState, 0); } else { @@ -1527,15 +1527,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; @@ -1897,14 +1897,17 @@ 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 (ftpRestartable(ftpState)) @@ -1940,14 +1943,20 @@ if (code == 125 || (code == 150 && ftpState->data.host)) { /* Begin data transfer */ debug(9, 3) ("ftpReadStor: starting data transfer\n"); + commSetSelect(ftpState->data.fd, + COMM_SELECT_WRITE, + ftpDataWrite, + ftpState, + Config.Timeout.read); /* - * Cancel the timeout on the Control socket, pumpStart will + * 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"); + commSetTimeout(ftpState->data.fd, Config.Timeout.read, ftpTimeout, + ftpState); ftpState->state = WRITING_DATA; + debug(9, 3) ("ftpReadStor: writing data channel\n"); } else if (code == 150) { /* Accept data channel */ debug(9, 3) ("ftpReadStor: accepting data channel\n"); @@ -2144,11 +2153,7 @@ /* Connection closed; retrieval done. */ if (ftpState->flags.html_header_sent) ftpListingFinish(ftpState); - if (!ftpState->flags.put) { - storeTimestampsSet(ftpState->entry); - fwdComplete(ftpState->fwd); - } - ftpDataTransferDone(ftpState); + ftpSendQuit(ftpState); } else { /* != 226 */ debug(9, 1) ("ftpReadTransferDone: Got code %d after reading data\n", code); @@ -2158,15 +2163,62 @@ } } +/* 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"); + ftpFailed(ftpState, ERR_READ_ERROR); + } else if (size == 0) { + /* End of transfer */ + ftpDataComplete(ftpState); } - ftpSendQuit(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()); + ftpFailed(ftpState, ERR_WRITE_ERROR); + } +} + +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); + ftpFailed(ftpState, ERR_FTP_PUT_ERROR); + return; + } + storeTimestampsSet(ftpState->entry); /* XXX Is this needed? */ + ftpSendReply(ftpState); } static void @@ -2358,48 +2410,6 @@ } static void -ftpPumpClosedData(int data_fd, void *data) -{ - FtpStateData *ftpState = data; - assert(data_fd == ftpState->data.fd); - /* - * Ugly pump module closed our server-side. Deal with it. - * The data FD is already closed, so just set it to -1. - */ - ftpState->data.fd = -1; - /* - * Currently, thats all we have to do. Because the upload failed, - * storeAbort() will be called on the reply entry. That will - * call fwdAbort, which closes ftpState->ctrl.fd and then - * ftpStateFree gets called. - */ -} - -static void -ftpPutStart(FtpStateData * ftpState) -{ - debug(9, 3) ("ftpPutStart\n"); - /* - * sigh, we need this gross hack to detect when ugly pump module - * aborts and wants to close the server-side. - */ - comm_add_close_handler(ftpState->data.fd, ftpPumpClosedData, ftpState); - pumpStart(ftpState->data.fd, ftpState->fwd, 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_remove_close_handler(fd, ftpPumpClosedData, ftpState); - comm_close(ftpState->data.fd); - ftpState->data.fd = -1; - } - ftpReadComplete(ftpState); -} - -static void ftpSendReply(FtpStateData * ftpState) { ErrorState *err; Index: squid/src/http.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/http.c,v retrieving revision 1.1.1.3.4.1 retrieving revision 1.1.1.3.4.1.2.1 diff -u -r1.1.1.3.4.1 -r1.1.1.3.4.1.2.1 --- squid/src/http.c 4 Feb 2000 19:39:40 -0000 1.1.1.3.4.1 +++ squid/src/http.c 14 Apr 2000 23:09:53 -0000 1.1.1.3.4.1.2.1 @@ -1,6 +1,6 @@ /* - * $Id: http.c,v 1.1.1.3.4.1 2000/02/04 19:39:40 hno Exp $ + * $Id: http.c,v 1.1.1.3.4.1.2.1 2000/04/14 23:09:53 hno Exp $ * * DEBUG: section 11 Hypertext Transfer Protocol (HTTP) * AUTHOR: Harvest Derived @@ -44,7 +44,6 @@ static CWCB httpSendComplete; static CWCB httpSendRequestEntry; -static CWCB httpSendRequestEntryDone; static PF httpReadReply; static void httpSendRequest(HttpStateData *); @@ -834,7 +833,7 @@ debug(11, 5) ("httpSendRequest: FD %d: httpState %p.\n", httpState->fd, httpState); - if (httpState->orig_request->content_length > 0) + if (httpState->orig_request->body_connection) sendHeaderDone = httpSendRequestEntry; else sendHeaderDone = httpSendComplete; @@ -931,43 +930,50 @@ } static void -httpSendRequestEntry(int fd, char *bufnotused, size_t size, int errflag, void *data) +httpSendRequestEntryDone(int fd, void *data) { HttpStateData *httpState = data; - StoreEntry *entry = httpState->entry; - ErrorState *err; - debug(11, 5) ("httpSendRequestEntry: FD %d: size %d: errflag %d.\n", - fd, size, errflag); - if (size > 0) { - fd_bytes(fd, size, FD_WRITE); - kb_incr(&Counter.server.all.kbytes_out, size); - kb_incr(&Counter.server.http.kbytes_out, size); - } - if (errflag == COMM_ERR_CLOSING) - return; - if (errflag) { - err = errorCon(ERR_WRITE_ERROR, HTTP_INTERNAL_SERVER_ERROR); - err->xerrno = errno; - err->request = requestLink(httpState->orig_request); - errorAppendEntry(entry, err); - comm_close(fd); - return; + aclCheck_t ch; + debug(11, 5) ("httpSendRequestEntryDone: FD %d\n", + fd); + memset(&ch, '\0', sizeof(ch)); + ch.request = httpState->request; + if (!Config.accessList.brokenPosts) { + debug(11, 5) ("httpSendRequestEntryDone: No brokenPosts list\n"); + httpSendComplete(fd, NULL, 0, 0, data); + } else if (!aclCheckFast(Config.accessList.brokenPosts, &ch)) { + debug(11, 5) ("httpSendRequestEntryDone: didn't match brokenPosts\n"); + httpSendComplete(fd, NULL, 0, 0, data); + } else { + debug(11, 2) ("httpSendRequestEntryDone: matched brokenPosts\n"); + comm_write(fd, "\r\n", 2, httpSendComplete, data, NULL); } - if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { - comm_close(fd); - return; +} + +static void +httpRequestBodyHandler(char *buf, size_t size, void *data) +{ + HttpStateData *httpState = (HttpStateData *)data; + if ( size > 0 ) { + comm_write(httpState->fd, buf, size, httpSendRequestEntry, data, memFree8K); + } else if (size == 0) { + /* End of body */ + memFree8K(buf); + httpSendRequestEntryDone(httpState->fd, data); + } else { + /* Failed to get whole body, probably aborted */ + memFree8K(buf); + httpSendComplete(httpState->fd, NULL, 0, COMM_ERR_CLOSING, data); } - pumpStart(fd, httpState->fwd, httpSendRequestEntryDone, httpState); } static void -httpSendRequestEntryDone(int fd, char *bufnotused, size_t size, int errflag, void *data) +httpSendRequestEntry(int fd, char *bufnotused, size_t size, int errflag, void *data) { HttpStateData *httpState = data; StoreEntry *entry = httpState->entry; ErrorState *err; - aclCheck_t ch; - debug(11, 5) ("httpSendRequestEntryDone: FD %d: size %d: errflag %d.\n", + debug(11, 5) ("httpSendRequestEntry: FD %d: size %d: errflag %d.\n", fd, size, errflag); if (size > 0) { fd_bytes(fd, size, FD_WRITE); @@ -984,16 +990,9 @@ comm_close(fd); return; } - memset(&ch, '\0', sizeof(ch)); - ch.request = httpState->request; - if (!Config.accessList.brokenPosts) { - debug(11, 5) ("httpSendRequestEntryDone: No brokenPosts list\n"); - httpSendComplete(fd, NULL, 0, 0, data); - } else if (!aclCheckFast(Config.accessList.brokenPosts, &ch)) { - debug(11, 5) ("httpSendRequestEntryDone: didn't match brokenPosts\n"); - httpSendComplete(fd, NULL, 0, 0, data); - } else { - debug(11, 2) ("httpSendRequestEntryDone: matched brokenPosts\n"); - comm_write(fd, "\r\n", 2, httpSendComplete, data, NULL); + if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { + comm_close(fd); + return; } + clientReadBody(httpState->orig_request, memAllocate(MEM_8K_BUF), 8192, httpRequestBodyHandler, httpState); } Index: squid/src/protos.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/protos.h,v retrieving revision 1.1.1.3.12.1 retrieving revision 1.1.1.3.12.2 diff -u -r1.1.1.3.12.1 -r1.1.1.3.12.2 --- squid/src/protos.h 5 Feb 2000 20:14:19 -0000 1.1.1.3.12.1 +++ squid/src/protos.h 14 Apr 2000 23:09:53 -0000 1.1.1.3.12.2 @@ -1,6 +1,6 @@ /* - * $Id: protos.h,v 1.1.1.3.12.1 2000/02/05 20:14:19 hno Exp $ + * $Id: protos.h,v 1.1.1.3.12.2 2000/04/14 23:09:53 hno Exp $ * * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ @@ -136,6 +136,8 @@ extern void clientHttpConnectionsClose(void); extern StoreEntry *clientCreateStoreEntry(clientHttpRequest *, method_t, request_flags); 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 int commUnsetNonBlocking(int fd); @@ -1040,11 +1042,6 @@ extern void PrintRusage(void); extern void dumpMallocStats(void); -extern void pumpInit(int fd, request_t * r, char *uri); -extern void pumpStart(int, FwdState *, CWCB * callback, void *); -extern int pumpMethod(method_t method); -extern int pumpRestart(request_t *); - extern void unlinkdInit(void); extern void unlinkdClose(void); extern void unlinkdUnlink(const char *); --- squid/src/pump.c Wed Feb 14 00:43:18 2007 +++ /dev/null Wed Feb 14 00:42:24 2007 @@ -1,437 +0,0 @@ -/* - * $Id: pump.c,v 1.1.1.3 2000/01/26 03:25:01 hno Exp $ - * - * DEBUG: section 61 PUMP handler - * AUTHOR: Kostas Anagnostakis - * - * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ - * ---------------------------------------------------------- - * - * Squid is the result of efforts by numerous individuals from the - * Internet community. Development is led by Duane Wessels of the - * National Laboratory for Applied Network Research and funded by the - * National Science Foundation. Squid is Copyrighted (C) 1998 by - * Duane Wessels and the University of California San Diego. Please - * see the COPYRIGHT file for full details. Squid incorporates - * software developed and/or copyrighted by other sources. Please see - * the CREDITS file for full details. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. - * - */ - -#include "squid.h" - -#define PUMP_MAXBUFFER 2*SQUID_UDP_SO_SNDBUF - -struct _PumpStateData { - FwdState *fwd; - request_t *req; - int c_fd; /* client fd */ - int s_fd; /* server end */ - int rcvd; /* bytes received from client */ - int sent; /* bytes sent to server */ - StoreEntry *request_entry; /* the request entry */ - StoreEntry *reply_entry; /* the reply entry */ - CWCB *callback; /* what to do when we finish sending */ - void *cbdata; /* callback data passed to callback func */ - struct { - int closing:1; - } flags; - struct _PumpStateData *next; -}; - -#define PUMP_FLAG_CLOSING 0x01 - -typedef struct _PumpStateData PumpStateData; - -static PumpStateData *pump_head = NULL; - -static PF pumpReadFromClient; -static STCB pumpServerCopy; -static CWCB pumpServerCopyComplete; -static PF pumpFree; -static PF pumpTimeout; -static PF pumpServerClosed; -static DEFER pumpReadDefer; -static void pumpClose(void *data); - -void -pumpInit(int fd, request_t * r, char *uri) -{ - request_flags flags; - LOCAL_ARRAY(char, new_key, MAX_URL + 8); - PumpStateData *p = xcalloc(1, sizeof(PumpStateData)); - debug(61, 3) ("pumpInit: FD %d, uri=%s\n", fd, uri); - /* - * create a StoreEntry which will buffer the data - * to be pumped - */ - assert(fd > -1); - assert(uri != NULL); - assert(r != NULL); - /* we shouldn't have gotten this far if content-length is invalid */ - assert(r->content_length >= 0); - debug(61, 4) ("pumpInit: Content-Length=%d.\n", r->content_length); - flags = null_request_flags; - flags.nocache = 1; - snprintf(new_key, MAX_URL + 5, "%s|Pump", uri); - cbdataAdd(p, cbdataXfree, 0); - p->request_entry = storeCreateEntry(new_key, new_key, flags, r->method); - storeClientListAdd(p->request_entry, p); - EBIT_SET(p->request_entry->flags, ENTRY_DONT_LOG); -#if DELAY_POOLS - delaySetStoreClient(p->request_entry, p, delayClient(r)); -#endif - /* - * initialize data structure - */ - p->c_fd = fd; - p->s_fd = -1; - p->req = requestLink(r); - p->callback = NULL; - p->cbdata = NULL; - p->next = pump_head; - pump_head = p; - comm_add_close_handler(p->c_fd, pumpFree, p); - commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0); - debug(61, 4) ("pumpInit: FD %d, Created %p\n", fd, p); -} - -void -pumpStart(int s_fd, FwdState * fwd, CWCB * callback, void *cbdata) -{ - PumpStateData *p = NULL; - request_t *r = fwd->request; - size_t copy_sz; - debug(61, 3) ("pumpStart: FD %d, key %s\n", - s_fd, storeKeyText(fwd->entry->key)); - /* - * find state data generated by pumpInit in linked list - */ - for (p = pump_head; p && p->req != r; p = p->next); - assert(p != NULL); - assert(p->request_entry); - assert(p->c_fd > -1); - assert(r == p->req); - /* - * fill in the rest of data needed by the pump - */ - p->fwd = fwd; - p->s_fd = s_fd; - p->reply_entry = fwd->entry; - p->callback = callback; - p->cbdata = cbdata; - cbdataLock(p->cbdata); - storeLockObject(p->reply_entry); - comm_add_close_handler(p->s_fd, pumpServerClosed, p); - /* - * see if part of the body is in the request - */ - if (p->rcvd < p->req->content_length && r->body_sz > 0) { - assert(p->request_entry->store_status == STORE_PENDING); - assert(r->body != NULL); - assert(r->body_sz <= p->req->content_length); - copy_sz = XMIN(r->body_sz, p->req->content_length); - debug(61, 3) ("pumpStart: Appending %d bytes from r->body\n", copy_sz); - storeAppend(p->request_entry, r->body, copy_sz); - p->rcvd = copy_sz; - } - /* - * Do we need to read more data from the client? - */ - if (p->rcvd < p->req->content_length) { - assert(p->request_entry->store_status == STORE_PENDING); - commSetSelect(p->c_fd, COMM_SELECT_READ, pumpReadFromClient, p, 0); - commSetTimeout(p->c_fd, Config.Timeout.read, pumpTimeout, p); - commSetDefer(p->c_fd, pumpReadDefer, p); - } - p->sent = 0; - if (p->sent == p->req->content_length) { - pumpServerCopyComplete(p->s_fd, NULL, 0, DISK_OK, p); - } else { - storeClientCopy(p->request_entry, p->sent, p->sent, 4096, - memAllocate(MEM_4K_BUF), - pumpServerCopy, p); - } -} - -static void -pumpServerCopy(void *data, char *buf, ssize_t size) -{ - PumpStateData *p = data; - debug(61, 5) ("pumpServerCopy: called with size=%d\n", size); - if (size < 0) { - debug(61, 5) ("pumpServerCopy: freeing and returning\n"); - memFree(buf, MEM_4K_BUF); - return; - } - if (size == 0) { - debug(61, 5) ("pumpServerCopy: done, finishing\n", size); - pumpServerCopyComplete(p->s_fd, NULL, 0, DISK_OK, p); - memFree(buf, MEM_4K_BUF); - return; - } - debug(61, 5) ("pumpServerCopy: to FD %d, %d bytes\n", p->s_fd, size); - comm_write(p->s_fd, buf, size, pumpServerCopyComplete, p, memFree4K); -} - -static void -pumpServerCopyComplete(int fd, char *bufnotused, size_t size, int errflag, void *data) -{ - PumpStateData *p = data; - int sfd; - debug(61, 5) ("pumpServerCopyComplete: called with size=%d (%d,%d)\n", - size, p->sent + size, p->req->content_length); - if (errflag == COMM_ERR_CLOSING) - return; - if (errflag != 0) { - debug(61, 5) ("pumpServerCopyComplete: aborted, errflag %d\n", errflag); - pumpClose(p); - return; - } - if (EBIT_TEST(p->request_entry->flags, ENTRY_ABORTED)) { - debug(61, 5) ("pumpServerCopyComplete: ENTRY_ABORTED\n"); - pumpClose(p); - return; - } - p->sent += size; - assert(p->sent <= p->req->content_length); - if (p->sent < p->req->content_length) { - storeClientCopy(p->request_entry, p->sent, p->sent, 4096, - memAllocate(MEM_4K_BUF), - pumpServerCopy, p); - return; - } - debug(61, 5) ("pumpServerCopyComplete: Done!\n", size); - /* - * we don't care what happens on the server side now - */ - sfd = p->s_fd; - comm_remove_close_handler(p->s_fd, pumpServerClosed, p); - p->s_fd = -1; - if (cbdataValid(p->cbdata)) - p->callback(sfd, NULL, p->sent, 0, p->cbdata); - cbdataUnlock(p->cbdata); - storeUnlockObject(p->reply_entry); - p->reply_entry = NULL; -} - - -static void -pumpReadFromClient(int fd, void *data) -{ - PumpStateData *p = data; - StoreEntry *req = p->request_entry; - LOCAL_ARRAY(char, buf, SQUID_TCP_SO_RCVBUF); - int bytes_to_read = XMIN(p->req->content_length - p->rcvd, SQUID_TCP_SO_RCVBUF); - int len = 0; - errno = 0; - Counter.syscalls.sock.reads++; - len = read(fd, buf, bytes_to_read); - fd_bytes(fd, len, FD_READ); - debug(61, 5) ("pumpReadFromClient: FD %d: len %d.\n", fd, len); - if (len > 0) { - (void) 0; /* continue */ - } else if (len < 0) { - debug(61, 2) ("pumpReadFromClient: FD %d: read failure: %s.\n", - fd, xstrerror()); - if (ignoreErrno(errno)) { - debug(61, 5) ("pumpReadFromClient: FD %d: len %d and ignore!\n", - fd, len); - commSetSelect(fd, - COMM_SELECT_READ, - pumpReadFromClient, - p, - Config.Timeout.read); - } else { - debug(61, 2) ("pumpReadFromClient: aborted.\n"); - pumpClose(p); - } - return; - } else if (req->mem_obj->inmem_hi == 0) { - debug(61, 2) ("pumpReadFromClient: FD %d: failed.\n", fd); - pumpClose(p); - return; - } else if (p->rcvd < p->req->content_length) { - debug(61, 4) ("pumpReadFromClient: FD %d, incomplete request\n", fd); - pumpClose(p); - return; - } - if (len > 0) { - int delta = p->rcvd + len - p->req->content_length; - if (delta > 0 && p->req->flags.proxy_keepalive) { - debug(61, delta == 2 ? 3 : 1) ("pumpReadFromClient: Warning: read %d bytes past content-length, truncating\n", delta); - len = p->req->content_length - p->rcvd; - } - storeAppend(req, buf, len); - p->rcvd += len; - } - if (p->rcvd < p->req->content_length) { - /* We need more data */ - commSetSelect(fd, COMM_SELECT_READ, pumpReadFromClient, - p, Config.Timeout.read); - return; - } - /* all done! */ - if (p->req->flags.proxy_keepalive) - assert(p->rcvd == p->req->content_length); - debug(61, 2) ("pumpReadFromClient: finished!\n"); - storeComplete(req); - commSetDefer(p->c_fd, NULL, NULL); - commSetTimeout(p->c_fd, -1, NULL, NULL); -} - -static int -pumpReadDefer(int fd, void *data) -{ - PumpStateData *p = data; - assert(p->rcvd >= p->sent); - if ((p->rcvd - p->sent) < PUMP_MAXBUFFER) - return 0; - debug(61, 5) ("pumpReadDefer: deferring, rcvd=%d, sent=%d\n", - p->rcvd, p->sent); - return 1; -} - -static void -pumpClose(void *data) -{ - PumpStateData *p = data; - StoreEntry *req = p->request_entry; - StoreEntry *rep = p->reply_entry; - cbdataLock(p); - debug(61, 3) ("pumpClose: %p Server FD %d, Client FD %d\n", - p, p->s_fd, p->c_fd); - /* double-call detection */ - assert(!p->flags.closing); - p->flags.closing = 1; - if (req != NULL && req->store_status == STORE_PENDING) { - storeUnregister(req, p); - } - if (rep != NULL && rep->store_status == STORE_PENDING) { - ErrorState *err = errorCon(ERR_READ_ERROR, HTTP_INTERNAL_SERVER_ERROR); - fwdFail(p->fwd, err); - } - if (p->s_fd > -1) { - comm_close(p->s_fd); - p->s_fd = -1; - } - if (p->c_fd > -1) { - comm_close(p->c_fd); - } - /* This tests that pumpFree() got called somewhere */ - assert(0 == cbdataValid(p)); - cbdataUnlock(p); -} - -static void -pumpFree(int fd, void *data) -{ - PumpStateData *p = NULL; - PumpStateData *q = NULL; - StoreEntry *req; - StoreEntry *rep; - debug(61, 3) ("pumpFree: FD %d, releasing %p!\n", fd, data); - for (p = pump_head; p && p != data; q = p, p = p->next); - if (p == NULL) { - debug(61, 1) ("pumpFree: p=%p not found?\n", p); - return; - } - if (q) - q->next = p->next; - else - pump_head = p->next; - assert(fd == p->c_fd); - p->c_fd = -1; - req = p->request_entry; - rep = p->reply_entry; - if (req != NULL) { - storeUnregister(req, p); - storeUnlockObject(req); - p->request_entry = NULL; - } - if (rep != NULL) { - debug(61, 3) ("pumpFree: did the server-side FD (%d) get closed?\n", p->s_fd); - storeUnlockObject(rep); - p->reply_entry = NULL; - } - requestUnlink(p->req); - if (p->s_fd > -1) { - assert(!fd_table[p->s_fd].flags.open); - p->s_fd = -1; - } - cbdataFree(p); -} - -static void -pumpTimeout(int fd, void *data) -{ - PumpStateData *p = data; - debug(61, 3) ("pumpTimeout: FD %d\n", p->c_fd); - pumpClose(p); -} - -/* - *This is called only if the client connect closes unexpectedly - */ -static void -pumpServerClosed(int fd, void *data) -{ - PumpStateData *p = data; - debug(61, 3) ("pumpServerClosed: FD %d\n", fd); - /* - * we have been called from comm_close for the server side, so - * just need to clean up the client side - */ - assert(p->s_fd == fd); - p->s_fd = -1; - if (p->flags.closing) - return; - if (p->c_fd > -1) - comm_close(p->c_fd); -} - -/* - * This function returns True if we can submit this request again. - * The request may have been pipelined, but the connection got - * closed before we got a reply. If we still have the whole - * request in memory then we can send it again. If we want to - * be able to restart very large requests, then we'll have to - * swap them out to disk. - */ -int -pumpRestart(request_t * r) -{ - PumpStateData *p; - MemObject *mem; - for (p = pump_head; p && p->req != r; p = p->next); - if (p == NULL) { - debug(61, 3) ("pumpRestart: NO: Can't find pumpState!\n"); - return 0; - } - mem = p->request_entry->mem_obj; - if (mem == NULL) { - debug(61, 3) ("pumpRestart: NO: request_entry->mem_obj == NULL!\n"); - return 0; - } - if (mem->inmem_lo > 0) { - debug(61, 3) ("pumpRestart: NO: mem->inmem_lo == %d\n", - (int) mem->inmem_lo); - return 0; - } - debug(61, 3) ("pumpRestart: YES!\n"); - return 1; -} Index: squid/src/structs.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/structs.h,v retrieving revision 1.1.1.3.4.1.2.1 retrieving revision 1.1.1.3.4.1.2.2 diff -u -r1.1.1.3.4.1.2.1 -r1.1.1.3.4.1.2.2 --- squid/src/structs.h 5 Feb 2000 20:14:19 -0000 1.1.1.3.4.1.2.1 +++ squid/src/structs.h 14 Apr 2000 23:09:53 -0000 1.1.1.3.4.1.2.2 @@ -1,6 +1,6 @@ /* - * $Id: structs.h,v 1.1.1.3.4.1.2.1 2000/02/05 20:14:19 hno Exp $ + * $Id: structs.h,v 1.1.1.3.4.1.2.2 2000/04/14 23:09:53 hno Exp $ * * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ @@ -892,6 +892,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; @@ -1386,6 +1394,7 @@ #endif unsigned int accelerated:1; unsigned int internal:1; + unsigned int body_sent:1; }; struct _link_list { @@ -1453,8 +1462,7 @@ struct in_addr my_addr; unsigned short my_port; HttpHeader header; - char *body; - size_t body_sz; + ConnStateData *body_connection; /* used by clientReadBody() */ int content_length; HierarchyLogEntry hier; err_type err_type; Index: squid/src/typedefs.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/typedefs.h,v retrieving revision 1.1.1.3 retrieving revision 1.1.1.3.12.1 diff -u -r1.1.1.3 -r1.1.1.3.12.1 --- squid/src/typedefs.h 26 Jan 2000 03:25:01 -0000 1.1.1.3 +++ squid/src/typedefs.h 14 Apr 2000 23:09:53 -0000 1.1.1.3.12.1 @@ -1,6 +1,6 @@ /* - * $Id: typedefs.h,v 1.1.1.3 2000/01/26 03:25:01 hno Exp $ + * $Id: typedefs.h,v 1.1.1.3.12.1 2000/04/14 23:09:53 hno Exp $ * * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ @@ -197,6 +197,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 STIOCB(void *their_data, int errflag, storeIOState *); typedef void STRCB(void *their_data, const char *buf, ssize_t len);