File cntlm-0.92.3-HTTP-1.1-persistent-connections-with-HTTP-1.0-clients.patch of Package cntlm

Index: utils.c
===================================================================
--- utils.c	(revision 305)
+++ utils.c	(revision 306)
@@ -508,6 +508,7 @@
 	data->body_len = 0;
 	data->empty = 1;
 	data->port = 0;
+	data->http_version = -1;
 	data->headers = NULL;
 	data->method = NULL;
 	data->url = NULL;
@@ -535,6 +536,7 @@
 	dst->body_len = src->body_len;
 	dst->empty = src->empty;
 	dst->port = src->port;
+	dst->http_version = src->http_version;
 
 	if (src->headers)
 		dst->headers = hlist_dup(src->headers);
@@ -584,6 +586,7 @@
 	data->body_len = 0;
 	data->empty = 1;
 	data->port = 0;
+	data->http_version = -1;
 
 	if (data->headers) hlist_free(data->headers);
 	if (data->method) free(data->method);
@@ -623,6 +626,7 @@
 	if (data->http) free(data->http);
 	if (data->msg) free(data->msg);
 	if (data->body) free(data->body);
+	memset(data, 0, sizeof(struct rr_data_s));
 	free(data);
 }
 
Index: forward.c
===================================================================
--- forward.c	(revision 305)
+++ forward.c	(revision 306)
@@ -188,6 +188,7 @@
 
 	if (debug) {
 		printf("\nSending PROXY auth request...\n");
+		printf("HEAD: %s %s %s\n", auth->method, auth->url, auth->http);
 		hlist_dump(auth->headers);
 	}
 
