diff --git a/basis/http/server/rewrite/rewrite-docs.factor b/basis/http/server/rewrite/rewrite-docs.factor new file mode 100644 index 0000000000..478adbab69 --- /dev/null +++ b/basis/http/server/rewrite/rewrite-docs.factor @@ -0,0 +1,72 @@ +IN: http.server.rewrite +USING: help.syntax help.markup http.server ; + +HELP: rewrite +{ $class-description "The class of directory rewrite responders. The slots are as follows:" +{ $list + { { $slot "default" } " - the responder to call if no file name is provided." } + { { $slot "child" } " - the responder to call if a file name is provided." } + { { $slot "param" } " - the name of a request parameter which will store the first path component of the file name passed to the responder." } +} } ; + +HELP: +{ $values { "rewrite" rewrite } } +{ $description "Creates a new " { $link rewrite } " responder." } +{ $examples + { $code + "" + " >>default" + " >>child" + " \"comment_id\" >>param" + } +} ; + +HELP: vhost-rewrite +{ $class-description "The class of virtual host rewrite responders. The slots are as follows:" +{ $list + { { $slot "default" } " - the responder to call if no host name prefix is provided." } + { { $slot "child" } " - the responder to call if a host name prefix is provided." } + { { $slot "param" } " - the name of a request parameter which will store the first host name component of the host name passed to the responder." } + { { $slot "suffix" } " - the domain name suffix which will be chopped off the end of the request's host name in order to produce the parameter." } +} } ; + +HELP: +{ $values { "vhost-rewrite" vhost-rewrite } } +{ $description "Creates a new " { $link vhost-rewrite } " responder." } +{ $examples + { $code + "" + " >>default" + " >>child" + " \"blog_id\" >>param" + " \"blogs.vegan.net >>suffix" + } +} ; + +ARTICLE: "http.server.rewrite.overview" "Rewrite responder overview" +"Rewrite responders take the file name and turn it into a request parameter named by the " { $slot "param" } " slot before delegating to a child responder. If a file name is provided, it calls the responder in the " { $slot "child" } " slot. If no file name is provided, they call the default responder in the " { $slot "default" } " slot." +$nl +"For example, suppose you want to have the following website schema:" +{ $list +{ { $snippet "/posts/" } " - show a list of posts" } +{ { $snippet "/posts/factor_language" } " - show thread with ID " { $snippet "factor_language" } } +{ { $snippet "/posts/factor_language/1" } " - show first comment in the thread with ID " { $snippet "factor_language" } } +{ { $snippet "/animals" } ", ... - a bunch of other actions" } } +"One way to achieve this would be to have a nesting of responders as follows:" +{ $list +{ "A dispatcher at the top level" } + { "A " { $link rewrite } " as a child of the dispatcher under the name " { $snippet "posts" } ". The rewrite has the " { $slot "param" } " slot set to, say, " { $snippet "post_id" } ". The " { $slot "default" } " slot is set to a Furnace action which displays a list of posts." } + { "The child slot is set to a second " { $link rewrite } " instance, with " { $snippet "param" } " set to " { $snippet "comment_id" } ", the " { $slot "default" } " slot set to an action which displays a post identified by the " { $snippet "post_id" } " parameter, and the " { $snippet "child" } " slot set to an action which displays the comment identified by the " { $snippet "comment_id" } " parameter." } } +"Note that parameters can be extracted from the request using the " { $link param } " word, but most of the time you want to use " { $vocab-link "furnace.actions" } " instead." ; + +ARTICLE: "http.server.rewrite" "URL rewrite responders" +"The " { $vocab-link "http.server.rewrite" } " vocabulary defines two responder types which can help make website URLs more human-friendly." +{ $subsection "http.server.rewrite.overview" } +"Directory rewrite responders:" +{ $subsection rewrite } +{ $subsection } +"Virtual host rewrite responders -- these chop off the value in the " { $snippet "suffix" } " slot from the tail of the host name, and use the rest as the parameter value:" +{ $subsection vhost-rewrite } +{ $subsection } ; + +ABOUT: "http.server.rewrite" \ No newline at end of file diff --git a/basis/http/server/rewrite/rewrite-tests.factor b/basis/http/server/rewrite/rewrite-tests.factor new file mode 100644 index 0000000000..3a053c3a9c --- /dev/null +++ b/basis/http/server/rewrite/rewrite-tests.factor @@ -0,0 +1,48 @@ +USING: accessors arrays http.server http.server.rewrite kernel +namespaces tools.test urls ; +IN: http.server.rewrite.tests + +TUPLE: rewrite-test-default ; + +M: rewrite-test-default call-responder* + drop "DEFAULT!" 2array ; + +TUPLE: rewrite-test-child ; + +M: rewrite-test-child call-responder* + drop "rewritten-param" param 2array ; + +V{ } clone responder-nesting set +H{ } clone params set + + + rewrite-test-child new >>child + rewrite-test-default new >>default + "rewritten-param" >>param +"rewrite" set + +[ { { } "DEFAULT!" } ] [ { } "rewrite" get call-responder ] unit-test +[ { { } "xxx" } ] [ { "xxx" } "rewrite" get call-responder ] unit-test +[ { { "blah" } "xxx" } ] [ { "xxx" "blah" } "rewrite" get call-responder ] unit-test + + + rewrite-test-child new >>child + rewrite-test-default new >>default + "rewritten-param" >>param + "blogs.vegan.net" >>suffix +"rewrite" set + +[ { { } "DEFAULT!" } ] [ + URL" http://blogs.vegan.net" url set + { } "rewrite" get call-responder +] unit-test + +[ { { } "DEFAULT!" } ] [ + URL" http://www.blogs.vegan.net" url set + { } "rewrite" get call-responder +] unit-test + +[ { { } "erg" } ] [ + URL" http://erg.blogs.vegan.net" url set + { } "rewrite" get call-responder +] unit-test \ No newline at end of file diff --git a/basis/http/server/rewrite/rewrite.factor b/basis/http/server/rewrite/rewrite.factor new file mode 100644 index 0000000000..ec6b7efed2 --- /dev/null +++ b/basis/http/server/rewrite/rewrite.factor @@ -0,0 +1,33 @@ +! Copyright (C) 2009 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: accessors http.server kernel namespaces sequences +splitting urls ; +IN: http.server.rewrite + +TUPLE: rewrite param child default ; + +: ( -- rewrite ) + rewrite new ; + +M: rewrite call-responder* + over empty? [ default>> ] [ + [ [ first ] [ param>> ] bi* set-param ] + [ [ rest ] [ child>> ] bi* ] + 2bi + ] if + call-responder* ; + +TUPLE: vhost-rewrite suffix param child default ; + +: ( -- vhost-rewrite ) + vhost-rewrite new ; + +: sub-domain? ( vhost-rewrite url -- subdomain ? ) + swap suffix>> dup [ + [ host>> canonical-host ] [ "." prepend ] bi* ?tail + ] [ 2drop f f ] if ; + +M: vhost-rewrite call-responder* + dup url get sub-domain? + [ over param>> set-param child>> ] [ drop default>> ] if + call-responder ; \ No newline at end of file