Search code examples
postcommon-lispsbclhunchentoot

How to get the POST as parameter of a function in Hunchentoot?


I want to use a web formular to filter records stored in mongo-db.

My query function uses a filter as followed:

(defun models (filter)
  (docs (db.find *model-collection*
      filter
      :limit 1)))

And when I use it in SBCL, it can retrieve the record {"NAME" :"a1"}, with one of the following command:

(models ($ "NOM" "a1"))
(models (eval (read-from-string "(kv \"NOM\" \"a1\")")))

(<DOCUMENT> : { 
_id : CL-MONGO::BSON-OID ...elements : 14})

Now I add the web interface developed in Hunchentoot, one for the query formular and one to display the response:

(define-easy-handler (test :uri "/test") () 
  (with-html-output-to-string (*standard-output* nil :prologue t :indent t)
    (:html 
     (:body
      (:h1 "Test")
      (:form :action "/test1" :method "post" :id "addform"
       (:input :type "text" :name "name" :class "txt")
       (:input :type "submit" :class "btn" :value "Submit"))))))

(define-easy-handler (test1 :uri "/test1") (name)
 (with-html-output-to-string (*standard-output* nil :prologue t :indent t)  
  (:html 
   (:body  
    (:h1 "My List")
       (:p (str (models name)))))))

When I enter in the submit form the following filter : ($ "NAME" "a1"), i get an error at the display page, and the following log in SBCL:

compiling (DEFINE-EASY-HANDLER (TEST1 :URI ...) ...)
[2015-02-12 15:41:47 [ERROR]] The value #\( is not of type (UNSIGNED-BYTE 8).

17: ((SB-PCL::FAST-METHOD CL-MONGO:DB.FIND (STRING T))
    #<unused argument>
    #<unused argument>
    "mycollection"
    "($ \"NOM\" \"a1\")"
   :MONGO
   NIL
   :OPTIONS
   0
   :SKIP
   0
   :LIMIT
   1
   :SELECTOR
   NIL)
18: (WEB-TEST::MODELS2 "($ \"NOM\" \"a1\")")
19: (WEB-TEST::TEST1 :NAME NIL)

It try several pre transformation in test1 such as:

(:p (str (models (eval (read-from-string name)))))
or (:p (str (models (eval (esc name)))))

But none of them work properly. Does anyone could advice?


Solution

  • You are passing a string to models, not a filter produced by $. Using eval on external input is a very bad idea, too.

    You could just pass the name to your handler and build the filter from that:

    (:p (str (models ($ "NOM" name))))
    

    Call your handler with a1 as name.

    I would generally not advise to let users pass in arbitrary expressions that hit the database unchecked.