@@ -316,7 +317,7 @@
  * request is NOT freed
  */
 rr_data_t forward_request(void *thread_data, rr_data_t request) {
-	int i, w, loop, plugin, retry = 0;
+	int i, loop, plugin, retry = 0;
 	int *rsocket[2], *wsocket[2];
 	rr_data_t data[2], rc = NULL;
 	hlist_t tl;
@@ -368,7 +369,7 @@
 		sd = proxy_connect(tcreds);
 		if (sd <= 0) {
 			tmp = gen_502_page(request->http, "Parent proxy unreacheable");
-			w = write(cd, tmp, strlen(tmp));
+			i = write(cd, tmp, strlen(tmp));
 			free(tmp);
 			rc = (void *)-1;
 			goto bailout;
@@ -446,7 +447,9 @@
 					&& strcasecmp(hostname, data[0]->hostname)) {
 				if (debug)
 					printf("\n******* F RETURN: %s *******\n", data[0]->url);
-				if (authok)
+				if (authok && data[0]->http_version >= 11
+						&& (hlist_subcmp(data[0]->headers, "Proxy-Connection", "keep-alive")
+							|| hlist_subcmp(data[0]->headers, "Connection", "keep-alive")))
 					proxy_alive = 1;
 
 				rc = dup_rr_data(data[0]);
@@ -465,7 +468,7 @@
 			/*
 			 * Modify request headers.
 			 *
-			 * Try to request keep-alive for every connection. We keep them in a pool
+			 * Try to request keep-alive for every client supporting HTTP/1.1+. We keep them in a pool
 			 * for future reuse.
 			 */
 			if (loop == 0 && data[0]->req) {
@@ -474,13 +477,14 @@
 				 */
 				if (http_parse_basic(data[loop]->headers, "Proxy-Authorization", tcreds) > 0) {
 					if (debug)
-						printf("NTLM-to-basic: Credentials parsed: %s\\%s at %s\n", tcreds->domain, tcreds->user, tcreds->workstation);
+						printf("NTLM-to-basic: Credentials parsed: %s\\%s at %s\n",
+								tcreds->domain, tcreds->user, tcreds->workstation);
 				} else if (ntlmbasic) {
 					if (debug)
 						printf("NTLM-to-basic: Returning client auth request.\n");
 
 					tmp = gen_407_page(data[loop]->http);
-					w = write(cd, tmp, strlen(tmp));
+					i = write(cd, tmp, strlen(tmp));
 					free(tmp);
 
 					free_rr_data(data[0]);
@@ -499,13 +503,14 @@
 				}
 
 				/*
-				 * Also remove runaway P-A from the client (e.g. Basic from N-t-B), which might 
-				 * cause some ISAs to deny us, even if the connection is already auth'd.
+				 * Force proxy keep-alive if the client can handle it (HTTP >= 1.1)
 				 */
-				data[0]->headers = hlist_mod(data[0]->headers, "Proxy-Connection", "keep-alive", 1);
+				if (data[0]->http_version >= 11)
+					data[0]->headers = hlist_mod(data[0]->headers, "Proxy-Connection", "keep-alive", 1);
 
 				/*
-				 * Remove all Proxy-Authorization headers from client
+				 * Also remove runaway P-A from the client (e.g. Basic from N-t-B), which might 
+				 * cause some ISAs to deny us, even if the connection is already auth'd.
 				 */
 				while (hlist_get(data[loop]->headers, "Proxy-Authorization")) {
 					data[loop]->headers = hlist_del(data[loop]->headers, "Proxy-Authorization");
@@ -623,8 +628,10 @@
 			if (plugin & PLUG_SENDHEAD) {
 				if (debug) {
 					printf("Sending headers (%d)...\n", *wsocket[loop]);
-					if (loop == 0)
+					if (loop == 0) {
+						printf("HEAD: %s %s %s\n", data[loop]->method, data[loop]->url, data[loop]->http);
 						hlist_dump(data[loop]->headers);
+					}
 				}
 
 				/*
@@ -672,8 +679,14 @@
 			 * This way, we also tell our caller that proxy keep-alive is impossible.
 			 */
 			if (loop == 1) {
-				proxy_alive = hlist_subcmp(data[loop]->headers, "Proxy-Connection", "keep-alive");
-				if (!proxy_alive) {
+				proxy_alive = hlist_subcmp(data[1]->headers, "Proxy-Connection", "keep-alive")
+					&& data[0]->http_version >= 11;
+				if (proxy_alive) {
+					data[1]->headers = hlist_mod(data[1]->headers, "Proxy-Connection", "keep-alive", 1);
+					data[1]->headers = hlist_mod(data[1]->headers, "Connection", "keep-alive", 1);
+				} else {
+					data[1]->headers = hlist_mod(data[1]->headers, "Proxy-Connection", "close", 1);
+					data[1]->headers = hlist_mod(data[1]->headers, "Connection", "close", 1);
 					if (debug)
 						printf("PROXY CLOSING CONNECTION\n");
 					rc = (void *)-1;
Index: utils.h
===================================================================
--- utils.h	(revision 305)
+++ utils.h	(revision 306)
@@ -89,6 +89,7 @@
 	int body_len;
 	int empty;
 	int port;
+	int http_version;
 	char *method;
 	char *url;
 	char *rel_url;
Index: http.c
===================================================================
--- http.c	(revision 305)
+++ http.c	(revision 306)
@@ -84,7 +84,7 @@
  */
 int headers_recv(int fd, rr_data_t data) {
 	int i, bsize;
-	int len;
+	int len, is_http = 0;
 	char *buf;
 	char *tok, *s3 = 0;
 	char *orig = NULL;
@@ -108,12 +108,22 @@
 	orig = strdup(buf);
 	len = strlen(buf);
 	tok = strtok_r(buf, " ", &s3);
-	if (tok && (!strncasecmp(buf, "HTTP/", 5) || !strncasecmp(tok, "ICY", 3))) {
+	if (tok && ((is_http = !strncasecmp(tok, "HTTP/", 5)) || !strncasecmp(tok, "ICY", 3))) {
 		data->req = 0;
 		data->empty = 0;
 		data->http = strdup(tok);
 		data->msg = NULL;
 
+		/*
+		 * Let's find out the numeric version of the HTTP version: 09, 10, 11.
+		 * Set to -1 if header is misformatted.
+		 */
+		if (is_http && (tok = strchr(data->http, '/')) && strlen(tok) >= 4 && isdigit(tok[1]) && isdigit(tok[3])) {
+			data->http_version = (tok[1] - 0x30) * 10 + (tok[3] - 0x30);
+		} else {
+			data->http_version = -1;
+		}
+
 		tok = strtok_r(NULL, " ", &s3);
 		if (tok) {
 			ccode = strdup(tok);
@@ -156,6 +166,16 @@
 			goto bailout;
 		}
 
+		/*
+		 * Let's find out the numeric version of the HTTP version: 09, 10, 11.
+		 * Set to -1 if header is misformatted.
+		 */
+		if ((tok = strchr(data->http, '/')) && strlen(tok) >= 4 && isdigit(tok[1]) && isdigit(tok[3])) {
+			data->http_version = (tok[1] - 0x30) * 10 + (tok[3] - 0x30);
+		} else {
+			data->http_version = -1;
+		}
+
 		if ((tok = strstr(data->url, "://"))) {
 			tok += 3;
 		} else {
@@ -367,7 +387,7 @@
  */
 int chunked_data_send(int dst, int src) {
 	char *buf;
-	int bsize;
+	int bsize, len;
 	int i, w, csize;
 
 	char *err = NULL;
@@ -408,11 +428,14 @@
 	} while (csize != 0);
 
 	/* Take care of possible trailer */
+	w = len = i = 0;
 	do {
 		i = so_recvln(src, &buf, &bsize);
-		if (dst >= 0 && i > 0)
-			w = write(dst, buf, strlen(buf));
-	} while (i > 0 && buf[0] != '\r' && buf[0] != '\n');
+		if (dst >= 0 && i > 0) {
+			len = strlen(buf);
+			w = write(dst, buf, len);
+		}
+	} while (w == len && i > 0 && buf[0] != '\r' && buf[0] != '\n');
 
 	free(buf);
 	return 1;
Index: direct.c
===================================================================
--- direct.c	(revision 305)
+++ direct.c	(revision 306)
@@ -198,6 +198,8 @@
 		syslog(LOG_WARNING, "Connection failed for %s:%d (%s)", request->hostname, request->port, strerror(errno));
 		tmp = gen_502_page(request->http, strerror(errno));
 		w = write(cd, tmp, strlen(tmp));
+		// We don't really care about the result - shut up GCC warning (unused-but-set-variable)
+		if (!w) w = 1;
 		free(tmp);
 
 		rc = (void *)-1;
@@ -282,10 +284,21 @@
 					data[0]->url = strdup(data[0]->rel_url);
 				}
 
-				data[0]->headers = hlist_mod(data[0]->headers, "Connection", "keep-alive", 1);
-				data[0]->headers = hlist_del(data[0]->headers, "Proxy-Authorization");
+				/*
+				 * Force proxy keep-alive if the client can handle it (HTTP >= 1.1)
+				 */
+				if (data[0]->http_version >= 11)
+					data[0]->headers = hlist_mod(data[0]->headers, "Connection", "keep-alive", 1);
 
 				/*
+				 * Also remove runaway P-A from the client (e.g. Basic from N-t-B), which might 
+				 * cause some ISAs to deny us, even if the connection is already auth'd.
+				 */
+				while (hlist_get(data[loop]->headers, "Proxy-Authorization")) {
+					data[loop]->headers = hlist_del(data[loop]->headers, "Proxy-Authorization");
+				}
+
+				/*
 				 * Try to get auth from client if present
 				 */
 				if (http_parse_basic(data[0]->headers, "Authorization", tcreds) > 0 && debug)
@@ -373,18 +386,25 @@
 			 */
 			if (loop == 1) {
 				conn_alive = !hlist_subcmp(data[1]->headers, "Connection", "close")
-					&& http_has_body(data[0], data[1]) != -1;
+					&& http_has_body(data[0], data[1]) != -1
+					&& data[0]->http_version >= 11;
 				if (conn_alive) {
 					data[1]->headers = hlist_mod(data[1]->headers, "Proxy-Connection", "keep-alive", 1);
 					data[1]->headers = hlist_mod(data[1]->headers, "Connection", "keep-alive", 1);
 				} else {
 					data[1]->headers = hlist_mod(data[1]->headers, "Proxy-Connection", "close", 1);
+					data[1]->headers = hlist_mod(data[1]->headers, "Connection", "close", 1);
 					rc = (void *)-1;
 				}
 			}
 
-			if (debug)
+			if (debug) {
 				printf("Sending headers (%d)...\n", *wsocket[loop]);
+				if (loop == 0) {
+					printf("HEAD: %s %s %s\n", data[loop]->method, data[loop]->url, data[loop]->http);
+					hlist_dump(data[loop]->headers);
+				}
+			}
 
 			/*
 			 * Send headers
Index: main.c
===================================================================
--- main.c	(revision 305)
+++ main.c	(revision 306)
@@ -462,6 +462,8 @@
 		bs[0] = 5;
 		bs[1] = 0xFF;
 		w = write(cd, bs, 2);
+		// We don't really care about the result - shut up GCC warning (unused-but-set-variable)
+		if (!w) w = 1;
 		goto bailout;
 	} else {
 		bs[0] = 5;
@@ -1400,6 +1402,8 @@
 	 * If we fail, exit with error.
 	 */
 	if (strlen(cpidfile)) {
+		int len;
+
 		umask(0);
 		cd = open(cpidfile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
 		if (cd < 0) {
@@ -1409,7 +1413,11 @@
 
 		tmp = new(50);
 		snprintf(tmp, 50, "%d\n", getpid());
-		w = write(cd, tmp, strlen(tmp));
+		w = write(cd, tmp, (len = strlen(tmp)));
+		if (w != len) {
+			syslog(LOG_ERR, "Error writing to the PID file\n");
+			myexit(1);
+		}
 		free(tmp);
 		close(cd);
 	}
@@ -1517,6 +1525,8 @@
 						inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));
 					tmp = gen_denied_page(inet_ntoa(caddr.sin_addr));
 					w = write(cd, tmp, strlen(tmp));
+					// We don't really care about the result - shut up GCC warning (unused-but-set-variable)
+					if (!w) w = 1;
 					free(tmp);
 					close(cd);
 					continue;
Index: scanner.c
===================================================================
--- scanner.c	(revision 305)
+++ scanner.c	(revision 306)
@@ -153,6 +153,8 @@
 						tmp = new(MINIBUF_SIZE);
 						snprintf(tmp, MINIBUF_SIZE, "%s 200 OK\r\n", request->http);
 						w = write(cd, tmp, strlen(tmp));
+						// We don't really care about the result - shut up GCC warning (unused-but-set-variable)
+						if (!w) w = 1;
 						free(tmp);
 					}