racket/collects/web-server/docs/reference/lang.scrbl
Jay McCarthy 918d5d485b Updating
svn: r6518
2007-06-07 16:21:22 +00:00

251 lines
10 KiB
Racket

#reader(lib "docreader.ss" "scribble")
@require["../web-server.ss"]
@title[#:tag "lang"
#:style 'toc]{Web Language Servlets}
The @file{web-server} allows servlets to be written in a special Web
language that is nearly identical to Scheme. Herein we discuss how it
is different and what API is provided.
@local-table-of-contents[]
@; ------------------------------------------------------------
@section[#:tag "lang-servlets"]{Definition}
A @defterm{Web language servlet} is a module written in the
@scheme[(lib "lang.ss" "web-server")] module language. It should provide
the following identifier:
@defproc[(start [initial-request request?])
response?]{
This function is called when this servlet is invoked.
The argument is the HTTP request that initiated the servlet.
}
@; XXX Cite paper
@; ------------------------------------------------------------
@section[#:tag "considerations"]{Usage Considerations}
A servlet has the following process performed on it automatically:
@itemize[
@item{All uses of @scheme[letrec] are removed and replaced with equivalent uses of
@scheme[let] and imperative features. (@file{lang/elim-letrec.ss})}
@item{The program is converted into ANF (Administrative Normal Form),
making all continuations explicit. (@file{lang/anormal.ss})}
@item{All continuations (and other continuations marks) are recorded in the
continuation marks of the expression
they are the continuation of. (@file{lang/elim-callcc.ss})}
@item{All calls to external modules are identified and marked.
(@file{lang/elim-callcc.ss})}
@item{All uses of @scheme[call/cc] are removed and replaced with
equivalent gathering of the continuations through the continuation-marks.
(@file{lang/elim-callcc.ss})}
@item{The program is defunctionalized with a serializable data-structure for each
anonymous lambda. (@file{lang/defun.ss})}
]
This process allows the continuations captured by your servlet to be serialized.
This means they may be stored on the client's browser or the server's disk.
Thus, your servlet has no cost to the server other than execution. This is
very attractive if you've used Scheme servlets and had memory problems.
This process IS defined on all of PLT Scheme and occurs AFTER macro-expansion,
so you are free to use all interesting features of PLT Scheme. However, there
are some considerations you must make.
First, this process drastically changes the structure of your program. It
will create an immense number of lambdas and structures your program
did not normally contain. The performance implication of this has not been
studied with PLT Scheme. However, it is theoretically a benefit. The main
implications would be due to optimizations MzScheme attempts to perform
that will no longer apply. Ideally, your program should be optimized first.
Second, the defunctionalization process is sensitive to the syntactic structure
of your program. Therefore, if you change your program in a trivial way, for example,
changing a constant, then all serialized continuations will be obsolete and will
error when deserialization is attempted. This is a feature, not a bug!
Third, the values in the lexical scope of your continuations must be serializable
for the continuations itself to be serializable. This means that you must use
@scheme[define-serializable-struct] rather than @scheme[define-struct], and take
care to use modules that do the same. Similarly, you may not use @scheme[parameterize],
because parameterizations are not serializable.
Fourth, and related, this process only runs on your code, not on the code you
@scheme[require]. Thus, your continuations---to be capturable---must not
be in the context of another module. For example, the following will not work:
@schemeblock[
(define requests
(map (lambda (rg) (send/suspend/url rg))
response-generators))
]
because @scheme[map] is not transformed by the process. However, if you defined
your own @scheme[map] function, there would be no problem.
Fifth, the store is NOT serialized. If you rely on the store you will
be taking huge risks. You will be assuming that the serialized continuation
is invoked before the server is restarted or the memory is garbage collected.
@; ------------------------------------------------------------
@section[#:tag "reprovided"]{Reprovided API}
The APIs from @scheme[(lib "url.ss" "net")], @secref["request-structs.ss"],
@secref["response-structs.ss"], and @secref["helpers.ss"] are reprovided
by the Web language API.
@; ------------------------------------------------------------
@section[#:tag "lang/web.ss"]{Web}
@file{lang/web.ss} provides the most basic Web functionality.
@defproc[(send/suspend/url [response-generator (url? . -> . response?)])
request?]{
Captures the current continuation. Serializes it and stuffs it into
a URL. Calls @scheme[response-generator] with this URL and delivers
the response to the client. If the URL is invoked
the request is returned to this continuation.
}
@defproc[(send/suspend/hidden [response-generator (url? xexpr? . -> . response?)])
request?]{
Captures the current continuation. Serializes it and generates an INPUT
form that includes the serialization as a hidden form.
Calls @scheme[response-generator] with this URL and form field and delivers
the response to the client. If the URL is invoked with form data containing
the hidden form,
the request is returned to this continuation.
Note: The continuation is NOT stuffed.
}
@defproc[(embed-proc/url [k-url url?]
[proc (request? . -> . any/c)])
url?]{
Serializes and stuffs @scheme[proc] into @scheme[k-url]. For use with
@scheme[extract-proc/url].
}
@defproc[(extract-proc/url [req request?])
any/c]{
Inspects the URL of @scheme[req] and attempts to extract the procedure
embedded with @scheme[embed-proc/url]. If successful, it is invoked with
@scheme[req] as an argument.
}
@; ------------------------------------------------------------
@section[#:tag "lang/stuff-url.ss"]{Stuff URL}
@file{lang/stuff-url.ss} provides an interface for "stuffing"
serializable values into URLs. Currently there is a particular
hard-coded behavior, but we hope to make it more flexible in
the future.
@defproc[(stuff-url [v serializable?]
[u url?])
url?]{
Serializes @scheme[v] and computes the MD5 of the serialized
representation. The serialization of @scheme[v] is written to
@file{$HOME/.urls/M} where `M' is the MD5. `M' is then
placed in @scheme[u] as a URL param.
}
@defproc[(stuffed-url? [u url?])
boolean?]{
Checks if @scheme[u] appears to be produced by @scheme[stuff-url].
}
@defproc[(unstuff-url [u url?])
serializable?]{
Extracts the value previously serialized into @scheme[u] by @scheme[stuff-url].
}
In the future, we will offer the facilities to:
@itemize[
@item{Optionally use the content-addressed storage.}
@item{Use different hashing algorithms for the CAS.}
@item{Encrypt the serialized value.}
@item{Only use the CAS if the URL would be too long. (URLs may only be 1024 characters.)}
]
@; ------------------------------------------------------------
@section[#:tag "lang/web-extras.ss"]{Web Extras}
@file{lang/web-extras.ss} provides @scheme[send/suspend/dispatch] and
@scheme[redirect/get] as @secref["web.ss"], except they use
@scheme[embed-proc/url] + @scheme[extract-proc/url] and
@scheme[send/suspend/url] respectively.
@; XXX Make warning cool
@; ------------------------------------------------------------
@section[#:tag "lang/file-box.ss"]{File Boxes}
As mentioned earlier, it is dangerous to rely on the store in
Web Language servlets, due to the deployment scenarios available
to them. @file{lang/file-box.ss} provides a simple API to replace
boxes in a safe way.
@defproc[(file-box? [v any/c])
boolean?]{Checks if @scheme[v] is a file-box.}
@defproc[(file-box [p path?]
[v serializable?])
file-box?]{
Creates a file-box that is stored at @scheme[p], with the default
contents of @scheme[v].
}
@defproc[(file-unbox [fb file-box?])
serializable?]{
Returns the value inside @scheme[fb]
}
@defproc[(file-box-set? [fb file-box?])
boolean?]{
Returns @scheme[#t] if @scheme[fb] contains a value.
}
@defproc[(file-box-set! [fb file-box?]
[v serializable?])
void]{
Saves @scheme[v] in the file represented by @scheme[fb].
}
Warning: If you plan on using a load-balancer, make sure your file-boxes
are on a shared medium.
@; ------------------------------------------------------------
@section[#:tag "lang/web-param.ss"]{Web Parameters}
As mentioned earlier, it is not easy to use @scheme[parameterize] in the
Web Language. @file{lang/web-param.ss} provides (roughly) the same
functionality in a way that is serializable. Like other serializable
things in the Web Language, they are sensitive to source code modification.
@defform[(make-web-parameter default)]{
Expands to the definition of a web-parameter with
@scheme[default] as the default value. A web-parameter is
a procedure that, when called with zero arguments, returns @scheme[default]
or the last value @scheme[web-parameterize]d in the dynamic context
of the call.
}
@defproc[(web-parameter? [v any/c])
boolean?]{
Checks if @scheme[v] appears to be a web-parameter.
}
@defform[(web-parameterize ([web-parameter-expr value-expr] ...) expr ...)]{
Runs @scheme[(begin expr ...)] such that the web-parameters that
the @scheme[web-parameter-expr]s evaluate to are bound to the @scheme[value-expr]s.
From the perspective of the @scheme[value-expr]s, this is like @scheme[let].
}
@; ------------------------------------------------------------
@section[#:tag "lang/web-cells.ss"]{Web Cells}
@file{lang/web-cells.ss} provides the same API as @secref["web-cells.ss"],
but in a way compatible with the Web Language. The one difference is that
@scheme[make-web-cell] is syntax, rather than a function.