From: Amos Jeffries Date: Mon, 13 Sep 2010 05:39:51 +0000 (+1200) Subject: Merge from trunk. plus some polish X-Git-Tag: take08~55^2~124^2~63 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9cf7de1b32f21d42c381e7141b6a398816ca56d5;p=thirdparty%2Fsquid.git Merge from trunk. plus some polish --- 9cf7de1b32f21d42c381e7141b6a398816ca56d5 diff --cc src/Server.cc index 9af6116dd1,8f11549bb1..40d45f8b87 --- a/src/Server.cc +++ b/src/Server.cc @@@ -390,13 -391,14 +393,15 @@@ ServerStateData::sentRequestBody(const return; } - if (requestBodySource->exhausted()) + if (!requestBodySource->exhausted()) + sendMoreRequestBody(); + else if (receivedWholeRequestBody) doneSendingRequestBody(); else - sendMoreRequestBody(); + debugs(9,3, HERE << "waiting for body production end or abort"); } +#if 0 bool ServerStateData::canSend(int fd) const { diff --cc src/client_side.cc index 17e08490ab,e628863b8b..741e8de1f8 --- a/src/client_side.cc +++ b/src/client_side.cc @@@ -199,13 -197,10 +198,11 @@@ static void clientUpdateSocketStats(log char *skipLeadingSpace(char *aString); static void connNoteUseOfBuffer(ConnStateData* conn, size_t byteCount); - static int connKeepReadingIncompleteRequest(ConnStateData * conn); - static void connCancelIncompleteRequests(ConnStateData * conn); -static ConnStateData *connStateCreate(const Ip::Address &peer, const Ip::Address &me, int fd, http_port_list *port); +static ConnStateData *connStateCreate(const Comm::ConnectionPointer &details, http_port_list *port); +// TODO make this return the conn for use instead. int ClientSocketContext::fd() const { @@@ -2359,19 -2346,11 +2348,11 @@@ ConnStateData::clientMaybeReadData(int void ConnStateData::clientAfterReadingRequests(int do_next_read) { - /* - * If (1) we are reading a message body, (2) and the connection - * is half-closed, and (3) we didn't get the entire HTTP request - * yet, then close this connection. - */ - - if (fd_table[clientConn->fd].flags.socket_eof) { - if ((int64_t)in.notYetUsed < bodySizeLeft()) { - /* Partial request received. Abort client connection! */ - debugs(33, 3, "clientAfterReadingRequests: FD " << clientConn->fd << " aborted, partial request"); - clientConn->close(); - return; - } + // Were we expecting to read more request body from half-closed connection? + if (mayNeedToReadMoreBody() && commIsHalfClosed(fd)) { - debugs(33, 3, HERE << "truncated body: closing half-closed FD " << fd); - comm_close(fd); ++ debugs(33, 3, HERE << "truncated body: closing half-closed FD " << clientConn); ++ clientConn->close(); + return; } clientMaybeReadData (do_next_read); @@@ -2680,9 -2638,12 +2638,12 @@@ clientParseRequest(ConnStateData * conn HttpVersion http_ver; HttpParser hp; - debugs(33, 5, "clientParseRequest: FD " << conn->fd << ": attempting to parse"); + debugs(33, 5, HERE << conn->clientConn << ": attempting to parse"); - while (conn->in.notYetUsed > 0 && conn->bodySizeLeft() == 0) { + // Loop while we have read bytes that are not needed for producing the body + // On errors, bodyPipe may become nil, but readMoreRequests will be cleared + while (conn->in.notYetUsed > 0 && !conn->bodyPipe && + conn->flags.readMoreRequests) { connStripBufferWhitespace (conn); /* Don't try to parse if the buffer is empty */ @@@ -2874,61 -2831,13 +2832,13 @@@ ConnStateData::handleRequestBodyData( size_t putSize = 0; - #if FUTURE_CODE_TO_SUPPORT_CHUNKED_REQUESTS - // The code below works, in principle, but we cannot do dechunking - // on-the-fly because that would mean sending chunked requests to - // the next hop. Squid lacks logic to determine which servers can - // receive chunk requests. Squid v3.0 code cannot even handle chunked - // responses which we may encourage by sending chunked requests. - // The error generation code probably needs more work. - if (in.bodyParser) { // chunked body - debugs(33,5, HERE << "handling chunked request body for FD " << clientConn->fd); - bool malformedChunks = false; - - MemBuf raw; // ChunkedCodingParser only works with MemBufs - raw.init(in.notYetUsed, in.notYetUsed); - raw.append(in.buf, in.notYetUsed); - try { // the parser will throw on errors - const mb_size_t wasContentSize = raw.contentSize(); - BodyPipeCheckout bpc(*bodyPipe); - const bool parsed = in.bodyParser->parse(&raw, &bpc.buf); - bpc.checkIn(); - putSize = wasContentSize - raw.contentSize(); - - if (parsed) { - stopProducingFor(bodyPipe, true); // this makes bodySize known - } else { - // parser needy state must imply body pipe needy state - if (in.bodyParser->needsMoreData() && - !bodyPipe->mayNeedMoreData()) - malformedChunks = true; - // XXX: if bodyParser->needsMoreSpace, how can we guarantee it? - } - } catch (...) { // XXX: be more specific - malformedChunks = true; - } - - if (malformedChunks) { - if (bodyPipe != NULL) - stopProducingFor(bodyPipe, false); - - ClientSocketContext::Pointer context = getCurrentContext(); - if (!context->http->out.offset) { - clientStreamNode *node = context->getClientReplyContext(); - clientReplyContext *repContext = dynamic_cast(node->data.getRaw()); - assert (repContext); - repContext->setReplyToError(ERR_INVALID_REQ, HTTP_BAD_REQUEST, - METHOD_NONE, NULL, &peer.sin_addr, - NULL, NULL, NULL); - context->pullData(); - } - flags.readMoreRequests = false; - return; // XXX: is that sufficient to generate an error? + if (in.bodyParser) { // chunked encoding + if (const err_type error = handleChunkedRequestBody(putSize)) { + abortChunkedRequestBody(error); + return false; } - } else // identity encoding - #endif - { - debugs(33,5, HERE << "handling plain request body for FD " << clientConn->fd); + } else { // identity encoding - debugs(33,5, HERE << "handling plain request body for FD " << fd); ++ debugs(33,5, HERE << "handling plain request body for " << clientConn); putSize = bodyPipe->putMoreData(in.buf, in.notYetUsed); if (!bodyPipe->mayNeedMoreData()) { // BodyPipe will clear us automagically when we produced everything @@@ -2940,21 -2849,99 +2850,99 @@@ connNoteUseOfBuffer(this, putSize); if (!bodyPipe) { - debugs(33,5, HERE << "produced entire request body for FD " << clientConn->fd); - debugs(33,5, HERE << "produced entire request body for FD " << fd); ++ debugs(33,5, HERE << "produced entire request body for " << clientConn); if (closing()) { /* we've finished reading like good clients, * now do the close that initiateClose initiated. - * - * XXX: do we have to close? why not check keepalive et. - * - * XXX: To support chunked requests safely, we need to handle - * the case of an endless request. This if-statement does not, - * because mayNeedMoreData is true if request size is not known. */ - comm_close(fd); + clientConn->close(); + return false; } } + + return true; + } + + /// parses available chunked encoded body bytes, checks size, returns errors + err_type + ConnStateData::handleChunkedRequestBody(size_t &putSize) + { - debugs(33,7, HERE << "chunked from FD " << fd << ": " << in.notYetUsed); ++ debugs(33,7, HERE << "chunked from " << clientConn << ": " << in.notYetUsed); + + try { // the parser will throw on errors + + if (!in.notYetUsed) // nothing to do (MemBuf::init requires this check) + return ERR_NONE; + + MemBuf raw; // ChunkedCodingParser only works with MemBufs + // add one because MemBuf will assert if it cannot 0-terminate + raw.init(in.notYetUsed, in.notYetUsed+1); + raw.append(in.buf, in.notYetUsed); + + const mb_size_t wasContentSize = raw.contentSize(); + BodyPipeCheckout bpc(*bodyPipe); + const bool parsed = in.bodyParser->parse(&raw, &bpc.buf); + bpc.checkIn(); + putSize = wasContentSize - raw.contentSize(); + + // dechunk then check: the size limit applies to _dechunked_ content + if (clientIsRequestBodyTooLargeForPolicy(bodyPipe->producedSize())) + return ERR_TOO_BIG; + + if (parsed) { + finishDechunkingRequest(true); + Must(!bodyPipe); + return ERR_NONE; // nil bodyPipe implies body end for the caller + } + + // if chunk parser needs data, then the body pipe must need it too + Must(!in.bodyParser->needsMoreData() || bodyPipe->mayNeedMoreData()); + + // if parser needs more space and we can consume nothing, we will stall + Must(!in.bodyParser->needsMoreSpace() || bodyPipe->buf().hasContent()); + } catch (...) { // TODO: be more specific + debugs(33, 3, HERE << "malformed chunks" << bodyPipe->status()); + return ERR_INVALID_REQ; + } + + debugs(33, 7, HERE << "need more chunked data" << *bodyPipe->status()); + return ERR_NONE; + } + + /// quit on errors related to chunked request body handling + void + ConnStateData::abortChunkedRequestBody(const err_type error) + { + finishDechunkingRequest(false); + + // XXX: The code below works if we fail during initial request parsing, + // but if we fail when the server-side works already, the server may send + // us its response too, causing various assertions. How to prevent that? + #if WE_KNOW_HOW_TO_SEND_ERRORS + ClientSocketContext::Pointer context = getCurrentContext(); + if (context != NULL && !context->http->out.offset) { // output nothing yet + clientStreamNode *node = context->getClientReplyContext(); + clientReplyContext *repContext = dynamic_cast(node->data.getRaw()); + assert(repContext); + const http_status scode = (error == ERR_TOO_BIG) ? + HTTP_REQUEST_ENTITY_TOO_LARGE : HTTP_BAD_REQUEST; + repContext->setReplyToError(error, scode, + repContext->http->request->method, + repContext->http->uri, + peer, + repContext->http->request, + in.buf, NULL); + context->pullData(); + } else { + // close or otherwise we may get stuck as nobody will notice the error? - comm_reset_close(fd); ++ comm_reset_close(clientConn); + } + #else + debugs(33, 3, HERE << "aborting chunked request without error " << error); - comm_reset_close(fd); ++ comm_reset_close(clientConn); + #endif + flags.readMoreRequests = false; } void @@@ -3050,7 -3037,7 +3038,7 @@@ clientLifetimeTimeout(int fd, void *dat debugs(33, 1, "WARNING: Closing client " << " connection due to lifetime timeout"); debugs(33, 1, "\t" << http->uri); http->al.http.timedout = true; -- comm_close(fd); ++ comm_close(fd); // XXX: this breaks ConnStateData::clientConn. } ConnStateData * diff --cc src/client_side.h index c2379ffe6c,6f932f35de..e07a40429e --- a/src/client_side.h +++ b/src/client_side.h @@@ -125,8 -136,10 +136,8 @@@ private }; -class ConnectionDetail; - /** A connection to a socket */ - class ConnStateData : public BodyProducer/*, public RefCountable*/ + class ConnStateData : public BodyProducer, public HttpControlMsgSink { public: @@@ -145,13 -158,13 +156,14 @@@ void addContextToQueue(ClientSocketContext * context); int getConcurrentRequestCount() const; bool isOpen() const; + void checkHeaderLimits(); + + // HttpControlMsgSink API + virtual void sendControlMsg(HttpControlMsg msg); - int fd; + // Client TCP connection details from comm layer. + Comm::ConnectionPointer clientConn; - /// chunk buffering and parsing algorithm state - typedef enum { chunkUnknown, chunkNone, chunkParsing, chunkReady, chunkError } DechunkingState; - struct In { In(); ~In(); diff --cc src/client_side_reply.cc index 75bad3daff,19763b7076..0df082ea79 --- a/src/client_side_reply.cc +++ b/src/client_side_reply.cc @@@ -679,9 -682,12 +681,11 @@@ clientReplyContext::processMiss( if (http->flags.internal) r->protocol = PROTO_INTERNAL; + r->clientConnection = http->getConn(); + /** Start forwarding to get the new object from network */ - FwdState::fwdStart(http->getConn() != NULL ? http->getConn()->fd : -1, - http->storeEntry(), - r); + Comm::ConnectionPointer conn = http->getConn() != NULL ? http->getConn()->clientConn : NULL; + FwdState::fwdStart(conn, http->storeEntry(), r); } } diff --cc src/forward.cc index a6b09ec596,6f366785f7..f61d138011 --- a/src/forward.cc +++ b/src/forward.cc @@@ -496,38 -506,47 +506,36 @@@ FwdState::serverClosed(int fd void FwdState::retryOrBail() { - if (!self) { // we have aborted before the server called us back - debugs(17, 5, HERE << "not retrying because of earlier abort"); - // we will be destroyed when the server clears its Pointer to us - return; - } - if (checkRetry()) { - int originserver = (servers->_peer == NULL); - debugs(17, 3, "fwdServerClosed: re-forwarding (" << n_tries << " tries, " << (squid_curtime - start_t) << " secs)"); - - if (servers->next) { - /* use next, or cycle if origin server isn't last */ - FwdServer *fs = servers; - FwdServer **T, *T2 = NULL; - servers = fs->next; - - for (T = &servers; *T; T2 = *T, T = &(*T)->next); - if (T2 && T2->_peer) { - /* cycle */ - *T = fs; - fs->next = NULL; - } else { - /* Use next. The last "direct" entry is retried multiple times */ - servers = fs->next; - fwdServerFree(fs); - originserver = 0; + debugs(17, 3, HERE << "re-forwarding (" << n_tries << " tries, " << (squid_curtime - start_t) << " secs)"); + + serverDestinations.shift(); // last one failed. try another. + + if (serverDestinations.size() > 0) { + /* Ditch error page if it was created before. + * A new one will be created if there's another problem */ + if (err) { + errorStateFree(err); + err = NULL; } - } - /* Ditch error page if it was created before. - * A new one will be created if there's another problem */ - if (err) { - errorStateFree(err); - err = NULL; + connectStart(); + return; } + // else bail. no more serverDestinations possible to try. - /* use eventAdd to break potential call sequence loops and to slow things down a little */ - eventAdd("fwdConnectStart", fwdConnectStartWrapper, this, originserver ? 0.05 : 0.005, 0); - - return; + // AYJ: cannot-forward error ?? - ErrorState *anErr = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE, request); - errorAppendEntry(entry, anErr); ++// is this hack needed since we now have doneWithRetries() below? ++// ErrorState *anErr = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE, request); ++// errorAppendEntry(entry, anErr); } - if (!err && shutting_down) { + // TODO: should we call completed() here and move doneWithRetries there? + doneWithRetries(); + + if (self != NULL && !err && shutting_down) { - errorCon(ERR_SHUTTING_DOWN, HTTP_SERVICE_UNAVAILABLE, request); + ErrorState *anErr = errorCon(ERR_SHUTTING_DOWN, HTTP_SERVICE_UNAVAILABLE, request); + errorAppendEntry(entry, anErr); } self = NULL; // refcounted diff --cc src/http.cc index 83e9f6000d,3505ec1ce2..abf291c959 --- a/src/http.cc +++ b/src/http.cc @@@ -42,8 -42,8 +42,9 @@@ #include "acl/FilledChecklist.h" #include "auth/UserRequest.h" + #include "base/AsyncJobCalls.h" #include "base/TextException.h" +#include "comm/Connection.h" #if DELAY_POOLS #include "DelayPools.h" #endif @@@ -162,17 -165,14 +164,17 @@@ HttpStateData::~HttpStateData( HTTPMSGUNLOCK(orig_request); - debugs(11,5, HERE << "HttpStateData " << this << " destroyed; FD " << fd); + cbdataReferenceDone(_peer); + - debugs(11,5, HERE << "HttpStateData " << this << " destroyed; FD " << (serverConnection!=NULL?serverConnection->fd:-1) ); ++ debugs(11,5, HERE << "HttpStateData " << this << " destroyed; " << serverConnection); } -int +const Comm::ConnectionPointer & HttpStateData::dataDescriptor() const { - return fd; + return serverConnection; } + /* static void httpStateFree(int fd, void *data) @@@ -205,7 -205,7 +207,7 @@@ httpCachable(const HttpRequestMethod& m void HttpStateData::httpTimeout(const CommTimeoutCbParams ¶ms) { - debugs(11, 4, "httpTimeout: FD " << serverConnection->fd << ": '" << entry->url() << "'" ); - debugs(11, 4, "httpTimeout: FD " << fd << ": '" << entry->url() << "'" ); ++ debugs(11, 4, HERE << serverConnection << ": '" << entry->url() << "'" ); if (entry->store_status == STORE_PENDING) { fwd->fail(errorCon(ERR_READ_TIMEOUT, HTTP_GATEWAY_TIMEOUT, fwd->request)); @@@ -956,7 -1002,7 +1004,7 @@@ HttpStateData::statusIfComplete() cons HttpStateData::ConnectionStatus HttpStateData::persistentConnStatus() const { - debugs(11, 3, "persistentConnStatus: FD " << serverConnection->fd << " eof=" << eof); - debugs(11, 3, "persistentConnStatus: FD " << fd << " eof=" << eof); ++ debugs(11, 3, HERE << serverConnection << " eof=" << eof); const HttpReply *vrep = virginReply(); debugs(11, 5, "persistentConnStatus: content_length=" << vrep->content_length); @@@ -1030,7 -1076,7 +1078,7 @@@ HttpStateData::readReply(const CommIoCb int clen; int len = io.size; - assert(serverConnection->fd == io.fd); - assert(fd == io.fd); ++// assert(serverConnection->fd == io.fd); // XXX: false when closing. serverConnection-> will already be -1. flags.do_next_read = 0; @@@ -1387,7 -1455,7 +1456,7 @@@ HttpStateData::maybeReadVirginBody( const int read_size = replyBodySpace(*readBuf, minRead); debugs(11,9, HERE << (flags.do_next_read ? "may" : "wont") << - " read up to " << read_size << " bytes from FD " << serverConnection->fd); - " read up to " << read_size << " bytes from FD " << fd); ++ " read up to " << read_size << " bytes from " << serverConnection); /* * why <2? Because delayAwareRead() won't actually read if @@@ -1408,13 -1476,11 +1477,11 @@@ } } - /* - * This will be called when request write is complete. - */ + /// called after writing the very last request byte (body, last-chunk, etc) void - HttpStateData::sendComplete(const CommIoCbParams &io) + HttpStateData::wroteLast(const CommIoCbParams &io) { - debugs(11, 5, "httpSendComplete: FD " << serverConnection->fd << ": size " << io.size << ": errflag " << io.flag << "."); - debugs(11, 5, HERE << "FD " << fd << ": size " << io.size << ": errflag " << io.flag << "."); ++ debugs(11, 5, HERE << serverConnection << ": size " << io.size << ": errflag " << io.flag << "."); #if URL_CHECKSUM_DEBUG entry->mem_obj->checkUrlChecksum(); @@@ -1461,22 -1534,24 +1535,22 @@@ HttpStateData::sendComplete( void HttpStateData::closeServer() { - debugs(11,5, HERE << "closing HTTP server FD " << serverConnection->fd << " this " << this); - debugs(11,5, HERE << "closing HTTP server FD " << fd << " this " << this); ++ debugs(11,5, HERE << "closing HTTP server " << serverConnection << " this " << this); - if (serverConnection->isOpen()) { - if (fd >= 0) { - fwd->unregister(fd); - comm_remove_close_handler(fd, closeHandler); ++ if (Comm::IsConnOpen(serverConnection)) { + fwd->unregister(serverConnection); + comm_remove_close_handler(serverConnection->fd, closeHandler); closeHandler = NULL; - comm_close(fd); - fd = -1; + serverConnection->close(); } } bool HttpStateData::doneWithServer() const { - return serverConnection == NULL || !serverConnection->isOpen(); - return fd < 0; ++ return !Comm::IsConnOpen(serverConnection); } - /* * Fixup authentication request headers for special cases */ @@@ -1978,10 -2061,10 +2060,10 @@@ HttpStateData::sendRequest( { MemBuf mb; - debugs(11, 5, "httpSendRequest: FD " << serverConnection->fd << ", request " << request << ", this " << this << "."); - debugs(11, 5, "httpSendRequest: FD " << fd << ", request " << request << ", this " << this << "."); ++ debugs(11, 5, HERE << serverConnection << ", request " << request << ", this " << this << "."); - if (!canSend(fd)) { - debugs(11,3, HERE << "cannot send request to closing FD " << fd); + if (!Comm::IsConnOpen(serverConnection)) { - debugs(11,3, HERE << "cannot send request to closing FD " << serverConnection->fd); ++ debugs(11,3, HERE << "cannot send request to closing " << serverConnection); assert(closeHandler != NULL); return false; } @@@ -2045,8 -2128,8 +2127,8 @@@ mb.init(); request->peer_host=_peer?_peer->host:NULL; buildRequestPrefix(request, orig_request, entry, &mb, flags); - debugs(11, 6, "httpSendRequest: FD " << serverConnection->fd << ":\n" << mb.buf); - debugs(11, 6, "httpSendRequest: FD " << fd << ":\n" << mb.buf); - comm_write_mbuf(fd, &mb, requestSender); ++ debugs(11, 6, HERE << serverConnection << ":\n" << mb.buf); + comm_write_mbuf(serverConnection->fd, &mb, requestSender); return true; } @@@ -2073,42 -2190,72 +2189,72 @@@ httpStart(FwdState *fwd */ } - void - HttpStateData::doneSendingRequestBody() + /// if broken posts are enabled for the request, try to fix and return true + bool + HttpStateData::finishingBrokenPost() { - debugs(11,5, HERE << "doneSendingRequestBody: FD " << serverConnection->fd); - #if USE_HTTP_VIOLATIONS - if (Config.accessList.brokenPosts) { - ACLFilledChecklist ch(Config.accessList.brokenPosts, request, NULL); - if (!ch.fastCheck()) { - debugs(11, 5, "doneSendingRequestBody: didn't match brokenPosts"); - CommIoCbParams io(NULL); - io.fd = serverConnection->fd; - io.flag = COMM_OK; - sendComplete(io); - } else { - debugs(11, 2, "doneSendingRequestBody: matched brokenPosts"); + if (!Config.accessList.brokenPosts) { + debugs(11, 5, HERE << "No brokenPosts list"); + return false; + } - if (!Comm::IsConnOpen(serverConnection)) { - debugs(11,2, HERE << "cannot send CRLF to closing FD"); - assert(closeHandler != NULL); - return; - } + ACLFilledChecklist ch(Config.accessList.brokenPosts, request, NULL); + if (!ch.fastCheck()) { + debugs(11, 5, HERE << "didn't match brokenPosts"); + return false; + } - typedef CommCbMemFunT Dialer; - AsyncCall::Pointer call = JobCallback(11, 5, Dialer, this, HttpStateData::sendComplete); - comm_write(serverConnection->fd, "\r\n", 2, call); - } - return; - if (!canSend(fd)) { - debugs(11,2, HERE << "ignoring broken POST for closing FD " << fd); ++ if (!Comm::IsConnOpen(serverConnection)) { ++ debugs(11,2, HERE << "ignoring broken POST for closed " << serverConnection); + assert(closeHandler != NULL); + return true; // prevent caller from proceeding as if nothing happened } - debugs(11, 5, "doneSendingRequestBody: No brokenPosts list"); + + debugs(11, 2, "finishingBrokenPost: fixing broken POST"); + typedef CommCbMemFunT Dialer; + requestSender = JobCallback(11,5, + Dialer, this, HttpStateData::wroteLast); - comm_write(fd, "\r\n", 2, requestSender); ++ comm_write(serverConnection->fd, "\r\n", 2, requestSender); + return true; + #else + return false; #endif /* USE_HTTP_VIOLATIONS */ + } + + /// if needed, write last-chunk to end the request body and return true + bool + HttpStateData::finishingChunkedRequest() + { + if (flags.sentLastChunk) { + debugs(11, 5, HERE << "already sent last-chunk"); + return false; + } + + Must(receivedWholeRequestBody); // or we should not be sending last-chunk + flags.sentLastChunk = true; + + typedef CommCbMemFunT Dialer; + requestSender = JobCallback(11,5, + Dialer, this, HttpStateData::wroteLast); - comm_write(fd, "0\r\n\r\n", 5, requestSender); ++ comm_write(serverConnection->fd, "0\r\n\r\n", 5, requestSender); + return true; + } + + void + HttpStateData::doneSendingRequestBody() + { + ServerStateData::doneSendingRequestBody(); - debugs(11,5, HERE << "doneSendingRequestBody: FD " << fd); ++ debugs(11,5, HERE << serverConnection); + + // do we need to write something after the last body byte? + const bool chunked = request->header.chunked(); + if (chunked && finishingChunkedRequest()) + return; + if (!chunked && finishingBrokenPost()) + return; - CommIoCbParams io(NULL); - io.fd = serverConnection->fd; - io.flag = COMM_OK; - sendComplete(io); + sendComplete(); } // more origin request body data is available @@@ -2171,10 -2314,10 +2313,10 @@@ voi HttpStateData::abortTransaction(const char *reason) { debugs(11,5, HERE << "aborting transaction for " << reason << - "; FD " << serverConnection->fd << ", this " << this); - "; FD " << fd << ", this " << this); ++ "; " << serverConnection << ", this " << this); - if (fd >= 0) { - comm_close(fd); + if (serverConnection->isOpen()) { + serverConnection->close(); return; } diff --cc src/http.h index d64f552300,b53092a3ba..97b4a393d6 --- a/src/http.h +++ b/src/http.h @@@ -81,13 -81,11 +81,17 @@@ public protected: virtual HttpRequest *originalRequest(); + void processReply(); + void proceedAfter1xx(); + void handle1xx(HttpReply *msg); + private: + /** + * The current server connection. + * Maybe open, closed, or NULL. + * Use doneWithServer() to check if the server is available for use. + */ + Comm::ConnectionPointer serverConnection; AsyncCall::Pointer closeHandler; enum ConnectionStatus { INCOMPLETE_MSG,