URL handling
[hcoop/domtool2.git] / src / plugins / apache.sml
index 27641ab..4ea8f22 100644 (file)
@@ -22,6 +22,43 @@ structure Apache :> APACHE = struct
 
 open Ast
 
+val _ = Env.type_one "proxy_port"
+       Env.int
+       (fn n => n > 1024)
+
+val _ = Env.type_one "proxy_target"
+       Env.string
+       (fn s =>
+           let
+               fun default () = List.exists (fn s' => s = s') Config.Apache.proxyTargets
+           in
+               case String.fields (fn ch => ch = #":") s of
+                   ["http", "//localhost", rest] =>
+                   (case String.fields (fn ch => ch = #"/") rest of
+                        port :: _ =>
+                        (case Int.fromString port of
+                             NONE => default ()
+                           | SOME n => n > 1024 orelse default ())
+                      | _ => default ())
+                 | _ => default ()
+           end)
+
+val _ = Env.type_one "rewrite_arg"
+       Env.string
+       (CharVector.all Char.isAlphaNum)
+
+fun validLocation s =
+    size s > 0 andalso size s < 1000 andalso CharVector.all
+                                                (fn ch => Char.isAlphaNum ch
+                                                          orelse ch = #"-"
+                                                          orelse ch = #"_"
+                                                          orelse ch = #"."
+                                                          orelse ch = #"/") s
+
+val _ = Env.type_one "location"
+       Env.string
+       validLocation
+
 val dl = ErrorMsg.dummyLoc
 
 val _ = Main.registerDefault ("WebNodes",
@@ -48,6 +85,48 @@ val _ = Main.registerDefault ("ServerAdmin",
                              (TBase "email", dl),
                              (fn () => (EString (Domain.getUser () ^ "@" ^ Config.defaultDomain), dl)))
 
+
+val redirect_code = fn (EVar "temp", _) => SOME "temp"
+                    | (EVar "permanent", _) => SOME "permanent"
+                    | (EVar "seeother", _) => SOME "seeother"
+                    | (EVar "redir300", _) => SOME "300"
+                    | (EVar "redir301", _) => SOME "301"
+                    | (EVar "redir302", _) => SOME "302"
+                    | (EVar "redir303", _) => SOME "303"
+                    | (EVar "redir304", _) => SOME "304"
+                    | (EVar "redir305", _) => SOME "305"
+                    | (EVar "redir307", _) => SOME "307"
+                    | _ => NONE
+
+val flag = fn (EVar "redirect", _) => SOME "R"
+           | (EVar "forbidden", _) => SOME "F"
+           | (EVar "gone", _) => SOME "G"
+           | (EVar "last", _) => SOME "L"
+           | (EVar "chain", _) => SOME "C"
+           | (EVar "nosubreq", _) => SOME "NS"
+           | (EVar "nocase", _) => SOME "NC"
+           | (EVar "qsappend", _) => SOME "QSA"
+           | (EVar "noescape", _) => SOME "NE"
+           | (EVar "passthrough", _) => SOME "PT"
+           | (EApp ((EVar "mimeType", _), e), _) =>
+             Option.map (fn s => "T=" ^ s) (Env.string e)
+           | (EApp ((EVar "redirectWith", _), e), _) =>
+             Option.map (fn s => "R=" ^ s) (redirect_code e)
+           | (EApp ((EVar "skip", _), e), _) =>
+             Option.map (fn n => "S=" ^ Int.toString n) (Env.int e)
+           | (EApp ((EApp ((EVar "env", _), e1), _), e2), _) =>
+             (case Env.string e1 of
+                  NONE => NONE
+                | SOME s1 => Option.map (fn s2 => "E=" ^ s1 ^ ":" ^ s2)
+                                        (Env.string e2))
+
+           | _ => NONE
+
+val cond_flag = fn (EVar "cond_nocase", _) => SOME "NC"
+           | (EVar "ornext", _) => SOME "OR"
+           | _ => NONE
+
+
 val vhostsChanged = ref false
 
 val () = Slave.registerPreHandler
@@ -90,6 +169,8 @@ val () = Slave.registerPostHandler
 val vhostFiles : TextIO.outstream list ref = ref []
 fun write s = app (fn file => TextIO.output (file, s)) (!vhostFiles)
 
+val rewriteEnabled = ref false
+
 val () = Env.containerV_one "vhost"
         ("host", Env.string)
         (fn (env, host) =>
@@ -105,6 +186,7 @@ val () = Env.containerV_one "vhost"
                 val fullHost = host ^ "." ^ Domain.currentDomain ()
                 val confFile = fullHost ^ (if ssl then ".vhost_ssl" else ".vhost")
             in
+                rewriteEnabled := false;
                 vhostFiles := map (fn node =>
                                       let
                                           val file = Domain.domainFile {node = node,
@@ -134,4 +216,119 @@ val () = Env.containerV_one "vhost"
          fn () => (write "</VirtualHost>\n";
                    app TextIO.closeOut (!vhostFiles)))
 
+val () = Env.container_one "location"
+        ("prefix", Env.string)
+        (fn prefix =>
+            (write "\t<Location ";
+             write prefix;
+             write ">\n"),
+         fn () => write "\t</Location>\n")
+
+val () = Env.container_one "directory"
+        ("directory", Env.string)
+        (fn directory =>
+            (write "\t<Directory ";
+             write directory;
+             write ">\n"),
+         fn () => write "\t</Directory>\n")
+
+fun checkRewrite () =
+    if !rewriteEnabled then
+       ()
+    else
+       (write "\tRewriteEngine on\n";
+        rewriteEnabled := true)
+
+val () = Env.action_three "localProxyRewrite"
+        ("from", Env.string, "to", Env.string, "port", Env.int)
+        (fn (from, to, port) =>
+            (checkRewrite ();
+             write "\tRewriteRule\t";
+             write from;
+             write "\thttp://localhost:";
+             write (Int.toString port);
+             write "/";
+             write to;
+             write " [P]\n"))
+
+val () = Env.action_two "proxyPass"
+        ("from", Env.string, "to", Env.string)
+        (fn (from, to) =>
+                (write "\tProxyPass\t";
+                 write from;
+                 write "\t";
+                 write to;
+                 write "\n"))
+
+val () = Env.action_two "proxyPassReverse"
+        ("from", Env.string, "to", Env.string)
+        (fn (from, to) =>
+                (write "\tProxyPassReverse\t";
+                 write from;
+                 write "\t";
+                 write to;
+                 write "\n"))
+
+val () = Env.action_three "rewriteRule"
+        ("from", Env.string, "to", Env.string, "flags", Env.list flag)
+        (fn (from, to, flags) =>
+            (checkRewrite ();
+             write "\tRewriteRule\t";
+             write from;
+             write "\t";
+             write to;
+             case flags of
+                 [] => ()
+               | flag::rest => (write " [";
+                                write flag;
+                                app (fn flag => (write ",";
+                                                 write flag)) rest;
+                                write "]");
+             write "\n"))
+
+val () = Env.action_three "rewriteCond"
+        ("test", Env.string, "pattern", Env.string, "flags", Env.list cond_flag)
+        (fn (from, to, flags) =>
+            (checkRewrite ();
+             write "\tRewriteCond\t";
+             write from;
+             write "\t";
+             write to;
+             case flags of
+                 [] => ()
+               | flag::rest => (write " [";
+                                write flag;
+                                app (fn flag => (write ",";
+                                                 write flag)) rest;
+                                write "]");
+             write "\n"))
+
+val () = Env.action_two "alias"
+        ("from", Env.string, "to", Env.string)
+        (fn (from, to) =>
+            (write "\tAlias\t";
+             write from;
+             write " ";
+             write to;
+             write "\n"))
+
+val () = Env.action_two "scriptAlias"
+        ("from", Env.string, "to", Env.string)
+        (fn (from, to) =>
+            (write "\tScriptAlias\t";
+             write from;
+             write " ";
+             write to;
+             write "\n"))
+
+val () = Env.action_two "errorDocument"
+        ("code", Env.string, "handler", Env.string)
+        (fn (code, handler) =>
+            (write "\tErrorDocument\t";
+             write code;
+             write " ";
+             write handler;
+             write "\n"))
+
+
 end