From a28cf7df10b518be524cd172399ccc018dab0398 Mon Sep 17 00:00:00 2001 From: Jay McCarthy Date: Sat, 27 Nov 2010 21:37:05 -0500 Subject: [PATCH] Updating docs --- .../web-server/configuration/responders.rkt | 34 ++-- .../servlets/examples/template-full.rkt | 2 +- .../servlets/examples/template-simple.rkt | 9 +- .../servlets/examples/template-xexpr.rkt | 1 + collects/web-server/private/mime-types.rkt | 2 +- .../web-server/scribblings/contracts.scrbl | 19 +- .../scribblings/dispatch-servlets.scrbl | 9 +- .../web-server/scribblings/formlets.scrbl | 7 +- collects/web-server/scribblings/http.scrbl | 189 +++++++----------- .../web-server/scribblings/lang-api.scrbl | 3 +- collects/web-server/scribblings/launch.scrbl | 1 + .../web-server/scribblings/mime-types.scrbl | 5 +- collects/web-server/scribblings/page.scrbl | 15 +- collects/web-server/scribblings/running.scrbl | 8 +- .../scribblings/servlet-env-int.scrbl | 1 + .../web-server/scribblings/servlet-env.scrbl | 17 +- .../scribblings/servlet-setup.scrbl | 4 +- collects/web-server/scribblings/servlet.scrbl | 10 +- collects/web-server/scribblings/soft.scrbl | 6 +- .../web-server/scribblings/templates.scrbl | 82 ++++---- .../web-server/scribblings/web-cells.scrbl | 16 +- collects/web-server/scribblings/web.scrbl | 92 +++++---- collects/web-server/templates.rkt | 2 +- 23 files changed, 266 insertions(+), 268 deletions(-) diff --git a/collects/web-server/configuration/responders.rkt b/collects/web-server/configuration/responders.rkt index 0a73ad6d6c..34471c1b38 100644 --- a/collects/web-server/configuration/responders.rkt +++ b/collects/web-server/configuration/responders.rkt @@ -2,6 +2,7 @@ (require racket/runtime-path net/url web-server/private/xexpr + web-server/http/xexpr web-server/http/response-structs web-server/http/request-structs) @@ -24,22 +25,23 @@ "web-server/default-web-root/htdocs/error.css")) (define (pretty-exception-response url exn) - `(html - (head - (title "Servlet Error") - (link ([rel "stylesheet"] [href "/error.css"]))) - (body - (div ([class "section"]) - (div ([class "title"]) "Exception") - (p - "The application raised an exception with the message:" - (pre ,(if (exn:pretty? exn) - (exn:pretty-xexpr exn) - (exn-message exn)))) - (p - "Stack trace:" - ,(format-stack-trace - (continuation-mark-set->context (exn-continuation-marks exn)))))))) + (response/xexpr + `(html + (head + (title "Servlet Error") + (link ([rel "stylesheet"] [href "/error.css"]))) + (body + (div ([class "section"]) + (div ([class "title"]) "Exception") + (p + "The application raised an exception with the message:" + (pre ,(if (exn:pretty? exn) + (exn:pretty-xexpr exn) + (exn-message exn)))) + (p + "Stack trace:" + ,(format-stack-trace + (continuation-mark-set->context (exn-continuation-marks exn))))))))) ; file-response : nat str str [(cons sym str) ...] -> response diff --git a/collects/web-server/default-web-root/htdocs/servlets/examples/template-full.rkt b/collects/web-server/default-web-root/htdocs/servlets/examples/template-full.rkt index 3c0c3853c0..65c03e0179 100644 --- a/collects/web-server/default-web-root/htdocs/servlets/examples/template-full.rkt +++ b/collects/web-server/default-web-root/htdocs/servlets/examples/template-full.rkt @@ -10,4 +10,4 @@ 200 #"Okay" (current-seconds) TEXT/HTML-MIME-TYPE empty - (list (include-template "static.html")))) + (list (string->bytes/utf-8 (include-template "static.html"))))) diff --git a/collects/web-server/default-web-root/htdocs/servlets/examples/template-simple.rkt b/collects/web-server/default-web-root/htdocs/servlets/examples/template-simple.rkt index 586ec8cc09..65c03e0179 100644 --- a/collects/web-server/default-web-root/htdocs/servlets/examples/template-simple.rkt +++ b/collects/web-server/default-web-root/htdocs/servlets/examples/template-simple.rkt @@ -1,8 +1,13 @@ #lang racket -(require web-server/templates) +(require web-server/templates + web-server/http) (provide (all-defined-out)) (define interface-version 'v1) (define timeout +inf.0) (define (start initial-request) - (response/template (include-template "static.html"))) + (response/full + 200 #"Okay" + (current-seconds) TEXT/HTML-MIME-TYPE + empty + (list (string->bytes/utf-8 (include-template "static.html"))))) diff --git a/collects/web-server/default-web-root/htdocs/servlets/examples/template-xexpr.rkt b/collects/web-server/default-web-root/htdocs/servlets/examples/template-xexpr.rkt index abc8b60b7f..984b209930 100644 --- a/collects/web-server/default-web-root/htdocs/servlets/examples/template-xexpr.rkt +++ b/collects/web-server/default-web-root/htdocs/servlets/examples/template-xexpr.rkt @@ -1,5 +1,6 @@ #lang racket (require web-server/templates + web-server/http xml) (provide (all-defined-out)) (define interface-version 'v1) diff --git a/collects/web-server/private/mime-types.rkt b/collects/web-server/private/mime-types.rkt index f79db47da0..bb76d5e1bd 100644 --- a/collects/web-server/private/mime-types.rkt +++ b/collects/web-server/private/mime-types.rkt @@ -5,7 +5,7 @@ (require "util.rkt" web-server/http) (provide/contract - [read-mime-types (path-string? . -> . hash?)] + [read-mime-types (path-string? . -> . (hash/c symbol? bytes?))] [make-path->mime-type (path-string? . -> . (path? . -> . bytes?))]) ; read-mime-types : path? -> hash-table? diff --git a/collects/web-server/scribblings/contracts.scrbl b/collects/web-server/scribblings/contracts.scrbl index e71624958a..c2c4f4fac8 100644 --- a/collects/web-server/scribblings/contracts.scrbl +++ b/collects/web-server/scribblings/contracts.scrbl @@ -3,6 +3,7 @@ @title[#:tag "servlet-structs"]{Common Contracts} @(require (for-label web-server/servlet/servlet-structs + web-server/http web-server/servlet)) @defmodule[web-server/servlet/servlet-structs]{ @@ -19,10 +20,11 @@ Example: @racket["http://localhost:8080/servlets;1*1*20131636/examples/add.rkt"] Equivalent to @racket[(k-url? . -> . response?)]. Example: @racketblock[(lambda (k-url) - `(html - (body - (a ([href ,k-url]) - "Click Me to Invoke the Continuation!"))))] + (response/xexpr + `(html + (body + (a ([href ,k-url]) + "Click Me to Invoke the Continuation!")))))] } @defthing[expiration-handler/c contract?]{ @@ -31,10 +33,11 @@ Equivalent to @racket[(or/c false/c (request? . -> . response?))]. Typically @racket[#f] uses the default expiration handler, which displays an error message. Example: @racketblock[(lambda (req) - `(html (head (title "Expired")) - (body (h1 "Expired") - (p "This URL has expired. " - "Please return to the home page."))))] + (response/xexpr + `(html (head (title "Expired")) + (body (h1 "Expired") + (p "This URL has expired. " + "Please return to the home page.")))))] } @defthing[embed/url/c contract?]{ diff --git a/collects/web-server/scribblings/dispatch-servlets.scrbl b/collects/web-server/scribblings/dispatch-servlets.scrbl index b5026bb701..369679c4f2 100644 --- a/collects/web-server/scribblings/dispatch-servlets.scrbl +++ b/collects/web-server/scribblings/dispatch-servlets.scrbl @@ -1,5 +1,12 @@ #lang scribble/doc -@(require "web-server.rkt") +@(require "web-server.rkt" + (for-label web-server/http + web-server/private/servlet + web-server/configuration/responders + web-server/dispatchers/filesystem-map + web-server/servlet/setup + net/url + web-server/managers/manager)) @title[#:tag "dispatch-servlets"]{Serving Servlets} @a-dispatcher[web-server/dispatchers/dispatch-servlets diff --git a/collects/web-server/scribblings/formlets.scrbl b/collects/web-server/scribblings/formlets.scrbl index 3e5e4102dd..11c8c94898 100755 --- a/collects/web-server/scribblings/formlets.scrbl +++ b/collects/web-server/scribblings/formlets.scrbl @@ -431,19 +431,20 @@ These @tech{formlet}s are the main combinators for form input. @section{Utilities} -@(require (for-label web-server/formlets/servlet)) +@(require (for-label web-server/formlets/servlet + web-server/http)) @defmodule[web-server/formlets/servlet]{ A few utilities are provided for using @tech{formlet}s in Web applications. @defproc[(send/formlet [f (formlet/c any/c ...)] [#:wrap wrapper - (xexpr/c . -> . response?) + (xexpr/c . -> . xexpr/c) (lambda (form-xexpr) `(html (head (title "Form Entry")) (body ,form-xexpr)))]) (values any/c ...)]{ - Uses @racket[send/suspend] to send @racket[f]'s rendering (wrapped in a FORM tag whose action is + Uses @racket[send/suspend] and @racket[response/xexpr] to send @racket[f]'s rendering (wrapped in a FORM tag whose action is the continuation URL (wrapped again by @racket[wrapper])) to the client. When the form is submitted, the request is passed to the processing stage of @racket[f]. diff --git a/collects/web-server/scribblings/http.scrbl b/collects/web-server/scribblings/http.scrbl index 00304bbdf4..4e2a414067 100644 --- a/collects/web-server/scribblings/http.scrbl +++ b/collects/web-server/scribblings/http.scrbl @@ -5,7 +5,7 @@ @defmodule[web-server/http] -The @web-server implements many HTTP RFCs that are provided by this module. +The @web-server implements many HTTP libraries that are provided by this module. @; ------------------------------------------------------------ @section[#:tag "request-structs"]{Requests} @@ -159,35 +159,37 @@ Here is an example typical of what you will find in many applications: @defmodule[web-server/http/response-structs]{ -@defstruct[response/basic +@defstruct*[response ([code number?] [message bytes?] [seconds number?] [mime bytes?] - [headers (listof header?)])]{ - A basic HTTP response containing no body. @racket[code] is the response code, + [headers (listof header?)] + [output (output-port? . -> . void)])]{ + An HTTP response where @racket[output] produces the body. @racket[code] is the response code, @racket[message] the message, @racket[seconds] the generation time, @racket[mime] the MIME type of the file, and @racket[extras] are the extra headers, in addition to those produced by the server. Example: @racketblock[ - (make-response/basic + (response 301 #"Moved Permanently" (current-seconds) TEXT/HTML-MIME-TYPE (list (make-header #"Location" - #"http://racket-lang.org/downloads"))) + #"http://racket-lang.org/downloads")) + (λ (op) (write-bytes #"Moved" op))) ] } - -@defstruct[(response/full response/basic) - ([body (listof bytes?)])]{ - As with @racket[response/basic], except with @racket[body] as the response - body. - + +@defproc[(response/full [code number?] [message bytes?] [seconds number?] [mime bytes?] + [headers (listof header?)] [body (listof bytes?)]) + response?]{ + A constructor for responses where @racket[body] is the response body. + Example: @racketblock[ - (make-response/full + (response/full 301 #"Moved Permanently" (current-seconds) TEXT/HTML-MIME-TYPE (list (make-header #"Location" @@ -199,83 +201,6 @@ Here is an example typical of what you will find in many applications: #"

