reformatting, lots of it

svn: r4929
This commit is contained in:
Eli Barzilay 2006-11-23 03:59:57 +00:00
parent 7746993512
commit 2a4c258bef

View File

@ -1,9 +1,5 @@
(module cgi-unit mzscheme (module cgi-unit mzscheme
(require (lib "unitsig.ss") (require (lib "unitsig.ss") "cgi-sig.ss" (lib "etc.ss"))
(lib "etc.ss"))
(require "cgi-sig.ss")
(provide net:cgi@) (provide net:cgi@)
(define net:cgi@ (define net:cgi@
@ -30,8 +26,7 @@
;; -------------------------------------------------------------------- ;; --------------------------------------------------------------------
;; query-chars->string : ;; query-chars->string : list (char) -> string
;; list (char) -> string
;; -- The input is the characters post-processed as per Web specs, which ;; -- The input is the characters post-processed as per Web specs, which
;; is as follows: ;; is as follows:
@ -39,18 +34,17 @@
;; where XX are hex digits, eg, %E7 for ~. The output is a regular ;; where XX are hex digits, eg, %E7 for ~. The output is a regular
;; Scheme string with all the characters converted back. ;; Scheme string with all the characters converted back.
(define query-chars->string (define (query-chars->string chars)
(lambda (chars)
(list->string (list->string
(let loop ((chars chars)) (let loop ([chars chars])
(if (null? chars) null (if (null? chars) null
(let ((first (car chars)) (let ([first (car chars)]
(rest (cdr chars))) [rest (cdr chars)])
(let-values (((this rest) (let-values ([(this rest)
(cond (cond
((char=? first #\+) [(char=? first #\+)
(values #\space rest)) (values #\space rest)]
((char=? first #\%) [(char=? first #\%)
(if (and (pair? rest) (if (and (pair? rest)
(pair? (cdr rest))) (pair? (cdr rest)))
(values (values
@ -67,25 +61,22 @@
(car rest)))))) (car rest))))))
(cddr rest)) (cddr rest))
(raise (raise
(make-incomplete-%-suffix rest)))) (make-incomplete-%-suffix rest)))]
(else [else
(values first rest))))) (values first rest)])])
(cons this (loop rest))))))))) (cons this (loop rest))))))))
;; string->html : ;; string->html : string -> string
;; string -> string
;; -- the input is raw text, the output is HTML appropriately quoted ;; -- the input is raw text, the output is HTML appropriately quoted
(define string->html (define (string->html s)
(lambda (s) (apply string-append (map (lambda (c)
(apply string-append
(map (lambda (c)
(case c (case c
((#\<) "&lt;") [(#\<) "&lt;"]
((#\>) "&gt;") [(#\>) "&gt;"]
((#\&) "&amp;") [(#\&) "&amp;"]
(else (string c)))) [else (string c)]))
(string->list s))))) (string->list s))))
(define default-text-color "#000000") (define default-text-color "#000000")
(define default-bg-color "#ffffff") (define default-bg-color "#ffffff")
@ -98,15 +89,14 @@
(define generate-html-output (define generate-html-output
(opt-lambda (title body-lines (opt-lambda (title body-lines
(text-color default-text-color) [text-color default-text-color]
(bg-color default-bg-color) [bg-color default-bg-color]
(link-color default-link-color) [link-color default-link-color]
(vlink-color default-vlink-color) [vlink-color default-vlink-color]
(alink-color default-alink-color)) [alink-color default-alink-color])
(let ((sa string-append)) (let ([sa string-append])
(for-each (for-each
(lambda (l) (lambda (l) (display l) (newline))
(display l) (newline))
`("Content-type: text/html" `("Content-type: text/html"
"" ""
"<html>" "<html>"
@ -116,7 +106,6 @@
" http://www.plt-scheme.org/software/mzscheme/" " http://www.plt-scheme.org/software/mzscheme/"
" and for the CGI utilities, contact" " and for the CGI utilities, contact"
" (sk@cs.brown.edu). -->" " (sk@cs.brown.edu). -->"
"<head>" "<head>"
,(sa "<title>" title "</title>") ,(sa "<title>" title "</title>")
"</head>" "</head>"
@ -132,195 +121,123 @@
;; output-http-headers : -> void ;; output-http-headers : -> void
(define (output-http-headers) (define (output-http-headers)
(printf "Content-type: text/html~a~n~a~n" #\return #\return)) (printf "Content-type: text/html\r\n\r\n"))
;; read-until-char : ;; read-until-char : iport x char -> list (char) x bool
;; iport x char -> list (char) x bool
;; -- operates on the default input port; the second value indicates ;; -- operates on the default input port; the second value indicates
;; whether reading stopped because an EOF was hit (as opposed to the ;; whether reading stopped because an EOF was hit (as opposed to the
;; delimiter being seen); the delimiter is not part of the result ;; delimiter being seen); the delimiter is not part of the result
(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))]))))
(define read-until-char ;; read-name+value : iport -> (symbol + bool) x (string + bool) x bool
(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
;; -- If the first value is false, so is the second, and the third is ;; -- If the first value is false, so is the second, and the third is
;; true, indicating EOF was reached without any input seen. Otherwise, ;; true, indicating EOF was reached without any input seen. Otherwise,
;; the first and second values contain strings and the third is either ;; the first and second values contain strings and the third is either
;; true or false depending on whether the EOF has been reached. The ;; true or false depending on whether the EOF has been reached. The
;; strings are processed to remove the CGI spec "escape"s. ;; strings are processed to remove the CGI spec "escape"s.
;; This code is _slightly_ lax: it allows an input to end in `&'. It'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 ;; 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. ;; value binding must end in an EOF. It doesn't look like this matters.
;; It would also introduce needless modality and reduce flexibility. ;; It would also introduce needless modality and reduce flexibility.
(define (read-name+value ip)
(define read-name+value (let-values ([(name eof?) (read-until-char ip #\=)])
(lambda (ip) (cond [(and eof? (null? name)) (values #f #f #t)]
(let-values [eof?
(((name eof?)
(read-until-char ip #\=)))
(cond
((and eof? (null? name))
(values #f #f #t))
(eof?
(generate-error-output (generate-error-output
(list "Server generated malformed input for POST method:" (list "Server generated malformed input for POST method:"
(string-append (string-append
"No binding for `" (list->string name) "' field.")))) "No binding for `" (list->string name) "' field.")))]
(else [else (let-values ([(value eof?) (read-until-char ip #\&)])
(let-values (((value eof?)
(read-until-char ip #\&)))
(values (string->symbol (query-chars->string name)) (values (string->symbol (query-chars->string name))
(query-chars->string value) (query-chars->string value)
eof?))))))) eof?))])))
;; get-bindings/post : ;; get-bindings/post : () -> bindings
;; () -> 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))])))
(define get-bindings/post ;; get-bindings/get : () -> bindings
(lambda () (define (get-bindings/get)
(let-values (((name value eof?) (let ([p (open-input-string (getenv "QUERY_STRING"))])
(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
(define get-bindings/get
(lambda ()
(let ((p (open-input-string
(getenv "QUERY_STRING"))))
(let loop () (let loop ()
(let-values (((name value eof?) (let-values ([(name value eof?) (read-name+value p)])
(read-name+value p))) (cond [(and eof? (not name)) null]
(cond [(and eof? name) (list (cons name value))]
((and eof? (not name)) [else (cons (cons name value) (loop))])))))
null)
((and eof? name)
(list (cons name value)))
(else
(cons (cons name value)
(loop)))))))))
;; get-bindings : ;; get-bindings : () -> bindings
;; () -> bindings (define (get-bindings)
(define get-bindings
(lambda ()
(if (string=? (get-cgi-method) "POST") (if (string=? (get-cgi-method) "POST")
(get-bindings/post) (get-bindings/post)
(get-bindings/get)))) (get-bindings/get)))
;; generate-error-output : ;; generate-error-output : list (html-string) -> <exit>
;; list (html-string) -> <exit> (define (generate-error-output error-message-lines)
(generate-html-output "Internal Error" error-message-lines)
(exit))
(define generate-error-output ;; bindings-as-html : bindings -> list (html-string)
(lambda (error-message-lines)
(generate-html-output "Internal Error"
error-message-lines)
(exit)))
;; bindings-as-html :
;; bindings -> list (html-string)
;; -- formats name-value bindings as HTML appropriate for displaying ;; -- formats name-value bindings as HTML appropriate for displaying
(define (bindings-as-html bindings)
(define bindings-as-html
(lambda (bindings)
`("<code>" `("<code>"
,@(map ,@(map (lambda (bind)
(lambda (bind) (string-append (symbol->string (car bind))
(string-append
(symbol->string (car bind))
"&nbsp;--&gt;&nbsp;" "&nbsp;--&gt;&nbsp;"
(cdr bind) (cdr bind)
"<br>")) "<br>"))
bindings) bindings)
"</code>"))) "</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 ;; -- Extracts the bindings associated with a given name. The semantics
;; of forms states that a CHECKBOX may use the same NAME field multiple ;; 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 ;; times. Hence, a list of strings is returned. Note that the result
;; may be the empty list. ;; may be the empty list.
(define (extract-bindings field-name bindings)
(define extract-bindings (let ([field-name (if (symbol? field-name)
(lambda (field-name bindings) field-name (string->symbol field-name))])
(let ((field-name (if (symbol? field-name) field-name (let loop ([found null] [bindings bindings])
(string->symbol field-name))))
(let loop ((found null) (bindings bindings))
(if (null? bindings) (if (null? bindings)
found found
(if (equal? field-name (caar bindings)) (if (equal? field-name (caar bindings))
(loop (cons (cdar bindings) found) (cdr bindings)) (loop (cons (cdar bindings) found) (cdr bindings))
(loop found (cdr bindings)))))))) (loop found (cdr bindings)))))))
;; extract-binding/single : ;; extract-binding/single : (string + symbol) x bindings -> string
;; (string + symbol) x bindings -> string
;; -- used in cases where only one binding is supposed to occur ;; -- used in cases where only one binding is supposed to occur
(define (extract-binding/single field-name bindings)
(define extract-binding/single (let* ([field-name (if (symbol? field-name)
(lambda (field-name bindings) field-name (string->symbol field-name))]
(let ((field-name (if (symbol? field-name) field-name [result (extract-bindings field-name bindings)])
(string->symbol field-name))))
(let ((result (extract-bindings field-name bindings)))
(cond (cond
((null? result) [(null? result)
(generate-error-output (generate-error-output
`(,(string-append "No binding for field `" (cons (format "No binding for field `~a':<br>" field-name)
(if (symbol? field-name) (bindings-as-html bindings)))]
(symbol->string field-name) [(null? (cdr result))
field-name) (car result)]
"' in <p>") [else
,@(bindings-as-html bindings))))
((null? (cdr result))
(car result))
(else
(generate-error-output (generate-error-output
`(,(string-append "Multiple bindings for field `" (cons (format "Multiple bindings for field `~a' where one expected:<br>"
(if (symbol? field-name)
(symbol->string field-name)
field-name) field-name)
"' where only one was expected in <p>") (bindings-as-html bindings)))])))
,@(bindings-as-html bindings)))))))))
;; get-cgi-method : ;; get-cgi-method : () -> string
;; () -> string
;; -- string is either GET or POST (though future extension is possible) ;; -- string is either GET or POST (though future extension is possible)
(define (get-cgi-method)
(getenv "REQUEST_METHOD"))
(define get-cgi-method ;; generate-link-text : string x html-string -> html-string
(lambda () (define (generate-link-text url anchor-text)
(getenv "REQUEST_METHOD"))) (string-append "<a href=\"" url "\">" anchor-text "</a>"))
;; 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>")))
;; ====================================================================
))) )))