Redoing documentation layout

svn: r12418
This commit is contained in:
Jay McCarthy 2008-11-12 23:45:00 +00:00
parent cc69a51813
commit d56eed754b
33 changed files with 881 additions and 738 deletions

View File

@ -1,7 +1,6 @@
#lang scheme/base
(require (planet "test.ss" ("schematics" "schemeunit.plt" 2))
web-server/http
web-server/servlet/helpers)
web-server/servlet)
(provide helpers-tests)
(define (dehead hs)

View File

@ -1,18 +1,16 @@
#lang scheme
(require net/url
web-server/http
"abort-resume.ss"
"web.ss"
"web-cells.ss"
"web-param.ss"
"file-box.ss"
"web-extras.ss")
web-server/lang/abort-resume
web-server/lang/web
web-server/lang/web-cells
web-server/lang/web-param
web-server/lang/file-box)
(provide (except-out (all-from-out scheme) #%module-begin)
(all-from-out net/url
web-server/http
"abort-resume.ss"
"web.ss"
"web-cells.ss"
"web-param.ss"
"file-box.ss"
"web-extras.ss"))
web-server/lang/abort-resume
web-server/lang/web
web-server/lang/web-cells
web-server/lang/web-param
web-server/lang/file-box))

View File

@ -1,10 +0,0 @@
#lang scheme/base
(require net/url
scheme/contract
"web.ss"
web-server/http)
(provide/contract
[redirect/get (-> request?)])
(define (redirect/get)
(send/suspend/url (lambda (k-url) (redirect-to (url->string k-url) temporarily))))

View File

