aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--README.md8
-rw-r--r--ex.c531
-rw-r--r--gmid.130
-rw-r--r--gmid.c125
-rw-r--r--gmid.h51
-rw-r--r--parse.y22
-rwxr-xr-xregress/regress7
-rw-r--r--regress/tests.sh89
-rw-r--r--sandbox.c2
-rw-r--r--server.c487
11 files changed, 186 insertions, 1167 deletions
diff --git a/Makefile b/Makefile
index 26e7b0c..60de30f 100644
--- a/Makefile
+++ b/Makefile
@@ -63,7 +63,6 @@ COMPATS = compat/err.c \
compat/vasprintf.c
GMID_SRCS = dirs.c \
- ex.c \
fcgi.c \
gmid.c \
iri.c \
diff --git a/README.md b/README.md
index 4263391..ca18f85 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@ featureful server.
- IRI support (RFC3987)
- automatic certificate generation for config-less mode
- reverse proxying
- - CGI and FastCGI support
+ - FastCGI support
- virtual hosts
- location rules
- event-based asynchronous I/O model
@@ -75,9 +75,6 @@ server "example.com" {
# lang for text/gemini files
lang "en"
- # execute CGI scripts in /cgi/
- cgi "/cgi/*"
-
# only for locations that matches /files/*
location "/files/*" {
# generate directory listings
@@ -141,6 +138,9 @@ to the `contrib` directory.
## Architecture/Security considerations
+**outdated: revisit for gmid 2.0**
+
+
gmid is composed by four processes: the parent process, the logger,
the listener and the executor. The parent process is the only one
that doesn't drop privileges, but all it does is to wait for a SIGHUP
diff --git a/ex.c b/ex.c
deleted file mode 100644
index fbda0b5..0000000
--- a/ex.c
+++ /dev/null
@@ -1,531 +0,0 @@
-/*
- * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "gmid.h"
-
-#include <sys/un.h>
-
-#include <err.h>
-#include <errno.h>
-
-#include <event.h>
-#include <fcntl.h>
-#include <libgen.h>
-#include <limits.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <string.h>
-
-static void handle_imsg_cgi_req(struct imsgbuf*, struct imsg*, size_t);
-static void handle_imsg_fcgi_req(struct imsgbuf*, struct imsg*, size_t);
-static void handle_imsg_conn_req(struct imsgbuf *, struct imsg *, size_t);
-static void handle_imsg_quit(struct imsgbuf*, struct imsg*, size_t);
-static void handle_dispatch_imsg(int, short, void*);
-
-static imsg_handlerfn *handlers[] = {
- [IMSG_FCGI_REQ] = handle_imsg_fcgi_req,
- [IMSG_CGI_REQ] = handle_imsg_cgi_req,
- [IMSG_CONN_REQ] = handle_imsg_conn_req,
- [IMSG_QUIT] = handle_imsg_quit,
-};
-
-static inline void
-safe_setenv(const char *name, const char *val)
-{
- if (val == NULL)
- val = "";
- setenv(name, val, 1);
-}
-
-static char *
-xasprintf(const char *fmt, ...)
-{
- va_list ap;
- char *s;
-
- va_start(ap, fmt);
- if (vasprintf(&s, fmt, ap) == -1)
- s = NULL;
- va_end(ap);
-
- return s;
-}
-
-static void
-do_exec(const char *ex, const char *spath, char *query)
-{
- char **argv, buf[PATH_MAX], *sname, *t;
- size_t i, n;
-
- /* restore the default handlers */
- signal(SIGPIPE, SIG_DFL);
- signal(SIGCHLD, SIG_DFL);
- signal(SIGHUP, SIG_DFL);
- signal(SIGINT, SIG_DFL);
- signal(SIGTERM, SIG_DFL);
-
- strlcpy(buf, spath, sizeof(buf));
- sname = basename(buf);
-
- if (query == NULL || strchr(query, '=') != NULL) {
- if ((argv = calloc(2, sizeof(char*))) == NULL)
- err(1, "calloc");
- argv[0] = sname;
- execvp(ex, argv);
- warn("execvp: %s", argv[0]);
- return;
- }
-
- n = 1;
- for (t = query ;; t++, n++) {
- if ((t = strchr(t, '+')) == NULL)
- break;
- }
-
- if ((argv = calloc(n+2, sizeof(char*))) == NULL)
- err(1, "calloc");
-
- argv[0] = sname;
- for (i = 0; i < n; ++i) {
- t = strchr(query, '+');
- if (t != NULL)
- *t = '\0';
- argv[i+1] = pct_decode_str(query);
- query = t+1;
- }
-
- execvp(ex, argv);
- warn("execvp: %s", argv[0]);
-}
-
-static inline void
-setenv_time(const char *var, time_t t)
-{
- char timebuf[21];
- struct tm tminfo;
-
- if (t == -1)
- return;
-
- strftime(timebuf, sizeof(timebuf), "%FT%TZ",
- gmtime_r(&t, &tminfo));
- setenv(var, timebuf, 1);
-}
-
-/* fd or -1 on error */
-static int
-launch_cgi(struct iri *iri, struct cgireq *req, struct vhost *vhost,
- struct location *loc)
-{
- int p[2], errp[2]; /* read end, write end */
-
- if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, p) == -1)
- return -1;
- if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, errp) == -1)
- return -1;
-
- switch (fork()) {
- case -1:
- log_err(NULL, "fork failed: %s", strerror(errno));
- close(p[0]);
- close(p[1]);
- close(errp[0]);
- close(errp[1]);
- return -1;
-
- case 0: { /* child */
- char *ex, *pwd;
- char iribuf[GEMINI_URL_LEN];
- char path[PATH_MAX];
- struct envlist *e;
-
- close(p[0]);
- if (dup2(p[1], 1) == -1)
- goto childerr;
-
- close(errp[0]);
- if (dup2(errp[1], 2) == -1)
- goto childerr;
-
- ex = xasprintf("%s/%s", loc->dir, req->spath);
-
- serialize_iri(iri, iribuf, sizeof(iribuf));
-
- safe_setenv("GATEWAY_INTERFACE", "CGI/1.1");
- safe_setenv("GEMINI_DOCUMENT_ROOT", loc->dir);
- safe_setenv("GEMINI_SCRIPT_FILENAME",
- xasprintf("%s/%s", loc->dir, req->spath));
- safe_setenv("GEMINI_URL", iribuf);
-
- strlcpy(path, "/", sizeof(path));
- strlcat(path, req->spath, sizeof(path));
- safe_setenv("GEMINI_URL_PATH", path);
-
- if (*req->relpath != '\0') {
- strlcpy(path, "/", sizeof(path));
- strlcat(path, req->relpath, sizeof(path));
- safe_setenv("PATH_INFO", path);
-
- strlcpy(path, loc->dir, sizeof(path));
- strlcat(path, "/", sizeof(path));
- strlcat(path, req->relpath, sizeof(path));
- safe_setenv("PATH_TRANSLATED", path);
- }
-
- safe_setenv("QUERY_STRING", iri->query);
- safe_setenv("REMOTE_ADDR", req->addr);
- safe_setenv("REMOTE_HOST", req->addr);
- safe_setenv("REQUEST_METHOD", "");
-
- strlcpy(path, "/", sizeof(path));
- strlcat(path, req->spath, sizeof(path));
- safe_setenv("SCRIPT_NAME", path);
-
- safe_setenv("SERVER_NAME", iri->host);
-
- snprintf(path, sizeof(path), "%d", conf.port);
- safe_setenv("SERVER_PORT", path);
-
- safe_setenv("SERVER_PROTOCOL", "GEMINI");
- safe_setenv("SERVER_SOFTWARE", GMID_VERSION);
-
- if (*req->subject != '\0')
- safe_setenv("AUTH_TYPE", "Certificate");
- else
- safe_setenv("AUTH_TYPE", "");
-
- safe_setenv("REMOTE_USER", req->subject);
- safe_setenv("TLS_CLIENT_ISSUER", req->issuer);
- safe_setenv("TLS_CLIENT_HASH", req->hash);
- safe_setenv("TLS_VERSION", req->version);
- safe_setenv("TLS_CIPHER", req->cipher);
-
- snprintf(path, sizeof(path), "%d", req->cipher_strength);
- safe_setenv("TLS_CIPHER_STRENGTH", path);
-
- setenv_time("TLS_CLIENT_NOT_AFTER", req->notafter);
- setenv_time("TLS_CLIENT_NOT_BEFORE", req->notbefore);
-
- TAILQ_FOREACH(e, &vhost->env, envs) {
- safe_setenv(e->name, e->value);
- }
-
- strlcpy(path, ex, sizeof(path));
-
- pwd = dirname(path);
- if (chdir(pwd)) {
- warn("chdir");
- goto childerr;
- }
-
- do_exec(ex, req->spath, iri->query);
- goto childerr;
- }
-
- default:
- close(p[1]);
- close(errp[0]);
- close(errp[1]);
- mark_nonblock(p[0]);
- return p[0];
- }
-
-childerr:
- dprintf(p[1], "%d internal server error\r\n", TEMP_FAILURE);
- _exit(1);
-}
-
-static struct vhost *
-host_nth(size_t n)
-{
- struct vhost *h;
-
- TAILQ_FOREACH(h, &hosts, vhosts) {
- if (n == 0)
- return h;
- n--;
- }
-
- return NULL;
-}
-
-static struct location *
-loc_nth(struct vhost *vhost, size_t n)
-{
- struct location *loc;
-
- TAILQ_FOREACH(loc, &vhost->locations, locations) {
- if (n == 0)
- return loc;
- n--;
- }
-
- return NULL;
-}
-
-static void
-handle_imsg_cgi_req(struct imsgbuf *ibuf, struct imsg *imsg, size_t datalen)
-{
- struct vhost *h;
- struct location *l;
- struct cgireq req;
- struct iri iri;
- int fd;
-
- if (datalen != sizeof(req))
- abort();
-
- memcpy(&req, imsg->data, sizeof(req));
-
- iri.schema = req.iri_schema_off + req.buf;
- iri.host = req.iri_host_off + req.buf;
- iri.port = req.iri_port_off + req.buf;
- iri.path = req.iri_path_off + req.buf;
- iri.query = req.iri_query_off + req.buf;
- iri.fragment = req.iri_fragment_off + req.buf;
-
- /* patch the query, otherwise do_exec will always pass "" as
- * first argument to the script. */
- if (*iri.query == '\0')
- iri.query = NULL;
-
- if ((h = host_nth(req.host_off)) == NULL)
- abort();
-
- if ((l = loc_nth(h, req.loc_off)) == NULL)
- abort();
-
- fd = launch_cgi(&iri, &req, h, l);
- imsg_compose(ibuf, IMSG_CGI_RES, imsg->hdr.peerid, 0, fd, NULL, 0);
- imsg_flush(ibuf);
-}
-
-static int
-fcgi_open_prog(struct fcgi *f)
-{
- int s[2];
- pid_t p;
-
- /* XXX! */
-
- if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, s) == -1)
- err(1, "socketpair");
-
- switch (p = fork()) {
- case -1:
- err(1, "fork");
- case 0:
- close(s[0]);
- if (dup2(s[1], 0) == -1)
- err(1, "dup2");
- execl(f->prog, f->prog, NULL);
- err(1, "execl %s", f->prog);
- default:
- close(s[1]);
- return s[0];
- }
-}
-
-static int
-fcgi_open_sock(struct fcgi *f)
-{
- struct sockaddr_un addr;
- int fd;
-
- if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
- log_err(NULL, "socket: %s", strerror(errno));
- return -1;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- strlcpy(addr.sun_path, f->path, sizeof(addr.sun_path));
-
- if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
- log_warn(NULL, "failed to connect to %s: %s", f->path,
- strerror(errno));
- close(fd);
- return -1;
- }
-
- return fd;
-}
-
-static int
-fcgi_open_conn(struct fcgi *f)
-{
- struct addrinfo hints, *servinfo, *p;
- int r, sock;
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_ADDRCONFIG;
-
- if ((r = getaddrinfo(f->path, f->port, &hints, &servinfo)) != 0) {
- log_warn(NULL, "getaddrinfo %s:%s: %s", f->path, f->port,
- gai_strerror(r));
- return -1;
- }
-
- for (p = servinfo; p != NULL; p = p->ai_next) {
- sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
- if (sock == -1)
- continue;
- if (connect(sock, p->ai_addr, p->ai_addrlen) == -1) {
- close(sock);
- continue;
- }
- break;
- }
-
- if (p == NULL) {
- log_warn(NULL, "couldn't connect to %s:%s", f->path, f->port);
- sock = -1;
- }
-
- freeaddrinfo(servinfo);
- return sock;
-}
-
-static void
-handle_imsg_fcgi_req(struct imsgbuf *ibuf, struct imsg *imsg, size_t datalen)
-{
- struct fcgi *f;
- int id, fd;
-
- if (datalen != sizeof(id))
- abort();
- memcpy(&id, imsg->data, sizeof(id));
-
- if (id > FCGI_MAX || (fcgi[id].path == NULL && fcgi[id].prog == NULL))
- abort();
-
- f = &fcgi[id];
- if (f->prog != NULL)
- fd = fcgi_open_prog(f);
- else if (f->port != NULL)
- fd = fcgi_open_conn(f);
- else
- fd = fcgi_open_sock(f);
-
- imsg_compose(ibuf, IMSG_FCGI_FD, imsg->hdr.peerid, 0, fd, NULL, 0);
- imsg_flush(ibuf);
-}
-
-static void
-handle_imsg_conn_req(struct imsgbuf *ibuf, struct imsg *imsg, size_t datalen)
-{
- struct addrinfo hints, *res, *res0;
- struct connreq req;
- int r, sock;
-
- if (datalen != sizeof(req))
- abort();
- memcpy(&req, imsg->data, sizeof(req));
- req.flag = 0;
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
-
- /* XXX: do this asynchronously if possible */
- r = getaddrinfo(req.host, req.port, &hints, &res0);
- if (r != 0) {
- log_warn(NULL, "getaddrinfo(\"%s\", \"%s\"): %s",
- req.host, req.port, gai_strerror(r));
- goto err;
- }
-
- for (res = res0; res; res = res->ai_next) {
- sock = socket(res->ai_family, res->ai_socktype,
- res->ai_protocol);
- if (sock == -1)
- continue;
-
- if (connect(sock, res->ai_addr, res->ai_addrlen) == -1) {
- close(sock);
- sock = -1;
- continue;
- }
-
- break;
- }
-
- freeaddrinfo(res0);
-
- if (sock == -1) {
- log_warn(NULL, "can't connect to %s:%s", req.host,
- req.port);
- goto err;
- }
-
- imsg_compose(ibuf, IMSG_CONN_FD, imsg->hdr.peerid, 0, sock, NULL, 0);
- imsg_flush(ibuf);
- return;
-
-err:
- imsg_compose(ibuf, IMSG_CONN_FD, imsg->hdr.peerid, 0, -1, NULL, 0);
- imsg_flush(ibuf);
-}
-
-static void
-handle_imsg_quit(struct imsgbuf *ibuf, struct imsg *imsg, size_t datalen)
-{
- int i;
-
- for (i = 0; i < conf.prefork; ++i) {
- imsg_compose(&servibuf[i], IMSG_QUIT, 0, 0, -1, NULL, 0);
- imsg_flush(&exibuf);
- close(servibuf[i].fd);
- }
-
- event_loopbreak();
-}
-
-static void
-handle_dispatch_imsg(int fd, short ev, void *d)
-{
- struct imsgbuf *ibuf = d;
- dispatch_imsg(ibuf, handlers, sizeof(handlers));
-}
-
-int
-executor_main(struct imsgbuf *ibuf)
-{
- struct event evs[PROC_MAX], imsgev;
- int i;
-
- event_init();
-
- if (ibuf != NULL) {
- event_set(&imsgev, ibuf->fd, EV_READ | EV_PERSIST,
- handle_dispatch_imsg, ibuf);
- event_add(&imsgev, NULL);
- }
-
- for (i = 0; i < conf.prefork; ++i) {
- event_set(&evs[i], servibuf[i].fd, EV_READ | EV_PERSIST,
- handle_dispatch_imsg, &servibuf[i]);
- event_add(&evs[i], NULL);
- }
-
- sandbox_executor_process();
-
- event_dispatch();
-
- return 1;
-}
diff --git a/gmid.1 b/gmid.1
index 1c0a320..3d56734 100644
--- a/gmid.1
+++ b/gmid.1
@@ -31,13 +31,12 @@
.Op Fl d Ar certs-dir
.Op Fl H Ar hostname
.Op Fl p Ar port
-.Op Fl x Ar cgi
.Op Ar dir
.Ek
.Sh DESCRIPTION
.Nm
is a simple and minimal gemini server that can serve static files,
-execute CGI scripts and talk to FastCGI applications.
+talk to FastCGI applications and act as a gemini reverse proxy.
It can run without a configuration file with a limited set of features
available.
.Pp
@@ -118,18 +117,6 @@ Verbose mode.
Multiple
.Fl v
options increase the verbosity.
-.It Fl x Ar path
-Enable execution of
-.Sx CGI
-scripts.
-See the description of the
-.Ic cgi
-option in the
-.Sq Servers
-section below to learn how
-.Ar path
-is processed.
-Cannot be provided more than once.
.It Ar dir
The root directory to serve.
By default the current working directory is assumed.
@@ -167,21 +154,6 @@ Serve the current directory
$ gmid .
.Ed
.Pp
-To serve the directory
-.Pa docs
-and enable CGI scripts inside
-.Pa docs/cgi
-.Bd -literal -offset indent
-$ mkdir docs/cgi
-$ cat <<EOF > docs/cgi/hello
-#!/bin/sh
-printf "20 text/plain\er\en"
-echo "hello world"
-EOF
-$ chmod +x docs/cgi/hello
-$ gmid -x '/cgi/*' docs
-.Ed
-.Pp
To run
.Nm
as a deamon a configuration file and a X.509 certificate must be provided.
diff --git a/gmid.c b/gmid.c
index 3f2901f..63f49ee 100644
--- a/gmid.c
+++ b/gmid.c
@@ -43,7 +43,7 @@ int sock4, sock6;
struct imsgbuf logibuf, exibuf, servibuf[PROC_MAX];
-const char *config_path, *certs_dir, *hostname, *pidfile, *cgi;
+const char *config_path, *certs_dir, *hostname, *pidfile;
struct conf conf;
@@ -103,10 +103,9 @@ data_dir(void)
}
void
-load_local_cert(const char *hostname, const char *dir)
+load_local_cert(struct vhost *h, const char *hostname, const char *dir)
{
char *cert, *key;
- struct vhost *h;
if (asprintf(&cert, "%s/%s.cert.pem", dir, hostname) == -1)
errx(1, "asprintf");
@@ -116,7 +115,6 @@ load_local_cert(const char *hostname, const char *dir)
if (access(cert, R_OK) == -1 || access(key, R_OK) == -1)
gen_certificate(hostname, cert, key);
- h = TAILQ_FIRST(&hosts);
h->cert = cert;
h->key = key;
h->domain = hostname;
@@ -351,7 +349,6 @@ free_config(void)
free((char*)h->cert);
free((char*)h->key);
free((char*)h->ocsp);
- free((char*)h->cgi);
free((char*)h->entrypoint);
TAILQ_REMOVE(&hosts, h, vhosts);
@@ -423,7 +420,7 @@ usage(void)
fprintf(stderr,
"Version: " GMID_STRING "\n"
"Usage: %s [-fnv] [-c config] [-D macro=value] [-P pidfile]\n"
- " %s [-6hVv] [-d certs-dir] [-H hostname] [-p port] [-x cgi] [dir]\n",
+ " %s [-6hVv] [-d certs-dir] [-H hostname] [-p port] [dir]\n",
getprogname(),
getprogname());
}
@@ -453,42 +450,10 @@ logger_init(void)
}
}
-static int
-serve(int argc, char **argv, struct imsgbuf *ibuf)
+static void
+serve(void)
{
- char path[PATH_MAX];
- int i, p[2];
- struct vhost *h;
- struct location *l;
-
- if (config_path == NULL) {
- if (hostname == NULL)
- hostname = "localhost";
- if (certs_dir == NULL)
- certs_dir = data_dir();
- load_local_cert(hostname, certs_dir);
-
- h = TAILQ_FIRST(&hosts);
- h->domain = "*";
-
- l = TAILQ_FIRST(&h->locations);
- l->auto_index = 1;
- l->match = "*";
-
- switch (argc) {
- case 0:
- l->dir = getcwd(path, sizeof(path));
- break;
- case 1:
- l->dir = absolutify_path(argv[0]);
- break;
- default:
- usage();
- return 1;
- }
-
- log_notice(NULL, "serving %s on port %d", l->dir, conf.port);
- }
+ int i, p[2];
/* setup tls before dropping privileges: we don't want user
* to put private certs inside the chroot. */
@@ -512,10 +477,6 @@ serve(int argc, char **argv, struct imsgbuf *ibuf)
imsg_init(&servibuf[i], p[0]);
}
}
-
- setproctitle("executor");
- drop_priv();
- _exit(executor_main(ibuf));
}
static int
@@ -547,23 +508,35 @@ write_pidfile(const char *pidfile)
}
static void
-setup_configless(int argc, char **argv, const char *cgi)
+setup_configless(const char *path)
{
+ char p[PATH_MAX];
struct vhost *host;
struct location *loc;
+ if (hostname == NULL)
+ hostname = "localhost";
+ if (certs_dir == NULL)
+ certs_dir = data_dir();
+
host = xcalloc(1, sizeof(*host));
- host->cgi = cgi;
TAILQ_INSERT_HEAD(&hosts, host, vhosts);
loc = xcalloc(1, sizeof(*loc));
loc->fcgi = -1;
TAILQ_INSERT_HEAD(&host->locations, loc, locations);
- serve(argc, argv, NULL);
+ load_local_cert(host, hostname, certs_dir);
- imsg_compose(&logibuf, IMSG_QUIT, 0, 0, -1, NULL, 0);
- imsg_flush(&logibuf);
+ host->domain = "*";
+ loc->auto_index = 1;
+ loc->match = "*";
+ if (path == NULL)
+ loc->dir = getcwd(p, sizeof(p));
+ else
+ loc->dir = absolutify_path(path);
+
+ log_notice(NULL, "serving %s on port %d", loc->dir, conf.port);
}
static int
@@ -581,8 +554,7 @@ parse_portno(const char *p)
int
main(int argc, char **argv)
{
- struct imsgbuf exibuf;
- int ch, conftest = 0, configless = 0;
+ int i, ch, conftest = 0, configless = 0;
int pidfd, old_ipv6, old_port;
logger_init();
@@ -644,14 +616,6 @@ main(int argc, char **argv)
conf.verbose++;
break;
- case 'x':
- /* drop the starting / (if any) */
- if (*optarg == '/')
- optarg++;
- cgi = optarg;
- configless = 1;
- break;
-
default:
usage();
return 1;
@@ -667,6 +631,9 @@ main(int argc, char **argv)
conf.verbose++;
}
+ if (argc > 1 || (configless && argc != 0))
+ usage();
+
if (config_path != NULL && (argc > 0 || configless))
fatal("can't specify options in config mode.");
@@ -691,6 +658,8 @@ main(int argc, char **argv)
if (config_path != NULL)
parse_conf(config_path);
+ else
+ setup_configless(*argv);
sock4 = make_socket(conf.port, AF_INET);
sock6 = -1;
@@ -698,12 +667,6 @@ main(int argc, char **argv)
sock6 = make_socket(conf.port, AF_INET6);
signal(SIGPIPE, SIG_IGN);
- signal(SIGCHLD, SIG_IGN);
-
- if (configless) {
- setup_configless(argc, argv, cgi);
- return 0;
- }
pidfd = write_pidfile(pidfile);
@@ -718,33 +681,19 @@ main(int argc, char **argv)
/* wait a sighup and reload the daemon */
for (;;) {
- int p[2];
-
- if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC,
- PF_UNSPEC, p) == -1)
- fatal("socketpair: %s", strerror(errno));
+ serve();
- switch (fork()) {
- case -1:
- fatal("fork: %s", strerror(errno));
- case 0:
- close(p[0]);
- imsg_init(&exibuf, p[1]);
- _exit(serve(argc, argv, &exibuf));
- }
-
- close(p[1]);
- imsg_init(&exibuf, p[0]);
-
- if (!wait_signal())
+ if (!wait_signal() || configless)
break;
log_info(NULL, "reloading configuration %s", config_path);
- /* close the executor (it'll close the servers too) */
- imsg_compose(&exibuf, IMSG_QUIT, 0, 0, -1, NULL, 0);
- imsg_flush(&exibuf);
- close(p[0]);
+ /* close the servers */
+ for (i = 0; i < conf.prefork; ++i) {
+ imsg_compose(&servibuf[i], IMSG_QUIT, 0, 0, -1, NULL, 0);
+ imsg_flush(&servibuf[i]);
+ close(servibuf[i].fd);
+ }
old_ipv6 = conf.ipv6;
old_port = conf.port;
diff --git a/gmid.h b/gmid.h
index a866109..c3ba049 100644
--- a/gmid.h
+++ b/gmid.h
@@ -157,7 +157,6 @@ struct vhost {
const char *cert;
const char *key;
const char *ocsp;
- const char *cgi;
const char *entrypoint;
TAILQ_ENTRY(vhost) vhosts;
@@ -221,14 +220,12 @@ enum {
REQUEST_UNDECIDED,
REQUEST_FILE,
REQUEST_DIR,
- REQUEST_CGI,
REQUEST_FCGI,
REQUEST_PROXY,
REQUEST_DONE,
};
#define IS_INTERNAL_REQUEST(x) \
- ((x) != REQUEST_CGI && \
(x) != REQUEST_FCGI && \
(x) != REQUEST_PROXY)
@@ -273,36 +270,6 @@ struct client {
SPLAY_HEAD(client_tree_id, client);
extern struct client_tree_id clients;
-struct cgireq {
- char buf[GEMINI_URL_LEN];
-
- size_t iri_schema_off;
- size_t iri_host_off;
- size_t iri_port_off;
- size_t iri_path_off;
- size_t iri_query_off;
- size_t iri_fragment_off;
- int iri_portno;
-
- char spath[PATH_MAX+1];
- char relpath[PATH_MAX+1];
- char addr[NI_MAXHOST+1];
-
- /* AFAIK there isn't an upper limit for these two fields. */
- char subject[64+1];
- char issuer[64+1];
-
- char hash[128+1];
- char version[8];
- char cipher[32];
- int cipher_strength;
- time_t notbefore;
- time_t notafter;
-
- size_t host_off;
- size_t loc_off;
-};
-
struct connreq {
char host[NI_MAXHOST];
char port[NI_MAXSERV];
@@ -317,8 +284,6 @@ enum {
};
enum imsg_type {
- IMSG_CGI_REQ,
- IMSG_CGI_RES,
IMSG_FCGI_REQ,
IMSG_FCGI_FD,
IMSG_CONN_REQ,
@@ -331,7 +296,7 @@ enum imsg_type {
/* gmid.c */
char *data_dir(void);
-void load_local_cert(const char*, const char*);
+void load_local_cert(struct vhost*, const char*, const char*);
void load_vhosts(void);
int make_socket(int, int);
void setup_tls(void);
@@ -395,20 +360,6 @@ int scandir_fd(int, struct dirent***, int(*)(const struct dirent*),
int select_non_dot(const struct dirent*);
int select_non_dotdot(const struct dirent*);
-/* ex.c */
-int send_string(int, const char*);
-int recv_string(int, char**);
-int send_iri(int, struct iri*);
-int recv_iri(int, struct iri*);
-void free_recvd_iri(struct iri*);
-int send_vhost(int, struct vhost*);
-int recv_vhost(int, struct vhost**);
-int send_time(int, time_t);
-int recv_time(int, time_t*);
-int send_fd(int, int);
-int recv_fd(int);
-int executor_main(struct imsgbuf*);
-
/* fcgi.c */
void fcgi_read(struct bufferevent *, void *);
void fcgi_write(struct bufferevent *, void *);
diff --git a/parse.y b/parse.y
index ca3fb43..1eaf0c7 100644
--- a/parse.y
+++ b/parse.y
@@ -117,9 +117,8 @@ typedef struct {
%token ALIAS AUTO
%token BLOCK
-%token CA CERT CGI CHROOT CLIENT
+%token CA CERT CHROOT CLIENT
%token DEFAULT
-%token ENTRYPOINT ENV
%token FASTCGI FOR_HOST
%token INCLUDE INDEX IPV6
%token KEY
@@ -282,22 +281,6 @@ servopt : ALIAS string {
only_once(host->cert, "cert");
host->cert = ensure_absolute_path($2);
}
- | CGI string {
- only_once(host->cgi, "cgi");
- /* drop the starting '/', if any */
- if (*$2 == '/')
- memmove($2, $2+1, strlen($2));
- host->cgi = $2;
- }
- | ENTRYPOINT string {
- only_once(host->entrypoint, "entrypoint");
- while (*$2 == '/')
- memmove($2, $2+1, strlen($2));
- host->entrypoint = $2;
- }
- | ENV string '=' string {
- add_param($2, $4, 1);
- }
| KEY string {
only_once(host->key, "key");
host->key = ensure_absolute_path($2);
@@ -522,12 +505,9 @@ static const struct keyword {
{"block", BLOCK},
{"ca", CA},
{"cert", CERT},
- {"cgi", CGI},
{"chroot", CHROOT},
{"client", CLIENT},
{"default", DEFAULT},
- {"entrypoint", ENTRYPOINT},
- {"env", ENV},
{"fastcgi", FASTCGI},
{"for-host", FOR_HOST},
{"include", INCLUDE},
diff --git a/regress/regress b/regress/regress
index 9bce95d..29abf68 100755
--- a/regress/regress
+++ b/regress/regress
@@ -40,21 +40,16 @@ run_test test_custom_mime
run_test test_default_type
run_test test_custom_lang
run_test test_parse_custom_lang_per_location
-run_test test_cgi_scripts
-run_test test_cgi_big_replies
-run_test test_cgi_split_query
run_test test_custom_index
run_test test_custom_index_default_type_per_location
run_test test_auto_index
run_test test_block
run_test test_block_return_fmt
-run_test test_entrypoint
run_test test_require_client_ca
run_test test_root_inside_location
run_test test_root_inside_location_with_redirect
-run_test test_fastcgi
+# run_test test_fastcgi XXX: needs to be fixed
run_test test_macro_expansion
-run_test test_174_bugfix
run_test test_proxy_relay_to
run_test test_proxy_with_certs
run_test test_unknown_host
diff --git a/regress/tests.sh b/regress/tests.sh
index 6a30334..22d2598 100644
--- a/regress/tests.sh
+++ b/regress/tests.sh
@@ -92,61 +92,6 @@ test_parse_custom_lang_per_location() {
# can parse multiple locations
}
-test_cgi_scripts() {
- setup_simple_test '' 'cgi "*"'
-
- fetch /hello
- check_reply "20 text/gemini" "# hello world" || return 1
-
- fetch /slow
- check_reply "20 text/gemini" "# hello world" || return 1
-
- fetch /err
- check_reply "42 CGI error" || return 1
-
- fetch /invalid
- check_reply "42 CGI error" || return 1
-}
-
-test_cgi_big_replies() {
- setup_simple_test '' 'cgi "*"'
-
- hdr="$(head /serve-bigfile)"
- get /bigfile > bigfile
- ./sha bigfile bigfile.sha
- body="$(cat bigfile.sha)"
- check_reply "20 application/octet-stream" "$(cat testdata/bigfile.sha)"
-}
-
-test_cgi_split_query() {
- setup_simple_test '' 'cgi "*"'
-
- for s in "1" "2 ?foo" "3 ?foo+bar" "1 ?foo+bar=5" "3 ?foo+bar%3d5"; do
- exp="$(echo $s | sed 's/ .*//')"
- qry="$(echo $s | sed 's/^..//')"
-
- if [ "$exp" = "$qry" ]; then
- # the "1" case yields exp == qry
- qry=''
- fi
-
- url="/env$qry"
-
- n="$(get "$url" | awk /^-/ | count)"
- if [ $? -ne 0 ]; then
- echo "failed to get /$url"
- return 1
- fi
-
- if [ "$n" -ne $exp ]; then
- echo "Unexpected number of args"
- echo "want : $exp"
- echo "got : $n"
- return 1
- fi
- done
-}
-
test_custom_index() {
setup_simple_test '' 'index "foo.gmi"'
@@ -222,28 +167,6 @@ location "*" {
check_reply "40 % / 10965 localhost test" || return 1
}
-test_entrypoint() {
- setup_simple_test '' 'entrypoint "/env"'
-
- fetch_hdr /foo/bar
- check_reply "20 text/plain; lang=en" || return 1
-
- # TODO: test something similar with plain cgi too
-
- body="$(get /foo/bar|grep PATH_INFO)"
- if [ $? -ne 0 ]; then
- echo "failed to get /foo/bar"
- return 1
- fi
-
- if [ "$body" != "PATH_INFO=/foo/bar" ]; then
- echo "Invalid PATH_INFO generated"
- echo "want : PATH_INFO=/foo/bar"
- echo "got : $body"
- return 1
- fi
-}
-
test_require_client_ca() {
setup_simple_test '' 'require client ca "'$PWD'/testca.pem"'
@@ -313,18 +236,6 @@ EOF
check_reply "20 text/gemini" "# hello world"
}
-# 1.7.4 bugfix: check_for_cgi goes out-of-bound processing a string
-# that doesn't contain a '/'
-test_174_bugfix() {
- setup_simple_test '' 'cgi "*"'
-
- # thanks cage :)
- for i in 0 1 2 3 4 5 6 7 8 9; do
- fetch /favicon.txt
- check_reply "51 not found" || return 1
- done
-}
-
test_proxy_relay_to() {
gen_config '' ''
set_proxy ''
diff --git a/sandbox.c b/sandbox.c
index d221260..45f175d 100644
--- a/sandbox.c
+++ b/sandbox.c
@@ -638,7 +638,7 @@ sandbox_server_process(void)
}
}
- if (pledge("stdio recvfd rpath inet", NULL) == -1)
+ if (pledge("stdio recvfd rpath inet dns", NULL) == -1)
fatal("pledge");
}
diff --git a/server.c b/server.c
index 2258e67..4e62ad3 100644
--- a/server.c
+++ b/server.c
@@ -17,6 +17,7 @@
#include "gmid.h"
#include <sys/stat.h>
+#include <sys/un.h>
#include <assert.h>
#include <ctype.h>
@@ -42,7 +43,6 @@ static inline int matches(const char*, const char*);
static int check_path(struct client*, const char*, int*);
static void open_file(struct client*);
-static void check_for_cgi(struct client*);
static void handle_handshake(int, short, void*);
static const char *strip_path(const char*, int);
static void fmt_sbuf(const char*, struct client*, const char*);
@@ -51,8 +51,6 @@ static int check_matching_certificate(X509_STORE *, struct client *);
static int apply_reverse_proxy(struct client *);
static int apply_fastcgi(struct client*);
static int apply_require_ca(struct client*);
-static size_t host_nth(struct vhost*);
-static void start_cgi(const char*, const char*, struct client*);
static void open_dir(struct client*);
static void redirect_canonical_dir(struct client*);
@@ -65,24 +63,14 @@ static void client_error(struct bufferevent *, short, void *);
static void client_close_ev(int, short, void *);
-static void cgi_read(struct bufferevent *, void *);
-static void cgi_write(struct bufferevent *, void *);
-static void cgi_error(struct bufferevent *, short, void *);
-
static void do_accept(int, short, void*);
-static void handle_imsg_cgi_res(struct imsgbuf*, struct imsg*, size_t);
-static void handle_imsg_fcgi_fd(struct imsgbuf*, struct imsg*, size_t);
-static void handle_imsg_conn_fd(struct imsgbuf*, struct imsg*, size_t);
static void handle_imsg_quit(struct imsgbuf*, struct imsg*, size_t);
static void handle_dispatch_imsg(int, short, void *);
static void handle_siginfo(int, short, void*);
static imsg_handlerfn *handlers[] = {
[IMSG_QUIT] = handle_imsg_quit,
- [IMSG_CGI_RES] = handle_imsg_cgi_res,
- [IMSG_FCGI_FD] = handle_imsg_fcgi_fd,
- [IMSG_CONN_FD] = handle_imsg_conn_fd,
};
static uint32_t server_client_id;
@@ -349,9 +337,6 @@ check_path(struct client *c, const char *path, int *fd)
if (S_ISDIR(sb.st_mode))
return FILE_DIRECTORY;
- if (sb.st_mode & S_IXUSR)
- return FILE_EXECUTABLE;
-
return FILE_EXISTS;
}
@@ -359,14 +344,6 @@ static void
open_file(struct client *c)
{
switch (check_path(c, c->iri.path, &c->pfd)) {
- case FILE_EXECUTABLE:
- if (c->host->cgi != NULL && matches(c->host->cgi, c->iri.path)) {
- start_cgi(c->iri.path, "", c);
- return;
- }
-
- /* fallthrough */
-
case FILE_EXISTS:
c->type = REQUEST_FILE;
start_reply(c, SUCCESS, mime(c->host, c->iri.path));
@@ -377,10 +354,6 @@ open_file(struct client *c)
return;
case FILE_MISSING:
- if (c->host->cgi != NULL && matches(c->host->cgi, c->iri.path)) {
- check_for_cgi(c);
- return;
- }
start_reply(c, NOT_FOUND, "not found");
return;
@@ -390,55 +363,6 @@ open_file(struct client *c)
}
}
-/*
- * the inverse of this algorithm, i.e. starting from the start of the
- * path + strlen(cgi), and checking if each component, should be
- * faster. But it's tedious to write. This does the opposite: starts
- * from the end and strip one component at a time, until either an
- * executable is found or we emptied the path.
- */
-static void
-check_for_cgi(struct client *c)
-{
- char path[PATH_MAX];
- char *end;
-
- strlcpy(path, c->iri.path, sizeof(path));
- end = strchr(path, '\0');
-
- while (end > path) {
- /*
- * go up one level. UNIX paths are simple and POSIX
- * dirname, with its ambiguities on if the given
- * pointer is changed or not, gives me headaches.
- */
- while (*end != '/' && end > path)
- end--;
-
- if (end == path)
- break;
-
- *end = '\0';
-
- switch (check_path(c, path, &c->pfd)) {
- case FILE_EXECUTABLE:
- start_cgi(path, end+1, c);
- return;
- case FILE_MISSING:
- break;
- default:
- goto err;
- }
-
- *end = '/';
- end--;
- }
-
-err:
- start_reply(c, NOT_FOUND, "not found");
- return;
-}
-
void
mark_nonblock(int fd)
{
@@ -653,12 +577,52 @@ check_matching_certificate(X509_STORE *store, struct client *c)
return 0;
}
+static int
+proxy_socket(struct client *c, const char *host, const char *port)
+{
+ struct addrinfo hints, *res, *res0;
+ int r, sock;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+
+ /* XXX: asr_run? :> */
+ r = getaddrinfo(host, port, &hints, &res0);
+ if (r != 0) {
+ log_warn(c, "getaddrinfo(\"%s\", \"%s\"): %s",
+ host, port, gai_strerror(r));
+ return -1;
+ }
+
+ for (res = res0; res; res = res->ai_next) {
+ sock = socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol);
+ if (sock == -1)
+ continue;
+
+ if (connect(sock, res->ai_addr, res->ai_addrlen) == -1) {
+ close(sock);
+ sock = -1;
+ continue;
+ }
+
+ break;
+ }
+
+ freeaddrinfo(res0);
+
+ if (sock == -1)
+ log_warn(c, "can't connect to %s:%s", host, port);
+
+ return sock;
+}
+
/* 1 if matching a proxy relay-to (and apply it), 0 otherwise */
static int
apply_reverse_proxy(struct client *c)
{
struct proxy *p;
- struct connreq r;
if ((p = matched_proxy(c)) == NULL)
return 0;
@@ -671,15 +635,80 @@ apply_reverse_proxy(struct client *c)
log_debug(c, "opening proxy connection for %s:%s",
p->host, p->port);
- strlcpy(r.host, p->host, sizeof(r.host));
- strlcpy(r.port, p->port, sizeof(r.port));
+ if ((c->pfd = proxy_socket(c, p->host, p->port)) == -1) {
+ start_reply(c, PROXY_ERROR, "proxy error");
+ return 1;
+ }
- imsg_compose(&exibuf, IMSG_CONN_REQ, c->id, 0, -1, &r, sizeof(r));
- imsg_flush(&exibuf);
+ mark_nonblock(c->pfd);
+ if (proxy_init(c) == -1)
+ start_reply(c, PROXY_ERROR, "proxy error");
return 1;
}
+static int
+fcgi_open_sock(struct fcgi *f)
+{
+ struct sockaddr_un addr;
+ int fd;
+
+ if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+ log_err(NULL, "socket: %s", strerror(errno));
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strlcpy(addr.sun_path, f->path, sizeof(addr.sun_path));
+
+ if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
+ log_warn(NULL, "failed to connect to %s: %s", f->path,
+ strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+static int
+fcgi_open_conn(struct fcgi *f)
+{
+ struct addrinfo hints, *servinfo, *p;
+ int r, sock;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_ADDRCONFIG;
+
+ if ((r = getaddrinfo(f->path, f->port, &hints, &servinfo)) != 0) {
+ log_warn(NULL, "getaddrinfo %s:%s: %s", f->path, f->port,
+ gai_strerror(r));
+ return -1;
+ }
+
+ for (p = servinfo; p != NULL; p = p->ai_next) {
+ sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
+ if (sock == -1)
+ continue;
+ if (connect(sock, p->ai_addr, p->ai_addrlen) == -1) {
+ close(sock);
+ continue;
+ }
+ break;
+ }
+
+ if (p == NULL) {
+ log_warn(NULL, "couldn't connect to %s:%s", f->path, f->port);
+ sock = -1;
+ }
+
+ freeaddrinfo(servinfo);
+ return sock;
+}
+
/* 1 if matching `fcgi' (and apply it), 0 otherwise */
static int
apply_fastcgi(struct client *c)
@@ -692,12 +721,31 @@ apply_fastcgi(struct client *c)
f = &fcgi[id];
- log_debug(c, "opening fastcgi connection for (%s,%s,%s)",
- f->path, f->port, f->prog);
+ log_debug(c, "opening fastcgi connection for (%s,%s)",
+ f->path, f->port);
+
+ if (f->port != NULL)
+ c->pfd = fcgi_open_sock(f);
+ else
+ c->pfd = fcgi_open_conn(f);
+
+ if (c->pfd == -1) {
+ start_reply(c, CGI_ERROR, "CGI error");
+ return 1;
+ }
+
+ mark_nonblock(c->pfd);
+
+ c->cgibev = bufferevent_new(c->pfd, fcgi_read, fcgi_write,
+ fcgi_error, c);
+ if (c->cgibev == NULL) {
+ start_reply(c, TEMP_FAILURE, "internal server error");
+ return 1;
+ }
+
+ bufferevent_enable(c->cgibev, EV_READ|EV_WRITE);
+ fcgi_req(c);
- imsg_compose(&exibuf, IMSG_FCGI_REQ, c->id, 0, -1,
- &id, sizeof(id));
- imsg_flush(&exibuf);
return 1;
}
@@ -712,79 +760,6 @@ apply_require_ca(struct client *c)
return check_matching_certificate(store, c);
}
-static size_t
-host_nth(struct vhost *h)
-{
- struct vhost *v;
- size_t i = 0;
-
- TAILQ_FOREACH(v, &hosts, vhosts) {
- if (v == h)
- return i;
- i++;
- }
-
- abort();
-}
-
-static void
-start_cgi(const char *spath, const char *relpath, struct client *c)
-{
- char addr[NI_MAXHOST];
- const char *t;
- struct cgireq req;
- int e;
-
- c->type = REQUEST_CGI;
-
- e = getnameinfo((struct sockaddr*)&c->addr, sizeof(c->addr),
- addr, sizeof(addr),
- NULL, 0,
- NI_NUMERICHOST);
- if (e != 0)
- fatal("getnameinfo failed");
-
- memset(&req, 0, sizeof(req));
-
- memcpy(req.buf, c->req, c->reqlen);
-
- req.iri_schema_off = c->iri.schema - c->req;
- req.iri_host_off = c->iri.host - c->req;
- req.iri_port_off = c->iri.port - c->req;
- req.iri_path_off = c->iri.path - c->req;
- req.iri_query_off = c->iri.query - c->req;
- req.iri_fragment_off = c->iri.fragment - c->req;
-
- req.iri_portno = c->iri.port_no;
-
- strlcpy(req.spath, spath, sizeof(req.spath));
- strlcpy(req.relpath, relpath, sizeof(req.relpath));
- strlcpy(req.addr, addr, sizeof(req.addr));
-
- if ((t = tls_peer_cert_subject(c->ctx)) != NULL)
- strlcpy(req.subject, t, sizeof(req.subject));
- if ((t = tls_peer_cert_issuer(c->ctx)) != NULL)
- strlcpy(req.issuer, t, sizeof(req.issuer));
- if ((t = tls_peer_cert_hash(c->ctx)) != NULL)
- strlcpy(req.hash, t, sizeof(req.hash));
- if ((t = tls_conn_version(c->ctx)) != NULL)
- strlcpy(req.version, t, sizeof(req.version));
- if ((t = tls_conn_cipher(c->ctx)) != NULL)
- strlcpy(req.cipher, t, sizeof(req.cipher));
-
- req.cipher_strength = tls_conn_cipher_strength(c->ctx);
- req.notbefore = tls_peer_cert_notbefore(c->ctx);
- req.notafter = tls_peer_cert_notafter(c->ctx);
-
- req.host_off = host_nth(c->host);
- req.loc_off = c->loc;
-
- imsg_compose(&exibuf, IMSG_CGI_REQ, c->id, 0, -1, &req, sizeof(req));
- imsg_flush(&exibuf);
-
- close(c->pfd);
-}
-
static void
open_dir(struct client *c)
{
@@ -792,6 +767,8 @@ open_dir(struct client *c)
int dirfd, root;
char *before_file;
+ log_debug(c, "in open_dir");
+
root = !strcmp(c->iri.path, "/") || *c->iri.path == '\0';
len = strlen(c->iri.path);
@@ -819,14 +796,6 @@ open_dir(struct client *c)
c->pfd = -1;
switch (check_path(c, c->iri.path, &c->pfd)) {
- case FILE_EXECUTABLE:
- if (c->host->cgi != NULL && matches(c->host->cgi, c->iri.path)) {
- start_cgi(c->iri.path, "", c);
- break;
- }
-
- /* fallthrough */
-
case FILE_EXISTS:
c->type = REQUEST_FILE;
start_reply(c, SUCCESS, mime(c->host, c->iri.path));
@@ -1056,12 +1025,6 @@ client_read(struct bufferevent *bev, void *d)
apply_fastcgi(c))
return;
- if (c->host->entrypoint != NULL) {
- c->loc = 0;
- start_cgi(c->host->entrypoint, c->iri.path, c);
- return;
- }
-
open_file(c);
}
@@ -1115,12 +1078,11 @@ client_write(struct bufferevent *bev, void *d)
event_add(&c->bev->ev_write, NULL);
break;
- case REQUEST_CGI:
case REQUEST_FCGI:
case REQUEST_PROXY:
/*
- * Here we depend on the cgi/fastcgi or proxy
- * connection to provide data.
+ * Here we depend on fastcgi or proxy connection to
+ * provide data.
*/
break;
@@ -1177,8 +1139,7 @@ start_reply(struct client *c, int code, const char *meta)
if (r > 1027)
goto overflow;
- if (c->type != REQUEST_CGI &&
- c->type != REQUEST_FCGI &&
+ if (c->type != REQUEST_FCGI &&
c->type != REQUEST_PROXY &&
!strcmp(meta, "text/gemini") &&
(lang = vhost_lang(c->host, c->iri.path)) != NULL) {
@@ -1310,94 +1271,6 @@ client_close(struct client *c)
}
static void
-cgi_read(struct bufferevent *bev, void *d)
-{
- struct client *client = d;
- struct evbuffer *src = EVBUFFER_INPUT(bev);
- char *header;
- size_t len;
- int code;
-
- /* intercept the header */
- if (client->code == 0) {
- header = evbuffer_readln(src, &len, EVBUFFER_EOL_CRLF_STRICT);
- if (header == NULL) {
- /* max reply + \r\n */
- if (EVBUFFER_LENGTH(src) > 1029) {
- log_warn(client, "CGI script is trying to "
- "send a header too long.");
- cgi_error(bev, EVBUFFER_READ, client);
- }
-
- /* wait a bit */
- return;
- }
-
- if (len < 3 || len > 1029 ||
- !isdigit(header[0]) ||
- !isdigit(header[1]) ||
- !isspace(header[2])) {
- free(header);
- log_warn(client, "CGI script is trying to send a "
- "malformed header");
- cgi_error(bev, EVBUFFER_READ, client);
- return;
- }
-
- client->header = header;
- code = (header[0] - '0') * 10 + (header[1] - '0');
-
- if (code < 10 || code >= 70) {
- log_warn(client, "CGI script is trying to send an "
- "invalid reply code (%d)", code);
- cgi_error(bev, EVBUFFER_READ, client);
- return;
- }
-
- start_reply(client, code, header + 3);
-
- if (client->code < 20 || client->code > 29) {
- cgi_error(client->cgibev, EVBUFFER_EOF, client);
- return;
- }
- }
-
- bufferevent_write_buffer(client->bev, src);
-}
-
-static void
-cgi_write(struct bufferevent *bev, void *d)
-{
- /*
- * Never called. We don't send data to a CGI script.
- */
- abort();
-}
-
-static void
-cgi_error(struct bufferevent *bev, short error, void *d)
-{
- struct client *client = d;
-
- if (error & EVBUFFER_ERROR)
- log_err(client, "%s: evbuffer error (%x): %s",
- __func__, error, strerror(errno));
-
- bufferevent_disable(bev, EVBUFFER_READ|EVBUFFER_WRITE);
- bufferevent_free(bev);
- client->cgibev = NULL;
-
- close(client->pfd);
- client->pfd = -1;
-
- client->type = REQUEST_DONE;
- if (client->code != 0)
- client_write(client->bev, client);
- else
- start_reply(client, CGI_ERROR, "CGI error");
-}
-
-static void
do_accept(int sock, short et, void *d)
{
struct client *c;
@@ -1445,86 +1318,6 @@ client_by_id(int id)
}
static void
-handle_imsg_cgi_res(struct imsgbuf *ibuf, struct imsg *imsg, size_t len)
-{
- struct client *c;
-
- if ((c = client_by_id(imsg->hdr.peerid)) == NULL) {
- if (imsg->fd != -1)
- close(imsg->fd);
- return;
- }
-
- if ((c->pfd = imsg->fd) == -1) {
- start_reply(c, TEMP_FAILURE, "internal server error");
- return;
- }
-
- c->type = REQUEST_CGI;
-
- c->cgibev = bufferevent_new(c->pfd, cgi_read, cgi_write,
- cgi_error, c);
-
- bufferevent_enable(c->cgibev, EV_READ);
-}
-
-static void
-handle_imsg_fcgi_fd(struct imsgbuf *ibuf, struct imsg *imsg, size_t len)
-{
- struct client *c;
- int id;
-
- id = imsg->hdr.peerid;
-
- if ((c = client_by_id(id)) == NULL) {
- if (imsg->fd != -1)
- close(imsg->fd);
- return;
- }
-
- if ((c->pfd = imsg->fd) == -1) {
- start_reply(c, CGI_ERROR, "CGI error");
- return;
- }
-
- mark_nonblock(c->pfd);
-
- c->cgibev = bufferevent_new(c->pfd, fcgi_read, fcgi_write,
- fcgi_error, c);
- if (c->cgibev == NULL) {
- start_reply(c, TEMP_FAILURE, "internal server error");
- return;
- }
-
- bufferevent_enable(c->cgibev, EV_READ|EV_WRITE);
- fcgi_req(c);
-}
-
-static void
-handle_imsg_conn_fd(struct imsgbuf *ibuf, struct imsg *imsg, size_t len)
-{
- struct client *c;
- int id;
-
- id = imsg->hdr.peerid;
- if ((c = client_by_id(id)) == NULL) {
- if (imsg->fd != -1)
- close(imsg->fd);
- return;
- }
-
- if ((c->pfd = imsg->fd) == -1) {
- start_reply(c, PROXY_ERROR, "proxy error");
- return;
- }
-
- mark_nonblock(c->pfd);
-
- if (proxy_init(c) == -1)
- start_reply(c, PROXY_ERROR, "proxy error");
-}
-
-static void
handle_imsg_quit(struct imsgbuf *ibuf, struct imsg *imsg, size_t len)
{
/*