bug-guile
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Patch for guile-www-2.9 (www cgi), multiple fixes


From: Alan Grover
Subject: Patch for guile-www-2.9 (www cgi), multiple fixes
Date: Mon, 11 Apr 2005 21:09:12 -0400
User-agent: Mozilla Thunderbird 0.7 (X11/20040615)

Fixes the following:
* Change a use-module statement to (ice-9 optargs) instead of (ice-9 optargs-kw). Not deeply investigated. * Tolerates query-strings without a "=" for empty names. Thus: http://gnu.org?a=1&b will give two names (a and b), where b has the value "". * Tolerates query-strings where the name is empty. Thus: http:/gnu.org?=b will give a key of "" whose value is b. * Applies url-decode to each name. Thus: http://gnu.org?x%26y=1 will give a name of "x=y" whose value is 1. * Adds the variable cgi:names-values which holds the parsed name/value pairs in the same order as found in the query-string: ("a" . 1) ("b" . 2), etc. If a name repeats, it also repeats in the list. * Should be more friendly for mod-list/fastcgi style use. The "cgi:init" function should re-initialize the module completely (not thoroughly tested: works for query-string parsing).

This incorporates fixes to bugs reported by address@hidden on 11 April 2005:
* guile-www-2.9 (www cgi) names in query-string not url-decoded
* guile-www-2.9 (www cgi) form-data loses original order
* guile-www-2.9 (www cgi) bad cgi:values when a name has no "="
* guile-www-2.9 (www cgi) does not support mod-lisp/fastcgi style uses
* guile-www uses obsolete optargs-kw

Notes:
* Does not use shared-substrings (these are deprecated).
* I did not concern myself with time/space optimization since query-string parsing happens only once per request, and the query-string is typically of reasonable size. Instead of append!, one could cons onto the head and reverse later. No doubt other optimizations can be done.

Patch:

cgi.scm

<   #:use-module (ice-9 optargs-kw))
<
---
>   #:use-module (srfi srfi-1)
>   #:use-module (ice-9 optargs))
42c42,44
< (define *env-alist*
---
> (define *env-alist* #f)
> (define (make-env-alist)
>  (set! *env-alist*
97c99
<                                 #\, types)))))))))
---
>                                 #\, types))))))))))
116a119,120
>   (make-env-alist)
>   (set! form-variables '())
178a183,187
> ;; Return the key-value pairs (as cons), in the
> ;; order they appeared. Thus, you can exactly reconstruct the query-string.
> ;;
> (define-public cgi:names-values #f) ; Stable order of name-value pairs
>
179a189
> ;; At least '(). It is possible for a name to be "".
273,290c283,336
< (define (parse-form raw-data)
< ;; get-name and get-value are used to parse individual `name=value' pairs.
<   ;; Values are URL-encoded, so each must be decoded.
<   (define (get-name pair)
<     (let ((p (string-index pair #\=)))
<       (and p (subs pair 0 p))))
<   (define (get-value pair)
<     (let ((p (string-index pair #\=)))
<       (and p (url-coding:decode (subs pair (+ p 1))))))
<   (for-each (lambda (pair)
<               (let* ((name (get-name pair))
<                      (value (get-value pair))
<                      (old-value (cgi:values name)))
<                 (set! form-variables
<                       (assoc-set! form-variables
<                                   name
<                                   (cons value (or old-value '()))))))
<             (separate-fields-discarding-char #\& raw-data)))
---
> ; The results are nearly stable. cgi:names will give
> ; the names back as they are left-to-right in the query-string,
> ; and the cgi:values will be in the original left-to-right order.
> ; Except, if a name appears more than once in the query-string,
> ; it will only appear once in cgi:names, in the first position.
> ;
>
> (define (parse-form qstring)
> "url-decoded (key . values), values is "" if no value. updates form-variables"
>   (set! cgi:names-values '())
>   (let* (
>     (dictionary '()) ; alist for key . (values)
>     (key-value-strings
> (filter (lambda (x) (not (eq? x '()))) ; remove empties (e.g. "&&")
>         (string-split qstring #\& )))  ; split on &
>     (split-to-key-value (lambda (kv-string)
>       (let* (
>         (index-of-equals (string-index kv-string #\=)) ; find '='
>         (key ; key part
>           (begin
>             (if index-of-equals
>               (if (> index-of-equals 0)
>                 (substring kv-string 0 index-of-equals )
>                 "")  ; '=' at beginning
>               (if (> (string-length kv-string) 0)
>                 kv-string
>                 #f))))  ; 0 length, which shouldn't happen here
>         (value ; value part (as list) or #f
> (if (and key index-of-equals (< index-of-equals (- (string-length kv-string) 1)))
>             (substring kv-string (+ index-of-equals 1))
>             #f))
>         )
>         (if key
> (cons (url-coding:decode key) (if value (url-coding:decode value) #f))
>           #f))))
>     (update-dictionary (lambda (kv)
> "The assoc list is kept in order of query-string, append entry or value"
>       (let* (
>         (key (car kv))  ; don't call with #f for key
>         (value (cdr kv))
>         (current-entry (assoc key dictionary))
>         )
>         (if current-entry
>           (append! (cdr current-entry) (list value))
>
> (set! dictionary (append! dictionary (list (cons key (list (or value "")))))))
>         )))
>     )
>     (begin
> (for-each update-dictionary ; insert into dictionary (or append values)
>         (filter identity ; remove empty key-value, e.g. "="
>           (map split-to-key-value
>             key-value-strings )))  ; get "k=v"
>       (set! form-variables dictionary))))
--
Alan Grover
address@hidden
+1.734.476.0969




reply via email to

[Prev in Thread] Current Thread [Next in Thread]