Index: squid/src/client_side.c diff -c squid/src/client_side.c:1.561.2.51 squid/src/client_side.c:1.561.2.52 *** squid/src/client_side.c:1.561.2.51 Mon Dec 22 18:04:23 2003 --- squid/src/client_side.c Mon Jan 12 03:51:58 2004 *************** *** 813,820 **** MemObject *mem = NULL; debug(33, 3) ("httpRequestFree: %s\n", storeUrl(http->entry)); if (!clientCheckTransferDone(http)) { ! if (request && request->body_connection) clientAbortBody(request); /* abort request body transter */ /* HN: This looks a bit odd.. why should client_side care about * the ICP selection status? */ --- 813,822 ---- MemObject *mem = NULL; debug(33, 3) ("httpRequestFree: %s\n", storeUrl(http->entry)); if (!clientCheckTransferDone(http)) { ! if (request && request->body_connection) { clientAbortBody(request); /* abort request body transter */ + request->body_connection = NULL; + } /* HN: This looks a bit odd.. why should client_side care about * the ICP selection status? */ *************** *** 1967,1984 **** return; } if (http->out.offset == 0) { - if (Config.onoff.log_mime_hdrs) { - size_t k; - if ((k = headersEnd(buf, size))) { - safe_free(http->al.headers.reply); - http->al.headers.reply = xcalloc(k + 1, 1); - xstrncpy(http->al.headers.reply, buf, k); - } - } rep = clientBuildReply(http, buf, size); if (rep) { aclCheck_t *ch; int rv; clientMaxBodySize(http->request, http, rep); if (http->log_type != LOG_TCP_DENIED && clientReplyBodyTooLarge(http, rep->content_length)) { ErrorState *err = errorCon(ERR_TOO_BIG, HTTP_FORBIDDEN); --- 1969,1986 ---- return; } if (http->out.offset == 0) { rep = clientBuildReply(http, buf, size); if (rep) { aclCheck_t *ch; int rv; + if (Config.onoff.log_mime_hdrs) { + size_t k; + if ((k = headersEnd(buf, size))) { + safe_free(http->al.headers.reply); + http->al.headers.reply = xcalloc(k + 1, 1); + xstrncpy(http->al.headers.reply, buf, k); + } + } clientMaxBodySize(http->request, http, rep); if (http->log_type != LOG_TCP_DENIED && clientReplyBodyTooLarge(http, rep->content_length)) { ErrorState *err = errorCon(ERR_TOO_BIG, HTTP_FORBIDDEN); *************** *** 2026,2041 **** return; } } - } else if (size < CLIENT_SOCK_SZ && entry->store_status == STORE_PENDING) { - /* wait for more to arrive */ - storeClientCopy(http->sc, entry, - http->out.offset + size, - http->out.offset, - CLIENT_SOCK_SZ, - buf, - clientSendMoreData, - http); - return; } /* reset range iterator */ http->range_iter.pos = HttpHdrRangeInitPos; --- 2028,2033 ---- *************** *** 3284,3291 **** CBCB *callback; void *cbdata; int valid; ! request->body_connection = NULL; ! if (!conn->body.callback || !conn->body.request) return; buf = conn->body.buf; callback = conn->body.callback; --- 3276,3282 ---- CBCB *callback; void *cbdata; int valid; ! if (!conn->body.callback || conn->body.request != request) return; buf = conn->body.buf; callback = conn->body.callback; Index: squid/src/http.c diff -c squid/src/http.c:1.384.2.9 squid/src/http.c:1.384.2.12 *** squid/src/http.c:1.384.2.9 Mon Aug 18 11:24:25 2003 --- squid/src/http.c Fri Jan 30 16:09:12 2004 *************** *** 64,69 **** --- 64,76 ---- #endif if (httpState == NULL) return; + if (httpState->body_buf) { + clientAbortBody(httpState->orig_request); + if (httpState->body_buf) { + memFree(httpState->body_buf, MEM_8K_BUF); + httpState->body_buf = NULL; + } + } storeUnlockObject(httpState->entry); if (httpState->reply_hdr) { memFree(httpState->reply_hdr, MEM_8K_BUF); *************** *** 466,474 **** if (httpState->flags.keepalive) if (httpState->peer) httpState->peer->stats.n_keepalives_sent++; ! if (reply->keep_alive) if (httpState->peer) httpState->peer->stats.n_keepalives_recv++; if (reply->date> -1 && !httpState->peer) { int skew = abs(reply->date - squid_curtime); if (skew> 86400) --- 473,488 ---- if (httpState->flags.keepalive) if (httpState->peer) httpState->peer->stats.n_keepalives_sent++; ! if (reply->keep_alive) { if (httpState->peer) httpState->peer->stats.n_keepalives_recv++; + if (Config.onoff.detect_broken_server_pconns && httpReplyBodySize(httpState->request->method, reply) == -1) { + debug(11, 1) ("httpProcessReplyHeader: Impossible keep-alive header from '%s'\n", storeUrl(entry)); + debug(11, 2) ("GOT HTTP REPLY HDR:\n---------\n%s\n----------\n", + httpState->reply_hdr); + httpState->flags.keepalive_broken = 1; + } + } if (reply->date> -1 && !httpState->peer) { int skew = abs(reply->date - squid_curtime); if (skew> 86400) *************** *** 571,588 **** #endif kb_incr(&statCounter.server.all.kbytes_in, len); kb_incr(&statCounter.server.http.kbytes_in, len); - commSetTimeout(fd, Config.Timeout.read, NULL, NULL); IOStats.Http.reads++; for (clen = len - 1, bin = 0; clen; bin++) clen>>= 1; IOStats.Http.read_hist[bin]++; } ! if (!httpState->reply_hdr && len> 0) { /* Skip whitespace */ while (len> 0 && xisspace(*buf)) xmemmove(buf, buf + 1, len--); if (len == 0) { /* Continue to read... */ commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0); return; } --- 585,602 ---- #endif kb_incr(&statCounter.server.all.kbytes_in, len); kb_incr(&statCounter.server.http.kbytes_in, len); IOStats.Http.reads++; for (clen = len - 1, bin = 0; clen; bin++) clen>>= 1; IOStats.Http.read_hist[bin]++; } ! if (!httpState->reply_hdr && len> 0 && fd_table[fd].uses> 1) { /* Skip whitespace */ while (len> 0 && xisspace(*buf)) xmemmove(buf, buf + 1, len--); if (len == 0) { /* Continue to read... */ + /* Timeout NOT increased. This whitespace was from previous reply */ commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0); return; } *************** *** 662,668 **** httpState->fd = -1; httpStateFree(fd, httpState); } else { ! /* Wait for EOF condition */ commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0); } } --- 676,687 ---- httpState->fd = -1; httpStateFree(fd, httpState); } else { ! /* Wait for more data or EOF condition */ ! if (httpState->flags.keepalive_broken) { ! commSetTimeout(fd, 10, NULL, NULL); ! } else { ! commSetTimeout(fd, Config.Timeout.read, NULL, NULL); ! } commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0); } } *************** *** 696,703 **** comm_close(fd); return; } else { - /* Schedule read reply. */ - commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0); /* * Set the read timeout here because it hasn't been set yet. * We only set the read timeout after the request has been --- 715,720 ---- *************** *** 965,972 **** StoreEntry *entry = httpState->entry; peer *p = httpState->peer; CWCB *sendHeaderDone; ! debug(11, 5) ("httpSendRequest: FD %d: httpState %p.\n", httpState->fd, httpState); if (httpState->orig_request->body_connection) sendHeaderDone = httpSendRequestEntry; --- 982,994 ---- StoreEntry *entry = httpState->entry; peer *p = httpState->peer; CWCB *sendHeaderDone; + int fd = httpState->fd; + + debug(11, 5) ("httpSendRequest: FD %d: httpState %p.\n", fd, httpState); ! /* Schedule read reply. (but no timeout set until request fully sent) */ ! commSetTimeout(fd, Config.Timeout.lifetime, httpTimeout, httpState); ! commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0); if (httpState->orig_request->body_connection) sendHeaderDone = httpSendRequestEntry; *************** *** 998,1005 **** entry, &mb, httpState->flags); ! debug(11, 6) ("httpSendRequest: FD %d:\n%s\n", httpState->fd, mb.buf); ! comm_write_mbuf(httpState->fd, mb, sendHeaderDone, httpState); } void --- 1020,1027 ---- entry, &mb, httpState->flags); ! debug(11, 6) ("httpSendRequest: FD %d:\n%s\n", fd, mb.buf); ! comm_write_mbuf(fd, mb, sendHeaderDone, httpState); } void *************** *** 1084,1090 **** --- 1106,1124 ---- httpRequestBodyHandler(char *buf, ssize_t size, void *data) { HttpStateData *httpState = (HttpStateData *) data; + httpState->body_buf = NULL; if (size> 0) { + if (httpState->reply_hdr_state>= 2 && !httpState->flags.abuse_detected) { + httpState->flags.abuse_detected = 1; + debug(11, 1) ("httpSendRequestEntryDone: Likely proxy abuse detected '%s' -> '%s'\n", + inet_ntoa(httpState->orig_request->client_addr), + storeUrl(httpState->entry)); + if (httpState->entry->mem_obj->reply->sline.status == HTTP_INVALID_HEADER) { + memFree8K(buf); + comm_close(httpState->fd); + return; + } + } comm_write(httpState->fd, buf, size, httpSendRequestEntry, data, memFree8K); } else if (size == 0) { /* End of body */ *************** *** 1124,1130 **** comm_close(fd); return; } ! clientReadBody(httpState->orig_request, memAllocate(MEM_8K_BUF), 8192, httpRequestBodyHandler, httpState); } void --- 1158,1165 ---- comm_close(fd); return; } ! httpState->body_buf = memAllocate(MEM_8K_BUF); ! clientReadBody(httpState->orig_request, httpState->body_buf, 8192, httpRequestBodyHandler, httpState); } void Index: squid/src/structs.h diff -c squid/src/structs.h:1.408.2.18 squid/src/structs.h:1.408.2.21 *** squid/src/structs.h:1.408.2.18 Sun Dec 14 06:33:47 2003 --- squid/src/structs.h Fri Jan 30 16:09:12 2004 *************** *** 593,598 **** --- 593,599 ---- int vary_ignore_expire; int pipeline_prefetch; int request_entities; + int detect_broken_server_pconns; } onoff; acl *aclList; struct { *************** *** 967,972 **** --- 968,975 ---- unsigned int proxying:1; unsigned int keepalive:1; unsigned int only_if_cached:1; + unsigned int keepalive_broken:1; + unsigned int abuse_detected:1; }; struct _HttpStateData { *************** *** 981,986 **** --- 984,990 ---- int fd; http_state_flags flags; FwdState *fwd; + char *body_buf; }; struct _icpUdpData { Index: squid/src/cf.data.pre diff -c squid/src/cf.data.pre:1.245.2.57 squid/src/cf.data.pre:1.245.2.58 *** squid/src/cf.data.pre:1.245.2.57 Fri Dec 19 09:34:22 2003 --- squid/src/cf.data.pre Fri Jan 30 16:09:12 2004 *************** *** 3766,3771 **** --- 3766,3786 ---- disable persistent connections with clients and/or servers. DOC_END + NAME: detect_broken_pconn + TYPE: onoff + LOC: Config.onoff.detect_broken_server_pconns + DEFAULT: off + DOC_START + Some servers have been found to incorrectly signal the use + of HTTP/1.0 persistent connections even on replies not + compatible, causing significant delays. This server problem + has mostly been seen on redirects. + + By enabling this directive Squid attempts to detect such + broken replies and automatically assume the reply is finished + after 10 seconds timeout. + DOC_END + NAME: pipeline_prefetch TYPE: onoff LOC: Config.onoff.pipeline_prefetch Index: squid/src/HttpMsg.c diff -c squid/src/HttpMsg.c:1.10 squid/src/HttpMsg.c:1.10.2.2 *** squid/src/HttpMsg.c:1.10 Thu Jan 11 17:37:14 2001 --- squid/src/HttpMsg.c Mon Jan 19 10:46:40 2004 *************** *** 91,96 **** --- 91,97 ---- int httpMsgIsPersistent(http_version_t http_ver, const HttpHeader * hdr) { + #if WHEN_SQUID_IS_HTTP1_1 if ((http_ver.major>= 1) && (http_ver.minor>= 1)) { /* * for modern versions of HTTP: persistent unless there is *************** *** 98,103 **** --- 99,107 ---- */ return !httpHeaderHasConnDir(hdr, "close"); } else { + #else + { + #endif /* * Persistent connections in Netscape 3.x are allegedly broken, * return false if it is a browser connection. If there is a