application/x-www-form-urlencoded parser

application/x-www-form-urlencoded (MIME型)

[9] application/x-www-form-urlencoded は、フォームの提出のための形式の1つです。 HTMLフォームの提出のために開発され、 HTTP POSTpayload bodyHTTP GETURL query で使われています。 HTML に限らず、 OAuth や各種サービスの Web API などでも標準的な入力形式として採用されています。

仕様書

[67] 歴史的には明確な仕様が存在せず、様々な仕様書がそれぞれの立場の規定を含めていました。 (歴史の項を参照。)

データモデル

[39] application/x-www-form-urlencoded のデータは、 0個以上の名前 (name) (value) の組の列を表しています。

[42] 名前や値は、それぞれ0個以上の文字の列です。

[82] 仕様上は文字列になっていますが、バイト列が用いられることも稀にあるようです。

[43] 名前の重複は禁止されていません。名前と値の組の順序は意味を持ちます。

[51] 応用によっては重複を禁じていたり、順序の意味を持たせなかったりすることもあります。

[74] 名前や値の値域や長さの制限はありません。大文字と小文字は区別されます。

[75] 応用によっては制限を設けたり、区別しなかったりすることもあります。

構文

[11] application/x-www-form-urlencoded では、 名前と値の組を & で区切って連結します。

  1. ?
    1. *
      1. &

[52] 名前と値は、 = で連結します。

  1. 名前
  2. =

[72] 名前と値は、パーセント符号化することができます。 0x00-0x7F の範囲外や区切りの &= とみなされるもの、 + は、パーセント符号化しなければなりません。

[73] 名前と値の + は、 0x20 を表します。

文字コード

[77] application/x-www-form-urlencoded 自体は ASCII によって表現されますが、そのパーセント符号化復号した結果は、 何らかの文字コード文字列となっています。

[83] 仕様上は認められていませんが、文字列ではなくバイト列になっていたり、 複数の文字コードが混在したりすることも現実にはあるようです。

[107] application/x-www-form-urlencoded直列化器は、 特に指定がない限り UTF-8 を使います >>68

[123] 歴史的な理由により、 HTMLフォームの提出では、 accept-charset の指定や文書文字符号化が使われます >>121。 現在ではこうしたものは好ましくないと考えられており、 accept-charset は指定するべきではなく、文書自体も常に UTF-8 とするべきです。
[125] HTML では必ずASCII互換文字符号化が選ばれます >>121

[170] application/x-www-form-urlencoded構文解析器は、 常に UTF-8 を使って復号します >>68

[78] 改訂以前のapplication/x-www-form-urlencoded構文解析器は、 次のように文字コードを決定していました >>68

  1. [79] _charset_ 有効で構文解析する場合には、 _charset_ という名前の組があり、 その値で符号化を取得して失敗しなければ、 得られた文字符号化
  2. [80] 文字符号化の指定ありで構文解析する場合には、 その文字符号化
  3. [81] UTF-8

[129] かつての HTML Standard が示していた復号アルゴリズムは、 _charset_ が含まれない場合文字コードはケースバイケースで決めるしかないとしつつも、 一般にはフォームが含まれる文書文字コードを既定値とするのがよく、 適当な既定値がなければ UTF-8 とするのがよさそうだ >>121 だとしています。

[133] HTMLフォームでは、 <input type=hidden name=_charset_> という要素を含めることで、使用した文字コードフォームデータ集合の一部として提出させることができます。

_charset_ hack を参照。

[84] 歴史的には _charset_ hack の他、 ie のような名前の組で文字コードを指定したり、 固定の文字を指定した組を含めてその符号化された値により文字コードを推定したり、 自動判別を用いたり、フォームが含まれる文書文字コードと推定したりと色々な方法が用いられてきました。 しかし現在では専ら UTF-8 が使われているとみなすことが多くなってきています。

[124] なお、選択した文字コードで表現できない文字を URL StandardHTML Standardアルゴリズム十進数文字参照によって表現します >>68, >>121十進数文字参照& から始まりますが、 後からパーセント符号化されるので区切り文字と誤認されることはありません。 しかしただの & はそのまま送信されるので、元のデータが & だったのか符号化によって十進数文字参照となったのかは区別できません。

この点からも、すべての文字をそのまま表現できる UTF-8 を使うべきです。

パーセント符号化

[85] 名前と値はパーセント符号化することになっています。

[86] application/x-www-form-urlencoded直列化器は、 application/x-www-form-urlencodedバイト直列化器 (application/x-www-form-urlencoded byte serializer) によってパーセント符号化します。具体的には、次のバイトはそのままとし、 0x20 は + とし、 それ以外はパーセント符号化します。 HTMLフォームでも同様です。 >>68, >>121

  • 0x2A (*)
  • 0x2D (-)
  • 0x2E (.)
  • 0x30-0x39 (0-9)
  • 0x41-0x5A (A-Z)
  • 0x5F (_)
  • 0x61-0x7A (a-z)

[87] これらはバイトであり、文字ではありません。ですから、例えば + は 0x20 を表しており、 U+0020 を表すとは限りません。
[88] URL非予約文字であるASCII文字のうち、 ~パーセント符号化されます。

[90] URL Standardapplication/x-www-form-urlencoded直列化器によって生成される application/x-www-form-urlencoded においてこのようにパーセント符号化することを求めていますが、 その他の方法で application/x-www-form-urlencoded が生成されることは排除していないようです。例えば Web 以外の利用者エージェントapplication/x-www-form-urlencoded を使うときに他の文字パーセント符号化したり、しなかったりしてもただちに問題とはなりません。

