Adding exampels to docs

svn: r12182
This commit is contained in:
Jay McCarthy 2008-10-30 20:34:24 +00:00
parent a6b7f4ba16
commit 4e7aa80828
3 changed files with 323 additions and 73 deletions

View File

@ -11,7 +11,8 @@ There are a number of ways to run the Web Server. They are given in order of sim
@; ------------------------------------------------------------
@section[#:tag "insta"]{Instant Servlets}
@(require (for-label (only-in web-server/insta/insta
no-web-browser static-files-path)))
no-web-browser static-files-path)
web-server/servlet-env))
@defmodulelang[web-server/insta]
The fastest way to get a servlet running in the Web server is to use the
@ -104,6 +105,7 @@ 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[
@ -143,7 +145,13 @@ from a given path:
(-> void)]{
Starts the @web-server with the settings defined by the given @scheme[web-config^] unit.
It is very useful to combine this with @scheme[configuration-table->web-config@] and @scheme[configuration-table-sexpr->web-config@].
It is very useful to combine this with @scheme[configuration-table->web-config@] and @scheme[configuration-table-sexpr->web-config@]:
@schemeblock[
(serve/web-config@
(configuration-table->web-config@
default-configuration-table-path))
(do-not-return)]
}
@defproc[(do-not-return) void]{

View File

@ -45,25 +45,82 @@ A @defterm{servlet} is a module that provides the following:
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!"))))
]
@; ------------------------------------------------------------
@section[#:tag "servlet-structs.ss"]{Contracts}
@(require (for-label web-server/servlet/servlet-structs))
@(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?].}
@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?)].}
@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[url-transform? contract?]{Equivalent to @scheme[(k-url? . -> . k-url?)].}
@defthing[url-transform? contract?]{
Equivalent to @scheme[(k-url? . -> . k-url?)].
Example: @scheme[(lambda (k-url) (regexp-replace "^/" k-url "/servlets/"))]
}
@defthing[expiration-handler/c contract?]{Equivalent to @scheme[(or/c false/c (request? . -> . response?))].}
@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?)].}
@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 "request-structs.ss"]{HTTP Requests}
@ -89,6 +146,8 @@ related to HTTP request data structures.
@defproc[(headers-assq* [id bytes?] [heads (listof header?)])
(or/c false/c header?)]{
Returns the header with a field case-insensitively equal to @scheme[id] from @scheme[heads] or @scheme[#f].
You almost @bold{always} want to use this, rather than @scheme[headers-assq] because Web browsers may send headers with arbitrary casing.
}
@defstruct[binding ([id bytes?])]{Represents a binding of @scheme[id].}
@ -121,7 +180,24 @@ related to HTTP request data structures.
to the server at @scheme[host-ip]:@scheme[host-port] with @scheme[headers/raw]
headers, @scheme[bindings/raw] GET and POST queries and @scheme[post-data/raw]
POST data.
You are @bold{unlikely to need to construct} a request struct.
}
Here is an example typical of what you will find in many applications:
@schemeblock[
(define (get-number req)
(match
(bindings-assq
#"number"
(request-bindings/raw req))
[(? binding:form? b)
(string->number
(bytes->string/utf-8
(binding:form-value b)))]
[_
(get-number (request-number))]))
]
@; ------------------------------------------------------------
@section[#:tag "bindings.ss"]{Request Bindings}
@ -132,6 +208,15 @@ related to HTTP request data structures.
@filepath{servlet/bindings.ss} provides a number of helper functions
for accessing request bindings.
These functions, while convenient, could introduce subtle bugs into your
application. Examples: that they are case-insensitive could introduce
a bug; if the data submitted is not in UTF-8 format, then the conversion
to a string will fail; if an attacker submits a form field as if it were
a file, when it is not, then the @scheme[request-bindings] will hold a
@scheme[bytes?] object and your program will error; and, for file uploads
you lose the filename. @bold{Therefore, we recommend against their use, but
they are provided for compatibility with old code.}
@defproc[(request-bindings [req request?])
(listof (or/c (cons/c symbol? string?)
(cons/c symbol? bytes?)))]{
@ -167,14 +252,15 @@ for accessing request bindings.
Returns @scheme[#t] if @scheme[binds] contains a binding for @scheme[id].
Otherwise, @scheme[#f].
}
These functions, while convenient, could introduce subtle bugs into your
application. Examples: that they are case-insensitive could introduce
a bug; if the data submitted is not in UTF-8 format, then the conversion
to a string will fail; if an attacked submits a form field as if it were
a file, when it is not, then the @scheme[request-bindings] will hold a
@scheme[bytes?] object and your program will error; and, for file uploads
you lose the filename.
Here is an example typical of what you will find in many applications:
@schemeblock[
(define (get-number req)
(string->number
(extract-binding/single
'number
(request-bindings req))))
]
@; ------------------------------------------------------------
@section[#:tag "response-structs.ss"]{HTTP Responses}
@ -196,6 +282,15 @@ HTTP responses.
@scheme[message] the message, @scheme[seconds] the generation time, @scheme[mime]
the MIME type of the file, and @scheme[extras] are the extra headers, in addition
to those produced by the server.
Example:
@schemeblock[
(make-response/basic
301 "Moved Permanently"
(current-seconds) TEXT/HTML-MIME-TYPE
(list (make-header #"Location"
#"http://www.plt-scheme.org/downloads")))
]
}
@; XXX Rename string? option
@ -203,6 +298,20 @@ HTTP responses.
([body (listof (or/c string? bytes?))])]{
As with @scheme[response/basic], except with @scheme[body] as the response
body.
Example:
@schemeblock[
(make-response/full
301 "Moved Permanently"
(current-seconds) TEXT/HTML-MIME-TYPE
(list (make-header #"Location"
#"http://www.plt-scheme.org/downloads"))
(list #"<html><body><p>"
#"Please go to <a href=\""
#"http://www.plt-scheme.org/downloads"
#"\">here</a> instead."
#"</p></body></html>"))
]
}
@defstruct[(response/incremental response/basic)
@ -222,7 +331,7 @@ HTTP responses.
(send/bytes #"Some content")
(send/bytes)
(send/bytes #"Even" #"more" #"content!")
(send/bytes "No we're done")))
(send/bytes "Now we're done")))
]
}
@ -238,8 +347,8 @@ HTTP responses.
@defthing[TEXT/HTML-MIME-TYPE bytes?]{Equivalent to @scheme[#"text/html; charset=utf-8"].}
@warning{If you include a Content-Length header in a response that is inaccurate, there WILL be an error in
transmission that the server will not catch.}
@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 "web.ss"]{Web}
@ -251,12 +360,32 @@ functions of interest for the servlet developer.}
@defproc[(send/back [response response?])
void?]{
Sends @scheme[response] to the client.
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?]
@ -267,6 +396,110 @@ functions of interest for the servlet developer.}
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].
}
@; XXX Move
@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.}
}
@; XXX Remove
@defthing[current-url-transform (parameter/c url-transform?)]{
Holds a @scheme[url-transform?] function that is called by
@scheme[send/suspend] to transform the URLs it generates.
@warning{This is deprecated and will be removed in a future release.}
}
@defproc[(continuation-url? [u url?])
@ -274,47 +507,7 @@ functions of interest for the servlet developer.}
Checks if @scheme[u] is a URL that refers to a continuation, if so
returns the instance id, continuation id, and nonce.
}
@; XXX Move
@defproc[(adjust-timeout! [t number?])
void?]{
Calls the servlet's manager's @scheme[adjust-timeout!] function.
}
@defproc[(clear-continuation-table!)
void?]{
Calls the servlet's manager's @scheme[clear-continuation-table!] function.
}
@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].
}
@defproc[(send/finish [response response?])
void?]{
Calls @scheme[clear-continuation-table!], then @scheme[send/back].
}
@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].
}
@defproc[(redirect/get)
request?]{
Calls @scheme[send/suspend] with @scheme[redirect-to].
}
@defproc[(redirect/get/forget)
request?]{
Calls @scheme[send/forward] with @scheme[redirect-to].
}
@; XXX Remove
@defproc[(embed-ids [ids (list/c number? number? number?)]
[u url?])
@ -322,12 +515,6 @@ functions of interest for the servlet developer.}
Creates a @scheme[continuation-url?].
}
@; XXX Remove
@defthing[current-url-transform (parameter/c url-transform?)]{
Holds a @scheme[url-transform?] function that is called by
@scheme[send/suspend] to transform the URLs it generates.
}
@; ------------------------------------------------------------
@section[#:tag "helpers.ss"]{Helpers}
@(require (for-label web-server/servlet/helpers))
@ -344,6 +531,9 @@ functions of interest for the servlet developer.}
response?]{
Generates an HTTP response that redirects the browser to @scheme[uri],
while including the @scheme[headers] in the response.
Example:
@scheme[(redirect-to "http://www.add-three-numbers.com" permanently)]
}
@defproc[(redirection-status? [v any/c])
@ -362,6 +552,14 @@ functions of interest for the servlet developer.}
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)))))
]
}
@; XXX Depreciate
@ -380,7 +578,7 @@ They may eventually provided by another module.
@defproc[(servlet-url->url-string/no-continuation [su servlet-url?])
string?]{
Returns a URL string without the continuation information in the URL
that went into @scheme[su]
that went into @scheme[su].
}
@; XXX Support Digest
@ -396,7 +594,10 @@ implementation of HTTP Basic Authentication.
@defproc[(extract-user-pass [heads (listof header?)])
(or/c false/c (cons/c bytes? bytes?))]{
Returns a pair of the username and password from the authentication
header in @scheme[heads] if they are present, or @scheme[#f]
header in @scheme[heads] if they are present, or @scheme[#f].
Example:
@scheme[(extract-user-pass (request-headers/raw req))] might return @scheme[(cons #"aladin" #"open sesame")].
}
@; ------------------------------------------------------------
@ -405,14 +606,14 @@ implementation of HTTP Basic Authentication.
@defmodule[web-server/servlet/web-cells]{The
@schememodname[web-server/servlet/web-cells] library provides the
interface to web cells.}
interface to Web cells.}
A web cell is a kind of state defined relative to the @defterm{frame tree}.
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
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/"
@ -440,3 +641,44 @@ generated. For more information on their semantics, consult the paper
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)))])
"+")))))))
]

View File

@ -9,7 +9,7 @@
; XXX Format better
(define (warning . x)
(apply elem "Warning:" x))
(apply elem (bold "Warning: ") x))
; XXX Actually display link
(define (href-link url label)