From 4f194ec8d9cc2d117739626d52a7f304b85ba1d1 Mon Sep 17 00:00:00 2001 From: reyk Date: Wed, 30 Jul 2014 13:49:48 +0000 Subject: [PATCH] Make "location" work with name-based virtual servers. --- usr.sbin/httpd/config.c | 16 ++++++---------- usr.sbin/httpd/httpd.h | 4 +--- usr.sbin/httpd/parse.y | 20 ++++++++++++++++++-- usr.sbin/httpd/server.c | 15 +-------------- usr.sbin/httpd/server_http.c | 26 +++++++++++++++++++------- 5 files changed, 45 insertions(+), 36 deletions(-) diff --git a/usr.sbin/httpd/config.c b/usr.sbin/httpd/config.c index 9e9d2c3754d..44cd419565f 100644 --- a/usr.sbin/httpd/config.c +++ b/usr.sbin/httpd/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.6 2014/07/30 10:05:14 reyk Exp $ */ +/* $OpenBSD: config.c,v 1.7 2014/07/30 13:49:48 reyk Exp $ */ /* * Copyright (c) 2011 - 2014 Reyk Floeter @@ -275,23 +275,19 @@ config_getserver(struct httpd *env, struct imsg *imsg) memcpy(&srv_conf, p, sizeof(srv_conf)); s = sizeof(srv_conf); - if (srv_conf.flags & SRVFLAG_LOCATION) { - if ((srv = server_byname(srv_conf.name)) == NULL) { - log_warnx("%s: invalid location", __func__); - return (-1); - } - return (config_getserver_config(env, srv, imsg)); - } - /* Check if server with matching listening socket already exists */ if ((srv = server_byaddr((struct sockaddr *) &srv_conf.ss, srv_conf.port)) != NULL) { /* Add "host" to existing listening server */ - close(imsg->fd); + if (imsg->fd != -1) + close(imsg->fd); return (config_getserver_config(env, srv, imsg)); } + if (srv_conf.flags & SRVFLAG_LOCATION) + fatalx("invalid location"); + /* Otherwise create a new server */ if ((srv = calloc(1, sizeof(*srv))) == NULL) { close(imsg->fd); diff --git a/usr.sbin/httpd/httpd.h b/usr.sbin/httpd/httpd.h index c15313243e4..7fa00efc9f4 100644 --- a/usr.sbin/httpd/httpd.h +++ b/usr.sbin/httpd/httpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: httpd.h,v 1.18 2014/07/30 10:05:14 reyk Exp $ */ +/* $OpenBSD: httpd.h,v 1.19 2014/07/30 13:49:48 reyk Exp $ */ /* * Copyright (c) 2006 - 2014 Reyk Floeter @@ -402,8 +402,6 @@ int server_bufferevent_write(struct client *, void *, size_t); void server_inflight_dec(struct client *, const char *); struct server * server_byaddr(struct sockaddr *, in_port_t); -struct server * - server_byname(const char *); SPLAY_PROTOTYPE(client_tree, client, clt_nodes, server_client_cmp); diff --git a/usr.sbin/httpd/parse.y b/usr.sbin/httpd/parse.y index 4844272b86e..3947f710cd5 100644 --- a/usr.sbin/httpd/parse.y +++ b/usr.sbin/httpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.9 2014/07/30 10:05:14 reyk Exp $ */ +/* $OpenBSD: parse.y,v 1.10 2014/07/30 13:49:48 reyk Exp $ */ /* * Copyright (c) 2007 - 2014 Reyk Floeter @@ -233,6 +233,11 @@ server : SERVER STRING { SPLAY_INIT(&srv->srv_clients); TAILQ_INSERT_TAIL(conf->sc_servers, srv, srv_entry); } '{' optnl serveropts_l '}' { + if (srv->srv_conf.ss.ss_family == AF_UNSPEC) { + yyerror("listen address not specified"); + free($2); + YYERROR; + } srv = NULL; } ; @@ -294,6 +299,12 @@ serveroptsl : LISTEN ON STRING port { | LOCATION STRING { struct server *s; + if (srv->srv_conf.ss.ss_family == AF_UNSPEC) { + yyerror("listen address not specified"); + free($2); + YYERROR; + } + if (parentsrv != NULL) { yyerror("location %s inside location", $2); free($2); @@ -337,8 +348,13 @@ serveroptsl : LISTEN ON STRING port { YYERROR; } - s->srv_conf.id = ++last_server_id; + /* A location entry uses the parent id */ + s->srv_conf.id = srv->srv_conf.id; s->srv_conf.flags = SRVFLAG_LOCATION; + memcpy(&s->srv_conf.ss, &srv->srv_conf.ss, + sizeof(s->srv_conf.ss)); + s->srv_conf.port = srv->srv_conf.port; + s->srv_conf.prefixlen = srv->srv_conf.prefixlen; if (last_server_id == INT_MAX) { yyerror("too many servers/locations defined"); diff --git a/usr.sbin/httpd/server.c b/usr.sbin/httpd/server.c index 2b230111cd7..4c2645d7833 100644 --- a/usr.sbin/httpd/server.c +++ b/usr.sbin/httpd/server.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server.c,v 1.16 2014/07/30 10:05:14 reyk Exp $ */ +/* $OpenBSD: server.c,v 1.17 2014/07/30 13:49:48 reyk Exp $ */ /* * Copyright (c) 2006 - 2014 Reyk Floeter @@ -199,19 +199,6 @@ server_byaddr(struct sockaddr *addr, in_port_t port) return (NULL); } -struct server * -server_byname(const char *name) -{ - struct server *srv; - - TAILQ_FOREACH(srv, env->sc_servers, srv_entry) { - if (strcmp(srv->srv_conf.name, name) == 0) - return (srv); - } - - return (NULL); -} - int server_socket_af(struct sockaddr_storage *ss, in_port_t port) { diff --git a/usr.sbin/httpd/server_http.c b/usr.sbin/httpd/server_http.c index 05e8bf5d755..8e4de311747 100644 --- a/usr.sbin/httpd/server_http.c +++ b/usr.sbin/httpd/server_http.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server_http.c,v 1.20 2014/07/30 10:05:14 reyk Exp $ */ +/* $OpenBSD: server_http.c,v 1.21 2014/07/30 13:49:48 reyk Exp $ */ /* * Copyright (c) 2006 - 2014 Reyk Floeter @@ -671,7 +671,7 @@ server_response(struct httpd *httpd, struct client *clt) char path[MAXPATHLEN]; struct http_descriptor *desc = clt->clt_desc; struct server *srv = clt->clt_srv; - struct server_config *srv_conf = &srv->srv_conf; + struct server_config *srv_conf = &srv->srv_conf, *location; struct kv *kv, key, *host; int ret; @@ -717,11 +717,9 @@ server_response(struct httpd *httpd, struct client *clt) if (host != NULL) { /* XXX maybe better to turn srv_hosts into a tree */ TAILQ_FOREACH(srv_conf, &srv->srv_hosts, entry) { - if (((srv_conf->flags & SRVFLAG_LOCATION) && - fnmatch(srv_conf->location, - desc->http_path, FNM_CASEFOLD) == 0) || - (fnmatch(srv_conf->name, host->kv_value, - FNM_CASEFOLD) == 0)) { + if ((srv_conf->flags & SRVFLAG_LOCATION) == 0 && + fnmatch(srv_conf->name, host->kv_value, + FNM_CASEFOLD) == 0) { /* Replace host configuration */ clt->clt_srv_conf = srv_conf; srv_conf = NULL; @@ -740,6 +738,20 @@ server_response(struct httpd *httpd, struct client *clt) if (strlcpy(desc->http_host, host->kv_value, sizeof(desc->http_host)) >= sizeof(desc->http_host)) goto fail; + srv_conf = clt->clt_srv_conf; + } + + /* Now search for the location */ + TAILQ_FOREACH(location, &srv->srv_hosts, entry) { + if ((location->flags & SRVFLAG_LOCATION) && + location->id == srv_conf->id && + fnmatch(location->location, desc->http_path, + FNM_CASEFOLD) == 0) { + /* Replace host configuration */ + clt->clt_srv_conf = location; + srv_conf = NULL; + break; + } } if ((ret = server_file(httpd, clt)) == -1) -- 2.20.1