[92] ただし application/x-www-form-urlencoded構文解析器UTF-8 以外の文字コードの時に 0x80-0xFF が入力に含まれていると、 構文解析せずに停止することになっています >>68相互運用性のために最低でも 0x80-0xFF はパーセント符号化するべきでしょう。

[108] HTML4 のあまり意味がなかった規定 (>>13) の影響で区切り文字として ; をも認識する側の実装が少なくありませんから、 0x3B (;) もパーセント符号化するべきでしょう。

[164] encodeURIComponent など汎用的なパーセント符号化の実装を使っていると、 より多くの文字パーセント符号化されます。

[165] 特にこだわりがなければ、 Webブラウザーに合わせる (>>86) か、 より保守的な方式を採用する (>>164) のが良さそうです。

[145] 歴史的に Webブラウザーやその他のクライアントがどの文字バイトパーセント符号化し、 どれをそのまま残すかには微妙な違いがあります。しかし仕様通りの方法で復号していれば、 その違いも自然に吸収されます。

[91] application/x-www-form-urlencoded直列化器HTML フォームによるパーセント符号化では、大文字十六進数字を使います >>68, >>121

[166] Webブラウザー以外の多くの実装も、大文字を使うのが普通のようです。

[97] application/x-www-form-urlencoded構文解析器は、 パーセント符号化大文字でも小文字でも復号します >>68

+

[89] 0x20 を + で表すのは application/x-www-form-urlencoded 独特の方式 (プラスパーセント符号化 (plus-percent-encoding) ) で、 通常のパーセント符号化では行われていません。

[58] 通常のパーセント符号化を流用した実装では、 0x20 が + ではなく %20 と表現されているかもしれません。

[143] Webブラウザーフォームの提出を行う時は + を使いますが、スクリプトURL を組み立てる時は encodeURIComponent を使って U+0020%20符号化しているかもしれません。

[144] Webブラウザーが従うべき application/x-www-form-urlencoded符号化のアルゴリズム上は + を使うことになっていますが、 application/x-www-form-urlencoded という構文としては %20 の利用が禁止されているわけではありません。
[160] パーセント符号化+ の章も参照。

[161] 通常のパーセント符号化と違って + を使うのは、 かつての isindex の送信方法 (>>127) に由来すると思われます。 isindex では空白区切りで複数のキーワードを指定して検索するという意味で、 パーセント符号化されたキーワード+ で連結して query に指定する方法を採っていました。

[162] CGIサーバーは、 query= が含まれないなら、 + 区切りのパーセント符号化されたキーワード列として解釈し、 各キーワードCGIスクリプトコマンドライン引数として使います。

[163] フォームの提出でこの方法を踏襲しなければならない理由も無いのですが、 フォームを最初に実装した Mosaic の時点で isindex は内部的にフォームに置き換えられていたようですから、 同じ符号化方法を採用した方が都合が良かったのでしょう。

= のない組

[98] application/x-www-form-urlencoded直列化器= が含まれない名前と値の組を生成することはありませんが、 実際には含まれないこともあるので、 application/x-www-form-urlencoded構文解析器は処理方法を規定しています。

[99] それによると、原則としてその部分全体を名前として扱い、値は空文字列とします >>68, >>121

[127] かつては isindex 要素との互換性のための規定がありましたが、 2016年4月の isindex 要素の完全廃止により、削除されました。

[100] ただし isindex 対応で構文解析する場合であって、 最初の名前と値の組の部分に = が含まれない場合に限り、 名前は空文字列とし、その部分全体を値として扱います >>68, >>121

[101] しかし application/x-www-form-urlencoded構文解析器を使って解釈される保証はありませんし、 isindex 対応で構文解析されるかどうかもわかりませんから、 = は必ず含めるべきでしょう。

[126] HTMLフォームから生成する際、フォームデータ集合の最初の項目の名前が isindex で種別が text なら、 値をパーセント符号化したもののみを結果に含め、名前や = は省略します >>121

MIME 型の引数

[93] Content-Type:application/x-www-form-urlencoded が指定される際に、引数も指定されることがあります。

[94] かつては引数に対応していない実装も少なくありませんでしたが、 その後 charset 引数を指定する実装が出てきたことから、 現在では引数に対応 (無視) しないとWeb互換とは言えない状況にあります。

[95] URL StandardHTML Standardcharset 引数を規定しておらず、解釈の際にも用いないことになっています。 HTML Standard には無視すると明記されています >>121。 しかしかつて標準不在だった時代に文字コードを明記するために charset 引数を使った実装や、 意味もなく見よう見まねで charset 引数を使った実装や使用例もありました。 現在でもその名残りでしばしば charset 引数を見かけます。

[96] charset 引数は指定するべきではありません。 指定されていても、無視するべきです。中には指定されていたらそれに従う実装もあるかもしれませんが、 無視する実装が普通なので、相互運用性の問題に陥るおそれもあります。

文脈

[49] application/x-www-form-urlencoded は、 HTML その他のフォーム提出や、 Web API その他の引数の指定などのため、 HTTP payload bodyHTTP要求要求URLURL query として非常によく使われています。

[50] application/x-www-form-urlencoded は、 OAuth 1.0からクライアントへのHTTP応答payload body で使われています。実装によっては OAuth 2.0 でも使われています。

