#lang scribble/doc @(require "web-server.ss") @title[#:tag "web.ss"]{Web Interaction} @(require (for-label web-server/servlet/web web-server/servlet/servlet-structs web-server/http net/url)) @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/c]) 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 (string? . -> . response/c)]) 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/c], 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/url [make-response (url? . -> . response/c)]) request?]{ Like @scheme[send/suspend] but with a URL struct. } @defproc[(send/suspend/dispatch [make-response (((request? . -> . any) . -> . string?) . -> . response/c)]) any]{ Calls @scheme[make-response] with a function (@scheme[embed/url]) 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]. Therefore, if you pass @scheme[embed/url] the identity function, @scheme[send/suspend/dispatch] devolves into @scheme[send/suspend]: @schemeblock[ (define (send/suspend response-generator) (send/suspend/dispatch (lambda (embed/url) (response-generator (embed/url (lambda (x) x)))))) ] 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)))]) "+")))))))) ] Notice that in this example the result of the handlers are returned to the continuation of @scheme[send/suspend/dispatch]. However, 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. Here is the same example in this style: @schemeblock[ (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))))]) "+"))))))) ] } @defproc[(send/suspend/url/dispatch [make-response (((request? . -> . any) . -> . url?) . -> . response/c)]) any]{ Like @scheme[send/suspend/dispatch], but with a URL struct. } @defproc[(send/forward [make-response (string? . -> . response/c)]) 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/c]) 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/c . -> . 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. } }