by shigemk2

当面は技術的なことしか書かない

request.elでマルチバイト文字の入ったJSONをPOSTできない

結論

パッチを投げました。

github.com

概要

EmacsのHTTPクライアント request.el というものがあります。これはcurlのラッパーみたいなもので、GETしたりPOSTしたりするのに大変便利なのですが、以下のようにマルチバイト文字の入ったJSONデータをPOSTしたりPUTしようとしたりすると死にます。POSTできませんが、elisp側でエラーは検出されません。

(request
 "http://httpbin.org/put"
 :type "PUT"
 :data (json-encode '(("key" . "値1") ("key2" . "値2")))
 :headers '(("Content-Type" . "application/json"))
 :parser 'json-read
 :success (cl-function
           (lambda (&key data &allow-other-keys)
             (message "I sent: %S" (assoc-default 'json data)))))

直接の原因はここです。curlでデータを送信するときにテンポラリのバッファにデータを入れているのですが、このときバッファのエンコーディングが 'binary になっているので、マルチバイト文字はユニコードに変換されたうえでHTTPリクエストされます。そのためにリクエストがエラーになってしまいます。

   (when data
     (let ((tempfile (request--make-temp-file)))
       (push tempfile (request-response--tempfiles response))
       (let ((file-coding-system-alist nil)
             (coding-system-for-write 'binary))
         (with-temp-file tempfile
           (setq buffer-file-coding-system 'binary)
           (set-buffer-multibyte nil)
           (insert data)))
       (list "--data-binary" (concat  "@" (request-untrampify-filename tempfile)))))

https://github.com/tkf/emacs-request/blob/master/request.el#L917-L926

んじゃあここの buffer-file-coding-system'utf-8 にして、 set-buffer-multibyte の設定をやめたらいいのでは?と思うのですが、これWindowsなど別の文字コードをベースにしてrequestするとまた別の問題が発生するかもしれないので、ココの部分を変数でもってユーザー側で変更できるようにしました。デフォルトは 'binary なので、既存のものはそのまま使えます。

ほんとはココと結構被るのですが、テストコードやドキュメントを追加した感じになります。

github.com

と言った感じの備忘録です。

問題点

最後のメンテが2017/1で1年近くメンテされておらず、誰がメンテナーなのかわかりません。ので、取り込まれるどころかレビューされるかどうかも怪しいです。気長にまとうと思います。