[137] application/x-www-form-urlencoded は、 OAuth 2.0素片識別子で使われています。

[140] OAuth 2.0 クライアント認証における基本認証では application/x-www-form-urlencodedパーセント符号化が採用されています。

演算

[105] URL Standard は、 application/x-www-form-urlencoded直列化器 (application/x-www-form-urlencoded serializer) を規定しています >>68。このアルゴリズムは、名前 (文字列) と値 (文字列) の組の列を入力とし、バイト列を出力とします。また文字符号化をオプション入力として持ちます。

[106] 本項の他の部分で説明している通り、 application/x-www-form-urlencoded の一般的な構文を示すものとなっています。 しかし application/x-www-form-urlencoded をこの方法で生成しなければならないとは規定されておらず、 実際これに従わない application/x-www-form-urlencoded のデータも存在します。 application/x-www-form-urlencoded のデータの適合性の規定は存在していないので、そのようなデータに問題があるとはいえません。 しかし相互運用性のためには、 Webブラウザーが実装している application/x-www-form-urlencoded直列化器の動作に倣うべきでしょう。

[158] mailto: URL へのフォームの提出では、 application/x-www-form-urlencoded直列化器の出力の +%20 に置換する場合があります。 つまり通常のパーセント符号化相当の動作とするべきことになります。

[102] URL Standard は、 application/x-www-form-urlencoded を解釈する方法としてapplication/x-www-form-urlencoded構文解析器 (application/x-www-form-urlencoded parser) を規定しています >>68。このアルゴリズムは、バイト列を入力とし、 名前 (文字列) と値 (文字列) の組の列または失敗を出力とします。また、 文字符号化_charset_ を使うか否かisindex を使うか否かをオプション入力として持ちます。

[103] 本項の他の部分で説明している通り、 application/x-www-form-urlencoded の汎用的な構文解析の方法を示すものとなっています。

[104] URL Standard は、 application/x-www-form-urlencoded文字列構文解析器 (application/x-www-form-urlencoded string parser) も規定しています >>68。このアルゴリズムは、文字列を入力とし、 名前 (文字列) と値 (文字列) の組の列を出力とします (失敗はしません)。これは入力を UTF-8符号化してから application/x-www-form-urlencoded構文解析器を呼び出す >>68 というものになっています。

URLSearchParams 関連 API で使われています。

[153] かつては HTML Standard にも独自の規定がありましたが (歴史的にはこちらが先)、 URL Standard の規定に一本化されました。

[122] HTML Standard は、 application/x-www-form-urlencoded符号化アルゴリズム (application/x-www-form-urlencoded encoding algorithm) としてフォームデータ集合から生成する方法を規定しています >>121isindex への対応を除けば URL Standard のアルゴリズムとほぼ同じですが、 HTMLフォームに特化した形で規定されています。 入力はフォームフォームデータ集合で、出力はバイト列です。

[128] HTML Standard は、 application/x-www-form-urlencoded payloadの復号 (decode application/x-www-form-urlencoded payloads) の方法も規定しています >>121。 このアルゴリズムU+0000-U+007F の範囲の文字列および文字符号化isindex 対応の有無を入力とし、 名前 (文字列) と値 (文字列) の組の整列リストを出力とします >>121。 このアルゴリズムは、入出力のデータ型を除けばapplication/x-www-form-urlencoded構文解析器 (application/x-www-form-urlencoded parser) と同じです。

フォーム・データ集合からの生成

本項は古くなっています。

[18] HTML 4 は、 application/x-www-form-urlencoded のデータはフォーム・データ集合から次のように生成しなければならないと規定しています HTML 4 17.13.4.1

  1. 制御子の名前と値を escape します。
    1. 間隔は + に置換します。
    2. 予約文字は RFC 1738 2.2 節の規定の通り escape します。
    3. 改行は %0D%0A で表現します。
  2. 制御子の名前・値は文書順で並べます。 名前と値は = で分離し、 名前・値の組は相互に & で分離します。

[21] XForms 1.0 は、 application/x-www-form-urlencoded による直列化を次の通り規定しています XForms 1.0 11.6

  1. 要素節文書順に見ていきます。 1つ文節を含む要素節を選びます。
  2. 要素節毎に、 EltName=value{sep} という文字列を作ります。
    • EltName は要素節の局所名です。
      1. 間隔は + で置換します。
      2. 非 ASCII 文字および予約文字 (RFC 2396 およびその改訂によります。) を UTF-8 で URI escape します。16進数は大文字で表現します。
      3. 改行は %0D%0A とします。
    • value は文節の内容です。
    • {sep}submissionseparator 属性で指定された分離子文字です。
    • なお、要素節の属性や名前空間など他の情報は使われません。
  3. すべてを文書順に連結します。

[20] HTML では、フォーム制御子ごとにフォーム・データ集合に何が含まれるのかが異なります。 フォーム・データ集合, 成功, 現在値の説明をごらんください。 特に、ファイル選択制御子 (input/file) の現在値はファイル名の並びであり、ファイルの内容ではありません。 また、画像提出ボタン制御子 (input/image) では座標が含まれます。

HTML 2.0 では、値無し (null) な欄は省略しても構わない などの規定が含まれていましたが、 HTML 4 では整理されて成功制御子の選択に関する規定に移動しています。

名前

[41] application/x-www-form-urlencoded としては名前と値の組で特別な意味を持つのは _charset_ だけですが、文脈次第で更にいくつかの名前が特別な意味を持つこともあります。

