diff --git a/config.c b/config.c index 0eac060..3b84aa4 100644 --- a/config.c +++ b/config.c @@ -97,11 +97,11 @@ config_purge(struct conf *conf) free(l->reqca_path); X509_STORE_free(l->reqca); free(l); - } - TAILQ_FOREACH_SAFE(e, &h->params, envs, te) { - TAILQ_REMOVE(&h->params, e, envs); - free(e); + TAILQ_FOREACH_SAFE(e, &l->params, envs, te) { + TAILQ_REMOVE(&l->params, e, envs); + free(e); + } } TAILQ_FOREACH_SAFE(a, &h->aliases, aliases, ta) { @@ -363,12 +363,12 @@ config_send(struct conf *conf) if (config_send_file(ps, PROC_SERVER, IMSG_RECONF_LOC, fd, &lcopy, sizeof(lcopy)) == -1) return -1; - } - TAILQ_FOREACH(e, &h->params, envs) { - if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_ENV, - e, sizeof(*e)) == -1) - return -1; + TAILQ_FOREACH(e, &l->params, envs) { + if (proc_compose(ps, PROC_SERVER, + IMSG_RECONF_ENV, e, sizeof(*e)) == -1) + return -1; + } } if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1) @@ -501,6 +501,7 @@ int config_recv(struct conf *conf, struct imsg *imsg) { static struct vhost *h; + static struct location *l; static struct proxy *p; struct privsep *ps = conf->ps; struct etm m; @@ -570,7 +571,8 @@ config_recv(struct conf *conf, struct imsg *imsg) h = vh; TAILQ_INSERT_TAIL(&conf->hosts, h, vhosts); - /* reset proxy */ + /* reset location and proxy */ + l = NULL; p = NULL; break; @@ -633,6 +635,7 @@ config_recv(struct conf *conf, struct imsg *imsg) IMSG_SIZE_CHECK(imsg, loc); loc = xcalloc(1, sizeof(*loc)); memcpy(loc, imsg->data, datalen); + TAILQ_INIT(&loc->params); if (imsg->fd != -1) { if (load_file(imsg->fd, &d, &len) == -1) @@ -643,16 +646,17 @@ config_recv(struct conf *conf, struct imsg *imsg) free(d); } + l = loc; TAILQ_INSERT_TAIL(&h->locations, loc, locations); break; case IMSG_RECONF_ENV: - if (h == NULL) - fatalx("recv'd env without host"); + if (l == NULL) + fatalx("recv'd env without location"); IMSG_SIZE_CHECK(imsg, env); env = xcalloc(1, sizeof(*env)); memcpy(env, imsg->data, datalen); - TAILQ_INSERT_TAIL(&h->params, env, envs); + TAILQ_INSERT_TAIL(&l->params, env, envs); break; case IMSG_RECONF_ALIAS: diff --git a/fcgi.c b/fcgi.c index 7a141a5..281dfaa 100644 --- a/fcgi.c +++ b/fcgi.c @@ -371,7 +371,7 @@ fcgi_error(struct bufferevent *bev, short err, void *d) } void -fcgi_req(struct client *c) +fcgi_req(struct client *c, struct location *loc) { char buf[22]; char *qs; @@ -398,7 +398,7 @@ fcgi_req(struct client *c) free(qs); } - TAILQ_FOREACH(p, &c->host->params, envs) { + TAILQ_FOREACH(p, &loc->params, envs) { fcgi_send_param(c->cgibev, p->name, p->value); } diff --git a/gmid.conf.5 b/gmid.conf.5 index 07e58e0..8e81498 100644 --- a/gmid.conf.5 +++ b/gmid.conf.5 @@ -212,10 +212,17 @@ If not specified, the .Ic default type is set to .Dq application/octet-stream . -.It Ic fastcgi Oo Ic tcp Oc Ar socket Oo Cm port Ar port Oc -Enable -.Sx FastCGI -instead of serving files. +.It Ic fastcgi Ar option +Enable FastCGI instead of serving files. +Multiple options may be specified within curly braces. +Valid options are: +.Bl -tag -width Ds +.It Ic param Ar name Cm = Ar value +Set the param +.Ar name +to +.Ar value . +.It Ic socket Oo Ic tcp Oc Ar socket Oo Cm port Ar port Oc The .Ar socket can either be a UNIX-domain socket or a TCP socket. @@ -234,64 +241,9 @@ is interpreted as a hostname or an IP address. can be either a port number or the name of a service enclosed in double quotes. If not specified defaults to 9000. -.It Ic index Ar string -Set the directory index file. -If not specified, it defaults to -.Pa index.gmi . -.It Ic key Ar file -Specify the private key to use for this server. -.Ar file -should contain a PEM encoded private key. -This option is mandatory. -.It Ic lang Ar string -Specify the language tag for the text/gemini content served. -If not specified, no -.Dq lang -parameter will be added in the response. -.It Ic listen on Ar address Op Ic port Ar number -Set the listen -.Ar address -and -.Ar port -which defaults to -.Sq 1965 . -This statement can be specified multiple times. -If -.Ar address -is -.Sq * -then -.Xr gmid 8 -will listen on all IPv4 and IPv6 addresses. -.Ar 0.0.0.0 -can be used to listen on all IPv4 addresses and -.Ar :: -on all IPv6 addresses. -.It Ic location Ar path Brq ... -Specify server configuration rules for a specific location. -.Ar path -argument will be matched against the request path with shell globbing -rules. -In case of multiple location statements in the same context, the first -matching location will be put into effect and the later ones ignored. -Therefore is advisable to match for more specific paths first and for -generic ones later on. -A -.Ic location -section may include most of the server configuration rules -except -.Ic alias , Ic cert , Ic key , Ic listen , Ic location , Ic param -and -.Ic proxy . -.It Ic log Ar bool -Enable or disable the logging for the current server or location block. -.It Ic param Ar name Cm = Ar value -Set the param -.Ar name -to -.Ar value -for FastCGI. -By default the following parameters are defined: +.El +.Pp +The FastCGI handler will be given the following variables by default: .Bl -tag -width 24m .It Ev GATEWAY_INTERFACE .Dq CGI/1.1 @@ -368,6 +320,57 @@ certificate in the ISO 8601 format The time corresponding to the start of the validity period of the peer certificate in the ISO 8601 format. .El +.It Ic index Ar string +Set the directory index file. +If not specified, it defaults to +.Pa index.gmi . +.It Ic key Ar file +Specify the private key to use for this server. +.Ar file +should contain a PEM encoded private key. +This option is mandatory. +.It Ic lang Ar string +Specify the language tag for the text/gemini content served. +If not specified, no +.Dq lang +parameter will be added in the response. +.It Ic listen on Ar address Op Ic port Ar number +Set the listen +.Ar address +and +.Ar port +which defaults to +.Sq 1965 . +This statement can be specified multiple times. +If +.Ar address +is +.Sq * +then +.Xr gmid 8 +will listen on all IPv4 and IPv6 addresses. +.Ar 0.0.0.0 +can be used to listen on all IPv4 addresses and +.Ar :: +on all IPv6 addresses. +.It Ic location Ar path Brq ... +Specify server configuration rules for a specific location. +.Ar path +argument will be matched against the request path with shell globbing +rules. +In case of multiple location statements in the same context, the first +matching location will be put into effect and the later ones ignored. +Therefore is advisable to match for more specific paths first and for +generic ones later on. +A +.Ic location +section may include most of the server configuration rules +except +.Ic alias , Ic cert , Ic key , Ic listen , Ic location +and +.Ic proxy . +.It Ic log Ar bool +Enable or disable the logging for the current server or location block. .It Ic ocsp Ar file Specify an OCSP response to be stapled during TLS handshakes with this server. diff --git a/gmid.h b/gmid.h index c1fd62c..337fb0c 100644 --- a/gmid.h +++ b/gmid.h @@ -175,6 +175,7 @@ struct location { X509_STORE *reqca; int disable_log; int fcgi; + struct envhead params; char dir[PATH_MAX]; int dirfd; @@ -209,7 +210,6 @@ struct vhost { */ struct lochead locations; - struct envhead params; struct aliashead aliases; struct proxyhead proxies; }; @@ -389,7 +389,7 @@ const char *vhost_default_mime(struct vhost*, const char*); const char *vhost_index(struct vhost*, const char*); int vhost_auto_index(struct vhost*, const char*); int vhost_block_return(struct vhost*, const char*, int*, const char**); -int vhost_fastcgi(struct vhost*, const char*); +struct location *vhost_fastcgi(struct vhost*, const char*); int vhost_dirfd(struct vhost*, const char*, size_t*); int vhost_strip(struct vhost*, const char*); X509_STORE *vhost_require_ca(struct vhost*, const char*); @@ -418,7 +418,7 @@ int select_non_dotdot(const struct dirent*); void fcgi_read(struct bufferevent *, void *); void fcgi_write(struct bufferevent *, void *); void fcgi_error(struct bufferevent *, short, void *); -void fcgi_req(struct client *); +void fcgi_req(struct client *, struct location *); /* sandbox.c */ void sandbox_main_process(void); diff --git a/parse.y b/parse.y index 5a72bf4..2dcb4bc 100644 --- a/parse.y +++ b/parse.y @@ -133,7 +133,7 @@ typedef struct { %token OCSP OFF ON %token PARAM PORT PREFORK PROTO PROTOCOLS PROXY %token RELAY_TO REQUIRE RETURN ROOT -%token SERVER SNI STRIP +%token SERVER SNI SOCKET STRIP %token TCP TOEXT TYPE TYPES %token USE_TLS USER %token VERIFYNAME @@ -326,6 +326,8 @@ servopt : ALIAS string { host->ocsp_path = $2; } | PARAM string '=' string { + yywarn("the top-level `param' directive is deprecated." + " Please use `fastcgi { param ... }`"); add_param($2, $4); } | LISTEN ON listen_addr { @@ -465,7 +467,7 @@ locopt : AUTO INDEX bool { loc->auto_index = $3 ? 1 : -1; } sizeof(loc->default_mime)); free($3); } - | FASTCGI fastcgi + | fastcgi | INDEX string { (void) strlcpy(loc->index, $2, sizeof(loc->index)); free($2); @@ -487,26 +489,44 @@ locopt : AUTO INDEX bool { loc->auto_index = $3 ? 1 : -1; } | STRIP NUM { loc->strip = check_strip_no($2); } ; -fastcgi : string { - loc->fcgi = fastcgi_conf($1, NULL); - free($1); - } - | TCP string PORT NUM { - char *c; - if (asprintf(&c, "%d", $4) == -1) - fatal("asprintf"); - loc->fcgi = fastcgi_conf($2, c); +fastcgi : FASTCGI '{' optnl fastcgiopts '}' + | FASTCGI fastcgiopt + | FASTCGI string { + yywarn("`fastcgi path' is deprecated. " + "Please use `fastcgi socket path' instead."); + loc->fcgi = fastcgi_conf($2, NULL); free($2); + } + | error '}' + ; + +fastcgiopts : /* empty */ + | fastcgiopts fastcgiopt optnl + ; + +fastcgiopt : PARAM string '=' string { + add_param($2, $4); + } + | SOCKET string { + loc->fcgi = fastcgi_conf($2, NULL); + free($2); + } + | SOCKET TCP string PORT NUM { + char *c; + + if (asprintf(&c, "%d", $5) == -1) + fatal("asprintf"); + loc->fcgi = fastcgi_conf($3, c); + free($3); free(c); } - | TCP string { - loc->fcgi = fastcgi_conf($2, "9000"); - free($2); + | SOCKET TCP string { + loc->fcgi = fastcgi_conf($3, "9000"); } - | TCP string PORT string { - loc->fcgi = fastcgi_conf($2, $4); - free($2); - free($4); + | SOCKET TCP string PORT string { + loc->fcgi = fastcgi_conf($3, $5); + free($3); + free($5); } ; @@ -586,6 +606,7 @@ static const struct keyword { {"root", ROOT}, {"server", SERVER}, {"sni", SNI}, + {"socket", SOCKET}, {"strip", STRIP}, {"tcp", TCP}, {"to-ext", TOEXT}, @@ -1183,7 +1204,7 @@ void add_param(char *name, char *val) { struct envlist *e; - struct envhead *h = &host->params; + struct envhead *h = &loc->params; e = xcalloc(1, sizeof(*e)); (void) strlcpy(e->name, name, sizeof(e->name)); diff --git a/server.c b/server.c index 8559b99..88479f1 100644 --- a/server.c +++ b/server.c @@ -243,23 +243,23 @@ vhost_block_return(struct vhost *v, const char *path, int *code, const char **fm return loc->block_code != 0; } -int +struct location * vhost_fastcgi(struct vhost *v, const char *path) { struct location *loc; if (v == NULL || path == NULL) - return -1; + return NULL; loc = TAILQ_FIRST(&v->locations); while ((loc = TAILQ_NEXT(loc, locations)) != NULL) { if (loc->fcgi != -1) if (matches(loc->match, path)) - return loc->fcgi; + return loc; } loc = TAILQ_FIRST(&v->locations); - return loc->fcgi; + return loc->fcgi == -1 ? NULL : loc; } int @@ -705,20 +705,21 @@ fcgi_open_conn(struct fcgi *f) static int apply_fastcgi(struct client *c) { - int id, i = 0; + int i = 0; struct fcgi *f; + struct location *loc; - if ((id = vhost_fastcgi(c->host, c->iri.path)) == -1) + if ((loc = vhost_fastcgi(c->host, c->iri.path)) == NULL) return 0; TAILQ_FOREACH(f, &c->conf->fcgi, fcgi) { - if (i == id) + if (i == loc->fcgi) break; ++i; } if (f == NULL) { - log_warnx("can't find fcgi #%d", id); + log_warnx("can't find fcgi #%d", loc->fcgi); return 0; } @@ -745,7 +746,7 @@ apply_fastcgi(struct client *c) } bufferevent_enable(c->cgibev, EV_READ|EV_WRITE); - fcgi_req(c); + fcgi_req(c, loc); return 1; } diff --git a/utils.c b/utils.c index a020b9f..2a9d4a4 100644 --- a/utils.c +++ b/utils.c @@ -348,7 +348,6 @@ new_vhost(void) h = xcalloc(1, sizeof(*h)); TAILQ_INIT(&h->addrs); TAILQ_INIT(&h->locations); - TAILQ_INIT(&h->params); TAILQ_INIT(&h->aliases); TAILQ_INIT(&h->proxies); return h; @@ -362,6 +361,7 @@ new_location(void) l = xcalloc(1, sizeof(*l)); l->dirfd = -1; l->fcgi = -1; + TAILQ_INIT(&l->params); return l; }