The teachpack servlet.ss
provides structures and
functions for building Web servlets in Scheme. The data definitions
represent HTTP requests and Web page responses using these two structures:
(define-struct request (method uri headers bindings host-ip client-ip))
(define-struct response/full (code message seconds mime extras body))
constrained as follows:
Env = (listof (cons Symbol String))
Request = (make-request (union 'get 'post) URL Env Env String String)
;; (search for "net" in Help Desk)
Response =
(union
X-expression ;; represent XHTML (search for "XML" in help-desk)
(cons String (listof String))
;; where the first string is the mime type from RFC 2822, often
;; "text/html", and the rest of the strings provide the document's
;; content.
(make-response/full N String N String Env (listof String))
;; where the fields are interpreted as follows:
;; code indicates the HTTP response code.
;; message describes the code in human language.
;; seconds indicates the origination time of the
;; response. Use (current-seconds) for dynamically created responses.
;; mime indicates the response type.
;; extras is an environment with extra headers for redirects, authentication, or cookies.
;; body is the message body.
Suspender = String -> Response
The following functions empower servlets to interact with a Web browser:
build-suspender :
(listof X-expr[HTML]) (listof X-expr[HTML]) [Env] [Env] -> Suspender
head
and
body
tags of the constructed page.
send/suspend : Suspender -> Request
send/finish : Response -> Void
initial-request : Request
extract-binding/single : Symbol Env -> string
extract-bindings : Symbol Env -> (listof String)
extract-string : String Env -> (listof String)
exists-binding? : Symbol Env -> Boolean
extract-user-pass : Env -> (union false (cons string string))
Here is a sample script that permits consumers to login to a site:
; Request -> Request
(define (get-login-information request0)
(let* ([bindings (request-bindings request0)]
[name (extract-bindings 'Name bindings)]
[form '((input ([type "text"][name "Name"][value ""]))
(br)
(input ([type "password"][name "Passwd"]))
(br)
(input ([type "submit"][value "Login"])))])
(if (null? name)
(send/suspend
(build-suspender
'("Login")
form))
(send/suspend
(build-suspender
'("Repeat Login")
`(("Dear "
,(car name)
" your username didn't match your password. Please try again."
(br))
,@form))))))
; Request -> Void
(define (check-login-information request)
(let* ([bindings (request-bindings request)]
[name (extract-binding/single 'Name bindings)]
[passwd (extract-binding/single 'Passwd bindings)])
(if (and (string=? "Paul" name) (string=? "Portland" passwd))
request
(check-login-information (get-login-information request)))))
; Request -> Void
(define (welcome request)
(let ([bindings (request-bindings request)])
(send/finish
`(html
,(extract-binding/single 'Name bindings)
" Thanks for using our service."
" We're glad you recalled that your password is "
,(extract-binding/single 'Passwd bindings)))))
; RUN:
(welcome
(check-login-information
(get-login-information initial-request)))