[44] _charset_ は、 _charset_ hack により文字コードを指定するために使われます。

[45] OAuth 1.0 においては、 oauth_ から始まる名前は OAuth 1.0 用に予約されており、応用が勝手に使ってはなりません。

[142] OpenID 2.0openid. から始まる名前を OpenID の用途で使っていました。

[141] OAuth 2.0 はいくつかの引数名を規定しています。

OAuth 2.0 参照。

[47] 媒体素片URI query として使う場合には t などいくつかの名前が媒体素片仕様の規定に従って解釈されるべきものとなります。

[48] フォームの提出では .x.y で終わる名前や xy は特別な用法を持っています。

[46] かつてフォームの提出では isindex という名前が特別な意味を持ち、 通常の方法で使うことはできませんでした。

転送符号化との関係

[36] あまり見かけませんが、電子メイルでフォームを提出することもありますから、 application/x-www-form-urlencodedMIME で使われることもあります。

MIME の Content-Transfer-Encoding は、普通は不要です (7bit で十分です)。 (application/x-www-form-urlencoded 自体が転送符号化のようなものですから。) ただし、少しでもデータ量が多いと改行がない (あったとしても百分率符号化されている) ので、電子メイル / MIME の行長制限に引っかかることが容易に考えられます。 その場合は CTE が必要になります。

CTE は Quoted-Printable が適当です。 元々7ビットのデータなのですから Base64 は効率が悪すぎます。

歴史

誕生

[109] application/x-www-form-urlencodedHTML2フォームが導入された時に、その(唯一の)表現方法として規定されました。

enctype も参照。

HTML4

[111] HTML4フォームデータ集合application/x-www-form-urlencoded符号化する方法 >>110 を規定していました。

[19] HTML4改行%0D%0A と表現するとの規定を持っていました >>110 が、 HTML5 では改行の正規化は application/x-www-form-urlencoded ではなくフォームデータ集合の過程となっています。

[112] OAuth 1.0HTML4 を参照しており、厳密に解釈すると OAuth にもこれが適用されることになりますが、一般的にはそうは解釈されていないように思われます。

[138] ASCII文字のどれをパーセント符号化しなければならず、 どれをパーセント符号化してはならないかについて、 HTML4 は明確に規定していませんでした。

[113] パーセント符号化を大文字にするか小文字にするかについて、 HTML4 は言及していませんでした。

[114] HTML4ASCII以外に application/x-www-form-urlencoded は不適切で、 multipart/form-data を使うべきである >>110 とし、 非ASCII文字application/x-www-form-urlencoded でどう表現されるべきかに一切言及していませんでした。

[115] 当時の時代的限界とはいえ、実際に既に広く使われていた非ASCII文字フォームWebブラウザーの存在 (と世界の大多数の非ASCII文字利用者の存在) を無視して規定を怠ったため、文字コードの解釈に関する混乱はその後も数年継続することとなってしまいました。

[116] _charset_ hack は当時まだありませんでした。 charset 引数もまだ見られませんでした。
[117] multipart/form-dataGET では使えませんし、 POST でもサイズが増えることが多いですし (HTML4非ASCII文字application/x-www-form-urlencoded は非効率的と言っており、それは正しいですが、フォームデータのように短いデータの場合は multipart/form-data の方がずっと大きくなります。)、 multipart/form-data の構文解析は数倍面倒になりますから、 (一応は現に動作している) application/x-www-form-urlencoded から移行する動機はほとんど無く、 HTML4 のこの記述は現実には無視されていました。
[118] 理論上は multipart/form-datacharset により文字コードを明記できますが、実際には現在に至るまで Webブラウザーcharset 引数を使っていないので、実は multipart/form-data にすれば文字コードの問題が解決するわけではありません。

[13] 名前と値の組の区切りは & ですが、 HTML4URL query& が含まれると属性値として指定するときにescape が必要になるため、かわりに ; も認めるべき >>119 としており、 application/x-www-form-urlencoded の実装がそのような配慮を行うことを暗に求めています >>110

[14] HTML4 はあまり明確に説明していませんが、行間によると、 フォームの提出 (特に GET の場合) と URL query をしばしば同一のコードにより処理されるため、 URL query; を区切りとして用いることを促進するべくそのような説明になっていると思われます。

[33] これに従い application/x-www-form-urlencoded でも ; を区切りとみなす実装が多々あります。

[120] しかし GETフォームの提出を行うと & を生成する Webブラウザーの動作は変更するわけにはいかず、 その URL をコピペしてリンクURL に使うのも一般的なので、 HTML4 が狙っていた ; への移行ははじめから無理な話でした。

[10] 独立して application/x-www-form-urlencoded を規定する仕様書は長らく存在しませんでした。 HTML や XForms など、採用する規格の仕様書が個々に定義しています。 なお、定義しようという Internet-Draft がでているので後述。

を付けたのは、特に重要な規定を含むものです。 その他は、補助的な規定や他の仕様を参照するものなどのうち、 特に多く章を裂いているものを挙げています。この他単に application/x-www-form-urlencoded を参照しているだけの仕様は枚挙に暇がありません。

[53] Web Services Description Language (WSDL) Version 2.0 Part 2: Adjuncts (2007-06-23 05:33:39 +09:00 版) http://www.w3.org/TR/2007/REC-wsdl20-adjuncts-20070626/#_http_x-www-form-urlencoded

