Moved `net/cgi' code from unit to module.
original commit: a5222b948186d80552ff70ee154c86719d1db758
This commit is contained in:
parent
f5de3bb7a4
commit
311fa622a0
|
@ -20,4 +20,3 @@ get-cgi-method
|
|||
;; -- general HTML utilities --
|
||||
string->html
|
||||
generate-link-text
|
||||
|
||||
|
|
|
@ -1,207 +1,8 @@
|
|||
#lang racket/unit
|
||||
(require "cgi-sig.rkt" "uri-codec.rkt")
|
||||
#lang racket/base
|
||||
|
||||
(import)
|
||||
(export cgi^)
|
||||
(require racket/unit
|
||||
"cgi-sig.rkt" "cgi.rkt")
|
||||
|
||||
;; type bindings = list ((symbol . string))
|
||||
(define-unit-from-context cgi@ cgi^)
|
||||
|
||||
;; --------------------------------------------------------------------
|
||||
|
||||
;; Exceptions:
|
||||
|
||||
(define-struct cgi-error ())
|
||||
|
||||
;; chars : list (char)
|
||||
;; -- gives the suffix which is invalid, not including the `%'
|
||||
|
||||
(define-struct (incomplete-%-suffix cgi-error) (chars))
|
||||
|
||||
;; char : char
|
||||
;; -- an invalid character in a hex string
|
||||
|
||||
(define-struct (invalid-%-suffix cgi-error) (char))
|
||||
|
||||
;; --------------------------------------------------------------------
|
||||
|
||||
;; query-string->string : string -> string
|
||||
|
||||
;; -- The input is the string post-processed as per Web specs, which
|
||||
;; is as follows:
|
||||
;; spaces are turned into "+"es and lots of things are turned into %XX, where
|
||||
;; XX are hex digits, eg, %E7 for ~. The output is a regular Scheme string
|
||||
;; with all the characters converted back.
|
||||
|
||||
(define query-string->string form-urlencoded-decode)
|
||||
|
||||
;; string->html : string -> string
|
||||
;; -- the input is raw text, the output is HTML appropriately quoted
|
||||
|
||||
(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-vlink-color "#882200")
|
||||
(define default-alink-color "#444444")
|
||||
|
||||
;; generate-html-output :
|
||||
;; html-string x list (html-string) x ... -> ()
|
||||
|
||||
(define (generate-html-output 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 ([l `("Content-type: text/html"
|
||||
""
|
||||
"<html>"
|
||||
"<!-- The form was processed, and this document was generated,"
|
||||
" using the CGI utilities for Racket. For more information"
|
||||
" on Racket, see"
|
||||
" http://racket-lang.org/"
|
||||
" 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>")])
|
||||
(display l)
|
||||
(newline))))
|
||||
|
||||
;; output-http-headers : -> void
|
||||
(define (output-http-headers)
|
||||
(printf "Content-type: text/html\r\n\r\n"))
|
||||
|
||||
;; delimiter->predicate : symbol -> regexp
|
||||
;; returns a regexp to read a chunk of text up to a delimiter (excluding it)
|
||||
(define (delimiter->rx delimiter)
|
||||
(case delimiter
|
||||
[(amp) #rx#"^[^&]*"]
|
||||
[(semi) #rx#"^[^;]*"]
|
||||
[(amp-or-semi) #rx#"^[^&;]*"]
|
||||
[else (error 'delimiter->rx
|
||||
"internal-error, unknown delimiter: ~e" delimiter)]))
|
||||
|
||||
;; get-bindings* : iport -> (listof (cons symbol string))
|
||||
;; Reads all bindings from the input port. The strings are processed to
|
||||
;; remove the CGI spec "escape"s.
|
||||
;; This code is _slightly_ lax: it allows an input to end in
|
||||
;; (current-alist-separator-mode). 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.
|
||||
;; ELI: * Keeping this behavior for now, maybe better to remove it?
|
||||
;; * Looks like `form-urlencoded->alist' is doing almost exactly
|
||||
;; the same job this code does.
|
||||
(define (get-bindings* method ip)
|
||||
(define (err fmt . xs)
|
||||
(generate-error-output
|
||||
(list (format "Server generated malformed input for ~a method:" method)
|
||||
(apply format fmt xs))))
|
||||
(define value-rx (delimiter->rx (current-alist-separator-mode)))
|
||||
(define (process str) (query-string->string (bytes->string/utf-8 str)))
|
||||
(let loop ([bindings '()])
|
||||
(if (eof-object? (peek-char ip))
|
||||
(reverse bindings)
|
||||
(let ()
|
||||
(define name (car (or (regexp-match #rx"^[^=]+" ip)
|
||||
(err "Missing field name before `='"))))
|
||||
(unless (eq? #\= (read-char ip))
|
||||
(err "No binding for `~a' field." name))
|
||||
(define value (car (regexp-match value-rx ip)))
|
||||
(read-char ip) ; consume the delimiter, possibly eof (retested above)
|
||||
(loop (cons (cons (string->symbol (process name)) (process value))
|
||||
bindings))))))
|
||||
|
||||
;; get-bindings/post : () -> bindings
|
||||
(define (get-bindings/post)
|
||||
(get-bindings* "POST" (current-input-port)))
|
||||
|
||||
;; get-bindings/get : () -> bindings
|
||||
(define (get-bindings/get)
|
||||
(get-bindings* "GET" (open-input-string (getenv "QUERY_STRING"))))
|
||||
|
||||
;; get-bindings : () -> bindings
|
||||
(define (get-bindings)
|
||||
(if (string=? (get-cgi-method) "POST")
|
||||
(get-bindings/post)
|
||||
(get-bindings/get)))
|
||||
|
||||
;; generate-error-output : list (html-string) -> <exit>
|
||||
(define (generate-error-output 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
|
||||
(define (bindings-as-html bindings)
|
||||
`("<code>"
|
||||
,@(map (lambda (bind)
|
||||
(string-append (symbol->string (car bind))
|
||||
" --> "
|
||||
(cdr bind)
|
||||
"<br>"))
|
||||
bindings)
|
||||
"</code>"))
|
||||
|
||||
;; 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)))))))
|
||||
|
||||
;; 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)))])))
|
||||
|
||||
;; get-cgi-method : () -> string
|
||||
;; -- string is either GET or POST (though future extension is possible)
|
||||
(define (get-cgi-method)
|
||||
(or (getenv "REQUEST_METHOD")
|
||||
(error 'get-cgi-method "no REQUEST_METHOD environment variable")))
|
||||
|
||||
;; generate-link-text : string x html-string -> html-string
|
||||
(define (generate-link-text url anchor-text)
|
||||
(string-append "<a href=\"" url "\">" anchor-text "</a>"))
|
||||
(provide cgi@)
|
||||
|
|
Loading…
Reference in New Issue
Block a user