aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReyk Floeter <reyk@esdenera.com>2015-01-03 14:45:56 +0100
committerReyk Floeter <reyk@esdenera.com>2015-01-03 14:45:56 +0100
commit311a75186cb09ce91bbb34f71ddbf282b420fd21 (patch)
treeab31ebfcf4f34f3aaa671f953e9134a27d6035e0
parentae6f0669f0feb84e338ca3ae62f1fedbd4169b42 (diff)
downloadhttpd-311a75186cb09ce91bbb34f71ddbf282b420fd21.tar.gz
httpd-311a75186cb09ce91bbb34f71ddbf282b420fd21.zip
Add support for aliases and multiple listen statements (pending diff)
-rw-r--r--TODO.md4
-rw-r--r--config.c4
-rw-r--r--httpd.conf.512
-rw-r--r--parse.y196
4 files changed, 200 insertions, 16 deletions
diff --git a/TODO.md b/TODO.md
index 6af9bb5..59f3e4f 100644
--- a/TODO.md
+++ b/TODO.md
@@ -30,8 +30,8 @@ is to set a non-accessible root:
root "/forbidden"
}
-#20150102-04 server aliases **OPEN**
-------------------------------------
+#20150102-04 server aliases **PENDING**
+---------------------------------------
Server aliases and a few restrictions of the grammar: Individual
server blocks can currently only have one name and listen statement.
diff --git a/config.c b/config.c
index d651a02..4969350 100644
--- a/config.c
+++ b/config.c
@@ -174,7 +174,9 @@ config_setserver(struct httpd *env, struct server *srv)
if ((what & CONFIG_SERVERS) == 0 || id == privsep_process)
continue;
- DPRINTF("%s: sending server \"%s[%u]\" to %s fd %d", __func__,
+ DPRINTF("%s: sending %s \"%s[%u]\" to %s fd %d", __func__,
+ (srv->srv_conf.flags & SRVFLAG_LOCATION) ?
+ "location" : "server",
srv->srv_conf.name, srv->srv_conf.id,
ps->ps_title[id], srv->srv_s);
diff --git a/httpd.conf.5 b/httpd.conf.5
index 222b3dc..275f48b 100644
--- a/httpd.conf.5
+++ b/httpd.conf.5
@@ -135,6 +135,10 @@ must have a
.Ar name
and include one or more lines of the following syntax:
.Bl -tag -width Ds
+.It Ic alias Ar name
+Specify an additional alias
+.Ar name
+for this server.
.It Ic connection Ar option
Set the specified options and limits for HTTP connections.
Valid options are:
@@ -180,6 +184,7 @@ and defaults to
.Pa /run/slowcgi.sock .
.It Ic listen on Ar address Oo Ic tls Oc Ic port Ar number
Set the listen address and port.
+This statement can be specified multiple times.
.It Ic location Ar path Brq ...
Specify server configuration rules for a specific location.
The
@@ -391,6 +396,13 @@ If the same address is repeated multiple times in the
statement,
the server will be matched based on the requested host name.
.Bd -literal -offset indent
+server "www.example.com" {
+ alias "example.com"
+ listen on * port 80
+ listen on * tls port 443
+ root "/htdocs/www.example.com"
+}
+
server "www.a.example.com" {
listen on 203.0.113.1 port 80
root "/htdocs/www.a.example.com"
diff --git a/parse.y b/parse.y
index 943e00a..089c35c 100644
--- a/parse.y
+++ b/parse.y
@@ -106,6 +106,8 @@ int host_if(const char *, struct addresslist *,
int host(const char *, struct addresslist *,
int, struct portrange *, const char *, int);
void host_free(struct addresslist *);
+struct server *server_inherit(struct server *, const char *,
+ struct server_config *);
int getservice(char *);
int is_if_in_group(const char *, const char *);
@@ -125,10 +127,10 @@ typedef struct {
%}
-%token ACCESS AUTO BACKLOG BODY BUFFER CERTIFICATE CHROOT CIPHERS COMMON
+%token ACCESS ALIAS AUTO BACKLOG BODY BUFFER CERTIFICATE CHROOT CIPHERS COMMON
%token COMBINED CONNECTION DIRECTORY ERR FCGI INDEX IP KEY LISTEN LOCATION
%token LOG LOGDIR MAXIMUM NO NODELAY ON PORT PREFORK REQUEST REQUESTS ROOT
-%token SACK SERVER SOCKET STYLE SYSLOG TCP TIMEOUT TLS TYPES
+%token SACK SERVER SOCKET STYLE SYSLOG TCP TIMEOUT TLS TYPES
%token ERROR INCLUDE
%token <v.string> STRING
%token <v.number> NUMBER
@@ -247,8 +249,14 @@ server : SERVER STRING {
srv_conf = &srv->srv_conf;
SPLAY_INIT(&srv->srv_clients);
+ TAILQ_INIT(&srv->srv_hosts);
+
+ TAILQ_INSERT_TAIL(&srv->srv_hosts, srv_conf, entry);
} '{' optnl serveropts_l '}' {
- struct server *s = NULL;
+ struct server *s = NULL, *sn;
+ struct server_config *a, *b;
+
+ srv_conf = &srv->srv_conf;
TAILQ_FOREACH(s, conf->sc_servers, srv_entry) {
if ((s->srv_conf.flags &
@@ -290,6 +298,44 @@ server : SERVER STRING {
TAILQ_INSERT_TAIL(conf->sc_servers, srv, srv_entry);
+ /*
+ * Add aliases and additional listen addresses as
+ * individual servers.
+ */
+ TAILQ_FOREACH(a, &srv->srv_hosts, entry) {
+ /* listen address */
+ if (a->ss.ss_family == AF_UNSPEC)
+ continue;
+ TAILQ_FOREACH(b, &srv->srv_hosts, entry) {
+ /* alias name */
+ if (*b->name == '\0' ||
+ (b == &srv->srv_conf && b == a))
+ continue;
+
+ if ((sn = server_inherit(srv,
+ b->name, a)) == NULL) {
+ serverconfig_free(srv_conf);
+ free(srv);
+ YYABORT;
+ }
+
+ DPRINTF("adding server \"%s[%u]\"",
+ sn->srv_conf.name, sn->srv_conf.id);
+
+ TAILQ_INSERT_TAIL(conf->sc_servers,
+ sn, srv_entry);
+ }
+ }
+
+ /* Remove temporary aliases */
+ TAILQ_FOREACH_SAFE(a, &srv->srv_hosts, entry, b) {
+ TAILQ_REMOVE(&srv->srv_hosts, a, entry);
+ if (a == &srv->srv_conf)
+ continue;
+ serverconfig_free(a);
+ free(a);
+ }
+
srv = NULL;
srv_conf = NULL;
}
@@ -302,7 +348,7 @@ serveropts_l : serveropts_l serveroptsl nl
serveroptsl : LISTEN ON STRING opttls port {
struct addresslist al;
struct address *h;
- struct server *s;
+ struct server_config *s_conf, *alias = NULL;
if (parentsrv != NULL) {
yyerror("listen %s inside location", $3);
@@ -311,11 +357,14 @@ serveroptsl : LISTEN ON STRING opttls port {
}
if (srv->srv_conf.ss.ss_family != AF_UNSPEC) {
- yyerror("listen address already specified");
- free($3);
- YYERROR;
+ if ((alias = calloc(1,
+ sizeof(*alias))) == NULL)
+ fatal("out of memory");
+
+ /* Add as an alias */
+ s_conf = alias;
} else
- s = srv;
+ s_conf = &srv->srv_conf;
if ($5.op != PF_OP_EQ) {
yyerror("invalid port");
free($3);
@@ -330,16 +379,43 @@ serveroptsl : LISTEN ON STRING opttls port {
}
free($3);
h = TAILQ_FIRST(&al);
- memcpy(&srv->srv_conf.ss, &h->ss,
- sizeof(s->srv_conf.ss));
- s->srv_conf.port = h->port.val[0];
- s->srv_conf.prefixlen = h->prefixlen;
+ memcpy(&s_conf->ss, &h->ss, sizeof(s_conf->ss));
+ s_conf->port = h->port.val[0];
+ s_conf->prefixlen = h->prefixlen;
host_free(&al);
if ($4) {
- s->srv_conf.flags |= SRVFLAG_TLS;
+ s_conf->flags |= SRVFLAG_TLS;
+ }
+
+ if (alias != NULL) {
+ TAILQ_INSERT_TAIL(&srv->srv_hosts,
+ alias, entry);
}
}
+ | ALIAS STRING {
+ struct server_config *alias;
+
+ if (parentsrv != NULL) {
+ yyerror("alias inside location");
+ free($2);
+ YYERROR;
+ }
+
+ if ((alias = calloc(1, sizeof(*alias))) == NULL)
+ fatal("out of memory");
+
+ if (strlcpy(alias->name, $2, sizeof(alias->name)) >=
+ sizeof(alias->name)) {
+ yyerror("server alias truncated");
+ free($2);
+ free(alias);
+ YYERROR;
+ }
+ free($2);
+
+ TAILQ_INSERT_TAIL(&srv->srv_hosts, alias, entry);
+ }
| TCP {
if (parentsrv != NULL) {
yyerror("tcp flags inside location");
@@ -852,6 +928,7 @@ lookup(char *s)
/* this has to be sorted always */
static const struct keywords keywords[] = {
{ "access", ACCESS },
+ { "alias", ALIAS },
{ "auto", AUTO },
{ "backlog", BACKLOG },
{ "body", BODY },
@@ -1646,6 +1723,99 @@ host_free(struct addresslist *al)
}
}
+struct server *
+server_inherit(struct server *src, const char *name,
+ struct server_config *addr)
+{
+ struct server *dst, *s, *dstl;
+
+ if ((dst = calloc(1, sizeof(*dst))) == NULL)
+ fatal("out of memory");
+
+ /* Copy the source server and assign a new Id */
+ memcpy(&dst->srv_conf, &src->srv_conf, sizeof(dst->srv_conf));
+ if ((dst->srv_conf.tls_cert_file =
+ strdup(src->srv_conf.tls_cert_file)) == NULL)
+ fatal("out of memory");
+ if ((dst->srv_conf.tls_key_file =
+ strdup(src->srv_conf.tls_key_file)) == NULL)
+ fatal("out of memory");
+
+ dst->srv_conf.id = ++last_server_id;
+ if (last_server_id == INT_MAX) {
+ yyerror("too many servers defined");
+ free(dst);
+ return (NULL);
+ }
+
+ /* Now set alias and listen address */
+ strlcpy(dst->srv_conf.name, name, sizeof(dst->srv_conf.name));
+ memcpy(&dst->srv_conf.ss, &addr->ss, sizeof(dst->srv_conf.ss));
+ dst->srv_conf.port = addr->port;
+ dst->srv_conf.prefixlen = addr->prefixlen;
+ if (addr->flags & SRVFLAG_TLS)
+ dst->srv_conf.flags |= SRVFLAG_TLS;
+ else
+ dst->srv_conf.flags &= ~SRVFLAG_TLS;
+
+ if (server_tls_load_keypair(dst) == -1) {
+ yyerror("failed to load public/private keys "
+ "for server %s", dst->srv_conf.name);
+ serverconfig_free(&dst->srv_conf);
+ free(dst);
+ return (NULL);
+ }
+
+ /* Check if the new server already exists */
+ TAILQ_FOREACH(s, conf->sc_servers, srv_entry) {
+ if ((s->srv_conf.flags &
+ SRVFLAG_LOCATION) == 0 &&
+ strcmp(s->srv_conf.name,
+ dst->srv_conf.name) == 0 &&
+ s->srv_conf.port == dst->srv_conf.port &&
+ sockaddr_cmp(
+ (struct sockaddr *)&s->srv_conf.ss,
+ (struct sockaddr *)&dst->srv_conf.ss,
+ s->srv_conf.prefixlen) == 0)
+ break;
+ }
+ if (s != NULL) {
+ yyerror("server \"%s\" defined twice",
+ dst->srv_conf.name);
+ serverconfig_free(&dst->srv_conf);
+ free(dst);
+ return (NULL);
+ }
+
+ /* Copy all the locations of the source server */
+ TAILQ_FOREACH(s, conf->sc_servers, srv_entry) {
+ if (!(s->srv_conf.flags & SRVFLAG_LOCATION &&
+ s->srv_conf.id == src->srv_conf.id))
+ continue;
+
+ if ((dstl = calloc(1, sizeof(*dstl))) == NULL)
+ fatal("out of memory");
+
+ memcpy(&dstl->srv_conf, &s->srv_conf, sizeof(dstl->srv_conf));
+ strlcpy(dstl->srv_conf.name, name, sizeof(dstl->srv_conf.name));
+
+ /* Copy the new Id and listen address */
+ dstl->srv_conf.id = dst->srv_conf.id;
+ memcpy(&dstl->srv_conf.ss, &addr->ss,
+ sizeof(dstl->srv_conf.ss));
+ dstl->srv_conf.port = addr->port;
+ dstl->srv_conf.prefixlen = addr->prefixlen;
+
+ DPRINTF("adding location \"%s\" for \"%s[%u]\"",
+ dstl->srv_conf.location,
+ dstl->srv_conf.name, dstl->srv_conf.id);
+
+ TAILQ_INSERT_TAIL(conf->sc_servers, dstl, srv_entry);
+ }
+
+ return (dst);
+}
+
int
getservice(char *n)
{