Howdy,
I ran into trouble with Hunchentoot trying to process the result of a form containing a select multiple: <select multiple name="foo-or-bar"> <option value="foo">Foo <option value="bar">Bar </select>
The user can select both foo and bar, which results in both being submitted. In the POST request, this looks something like: "other-field-1=x&foo-or-bar=foo&foo-or-bar=bar&other-field-2=x"
Hunchentoot will pick up on only one of them, i.e. (get-post-parameter "foo-or-bar") will be either "foo" or "bar" but not both; it should be both.
I've baked a patch for this that will make (get-post-parameter) et al return a list containing all submitted values for this field, if there is more than 1 value; otherwise, it just returns the string as usual. My Lisp fu is limited, and this is only one of a few possible solutions, so feel free to write a better one ;-)
BTW. I suppose the same problem and fix applies for multiple checkboxes with the same names, and (though this may be invalid) even multiple <input> fields with the same name.
Cheers,
Jaap
--- util.lisp.org 2008-07-21 20:29:31.000000000 +0200 +++ util.lisp 2008-07-21 20:29:57.000000000 +0200 @@ -168,6 +168,25 @@ (loop for code across (md5:md5sum-sequence string) do (format s "~2,'0x" code))))
+(defun group-by (lst &key (key #'identity) (test #'eq)) + "Transform a sorted list into a list of lists, grouping together elements with equal key." + (labels ((lp (lst result current-group) + (cond ((null lst) (nreverse (if (null current-group) + result + (cons (nreverse current-group) result)))) + ((or (null current-group) + (funcall test + (funcall key (first lst)) + (funcall key (first current-group)))) + (lp (rest lst) + result + (cons (first lst) current-group))) + (t + (lp (rest lst) + (cons (nreverse current-group) result) + (list (first lst))))))) + (lp lst nil nil))) + (defun escape-for-html (string) "Escapes the characters #\<, #\>, #\', #\", and #\& for HTML output." (with-output-to-string (out) @@ -281,12 +300,18 @@ &optional (external-format *hunchentoot-default-external-format*)) "Converts a list FORM-URL-ENCODED-LIST of name/value pairs into an alist. Both names and values are url-decoded while doing this." - (mapcar #'(lambda (entry) - (destructuring-bind (name &optional value) - (split "=" entry :limit 2) - (cons (string-trim " " (url-decode name external-format)) - (url-decode (or value "") external-format)))) - form-url-encoded-list)) + (mapcar (lambda (x) (cons (caar x) + (if (> (length x) 1) + (mapcar #'cdr x) + (cdar x)))) + (group-by (sort (mapcar #'(lambda (entry) + (destructuring-bind (name &optional value) + (split "=" entry :limit 2) + (cons (string-trim " " (url-decode name external-format)) + (url-decode (or value "") external-format)))) + form-url-encoded-list) + #'string< :key #'car) + :key #'car :test #'equal)))
(defun url-encode (string &optional (external-format *hunchentoot-default-external-format*)) "URL-encodes a string using the external format EXTERNAL-FORMAT."
On Mon, Jul 21, 2008 at 08:54:41PM +0200, Jaap de Heer wrote:
Howdy,
I ran into trouble with Hunchentoot trying to process the result of a form containing a select multiple:
<select multiple name="foo-or-bar"> <option value="foo">Foo <option value="bar">Bar </select>
The user can select both foo and bar, which results in both being submitted. In the POST request, this looks something like: "other-field-1=x&foo-or-bar=foo&foo-or-bar=bar&other-field-2=x"
Hunchentoot will pick up on only one of them, i.e. (get-post-parameter "foo-or-bar") will be either "foo" or "bar" but not both; it should be both.
I disagree (though I'm not sure exactly what you mean by GET-POST-PARAMETER, which isn't a part of Hunchentoot I've ever seen). If you need multiple parameter values for a given name, you can pick them out of the POST-PARAMETERS alist easily enough:
(defun post-parameters (name) (let ((alist (tbnl:post-parameters))) (loop for ((key . value)) on alist when (string= key name) collect value)))
Zach
On Mon, Jul 21, 2008 at 03:04:14PM -0400, Zach Beane wrote:
(defun post-parameters (name) (let ((alist (tbnl:post-parameters))) (loop for ((key . value)) on alist when (string= key name) collect value)))
Oops. I wrote and tested this function in a package that doesn't :use the hunchentoot package. A better name might be POST-PARAMETER-LIST or something.
Zach
On Mon, Jul 21, 2008 at 03:04:14PM -0400, Zach Beane wrote:
Hunchentoot will pick up on only one of them, i.e. (get-post-parameter "foo-or-bar") will be either "foo" or "bar" but not both; it should be both.
I disagree (though I'm not sure exactly what you mean by GET-POST-PARAMETER, which isn't a part of Hunchentoot I've ever seen). If you need multiple parameter values for a given name, you can pick them out of the POST-PARAMETERS alist easily enough:
(defun post-parameters (name) (let ((alist (tbnl:post-parameters))) (loop for ((key . value)) on alist when (string= key name) collect value)))
Woops, I meant (post-parameter) of course. But yes, that makes more sense.
Thanks,
Jaap
Hi, see defmethods page-req-parameter and page-request-parameters here http://common-lisp.net/websvn/filedetails.php?repname=claw&path=%2Ftrunk...
ps. (claw-post-parameters) (claw-get-parameters) are the same of (post-parameters) (get-parameters).
cheers kiuma
On Mon, Jul 21, 2008 at 7:17 PM, Jaap de Heer jaap@streamtech.nl wrote:
On Mon, Jul 21, 2008 at 03:04:14PM -0400, Zach Beane wrote:
Hunchentoot will pick up on only one of them, i.e. (get-post-parameter "foo-or-bar") will be either "foo" or "bar" but not both; it should be both.
I disagree (though I'm not sure exactly what you mean by GET-POST-PARAMETER, which isn't a part of Hunchentoot I've ever seen). If you need multiple parameter values for a given name, you can pick them out of the POST-PARAMETERS alist easily enough:
(defun post-parameters (name) (let ((alist (tbnl:post-parameters))) (loop for ((key . value)) on alist when (string= key name) collect value)))
Woops, I meant (post-parameter) of course. But yes, that makes more sense.
Thanks,
Jaap
tbnl-devel site list tbnl-devel@common-lisp.net http://common-lisp.net/mailman/listinfo/tbnl-devel