")) ] } - -@defstruct[(response/port response/basic) - ([output (output-port? . -> . void)])]{ - As with @racket[response/basic], except where @racket[output] generates the response - body. This response type is not as safe and efficient for clients as @racket[response/incremental], - but can be convenient on the server side. - - Example: - @racketblock[ - (make-response/full - 301 #"Moved Permanently" - (current-seconds) TEXT/HTML-MIME-TYPE - (list (make-header #"Location" - #"http://racket-lang.org/downloads")) - (λ (op) - (write-bytes #"

" op) - (write-bytes #"Please go to here instead." op) - (write-bytes #"

" op))) - ] -} - -@defstruct[(response/incremental response/basic) - ([generator ((() () #:rest (listof bytes?) . ->* . any) . -> . any)])]{ - As with @racket[response/basic], except with @racket[generator] as a function that is - called to generate the response body, by being given an @racket[output-response] function - that outputs the content it is called with. If the @racket[output-response] function is called - with arguments of zero length (when concatenated), then the output port is flushed with - @racket[flush-output]. - - Here is a short example: - @racketblock[ - (make-response/incremental - 200 #"OK" (current-seconds) - #"application/octet-stream" - (list (make-header #"Content-Disposition" - #"attachment; filename=\"file\"")) - (lambda (output-response) - (output-response #"Some content") - (output-response) - (output-response #"Even" #"more" #"content!") - (output-response #"Now we're done"))) - ] -} - -@defthing[response/c contract?]{ - Equivalent to - @racketblock[ - (or/c response/basic? - (cons/c bytes? (listof (or/c string? bytes?))) - xexpr/c) - ] -} - -@defproc[(make-xexpr-response [xexpr xexpr/c] - [#:code code number? 200] - [#:message message bytes? #"Okay"] - [#:seconds seconds number? (current-seconds)] - [#:mime-type mime-type bytes? TEXT/HTML-MIME-TYPE] - [#:headers headers (listof header?) empty] - [#:preamble preamble bytes? #""]) - response/full?]{ - Equivalent to - @racketblock[ - (make-response/full - code message seconds mime-type headers - (list preamble (string->bytes/utf-8 (xexpr->string xexpr)))) - ]} - -@defproc[(normalize-response [response response/c] [close? boolean? #f]) - (or/c response/full? response/incremental? response/port?)]{ - Coerces @racket[response] into a full response, filling in additional details where appropriate. - - @racket[close?] represents whether the connection will be closed after the response is sent (i.e. if HTTP 1.0 is being used.) The accuracy of this only matters if -@racket[response] is a @racket[response/incremental?]. -} @defthing[TEXT/HTML-MIME-TYPE bytes?]{Equivalent to @racket[#"text/html; charset=utf-8"].} @@ -289,6 +214,7 @@ transmission that the server @bold{will not catch}.} @(require (for-label net/cookie web-server/servlet + web-server/http/xexpr web-server/http/redirect web-server/http/request-structs web-server/http/response-structs @@ -311,12 +237,6 @@ transmission that the server @bold{will not catch}.} Constructs a header that sets the cookie. } - @defproc[(xexpr-response/cookies [cookies (listof cookie?)] - [xexpr xexpr/c]) - response/full?]{ - Constructs a response using @racket[xexpr] that sets all the cookies in @racket[cookies]. - } - Examples: @racketblock[ (define time-cookie @@ -332,11 +252,11 @@ transmission that the server @bold{will not catch}.} (list time-cookie id-cookie))) (send/suspend - (lambda (k-url) - (xexpr-response/cookies - (list time-cookie id-cookie) - `(html (head (title "Cookie Example")) - (body (h1 "You're cookie'd!")))))) + (lambda (k-url) + (response/xexpr + #:cookies (list time-cookie id-cookie) + `(html (head (title "Cookie Example")) + (body (h1 "You're cookie'd!")))))) ] @warning{When using cookies, make sure you follow the advice of the @link["http://cookies.lcs.mit.edu/"]{MIT Cookie Eaters}, @@ -347,6 +267,7 @@ transmission that the server @bold{will not catch}.} @section[#:tag "cookie-parse"]{Extracting Cookies} @(require (for-label web-server/http/cookie-parse + web-server/http/xexpr net/cookie net/url racket/list)) @@ -384,10 +305,11 @@ transmission that the server @bold{will not catch}.} (cookie->header (make-cookie "id" "joseph")))))) (define (hello who) - `(html (head (title "Hello!")) - (body - (h1 "Hello " - ,who)))) + (response/xexpr + `(html (head (title "Hello!")) + (body + (h1 "Hello " + ,who))))) ] } @@ -424,7 +346,8 @@ transmission that the server @bold{will not catch}.} @; ------------------------------------------------------------ @section[#:tag "basic-auth"]{Basic Authentication} -@(require (for-label web-server/http/basic-auth)) +@(require (for-label web-server/http/response-structs + web-server/http/basic-auth)) @defmodule[web-server/http/basic-auth]{ @@ -449,21 +372,25 @@ web-server/insta (define (start req) (match (request->basic-credentials req) [(cons user pass) - `(html (head (title "Basic Auth Test")) - (body (h1 "User: " ,(bytes->string/utf-8 user)) - (h1 "Pass: " ,(bytes->string/utf-8 pass))))] + (response/xexpr + `(html (head (title "Basic Auth Test")) + (body (h1 "User: " ,(bytes->string/utf-8 user)) + (h1 "Pass: " ,(bytes->string/utf-8 pass)))))] [else - (make-response/basic + (response 401 #"Unauthorized" (current-seconds) TEXT/HTML-MIME-TYPE (list (make-basic-auth-header - (format "Basic Auth Test: ~a" (gensym)))))])) + (format "Basic Auth Test: ~a" (gensym)))) + void)])) ] } @; ------------------------------------------------------------ @section[#:tag "digest-auth"]{Digest Authentication} @(require (for-label web-server/http/digest-auth + web-server/http/xexpr + web-server/http/response-structs racket/pretty)) @defmodule[web-server/http/digest-auth]{ @@ -518,20 +445,48 @@ web-server/insta (define (start req) (match (request->digest-credentials req) [#f - (make-response/basic + (response 401 #"Unauthorized" (current-seconds) TEXT/HTML-MIME-TYPE (list (make-digest-auth-header (format "Digest Auth Test: ~a" (gensym)) - private-key opaque)))] + private-key opaque)) + void)] [alist (define check (make-check-digest-credentials (password->digest-HA1 (lambda (username realm) "pass")))) (define pass? (check "GET" alist)) - `(html (head (title "Digest Auth Test")) - (body - (h1 ,(if pass? "Pass!" "No Pass!")) - (pre ,(pretty-format alist))))])) + (response/xexpr + `(html (head (title "Digest Auth Test")) + (body + (h1 ,(if pass? "Pass!" "No Pass!")) + (pre ,(pretty-format alist)))))])) ] } + +@; ------------------------------------------------------------ +@section[#:tag "xexpr"]{X-expression Support} +@(require (for-label web-server/http/xexpr + xml)) + +@defmodule[web-server/http/xexpr]{ + +@defproc[(response/xexpr [xexpr xexpr/c] + [#:code code number? 200] + [#:message message bytes? #"Okay"] + [#:seconds seconds number? (current-seconds)] + [#:mime-type mime-type bytes? TEXT/HTML-MIME-TYPE] + [#:headers headers (listof header?) empty] + [#:cookies cookies (listof cookie?) empty] + [#:preamble preamble bytes? #""]) + response?]{ + Equivalent to + @racketblock[ + (response/full + code message seconds mime-type + (append headers (map cookie->header cookies)) + (list preamble (string->bytes/utf-8 (xexpr->string xexpr)))) + ]} + +} \ No newline at end of file diff --git a/collects/web-server/scribblings/lang-api.scrbl b/collects/web-server/scribblings/lang-api.scrbl index 0491180334..0724cfc4e9 100644 --- a/collects/web-server/scribblings/lang-api.scrbl +++ b/collects/web-server/scribblings/lang-api.scrbl @@ -49,7 +49,8 @@ An example @racket['stateless] servlet module: serialize-stuffer (md5-stuffer (build-path (find-system-path 'home-dir) ".urls")))) (define (start req) - `(html (body (h2 "Look ma, no state!")))) + (response/xexpr + `(html (body (h2 "Look ma, no state!"))))) ] diff --git a/collects/web-server/scribblings/launch.scrbl b/collects/web-server/scribblings/launch.scrbl index a16533c788..cc69879421 100644 --- a/collects/web-server/scribblings/launch.scrbl +++ b/collects/web-server/scribblings/launch.scrbl @@ -10,6 +10,7 @@ web-server/private/dispatch-server-unit web-server/private/dispatch-server-sig web-server/dispatchers/dispatch + net/tcp-sig racket/async-channel unstable/contract web-server/configuration/configuration-table) diff --git a/collects/web-server/scribblings/mime-types.scrbl b/collects/web-server/scribblings/mime-types.scrbl index 961d9331bc..440d8f0288 100644 --- a/collects/web-server/scribblings/mime-types.scrbl +++ b/collects/web-server/scribblings/mime-types.scrbl @@ -2,7 +2,8 @@ @(require "web-server.rkt") @title[#:tag "mime-types"]{MIME Types} -@(require (for-label web-server/private/mime-types)) +@(require (for-label web-server/private/mime-types + racket/contract)) @defmodule[web-server/private/mime-types]{ @@ -10,7 +11,7 @@ This module provides function for dealing with @filepath{mime.types} files. @defproc[(read-mime-types [p path-string?]) - (hash-table/c symbol? bytes?)]{ + (hash/c symbol? bytes?)]{ Reads the @filepath{mime.types} file from @racket[p] and constructs a hash table mapping extensions to MIME types. } diff --git a/collects/web-server/scribblings/page.scrbl b/collects/web-server/scribblings/page.scrbl index 89df9bd592..5197e7e8c7 100644 --- a/collects/web-server/scribblings/page.scrbl +++ b/collects/web-server/scribblings/page.scrbl @@ -30,13 +30,14 @@ When used inside @racket[page] syntactically, a rename transformer for the proce A simple example: @racketblock[ (page - `(html - (body - (a ([href - ,(embed/url - (λ (req) - "You clicked!"))]) - "Click me"))))] + (response/xexpr + `(html + (body + (a ([href + ,(embed/url + (λ (req) + "You clicked!"))]) + "Click me")))))] Similarly, many Web applications make use almost exclusively of functions that are arguments to @racket[embed/url] and immediately invoke @racket[send/suspend/dispatch]. diff --git a/collects/web-server/scribblings/running.scrbl b/collects/web-server/scribblings/running.scrbl index c34f5bcd20..e4f1fb0322 100644 --- a/collects/web-server/scribblings/running.scrbl +++ b/collects/web-server/scribblings/running.scrbl @@ -9,6 +9,7 @@ There are a number of ways to run Web servlets. @section[#:tag "insta"]{Instant Servlets} @(require (for-label (only-in web-server/insta/insta no-web-browser static-files-path) + web-server/http web-server/servlet-env)) @defmodulelang[web-server/insta #:use-sources (web-server/insta/insta)] @@ -19,9 +20,10 @@ The fastest way to get a servlet running in the Web server is to use the @racketmod[ web-server/insta -(define (start request) - `(html (head (title "Hello world!")) - (body (p "Hey out there!")))) +(define (start req) + (response/xexpr + `(html (head (title "Hello world!")) + (body (p "Hey out there!"))))) ] And press @onscreen["Run"]. A Web browser will open up showing your new servlet. diff --git a/collects/web-server/scribblings/servlet-env-int.scrbl b/collects/web-server/scribblings/servlet-env-int.scrbl index b59a0cebe0..55109d3f23 100644 --- a/collects/web-server/scribblings/servlet-env-int.scrbl +++ b/collects/web-server/scribblings/servlet-env-int.scrbl @@ -5,6 +5,7 @@ @(require (for-label web-server/servlet-env web-server/servlet-dispatch web-server/http + web-server/managers/manager web-server/managers/lru web-server/private/util web-server/dispatchers/dispatch diff --git a/collects/web-server/scribblings/servlet-env.scrbl b/collects/web-server/scribblings/servlet-env.scrbl index 47c805da41..02c625cc1a 100644 --- a/collects/web-server/scribblings/servlet-env.scrbl +++ b/collects/web-server/scribblings/servlet-env.scrbl @@ -28,9 +28,10 @@ racket (require web-server/servlet web-server/servlet-env) -(define (start request) - `(html (head (title "Hello world!")) - (body (p "Hey out there!")))) +(define (start req) + (response/xexpr + `(html (head (title "Hello world!")) + (body (p "Hey out there!"))))) (serve/servlet start) ] @@ -41,9 +42,10 @@ racket (require web-server/servlet web-server/servlet-env) -(define (my-app request) - `(html (head (title "Hello world!")) - (body (p "Hey out there!")))) +(define (my-app req) + (response/xexpr + `(html (head (title "Hello world!")) + (body (p "Hey out there!"))))) (serve/servlet my-app) ] @@ -117,7 +119,8 @@ You can also put the call to @racket[serve/servlet] in the @racketmodname[web-se (start (send/suspend (lambda (k-url) - `(html (body (a ([href ,k-url]) "Hello world!"))))))) + (response/xexpr + `(html (body (a ([href ,k-url]) "Hello world!")))))))) (serve/servlet start #:stateless? #t) ] diff --git a/collects/web-server/scribblings/servlet-setup.scrbl b/collects/web-server/scribblings/servlet-setup.scrbl index bb7bad5cc1..96b6036f7c 100644 --- a/collects/web-server/scribblings/servlet-setup.scrbl +++ b/collects/web-server/scribblings/servlet-setup.scrbl @@ -6,7 +6,9 @@ web-server/http web-server/private/servlet web-server/managers/manager - web-server/configuration/namespace)) + web-server/configuration/namespace + racket/serialize + web-server/stuffers/stuffer)) @defmodule[web-server/servlet/setup]{ diff --git a/collects/web-server/scribblings/servlet.scrbl b/collects/web-server/scribblings/servlet.scrbl index 984d3e293e..84c84b861a 100644 --- a/collects/web-server/scribblings/servlet.scrbl +++ b/collects/web-server/scribblings/servlet.scrbl @@ -39,11 +39,13 @@ An example version 2 module: (define manager (create-none-manager (lambda (req) - `(html (head (title "No Continuations Here!")) - (body (h1 "No Continuations Here!")))))) + (response/xexpr + `(html (head (title "No Continuations Here!")) + (body (h1 "No Continuations Here!"))))))) (define (start req) - `(html (head (title "Hello World!")) - (body (h1 "Hi Mom!")))) + (response/xexpr + `(html (head (title "Hello World!")) + (body (h1 "Hi Mom!"))))) ] These servlets have an extensive API available to them: @racketmodname[net/url], @racketmodname[web-server/http], diff --git a/collects/web-server/scribblings/soft.scrbl b/collects/web-server/scribblings/soft.scrbl index fafa15c534..29d656be3c 100644 --- a/collects/web-server/scribblings/soft.scrbl +++ b/collects/web-server/scribblings/soft.scrbl @@ -1,6 +1,7 @@ #lang scribble/doc @(require "web-server.rkt" - (for-label web-server/lang/soft + (for-label web-server/http + web-server/lang/soft web-server/lang/web)) @title[]{Soft State} @@ -47,7 +48,8 @@ Here's an example servlet that uses soft state: (start (send/suspend (lambda (k-url) - `(html (body (a ([href ,k-url]) "Done"))))))) + (response/xexpr + `(html (body (a ([href ,k-url]) "Done")))))))) ] When this is run and the link is clicked a few times, the output is: diff --git a/collects/web-server/scribblings/templates.scrbl b/collects/web-server/scribblings/templates.scrbl index 7223a69d1e..76c5f5ecdf 100644 --- a/collects/web-server/scribblings/templates.scrbl +++ b/collects/web-server/scribblings/templates.scrbl @@ -256,18 +256,13 @@ Notice how it also avoids the absurd amount of punctuation on line two. @section{HTTP Responses} The quickest way to generate an HTTP response from a template is using -the @racket[list] response type: -@racketblock[ - (list #"text/html" (include-template "static.html")) -] - -If you want more control then you can generate a @racket[response?] struct: +a @racket[response?] struct: @racketblock[ (response/full 200 #"Okay" (current-seconds) TEXT/HTML-MIME-TYPE empty - (list (include-template "static.html"))) + (list (string->bytes/utf-8 (include-template "static.html")))) ] Finally, if you want to include the contents of a template inside a larger @xexpr : @@ -335,12 +330,13 @@ He has divided his code into presentation functions and logic functions. We'll l The first presentation function defines the common layout of all pages. @racketblock[ (define (template section body) - `(html - (head (title "Al's Church: " ,section)) - (body - (h1 "Al's Church: " ,section) - (div ([id "main"]) - ,@body)))) + (response/xexpr + `(html + (head (title "Al's Church: " ,section)) + (body + (h1 "Al's Church: " ,section) + (div ([id "main"]) + ,@body))))) ] One of the things to notice here is the @racket[unquote-splicing] on the @racket[body] argument. @@ -379,32 +375,33 @@ his blog. He changes the @racket[template] function to: @racketblock[ (define (template section body) - `(html - (head - (title "Al's Church: " ,section) - (style ([type "text/css"]) - "body {margin: 0px; padding: 10px;}" - "#main {background: #dddddd;}")) - (body - (script - ([type "text/javascript"]) - ,(make-cdata - #f #f - "var gaJsHost = ((\"https:\" ==" - "document.location.protocol)" - "? \"https://ssl.\" : \"http://www.\");" - "document.write(unescape(\"%3Cscript src='\" + gaJsHost" - "+ \"google-analytics.com/ga.js' " - "type='text/javascript'%3E%3C/script%3E\"));")) - (script - ([type "text/javascript"]) - ,(make-cdata - #f #f - "var pageTracker = _gat._getTracker(\"UA-YYYYYYY-Y\");" - "pageTracker._trackPageview();")) - (h1 "Al's Church: " ,section) - (div ([id "main"]) - ,@body)))) + (response/xexpr + `(html + (head + (title "Al's Church: " ,section) + (style ([type "text/css"]) + "body {margin: 0px; padding: 10px;}" + "#main {background: #dddddd;}")) + (body + (script + ([type "text/javascript"]) + ,(make-cdata + #f #f + "var gaJsHost = ((\"https:\" ==" + "document.location.protocol)" + "? \"https://ssl.\" : \"http://www.\");" + "document.write(unescape(\"%3Cscript src='\" + gaJsHost" + "+ \"google-analytics.com/ga.js' " + "type='text/javascript'%3E%3C/script%3E\"));")) + (script + ([type "text/javascript"]) + ,(make-cdata + #f #f + "var pageTracker = _gat._getTracker(\"UA-YYYYYYY-Y\");" + "pageTracker._trackPageview();")) + (h1 "Al's Church: " ,section) + (div ([id "main"]) + ,@body))))) ] @margin-note{Some of these problems go away by using here strings, as described in the documentation on @@ -447,8 +444,11 @@ To use templates, we need only change @racket[template], @racket[blog-posted], a @racketblock[ (define (template section body) - (list TEXT/HTML-MIME-TYPE - (include-template "blog.html"))) + (response/full + 200 #"Okay" + (current-seconds) TEXT/HTML-MIME-TYPE + empty + (list (string->bytes/utf-8 (include-template "blog.html"))))) (define (blog-posted title body k-url) (include-template "blog-posted.html")) diff --git a/collects/web-server/scribblings/web-cells.scrbl b/collects/web-server/scribblings/web-cells.scrbl index 6fd5721965..c70c2bc281 100644 --- a/collects/web-server/scribblings/web-cells.scrbl +++ b/collects/web-server/scribblings/web-cells.scrbl @@ -2,7 +2,8 @@ @(require "web-server.rkt") @title[#:tag "web-cells"]{Web Cells} -@(require (for-label web-server/servlet/web-cells +@(require (for-label web-server/http + web-server/servlet/web-cells web-server/servlet/web)) @defmodule[web-server/servlet/web-cells]{The @@ -56,12 +57,13 @@ transformations of the program into continuation or store passing style. (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))))))) + (response/xexpr + `(html + (body (h2 "Double Counters") + (div (h3 "First") + ,(include1 embed/url)) + (div (h3 "Second") + ,(include2 embed/url)))))))) (define (make-counter) (make-web-cell 0)) diff --git a/collects/web-server/scribblings/web.scrbl b/collects/web-server/scribblings/web.scrbl index 6f6fc0e850..aed8f461b2 100644 --- a/collects/web-server/scribblings/web.scrbl +++ b/collects/web-server/scribblings/web.scrbl @@ -19,11 +19,12 @@ functions of interest for the servlet developer. Example: @racketblock[ (send/back - `(html - (body - (h1 "The sum is: " - ,(+ first-number - second-number))))) + (response/xexpr + `(html + (body + (h1 "The sum is: " + ,(+ first-number + second-number)))))) ] } @@ -39,12 +40,13 @@ functions of interest for the servlet developer. @racketblock[ (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"]))))))) + (response/xexpr + `(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 @racket[send/suspend]. @@ -78,20 +80,21 @@ functions of interest for the servlet developer. (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)))]) - "+")))))))) + (response/xexpr + `(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)))]) + "+"))))))))) ] Notice that in this example the result of the handlers are returned to the continuation of @racket[send/suspend/dispatch]. However, it is very common that the return value of @racket[send/suspend/dispatch] is irrevelant in @@ -100,20 +103,21 @@ functions of interest for the servlet developer. (define (count-dot-com i) (send/suspend/dispatch (lambda (embed/url) - `(html - (head (title "Count!")) - (body - (h2 (a ([href - ,(embed/url - (lambda (req) - (count-dot-com (sub1 i))))]) - "-")) - (h1 ,(number->string i)) - (h2 (a ([href - ,(embed/url - (lambda (req) - (count-dot-com (add1 i))))]) - "+"))))))) + (response/xexpr + `(html + (head (title "Count!")) + (body + (h2 (a ([href + ,(embed/url + (lambda (req) + (count-dot-com (sub1 i))))]) + "-")) + (h1 ,(number->string i)) + (h2 (a ([href + ,(embed/url + (lambda (req) + (count-dot-com (add1 i))))]) + "+")))))))) ] } @@ -136,9 +140,10 @@ functions of interest for the servlet developer. Use this if the user is truly `done' with your application. For example, it may be used to display the post-logout page: @racketblock[ (send/finish - `(html (head (title "Logged out")) - (body (p "Thank you for using the services " - "of the Add Two Numbers, Inc.")))) + (response/xexpr + `(html (head (title "Logged out")) + (body (p "Thank you for using the services " + "of the Add Two Numbers, Inc."))))) ] } @@ -164,7 +169,8 @@ functions of interest for the servlet developer. (parameterize ([current-servlet-continuation-expiration-handler (lambda (req) - `(html (head (title "Custom Expiration!"))))]) + (response/xexpr + `(html (head (title "Custom Expiration!")))))]) (send/suspend ....)) ] diff --git a/collects/web-server/templates.rkt b/collects/web-server/templates.rkt index 68cd8edb46..33307c3132 100644 --- a/collects/web-server/templates.rkt +++ b/collects/web-server/templates.rkt @@ -1,4 +1,4 @@ -#lang racket +#lang racket/base (require xml scribble/text racket/port)