kobapan@wiLiki
Login
Gauche

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

Debian
Emacs
Firefox
Gauche
JavaScript
Linux
Scheme
org-mode/latex

More ...