Hi,

I discovered that the wrong server configuration is evaluated in the
server_read_http function. Only the first server in httpd.conf is checked. For
example, I have five servers setup in httpd.conf and the third server is the
only one with connection { max request body ####} set, because I desire it to
accept larger uploads than the other servers. When the upload is initiated,
server one dictates the max request body size, globally.

The attached diff moves the queue loop out of the server_response function in to
its own function, as to not duplicate code.

I don't know if this is the only place the wrong information is evaluated. Also,
I'm not sure this is the best method to fix the problem, but it should point the
powers that be in the right direction.

Thanks,

Tracey

--- usr.sbin/httpd/httpd.h.orig	Wed Jul 25 13:54:54 2018
+++ usr.sbin/httpd/httpd.h	Wed Jul 25 15:06:59 2018
@@ -691,6 +691,8 @@
 char	*server_http_parsehost(char *, char *, size_t, int *);
 ssize_t	 server_http_time(time_t, char *, size_t);
 int	 server_log_http(struct client *, unsigned int, size_t);
+int	 server_check_client_config(struct server_config *, struct client *,
+	    struct kv *);
 
 /* server_file.c */
 int	 server_file(struct httpd *, struct client *);
--- usr.sbin/httpd/server_http.c.orig	Wed Jul 25 13:55:06 2018
+++ usr.sbin/httpd/server_http.c	Wed Jul 25 15:37:58 2018
@@ -204,7 +204,7 @@
 	char			*line = NULL, *key, *value;
 	const char		*errstr;
 	size_t			 size, linelen;
-	struct kv		*hdr = NULL;
+	struct kv		*hdr = NULL, kv_key, *host;
 
 	getmonotime(&clt->clt_tv_last);
 
@@ -344,6 +344,16 @@
 				goto abort;
 			}
 
+			kv_key.kv_key = "Host";
+			if ((host = kv_find(&desc->http_headers, &kv_key)) !=
+			    NULL && host->kv_value == NULL)
+				host = NULL;
+
+			if (server_check_client_config(srv_conf, clt, host))
+				goto fail;
+
+			srv_conf = clt->clt_srv_conf;
+
 			/*
 			 * Need to read data from the client after the
 			 * HTTP header.
@@ -1168,10 +1178,7 @@
 	struct server		*srv = clt->clt_srv;
 	struct server_config	*srv_conf = &srv->srv_conf;
 	struct kv		*kv, key, *host;
-	struct str_find		 sm;
-	int			 portval = -1, ret;
-	char			*hostval, *query;
-	const char		*errstr = NULL;
+	char			*query;
 
 	/* Decode the URL */
 	if (desc->http_path == NULL ||
@@ -1219,59 +1226,11 @@
 	if (clt->clt_pipelining && clt->clt_toread > 0)
 		clt->clt_persist = 0;
 
-	/*
-	 * Do we have a Host header and matching configuration?
-	 * XXX the Host can also appear in the URL path.
-	 */
-	if (host != NULL) {
-		if ((hostval = server_http_parsehost(host->kv_value,
-		    hostname, sizeof(hostname), &portval)) == NULL)
-			goto fail;
+	if (server_check_client_config(srv_conf, clt, host))
+		goto fail;
 
-		TAILQ_FOREACH(srv_conf, &srv->srv_hosts, entry) {
-#ifdef DEBUG
-			if ((srv_conf->flags & SRVFLAG_LOCATION) == 0) {
-				DPRINTF("%s: virtual host \"%s:%u\""
-				    " host \"%s\" (\"%s\")",
-				    __func__, srv_conf->name,
-				    ntohs(srv_conf->port), host->kv_value,
-				    hostname);
-			}
-#endif
-			if (srv_conf->flags & SRVFLAG_LOCATION)
-				continue;
-			else if (srv_conf->flags & SRVFLAG_SERVER_MATCH) {
-				str_find(hostname, srv_conf->name,
-				    &sm, 1, &errstr);
-				ret = errstr == NULL ? 0 : -1;
-			} else {
-				ret = fnmatch(srv_conf->name,
-				    hostname, FNM_CASEFOLD);
-			}
-			if (ret == 0 &&
-			    (portval == -1 ||
-			    (portval != -1 && portval == srv_conf->port))) {
-				/* Replace host configuration */
-				clt->clt_srv_conf = srv_conf;
-				srv_conf = NULL;
-				break;
-			}
-		}
-	}
+	srv_conf = clt->clt_srv_conf;
 
-	if (srv_conf != NULL) {
-		/* Use the actual server IP address */
-		if (server_http_host(&clt->clt_srv_ss, hostname,
-		    sizeof(hostname)) == NULL)
-			goto fail;
-	} else {
-		/* Host header was valid and found */
-		if (strlcpy(hostname, host->kv_value, sizeof(hostname)) >=
-		    sizeof(hostname))
-			goto fail;
-		srv_conf = clt->clt_srv_conf;
-	}
-
 	if ((desc->http_host = strdup(hostname)) == NULL)
 		goto fail;
 
@@ -1748,4 +1707,69 @@
 	free(agent_v);
 
 	return (ret);
+}
+
+int
+server_check_client_config(struct server_config *srv_conf, struct client *clt,
+    struct kv *host)
+{
+	char                     hostname[HOST_NAME_MAX+1];
+	struct server           *srv = clt->clt_srv;
+	struct str_find          sm;
+	int			 portval = -1, ret;
+	char                    *hostval;
+	const char              *errstr = NULL;
+
+	/*
+	 * Do we have a Host header and matching configuration?
+	 * XXX the Host can also appear in the URL path.
+	 */
+	if (host != NULL) {
+		if ((hostval = server_http_parsehost(host->kv_value,
+		    hostname, sizeof(hostname), &portval)) == NULL)
+			return(-1);
+
+		TAILQ_FOREACH(srv_conf, &srv->srv_hosts, entry) {
+#ifdef DEBUG
+			if ((srv_conf->flags & SRVFLAG_LOCATION) == 0) {
+				DPRINTF("%s: virtual host \"%s:%u\""
+				    " host \"%s\" (\"%s\")",
+				    __func__, srv_conf->name,
+				    ntohs(srv_conf->port), host->kv_value,
+				    hostname);
+			}
+#endif
+			if (srv_conf->flags & SRVFLAG_LOCATION)
+				continue;
+			else if (srv_conf->flags & SRVFLAG_SERVER_MATCH) {
+				str_find(hostname, srv_conf->name,
+				    &sm, 1, &errstr);
+				ret = errstr == NULL ? 0 : -1;
+			} else {
+				ret = fnmatch(srv_conf->name,
+				    hostname, FNM_CASEFOLD);
+			}
+			if (ret == 0 &&
+			    (portval == -1 ||
+			    (portval != -1 && portval == srv_conf->port))) {
+				/* Replace host configuration */
+				clt->clt_srv_conf = srv_conf;
+				srv_conf = NULL;
+				break;
+			}
+		}
+	}
+
+	if (srv_conf != NULL) {
+		/* Use the actual server IP address */
+		if (server_http_host(&clt->clt_srv_ss, hostname,
+		    sizeof(hostname)) == NULL)
+			return(-1);
+	} else {
+		/* Host header was valid and found */
+		if (strlcpy(hostname, host->kv_value, sizeof(hostname)) >=
+		    sizeof(hostname))
+			return(-1);
+	}
+	return(0);
 }

Reply via email to