[76] 文字の符号化の方法 (charset) は規定されていません。 HTML 4 は ASCII 文字だけが使用できると述べています HTML 4 17.13.1 Note が、現実には任意の符号化方式が使われています。 (ASCII 非互換なものも含まれます。) URI 符号化を使うことからも明らかなように、 任意のバイナリ・データの転送に使用するのには向いていませんが、 稀にそのような用途でも使われます。 (但し、そのような場合であっても、 フォームの他の文字的データと共に転送する目的であり、 専らバイナリ・データを転送するために使用することは考えにくいです。) XForms はバイナリ内容には他の直列化方式を使うことを推奨しています XForms 1.0 11.6

[12] application/x-www-form-urlencoded の書式を ABNF で表現してみたのが次の生成規則です。 但し、すべての仕様・実装がこの規則に合致しているわけではありません。

  1. body = field *(separator field) / obs-body
  2. separator = "&" / obs-separator
  3. field = name "=" value
  4. name = 1*uchar / obs-name
  5. value = 1*uchar / obs-value
  6. uchar = ALPHA / DIGIT / "-" / "_" / "." / "," / ":" / joint / escaped / obs-uchar
  7. joint = "+"
  8. escaped = "%" escaped-code / "%0D%0A"
  9. escaped-code = "0" ( "0" / .. / "9" / "B" / "C" / "E" / "F" ) / ( "1" / .. / "7" ) HEXDIGIT / obs-escaped-code
  10. obs-escaped-code = 2HEXDIGIT
  11. obs-separator = ";"
  12. obs-body = *(separator field) [ separator ]
  13. obs-name = *uchar
  14. obs-value = *uchar
  15. obs-uchar = "'" / "(" / ")" / ";" / "$" / "@" / "*" / "!"

[15] HTML フォームの提出に際して UA が使用する charset は、 >>14 の通り、 HTML 4 は規定していません。 実装は、

  • 文書の charset と同じものを使用する
  • UA の charset (UA の内部符号やその環境の符号) と同じものを使用する
  • accept-charset で指定されたものを使用する

