This patch is generated from the http11 branch of HEAD in squid Sun Dec 2 01:17:58 2007 GMT See http://devel.squid-cache.org/ Index: squid/src/HttpMsg.c diff -u squid/src/HttpMsg.c:1.12 squid/src/HttpMsg.c:1.8.14.4 --- squid/src/HttpMsg.c:1.12 Sun Apr 1 07:04:42 2007 +++ squid/src/HttpMsg.c Thu Apr 12 18:56:48 2007 @@ -100,17 +100,13 @@ { if (httpHeaderHasConnDir(hdr, "close")) return 0; -#if WHEN_SQUID_IS_HTTP1_1 - if ((http_ver.major >= 1) && (http_ver.minor >= 1)) { + if ((http_ver.major >= 1 && http_ver.minor >= 1) || http_ver.major > 1) { /* * for modern versions of HTTP: persistent unless there is * a "Connection: close" header. */ return 1; } else { -#else - { -#endif /* * Persistent connections in Netscape 3.x are allegedly broken, * return false if it is a browser connection. If there is a Index: squid/src/HttpReply.c diff -u squid/src/HttpReply.c:1.24 squid/src/HttpReply.c:1.16.14.8 --- squid/src/HttpReply.c:1.24 Wed Nov 21 05:51:44 2007 +++ squid/src/HttpReply.c Tue Nov 27 06:18:17 2007 @@ -197,7 +197,7 @@ #endif MemBuf -httpPacked304Reply(const HttpReply * rep) +httpPacked304Reply(const HttpReply * rep, int http11) { static const http_hdr_type ImsEntries[] = {HDR_DATE, HDR_CONTENT_TYPE, HDR_EXPIRES, HDR_LAST_MODIFIED, HDR_ETAG, /* eof */ HDR_OTHER}; @@ -209,7 +209,7 @@ memBufDefInit(&mb); packerToMemInit(&p, &mb); - memBufPrintf(&mb, "%s", "HTTP/1.0 304 Not Modified\r\n"); + memBufPrintf(&mb, "HTTP/1.%d 304 Not Modified\r\n", http11); for (t = 0; ImsEntries[t] != HDR_OTHER; ++t) if ((e = httpHeaderFindEntry(&rep->header, ImsEntries[t]))) httpHeaderEntryPackInto(e, &p); @@ -254,7 +254,7 @@ HttpHeader *hdr; http_version_t ver; assert(reply); - httpBuildVersion(&ver, 1, 0); + httpBuildVersion(&ver, 1, 1); httpStatusLineSet(&reply->sline, ver, status, httpStatusString(status)); hdr = &reply->header; httpHeaderPutStr(hdr, HDR_SERVER, full_appname_string); @@ -321,7 +321,7 @@ if (httpHeaderHas(&rep->header, HDR_EXPIRES)) { const time_t e = httpHeaderGetTime(&rep->header, HDR_EXPIRES); /* - * HTTP/1.0 says that robust implementations should consider + * HTTP/1.1 says that robust implementations should consider * bad or malformed Expires header as equivalent to "expires * immediately." */ Index: squid/src/HttpRequest.c diff -u squid/src/HttpRequest.c:1.18 squid/src/HttpRequest.c:1.16.10.3 --- squid/src/HttpRequest.c:1.18 Wed Nov 14 20:52:06 2007 +++ squid/src/HttpRequest.c Tue Nov 27 06:18:17 2007 @@ -113,8 +113,8 @@ { assert(req && p); /* pack request-line */ - packerPrintf(p, "%s %s HTTP/1.0\r\n", - RequestMethods[req->method].str, strBuf(req->urlpath)); + packerPrintf(p, "%s %s HTTP/%d.%d\r\n", + RequestMethods[req->method].str, strBuf(req->urlpath), req->http_ver.major, req->http_ver.minor); /* headers */ httpHeaderPackInto(&req->header, p); /* trailer */ Index: squid/src/HttpStatusLine.c diff -u squid/src/HttpStatusLine.c:1.13 squid/src/HttpStatusLine.c:1.9.48.5 --- squid/src/HttpStatusLine.c:1.13 Sat Jul 14 23:51:50 2007 +++ squid/src/HttpStatusLine.c Wed Aug 22 18:26:39 2007 @@ -279,6 +279,9 @@ case HTTP_HTTP_VERSION_NOT_SUPPORTED: p = "HTTP Version not supported"; break; + case HTTP_EXPECTATION_FAILED: + p = "Expectation failed"; + break; default: p = "Unknown"; debug(57, 3) ("Unknown HTTP status code: %d\n", status); Index: squid/src/cache_cf.c diff -u squid/src/cache_cf.c:1.105 squid/src/cache_cf.c:1.87.2.10 --- squid/src/cache_cf.c:1.105 Fri Nov 23 03:53:07 2007 +++ squid/src/cache_cf.c Tue Nov 27 06:18:17 2007 @@ -1820,6 +1820,8 @@ p->connection_auth = -1; } else if (strncmp(token, "idle=", 5) == 0) { p->idle = xatoi(token + 5); + } else if (strcmp(token, "http11") == 0) { + p->options.http11 = 1; } else { debug(3, 0) ("parse_peer: token='%s'\n", token); self_destruct(); @@ -2813,6 +2815,8 @@ s->accel = 1; } else if (strcmp(token, "allow-direct") == 0) { s->allow_direct = 1; + } else if (strcmp(token, "http11") == 0) { + s->http11 = 1; } else { self_destruct(); } @@ -2898,6 +2902,8 @@ if (s->tproxy) storeAppendPrintf(e, " tproxy"); #endif + if (s->http11) + storeAppendPrintf(e, " http11"); } static void dump_http_port_list(StoreEntry * e, const char *n, const http_port_list * s) Index: squid/src/cf.data.pre diff -u squid/src/cf.data.pre:1.224 squid/src/cf.data.pre:1.161.6.13 --- squid/src/cf.data.pre:1.224 Mon Nov 26 02:51:21 2007 +++ squid/src/cf.data.pre Tue Nov 27 06:18:17 2007 @@ -1043,6 +1043,10 @@ This currently means generate own Date: and Expires: headers. Implies accel. + http11 Enables HTTP/1.1 support to clients. The HTTP/1.1 + support is still incomplete, but should work with + most clients. + If you run Squid on a dual-homed machine with an internal and an external interface we recommend you to specify the internal address:port in http_port. This way Squid will only be @@ -1417,6 +1421,7 @@ front-end-https[=on|auto] connection-auth[=on|off|auto] idle=n + http11 use 'proxy-only' to specify objects fetched from this cache should not be saved locally. @@ -1641,6 +1646,9 @@ use idle=n to specify a minimum number of idle connections that should be kept open to this peer. + + use http11 to send requests using HTTP/1.1 to this peer. + The HTTP/1.1 support is still incomplete. DOC_END NAME: cache_peer_domain cache_host_domain @@ -3335,6 +3343,29 @@ or response to be rejected. DOC_END +NAME: server_http11 +COMMENT: on|off +TYPE: onoff +LOC: Config.onoff.server_http11 +DEFAULT: off +DOC_START + This option enables the use ot HTTP/1.1 on outgoing "direct" requests. + See also the http11 cache_peer option. + Note: The HTTP/1.1 support is still incomplete. +DOC_END + +NAME: ignore_expect_100 +COMMENT: on|off +TYPE: onoff +LOC: Config.onoff.ignore_expect_100 +DEFAULT: off +DOC_START + This option makes Squid ignore any Expect: 100-continue header present + in the request. + Note: Enabling this is a HTTP protocol violation, but some client may + not handle it well.. +DOC_END + NAME: external_refresh_check TYPE: refreshCheckHelper DEFAULT: none Index: squid/src/client_side.c diff -u squid/src/client_side.c:1.214 squid/src/client_side.c:1.154.2.31 --- squid/src/client_side.c:1.214 Thu Nov 29 05:52:06 2007 +++ squid/src/client_side.c Sat Dec 1 13:22:55 2007 @@ -1476,7 +1476,10 @@ RequestMethods[request->method].str); { http_version_t http_ver; - httpBuildVersion(&http_ver, 1, 0); /* we are HTTP/1.0, no matter what the client requests... */ + if (http->conn->port->http11) + http_ver = request->http_ver; + else + httpBuildVersion(&http_ver, 1, 0); /* we are HTTP/1.0, no matter what the client requests... */ if (httpMsgIsPersistent(http_ver, req_hdr)) request->flags.proxy_keepalive = 1; } @@ -1876,8 +1879,13 @@ getMyHostname(), getMyPort()); #endif if (httpReplyBodySize(request->method, rep) < 0) { - debug(33, 3) ("clientBuildReplyHeader: can't keep-alive, unknown body size\n"); - request->flags.proxy_keepalive = 0; + if (http->conn->port->http11 && (request->http_ver.major > 1 || (request->http_ver.major == 1 && request->http_ver.minor >= 1))) { + debug(33, 2) ("clientBuildReplyHeader: send chunked response, unknown body size\n"); + request->flags.chunked_response = 1; + } else { + debug(33, 3) ("clientBuildReplyHeader: can't keep-alive, unknown body size\n"); + request->flags.proxy_keepalive = 0; + } } if (fdUsageHigh() && !request->flags.must_keepalive) { debug(33, 3) ("clientBuildReplyHeader: Not many unused FDs, can't keep-alive\n"); @@ -1893,6 +1901,10 @@ debug(33, 2) ("clientBuildReplyHeader: Connection oriented auth but server side non-persistent\n"); request->flags.proxy_keepalive = 0; } + /* Append Transfer-Encoding */ + if (request->flags.chunked_response) { + httpHeaderPutStr(hdr, HDR_TRANSFER_ENCODING, "chunked"); + } /* Append Via */ if (Config.onoff.via) { LOCAL_ARRAY(char, bbuf, MAX_URL + 32); @@ -1906,9 +1918,13 @@ stringClean(&strVia); } /* Signal keep-alive if needed */ - httpHeaderPutStr(hdr, - (http->flags.accel || http->flags.transparent) ? HDR_CONNECTION : HDR_PROXY_CONNECTION, - request->flags.proxy_keepalive ? "keep-alive" : "close"); + if (!request->flags.proxy_keepalive) + httpHeaderPutStr(hdr, HDR_CONNECTION, "close"); + else if (request->http_ver.major == 1 && request->http_ver.minor == 0) { + httpHeaderPutStr(hdr, HDR_CONNECTION, "keep-alive"); + if (!(http->flags.accel || http->flags.transparent)) + httpHeaderPutStr(hdr, HDR_PROXY_CONNECTION, "keep-alive"); + } #if ADD_X_REQUEST_URI /* * Knowing the URI of the request is useful when debugging persistent @@ -1955,8 +1971,13 @@ /* try to grab the already-parsed header */ rep = httpReplyClone(orig_rep); if (rep->pstate == psParsed) { - /* enforce 1.0 reply version */ - httpBuildVersion(&rep->sline.version, 1, 0); + if (http->conn->port->http11) { + /* enforce 1.1 reply version */ + httpBuildVersion(&rep->sline.version, 1, 1); + } else { + /* enforce 1.0 reply version */ + httpBuildVersion(&rep->sline.version, 1, 0); + } /* do header conversions */ clientBuildReplyHeader(http, rep); /* if we do ranges, change status to "Partial Content" */ @@ -2408,7 +2429,7 @@ if (is_modified == 0) { time_t timestamp = e->timestamp; - MemBuf mb = httpPacked304Reply(e->mem_obj->reply); + MemBuf mb = httpPacked304Reply(e->mem_obj->reply, http->conn->port->http11); http->log_type = LOG_TCP_IMS_HIT; storeClientUnregister(http->sc, e, http); http->sc = NULL; @@ -3000,7 +3021,7 @@ memFree(buf, MEM_STORE_CLIENT_BUF); return; } - if (!http->request->range) { + if (!http->request->range && !http->request->flags.chunked_response) { /* Avoid copying to MemBuf for non-range requests */ http->out.offset += size; comm_write(fd, buf, size, clientWriteBodyComplete, http, NULL); @@ -3037,7 +3058,15 @@ memBufAppend(&mb, buf, size); } /* write body */ - comm_write_mbuf(fd, mb, clientWriteComplete, http); + if (http->request->flags.chunked_response) { + char header[32]; + size_t header_size; + header_size = snprintf(header, sizeof(header), "%x\r\n", mb.size); + memBufAppend(&mb, "\r\n", 2); + comm_write_mbuf_header(fd, mb, header, header_size, clientWriteComplete, http); + } else { + comm_write_mbuf(fd, mb, clientWriteComplete, http); + } memFree(buf, MEM_STORE_CLIENT_BUF); } @@ -3160,6 +3189,10 @@ } else if (clientGotNotEnough(http)) { debug(33, 5) ("clientWriteComplete: client didn't get all it expected\n"); comm_close(fd); + } else if (http->request->flags.chunked_response) { + /* Finish chunked transfer encoding */ + http->request->flags.chunked_response = 0; /* no longer chunking */ + comm_write(http->conn->fd, "0\r\n\r\n", 5, clientWriteComplete, http, NULL); } else if (http->request->body_reader == clientReadBody) { debug(33, 5) ("clientWriteComplete: closing, but first we need to read the rest of the request\n"); /* XXX We assumes the reply does fit in the TCP transmit window. @@ -3359,6 +3392,22 @@ RequestMethods[r->method].str, url); r->flags.collapsed = 0; + if (httpHeaderHas(&r->header, HDR_EXPECT)) { + int ignore = 0; + if (Config.onoff.ignore_expect_100) { + String expect = httpHeaderGetList(&r->header, HDR_EXPECT); + if (strCaseCmp(expect, "100-continue") == 0) + ignore = 1; + stringClean(&expect); + } + if (!ignore) { + ErrorState *err = errorCon(ERR_INVALID_REQ, HTTP_EXPECTATION_FAILED, r); + http->log_type = LOG_TCP_MISS; + http->entry = clientCreateStoreEntry(http, http->request->method, null_request_flags); + errorAppendEntry(http->entry, err); + return; + } + } if (r->method == METHOD_CONNECT && !http->redirect.status) { http->log_type = LOG_TCP_MISS; #if USE_SSL && SSL_CONNECT_INTERCEPT @@ -3910,8 +3959,7 @@ request->my_addr = conn->me.sin_addr; request->my_port = ntohs(conn->me.sin_port); request->http_ver = http->http_ver; - if (!urlCheckRequest(request) || - httpHeaderHas(&request->header, HDR_TRANSFER_ENCODING)) { + if (!urlCheckRequest(request)) { err = errorCon(ERR_UNSUP_REQ, HTTP_NOT_IMPLEMENTED, request); request->flags.proxy_keepalive = 0; http->al.http.code = err->http_status; @@ -3920,7 +3968,7 @@ errorAppendEntry(http->entry, err); return -1; } - if (!clientCheckContentLength(request)) { + if (!clientCheckContentLength(request) || httpHeaderHas(&request->header, HDR_TRANSFER_ENCODING)) { err = errorCon(ERR_INVALID_REQ, HTTP_LENGTH_REQUIRED, request); http->al.http.code = err->http_status; http->log_type = LOG_TCP_DENIED; Index: squid/src/comm.c diff -u squid/src/comm.c:1.55 squid/src/comm.c:1.49.6.5 --- squid/src/comm.c:1.55 Fri Sep 21 07:52:48 2007 +++ squid/src/comm.c Mon Sep 24 15:56:50 2007 @@ -1114,11 +1114,14 @@ assert(state->valid); - debug(5, 5) ("commHandleWrite: FD %d: off %ld, sz %ld.\n", - fd, (long int) state->offset, (long int) state->size); + debug(5, 5) ("commHandleWrite: FD %d: off %ld, hd %ld, sz %ld.\n", + fd, (long int) state->offset, (long int) state->header_size, (long int) state->size); - nleft = state->size - state->offset; - len = FD_WRITE_METHOD(fd, state->buf + state->offset, nleft); + nleft = state->size + state->header_size - state->offset; + if (state->offset < state->header_size) + len = FD_WRITE_METHOD(fd, state->header + state->offset, state->header_size - state->offset); + else + len = FD_WRITE_METHOD(fd, state->buf + state->offset - state->header_size, nleft); debug(5, 5) ("commHandleWrite: write() returns %d\n", len); fd_bytes(fd, len, FD_WRITE); statCounter.syscalls.sock.writes++; @@ -1151,7 +1154,7 @@ } else { /* A successful write, continue */ state->offset += len; - if (state->offset < state->size) { + if (state->offset < state->size + state->header_size) { /* Not done, reinstall the write handler and write some more */ commSetSelect(fd, COMM_SELECT_WRITE, @@ -1180,6 +1183,7 @@ } state->buf = (char *) buf; state->size = size; + state->header_size = 0; state->offset = 0; state->handler = handler; state->handler_data = handler_data; @@ -1189,6 +1193,32 @@ commSetSelect(fd, COMM_SELECT_WRITE, commHandleWrite, NULL, 0); } +/* Select for Writing on FD, until SIZE bytes are sent. Call + * *HANDLER when complete. */ +void +comm_write_header(int fd, const char *buf, int size, const char *header, size_t header_size, CWCB * handler, void *handler_data, FREE * free_func) +{ + CommWriteStateData *state = &fd_table[fd].rwstate; + debug(5, 5) ("comm_write: FD %d: sz %d: hndl %p: data %p.\n", + fd, size, handler, handler_data); + if (state->valid) { + debug(5, 1) ("comm_write: fd_table[%d].rwstate.valid == true!\n", fd); + fd_table[fd].rwstate.valid = 0; + } + state->buf = (char *) buf; + state->size = size; + state->offset = 0; + state->handler = handler; + state->handler_data = handler_data; + cbdataLock(handler_data); + state->free_func = free_func; + state->valid = 1; + assert(header_size < sizeof(state->header)); + memcpy(state->header, header, header_size); + state->header_size = header_size; + commSetSelect(fd, COMM_SELECT_WRITE, commHandleWrite, NULL, 0); +} + /* a wrapper around comm_write to allow for MemBuf to be comm_written in a snap */ void comm_write_mbuf(int fd, MemBuf mb, CWCB * handler, void *handler_data) @@ -1196,6 +1226,13 @@ comm_write(fd, mb.buf, mb.size, handler, handler_data, memBufFreeFunc(&mb)); } +/* a wrapper around comm_write to allow for MemBuf to be comm_written in a snap */ +void +comm_write_mbuf_header(int fd, MemBuf mb, const char *header, size_t header_size, CWCB * handler, void *handler_data) +{ + comm_write_header(fd, mb.buf, mb.size, header, header_size, handler, handler_data, memBufFreeFunc(&mb)); +} + /* * hm, this might be too general-purpose for all the places we'd * like to use it. Index: squid/src/enums.h diff -u squid/src/enums.h:1.64 squid/src/enums.h:1.57.6.7 --- squid/src/enums.h:1.64 Wed Nov 21 07:52:30 2007 +++ squid/src/enums.h Tue Nov 27 06:18:21 2007 @@ -502,6 +502,7 @@ HTTP_REQUEST_ENTITY_TOO_LARGE = 413, HTTP_REQUEST_URI_TOO_LONG = 414, HTTP_UNSUPPORTED_MEDIA_TYPE = 415, + HTTP_EXPECTATION_FAILED = 417, HTTP_UNPROCESSABLE_ENTITY = 422, /* RFC2518 section 10.3 */ HTTP_LOCKED = 423, /* RFC2518 section 10.4 */ HTTP_FAILED_DEPENDENCY = 424, /* RFC2518 section 10.5 */ Index: squid/src/http.c diff -u squid/src/http.c:1.68 squid/src/http.c:1.49.6.14 --- squid/src/http.c:1.68 Fri Nov 23 23:51:52 2007 +++ squid/src/http.c Tue Nov 27 06:18:21 2007 @@ -474,8 +474,19 @@ /* Parse headers into reply structure */ /* what happens if we fail to parse here? */ httpReplyParse(reply, httpState->reply_hdr.buf, hdr_size); - storeAppend(entry, httpState->reply_hdr.buf, hdr_size); done = hdr_size - old_size; + /* Skip 1xx messages for now. Advertised in Via as an internal 1.0 hop */ + if (reply->sline.status >= 100 && reply->sline.status < 200) { + memBufClean(&httpState->reply_hdr); + httpReplyReset(reply); + httpState->reply_hdr_state = 0; + ctx_exit(ctx); + if (done < size) + return done + httpProcessReplyHeader(httpState, buf + done, size - done); + else + return done; + } + storeAppend(entry, httpState->reply_hdr.buf, hdr_size); if (reply->sline.status >= HTTP_INVALID_HEADER) { debug(11, 3) ("httpProcessReplyHeader: Non-HTTP-compliant header: '%s'\n", httpState->reply_hdr.buf); memBufClean(&httpState->reply_hdr); @@ -1189,7 +1200,6 @@ case HDR_TRANSFER_ENCODING: case HDR_UPGRADE: case HDR_PROXY_CONNECTION: - case HDR_EXPECT: /* hop-by-hop headers. Don't forward */ break; case HDR_CACHE_CONTROL: @@ -1212,6 +1222,8 @@ orig_request->http_ver.major, orig_request->http_ver.minor, ThisCache); strListAdd(&strVia, bbuf, ','); + if (flags.http11) + strListAdd(&strVia, "1.0 internal", ','); httpHeaderPutStr(hdr_out, HDR_VIA, strBuf(strVia)); stringClean(&strVia); } @@ -1363,9 +1375,10 @@ http_state_flags flags) { const int offset = mb->size; - memBufPrintf(mb, "%s %s HTTP/1.0\r\n", + memBufPrintf(mb, "%s %s HTTP/1.%d\r\n", RequestMethods[request->method].str, - strLen(request->urlpath) ? strBuf(request->urlpath) : "/"); + strLen(request->urlpath) ? strBuf(request->urlpath) : "/", + flags.http11); /* build and pack headers */ { HttpHeader hdr; @@ -1432,6 +1445,10 @@ httpState->flags.only_if_cached = 1; httpState->flags.front_end_https = httpState->peer->front_end_https; } + if (httpState->peer) + httpState->flags.http11 = httpState->peer->options.http11; + else + httpState->flags.http11 = Config.onoff.server_http11; memBufDefInit(&mb); httpBuildRequestPrefix(req, httpState->orig_request, Index: squid/src/protos.h diff -u squid/src/protos.h:1.153 squid/src/protos.h:1.129.6.11 --- squid/src/protos.h:1.153 Fri Nov 23 03:53:16 2007 +++ squid/src/protos.h Tue Nov 27 06:18:22 2007 @@ -181,6 +181,15 @@ void *handler_data, FREE *); extern void comm_write_mbuf(int fd, MemBuf mb, CWCB * handler, void *handler_data); +extern void comm_write_header(int fd, + const char *buf, + int size, + const char *header, + size_t header_size, + CWCB * handler, + void *handler_data, + FREE *); +extern void comm_write_mbuf_header(int fd, MemBuf mb, const char *header, size_t header_size, CWCB * handler, void *handler_data); extern void commCallCloseHandlers(int fd); extern int commSetTimeout(int fd, int, PF *, void *); extern void commSetDefer(int fd, DEFER * func, void *); @@ -502,7 +511,7 @@ extern MemBuf httpPackedReply(http_version_t ver, http_status status, const char *ctype, squid_off_t clen, time_t lmt, time_t expires); /* construct 304 reply and pack it into MemBuf, return MemBuf */ -extern MemBuf httpPacked304Reply(const HttpReply * rep); +extern MemBuf httpPacked304Reply(const HttpReply * rep, int http11); /* update when 304 reply is received for a cached object */ extern void httpReplyUpdateOnNotModified(HttpReply * rep, HttpReply * freshRep); /* header manipulation */ Index: squid/src/ssl.c diff -u squid/src/ssl.c:1.31 squid/src/ssl.c:1.25.6.6 --- squid/src/ssl.c:1.31 Sat Jul 14 23:51:53 2007 +++ squid/src/ssl.c Sat Aug 11 18:14:03 2007 @@ -52,9 +52,11 @@ delay_id delay_id; #endif int connected; + int http11; /* Client-side HTTP/1.1 capable */ } SslStateData; -static const char *const conn_established = "HTTP/1.0 200 Connection established\r\n\r\n"; +static const char *const conn_established_10 = "HTTP/1.0 200 Connection established\r\n\r\n"; +static const char *const conn_established_11 = "HTTP/1.1 200 Connection established\r\n\r\n"; static CNCB sslConnectDone; static ERCB sslErrorComplete; @@ -392,8 +394,13 @@ SslStateData *sslState = data; debug(26, 3) ("sslConnected: FD %d sslState=%p\n", fd, sslState); *sslState->status_ptr = HTTP_OK; - xstrncpy(sslState->server.buf, conn_established, SQUID_TCP_SO_RCVBUF); - sslState->server.len = strlen(conn_established); + if (sslState->http11) { + xstrncpy(sslState->server.buf, conn_established_11, SQUID_TCP_SO_RCVBUF); + sslState->server.len = strlen(conn_established_11); + } else { + xstrncpy(sslState->server.buf, conn_established_10, SQUID_TCP_SO_RCVBUF); + sslState->server.len = strlen(conn_established_10); + } sslSetSelect(sslState); } @@ -539,6 +546,7 @@ #endif sslState->url = xstrdup(url); sslState->request = requestLink(request); + sslState->http11 = http->conn->port->http11; sslState->size_ptr = size_ptr; sslState->status_ptr = status_ptr; sslState->client.fd = fd; @@ -585,7 +593,7 @@ memset(&flags, '\0', sizeof(flags)); flags.proxying = sslState->request->flags.proxying; memBufDefInit(&mb); - memBufPrintf(&mb, "CONNECT %s HTTP/1.0\r\n", sslState->url); + memBufPrintf(&mb, "CONNECT %s HTTP/1.%d\r\n", sslState->url, sslState->servers->peer ? sslState->servers->peer->options.http11 : 0); httpBuildRequestHeader(sslState->request, sslState->request, NULL, /* StoreEntry */ Index: squid/src/structs.h diff -u squid/src/structs.h:1.165 squid/src/structs.h:1.136.6.14 --- squid/src/structs.h:1.165 Fri Nov 23 23:51:52 2007 +++ squid/src/structs.h Tue Nov 27 06:18:23 2007 @@ -370,6 +370,7 @@ unsigned int vhost; /* uses host header */ unsigned int vport; /* virtual port support */ unsigned int no_connection_auth; /* Don't support connection oriented auth */ + unsigned int http11; /* HTTP/1.1 support */ #if LINUX_TPROXY unsigned int tproxy; #endif @@ -661,6 +662,7 @@ int redirector_bypass; int storeurl_bypass; int ignore_unknown_nameservers; + int server_http11; int client_pconns; int server_pconns; int error_pconns; @@ -690,6 +692,7 @@ int log_uses_indirect_client; #endif int update_headers; + int ignore_expect_100; } onoff; acl *aclList; struct { @@ -867,6 +870,8 @@ CWCB *handler; void *handler_data; FREE *free_func; + char header[32]; + size_t header_size; }; @@ -1112,6 +1117,7 @@ unsigned int originpeer:1; unsigned int chunked:1; unsigned int trailer:1; + unsigned int http11:1; }; struct _HttpStateData { @@ -1460,6 +1466,7 @@ #if USE_CARP unsigned int carp:1; #endif + unsigned int http11:1; /* HTTP/1.1 support */ } options; int weight; struct { @@ -1863,6 +1870,7 @@ unsigned int collapsed:1; /* This request was collapsed. Don't trust the store entry to be valid */ unsigned int cache_validation:1; /* This request is an internal cache validation */ unsigned int no_direct:1; /* Deny direct forwarding unless overriden by always_direct. Used in accelerator mode */ + unsigned int chunked_response:1; /* Send the response using chunked encoding */ }; struct _link_list { Index: squid/tools/squidclient.c diff -u squid/tools/squidclient.c:1.6 squid/tools/squidclient.c:1.5.20.2 --- squid/tools/squidclient.c:1.6 Sat Sep 1 13:06:46 2007 +++ squid/tools/squidclient.c Sat Sep 1 13:11:55 2007 @@ -386,13 +386,17 @@ snprintf(buf, BUFSIZ, "Authorization: Basic %s\r\n", base64_encode(buf)); strcat(msg, buf); } - if (keep_alive) { - if (strstr(url, "://")) - strcat(msg, "Proxy-Connection: keep-alive\r\n"); - strcat(msg, "Connection: keep-alive\r\n"); + if (strcmp(version, "1.0") == 0) { + if (keep_alive) { + if (strstr(url, "://")) + strcat(msg, "Proxy-Connection: keep-alive\r\n"); + else + strcat(msg, "Connection: keep-alive\r\n"); + } + } else { + if (!keep_alive) + strcat(msg, "Connection: close\r\n"); } - if (!keep_alive) - strcat(msg, "Connection: close\r\n"); strcat(msg, extra_hdrs); strcat(msg, "\r\n");