Gauche:cgi-get-parameterのなぞ
Gaucheでformを書く際にPOSTとGETの扱いで戸惑った。
何ができないか
POST送信のに、URLで渡した値が取得できない。
次のformでindex.scmにリクエストを送信する
<form action="index.scm?controller=edit" method="post">
<input id="from" name="from" type="text" />
<input type="submit" />
</form>
index.scmでは以下のようにparamsからcontrollerの値を取得したかったがこれができない。
(define (main args)
(cgi-main
(lambda (params)
(let* ((controller (cgi-get-parameter "controller" params)))))))
以下のようにhiddenにすれば、controllerの値を取得できる。
<form action="index.scm" method="post">
<input id="from" name="from" type="text" />
<input type="submit" />
<input type="hidden" name="controller" value="edit" />
</form>
そりゃそうか。って、method="POST"のときはPOSTの値だけ?え~そんなああ。
www.cgiモジュールの中を覗いてみる。
/usr/local/share/gauche/0.8.14/lib/www/cgi.scm
(define (cgi-get-query content-length)
(let* ((type (mime-parse-content-type (get-meta "CONTENT_TYPE")))
(typesig (and type (list (car type) (cadr type))))
(method (get-meta "REQUEST_METHOD")))
(unless (or (not type)
(member typesig
'(("application" "x-www-form-urlencoded")
("multipart" "form-data"))))
(errorf
:content-type type
"Unsupported CONTENT_TYPE: ~a" type))
(cond ((not method) ;; interactive use.
~中略~
((or (string-ci=? method "GET")
(string-ci=? method "HEAD"))
(or (get-meta "QUERY_STRING") ""))
((string-ci=? method "POST")
(if (equal? typesig '("multipart" "form-data"))
'mime
(or (and-let* ((lenp (or content-length
(get-meta "CONTENT_LENGTH")))
(len (x->integer lenp))
((<= 0 len)))
(string-incomplete->complete (read-block len)))
(port->string (current-input-port)))))
(else
(errorf
:request-method method
"Unknown REQUEST_METHOD: ~a" method))
)))
(define (read-complete-block len)
(if (zero? len)
'#u8()
(let ([buf (make-u8vector len)]
[inp (current-input-port)])
(let loop ([i 0])
(let1 nread (read-block! buf inp i)
(cond [(eof-object? nread)
(errorf <cgi-error> "POST request ends prematurely. Expected content-length: ~a, but read only ~a octets." len i)]
[(< (+ nread i) len) (loop (+ nread i))]
[else buf]))))))
methodが「GETかHEAD」のときと、「POST」のときで取得方法が分けられていて、どっちかしか取れない。
method が POST のときに、cgi-parse-parameters を、キーワード :query-string なしで呼び出すと、 cgi.scm の read-complete-block がエラーを吐いてしまう。
POSTで送信する際、URLに渡した値を同時に取得したいけどな。
hiddenをがしがし書くしかないってことか。
cgi-get-metavariable
と思ったら一応手続きがあった。
cgi-get-metavariable | Gauche ユーザリファレンス: CGIユーティリティ
こう。
(cgi-get-parameter "controller" (cgi-parse-parameters :query-string (cgi-get-metavariable "QUERY_STRING")))
(use www.cgi)
(use text.html-lite)
(define controller
(cgi-get-parameter
"controller"
(cgi-parse-parameters :query-string (cgi-get-metavariable "QUERY_STRING"))))
(define (main args)
(cgi-main
(lambda (params)
`(,(cgi-header)
,(html-doctype)
,(html:html
(html:head (html:title "test"))
(html:body
(html:form :action #"t3.scm?controller=~controller" :method "post"
(html:input :id "from" :name "from" :type "text")
(html:input :type "submit"))
(html:div #"controller=[~|controller|]")
(html:table
:border 1
(html:tr (html:th "Name") (html:th "Value"))
(map (lambda (p)
(html:tr
(html:td (html-escape-string (car p)))
(html:td (html-escape-string (x->string (cadr p))))))
params))))))))
できた。
Gauche Scheme Lisp