Implement --forward-all to forward all requests to a given url.
authorEmil Mikulic <emikulic@gmail.com>
Fri, 14 Mar 2014 11:36:37 +0000 (22:36 +1100)
committerEmil Mikulic <emikulic@gmail.com>
Fri, 14 Mar 2014 11:40:55 +0000 (22:40 +1100)
Suggested and initially implemented by: Christian Hesse <mail@eworm.de>

README
darkhttpd.c
devel/cover
devel/test_forward_all.py [new file with mode: 0755]

diff --git a/README b/README
index 0447aef..6b9df13 100644 (file)
--- a/README
+++ b/README
@@ -49,9 +49,15 @@ 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
 
+Web forward (301) requests for all hosts:
+  $ ./darkhttpd /var/www/htdocs --forward example.com http://www.example.com \
+    --forward-all http://catchall.example.com
+
 Commandline options can be combined:
        $ ./darkhttpd ~/public_html --port 8080 --addr 127.0.0.1
 
 To see a full list of commandline options,
 run darkhttpd without any arguments:
        $ ./darkhttpd
+
+vim:set ts=2 sw=2 et tw=80:
index 741e021..2c921ef 100644 (file)
@@ -233,6 +233,7 @@ struct forward_mapping {
 
 static struct forward_mapping *forward_map = NULL;
 static size_t forward_map_size = 0;
+static const char *forward_all_url = NULL;
 
 struct mime_mapping {
     char *extension, *mimetype;
@@ -1019,6 +1020,11 @@ static void parse_commandline(const int argc, char *argv[]) {
             url = argv[i];
             add_forward_mapping(host, url);
         }
+        else if (strcmp(argv[i], "--forward-all") == 0) {
+            if (++i >= argc)
+                errx(1, "missing url after --forward-all");
+            forward_all_url = argv[i];
+        }
         else if (strcmp(argv[i], "--no-server-id") == 0) {
             want_server_id = 0;
         }
@@ -1752,6 +1758,7 @@ static void process_get(struct connection *conn) {
     char *decoded_url, *target, *if_mod_since;
     char date[DATE_LEN], lastmod[DATE_LEN];
     const char *mimetype = NULL;
+    const char *forward_to = NULL;
     struct stat filestat;
 
     /* work out path of file being requested */
@@ -1774,16 +1781,21 @@ static void process_get(struct connection *conn) {
                 printf("host=\"%s\"\n", host);
             for (i = 0; i < forward_map_size; i++) {
                 if (strcasecmp(forward_map[i].host, host) == 0) {
-                    redirect(conn, "%s%s",
-                             forward_map[i].target_url, decoded_url);
-                    free(host);
-                    free(decoded_url);
-                    return;
+                    forward_to = forward_map[i].target_url;
+                    break;
                 }
             }
             free(host);
         }
     }
+    if (!forward_to) {
+        forward_to = forward_all_url;
+    }
+    if (forward_to) {
+        redirect(conn, "%s%s", forward_to, decoded_url);
+        free(decoded_url);
+        return;
+    }
 
     /* does it end in a slash? serve up url/index_name */
     if (decoded_url[strlen(decoded_url)-1] == '/') {
index 5c82b09..b431d24 100755 (executable)
@@ -31,7 +31,7 @@ python test.py
 kill $PID
 wait $PID
 
-echo "===> run forwarding tests"
+echo "===> run --forward tests"
 ./a.out $DIR --port $PORT \
   --forward example.com http://www.example.com \
   --forward secure.example.com https://www.example.com/secure >/dev/null &
@@ -41,7 +41,17 @@ python test_forward.py
 kill $PID
 wait $PID
 
-echo "===> run no-server-id tests"
+echo "===> run --forward-all tests"
+./a.out $DIR --port $PORT \
+  --forward example.com http://www.example.com \
+  --forward-all http://catchall.example.com >/dev/null &
+PID=$!
+kill -0 $PID || exit 1
+python test_forward_all.py
+kill $PID
+wait $PID
+
+echo "===> run --no-server-id tests"
 ./a.out $DIR --port $PORT --no-server-id >/dev/null &
 PID=$!
 kill -0 $PID || exit 1
diff --git a/devel/test_forward_all.py b/devel/test_forward_all.py
new file mode 100755 (executable)
index 0000000..93efe4b
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+# This is run by the "cover" script.
+import unittest
+from test import TestHelper, Conn, parse
+
+class TestForwardAll(TestHelper):
+    def test_forward_root(self):
+        resp = Conn().get("/", req_hdrs = { "Host": "not-example.com" })
+        status, hdrs, body = parse(resp)
+        self.assertContains(status, "301 Moved Permanently")
+        expect = "http://catchall.example.com/"
+        self.assertEquals(hdrs["Location"], expect)
+        self.assertContains(body, expect)
+
+    def test_forward_relative(self):
+        resp = Conn().get("/foo/bar",
+                          req_hdrs = { "Host": "still-not.example.com" })
+        status, hdrs, body = parse(resp)
+        self.assertContains(status, "301 Moved Permanently")
+        expect = "http://catchall.example.com/foo/bar"
+        self.assertEquals(hdrs["Location"], expect)
+        self.assertContains(body, expect)
+
+if __name__ == '__main__':
+    unittest.main()
+
+# vim:set ts=4 sw=4 et: