From 9448787ff260abcd3b7bd5d6c932b8e43b738e8d Mon Sep 17 00:00:00 2001
From: Robert James Kaes <rjkaes@users.sourceforge.net>
Date: Mon, 17 Dec 2001 00:11:32 +0000
Subject: Added UPSTREAM_CONFIGURED() macro to help clean up the code.

Ignore any blank lines when tinyproxy is expecting a request line.

Instead of sending the request line to the remote server in pieces,
tinyproxy nows sends it in once go. This was done to fix a problem with
some sites like www.heise.de.

Changed all calls to connptr->ssl to connptr->connect_method.

Changed all calls to connptr->send_message to
connptr->send_response_message.

Moved the call to Via header code to inside to the tests to handle if
tinyproxy is sending an error message (don't need to send any headers.)
---
 src/reqs.c | 189 ++++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 100 insertions(+), 89 deletions(-)

diff --git a/src/reqs.c b/src/reqs.c
index 9519924..aee7b82 100644
--- a/src/reqs.c
+++ b/src/reqs.c
@@ -1,4 +1,4 @@
-/* $Id: reqs.c,v 1.42 2001-11-23 01:17:19 rjkaes Exp $
+/* $Id: reqs.c,v 1.43 2001-12-17 00:11:32 rjkaes Exp $
  *
  * This is where all the work in tinyproxy is actually done. Incoming
  * connections have a new thread created for them. The thread then
@@ -41,6 +41,16 @@
 #define HTTP500ERROR "Unable to connect to remote server."
 #define HTTP503ERROR "Internal server error."
 
+/*
+ * Macro to help test if the Upstream proxy supported is compiled in and
+ * enabled.
+ */
+#ifdef UPSTREAM_SUPPORT
+#  define UPSTREAM_CONFIGURED() (config.upstream_name && config.upstream_port != -1)
+#else
+#  define UPSTREAM_CONFIGURED() (0)
+#endif
+
 /*
  * Read in the first line from the client (the request line for HTTP
  * connections. The request line is allocated from the heap, but it must
@@ -52,6 +62,7 @@ read_request_line(struct conn_s *connptr)
 	char *request_buffer;
 	size_t len;
 
+      retry:
 	len = readline(connptr->client_fd, &request_buffer);
 	if (len <= 0) {
 		log_message(LOG_ERR,
@@ -64,7 +75,15 @@ read_request_line(struct conn_s *connptr)
 	/*
 	 * Strip the new line and character return from the string.
 	 */
-	chomp(request_buffer, len);
+	if (chomp(request_buffer, len) == len) {
+		/*
+		 * If the number of characters removed is the same as the
+		 * length then it was a blank line. Free the buffer and
+		 * try again (since we're looking for a request line.)
+		 */
+		safefree(request_buffer);
+		goto retry;
+	}
 
 	log_message(LOG_CONN, "Request (file descriptor %d): %s",
 		    connptr->client_fd, request_buffer);
@@ -164,43 +183,42 @@ extract_ssl_url(const char *url, struct request_s *request)
 /*
  * Create a connection for HTTP connections.
  */
+#define HTTP_LINE_LENGTH (1024 * 16)
 static int
 establish_http_connection(struct conn_s *connptr, struct request_s *request)
 {
-	/*
-	 * Send the request line
-	 */
-	if (safe_write
-	    (connptr->server_fd, request->method, strlen(request->method)) < 0)
-		return -1;
-	if (safe_write(connptr->server_fd, " ", 1) < 0)
-		return -1;
-	if (safe_write(connptr->server_fd, request->path, strlen(request->path)) < 0)
-		return -1;
-	if (safe_write(connptr->server_fd, " ", 1) < 0)
-		return -1;
-	if (safe_write(connptr->server_fd, "HTTP/1.0\r\n", 10) < 0)
+	char *buffer;
+
+	buffer = safemalloc(HTTP_LINE_LENGTH);
+	if (!buffer)
 		return -1;
 
+	if (snprintf(buffer, HTTP_LINE_LENGTH, "%s %s HTTP/1.0\r\n", request->method, request->path) < 0)
+		goto error;
+	if (safe_write(connptr->server_fd, buffer, strlen(buffer)) < 0)
+		goto error;
+
 	/*
 	 * Send headers
 	 */
-	if (safe_write(connptr->server_fd, "Host: ", 6) < 0)
-		return -1;
-	if (safe_write(connptr->server_fd, request->host, strlen(request->host)) < 0)
-		return -1;
-
-	if (safe_write(connptr->server_fd, "\r\n", 2) < 0)
-		return -1;
+	if (snprintf(buffer, HTTP_LINE_LENGTH, "Host: %s\r\n", request->host) < 0)
+		goto error;
+	if (safe_write(connptr->server_fd, buffer, strlen(buffer)) < 0)
+		goto error;
 
 	/*
 	 * Send the Connection header since we don't support persistant
 	 * connections.
 	 */
 	if (safe_write(connptr->server_fd, "Connection: close\r\n", 19) < 0)
-		return -1;
+		goto error;
 
+	safefree(buffer);
 	return 0;
+
+      error:
+	safefree(buffer);
+	return -1;
 }
 
 /*
@@ -275,9 +293,11 @@ process_request(struct conn_s *connptr, char *request_line)
 		free_request_struct(request);
 
 		return NULL;
-	} else if (ret == 2) {
-		connptr->simple_req = TRUE;
 	}
+	/* 
+	 * NOTE: We need to add code for the simple HTTP/0.9 style GET
+	 * request.
+	 */
 
 	if (!url) {
 		log_message(LOG_ERR,
@@ -304,7 +324,6 @@ process_request(struct conn_s *connptr, char *request_line)
 
 			return NULL;
 		}
-		connptr->ssl = FALSE;
 	} else if (strcmp(request->method, "CONNECT") == 0) {
 		if (extract_ssl_url(url, request) < 0) {
 			httperr(connptr, 400,
@@ -315,7 +334,8 @@ process_request(struct conn_s *connptr, char *request_line)
 
 			return NULL;
 		}
-		connptr->ssl = TRUE;
+		
+		connptr->connect_method = TRUE;
 	} else {
 		log_message(LOG_ERR,
 			    "process_request: Unknown URL type on file descriptor %d",
@@ -368,7 +388,7 @@ process_request(struct conn_s *connptr, char *request_line)
 	 */
 	if (strncasecmp(request->protocol, "http", 4) == 0) {
 		memcpy(request->protocol, "HTTP", 4);
-		sscanf(request->protocol, "HTTP/%hu.%hu",
+		sscanf(request->protocol, "HTTP/%u.%u",
 		       &connptr->protocol.major, &connptr->protocol.minor);
 	}
 
@@ -428,7 +448,7 @@ pull_client_data(struct conn_s *connptr, unsigned long int length)
 			return -1;
 		}
 
-		if (!connptr->send_message) {
+		if (!connptr->send_response_message) {
 			if (safe_write(connptr->server_fd, buffer, len) < 0) {
 				safefree(buffer);
 				return -1;
@@ -483,6 +503,7 @@ process_client_headers(struct conn_s *connptr)
 	char *header;
 	long content_length = -1;
 	short int sent_via_header = 0;
+	ssize_t len;
 
 	static char *skipheaders[] = {
 		"proxy-connection",
@@ -495,27 +516,28 @@ process_client_headers(struct conn_s *connptr)
 	int i;
 
 	for (;;) {
-		if (readline(connptr->client_fd, &header) <= 0) {
+		if ((len = readline(connptr->client_fd, &header)) <= 0) {
 			DEBUG2("Client (file descriptor %d) closed connection.",
 			       connptr->client_fd);
 			return -1;
 		}
 
-		if (header[0] == '\n'
-		    || (header[0] == '\r' && header[1] == '\n')) {
+		/*
+		 * If we receive a CR LF (or just a LF) on a line by itself,
+		 * the headers are finished.
+		 */
+		if ((len == 1 && header[0] == '\n')
+		    || (len == 2 && header[0] == '\r' && header[1] == '\n')) {
 			break;
 		}
 
-		if (connptr->send_message) {
-			safefree(header);
-			continue;
-		}
-
 		/*
-		 * Don't send any of the headers if we're in SSL mode and
-		 * NOT using an upstream proxy.
+		 * Don't send headers if there's already an error, or if
+		 * this was a CONNECT method (unless upstream proxy is in
+		 * use.)
 		 */
-		if (connptr->ssl && !connptr->upstream) {
+		if (connptr->server_fd == -1
+		    || (connptr->connect_method && !UPSTREAM_CONFIGURED())) {
 			safefree(header);
 			continue;
 		}
@@ -575,9 +597,7 @@ process_client_headers(struct conn_s *connptr)
 			content_length = atol(content_ptr);
 		}
 
-		if ((connptr->server_fd != -1)
-		    && safe_write(connptr->server_fd, header,
-				  strlen(header)) < 0) {
+		if (safe_write(connptr->server_fd, header, strlen(header)) < 0) {
 			safefree(header);
 			return -1;
 		}
@@ -585,23 +605,8 @@ process_client_headers(struct conn_s *connptr)
 		safefree(header);
 	}
 
-	if (sent_via_header == 0) {
-		/*
-		 * We're the first proxy so send the first Via header.
-		 */
-		char via_header_buffer[256];
-		char hostname[128];
-
-		gethostname(hostname, sizeof(hostname));
-		snprintf(via_header_buffer, sizeof(via_header_buffer),
-			 "Via: %hu.%hu %s (%s/%s)\r\n", connptr->protocol.major,
-			 connptr->protocol.minor, hostname, PACKAGE, VERSION);
-
-		safe_write(connptr->server_fd, via_header_buffer,
-			   strlen(via_header_buffer));
-	}
-
-	if (!connptr->send_message && (connptr->upstream || !connptr->ssl)) {
+	if (!connptr->send_response_message
+	    && (!connptr->connect_method || UPSTREAM_CONFIGURED())) {
 #ifdef XTINYPROXY_ENABLE
 		if (config.my_domain && add_xtinyproxy_header(connptr) < 0) {
 			safefree(header);
@@ -609,6 +614,22 @@ process_client_headers(struct conn_s *connptr)
 		}
 #endif				/* XTINYPROXY */
 
+		if (sent_via_header == 0) {
+			/*
+			 * We're the first proxy so send the first Via header.
+			 */
+			char via_header_buffer[256];
+			char hostname[128];
+
+			gethostname(hostname, sizeof(hostname));
+			snprintf(via_header_buffer, sizeof(via_header_buffer),
+				 "Via: %hu.%hu %s (%s/%s)\r\n", connptr->protocol.major,
+				 connptr->protocol.minor, hostname, PACKAGE, VERSION);
+
+			safe_write(connptr->server_fd, via_header_buffer,
+				   strlen(via_header_buffer));
+		}
+
 		if ((connptr->server_fd != -1)
 		    && safe_write(connptr->server_fd, header,
 				  strlen(header)) < 0) {
@@ -650,16 +671,13 @@ process_server_headers(struct conn_s *connptr)
 			break;
 		}
 
-		if (!connptr->simple_req
-		    && safe_write(connptr->client_fd, header,
-				  strlen(header)) < 0) {
+		if (safe_write(connptr->client_fd, header, strlen(header)) < 0) {
 			safefree(header);
 			return -1;
 		}
 	}
 
-	if (!connptr->simple_req
-	    && safe_write(connptr->client_fd, header, strlen(header)) < 0) {
+	if (safe_write(connptr->client_fd, header, strlen(header)) < 0) {
 		safefree(header);
 		return -1;
 	}
@@ -734,19 +752,19 @@ relay_connection(struct conn_s *connptr)
 		}
 
 		if (FD_ISSET(connptr->server_fd, &rset)
-		    && readbuff(connptr->server_fd, connptr->sbuffer) < 0) {
+		    && read_buffer(connptr->server_fd, connptr->sbuffer) < 0) {
 			break;
 		}
 		if (FD_ISSET(connptr->client_fd, &rset)
-		    && readbuff(connptr->client_fd, connptr->cbuffer) < 0) {
+		    && read_buffer(connptr->client_fd, connptr->cbuffer) < 0) {
 			break;
 		}
 		if (FD_ISSET(connptr->server_fd, &wset)
-		    && writebuff(connptr->server_fd, connptr->cbuffer) < 0) {
+		    && write_buffer(connptr->server_fd, connptr->cbuffer) < 0) {
 			break;
 		}
 		if (FD_ISSET(connptr->client_fd, &wset)
-		    && writebuff(connptr->client_fd, connptr->sbuffer) < 0) {
+		    && write_buffer(connptr->client_fd, connptr->sbuffer) < 0) {
 			break;
 		}
 	}
@@ -757,7 +775,7 @@ relay_connection(struct conn_s *connptr)
 	 */
 	socket_blocking(connptr->client_fd);
 	while (BUFFER_SIZE(connptr->sbuffer) > 0) {
-		if (writebuff(connptr->client_fd, connptr->sbuffer) < 0)
+		if (write_buffer(connptr->client_fd, connptr->sbuffer) < 0)
 			break;
 	}
 
@@ -766,7 +784,7 @@ relay_connection(struct conn_s *connptr)
 	 */
 	socket_blocking(connptr->server_fd);
 	while (BUFFER_SIZE(connptr->cbuffer) > 0) {
-		if (writebuff(connptr->client_fd, connptr->cbuffer) < 0)
+		if (write_buffer(connptr->client_fd, connptr->cbuffer) < 0)
 			break;
 	}
 
@@ -802,7 +820,7 @@ connect_to_upstream(struct conn_s *connptr, struct request_s *request)
 	 * can reuse the establish_http_connection() function. It expects a
 	 * method and path.
 	 */
-	if (connptr->ssl) {
+	if (connptr->connect_method) {
 		len = strlen(request->host) + 6;
 
 		combined_string = safemalloc(len + 1);
@@ -915,21 +933,18 @@ handle_connection(int fd)
 	safefree(request_line);
 
 	if (!request) {
-		if (!connptr->send_message) {
+		if (!connptr->send_response_message) {
 			update_stats(STAT_BADCONN);
 			destroy_conn(connptr);
 			return;
 		}
 		goto send_error;
 	}
-#ifdef UPSTREAM_SUPPORT
-	if (config.upstream_name && config.upstream_port != -1) {
-		connptr->upstream = TRUE;
 
+	if (UPSTREAM_CONFIGURED()) {
 		if (connect_to_upstream(connptr, request) < 0)
 			goto send_error;
 	} else {
-#endif
 		connptr->server_fd = opensock(request->host, request->port);
 		if (connptr->server_fd < 0) {
 			httperr(connptr, 500, HTTP500ERROR);
@@ -940,31 +955,27 @@ handle_connection(int fd)
 			    "Established connection to host \"%s\" using file descriptor %d.",
 			    request->host, connptr->server_fd);
 
-		if (!connptr->ssl)
+		if (!connptr->connect_method)
 			establish_http_connection(connptr, request);
-#ifdef UPSTREAM_SUPPORT
 	}
-#endif
 
       send_error:
 	free_request_struct(request);
 
-	if (!connptr->simple_req) {
-		if (process_client_headers(connptr) < 0) {
-			update_stats(STAT_BADCONN);
-			if (!connptr->send_message) {
-				destroy_conn(connptr);
-				return;
-			}
+	if (process_client_headers(connptr) < 0) {
+		update_stats(STAT_BADCONN);
+		if (!connptr->send_response_message) {
+			destroy_conn(connptr);
+			return;
 		}
 	}
 
-	if (connptr->send_message) {
+	if (connptr->send_response_message) {
 		destroy_conn(connptr);
 		return;
 	}
 
-	if (!connptr->ssl || connptr->upstream) {
+	if (!connptr->connect_method || UPSTREAM_CONFIGURED()) {
 		if (process_server_headers(connptr) < 0) {
 			update_stats(STAT_BADCONN);
 			destroy_conn(connptr);
-- 
cgit v1.2.3