ども。GitHubで発生したIssueをとりあえずまとめることにしました。
概要
P2Pの実験で2ちゃんねるの専用ブラウザ(以下専ブラ)とPlay! Frameworkを通信させているのですが、問題が発生しました。ある種の専ブラからの書き込みが文字化けするらしい(リンクはGitHubのIssue)のです。
結論から申しますと、2ch専ブラは正しくPOSTメソッドのパラメータをエンコードしていません。
パーセントエンコーディング
まず、「2ちゃんねる」への投稿はHTTP POSTメソッドを利用して行います。POSTメソッドのパラメータはパーセントエンコーディング(URLエンコードだとかURLエスケープとも呼ばれる)されていることが必要です。このあたりの基礎的な解説は、有名な「と〜く2ちゃんねる」を参照していただけるといいと思います。要するに、こういう -- 言語道断横断歩道 -> %8c%be%8c%ea%93%b9%92f%89%a1%92f%95%e0%93%b9
-- 文字列のことです。
さてここで厄介なのが、(Wikipediaを見る限り)パーセントエンコーディングには二種類ある、という事です。RFC3986のSection 2.1による「狭義のパーセントエンコーディング」と、RFC1866のSection-8.2.1による「application/x-www-form-urlencoded」というMIMEで指定される符号化の方式です。そして、POSTに利用されるのは後者の方式です。これはHTML4.01の規約に記載されています。
If the method is "post" and the action is an HTTP URI, the user agent conducts an HTTP "post" transaction using the value of the action attribute and a message created according to the content type specified by the enctype attribute.
application/x-www-form-urlencoded
This is the default content type. Forms submitted with this content type must be encoded as follows:
Control names and values are escaped. Space characters are replaced by `+', and then reserved characters are escaped as described in [RFC1738], section 2.2: Non-alphanumeric characters are replaced by `%HH', a percent sign and two hexadecimal digits representing the ASCII code of the character. Line breaks are represented as "CR LF" pairs (i.e., `%0D%0A'). The control names/values are listed in the order they appear in the document. The name is separated from the value by `=' and name/value pairs are separated from each other by `&'.(強調は筆者による)
二つの符号化の方式の違いは、半角スペースの扱いです。「狭義のパーセントエンコーディング」では、半角スペース、つまりASCIIコード0x20は"%20"としてエンコードされますが、「x-www-form-urlencoded」では半角スペースは"+"でエンコードされます。
- 狭義のパーセントエンコーディング: 半角スペースは"%20"。
application/x-www-form-urlencoded
: 半角スペースは"+"。HTTP/POSTに使用される。
Playの場合 - java.net.URLEncoder
さて、Play! FrameworkでHTTP/POSTパラメータのデコードに利用されているのはjava.net.URLEncoder
です。このクラスは規約に忠実にapplication/x-www-form-urlencoded
を適用し、半角スペースを"+"としてエンコードします。
専ブラの場合
問題なのは専ブラです。パケットキャプチャなどにより確認・報告した限りでは
- Thousand (Mac OSX)
- navi2ch (Emacs)
- JaneDoe Viewer (Windows)
少なくともこれらの専ブラが「狭義のパーセントエンコーディング」を使用し、半角スペースを"%20"としてエンコードしているようです。さらに、これらのクライアントはContent-Type
にx-www-form-urlencoded
を指定しながら、「狭義のパーセントエンコーディング」を利用しているようです。
しかし一定数の専ブラが、この奇妙な実装をしているということは、もしかしたら2ちゃんねるがこの方式を強制しているのかもしれません。正確なapplication/x-www-form-urlencoded
を利用して2chに書き込みできるかどうかは確かめていませんが、余裕があれば検証してみたいと思っています。
実証
Firefox
さて、手持ちのブラウザ(User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:25.0) Gecko/20100101 Firefox/25.0\r\n
)でシベリア超速報に書き込みしてみたところ、半角スペースはきちんと"+"としてエンコードされ、Content-Typeはapplication/x-www-form-urlencoded
であり、正常に書き込まれていました。
専ブラ
そして、手持ちの専ブラ「Thousand」で同じように書き込みしてみたところ、Content-Typeがapplicatioin/x-www-form-urlencoded
であったにもかかわらず、半角スペースは"%20"としてエンコードされていましたが、正常に書き込みされていました。
おそらく2ちゃんねるではどちらのエンコーディングもサポートできているようです。
しかしながら、規約に従わない専ブラがあるのは問題だと思っています。どのように実装しているのかは私の知る所ではありませんが、規約は規約ですので従うべきではないでしょうか。正しい
application/x-www-form-urlencoded
を使用しても問題は無いのですから。
どうか識者の方、ご意見ください。