commit 02d6ae5a5714ad24ea0d56a1d575c3dc72bb6949
parent 4948053bee6d4883d988d104316d11ad9a0ca092
Author: Laslo Hunhold <dev@frign.de>
Date:   Tue, 27 Feb 2018 11:36:24 +0100
Add support for adding a prefix to a target when matching vhosts
This makes quark's vhost-handling very powerful while still being
simple.
Imagine you have a website with a subdomain you really want
to move back to your main domain.
Say the subdomain is called "old.example.org" and you want to serve it
under "example.org" but in the subdirectory "old/", i.e. you want to
redirect a request "old.example.org/subdir/" to "example.org/old/subdir".
For a vhost-handler that only takes 4 arguments for each vhost this is
actually pretty powerful.
Diffstat:
2 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/config.def.h b/config.def.h
@@ -17,10 +17,12 @@ static struct {
 	const char *name;
 	const char *regex;
 	const char *dir;
+	const char *prefix;
 	regex_t re;
 } vhost[] = {
-	/* canonical host      host regex                     directory      */
-	{ "example.org",       "^(www\\.)?example\\.org$",    "/example.org" },
+	/* canonical host    host regex                     directory         prefix */
+	{ "example.org",     "^(www\\.)?example\\.org$",    "/example.org",   NULL   },
+	{ "example.org",     "old\\.example\\.org",         "/",              "/old" },
 };
 
 /* mime-types */
diff --git a/http.c b/http.c
@@ -320,6 +320,9 @@ http_send_response(int fd, struct request *r)
 	char *p, *q, *mime;
 	const char *vhostmatch, *err;
 
+	/* make a working copy of the target */
+	memcpy(realtarget, r->target, sizeof(realtarget));
+
 	/* match vhost */
 	vhostmatch = NULL;
 	if (vhosts) {
@@ -338,10 +341,17 @@ http_send_response(int fd, struct request *r)
 		if (i == LEN(vhost)) {
 			return http_send_status(fd, S_NOT_FOUND);
 		}
+
+		/* if we have a vhost prefix, prepend it to the target */
+		if (vhost[i].prefix) {
+			if (snprintf(realtarget, sizeof(realtarget), "%s%s",
+			    vhost[i].prefix, realtarget) >= sizeof(realtarget)) {
+				return http_send_status(fd, S_REQUEST_TOO_LARGE);
+			}
+		}
 	}
 
 	/* normalize target */
-	memcpy(realtarget, r->target, sizeof(realtarget));
 	if (normabspath(realtarget)) {
 		return http_send_status(fd, S_BAD_REQUEST);
 	}
@@ -369,7 +379,7 @@ http_send_response(int fd, struct request *r)
 		}
 	}
 
-	/* redirect if targets differ or host is non-canonical */
+	/* redirect if targets differ, host is non-canonical or we prefixed */
 	if (strcmp(r->target, realtarget) || (vhosts && vhostmatch &&
 	    strcmp(r->field[REQ_HOST], vhostmatch))) {
 		/* do we need to add a port to the Location? */