pr7974 + include in release

svn: r14132
This commit is contained in:
Jay McCarthy 2009-03-16 18:45:16 +00:00
parent fb15ae339f
commit f9c4e4eb54
3 changed files with 75 additions and 6 deletions

View File

@ -96,32 +96,47 @@
;; -- operates on the default input port; the second value indicates whether ;; -- operates on the default input port; the second value indicates whether
;; reading stopped because an EOF was hit (as opposed to the delimiter being ;; reading stopped because an EOF was hit (as opposed to the delimiter being
;; seen); the delimiter is not part of the result ;; seen); the delimiter is not part of the result
(define (read-until-char ip delimiter) (define (read-until-char ip delimiter?)
(let loop ([chars '()]) (let loop ([chars '()])
(let ([c (read-char ip)]) (let ([c (read-char ip)])
(cond [(eof-object? c) (values (reverse chars) #t)] (cond [(eof-object? c) (values (reverse chars) #t)]
[(char=? c delimiter) (values (reverse chars) #f)] [(delimiter? c) (values (reverse chars) #f)]
[else (loop (cons c chars))])))) [else (loop (cons c chars))]))))
;; delimiter->predicate :
;; symbol -> (char -> bool)
;; returns a predicates to pass to read-until-char
(define (delimiter->predicate delimiter)
(case delimiter
[(eq) (lambda (c) (char=? c #\=))]
[(amp) (lambda (c) (char=? c #\&))]
[(semi) (lambda (c) (char=? c #\;))]
[(amp-or-semi) (lambda (c) (or (char=? c #\&) (char=? c #\;)))]))
;; read-name+value : iport -> (symbol + bool) x (string + bool) x bool ;; 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, ;; -- 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 ;; indicating EOF was reached without any input seen. Otherwise, the first
;; and second values contain strings and the third is either true or false ;; 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 ;; 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 ;; 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, ;; 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 ;; 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 ;; look like this matters. It would also introduce needless modality and
;; reduce flexibility. ;; reduce flexibility.
(define (read-name+value ip) (define (read-name+value ip)
(let-values ([(name eof?) (read-until-char ip #\=)]) (let-values ([(name eof?) (read-until-char ip (delimiter->predicate 'eq))])
(cond [(and eof? (null? name)) (values #f #f #t)] (cond [(and eof? (null? name)) (values #f #f #t)]
[eof? [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 (let-values ([(value eof?) (read-until-char ip #\&)]) [else (let-values ([(value eof?)
(read-until-char
ip
(delimiter->predicate
(current-alist-separator-mode)))])
(values (string->symbol (query-chars->string name)) (values (string->symbol (query-chars->string name))
(query-chars->string value) (query-chars->string value)
eof?))]))) eof?))])))

View File

@ -1,6 +1,7 @@
#lang scribble/doc #lang scribble/doc
@(require "common.ss" @(require "common.ss"
(for-label net/cgi (for-label net/cgi
net/uri-codec
net/cgi-unit net/cgi-unit
net/cgi-sig)) net/cgi-sig))
@ -41,7 +42,10 @@ Returns the bindings that corresponding to the options specified by
the user. The @scheme[get-bindings/post] and the user. The @scheme[get-bindings/post] and
@scheme[get-bindings/get] variants work only when POST and GET forms @scheme[get-bindings/get] variants work only when POST and GET forms
are used, respectively, while @scheme[get-bindings] determines the are used, respectively, while @scheme[get-bindings] determines the
kind of form that was used and invokes the appropriate function.} kind of form that was used and invokes the appropriate function.
These functions respect @scheme[current-alist-separator-mode].
}
@defproc[(extract-bindings [key? (or/c symbol? string?)] @defproc[(extract-bindings [key? (or/c symbol? string?)]

50
collects/tests/net/cgi.ss Normal file
View File

@ -0,0 +1,50 @@
#lang scheme
(require net/cgi
net/uri-codec)
(define-syntax test-result
(syntax-rules ()
[(test-result expression expected)
(let ([result expression])
(if (equal? result expected)
(display (format "Ok: `~a' evaluated to `~a'.\n"
'expression expected))
(display (format
"Error: `~a' evaluated to `~a', expected `~a'.\n"
'expression result expected))))]))
(putenv "REQUEST_METHOD" "GET")
(test-result (begin
(current-alist-separator-mode 'amp-or-semi)
(putenv "QUERY_STRING" "key1=value1&key2=value2;key3=value3")
(get-bindings))
'((key1 . "value1")
(key2 . "value2")
(key3 . "value3")))
(test-result (begin
(current-alist-separator-mode 'amp)
(putenv "QUERY_STRING" "key1=value1&key2=value2")
(get-bindings))
'((key1 . "value1")
(key2 . "value2")))
(test-result (begin
(current-alist-separator-mode 'amp)
(putenv "QUERY_STRING" "key1=value1;key2=value2")
(get-bindings))
'((key1 . "value1;key2=value2")))
(test-result (begin
(current-alist-separator-mode 'semi)
(putenv "QUERY_STRING" "key1=value1;key2=value2")
(get-bindings))
'((key1 . "value1")
(key2 . "value2")))
(test-result (begin
(current-alist-separator-mode 'semi)
(putenv "QUERY_STRING" "key1=value1&key2=value2")
(get-bindings))
'((key1 . "value1&key2=value2")))