Make "location" work with name-based virtual servers.
authorreyk <reyk@openbsd.org>
Wed, 30 Jul 2014 13:49:48 +0000 (13:49 +0000)
committerreyk <reyk@openbsd.org>
Wed, 30 Jul 2014 13:49:48 +0000 (13:49 +0000)
usr.sbin/httpd/config.c
usr.sbin/httpd/httpd.h
usr.sbin/httpd/parse.y
usr.sbin/httpd/server.c
usr.sbin/httpd/server_http.c

index 9e9d2c3..44cd419 100644 (file)
@@ -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 <reyk@openbsd.org>
@@ -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);
index c153132..7fa00ef 100644 (file)
@@ -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 <reyk@openbsd.org>
@@ -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);
 
index 4844272..3947f71 100644 (file)
@@ -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 <reyk@openbsd.org>
@@ -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");
index 2b23011..4c2645d 100644 (file)
@@ -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 <reyk@openbsd.org>
@@ -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)
 {
index 05e8bf5..8e4de31 100644 (file)
@@ -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 <reyk@openbsd.org>
@@ -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)