Implement --forward.
authorEgor Ivanov <crackcraft@gmail.com>
Sat, 20 Apr 2013 10:05:27 +0000 (14:05 +0400)
committerEmil Mikulic <emikulic@gmail.com>
Sun, 28 Apr 2013 12:58:40 +0000 (22:58 +1000)
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.

README
darkhttpd.c

diff --git a/README b/README
index f740db7..5122a1a 100644 (file)
--- a/README
+++ b/README
@@ -45,6 +45,10 @@ Use acceptfilter (FreeBSD only):
 Run in the background and create a pidfile:
        $ ./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:
        $ ./darkhttpd ~/public_html --port 8080 --addr 127.0.0.1
 
index 620c7ea..1a55eb3 100644 (file)
@@ -227,6 +227,14 @@ struct connection {
           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 {
     char *extension, *mimetype;
 };
@@ -552,6 +560,21 @@ static char *make_safe_url(char *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
  * 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"
     "\t\tUse acceptfilter.  Needs the accf_http module loaded.\n\n");
 #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
@@ -978,6 +1006,15 @@ static void parse_commandline(const int argc, char *argv[]) {
         else if (strcmp(argv[i], "--accf") == 0) {
             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
             errx(1, "unknown argument `%s'", argv[i]);
     }
@@ -1709,6 +1746,32 @@ static void process_get(struct connection *conn) {
         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 */
     if (decoded_url[strlen(decoded_url)-1] == '/') {
         xasprintf(&target, "%s%s%s", wwwroot, decoded_url, index_name);