Implement --forward.

A web forward feature that performs 301 redirects for some requests
(in addition normal web content serving)

The "Host:" request header (HTTP/1.1 only) is compared with a list of
hosts, defined by the "--forward host url" option. If a match is found,
the request is redirected to url+path. Otherwise, it is served as a
request to the local file system.
This commit is contained in:
Egor Ivanov 2013-04-20 14:05:27 +04:00 committed by Emil Mikulic
parent 1b10a57f39
commit ab7af194e6
2 changed files with 67 additions and 0 deletions

4
README
View File

@ -45,6 +45,10 @@ Use acceptfilter (FreeBSD only):
Run in the background and create a pidfile: Run in the background and create a pidfile:
$ ./darkhttpd /var/www/htdocs --pidfile /var/run/httpd.pid --daemon $ ./darkhttpd /var/www/htdocs --pidfile /var/run/httpd.pid --daemon
Web forward (301) requests for some hosts:
$ ./darkhttpd /var/www/htdocs --forward example.com http://www.example.com \
--forward secure.example.com https://www.example.com/secure
Commandline options can be combined: Commandline options can be combined:
$ ./darkhttpd ~/public_html --port 8080 --addr 127.0.0.1 $ ./darkhttpd ~/public_html --port 8080 --addr 127.0.0.1

View File

@ -227,6 +227,14 @@ struct connection {
total_sent; /* header + body = total, for logging */ total_sent; /* header + body = total, for logging */
}; };
struct web_forward_record {
const char *host;
const char *target;
struct web_forward_record *next;
};
struct web_forward_record *web_forward = NULL;
struct mime_mapping { struct mime_mapping {
char *extension, *mimetype; char *extension, *mimetype;
}; };
@ -552,6 +560,21 @@ static char *make_safe_url(char *url) {
return url; return url;
} }
static void add_web_forward(const char * const host, const char * const target) {
if (debug)
printf("add web forward %s -> %s\n",
host, target);
struct web_forward_record **ref_ptr = &web_forward;
while(*ref_ptr) {
ref_ptr = &((*ref_ptr)->next);
}
(*ref_ptr) = xmalloc(sizeof(struct web_forward_record));
(*ref_ptr)->host = host;
(*ref_ptr)->target = target;
(*ref_ptr)->next = NULL;
}
/* Associates an extension with a mimetype in the mime_map. Entries are in /* Associates an extension with a mimetype in the mime_map. Entries are in
* unsorted order. Makes copies of extension and mimetype strings. * unsorted order. Makes copies of extension and mimetype strings.
*/ */
@ -867,6 +890,11 @@ static void usage(const char *argv0) {
printf("\t--accf (default: don't use acceptfilter)\n" printf("\t--accf (default: don't use acceptfilter)\n"
"\t\tUse acceptfilter. Needs the accf_http module loaded.\n\n"); "\t\tUse acceptfilter. Needs the accf_http module loaded.\n\n");
#endif #endif
printf("\t--forward host url (default: don't forward)\n"
"\t\tWeb forward (301 redirect).\n"
"\t\tRequests to the host are redirected to the corresponding url.\n"
"\t\tThe option may be specified multiple times. In the case\n"
"\t\tthe host is matched in the order of appearance.\n\n");
} }
/* Returns 1 if string is a number, 0 otherwise. Set num to NULL if /* Returns 1 if string is a number, 0 otherwise. Set num to NULL if
@ -978,6 +1006,15 @@ static void parse_commandline(const int argc, char *argv[]) {
else if (strcmp(argv[i], "--accf") == 0) { else if (strcmp(argv[i], "--accf") == 0) {
want_accf = 1; want_accf = 1;
} }
else if (strcmp(argv[i], "--forward") == 0) {
if (++i >= argc)
errx(1, "missing host after --forward");
const char * const host = argv[i];
if (++i >= argc)
errx(1, "missing url after --forward");
const char * const url = argv[i];
add_web_forward(host, url);
}
else else
errx(1, "unknown argument `%s'", argv[i]); errx(1, "unknown argument `%s'", argv[i]);
} }
@ -1709,6 +1746,32 @@ static void process_get(struct connection *conn) {
return; return;
} }
/* test the host against web forward options */
{
char *host = parse_field(conn, "Host: ");
if(host) {
if (debug)
printf("host=\"%s\"\n", host);
struct web_forward_record *ptr = web_forward;
for(; ptr; ptr=ptr->next) {
if (debug)
printf("test for web forward record \"%s\" -> \"%s\"\n", ptr->host, ptr->target);
if(!strcasecmp(ptr->host, host)) {
redirect(conn, "%s%s", ptr->target, decoded_url);
free(decoded_url);
free(host);
return;
}
}
free(host);
}
}
/* does it end in a slash? serve up url/index_name */ /* does it end in a slash? serve up url/index_name */
if (decoded_url[strlen(decoded_url)-1] == '/') { if (decoded_url[strlen(decoded_url)-1] == '/') {
xasprintf(&target, "%s%s%s", wwwroot, decoded_url, index_name); xasprintf(&target, "%s%s%s", wwwroot, decoded_url, index_name);