-# $OpenBSD: httpd.conf,v 1.3 2014/07/29 16:17:28 reyk Exp $
+# $OpenBSD: httpd.conf,v 1.4 2014/07/30 10:05:14 reyk Exp $
# Macros
ext_addr="egress"
# Servers
server "default" {
listen on $ext_addr port 80
+ location "/pub/*" {
+ directory auto index
+ }
}
# A name-based "virtual" server on the same address
-/* $OpenBSD: config.c,v 1.5 2014/07/25 23:30:58 reyk Exp $ */
+/* $OpenBSD: config.c,v 1.6 2014/07/30 10:05:14 reyk Exp $ */
/*
* Copyright (c) 2011 - 2014 Reyk Floeter <reyk@openbsd.org>
iov[c].iov_base = &s;
iov[c++].iov_len = sizeof(s);
- if (id == PROC_SERVER) {
+ if (id == PROC_SERVER &&
+ (srv->srv_conf.flags & SRVFLAG_LOCATION) == 0) {
/* XXX imsg code will close the fd after 1st call */
n = -1;
proc_range(ps, id, &n, &m);
#endif
struct server_config *srv_conf;
u_int8_t *p = imsg->data;
+ u_int f;
if ((srv_conf = calloc(1, sizeof(*srv_conf))) == NULL)
return (-1);
IMSG_SIZE_CHECK(imsg, srv_conf);
memcpy(srv_conf, p, sizeof(*srv_conf));
- TAILQ_INSERT_TAIL(&srv->srv_hosts, srv_conf, entry);
+ if (srv_conf->flags & SRVFLAG_LOCATION) {
+ /* Inherit configuration from the parent */
+ f = SRVFLAG_INDEX|SRVFLAG_NO_INDEX;
+ if ((srv_conf->flags & f) == 0) {
+ srv_conf->flags |= srv->srv_conf.flags & f;
+ (void)strlcpy(srv_conf->index, srv->srv_conf.index,
+ sizeof(srv_conf->index));
+ }
+
+ f = SRVFLAG_AUTO_INDEX|SRVFLAG_NO_AUTO_INDEX;
+ if ((srv_conf->flags & f) == 0)
+ srv_conf->flags |= srv->srv_conf.flags & f;
+
+ f = SRVFLAG_DOCROOT;
+ if ((srv_conf->flags & f) == 0) {
+ (void)strlcpy(srv_conf->docroot,
+ srv->srv_conf.docroot,
+ sizeof(srv_conf->docroot));
+ }
+
+ DPRINTF("%s: %s %d received location \"%s\", parent \"%s\"",
+ __func__, ps->ps_title[privsep_process], ps->ps_instance,
+ srv_conf->location, srv->srv_conf.name);
+ } else {
+ /* Add a new "virtual" server */
+ DPRINTF("%s: %s %d received server \"%s\", parent \"%s\"",
+ __func__, ps->ps_title[privsep_process], ps->ps_instance,
+ srv_conf->name, srv->srv_conf.name);
+ }
- DPRINTF("%s: %s %d received configuration \"%s\", parent \"%s\"",
- __func__, ps->ps_title[privsep_process], ps->ps_instance,
- srv_conf->name, srv->srv_conf.name);
+ TAILQ_INSERT_TAIL(&srv->srv_hosts, srv_conf, entry);
return (0);
}
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) {
-.\" $OpenBSD: httpd.conf.5,v 1.9 2014/07/30 09:51:40 reyk Exp $
+.\" $OpenBSD: httpd.conf.5,v 1.10 2014/07/30 10:05:14 reyk Exp $
.\"
.\" Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org>
.\"
will neither display nor generate a directory index.
.It Ic listen on Ar address Ic port Ar number
Set the listen address and port.
+.It Ic location Ar path { ... }
+Specify server configuration rules for a specific location.
+The
+.Ar path
+argument will be matched against the URL path with shell globbing rules.
+A location section may include all of the server configuration rules
+except
+.Ic listen on
+and
+.Ic location .
.It Ic root Ar directory
Set the document root of the server.
The
-/* $OpenBSD: httpd.h,v 1.17 2014/07/29 16:17:28 reyk Exp $ */
+/* $OpenBSD: httpd.h,v 1.18 2014/07/30 10:05:14 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
#define SRVFLAG_NO_INDEX 0x02
#define SRVFLAG_AUTO_INDEX 0x04
#define SRVFLAG_NO_AUTO_INDEX 0x08
+#define SRVFLAG_DOCROOT 0x10
+#define SRVFLAG_LOCATION 0x20
#define SRVFLAG_BITS \
- "\10\01INDEX\02NO_INDEX\03AUTO_INDEX\04NO_AUTO_INDEX"
+ "\10\01INDEX\02NO_INDEX\03AUTO_INDEX\04NO_AUTO_INDEX\05LOCATION"
#define TCPFLAG_NODELAY 0x01
#define TCPFLAG_NNODELAY 0x02
char name[MAXHOSTNAMELEN];
char docroot[MAXPATHLEN];
char index[NAME_MAX];
+ char location[NAME_MAX];
in_port_t port;
struct sockaddr_storage ss;
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);
-/* $OpenBSD: parse.y,v 1.8 2014/07/29 16:17:28 reyk Exp $ */
+/* $OpenBSD: parse.y,v 1.9 2014/07/30 10:05:14 reyk Exp $ */
/*
* Copyright (c) 2007 - 2014 Reyk Floeter <reyk@openbsd.org>
static int loadcfg = 0;
uint32_t last_server_id = 0;
-static struct server *srv = NULL;
+static struct server *srv = NULL, *parentsrv = NULL;
struct serverlist servers;
struct media_type media;
%}
-%token ALL AUTO DIRECTORY INDEX LISTEN LOG NO ON PORT PREFORK ROOT SERVER
-%token TYPES UPDATES VERBOSE
+%token ALL AUTO DIRECTORY INDEX LISTEN LOCATION LOG NO ON PORT PREFORK ROOT
+%token SERVER TYPES UPDATES VERBOSE
%token ERROR INCLUDE
%token <v.string> STRING
%token <v.number> NUMBER
YYERROR;
}
srv = s;
- } '{' optnl serveropts_l '}' {
+
SPLAY_INIT(&srv->srv_clients);
TAILQ_INSERT_TAIL(conf->sc_servers, srv, srv_entry);
+ } '{' optnl serveropts_l '}' {
+ srv = NULL;
}
;
struct address *h;
struct server *s;
+ if (parentsrv != NULL) {
+ yyerror("listen %s inside location", $3);
+ free($3);
+ YYERROR;
+ }
+
if (srv->srv_conf.ss.ss_family != AF_UNSPEC) {
yyerror("listen address already specified");
free($3);
YYERROR;
}
free($2);
+ srv->srv_conf.flags |= SRVFLAG_DOCROOT;
}
| DIRECTORY dirflags
| DIRECTORY '{' dirflags_l '}'
+ | LOCATION STRING {
+ struct server *s;
+
+ if (parentsrv != NULL) {
+ yyerror("location %s inside location", $2);
+ free($2);
+ YYERROR;
+ }
+
+ if (!loadcfg) {
+ free($2);
+ YYACCEPT;
+ }
+
+ TAILQ_FOREACH(s, conf->sc_servers, srv_entry)
+ if (strcmp(s->srv_conf.name,
+ srv->srv_conf.name) == 0 &&
+ strcmp(s->srv_conf.location, $2) == 0)
+ break;
+ if (s != NULL) {
+ yyerror("location %s defined twice", $2);
+ free($2);
+ YYERROR;
+ }
+
+ if ((s = calloc(1, sizeof (*s))) == NULL)
+ fatal("out of memory");
+
+ if (strlcpy(s->srv_conf.location, $2,
+ sizeof(s->srv_conf.location)) >=
+ sizeof(s->srv_conf.location)) {
+ yyerror("server location truncated");
+ free($2);
+ free(s);
+ YYERROR;
+ }
+ free($2);
+
+ if (strlcpy(s->srv_conf.name, srv->srv_conf.name,
+ sizeof(s->srv_conf.name)) >=
+ sizeof(s->srv_conf.name)) {
+ yyerror("server name truncated");
+ free(s);
+ YYERROR;
+ }
+
+ s->srv_conf.id = ++last_server_id;
+ s->srv_conf.flags = SRVFLAG_LOCATION;
+
+ if (last_server_id == INT_MAX) {
+ yyerror("too many servers/locations defined");
+ free(s);
+ YYERROR;
+ }
+ parentsrv = srv;
+ srv = s;
+ SPLAY_INIT(&srv->srv_clients);
+ TAILQ_INSERT_TAIL(conf->sc_servers, srv, srv_entry);
+ } '{' optnl serveropts_l '}' {
+ srv = parentsrv;
+ parentsrv = NULL;
+ }
;
dirflags_l : dirflags comma dirflags_l
{ "include", INCLUDE },
{ "index", INDEX },
{ "listen", LISTEN },
+ { "location", LOCATION },
{ "log", LOG },
{ "no", NO },
{ "on", ON },
-/* $OpenBSD: server.c,v 1.15 2014/07/29 16:38:34 reyk Exp $ */
+/* $OpenBSD: server.c,v 1.16 2014/07/30 10:05:14 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
int
server_privinit(struct server *srv)
{
+ if (srv->srv_conf.flags & SRVFLAG_LOCATION)
+ return (0);
+
log_debug("%s: adding server %s", __func__, srv->srv_conf.name);
if ((srv->srv_s = server_socket_listen(&srv->srv_conf.ss,
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)
{
-/* $OpenBSD: server_http.c,v 1.19 2014/07/25 23:25:38 reyk Exp $ */
+/* $OpenBSD: server_http.c,v 1.20 2014/07/30 10:05:14 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
void
server_abort_http(struct client *clt, u_int code, const char *msg)
{
- struct server_config *srv_conf = clt->clt_srv_conf;
+ struct server *srv = clt->clt_srv;
+ struct server_config *srv_conf = &srv->srv_conf;
struct bufferevent *bev = clt->clt_bev;
const char *httperr = NULL, *text = "";
char *httpmsg, *extraheader = NULL;
if (host != NULL) {
/* XXX maybe better to turn srv_hosts into a tree */
TAILQ_FOREACH(srv_conf, &srv->srv_hosts, entry) {
- if (fnmatch(srv_conf->name, host->kv_value,
- FNM_CASEFOLD) == 0) {
+ 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)) {
/* Replace host configuration */
clt->clt_srv_conf = srv_conf;
srv_conf = NULL;