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");