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