You are looking at historical revision 15382 of this page. It may differ significantly from its current revision.
Description
uri-dispatch is a simple mechanism to dispatch uris to procedures. This is useful for webprogramming where you might want to map uris of a certain kind to procedures that implement the logic for those uris.
Author
Requirements
Requires the uri-common and environments extensions.
Documentation
[procedure] (dispatch-uri URI)The main interface to dispatch-uri. This procedure invokes the dispatch-mechanism with the supplied uri. The dispatch-algorithm is implemented as follows:
(Note Although not explicitly stated here the algorithm performs a whitelist-check on any procedure before it is invoked. See enable-whitelisting and whitelist!)
- The path is empty. It checks if default-dispatch-target is bound to a procedure. If it is, then it is invoked. If it is not, then dispatch-error is invoked.
- The path has exactly one element. It assumes that this element is the name of a thunk that was defined outside a module. If such a thunk exists it is invoked. If no such a thunk exists dispatch-error.is invoked.
- The path contains at least two elements.
- It checks if the second element is a procedure defined in a module named by the first element. So if it sees (foo bar) it tries to find the procedure foo inside the module bar. If the procedure exists it is invoked with the rest of the elements as arguments.
- If it does not exist, it interpretes the first element as the name of a procedure that was defined outside any module. If such a procedure exists, it is invoked passing the rest of the elements as arguments. If no such procedure exists dispatch-error is invoked with the full path as arguments. The path is applied to the procedure so you can use for example dsssl-style lambdalists to declare optional arguments or a rest-argument.
Though nice for development it is not advisable to allow anybody out there to invoke abritary procedures of your application. So you might want to enable-whitelisting in production and whitelist only those modules and/or procedures you really want to be callable from the outside. Whis procedure expects a list that defines the procedure/modules you want to whitelist. If a procedure is requested that does exist but is not whitelisted dispatch-error is invoked. You have basically two possibilities to perform whitelisting, all of which can be combined.
1) whitelist procedures outside modules <pre>(whitelist! '(procedure1 procedure2 procedure3))</pre>
2) whitelist all procedures inside a module <pre>(whitelist! '((module my-module my-module2))</pre>
In the near future you will have the following possibilities as well:
whitelist specific procedures inside a module <pre>(whitelist! '((module-name procedure1 procedure2)))</pre>
It is also planned to implement some keywords that allow easier use of this procedure.
[parameter] dispatch-errorIf no handler for a uri can be found, the dispatcher will invoke the procedure that dispatch-error is currently parameterized with. NOTE dispatch-error is also invoked if the requested handler exists but is not whitelisted.
[parameter] enable-whitelistingIf set to #t then whitelist-checks are enabled. Defaults to #f. <parameter>default-dispatch-target</parameter>
A thunk that is invoke when the uri-path was empty. If set to #f then an empty path leads to the invocation of dispatch-error. Defaults to #f.
[parameter] dispatch-environmentThe environment that is used to lookup the procedures. It defaults to current-interaction-environment.
Examples
<pre>
(use spiffy intarweb uri-common uri-dispatch)
(define (my-dispatch-error . path)
(send-status 404 (sprintf "My Dispatch-error ~A" path)))
(module example
(echo webiota) (import scheme chicken srfi-1 extras) (require-library spiffy) (import (only spiffy send-status)) (define (webiota #!optional (start "0") (steps "10") #!rest rest) (send-status 200 (sprintf "webiota called: ~A" (iota (string->number steps) (string->number start))))) (define (echo . args) (send-status 200 (sprintf "echo: ~A" args))))
(define (outsidemodule . args) (send-status 200 "Outside module"))
(vhost-map `(("localhost" . ,(lambda (continue)
(parameterize ((handle-not-found (lambda (path) (dispatch-uri (request-uri (current-request))))) (dispatch-error (lambda path (send-status 404 (sprintf "Path not found: ~A" path))))) (continue))))))
(start-server) </pre>
Now start the server and visit the following pages:
- http://localhost:8080/example/webiota/2/10/
- http://localhost:8080/example/webiota/2/20/
- http://localhost:8080/example/webiota/echo/this/please
- http://localhost:8080/outsidemodule
- http://localhost:8080/i/do/not/exist