の3種類と、その混合があります。利用者によって編集されていないフォーム欄 (例えば input//hidden による隠し制御子) は文書の charset で、編集された欄は UA の charset で符号化するという UA すらかつて存在しました。 (その名も WinIE 3。)

XForms は、 UTF-8 を使用すると規定しています XForms 1.0 11.6

百分率符号化

[37] 文字 (あるいはオクテット) を百分率符号化するかどうかについて、 各仕様は次のように規定しています。

HTML 4
間隔+ とします。 それ以外の非英数字RFC 1738 2.2節の方法で符号化 (百分率符号化) します。 RFC 1738 によると、 百分率符号化には大文字の十六進数字を使いますが、 小文字を使っても構いません。改行%0D%0A とします。
XForms 1.0
間隔+ とします。 非 ASCII 文字と、 RFC 2396 (または以後の改訂) の予約文字は百分率符号化します。 百分率符号化には大文字の十六進数字を使います。 改行は %0D%0A とします。

[38] XForms 1.0は RFC 2396 の予約文字を符号化しろとは言っていますが、 非安全文字 (URI参照で使えない文字) を符号化しろとは言っていません。 これはミスではないですかね?

しかも URI の規格の最新版自動追尾になっております。 従って、どの URI の規格に従うかによって現時点で 3種類の方法があり得ます。

RFC 2396 による予約文字
[;/?:@&=+$,]
RFC 2732 による予約文字
[;/?[]:@&=+$,]
RFC 3986 による予約文字
[:/?#[]@!$&'()*+,;=]

URI 符号化

[16] 名前と値は、適当な charset によるオクテット表現を URI escape 符号化します。 XForms 1.0 XForms 1.0 11.6 によれば、

  • 間隔文字は、 + とします。
  • 改行は、 %0D%0A とします。
  • その他の URI 予約文字 (reserved) および非 ASCII 文字 (オクテット) は、 %HH とします。

16進数表現 HH は、 XForms によれば大文字を使います。

[17] この URI escape 符号化は名前にも値にも適用されますが、 制御子名に非 ASCII 文字や URI 予約文字を使うことはあまりないので、 名前の URI escape 符号化を復号しないフォーム処理エージェントが少なくないと推測されます。

Charset の識別

[22] >>11, >>14- にあるように、 application/x-www-form-urlencoded では、文字の符号化の方法が定まっていません。ですから、 判定のためにいくつもの方法が使われています。

決め打ち
特定の charset で提出されることが見込める環境のフォーム処理エージェントは、 charset に関する判定・変換を行いません。例えば、欧米で利用されており、 ASCII または ISO-8859-1 などで提出する利用者ばかりであると見込めるなら、 受け取ったデータをそのまま内部で使用していることがよくあります。 また、iモードなどの特定の機器から利用することを想定しているフォーム処理エージェントは、 シフトJIS (iモード拡張版) でデータを受け取るものと想定していることがよくあります。
自動判別
複数の charset が混在することが普通な環境では、 古くから自動判別によって内部用の charset に変換するなどしてから処理に使用するようにフォーム処理エージェントが設計されています。 例えば、日本語圏では昔から3つの符号化方式が混在してきましたから、 そのいずれであるかを判定し、どれかに統一するのが普通になっています。
識別情報の利用
自動判別は確実なものではなく、 よく文字化けが起こっていました。そのため、 外部や内部に識別情報を含め(させ)て、 それを使って復号するという手法が提案されてきました。 自動判別の手法も少しずつ改善されていますが、 それでも完全ではないことや、判定にかかる経費の問題がありますし、 識別情報を付加する UA が増えてきたこともあり、 現在では識別情報によって判断するフォーム処理エージェントが増えてきています。

自動判別

[23] application/x-www-form-urlencoded の文字列の符号化方式が不明な場合、 自動判別算法によって決定することがよくあります。 自動判別の方法は WWW でフォームが使われる以前から研究されてきましたが、 フォームのデータは従来の判別対象と比べて非常に短いものが多く、 より難しいものとなっています。

[24] また、 application/x-www-form-urlencoded では判定の対象となる名前・値が複数個存在しますが、 その一つに対する判定結果を他のすべてに対して使ってよいものかという問題もありました。 現在の実装は一つの application/x-www-form-urlencoded 実体で複数の符号化方式を混在させることはまずありませんが、 過去にはそうではないものもありました (>>15)。 ですから、ある欄がシフト JIS でも別の欄は日本語 EUC かもしれず、正確に処理するためにはすべての欄で別々に判定しなければなりませんから、 判定の経費が増大し、しかも判定の材料が少なくなるという悲惨な状況でした。

識別情報の利用

[25] 自動判別にできるだけ頼らず、 UA に識別情報を送らせたり、 一度判定済みの情報を再度利用することによって自動判別の不確実性や経費を削減する方法が古くから考えられてきました。

[5] 隠し欄を使った方法: 特定の文字を含めた隠し欄 (input//hidden) をフォームに含めておき、提出されたデータの中のその値とあらかじめ用意しておいた charset ごとのその文字の表現を比較するという方法があります。 たとえば、<input type="hidden" name="dot" value="・"> をフォームに含めておき、フォーム処理エージェントでは dot の値とあらかじめ用意しておいた のシフト JIS や日本語 EUC などによる表現と比較します。

この方法は、適当な文字を選べは確実に判定できる優れたものですが、 その情報が他の欄にも通用するとは限らないという問題 (>>24) があります。この方法が考案された当時実際に欄ごとに別の charset を用いる実装がありました (>>15) から、 かえって文字化けを誘発する虞がありました。

[27] 特別な名前を使った方法: 特定の名前・値の組を charset 名の識別として使います。 例えば、 Google では ie=UTF-8 のような組を含めることで、一度判別した情報を再利用しているようです。 但し、この使い方はフォームの提出の時点では (UA が対応していないので) 意味がありません。

この方法に UA が対応したものとして、 _charset_ hack と呼ばれるものがあります。フォームに特定の記述をしておくと、 UA が提出する際に charset 名を _charset_=ISO-2022-JP のような組として送信してくれます。この方法は最近主要な UA に実装され、徐々にフォーム処理エージェントでも使われるようになってきています。

[7] charset 引数を使った方法: POST で提出する場合など、 媒体型の引数が利用できる時に、 charset 引数を使って charset を指定します。

この方法は RFC 2070WAP WML, WAP 日本仕様ガイドライン で提案・規定されていますし、 Opera などの UA が提出の際に使っています。

[2] >>27 の方法と似ていますが、 >>27実体本体内の情報であるのに対し、 こちらは実体本体外 (実体頭欄) の情報ですから、 本体の構文解析より前に情報が得られます。その一方で、 実体頭欄を利用できない GET の HTTP URI のような場所では使えないという致命的な欠点があります。 また、 MIME の定義する charset 引数とは意味的にやや差異があり、 仕様上の問題はないとはいえ、一貫性に欠くとの批判もあります。 (RFC 2070 は、 URI 符号化が CTE のようなものと考えれば問題なかろうという見解を示しています。)

[29] Q: application/x-www-form-urlencoded で使う文字コードは何ですか?

A: application/x-www-form-urlencoded 実体自体は US-ASCII で記述します。符号化されている内容の文字コードは不定です。 (使用する場面の仕様や実装に依存します。)

詳細: >>11, >>14-15, >>22-, 提出, accept-charset

[30] Q: HTTP の Content-Type:charset を指定すればよいのではありませんか?

A: そのような実装も存在しますが、標準化されてはいません。また、 MIME の charset の仕様と意味的に異なるので望ましくないという考え方もあります。

詳細: >>7-, >>1-, charsetパラメーター

[31] Q: 非 ASCII 文字を使う時は multipart/form-data を使えと言うが、そんなブラウザはないのでは。

A: 現代の実用的な Web ブラウザで multipart/form-data に対応していないなんて考えられません。 HTML の場合は enctypemultipart/form-data著者が明示しておかないと multipart/form-data は使われませんよ。

詳細: multipart/form-data, enctype, 提出

[32] Q: TrackBack は application/x-www-form-urlencoded を使っているが、文字コードを指定できないではないか。欠陥だ。

A: そうですね。 application/x-www-form-urlencoded なんて使うからいけないのです。

関連: TrackBack

[34] Q: 鯖とやり取りするプログラムで、 application/x-www-form-urlencoded と書いてあった部分を application/x-www-form-urlencoded; charset=UTF-8 にしたら文字化けが起こらなくなりましたよ。

A: たまたまです。相性が良かったのです。 次のときもうまくいくとは限らないこと、 いつまでもうまく動き続けるとは限らないことを肝に銘じておいてください。

関連: >>11, >>14-15, >>22-, 提出, accept-charset, charsetパラメーター, multipart/form-data

[4] 過去のしがらみが無い HTTP POST を使うプロトコル・応用は、 できればこんな時代遅れの形式は使わずに、 multipart/form-data なり application/xml なり、 他のきちんと標準化された媒体型を使うべきです。

RFC 6749 (OAuth 2.0)

[135] RFC 6749 は、 HTML 4.01application/x-www-form-urlencoded の定義であるとしつつ、 非ASCII文字に対応しない不完全な定義だと述べています >>134

[136] RFC 6749 はまず名前と値を RFC 3629 UTF-8符号化してからパーセント符号化しなければならない >>134 と規定していました。

[139] ただし曖昧な HTML4 を参照しているため、 RFC 6749 の定義も曖昧無いとはいえません。例えばどの文字パーセント符号化しなければならないかは明確になっていません。

HTML5

[131] HTMLフォームの提出における application/x-www-form-urlencoded の生成方法は、 HTML5 によってようやく近代的な厳密な定義を得ることとなりました。 ようやくはじめて公式に HTMLフォームから非ASCII文字application/x-www-form-urlencoded提出できるようになりました。

[132] それから更に数年遅れて URL Standard によって URL 関連の規定の整備が進み、 HTMLフォームと切り離した application/x-www-form-urlencoded の規定も URL Standard に含まれることとなりました。それまで Webブラウザーapplication/x-www-form-urlencoded の生成のみで、 解釈は専ら側で行われていましたが、 URL Standard が新たに規定する URLSearchParams 関連 API によりスクリプトでも解釈が行われるようになりました。

実装

[1] http://openlab.ring.gr.jp/k16/htmllint/faq.html によると、古い Lynxcharset パラメーターを付けてしまうようです。 Perl の古い CGI 用 library である cgi-lib.pl はこれに対応していません。

この他にも、 Content-Type: 欄に引数が含まれるとうまく処理できなくなってしまうフォーム処理エージェントがかなり多く存在している模様です。

[6] 2003-09-26 07:29:50 +00:00 Opera 7.02 を使ってみましたが、こいつは application/x-www-form-urlencoded; charset=utf-8 なんてのを送ってきます。。。

[54] 豊島区立図書館のメモ - やればできる子の日記 ( 版) http://d.hatena.ne.jp/matsuza/20080831/1220177018

[28] 誤って1文字目に ? をつける実装もあります。

関連

[3] Lynxapplication/sgml-form-urlencoded に対応しています。これは & の代わりに ; を使います。

[8] mailto:ftp: などいくつかの URL schemequery において application/x-www-form-urlencoded と類似した構文を採用していますが、 application/x-www-form-urlencoded とはされていません。

[26] 媒体素片application/x-www-form-urlencoded と類似した構文を採用していますが、 application/x-www-form-urlencoded とは細部で異なります。

[40] text/plaintext/csvapplication/pdf などいくつかの MIME型では素片識別子application/x-www-form-urlencoded と類似した構文を採用していますが、 application/x-www-form-urlencoded とはされていません。

[159] フォームの提出enctypetext/plain の時に使われる形式は、 application/x-www-form-urlencoded からパーセント符号化を除いたものです。

メモ

Web アプリケーション 開発

[35] Q: ファイルをうpできません。ファイル名しか取得できません。

A: HTML のフォームでは、ファイルをうpするためには application/x-www-form-urlencoded は使えません。 multipart/form-data など他の形式をお使い下さい。

関連: input//file, enctype, multipart/form-data

[55] XForms 1.1 ( 版) http://www.w3.org/TR/2009/REC-xforms-20091020/#serialize-urlencode

[56] WWW-Talk Jul-Sep 1993: Submitting input-form data to server ( 版) http://1997.webhistory.org/www.lists/www-talk.1993q3/0812.html

[57] XProc: An XML Pipeline Language ( 版) http://www.w3.org/TR/2010/REC-xproc-20100511/#c.www-form-urldecode

[59] IRC logs: freenode / #whatwg / 20100926 ( ( 版)) http://krijnhoetmer.nl/irc-logs/whatwg/20100926

[60] Web Applications 1.0 r6450 Define how to parse the various form submission formats. Register the legacy one. Some editorial tweaks for consistency. ( ( 版)) http://html5.org/tools/web-apps-tracker?from=6449&to=6450

[61] Web Applications 1.0 r6641 Mention that application/x-www-form-urlencoded;charset does nothing. ( ( 版)) http://html5.org/tools/web-apps-tracker?from=6640&to=6641

[62] [ietf-types] Registration for application/x-www-form-urlencoded ( ( 版)) http://www.ietf.org/mail-archive/web/ietf-types/current/msg01711.html

[63] IRC logs: freenode / #whatwg / 20121130 ( ( 版)) http://krijnhoetmer.nl/irc-logs/whatwg/20121130#l-609

[64] IRC logs: freenode / #whatwg / 20121130 ( ( 版)) http://krijnhoetmer.nl/irc-logs/whatwg/20121130#l-1057

[65] SPARQL 1.1 Protocol ( ( 版)) http://www.w3.org/TR/2013/REC-sparql11-protocol-20130321/#query-via-post-urlencoded

[66] IRC logs: freenode / #whatwg / 20131010 ( ( 版)) http://krijnhoetmer.nl/irc-logs/whatwg/20131010#l-1183

[69] ( ( 版)) http://alcme.oclc.org/openurl/docs/pdf/KEV.pdf

[70] Core:Serializations - info:ofi/fmt:kev ( ( 版)) http://alcme.oclc.org/openurl/servlet/OAIHandler?verb=GetRecord&metadataPrefix=oai_dc&identifier=info:ofi/fmt:kev

[71] Generic syntax ( (Anne van Kesteren 著, 版)) http://lists.w3.org/Archives/Public/public-media-fragment/2013Aug/0001.html

[146] Remove allow non-ASCII-compatible encodings flag · whatwg/html@c485b70 ( 版) https://github.com/whatwg/html/commit/c485b70bfe41ed1302c451bc62b58df80cffd325

[147] Editorial cleanup for application/x-www-form-urlencoded · whatwg/url@74ea912 ( 版) https://github.com/whatwg/url/commit/74ea912c232d5f1596db06cb6297436cec3b0da3

[148] Align application/x-www-form-urlencoded serializer with the needs of … · whatwg/url@b174f8f ( 版) https://github.com/whatwg/url/commit/b174f8f2170a4ce6fd4031206e0490eff2b0aa02

[149] Adopt a great note about application/x-www-form-urlencoded from HTML · whatwg/url@ef6cda4 ( 版) https://github.com/whatwg/url/commit/ef6cda424a60ff435775dcb579839991d9318207

[150] Let the URL Standard deal with application/x-www-form-urlencoded · whatwg/html@0fef169 ( 版) https://github.com/whatwg/html/commit/0fef169e6fca7433e3aac2a3640b4665b791ff8e

[151] Fix logic errors in application/x-www-form-urlencoded · whatwg/url@052a89f ( 版) https://github.com/whatwg/url/commit/052a89fd039ae3e97908eba2d8fdaaac819d6aa2

[152] Remove isindex handling from application/x-www-form-urlencoded · whatwg/url@c85fb5d ( 版) https://github.com/whatwg/url/commit/c85fb5d527f822e089aecc9207f077c6b886aed5

[157] Fix form submission's encoding algorithms ( (annevk著, )) https://github.com/whatwg/html/commit/ec42efb1d7c3a2e34db21b8076a8a3f4bd6dfb81

[167] XProc 2.0: Standard Step Library () https://www.w3.org/TR/2016/NOTE-xproc20-steps-20160721/#c.www-form-urldecode

[168] Make application/x-www-form-urlencoded encode filenames (annevk著, ) https://github.com/whatwg/url/commit/26caf4927f6c95ba4f56d701ecd8a52fdb664982

[169] Parse application/x-www-form-urlencoded using UTF-8 only (annevk著, ) https://github.com/whatwg/url/commit/3fe969679f78c92c353047661b0c4b6797f099f6

[171] Firebase Cloud Messaging サーバーについて  |  Firebase ( ()) https://firebase.google.com/docs/cloud-messaging/server

application/x-www-form-urlencoded;charset=UTF-8(書式なしテキストの場合)

[172] Editorial: use Infra in a/x-www-form-urlencoded (TimothyGu著, ) https://github.com/whatwg/url/commit/1cdcab314ed539a1b26f53a2618ef480708eb297

[173] Micropub () https://micropub.net/draft/#overview-p-1

All Micropub requests to create posts are sent as UTF-8 x-www-form-urlencoded, multipart/form-data [HTML5], or [JSON]-encoded HTTP requests.

[174] Micropub () https://micropub.net/draft/#form-encoded-and-multipart-requests-p-1

For x-www-form-urlencoded and multipart/form-data requests, Micropub supports an extension of the standard URL encoding that includes explicit indicators of multi-valued properties. Specifically, this means in order to send multiple values for a given property, you must append square brackets [] to the property name.

[175] Micropub () https://micropub.net/draft/#source-content-p-3

The query can specify the list of properties being requested by setting one or more values for the properties key. If more than one is specified, use array bracket notation for each name, according to [HTML5] URL encoding.

[176] Remove _charset_ handling from application/x-www-form-urlencoded (tkent-google著, ) https://github.com/whatwg/url/commit/5c0d2ec09ec16099e5c453d088fea9b8ba0154a5

[177] Remove _charset_ handling. by tkent-google · Pull Request #382 · whatwg/url () https://github.com/whatwg/url/pull/382

[178] Move _charset_ handling to construct the form data set (tkent-google著, ) https://github.com/whatwg/html/commit/8c212e549607a41b6d40d953b47d9f3e749533f3

[179] Move _charset_ handling from "multipart/form-data encoding algorithm"… by tkent-google · Pull Request #3645 · whatwg/html () https://github.com/whatwg/html/pull/3645

[180] Remove 'type' from from data entries (tkent-google著, ) https://github.com/whatwg/url/commit/acc2bf4a8e67fb13523f4ee35ff32be922eb9142

[181] Remove 'type' from from data entries. by tkent-google · Pull Request #384 · whatwg/url () https://github.com/whatwg/url/pull/384

[182] 795733 - '&' and ';' should not be percent-encoded in URL queries - chromium - Monorail () https://bugs.chromium.org/p/chromium/issues/detail?id=795733

[183] percent-encode ' in queries of URLs with special schemes by achristensen07 · Pull Request #395 · whatwg/url () https://github.com/whatwg/url/pull/395

[184] https://lab.ndl.go.jp/dataset/ndlocr/text_recognition/ndlenfixed64-mj0-synth1.pth

なぜか Content-Typeapplication/x-www-form-urlencoded; charset=utf-8。 中身はぜんぜん違う。