Redoing documentation layout
svn: r12418
This commit is contained in:
parent
cc69a51813
commit
d56eed754b
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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))))
|
|
@ -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))))
|
||||
|
|
|
@ -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].
|
||||
}
|
||||
|
||||
}
|
|
@ -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}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#lang scheme/base
|
||||
|
||||
(define interface-version #f)
|
||||
(define start #f)
|
||||
|
||||
(provide (all-defined-out))
|
|
@ -3,7 +3,6 @@
|
|||
(define interface-version #f)
|
||||
(define timeout #f)
|
||||
(define start #f)
|
||||
(define manager #f)
|
||||
|
||||
(provide (all-defined-out))
|
||||
|
8
collects/web-server/scribblings/dummy-v2-servlet.ss
Normal file
8
collects/web-server/scribblings/dummy-v2-servlet.ss
Normal file
|
@ -0,0 +1,8 @@
|
|||
#lang scheme/base
|
||||
|
||||
(define interface-version #f)
|
||||
(define start #f)
|
||||
(define manager #f)
|
||||
|
||||
(provide (all-defined-out))
|
||||
|
16
collects/web-server/scribblings/extending.scrbl
Normal file
16
collects/web-server/scribblings/extending.scrbl
Normal 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"]
|
|
@ -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].
|
||||
}
|
||||
|
||||
}
|
|
@ -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")].
|
||||
}
|
||||
|
||||
}
|
27
collects/web-server/scribblings/lang-web-cells.scrbl
Normal file
27
collects/web-server/scribblings/lang-web-cells.scrbl
Normal 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].}
|
||||
|
||||
}
|
|
@ -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].}
|
||||
}
|
|
@ -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.
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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))
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
|
||||
}
|
12
collects/web-server/scribblings/servlet-definition.scrbl
Normal file
12
collects/web-server/scribblings/servlet-definition.scrbl
Normal 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"]
|
|
@ -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].
|
||||
}
|
||||
|
||||
}
|
53
collects/web-server/scribblings/servlet-setup.scrbl
Normal file
53
collects/web-server/scribblings/servlet-setup.scrbl
Normal 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.)
|
||||
}
|
||||
|
||||
}
|
|
@ -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.)
|
||||
}
|
95
collects/web-server/scribblings/stateless-servlet.scrbl
Normal file
95
collects/web-server/scribblings/stateless-servlet.scrbl
Normal 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.
|
36
collects/web-server/scribblings/v1-servlet.scrbl
Normal file
36
collects/web-server/scribblings/v1-servlet.scrbl
Normal 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.
|
39
collects/web-server/scribblings/v2-servlet.scrbl
Normal file
39
collects/web-server/scribblings/v2-servlet.scrbl
Normal 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.
|
87
collects/web-server/scribblings/web-cells.scrbl
Normal file
87
collects/web-server/scribblings/web-cells.scrbl
Normal 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"]
|
|
@ -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.
|
||||
}
|
||||
|
||||
}
|
|
@ -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.
|
||||
}
|
||||
|
||||
}
|
|
@ -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"]
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
|
|
167
collects/web-server/scribblings/web.scrbl
Normal file
167
collects/web-server/scribblings/web.scrbl
Normal 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.
|
||||
}
|
||||
|
||||
}
|
167
collects/web-server/scribblings/writing.scrbl
Normal file
167
collects/web-server/scribblings/writing.scrbl
Normal 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"]
|
|
@ -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
|
||||
|
|
|
@ -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)])
|
|
@ -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)])
|
Loading…
Reference in New Issue
Block a user