@ -85,3 +85,9 @@
[(struct binding:form (id kont))
(deserialize (read (open-input-bytes kont)))]
[_ #f])))
(provide/contract
[redirect/get (-> request?)])
(define (redirect/get)
(send/suspend/url (lambda (k-url) (redirect-to (url->string k-url) temporarily))))

View File

@ -13,7 +13,7 @@ configuring the @web-server .
@section[#:tag "configuration-table-structs.ss"]{Configuration Table Structure}
@(require (for-label web-server/configuration/configuration-table-structs))
@defmodule[web-server/configuration/configuration-table-structs]
@defmodule[web-server/configuration/configuration-table-structs]{
@filepath{configuration/configuration-table-structs.ss} provides the following structures that
represent a standard configuration (see @secref["web-server-unit.ss"]) of the @web-server .
@ -79,11 +79,14 @@ the configuration table S-expression file format described in
[mime-types (or/c false/c path-string?)]
[passwords (or/c false/c path-string?)])]
}
@; ------------------------------------------------------------
@section[#:tag "configuration-table.ss"]{Configuration Table}
@(require (for-label web-server/configuration/configuration-table))
@(require (for-label web-server/dispatchers/dispatch-log))
@defmodule[web-server/configuration/configuration-table]
@defmodule[web-server/configuration/configuration-table]{
@filepath{configuration/configuration-table.ss} provides functions for
reading, writing, parsing, and printing @scheme[configuration-table]
@ -147,8 +150,6 @@ where a @scheme[host-table-sexpr] is:
In this syntax, the @scheme['messages] paths are relative to the @scheme['configuration-root] directory.
All the paths in @scheme['paths] are relative to @scheme['host-root] (other than @scheme['host-root] obviously.)
@(require (for-label web-server/dispatchers/dispatch-log))
Allowable @scheme['log-format]s are those accepted by @scheme[log-format->format].
Note: You almost always want to leave everything in the @scheme['paths] section the default except the @scheme['host-root].
@ -162,12 +163,14 @@ This function reads a @scheme[configuration-table] from @scheme[path].
void]{
This function writes a @scheme[configuration-table] to @scheme[path].
}
}
@; ------------------------------------------------------------
@section[#:tag "namespace.ss"]{Servlet Namespaces}
@(require (for-label web-server/configuration/namespace))
@defmodule[web-server/configuration/namespace]
@defmodule[web-server/configuration/namespace]{
@filepath{configuration/namespace.ss} provides a function to help create the
@scheme[make-servlet-namespace] procedure needed by the @scheme[make] functions
@ -195,6 +198,8 @@ Example:
#:to-be-copied-module-specs `((lib "database.ss" "my-module")))
]
}
}
@subsection{Why this is useful}
@ -215,7 +220,7 @@ of servlets can share different sets of modules.
@section[#:tag "responders.ss"]{Standard Responders}
@(require (for-label web-server/configuration/responders))
@defmodule[web-server/configuration/responders]
@defmodule[web-server/configuration/responders]{
@filepath{configuration/responders.ss} provides some functions that help constructing HTTP responders.
These functions are used by the default dispatcher constructor (see @secref["web-server-unit.ss"]) to
@ -278,3 +283,5 @@ the @scheme[header]s as, you guessed it, headers.
(-> response?)]{
Returns a function that generates a standard "Garbage collection run" message with content from @scheme[file].
}
}

View File

@ -34,7 +34,7 @@ documentation will be useful.
@section[#:tag "dispatch.ss"]{General}
@(require (for-label web-server/dispatchers/dispatch))
@defmodule[web-server/dispatchers/dispatch]
@defmodule[web-server/dispatchers/dispatch]{
@filepath{dispatchers/dispatch.ss} provides a few functions for dispatchers in general.
@ -75,11 +75,13 @@ Consider the following example dispatcher, that captures the essence of URL rewr
[request-uri (rule (request-uri req))]))))
]
}
@; ------------------------------------------------------------
@section[#:tag "filesystem-map.ss"]{Mapping URLs to Paths}
@(require (for-label web-server/dispatchers/filesystem-map))
@defmodule[web-server/dispatchers/filesystem-map]
@defmodule[web-server/dispatchers/filesystem-map]{
@filepath{dispatchers/filesystem-map.ss} provides a means of mapping
URLs to paths on the filesystem.
@ -114,6 +116,8 @@ URLs to paths on the filesystem.
servlets when using the servlet dispatchers. It will return a @scheme[exn:fail:filesystem:exists?] exception if
the path does not match.
}
}
@; ------------------------------------------------------------
@section[#:tag "dispatch-sequencer.ss"]{Sequencing}

View File

@ -1,5 +1,6 @@
#lang scheme/base
(define interface-version #f)
(define start #f)
(provide (all-defined-out))

View File

@ -3,7 +3,6 @@
(define interface-version #f)
(define timeout #f)
(define start #f)
(define manager #f)
(provide (all-defined-out))

View File

@ -0,0 +1,8 @@
#lang scheme/base
(define interface-version #f)
(define start #f)
(define manager #f)
(provide (all-defined-out))

View File

@ -0,0 +1,16 @@
#lang scribble/doc
@(require "web-server.ss")
@title[#:style 'toc]{Extending the Web Server}
@local-table-of-contents[]
@include-section["configuration.scrbl"]
@include-section["servlet-setup.scrbl"]
@include-section["dispatchers.scrbl"]
@include-section["web-config-unit.scrbl"]
@include-section["web-server-unit.scrbl"]
@include-section["private.scrbl"]

View File

@ -100,7 +100,7 @@ The rest of the manual gives the details of @tech{formlet} usage and extension.
@section{Syntactic Shorthand}
@(require (for-label web-server/formlets/syntax))
@defmodule[web-server/formlets/syntax]
@defmodule[web-server/formlets/syntax]{
Most users will want to use the syntactic shorthand for creating @tech{formlet}s.
@ -116,10 +116,12 @@ Most users will want to use the syntactic shorthand for creating @tech{formlet}s
@scheme[(#%# _xexpr ...)] renders an @xexpr forest.
}
}
@section{Functional Usage}
@(require (for-label web-server/formlets/lib))
@defmodule[web-server/formlets/lib]
@defmodule[web-server/formlets/lib]{
The syntactic shorthand abbreviates the construction of @deftech{formlet}s with the following library.
These combinators may be used directly to construct low-level formlets, such as those for new INPUT element
@ -191,11 +193,13 @@ types. Refer to @secref["input-formlets"] for example low-level formlets using t
any/c]{
Runs the processing stage of @scheme[f] on the bindings in @scheme[r].
}
}
@section[#:tag "input-formlets"]{Predefined Formlets}
@(require (for-label web-server/formlets/input))
@defmodule[web-server/formlets/input]
@defmodule[web-server/formlets/input]{
There are a few basic @tech{formlet}s provided by this library.
@ -213,10 +217,12 @@ There are a few basic @tech{formlet}s provided by this library.
Equivalent to @scheme[(cross (pure string->symbol) input-string)].
}
}
@section{Utilities}
@(require (for-label web-server/formlets/servlet))
@defmodule[web-server/formlets/servlet]
@defmodule[web-server/formlets/servlet]{
A few utilities are provided for using @tech{formlet}s in Web applications.
@ -232,3 +238,5 @@ A few utilities are provided for using @tech{formlet}s in Web applications.
xexpr?]{
Like @scheme[send/formlet], but for use with @scheme[send/suspend/dispatch].
}
}

View File

@ -14,7 +14,7 @@ The @web-server implements many HTTP RFCs that are provided by this module.
@section[#:tag "request-structs.ss"]{Requests}
@(require (for-label web-server/http/request-structs))
@defmodule[web-server/http/request-structs]
@defmodule[web-server/http/request-structs]{
@defstruct[header ([field bytes?]
[value bytes?])]{
@ -82,11 +82,13 @@ Here is an example typical of what you will find in many applications:
(get-number (request-number))]))
]
}
@; ------------------------------------------------------------
@section[#:tag "bindings.ss"]{Bindings}
@(require (for-label web-server/http/bindings))
@defmodule[web-server/http/bindings]
@defmodule[web-server/http/bindings]{
These functions, while convenient, could introduce subtle bugs into your
application. Examples: that they are case-insensitive could introduce
@ -142,11 +144,13 @@ Here is an example typical of what you will find in many applications:
(request-bindings req))))
]
}
@; ------------------------------------------------------------
@section[#:tag "response-structs.ss"]{Responses}
@(require (for-label web-server/http/response-structs))
@defmodule[web-server/http/response-structs]
@defmodule[web-server/http/response-structs]{
@defstruct[response/basic
([code number?]
@ -225,12 +229,13 @@ Here is an example typical of what you will find in many applications:
@warning{If you include a Content-Length header in a response that is inaccurate, there @bold{will be an error} in
transmission that the server @bold{will not catch}.}
}
@; ------------------------------------------------------------
@section[#:tag "redirect.ss"]{Redirect}
@(require (for-label web-server/http/redirect))
@defmodule[web-server/http/redirect]
@defmodule[web-server/http/redirect]{
@defproc[(redirect-to [uri string?]
[perm/temp redirection-status? temporarily]
@ -254,11 +259,13 @@ transmission that the server @bold{will not catch}.}
@defthing[see-other redirection-status?]{A @scheme[redirection-status?] for "see-other" redirections.}
}
@; ------------------------------------------------------------
@section[#:tag "basic-auth.ss"]{Basic Authentication}
@(require (for-label web-server/http/basic-auth))
@defmodule[web-server/http/basic-auth]
@defmodule[web-server/http/basic-auth]{
An implementation of HTTP Basic Authentication.
@ -270,3 +277,5 @@ An implementation of HTTP Basic Authentication.
Example:
@scheme[(extract-user-pass (request-headers/raw req))] might return @scheme[(cons #"aladin" #"open sesame")].
}
}

View File

@ -0,0 +1,27 @@
#lang scribble/doc
@(require "web-server.ss")
@; ------------------------------------------------------------
@title[#:tag "lang/web-cells.ss"]{Stateless Web Cells}
@(require (for-label web-server/lang/web-cells))
@defmodule[web-server/lang/web-cells]{The
@schememodname[web-server/lang/web-cells] library provides the same
API as @schememodname[web-server/servlet/web-cells], but in a way
compatible with the Web Language. The one difference is that
@scheme[make-web-cell] is syntax, rather than a function.
@deftogether[(
@defproc[(web-cell? [v any/c])
boolean?]
@defform[(make-web-cell default-expr)]
@defproc[(web-cell-ref [wc web-cell?])
any/c]
@defproc[(web-cell-shadow [wc web-cell?]
[v any/c])
void]
)]{
See @schememodname[web-server/servlet/web-cells].}
}

View File

@ -1,98 +1,20 @@
#lang scribble/doc
@(require "web-server.ss")
@title[#:tag "lang"
#:style 'toc]{Web Language}
@title[#:tag "lang/web.ss"]{Stateless Web Interaction}
@defmodulelang[web-server]
The @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.
@(require (for-label web-server/lang/abort-resume))
@defmodule[web-server/lang/abort-resume]{
@local-table-of-contents[]
@defproc[(send/suspend [response-generator (continuation? . -> . any)])
any]{
Captures the current continuation in a serializable way and calls @scheme[response-generator] with it, returning the result.
}
}
@; ------------------------------------------------------------
@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. (@filepath{lang/elim-letrec.ss})}
@item{The program is converted into ANF (Administrative Normal Form),
making all continuations explicit. (@filepath{lang/anormal.ss})}
@item{All continuations (and other continuations marks) are recorded in the
continuation marks of the expression
they are the continuation of. (@filepath{lang/elim-callcc.ss})}
@item{All calls to external modules are identified and marked.
(@filepath{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.
(@filepath{lang/elim-callcc.ss})}
@item{The program is defunctionalized with a serializable data-structure for each
anonymous lambda. (@filepath{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.
This process is derived from the paper
@href-link["http://www.cs.brown.edu/~sk/Publications/Papers/Published/pcmkf-cont-from-gen-stack-insp/" "\"Continuations from Generalized Stack Inspection\""].
We thank Greg Pettyjohn for his initial implementation of this algorithm.
@; ------------------------------------------------------------
@section[#:tag "reprovided"]{Reprovided API}
The APIs from @scheme[net/url], @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}
@(require (for-label web-server/lang/web))
@defmodule[web-server/lang/web]
@filepath{lang/web.ss} provides the most basic Web functionality.
@defmodule[web-server/lang/web]{
@defproc[(send/suspend/url [response-generator (url? . -> . response?)])
request?]{
@ -122,11 +44,18 @@ by the Web language API.
@scheme[send/suspend/dispatch].
}
@deftogether[(
@defproc[(redirect/get) request?]
)]{
See @schememodname[web-server/servlet/web].}
}
@; ------------------------------------------------------------
@section[#:tag "lang/stuff-url.ss"]{Stuff URL}
@(require (for-label web-server/lang/stuff-url))
@defmodule[web-server/lang/stuff-url]
@defmodule[web-server/lang/stuff-url]{
@filepath{lang/stuff-url.ss} provides an interface for "stuffing"
serializable values into URLs. Currently there is a particular
@ -164,112 +93,4 @@ In the future, we will offer the facilities to:
@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}
@(require (for-label web-server/lang/web-extras))
@defmodule[web-server/lang/web-extras]{The
@schememodname[web-server/lang/web-extras] library provides
@scheme[redirect/get] as
@schememodname[web-server/servlet/web] except it uses
@scheme[send/suspend/url].}
@deftogether[(
@defproc[(redirect/get) request?]
)]{
See @schememodname[web-server/servlet/web].}
@; ------------------------------------------------------------
@section[#:tag "lang/file-box.ss"]{File Boxes}
@(require (for-label web-server/lang/file-box))
@defmodule[web-server/lang/file-box]
As mentioned earlier, it is dangerous to rely on the store in
Web Language servlets, due to the deployment scenarios available
to them. @filepath{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}
@(require (for-label web-server/lang/web-param))
@defmodule[web-server/lang/web-param]
As mentioned earlier, it is not easy to use @scheme[parameterize] in the
Web Language. @filepath{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}
@(require (for-label web-server/lang/web-cells))
@defmodule[web-server/lang/web-cells]{The
@schememodname[web-server/lang/web-cells] library provides the same
API as @schememodname[web-server/servlet/web-cells], but in a way
compatible with the Web Language. The one difference is that
@scheme[make-web-cell] is syntax, rather than a function.}
@deftogether[(
@defproc[(web-cell? [v any/c])
boolean?]
@defform[(make-web-cell default-expr)]
@defproc[(web-cell-ref [wc web-cell?])
any/c]
@defproc[(web-cell-shadow [wc web-cell?]
[v any/c])
void]
)]{
See @schememodname[web-server/servlet/web-cells].}
}

View File

@ -18,7 +18,7 @@ pluggable through the manager interface.
@(require (for-label web-server/managers/manager)
(for-label web-server/servlet/servlet-structs))
@defmodule[web-server/managers/manager]
@defmodule[web-server/managers/manager]{
@filepath{managers/manager.ss} defines the manager interface. It is required by
the users and implementers of managers.
@ -59,12 +59,14 @@ the users and implementers of managers.
This exception should be thrown by a manager when a continuation is
looked up that does not exist.
}
}
@; ------------------------------------------------------------
@section[#:tag "none.ss"]{No Continuations}
@(require (for-label web-server/managers/none))
@defmodule[web-server/managers/none]
@defmodule[web-server/managers/none]{
@filepath{managers/none.ss} defines a manager constructor:
@ -81,13 +83,15 @@ the users and implementers of managers.
}
If you are considering using this manager, also consider using the
Web Language. (See @secref["lang"].)
Web Language. (See @secref["stateless-servlets"].)
}
@; ------------------------------------------------------------
@section[#:tag "timeouts.ss"]{Timeouts}
@(require (for-label web-server/managers/timeouts))
@defmodule[web-server/managers/timeouts]
@defmodule[web-server/managers/timeouts]{
@filepath{managers/timeouts.ss} defines a manager constructor:
@ -113,11 +117,13 @@ Web Language. (See @secref["lang"].)
This manager has been found to be... problematic... in large-scale
deployments of the @web-server .
}
@; ------------------------------------------------------------
@section[#:tag "lru.ss"]{LRU}
@(require (for-label web-server/managers/lru))
@defmodule[web-server/managers/lru]
@defmodule[web-server/managers/lru]{
@filepath{managers/lru.ss} defines a manager constructor:
@ -168,4 +174,5 @@ The recommended usage of this manager is codified as the following function:
continuations, until the memory is back under control. If the load
stays low, it will still efficiently expire old continuations.
}
}

View File

@ -14,7 +14,7 @@ Some of these are documented here.
@section[#:tag "timer.ss"]{Timers}
@(require (for-label web-server/private/timer))
@defmodule[web-server/private/timer]
@defmodule[web-server/private/timer]{
@filepath{private/timer.ss} provides a functionality for running
procedures after a given amount of time, that may be extended.
@ -55,12 +55,13 @@ procedures after a given amount of time, that may be extended.
Cancels the firing of @scheme[t] ever and frees resources used by @scheme[t].
}
}
@; ------------------------------------------------------------
@section[#:tag "connection-manager.ss"]{Connection Manager}
@(require (for-label web-server/private/connection-manager))
@defmodule[web-server/private/connection-manager]
@defmodule[web-server/private/connection-manager]{
@filepath{private/connection-manager.ss} provides functionality for managing pairs of
input and output ports. We have plans to allow a number of different strategies
@ -102,6 +103,8 @@ for doing this.
void]{
Calls @scheme[reset-timer!] with the timer behind @scheme[c] with @scheme[t].
}
}
@; ------------------------------------------------------------
@section[#:tag "dispatch-server-unit.ss"]{Dispatching Server}
@ -114,7 +117,7 @@ This dispatching server component is useful on its own.
@subsection{Dispatching Server Signatures}
@defmodule[web-server/private/dispatch-server-sig]
@defmodule[web-server/private/dispatch-server-sig]{
The @schememodname[web-server/private/dispatch-server-sig] library
provides two signatures.
@ -152,10 +155,11 @@ The @scheme[dispatch-server^] signature is an alias for
@defthing[dispatch dispatcher?]{How to handle requests.}
}
}
@subsection{Dispatching Server Unit}
@defmodule[web-server/private/dispatch-server-unit]
@defmodule[web-server/private/dispatch-server-unit]{
The @schememodname[web-server/private/dispatch-server-unit] module
provides the unit that actually implements a dispatching server.
@ -166,6 +170,8 @@ provides the unit that actually implements a dispatching server.
@secref["connection-manager.ss"] to manage connections.
}
}
@; ------------------------------------------------------------
@section[#:tag "closure.ss"]{Serializable Closures}
@(require (for-label web-server/private/closure)
@ -173,7 +179,7 @@ provides the unit that actually implements a dispatching server.
@defmodule[web-server/private/closure]{
The defunctionalization process of the Web Language (see @secref["lang"])
The defunctionalization process of the Web Language (see @secref["stateless-servlets"])
requires an explicit representation of closures that is serializable.
@filepath{private/closure.ss} is this representation. It provides:
@ -239,7 +245,7 @@ Here is an example:
@section[#:tag "cache-table.ss"]{Cache Table}
@(require (for-label web-server/private/cache-table))
@defmodule[web-server/private/cache-table]
@defmodule[web-server/private/cache-table]{
@filepath{private/cache-table.ss} provides a set of caching hash table
functions.
@ -267,11 +273,13 @@ functions.
Determines if @scheme[v] is a cache table.
}
}
@; ------------------------------------------------------------
@section[#:tag "mime-types.ss"]{MIME Types}
@(require (for-label web-server/private/mime-types))
@defmodule[web-server/private/mime-types]
@defmodule[web-server/private/mime-types]{
@filepath{private/mime-types.ss} provides function for dealing with @filepath{mime.types}
files.
@ -287,12 +295,14 @@ files.
Uses a @scheme[read-mime-types] with @scheme[p] and constructs a
function from paths to their MIME type.
}
}
@; ------------------------------------------------------------
@section[#:tag "mod-map.ss"]{Serialization Utilities}
@(require (for-label web-server/private/mod-map))
@defmodule[web-server/private/mod-map]
@defmodule[web-server/private/mod-map]{
The @schememodname[scheme/serialize] library provides the
functionality of serializing values. @filepath{private/mod-map.ss}
@ -309,12 +319,14 @@ compresses the serialized representation.
Expands multiple occurrences of the same module in the module
map of the compressed serialized representation, @scheme[csv].
}
}
@; ------------------------------------------------------------
@section[#:tag "url-param.ss"]{URL Param}
@(require (for-label web-server/private/url-param))
@defmodule[web-server/private/url-param]
@defmodule[web-server/private/url-param]{
The @web-server needs to encode information in URLs. If this data
is stored in the query string, than it will be overridden by browsers that
@ -337,6 +349,8 @@ with this process.
@scheme[u], if there is one, returning @scheme[#f] otherwise.
}
}
@; ------------------------------------------------------------
@section[#:tag "util.ss"]{Miscellaneous Utilities}
@(require (for-label web-server/private/util))

View File

@ -34,7 +34,7 @@ You are given the entire @schememodname[web-server/servlet] API.
@subsection{Customization API}
@defmodule[web-server/insta/insta]
@defmodule[web-server/insta/insta] {
The following API is provided to customize the server instance:
@ -47,6 +47,8 @@ The following API is provided to customize the server instance:
This instructs the Web server to serve static files, such as stylesheet and images, from @scheme[path].
}
}
@; ------------------------------------------------------------
@include-section["servlet-env.scrbl"]
@ -79,8 +81,13 @@ To run the web server with MrEd, use
@; ------------------------------------------------------------
@section[#:tag "web-server.ss"]{Functional}
@(require (for-label web-server/web-server))
@(require (for-label web-server/dispatchers/filesystem-map)
(for-label web-server/web-config-unit)
(for-label web-server/web-config-sig)
(for-label web-server/configuration/configuration-table)
(prefix-in files: (for-label web-server/dispatchers/dispatch-files)))
@defmodule[web-server/web-server]
@defmodule[web-server/web-server]{
@filepath{web-server.ss} provides a number of functions for easing embedding
of the @web-server in other applications, or loading a custom
@ -102,12 +109,6 @@ dispatcher.
Here's an example of a simple web server that serves files
from a given path:
@(require (for-label web-server/dispatchers/filesystem-map)
(for-label web-server/web-config-unit)
(for-label web-server/web-config-sig)
(for-label web-server/configuration/configuration-table)
(prefix-in files: (for-label web-server/dispatchers/dispatch-files)))
@schemeblock[
(define (start-file-server base)
(serve
@ -157,4 +158,6 @@ from a given path:
@defproc[(do-not-return) void]{
This function does not return. If you are writing a script to load the @web-server
you are likely to want to call this functions at the end of your script.
}
}

View File

@ -0,0 +1,12 @@
#lang scribble/doc
@(require "web-server.ss")
@title[#:style 'toc #:tag "module-servlets"]{Defining a Servlet}
A @defterm{servlet} is a module with particular exports. There three kinds of servlets.
@local-table-of-contents[]
@include-section["v1-servlet.scrbl"]
@include-section["v2-servlet.scrbl"]
@include-section["stateless-servlet.scrbl"]

View File

@ -5,7 +5,7 @@
#:style 'toc]{Simple Single Servlet Servers}
@(require (for-label web-server/servlet-env))
@defmodule[web-server/servlet-env]
@defmodule[web-server/servlet-env]{
The @web-server provides a way to quickly configure and start a server instance.
@ -119,3 +119,5 @@ the top-level interacts with continuations. (Read: Don't do it.)
MIME types are looked up at @scheme[mime-types-path].
}
}

View File

@ -0,0 +1,53 @@
#lang scribble/doc
@(require "web-server.ss")
@title[#:tag "setup.ss"]{Setting Up Servlets}
@(require (for-label web-server/servlet/setup))
@defmodule[web-server/servlet/setup]{
This module is used internally to build and load servlets. It may be useful to those who are trying to extend the server.
@defproc[(make-v1.servlet [directory path?]
[timeout integer?]
[start (request? . -> . response?)])
servlet?]{
Creates a version 1 servlet that uses @scheme[directory] as its current directory, a timeout manager with a @scheme[timeout] timeout, and @scheme[start] as the request handler.
}
@defproc[(make-v2.servlet [directory path?]
[manager manager?]
[start (request? . -> . response?)])
servlet?]{
Creates a version 2 servlet that uses @scheme[directory] as its current directory, a @scheme[manager] as the continuation manager, and @scheme[start] as the request handler.
}
@defproc[(make-stateless.servlet [directory path?]
[start (request? . -> . response?)])
servlet?]{
Creates a stateless @schememodname[web-server] servlet that uses @scheme[directory] as its current directory and @scheme[start] as the request handler.
}
@defthing[default-module-specs (listof module-path?)]{
The modules that the Web Server needs to share with all servlets.
}
@defthing[path->servlet/c contract?]{
Equivalent to @scheme[(path? . -> . servlet?)].
}
@defproc[(make-default-path->servlet
[#:make-servlet-namespace
make-servlet-namespace
make-servlet-namespace?
(make-make-servlet-namespace)]
[#:timeouts-default-servlet
timeouts-default-servlet
integer?
30])
path->servlet/c]{
Constructs a procedure that loads a servlet from the path in a namespace created with @scheme[make-servlet-namespace],
using a timeout manager with @scheme[timeouts-default-servlet] as the default timeout (if no manager is given.)
}
}

View File

@ -1,427 +0,0 @@
#lang scribble/doc
@(require "web-server.ss")
@title[#:tag "servlet"
#:style 'toc]{Scheme Servlets}
@defmodule[web-server/servlet]
The @web-server allows servlets to be written in Scheme. It
provides the supporting API, described below, for the construction
of these servlets.
@local-table-of-contents[]
@; ------------------------------------------------------------
@section[#:tag "module-servlets"]{Definition}
@(require (for-label "dummy-servlet.ss")) @; to give a binding context
@declare-exporting[#:use-sources (web-server/scribblings/dummy-servlet)]
A @defterm{servlet} is a module that provides the following:
@defthing[interface-version (one-of/c 'v1 'v2 'stateless)]{
A symbol indicating the servlet interface the servlet conforms
to. This influences the other provided identifiers.
}
@defthing[timeout integer?]{
Only if @scheme[interface-version] is @scheme['v1].
This number is used as the @scheme[continuation-timeout] argument to
a timeout-based continuation manager used for this servlet. (See
@secref["timeouts.ss"].) (i.e., you do not have a choice of the manager
for this servlet and will be given a timeout-based manager.)
}
@defthing[manager manager?]{
Only if @scheme[interface-version] is @scheme['v2].
The manager for the continuations of this servlet.
}
@defproc[(start [initial-request request?])
response?]{
This function is called when an instance of this servlet is started.
The argument is the HTTP request that initiated the instance.
}
An example version 1 module:
@schememod[
scheme
(define interface-version 'v1)
(define timeout (* 60 60 24))
(define (start req)
`(html (head (title "Hello World!"))
(body (h1 "Hi Mom!"))))
]
An example version 2 module:
@(require (for-label web-server/managers/none))
@schememod[
scheme
(require web-server/managers/none)
(define interface-version 'v2)
(define manager
(create-none-manager
(lambda (req)
`(html (head (title "No Continuations Here!"))
(body (h1 "No Continuations Here!"))))))
(define (start req)
`(html (head (title "Hello World!"))
(body (h1 "Hi Mom!"))))
]
An example @scheme['stateless] servlet module:
@schememod[
web-server
(define interface-version 'stateless)
(define (start req)
`(html (body (h2 "Look ma, no state!"))))
]
@; ------------------------------------------------------------
@section[#:tag "servlet-structs.ss"]{Contracts}
@(require (for-label web-server/servlet/servlet-structs
web-server/servlet))
@defmodule[web-server/servlet/servlet-structs]
@filepath{servlet/servlet-structs.ss} provides a number of contracts
for use in servlets.
@defthing[k-url? contract?]{
Equivalent to @scheme[string?].
Example: @scheme["http://localhost:8080/servlets;1*1*20131636/examples/add.ss"]}
@defthing[response-generator? contract?]{
Equivalent to @scheme[(k-url? . -> . response?)].
Example: @schemeblock[(lambda (k-url)
`(html
(body
(a ([href ,k-url])
"Click Me to Invoke the Continuation!"))))]
}
@defthing[expiration-handler/c contract?]{
Equivalent to @scheme[(or/c false/c (request? . -> . response?))].
Example: @schemeblock[(lambda (req)
`(html (head (title "Expired"))
(body (h1 "Expired")
(p "This URL has expired. "
"Please return to the home page."))))]
}
@defthing[embed/url/c contract?]{
Equivalent to @scheme[(((request? . -> . any/c)) (expiration-handler/c) . opt-> . string?)].
This is what @scheme[send/suspend/dispatch] gives to its function argument.
}
@; ------------------------------------------------------------
@section[#:tag "web.ss"]{Web}
@(require (for-label web-server/servlet/web))
@defmodule[web-server/servlet/web]{The
@schememodname[web-server/servlet/web] library provides the primary
functions of interest for the servlet developer.}
@defproc[(send/back [response response?])
void?]{
Sends @scheme[response] to the client. No continuation is captured, so the servlet is done.
Example:
@schemeblock[
(send/back
`(html
(body
(h1 "The sum is: "
,(+ first-number
second-number)))))
]
}
@defthing[current-servlet-continuation-expiration-handler (parameter/c expiration-handler/c)]{
Holds the @scheme[expiration-handler/c] to be used when a continuation
captured in this context is expired, then looked up.
Example:
@schemeblock[
(parameterize
([current-servlet-continuation-expiration-handler
(lambda (req)
`(html (head (title "Custom Expiration!"))))])
(send/suspend
...))
]
}
@defproc[(send/suspend [make-response response-generator?]
[exp expiration-handler/c (current-servlet-continuation-expiration-handler)])
request?]{
Captures the current continuation, stores it with @scheme[exp] as the expiration
handler, and binds it to a URL. @scheme[make-response] is called with this URL and
is expected to generate a @scheme[response?], which is sent to the client. If the
continuation URL is invoked, the captured continuation is invoked and the request is
returned from this call to @scheme[send/suspend].
Example:
@schemeblock[
(send/suspend
(lambda (k-url)
`(html (head (title "Enter a number"))
(body
(form ([action ,k-url])
"Enter a number: "
(input ([name "number"]))
(input ([type "submit"])))))))
]
When this form is submitted by the browser, the request will be sent to the URL generated by @scheme[send/suspend].
Thus, the request will be ``returned'' from @scheme[send/suspend] to the continuation of this call.
}
@defproc[(send/suspend/dispatch [make-response (embed/url/c . -> . response?)])
any/c]{
Calls @scheme[make-response] with a function that, when called with a procedure from
@scheme[request?] to @scheme[any/c] will generate a URL, that when invoked will call
the function with the @scheme[request?] object and return the result to the caller of
@scheme[send/suspend/dispatch].
Use @scheme[send/suspend/dispatch] when there are multiple `logical' continuations of a page.
For example, we could either add to a number or subtract from it:
@schemeblock[
(define (count-dot-com i)
(count-dot-com
(send/suspend/dispatch
(lambda (embed/url)
`(html
(head (title "Count!"))
(body
(h2 (a ([href
,(embed/url
(lambda (req)
(sub1 i)))])
"-"))
(h1 ,(number->string i))
(h2 (a ([href
,(embed/url
(lambda (req)
(add1 i)))])
"+"))))))))
]
It is very common that the return value of @scheme[send/suspend/dispatch] is irrevelant in
your application and you may think of it as ``embedding'' value-less callbacks.
}
@defproc[(clear-continuation-table!)
void?]{
Calls the servlet's manager's @scheme[clear-continuation-table!] function. Normally, this deletes all the previously
captured continuations.
}
@defproc[(send/forward [make-response response-generator?]
[exp expiration-handler/c (current-servlet-continuation-expiration-handler)])
request?]{
Calls @scheme[clear-continuation-table!], then @scheme[send/suspend].
Use this if the user can logically go `forward' in your application, but cannot go backward.
}
@defproc[(send/finish [response response?])
void?]{
Calls @scheme[clear-continuation-table!], then @scheme[send/back].
Use this if the user is truly `done' with your application. For example, it may be used to display the post-logout page:
@schemeblock[
(send/finish
`(html (head (title "Logged out"))
(body (p "Thank you for using the services "
"of the Add Two Numbers, Inc."))))
]
}
@defproc[(redirect/get)
request?]{
Calls @scheme[send/suspend] with @scheme[redirect-to].
This implements the Post-Redirect-Get pattern.
Use this to prevent the @onscreen["Refresh"] button from duplicating effects, such as adding items to a database.
}
@defproc[(redirect/get/forget)
request?]{
Calls @scheme[send/forward] with @scheme[redirect-to].
}
@defproc[(adjust-timeout! [t number?])
void?]{
Calls the servlet's manager's @scheme[adjust-timeout!] function.
@warning{This is deprecated and will be removed in a future release.}
}
@defproc[(continuation-url? [u url?])
(or/c false/c (list/c number? number? number?))]{
Checks if @scheme[u] is a URL that refers to a continuation, if so
returns the instance id, continuation id, and nonce.
}
@; ------------------------------------------------------------
@section[#:tag "helpers.ss"]{Helpers}
@(require (for-label web-server/servlet/helpers))
@defmodule[web-server/servlet/helpers]
@defproc[(with-errors-to-browser [send/finish-or-back (response? . -> . request?)]
[thunk (-> any)])
any]{
Calls @scheme[thunk] with an exception handler that generates an HTML error page
and calls @scheme[send/finish-or-back].
Example:
@schemeblock[
(with-errors-to-browser
send/back
(lambda ()
(/ 1 (get-number (request-number)))))
]
}
@; ------------------------------------------------------------
@section[#:tag "web-cells.ss"]{Web Cells}
@(require (for-label web-server/servlet/web-cells))
@defmodule[web-server/servlet/web-cells]{The
@schememodname[web-server/servlet/web-cells] library provides the
interface to Web cells.}
A Web cell is a kind of state defined relative to the @defterm{frame tree}.
The frame-tree is a mirror of the user's browsing session. Every time a
continuation is invoked, a new frame (called the @defterm{current frame}) is
created as a child of the current frame when the continuation was captured.
You should use Web cells if you want an effect to be encapsulated in all
interactions linked from (in a transitive sense) the HTTP response being
generated. For more information on their semantics, consult the paper
@href-link["http://www.cs.brown.edu/~sk/Publications/Papers/Published/mk-int-safe-state-web/"
"\"Interaction-Safe State for the Web\""].
@defproc[(web-cell? [v any/c])
boolean?]{
Determines if @scheme[v] is a web-cell.
}
@defproc[(make-web-cell [v any/c])
web-cell?]{
Creates a web-cell with a default value of @scheme[v].
}
@defproc[(web-cell-ref [wc web-cell?])
any/c]{
Looks up the value of @scheme[wc] found in the nearest
frame.
}
@defproc[(web-cell-shadow [wc web-cell?]
[v any/c])
void]{
Binds @scheme[wc] to @scheme[v] in the current frame, shadowing any
other bindings to @scheme[wc] in the current frame.
}
Below is an extended example that demonstrates how Web cells allow
the creation of reusable Web abstractions without requiring global
transformations of the program into continuation or store passing style.
@schememod[
web-server/insta
(define (start initial-request)
(define counter1 (make-counter))
(define counter2 (make-counter))
(define include1 (include-counter counter1))
(define include2 (include-counter counter2))
(send/suspend/dispatch
(lambda (embed/url)
`(html
(body (h2 "Double Counters")
(div (h3 "First")
,(include1 embed/url))
(div (h3 "Second")
,(include2 embed/url)))))))
(define (make-counter)
(make-web-cell 0))
(define (include-counter a-counter)
(let/cc k
(let loop ()
(k
(lambda (embed/url)
`(div (h3 ,(number->string (web-cell-ref a-counter)))
(a ([href
,(embed/url
(lambda _
@code:comment{A new frame has been created}
(define last (web-cell-ref a-counter))
@code:comment{We can inspect the value at the parent}
(web-cell-shadow a-counter (add1 last))
@code:comment{The new frame has been modified}
(loop)))])
"+")))))))
]
@; ------------------------------------------------------------
@section[#:tag "setup.ss"]{Setup}
@(require (for-label web-server/servlet/setup))
@defmodule[web-server/servlet/setup]
This module is used internally to build and load servlets. It may be useful to those who are trying to extend the server.
@defproc[(make-v1.servlet [directory path?]
[timeout integer?]
[start (request? . -> . response?)])
servlet?]{
Creates a version 1 servlet that uses @scheme[directory] as its current directory, a timeout manager with a @scheme[timeout] timeout, and @scheme[start] as the request handler.
}
@defproc[(make-v2.servlet [directory path?]
[manager manager?]
[start (request? . -> . response?)])
servlet?]{
Creates a version 2 servlet that uses @scheme[directory] as its current directory, a @scheme[manager] as the continuation manager, and @scheme[start] as the request handler.
}
@defproc[(make-stateless.servlet [directory path?]
[start (request? . -> . response?)])
servlet?]{
Creates a stateless @schememodname[web-server] servlet that uses @scheme[directory] as its current directory and @scheme[start] as the request handler.
}
@defthing[default-module-specs (listof module-path?)]{
The modules that the Web Server needs to share with all servlets.
}
@defthing[path->servlet/c contract?]{
Equivalent to @scheme[(path? . -> . servlet?)].
}
@defproc[(make-default-path->servlet
[#:make-servlet-namespace
make-servlet-namespace
make-servlet-namespace?
(make-make-servlet-namespace)]
[#:timeouts-default-servlet
timeouts-default-servlet
integer?
30])
path->servlet/c]{
Constructs a procedure that loads a servlet from the path in a namespace created with @scheme[make-servlet-namespace],
using a timeout manager with @scheme[timeouts-default-servlet] as the default timeout (if no manager is given.)
}

View File

@ -0,0 +1,95 @@
#lang scribble/doc
@(require "web-server.ss")
@title[#:tag "stateless-servlets"]{Stateless Servlets}
@defmodulelang[web-server]
@(require (for-label "dummy-stateless-servlet.ss")) @; to give a binding context
@declare-exporting[#:use-sources (web-server/scribblings/dummy-stateless-servlet)]
@defthing[interface-version (one-of/c 'stateless)]{
This indicates that the servlet is a stateless servlet.
}
@defproc[(start [initial-request request?])
response?]{
This function is called when an instance of this servlet is started.
The argument is the HTTP request that initiated the instance.
}
An example @scheme['stateless] servlet module:
@schememod[
web-server
(define interface-version 'stateless)
(define (start req)
`(html (body (h2 "Look ma, no state!"))))
]
The @schememodname[web-server] language automatically provides the @schememodname[web-server/lang/lang-api] API.
@; ------------------------------------------------------------
@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. (@filepath{lang/elim-letrec.ss})}
@item{The program is converted into ANF (Administrative Normal Form),
making all continuations explicit. (@filepath{lang/anormal.ss})}
@item{All continuations (and other continuations marks) are recorded in the
continuation marks of the expression
they are the continuation of. (@filepath{lang/elim-callcc.ss})}
@item{All calls to external modules are identified and marked.
(@filepath{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.
(@filepath{lang/elim-callcc.ss})}
@item{The program is defunctionalized with a serializable data-structure for each
anonymous lambda. (@filepath{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.
This process is derived from the paper
@href-link["http://www.cs.brown.edu/~sk/Publications/Papers/Published/pcmkf-cont-from-gen-stack-insp/" "Continuations from Generalized Stack Inspection"].
We thank Greg Pettyjohn for his initial implementation of this algorithm.

View File

@ -0,0 +1,36 @@
#lang scribble/doc
@(require "web-server.ss")
@title{Version 1 Servlets}
@(require (for-label "dummy-v1-servlet.ss")) @; to give a binding context
@declare-exporting[#:use-sources (web-server/scribblings/dummy-v1-servlet)]
@defthing[interface-version (one-of/c 'v1)]{
This indicates that the servlet is a version one servlet.
}
@defthing[timeout integer?]{
This number is used as the @scheme[continuation-timeout] argument to
a timeout-based continuation manager used for this servlet. (See
@secref["timeouts.ss"].) (i.e., you do not have a choice of the manager
for this servlet and will be given a timeout-based manager.)
}
@defproc[(start [initial-request request?])
response?]{
This function is called when an instance of this servlet is started.
The argument is the HTTP request that initiated the instance.
}
An example version 1 module:
@schememod[
scheme
(define interface-version 'v1)
(define timeout (* 60 60 24))
(define (start req)
`(html (head (title "Hello World!"))
(body (h1 "Hi Mom!"))))
]
These servlets should use the @schememodname[web-server/servlet] API.

View File

@ -0,0 +1,39 @@
#lang scribble/doc
@(require "web-server.ss")
@title{Version 2 Servlets}
@(require (for-label "dummy-v2-servlet.ss")) @; to give a binding context
@declare-exporting[#:use-sources (web-server/scribblings/dummy-v2-servlet)]
@defthing[interface-version (one-of/c 'v2)]{
This indicates that the servlet is a version two servlet.
}
@defthing[manager manager?]{
The manager for the continuations of this servlet. See @secref["managers"] for options.
}
@defproc[(start [initial-request request?])
response?]{
This function is called when an instance of this servlet is started.
The argument is the HTTP request that initiated the instance.
}
An example version 2 module:
@(require (for-label web-server/managers/none))
@schememod[
scheme
(require web-server/managers/none)
(define interface-version 'v2)
(define manager
(create-none-manager
(lambda (req)
`(html (head (title "No Continuations Here!"))
(body (h1 "No Continuations Here!"))))))
(define (start req)
`(html (head (title "Hello World!"))
(body (h1 "Hi Mom!"))))
]
These servlets should use the @schememodname[web-server/servlet] API.

View File

@ -0,0 +1,87 @@
#lang scribble/doc
@(require "web-server.ss")
@title[#:tag "web-cells.ss"]{Web Cells}
@(require (for-label web-server/servlet/web-cells))
@defmodule[web-server/servlet/web-cells]{The
@schememodname[web-server/servlet/web-cells] library provides the
interface to Web cells.
A Web cell is a kind of state defined relative to the @defterm{frame tree}.
The frame-tree is a mirror of the user's browsing session. Every time a
continuation is invoked, a new frame (called the @defterm{current frame}) is
created as a child of the current frame when the continuation was captured.
You should use Web cells if you want an effect to be encapsulated in all
interactions linked from (in a transitive sense) the HTTP response being
generated. For more information on their semantics, consult the paper
@href-link["http://www.cs.brown.edu/~sk/Publications/Papers/Published/mk-int-safe-state-web/"
"\"Interaction-Safe State for the Web\""].
@defproc[(web-cell? [v any/c])
boolean?]{
Determines if @scheme[v] is a web-cell.
}
@defproc[(make-web-cell [v any/c])
web-cell?]{
Creates a web-cell with a default value of @scheme[v].
}
@defproc[(web-cell-ref [wc web-cell?])
any/c]{
Looks up the value of @scheme[wc] found in the nearest
frame.
}
@defproc[(web-cell-shadow [wc web-cell?]
[v any/c])
void]{
Binds @scheme[wc] to @scheme[v] in the current frame, shadowing any
other bindings to @scheme[wc] in the current frame.
}
Below is an extended example that demonstrates how Web cells allow
the creation of reusable Web abstractions without requiring global
transformations of the program into continuation or store passing style.
@schememod[
web-server/insta
(define (start initial-request)
(define counter1 (make-counter))
(define counter2 (make-counter))
(define include1 (include-counter counter1))
(define include2 (include-counter counter2))
(send/suspend/dispatch
(lambda (embed/url)
`(html
(body (h2 "Double Counters")
(div (h3 "First")
,(include1 embed/url))
(div (h3 "Second")
,(include2 embed/url)))))))
(define (make-counter)
(make-web-cell 0))
(define (include-counter a-counter)
(let/cc k
(let loop ()
(k
(lambda (embed/url)
`(div (h3 ,(number->string (web-cell-ref a-counter)))
(a ([href
,(embed/url
(lambda _
@code:comment{A new frame has been created}
(define last (web-cell-ref a-counter))
@code:comment{We can inspect the value at the parent}
(web-cell-shadow a-counter (add1 last))
@code:comment{The new frame has been modified}
(loop)))])
"+")))))))
]
}
@include-section["lang-web-cells.scrbl"]

View File

@ -1,15 +1,18 @@
#lang scribble/doc
@(require "web-server.ss")
@title[#:tag "web-config-unit.ss"]{Web Config Unit}
@title[#:tag "web-config-unit.ss"
#:style 'toc]{Web Config Unit}
@(require (for-label web-server/web-config-unit)
(for-label web-server/web-config-sig))
The @web-server offers a unit-based approach to configuring the server.
@local-table-of-contents[]
@section{Configuration Signature}
@defmodule[web-server/web-config-sig]
@defmodule[web-server/web-config-sig]{
@defsignature[web-config^ ()]{
@ -41,10 +44,12 @@ Provides contains the following identifiers.
Passed to @scheme[servlets:make].
}
}
}
@section{Configuration Units}
@defmodule[web-server/web-config-unit]
@defmodule[web-server/web-config-unit]{
@defproc[(configuration-table->web-config@ [path path?]
[#:port port (or/c false/c port-number?) #f]
@ -63,3 +68,5 @@ Provides contains the following identifiers.
(unit? web-config^)]{
Parses @scheme[sexpr] as a configuration-table and constructs a @scheme[web-config^] unit.
}
}

View File

@ -1,15 +1,18 @@
#lang scribble/doc
@(require "web-server.ss")
@title[#:tag "web-server-unit.ss"]{Web Server Unit}
@title[#:tag "web-server-unit.ss"
#:style 'toc]{Web Server Unit}
@(require (for-label web-server/web-server-sig)
(for-label web-server/web-server-unit))
The @web-server offers a unit-based approach to running the server.
@local-table-of-contents[]
@section{Signature}
@defmodule[web-server/web-server-sig]
@defmodule[web-server/web-server-sig]{
@defsignature[web-server^ ()]{
@ -25,9 +28,11 @@ The @web-server offers a unit-based approach to running the server.
}
}
}
@section{Unit}
@defmodule[web-server/web-server-unit]
@defmodule[web-server/web-server-unit]{
@defthing[web-server@ (unit/c (web-config^ tcp^)
(web-server^))]{
@ -50,3 +55,5 @@ operations:
Using this @scheme[dispatcher?], it loads a dispatching server that provides @scheme[serve]
and @scheme[serve-ports] functions that operate as expected.
}
}

View File

@ -11,22 +11,8 @@ develop Web applications in Scheme.
@table-of-contents[]
@include-section["running.scrbl"]
@include-section["http.scrbl"]
@include-section["servlet.scrbl"]
@include-section["lang.scrbl"]
@include-section["formlets.scrbl"]
@include-section["configuration.scrbl"]
@include-section["dispatchers.scrbl"]
@include-section["web-config-unit.scrbl"]
@include-section["web-server-unit.scrbl"]
@include-section["managers.scrbl"]
@include-section["private.scrbl"]
@include-section["writing.scrbl"]
@include-section["extending.scrbl"]
@include-section["faq.scrbl"]
@; ------------------------------------------------------------

View File

@ -0,0 +1,167 @@
#lang scribble/doc
@(require "web-server.ss")
@title[#:tag "web.ss"]{Web Interaction}
@(require (for-label web-server/servlet/web))
@defmodule[web-server/servlet/web]{The
@schememodname[web-server/servlet/web] library provides the primary
functions of interest for the servlet developer.
@defproc[(send/back [response response?])
void?]{
Sends @scheme[response] to the client. No continuation is captured, so the servlet is done.
Example:
@schemeblock[
(send/back
`(html
(body
(h1 "The sum is: "
,(+ first-number
second-number)))))
]
}
@defproc[(send/suspend [make-response response-generator?]
[exp expiration-handler/c (current-servlet-continuation-expiration-handler)])
request?]{
Captures the current continuation, stores it with @scheme[exp] as the expiration
handler, and binds it to a URL. @scheme[make-response] is called with this URL and
is expected to generate a @scheme[response?], which is sent to the client. If the
continuation URL is invoked, the captured continuation is invoked and the request is
returned from this call to @scheme[send/suspend].
Example:
@schemeblock[
(send/suspend
(lambda (k-url)
`(html (head (title "Enter a number"))
(body
(form ([action ,k-url])
"Enter a number: "
(input ([name "number"]))
(input ([type "submit"])))))))
]
When this form is submitted by the browser, the request will be sent to the URL generated by @scheme[send/suspend].
Thus, the request will be ``returned'' from @scheme[send/suspend] to the continuation of this call.
}
@defproc[(send/suspend/dispatch [make-response (embed/url/c . -> . response?)])
any/c]{
Calls @scheme[make-response] with a function that, when called with a procedure from
@scheme[request?] to @scheme[any/c] will generate a URL, that when invoked will call
the function with the @scheme[request?] object and return the result to the caller of
@scheme[send/suspend/dispatch].
Use @scheme[send/suspend/dispatch] when there are multiple `logical' continuations of a page.
For example, we could either add to a number or subtract from it:
@schemeblock[
(define (count-dot-com i)
(count-dot-com
(send/suspend/dispatch
(lambda (embed/url)
`(html
(head (title "Count!"))
(body
(h2 (a ([href
,(embed/url
(lambda (req)
(sub1 i)))])
"-"))
(h1 ,(number->string i))
(h2 (a ([href
,(embed/url
(lambda (req)
(add1 i)))])
"+"))))))))
]
It is very common that the return value of @scheme[send/suspend/dispatch] is irrevelant in
your application and you may think of it as ``embedding'' value-less callbacks.
}
@defproc[(send/forward [make-response response-generator?]
[exp expiration-handler/c (current-servlet-continuation-expiration-handler)])
request?]{
Calls @scheme[clear-continuation-table!], then @scheme[send/suspend].
Use this if the user can logically go `forward' in your application, but cannot go backward.
}
@defproc[(send/finish [response response?])
void?]{
Calls @scheme[clear-continuation-table!], then @scheme[send/back].
Use this if the user is truly `done' with your application. For example, it may be used to display the post-logout page:
@schemeblock[
(send/finish
`(html (head (title "Logged out"))
(body (p "Thank you for using the services "
"of the Add Two Numbers, Inc."))))
]
}
@defproc[(redirect/get)
request?]{
Calls @scheme[send/suspend] with @scheme[redirect-to].
This implements the Post-Redirect-Get pattern.
Use this to prevent the @onscreen["Refresh"] button from duplicating effects, such as adding items to a database.
}
@defproc[(redirect/get/forget)
request?]{
Calls @scheme[send/forward] with @scheme[redirect-to].
}
@defthing[current-servlet-continuation-expiration-handler (parameter/c expiration-handler/c)]{
Holds the @scheme[expiration-handler/c] to be used when a continuation
captured in this context is expired, then looked up.
Example:
@schemeblock[
(parameterize
([current-servlet-continuation-expiration-handler
(lambda (req)
`(html (head (title "Custom Expiration!"))))])
(send/suspend
...))
]
}
@defproc[(clear-continuation-table!)
void?]{
Calls the servlet's manager's @scheme[clear-continuation-table!] function. Normally, this deletes all the previously
captured continuations.
}
@defproc[(with-errors-to-browser [send/finish-or-back (response? . -> . request?)]
[thunk (-> any)])
any]{
Calls @scheme[thunk] with an exception handler that generates an HTML error page
and calls @scheme[send/finish-or-back].
Example:
@schemeblock[
(with-errors-to-browser
send/back
(lambda ()
(/ 1 (get-number (request-number)))))
]
}
@defproc[(adjust-timeout! [t number?])
void?]{
Calls the servlet's manager's @scheme[adjust-timeout!] function.
@warning{This is deprecated and will be removed in a future release.}
}
@defproc[(continuation-url? [u url?])
(or/c false/c (list/c number? number? number?))]{
Checks if @scheme[u] is a URL that refers to a continuation, if so
returns the instance id, continuation id, and nonce.
}
}

View File

@ -0,0 +1,167 @@
#lang scribble/doc
@(require "web-server.ss")
@title[#:style 'toc]{Writing Servlets}
@local-table-of-contents[]
@include-section["servlet-definition.scrbl"]
@; ------------------------------------------------------------
@section{APIs}
There are two API sets provided by the Web Server. One is for standard servlets, the other is for stateless servlets.
@subsection{Standard API}
@defmodule[web-server/servlet]{
This API provides:
@itemize{
@item{@schememodname[web-server/servlet/web-cells],}
@item{@schememodname[web-server/http/bindings],}
@item{@schememodname[web-server/http],}
@item{@schememodname[web-server/servlet/servlet-structs], and}
@item{@schememodname[web-server/servlet/web].}}
}
@subsection{Stateless API}
@defmodule[web-server/lang/lang-api]{
This API provides:
@itemize{
@item{@schememodname[net/url],}
@item{@schememodname[web-server/http],}
@item{@schememodname[web-server/lang/abort-resume],}
@item{@schememodname[web-server/lang/web],}
@item{@schememodname[web-server/lang/web-cells],}
@item{@schememodname[web-server/lang/web-param], and}
@item{@schememodname[web-server/lang/file-box].}}
}
@; ------------------------------------------------------------
@section[#:tag "servlet-structs.ss"]{Common Contracts}
@(require (for-label web-server/servlet/servlet-structs
web-server/servlet))
@defmodule[web-server/servlet/servlet-structs]{
@filepath{servlet/servlet-structs.ss} provides a number of contracts
for use in servlets.
@defthing[k-url? contract?]{
Equivalent to @scheme[string?].
Example: @scheme["http://localhost:8080/servlets;1*1*20131636/examples/add.ss"]}
@defthing[response-generator? contract?]{
Equivalent to @scheme[(k-url? . -> . response?)].
Example: @schemeblock[(lambda (k-url)
`(html
(body
(a ([href ,k-url])
"Click Me to Invoke the Continuation!"))))]
}
@defthing[expiration-handler/c contract?]{
Equivalent to @scheme[(or/c false/c (request? . -> . response?))].
Example: @schemeblock[(lambda (req)
`(html (head (title "Expired"))
(body (h1 "Expired")
(p "This URL has expired. "
"Please return to the home page."))))]
}
@defthing[embed/url/c contract?]{
Equivalent to @scheme[(((request? . -> . any/c)) (expiration-handler/c) . opt-> . string?)].
This is what @scheme[send/suspend/dispatch] gives to its function argument.
}
}
@; ------------------------------------------------------------
@include-section["http.scrbl"]
@include-section["web.scrbl"]
@include-section["lang.scrbl"]
@include-section["web-cells.scrbl"]
@; ------------------------------------------------------------
@section[#:tag "lang/file-box.ss"]{File Boxes}
@(require (for-label web-server/lang/file-box))
@defmodule[web-server/lang/file-box]{
As mentioned earlier, it is dangerous to rely on the store in
Web Language servlets, due to the deployment scenarios available
to them. @filepath{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"]{Stateless Web Parameters}
@(require (for-label web-server/lang/web-param))
@defmodule[web-server/lang/web-param]{
It is not easy to use @scheme[parameterize] in the
Web Language. @filepath{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].
}
}
@; ------------------------------------------------------------
@include-section["formlets.scrbl"]
@include-section["managers.scrbl"]

View File

@ -1,12 +1,10 @@
#lang scheme/base
(require web-server/servlet/helpers
web-server/servlet/web-cells
(require web-server/servlet/web-cells
web-server/http/bindings
web-server/http
web-server/servlet/servlet-structs
web-server/servlet/web)
(provide (all-from-out web-server/servlet/helpers
web-server/servlet/web-cells
(provide (all-from-out web-server/servlet/web-cells
web-server/http/bindings
web-server/http
web-server/servlet/servlet-structs

View File

@ -1,20 +0,0 @@
#lang scheme/base
(require scheme/contract)
(require "../private/util.ss"
web-server/http)
(define (with-errors-to-browser send/finish-or-back thunk)
(with-handlers ([exn? (lambda (exn)
(send/finish-or-back
`(html (head (title "Servlet Error"))
(body ([bgcolor "white"])
(p "The following error occured: "
(pre ,(exn->string exn)))))))])
(thunk)))
(provide/contract
[with-errors-to-browser
((response? . -> . request?)
(-> any)
. -> .
any)])

View File

@ -133,3 +133,20 @@
; redirect/get : -> request
(define redirect/get (make-redirect/get send/suspend))
(define redirect/get/forget (make-redirect/get send/forward))
(define (with-errors-to-browser send/finish-or-back thunk)
(with-handlers ([exn? (lambda (exn)
(send/finish-or-back
`(html (head (title "Servlet Error"))
(body ([bgcolor "white"])
(p "The following error occured: "
(pre ,(exn->string exn)))))))])
(thunk)))
(provide/contract
[with-errors-to-browser
((response? . -> . request?)
(-> any)
. -> .
any)])