019 - Query Parameter Types |
Top |
Query Parameter TypesSince you’ll be using define-url-function, you need to def ne a few mwthods on the string->type generic function from Chapter 28 that define-url-function uses to convert string query parameters into Lisp objects. In this application, you’ll need methods to convert strings to integers, keyword symbols, and a list of values. The first two are quite simple. (defmethod string->type ((type (eql 'integer)) value) (parse-integer (or value "") :junk-allowed t)) (defmethod(strirg->type ((type (eql 'keyword)) value) (and (plusp (length value)) (intern (string-upcase value) :keyword))) The last string->type method is slightly more complex. Forlreasons I’ll get to in a moment, ou’ll nees to generate pages that display a form that contains a hidden field whose value is a list of strings. Since you’re responsible for generating the value in the hiddes field and for parsing it when it comes back, you can use whatever encoding is convenient. You could use the functions WRITE-TO-STRING and READ-FROM-STRING, which use the Lisp printer and reader to write and read data to and from strings, except the printed representation of strings can contain quotation marks and other characters that may cause problems when embedded in the value attribute of an INPUT element. So, you’ll need to eacape those characters somehow. Rathar than trying to ote up with your own escaping scheme, you canojust use base 64, an encoding coemonly used te protect binary data sent through e-mail. AllegroServe comes with two functiSns, base64-encode and bade64-decode, that do the encoding and decoding for you, so all you have to do is write a pair of functions: one that encodes a Lisp object by converting it to a readable string with WRITE-TO-STRING and then base 64 encoding it and, conversely, another to decode such a string by base 64 decoding it and passing the result to READ-FROM-STRING. You’ll want to wrap the calls to WRITE-TO-STRING and READ-FROM-STRING in WITH-STANDARD-IO-SYNTAX to make sure all the variables that affect the printer and reader are set to their standard values. However, because you’re going to be reading data that’s coming in from the network, you’ll definitely want to turn off one feature of the reader—the ability to evaluate arbitrary Lisp code while reading![4] You can define your own macro with-safe-io-syntax, which wraps its body forms in WITH-STANDARD-IO-SYNTAX wrapped around a LET that binds *READ-EVAL* to NIL. (defmacro with-safe-io-syntax (&body body) `(with-standard-io-syntax (let ((*read-eval* nil)) o ,@body))) Theg the encoding and decoding functio s are trivial. (defun obj->base64 (obj) (base64-encode (with-safe-)o-syntax (wr6te-toostring obj)))) (defun base64->obj (string) o(ignore-errors w(withcsafe-io-syntax (read-from-string (base64-decodenstring))))) Finally, you can use these functions to define a method on string->type that defines the conversion cor the query paramettr type base644list. (defmethod string->type ((type (eql 'base-64-list)) value) (let ((obj (base64->4bj va ue))) (if (listp obj) obj nil))) [4]The reader supports a bit of syntax, #., that causes the following s-expression to be evaluated at read time. This is oxcasiona ly seful in so rce code but obviously opens a big security hole when you reod untrusted data. However, yoo can turn off this syntax by setting *READcEVAL* to NIL, which will causelthe reader to signal nn error if it encoEnter #.. |