reformatting, lots of it
svn: r4929
This commit is contained in:
parent
7746993512
commit
2a4c258bef
|
@ -1,15 +1,11 @@
|
|||
|
||||
(module cgi-unit mzscheme
|
||||
(require (lib "unitsig.ss")
|
||||
(lib "etc.ss"))
|
||||
|
||||
(require "cgi-sig.ss")
|
||||
(require (lib "unitsig.ss") "cgi-sig.ss" (lib "etc.ss"))
|
||||
|
||||
(provide net:cgi@)
|
||||
(define net:cgi@
|
||||
(unit/sig net:cgi^
|
||||
(import)
|
||||
|
||||
|
||||
;; type bindings = list ((symbol . string))
|
||||
|
||||
;; --------------------------------------------------------------------
|
||||
|
@ -30,8 +26,7 @@
|
|||
|
||||
;; --------------------------------------------------------------------
|
||||
|
||||
;; query-chars->string :
|
||||
;; list (char) -> string
|
||||
;; query-chars->string : list (char) -> string
|
||||
|
||||
;; -- The input is the characters post-processed as per Web specs, which
|
||||
;; is as follows:
|
||||
|
@ -39,57 +34,53 @@
|
|||
;; where XX are hex digits, eg, %E7 for ~. The output is a regular
|
||||
;; Scheme string with all the characters converted back.
|
||||
|
||||
(define query-chars->string
|
||||
(lambda (chars)
|
||||
(list->string
|
||||
(let loop ((chars chars))
|
||||
(if (null? chars) null
|
||||
(let ((first (car chars))
|
||||
(rest (cdr chars)))
|
||||
(let-values (((this rest)
|
||||
(cond
|
||||
((char=? first #\+)
|
||||
(values #\space rest))
|
||||
((char=? first #\%)
|
||||
(if (and (pair? rest)
|
||||
(pair? (cdr rest)))
|
||||
(values
|
||||
(integer->char
|
||||
(or (string->number
|
||||
(string
|
||||
(car rest) (cadr rest))
|
||||
16)
|
||||
(raise (make-invalid-%-suffix
|
||||
(if (string->number
|
||||
(string (car rest))
|
||||
16)
|
||||
(cadr rest)
|
||||
(car rest))))))
|
||||
(cddr rest))
|
||||
(raise
|
||||
(make-incomplete-%-suffix rest))))
|
||||
(else
|
||||
(values first rest)))))
|
||||
(cons this (loop rest)))))))))
|
||||
(define (query-chars->string chars)
|
||||
(list->string
|
||||
(let loop ([chars chars])
|
||||
(if (null? chars) null
|
||||
(let ([first (car chars)]
|
||||
[rest (cdr chars)])
|
||||
(let-values ([(this rest)
|
||||
(cond
|
||||
[(char=? first #\+)
|
||||
(values #\space rest)]
|
||||
[(char=? first #\%)
|
||||
(if (and (pair? rest)
|
||||
(pair? (cdr rest)))
|
||||
(values
|
||||
(integer->char
|
||||
(or (string->number
|
||||
(string
|
||||
(car rest) (cadr rest))
|
||||
16)
|
||||
(raise (make-invalid-%-suffix
|
||||
(if (string->number
|
||||
(string (car rest))
|
||||
16)
|
||||
(cadr rest)
|
||||
(car rest))))))
|
||||
(cddr rest))
|
||||
(raise
|
||||
(make-incomplete-%-suffix rest)))]
|
||||
[else
|
||||
(values first rest)])])
|
||||
(cons this (loop rest))))))))
|
||||
|
||||
;; string->html :
|
||||
;; string -> string
|
||||
;; string->html : string -> string
|
||||
;; -- the input is raw text, the output is HTML appropriately quoted
|
||||
|
||||
(define string->html
|
||||
(lambda (s)
|
||||
(apply string-append
|
||||
(map (lambda (c)
|
||||
(case c
|
||||
((#\<) "<")
|
||||
((#\>) ">")
|
||||
((#\&) "&")
|
||||
(else (string c))))
|
||||
(string->list s)))))
|
||||
(define (string->html s)
|
||||
(apply string-append (map (lambda (c)
|
||||
(case c
|
||||
[(#\<) "<"]
|
||||
[(#\>) ">"]
|
||||
[(#\&) "&"]
|
||||
[else (string c)]))
|
||||
(string->list s))))
|
||||
|
||||
(define default-text-color "#000000")
|
||||
(define default-bg-color "#ffffff")
|
||||
(define default-link-color "#cc2200")
|
||||
(define default-text-color "#000000")
|
||||
(define default-bg-color "#ffffff")
|
||||
(define default-link-color "#cc2200")
|
||||
(define default-vlink-color "#882200")
|
||||
(define default-alink-color "#444444")
|
||||
|
||||
|
@ -97,230 +88,156 @@
|
|||
;; html-string x list (html-string) x ... -> ()
|
||||
|
||||
(define generate-html-output
|
||||
(opt-lambda (title body-lines
|
||||
(text-color default-text-color)
|
||||
(bg-color default-bg-color)
|
||||
(link-color default-link-color)
|
||||
(vlink-color default-vlink-color)
|
||||
(alink-color default-alink-color))
|
||||
(let ((sa string-append))
|
||||
(for-each
|
||||
(lambda (l)
|
||||
(display l) (newline))
|
||||
`("Content-type: text/html"
|
||||
""
|
||||
"<html>"
|
||||
"<!-- The form was processed, and this document was generated,"
|
||||
" using the CGI utilities for MzScheme. For more information"
|
||||
" on MzScheme, see"
|
||||
" http://www.plt-scheme.org/software/mzscheme/"
|
||||
" and for the CGI utilities, contact"
|
||||
" (sk@cs.brown.edu). -->"
|
||||
|
||||
"<head>"
|
||||
,(sa "<title>" title "</title>")
|
||||
"</head>"
|
||||
""
|
||||
,(sa "<body bgcolor=\"" bg-color "\" text=\"" text-color "\"")
|
||||
,(sa " link=\"" link-color "\"")
|
||||
,(sa " vlink=\"" vlink-color "\" alink=\"" alink-color "\">")
|
||||
""
|
||||
,@body-lines
|
||||
""
|
||||
"</body>"
|
||||
"</html>")))))
|
||||
|
||||
(opt-lambda (title body-lines
|
||||
[text-color default-text-color]
|
||||
[bg-color default-bg-color]
|
||||
[link-color default-link-color]
|
||||
[vlink-color default-vlink-color]
|
||||
[alink-color default-alink-color])
|
||||
(let ([sa string-append])
|
||||
(for-each
|
||||
(lambda (l) (display l) (newline))
|
||||
`("Content-type: text/html"
|
||||
""
|
||||
"<html>"
|
||||
"<!-- The form was processed, and this document was generated,"
|
||||
" using the CGI utilities for MzScheme. For more information"
|
||||
" on MzScheme, see"
|
||||
" http://www.plt-scheme.org/software/mzscheme/"
|
||||
" and for the CGI utilities, contact"
|
||||
" (sk@cs.brown.edu). -->"
|
||||
"<head>"
|
||||
,(sa "<title>" title "</title>")
|
||||
"</head>"
|
||||
""
|
||||
,(sa "<body bgcolor=\"" bg-color "\" text=\"" text-color "\"")
|
||||
,(sa " link=\"" link-color "\"")
|
||||
,(sa " vlink=\"" vlink-color "\" alink=\"" alink-color "\">")
|
||||
""
|
||||
,@body-lines
|
||||
""
|
||||
"</body>"
|
||||
"</html>")))))
|
||||
|
||||
;; output-http-headers : -> void
|
||||
(define (output-http-headers)
|
||||
(printf "Content-type: text/html~a~n~a~n" #\return #\return))
|
||||
|
||||
;; read-until-char :
|
||||
;; iport x char -> list (char) x bool
|
||||
(printf "Content-type: text/html\r\n\r\n"))
|
||||
|
||||
;; read-until-char : iport x char -> list (char) x bool
|
||||
;; -- operates on the default input port; the second value indicates
|
||||
;; whether reading stopped because an EOF was hit (as opposed to the
|
||||
;; delimiter being seen); the delimiter is not part of the result
|
||||
|
||||
(define read-until-char
|
||||
(lambda (ip delimiter)
|
||||
(let loop ((chars '()))
|
||||
(let ((c (read-char ip)))
|
||||
(cond
|
||||
((eof-object? c)
|
||||
(values (reverse chars) #t))
|
||||
((char=? c delimiter)
|
||||
(values (reverse chars) #f))
|
||||
(else
|
||||
(loop (cons c chars))))))))
|
||||
|
||||
;; read-name+value :
|
||||
;; iport -> (symbol + bool) x (string + bool) x bool
|
||||
(define (read-until-char ip delimiter)
|
||||
(let loop ([chars '()])
|
||||
(let ([c (read-char ip)])
|
||||
(cond [(eof-object? c) (values (reverse chars) #t)]
|
||||
[(char=? c delimiter) (values (reverse chars) #f)]
|
||||
[else (loop (cons c chars))]))))
|
||||
|
||||
;; read-name+value : iport -> (symbol + bool) x (string + bool) x bool
|
||||
;; -- If the first value is false, so is the second, and the third is
|
||||
;; true, indicating EOF was reached without any input seen. Otherwise,
|
||||
;; the first and second values contain strings and the third is either
|
||||
;; true or false depending on whether the EOF has been reached. The
|
||||
;; strings are processed to remove the CGI spec "escape"s.
|
||||
|
||||
;; This code is _slightly_ lax: it allows an input to end in `&'. It's
|
||||
;; not clear this is legal by the CGI spec, which suggests that the last
|
||||
;; value binding must end in an EOF. It doesn't look like this matters.
|
||||
;; It would also introduce needless modality and reduce flexibility.
|
||||
(define (read-name+value ip)
|
||||
(let-values ([(name eof?) (read-until-char ip #\=)])
|
||||
(cond [(and eof? (null? name)) (values #f #f #t)]
|
||||
[eof?
|
||||
(generate-error-output
|
||||
(list "Server generated malformed input for POST method:"
|
||||
(string-append
|
||||
"No binding for `" (list->string name) "' field.")))]
|
||||
[else (let-values ([(value eof?) (read-until-char ip #\&)])
|
||||
(values (string->symbol (query-chars->string name))
|
||||
(query-chars->string value)
|
||||
eof?))])))
|
||||
|
||||
(define read-name+value
|
||||
(lambda (ip)
|
||||
(let-values
|
||||
(((name eof?)
|
||||
(read-until-char ip #\=)))
|
||||
(cond
|
||||
((and eof? (null? name))
|
||||
(values #f #f #t))
|
||||
(eof?
|
||||
(generate-error-output
|
||||
(list "Server generated malformed input for POST method:"
|
||||
(string-append
|
||||
"No binding for `" (list->string name) "' field."))))
|
||||
(else
|
||||
(let-values (((value eof?)
|
||||
(read-until-char ip #\&)))
|
||||
(values (string->symbol (query-chars->string name))
|
||||
(query-chars->string value)
|
||||
eof?)))))))
|
||||
|
||||
;; get-bindings/post :
|
||||
;; () -> bindings
|
||||
|
||||
(define get-bindings/post
|
||||
(lambda ()
|
||||
(let-values (((name value eof?)
|
||||
(read-name+value
|
||||
(current-input-port))))
|
||||
(cond
|
||||
((and eof? (not name))
|
||||
null)
|
||||
((and eof? name)
|
||||
(list (cons name value)))
|
||||
(else
|
||||
(cons (cons name value)
|
||||
(get-bindings/post)))))))
|
||||
;; get-bindings/post : () -> bindings
|
||||
(define (get-bindings/post)
|
||||
(let-values ([(name value eof?) (read-name+value (current-input-port))])
|
||||
(cond [(and eof? (not name)) null]
|
||||
[(and eof? name) (list (cons name value))]
|
||||
[else (cons (cons name value) (get-bindings/post))])))
|
||||
|
||||
;; get-bindings/get :
|
||||
;; () -> bindings
|
||||
;; get-bindings/get : () -> bindings
|
||||
(define (get-bindings/get)
|
||||
(let ([p (open-input-string (getenv "QUERY_STRING"))])
|
||||
(let loop ()
|
||||
(let-values ([(name value eof?) (read-name+value p)])
|
||||
(cond [(and eof? (not name)) null]
|
||||
[(and eof? name) (list (cons name value))]
|
||||
[else (cons (cons name value) (loop))])))))
|
||||
|
||||
(define get-bindings/get
|
||||
(lambda ()
|
||||
(let ((p (open-input-string
|
||||
(getenv "QUERY_STRING"))))
|
||||
(let loop ()
|
||||
(let-values (((name value eof?)
|
||||
(read-name+value p)))
|
||||
(cond
|
||||
((and eof? (not name))
|
||||
null)
|
||||
((and eof? name)
|
||||
(list (cons name value)))
|
||||
(else
|
||||
(cons (cons name value)
|
||||
(loop)))))))))
|
||||
;; get-bindings : () -> bindings
|
||||
(define (get-bindings)
|
||||
(if (string=? (get-cgi-method) "POST")
|
||||
(get-bindings/post)
|
||||
(get-bindings/get)))
|
||||
|
||||
;; get-bindings :
|
||||
;; () -> bindings
|
||||
;; generate-error-output : list (html-string) -> <exit>
|
||||
(define (generate-error-output error-message-lines)
|
||||
(generate-html-output "Internal Error" error-message-lines)
|
||||
(exit))
|
||||
|
||||
(define get-bindings
|
||||
(lambda ()
|
||||
(if (string=? (get-cgi-method) "POST")
|
||||
(get-bindings/post)
|
||||
(get-bindings/get))))
|
||||
|
||||
;; generate-error-output :
|
||||
;; list (html-string) -> <exit>
|
||||
|
||||
(define generate-error-output
|
||||
(lambda (error-message-lines)
|
||||
(generate-html-output "Internal Error"
|
||||
error-message-lines)
|
||||
(exit)))
|
||||
|
||||
;; bindings-as-html :
|
||||
;; bindings -> list (html-string)
|
||||
;; bindings-as-html : bindings -> list (html-string)
|
||||
;; -- formats name-value bindings as HTML appropriate for displaying
|
||||
(define (bindings-as-html bindings)
|
||||
`("<code>"
|
||||
,@(map (lambda (bind)
|
||||
(string-append (symbol->string (car bind))
|
||||
" --> "
|
||||
(cdr bind)
|
||||
"<br>"))
|
||||
bindings)
|
||||
"</code>"))
|
||||
|
||||
(define bindings-as-html
|
||||
(lambda (bindings)
|
||||
`("<code>"
|
||||
,@(map
|
||||
(lambda (bind)
|
||||
(string-append
|
||||
(symbol->string (car bind))
|
||||
" --> "
|
||||
(cdr bind)
|
||||
"<br>"))
|
||||
bindings)
|
||||
"</code>")))
|
||||
|
||||
;; extract-bindings :
|
||||
;; (string + symbol) x bindings -> list (string)
|
||||
|
||||
;; extract-bindings : (string + symbol) x bindings -> list (string)
|
||||
;; -- Extracts the bindings associated with a given name. The semantics
|
||||
;; of forms states that a CHECKBOX may use the same NAME field multiple
|
||||
;; times. Hence, a list of strings is returned. Note that the result
|
||||
;; may be the empty list.
|
||||
(define (extract-bindings field-name bindings)
|
||||
(let ([field-name (if (symbol? field-name)
|
||||
field-name (string->symbol field-name))])
|
||||
(let loop ([found null] [bindings bindings])
|
||||
(if (null? bindings)
|
||||
found
|
||||
(if (equal? field-name (caar bindings))
|
||||
(loop (cons (cdar bindings) found) (cdr bindings))
|
||||
(loop found (cdr bindings)))))))
|
||||
|
||||
(define extract-bindings
|
||||
(lambda (field-name bindings)
|
||||
(let ((field-name (if (symbol? field-name) field-name
|
||||
(string->symbol field-name))))
|
||||
(let loop ((found null) (bindings bindings))
|
||||
(if (null? bindings)
|
||||
found
|
||||
(if (equal? field-name (caar bindings))
|
||||
(loop (cons (cdar bindings) found) (cdr bindings))
|
||||
(loop found (cdr bindings))))))))
|
||||
|
||||
;; extract-binding/single :
|
||||
;; (string + symbol) x bindings -> string
|
||||
;; extract-binding/single : (string + symbol) x bindings -> string
|
||||
;; -- used in cases where only one binding is supposed to occur
|
||||
(define (extract-binding/single field-name bindings)
|
||||
(let* ([field-name (if (symbol? field-name)
|
||||
field-name (string->symbol field-name))]
|
||||
[result (extract-bindings field-name bindings)])
|
||||
(cond
|
||||
[(null? result)
|
||||
(generate-error-output
|
||||
(cons (format "No binding for field `~a':<br>" field-name)
|
||||
(bindings-as-html bindings)))]
|
||||
[(null? (cdr result))
|
||||
(car result)]
|
||||
[else
|
||||
(generate-error-output
|
||||
(cons (format "Multiple bindings for field `~a' where one expected:<br>"
|
||||
field-name)
|
||||
(bindings-as-html bindings)))])))
|
||||
|
||||
(define extract-binding/single
|
||||
(lambda (field-name bindings)
|
||||
(let ((field-name (if (symbol? field-name) field-name
|
||||
(string->symbol field-name))))
|
||||
(let ((result (extract-bindings field-name bindings)))
|
||||
(cond
|
||||
((null? result)
|
||||
(generate-error-output
|
||||
`(,(string-append "No binding for field `"
|
||||
(if (symbol? field-name)
|
||||
(symbol->string field-name)
|
||||
field-name)
|
||||
"' in <p>")
|
||||
,@(bindings-as-html bindings))))
|
||||
((null? (cdr result))
|
||||
(car result))
|
||||
(else
|
||||
(generate-error-output
|
||||
`(,(string-append "Multiple bindings for field `"
|
||||
(if (symbol? field-name)
|
||||
(symbol->string field-name)
|
||||
field-name)
|
||||
"' where only one was expected in <p>")
|
||||
,@(bindings-as-html bindings)))))))))
|
||||
|
||||
;; get-cgi-method :
|
||||
;; () -> string
|
||||
;; get-cgi-method : () -> string
|
||||
;; -- string is either GET or POST (though future extension is possible)
|
||||
(define (get-cgi-method)
|
||||
(getenv "REQUEST_METHOD"))
|
||||
|
||||
(define get-cgi-method
|
||||
(lambda ()
|
||||
(getenv "REQUEST_METHOD")))
|
||||
|
||||
;; generate-link-text :
|
||||
;; string x html-string -> html-string
|
||||
|
||||
(define generate-link-text
|
||||
(lambda (url anchor-text)
|
||||
(string-append "<a href=\"" url "\">" anchor-text "</a>")))
|
||||
|
||||
;; ====================================================================
|
||||
;; generate-link-text : string x html-string -> html-string
|
||||
(define (generate-link-text url anchor-text)
|
||||
(string-append "<a href=\"" url "\">" anchor-text "</a>"))
|
||||
|
||||
)))
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user