URIエンコーディング

パーセント符号化 (URL)

[37] URL で用いられている、 % と2桁の十六進数によってオクテットあるいは文字を表す表記法をパーセント符号化 (percent-encoding) といいます。

[38] 以前は URI エスケープ (escape) URL 符号化 (エンコーディング) (encoding) などとも呼ばれていました。
[66] 文字列パーセント符号化したり、パーセント符号化された文字列復号したりするには、 Charinfo をお使いください:

古い情報の見分け方

[182] パーセント符号化をめぐっては、古い情報や誤った情報が蔓延しています。 権威のありそうな文書を引用したり、さも当然のように断定したりしているのが、 事実とまったく正反対の説明だったりもするので、注意しなければなりません。

[183] 次のような条件に当てはまるものは、誤った情報の可能性が高いです。

仕様書

[27] URL および application/x-www-form-urlencoded におけるパーセント符号化は、 URL Standard で規定されています。

[28] URL および関連する概念が厳密に規定されてこなかった歴史的経緯から、 それ以外のいくつかの仕様書にも類似した規定が含まれています。

呼称

[44] パーセント符号化は、歴史的に URI 符号化 (URI encoding) URI 逃避符号化 (URI escape(d) encoding) URI 逃避 (エスケープ) (escape) など色々な呼ばれ方をしてきました。 URI の第4次規格である RFC 3986 (IETF インターネット標準) が以前の用語にかえてパーセント符号化 (percent‐encoding) という用語を採用したため、 現行仕様である WHATWG URL Standard もそれを踏襲しています >>43

[45] %HH という表記のことを、 UR[IL] escape という流儀と UR[IL] encode という流儀があります。仕様書にも混在していて、有意な使い分けも認められません。早い話がどっちでもいいということです。

[46] あ、でも、最新の URI の定義である RFC 2396 では整理されていて、 URI 符号化の意味の encode は必ず escaped encoding という語で登場します。 octet encoding と対になっています。

[47] 2396 に「URI encoding」という語がないことからこれを誤りで「URI escape」が正しいとする論もありますけどナンセンスですね。正確を期すなら「URI escape encoding」とフルスペって初めて意味を成す。 URI escape encoding にするという意味の動詞なら「URI escape する」でもいいとは思いますがね。

[76] 俗に、エスケープシーケンスと呼ぶこともあります。

構文

[97] パーセント符号化では、 % と二桁の ASCII 十六進数字によって一つのオクテットを表します。 % はそれ以外では使ってはいけませんが、もし使われた場合、そのものを表します。 % 以外の文字あるいはオクテットは、そのものを表します。

  1. *
    1. |
      1. % 以外
      2. =
        1. %
        2. 十六進数字
        3. 十六進数字

[67] パーセント符号化された3文字の列は、 RFC 2396 では escaped、 それより前は escape という ABNF 生成規則で定義されていました。

[77] 何を % を使って符号化し、何を元のまま残すかは、文脈によります。 個々の事情があるので、無条件にどれが正しいというものでもありません。

[78] 例えば https: URLpath segment 部分では、 互いの区切りの /%2F としなければなりません。 また query との区切りの ? も、 %3F としなければなりません。 @ は区切りとして使われませんから、 @ のままでも構いませんし、 %40 でも構いません。

>>59 を参照。
[174] 世間一般の解説記事の類で「パーセント符号化では○○を符号化しなければならない、 しなくてはよい、してはならない」といった記述がある場合、必ずしも正しくありませんから、 眉に唾をつけて読み飛ばしましょう。 RFC などを引用していても、 誤ったものを誤って解釈したり、十数年も前の古いものを参照していたりしますから、 下手に信用するのは危険です。

[108] パーセント符号化バイト (percent-encoded byte) は、 % の後にASCII十六進数字が2つ続くものです >>43

[109] %ASCII十六進数字も、符号位置です。 従ってパーセント符号化バイトは、文字列です。 (バイトと名前につくのは、それがバイトを表しているからであり、 それ自体はバイト列ではありません。)

大文字と小文字

[16] 現在の URL Standardパーセント符号化の定義では、 十六進数字大文字を使うことになっています。

[61] パーセント復号では、大文字小文字も区別せず復号されます。

[1] Bug in w3m-url-encode-string (2007-05-11 13:00:36 +09:00 版) http://emacs-w3m.namazu.org/ml/msg09323.html

Webとの互換性のためには百分率符号化大文字でなければならないらしい。

RFC 3986 的に大文字でなければならないというのは誤りで、 RFC 4234 ABNF大文字小文字を区別しない。

(名無しさん 2007-05-11 11:19:59 +00:00)

文脈

[73] パーセント符号化は、次の場面で用いられています。

[199] パーセント符号化される場面

非予約文字の百分率符号化

[2] 最後の path segment が %2E または %2E%2E, %2E., .%2E相対参照について。 (名無しさん)

[3] a href にそのような相対参照を指定した時のステータス・バーまたはツールチップに表示される絶対URI参照は:

(名無しさん)

[4] そのリンクかちったときに飛ばされる文書URI (アドレス・バーの表示や location.href) は:

(名無しさん)

[5] >>2 のような path segment が含まれるものの、最後の path segment ではない相対参照 (例えば %2E/) (名無しさん)

[6] >>5 ステータス・バーなどの表示:

(名無しさん)

[7] >>5 飛ばされる URI:

(名無しさん)

[8] URI scheme http の一部または全部が百分率符号化されているURI参照 (名無しさん)

[9] >>8 表示、移動先とも、 Firefox 1.5、Opera 9、 WinIE 6 のいずれも相対参照と解釈 (名無しさん)

[10] ASCII hostname の一部または全部が百分率符号化されているURI参照

(名無しさん)

[11] >>10: 表示: Firefox 1.5、Opera 9、WinIE 6 とも、 百分率符号化を解いたもの (名無しさん)

[12] >>10 移動先:

(名無しさん)

[13] ポート番号の一部または全部が百分率符号化されている場合: 表示、移動先とも:

(名無しさん)

[14] テスト: http://suika.fam.cx/~wakaba/-temp/test/uri/percent/unreserved/ (名無しさん 2007-05-21 05:49:59 +00:00)

[15] akr流(2007-02-22) (akr 著, 版) https://www.codeblog.org/blog/akr/20070222.html

%

[98] % は、オクテットを表す以外では使うことができません。 これはパーセント符号化のみならず、 URL 全体での原則です。

[99] しかし現実には % の後に十六進数字2桁が続かない場合もあります。 そのような場合には、 % そのものを表すと解釈することになっています。

[100] ただし、などの実装によっては致命的エラーとみなすこともあります。

[101] URL における % には次のような特別な使い方もあり、 パーセント符号化と混在するかもしれません。

[62] 長い URL が途中で分断されるなどの理由で % で終わる URL が生成されてしまうことがあります。

[63] メッセージIDでよく使われる文字である % を無変換で URL の一部に含めてしまいメーリングリストアーカイブなどで単独の % が混入することがあります。

+

[89] application/x-www-form-urlencoded の仕様より、 パーセント符号化された文字列において +0x20 ないしは U+0020 と解釈されることが多々あります (プラスパーセント符号化)。 これは application/x-www-form-urlencoded 側の仕様であって、 パーセント符号化の一部ではありません。

[158] URL のある部分がただのパーセント符号化であるかプラスパーセント符号化であるかは、 その部分に関する規定に依存しており、どちらであるかを判断するのは難しい問題ですが、 おおむね次のように決定できます。

  1. [159] URL の一部なら、
    1. [162] query なら、
      1. [165] URL schemehttp:/https:/ws:/wss: なら、
        1. [166] application/x-www-form-urlencoded の可能性が高い
      2. [167] それ以外なら、
        1. [168] おそらくただのパーセント符号化
    2. [163] それ以外なら、
      1. [164] おそらくただのパーセント符号化
  2. [160] POST データなら、
    1. [161] application/x-www-form-urlencoded

[21] mailto: URLquery媒体素片application/x-www-form-urlencoded と似ていますが、 + に特別な解釈を与えていません。

[169] http:/https: URLquery の解釈は、完全にサーバー側に委ねられています。 サーバーの管理者やWebアプリケーション開発者は、 ただのパーセント符号化でも、application/x-www-form-urlencoded でも、他の独自の形式でも、個々の事情に合わせて任意の形式を採用できます。 クライアントは事前情報無しにどちらを利用するべきか決定できません。

もっとも、フォームの提出application/x-www-form-urlencoded に固定されていますから、Webアプリケーションの開発者はそれに合わせた方が楽で無難です。

[104] ただのパーセント符号化+0x20 ないしは U+0020 と解釈する/させることは誤りです。 ただのパーセント符号化における + は、 + そのものを表します。 (文脈によっては、区切りなど特別な意味が与えられていることもあります。)

[79] JavaScriptencodeURIComponentパーセント符号化のためのもので、 application/x-www-form-urlencoded のためのものではありませんから、 U+0020 SPACE+ ではなく、 %20符号化されます。

[103] application/x-www-form-urlencoded でも %20 が禁止されているわけではありませんから、常に %20 を使うこととし + を使わないとしても、問題はありません。

[173] 世間のパーセント符号化URLフォームの実装や解説の類では、 application/x-www-form-urlencoded を含めいろいろなパーセント符号化のバリエーションについて、 混同して混乱していることがよくあります。仕様書などを引用していても、 誤った解釈から誤った結論を導いていることが少なくありませんから、 不用意に信用してはいけません。

符号化文字集合

[85] パーセント符号化復号したものは、バイト列 (オクテット列) です。

[86] これをどう解釈するかは、パーセント符号化が用いられる文脈によって異なります。

[87] 近代的な仕様やアプリケーションでは、UTF-8 によって符号化された文字列として解釈します。

[110] パーセント符号化バイトの列は、 パーセント復号してから UTF-8 decode without BOM or fail を適用しても失敗とならないべきです >>43

[88] 歴史的には UTF-8 以外によって解釈されることも多々ありました。 文字列ではないバイト列として解釈されることもあります。

[23] URL 一般においてはパーセント符号化されたバイト列文字コードが何であるか明記する仕組みはありません。 関連する仕様書によって明示的に規定されていることもあれば、 慣習によることや、受信者の自動判別に依存していることもあります。

[24] application/x-www-form-urlencoded では、 _charset_ hack や同様の手法でパーセント符号化されたバイト列文字コードが記述されることもあります。

[25] >>102 が提案する HTTPヘッダーのように外部に文字コードを明記する手法が提案されたり、 部分的に実装されたりすることもありましたが、広く普及しているものはありません。

%u 符号化

[36] ECMAScript によって導入された %u 符号化は、 URL での利用が認められたことはありませんが、現在でも稀に用いられます。 詳しくは %u の項をご覧ください。

application/x-www-form-urlencoded

[90] application/x-www-form-urlencodedパーセント符号化から派生した MIME型です。フォームの提出で採用されています。

[91] 詳しくは application/x-www-form-urlencoded の項を参照してください。

[92] application/x-www-form-urlencoded は単独の実体として使われる他に、 URLquery として使われることがあります。 >>89 の通り、 + の解釈がただのパーセント符号化とは異なります。 (この MIME型に限らず) http: URLquery の解釈はサーバーに委ねられていますから、 当該サーバーや当該サーバーと事前に知識を共有した者以外は query をどう解釈するべきか確実には決定できません。

パーセント符号化演算

[59] パーセント符号化 (やパーセント復号) の方法は、 入力が文字列バイト列、あるいは既にパーセント符号化を含む URL の一部分のいずれであるかにより、 またそれを URL のどの部分で用いるかにより、色々なバリエーションが存在しています。

[60] 多くの場合は特に区別せずに「パーセント符号化」や「URI符号化」 などと曖昧に呼ばれているので、しばしば混同され、相互運用性の問題を生じさせる原因ともなっています。

基本的な演算

[111] バイトバイトパーセント符号化 (percent encode) は、 次のようにしなければなりません >>43

  1. [112] % の後に、2桁の大文字十六進数バイトを表現したものを連結した文字列を返します。

[129] 仕様書上のパーセント符号化は、バイト列ではなくバイトに関する操作として定義されています。

[113] バイト列入力パーセント復号 (percent decode) は、 次のようにしなければなりません >>43

  1. [114] 出力を、バイト列に設定します。
  2. [115] 入力の各バイトバイトについて順に、
    1. [119] バイトが処理済みでなければ、
      1. [116] バイトが 0x25 なら、
        1. [120] バイトの次に2バイトあって、それがいずれも [0x30, 0x39], [0x41, 0x46], [0x61, 0x66] のいずれかの範囲に含まれるなら、
          1. [121] 復号バイトを、当該2バイトUTF-8 decode without BOM した結果を十六進数として解釈した結果に設定します。
          2. [122] 復号バイト出力の末尾に追加します。
          3. [123] 当該2バイトを処理済みとします。
        2. [124] それ以外なら、
          1. [125] バイト出力の末尾に追加します。
      2. [117] それ以外なら、
        1. [118] バイト出力の末尾に追加します。
  3. [126] 出力を返します。

[127] つまり、 %ASCII十六進数字2桁の列はその十六進数の表すバイトに置換され、 それ以外のバイト (不適切な % も含みます。) はそのまま出力されます。

[128] パーセント復号の結果はバイト列で、それをどう解釈するかは呼び出し元に委ねられています。 ただし、入力ASCIIバイト以外が含まれる場合、 UTF-8 decode without BOM 以外の方法で扱うのは安全ではないかもしれないので、 避けるべき>>43 とされています。


[130] 符号位置符号化集合に関するUTF-8パーセント符号化 (UTF-8 percent encode) は、 次のようにします >>43

  1. [131] 符号位置符号化集合に含まれないなら、
    1. [132] 符号位置を返します。
  2. [133] それ以外なら、
    1. [134] バイト群を、符号位置UTF-8符号化した結果に設定します。
    2. [135] バイト群の各バイトバイトを、 バイトパーセント符号化した結果に置換します。
    3. [136] バイト群を返します。

[143] UTF-8パーセント符号化は、 フォームの提出を除けば、URL構文解析器でのみ使われているようです。


[193] 文字列パーセント復号 (string percent decode) は、 文字列入力を次のようにすることをいいます。 >>43

  1. [194] バイト群を、 入力UTF-8符号化した結果に設定します。
  2. [195] バイト群パーセント復号した結果を返します。

[201] 入力文字列ですが、出力バイト列となります。

[196] 文字列パーセント復号する場面

application/x-www-form-urlencoded

[55] application/x-www-form-urlencoded は、任意の文字符号化によって符号化してからパーセント符号化する方法を規定しています。 ここでは 0x20 は + で表す点が通常のパーセント符号化と異なります。

[56] これに対応する復号の方法も規定されています。

詳しくは application/x-www-form-urlencoded を参照。

[140] mailto: URL へのフォームの提出では、 application/x-www-form-urlencoded として符号化した後で +%20 に置換する場合があります。つまり標準的なパーセント符号化となります。

OAuth 1.0 パーセント符号化

[29] OAuth 1.0 (RFC 5849) は、次のようなパーセント符号化の手順を規定しています >>26

  1. [52] テキストの値なら、 RFC 3629 UTF-8符号化します。 バイナリの値には適用しません。
  2. [53] RFC 3986 非予約文字以外オクテット% と2桁の大文字十六進数字の列に置き換えます。

[51] この符号化方式は OAuth 1.0 における Authorization: ヘッダーと、署名基底文字列で用いられます。 application/x-www-form-urlencoded ではこの方式は使いません。 >>26

[54] 復号の方法はなぜか明記されていません。 Authorization: では復号も必要なはずですが・・・。

[156] テキストの値の OAuth 1.0パーセント符号化は、 認証された要求の作成で呼び出されます。

[155] バイナリーの値をOAuth 1.0パーセント符号化することは無さそうに思いますが、 既に (OAuth 1.0署名以外) 作り終えた要求の一部を取り出して署名基底文字列を作成する時、 バイナリー入力のパーセント符号化が必要となります。

[185] AWSドキュメントで用いられる関数 UriEncode() >>184 は、予約文字以外パーセント符号化することを求めています。 これは OAuth 1.0 方式のパーセント符号化バイナリー入力を与えた場合と同じです。

JavaScript encodeURI / decodeURI

[50] JavaScriptencodeURI() >>144 は、 UTF-8パーセント符号化するものです。 サロゲートペアでないサロゲートが含まれると、失敗します。

[148] decodeURI() >>144 は、それに対応する復号の方法です。 予約文字は、符号化されたまま残します。 パーセント符号化として、または UTF-8 として不適切な入力だと、失敗します。

[175] これらの関数が有用な場面は意外とありません。ほとんどの場合は encodeURIComponent/decodeURIComponent の方が適切です。

JavaScript encodeURIComponent / decodeURIComponent

[150] JavaScriptencodeURIComponent() >>144 は、 UTF-8パーセント符号化するものです。 サロゲートペアでないサロゲートが含まれると、失敗します。

[187] UTF-8パーセント符号化を特定の符号化集合で実行したものと解釈できますが、 UTF-8パーセント符号化の入力は文字列であるのに対し、 JavaScript の入力は16ビット符号単位列なのでサロゲートの扱いが規定されている点が異なります。

[153] decodeURIComponent() >>144 は、それに対応する復号の方法です。 パーセント符号化として、または UTF-8 として不適切な入力だと、失敗します。

[176] JavaScript文字列処理により URL を組み立てる場合や、 URL の一部から符号化された文字列を取り出す場合には、 これらの関数が適切な場合が多いです。

[177] application/x-www-form-urlencoded でない普通のパーセント符号化ですから、 + の特別な処理は行われません。 URL query の処理で特に application/x-www-form-urlencoded を特に扱う必要がある時は、 処理前または処理後に適宜 + を置換しなければなりません。

[149] encodeURIComponent メソッド http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/script56/html/js56jsmthEncodeURIComponent.asp

[151] WinIE 6, Opera 9, Firefox 2 のいずれも、 encodeURIComponentサロゲート・ペアの片割れが与えられると正しく URIError を投げるようです。

[145] Firefox 2 では、 decodeURIComponentU+FFFEU+FFFF (に相当する %EF%BF%BE%EF%BF%BF) を与えると、 U+FFFD を返します。 WinIE 6Opera 9 ではそのようなことはありません。

[146] Opera 9 は %00復号しないようです。 Firefox 2 や WinIE 6 ではそのようなことはありません。

JavaScript escape() / unescape()

[48] JavaScriptescape() は、 ASCII文字パーセント符号化し、 非ASCII文字%u 符号化するものです。

[49] unescape() はそれを復号するものです。

%u 参照。

[178] これらの関数は歴史的なもので、必要となる場面はほとんどありません。

ALPN プロトコル名のパーセント符号化

[138] ALPNプロトコル名パーセント符号化する場合、 HTTP字句で表せるオクテット (% 以外) はそのまま、 それ以外はパーセント符号化し、パーセント符号化には大文字を使うことが求められています。

ALPN:Alt-Svc: を参照。

[142] この方法は、復号しないで符号化された状態で比較に使うことが想定されています。

CGI における取り扱い

[40] 文字列パーセント符号化する場合、 reserved に含まれていない文字符号化してはなりません >>39

URI Template のパーセント符号化

[57] URI Template は、雛形リテラルパーセント符号化文字列値のパーセント符号化 (雛形式参照。) の2種類のパーセント符号化の方法を規定しています。

IRI および IRI もどきのパーセント符号化

[58] IRI および各種の IRI もどきは、パーセント符号化により URI を得る方法を規定しています。細部が異なる色々なバリエーションがあります。

IRI 参照。

パーセント符号化される文字/バイトの比較

[141]

name
符号化の方式
encoded
符号化されるもの
name
UTF-8パーセント符号化 + C0制御パーセント符号化集合
encoded
https://chars.suikawiki.org/set/%24url%3Asimple-encode-set
name
UTF-8パーセント符号化 + パスパーセント符号化集合
encoded
https://chars.suikawiki.org/set/%24url%3Adefault-encode-set
name
UTF-8パーセント符号化 + 素片パーセント符号化集合
encoded
https://chars.suikawiki.org/set/%24url%3Afragment-encode-set
name
UTF-8パーセント符号化 + userinfoパーセント符号化集合
encoded
https://chars.suikawiki.org/set/%24url%3Auserinfo-encode-set
name
application/x-www-form-urlencoded
encoded
https://chars.suikawiki.org/set?expr=-%24url%3Aform%3Aunencoded-byte-char
name
ALPN
encoded
https://chars.suikawiki.org/set?expr=-%24rfc7230%3Atchar|[%25]
name
OAuth 1.0
encoded
https://chars.suikawiki.org/set?expr=-%24rfc3986%3Aunreserved
name
escape()
encoded
https://chars.suikawiki.org/set?expr=-%24ecma262%3Aescape-not-escaped
name
encodeURI()
encoded
https://chars.suikawiki.org/set?expr=-%24ecma262%3AunescapedURISet
name
encodeURIComponent()
encoded
https://chars.suikawiki.org/set?expr=-%24ecma262%3AunescapedURIComponentSet

[154] パーセント符号化される文字の比較:

各実装の符号化演算

[171] 歴代の URL仕様書パーセント符号化の規定があまり明確でなかったことや、 パーセント符号化が文脈によって色々な使われ方をしていることもあり、 各種プログラミング言語ライブラリーフレームワーク等のパーセント符号化パーセント復号の演算も多種多様で混乱しており、 利用する時は正しい物を注意深く選択しなければなりません。

[172] 例えば PHPhttp_build_query >>170 は、 符号化の方式を指定するオプションを用意していますが、 PHP_QUERY_RFC1738 は「RFC 1738 + application/x-www-form-urlencoded」、 PHP_QUERY_RFC3986 は「RFC 3986」の方式と説明されています。 RFC 3986 は古い URL の仕様書で、 RFC 1738 は更に何代か古い URL仕様書です。 前者が実はただのパーセント符号化ではなく application/x-www-form-urlencoded 方式だという重要な情報は定数名に現れず、 ドキュメントを読まないとわかりません。 また RFC 1738RFC 3986 とで reserved の定義が異なるためにどの文字をパーセント符号化するかが両方式では違っているということのようです。 しかし、これではいつどちらを使うべきなのかがさっぱりわかりません (PHP のドキュメントにも、もちろん両 RFC にも書かれていません)。

[186] プログラミング言語によっては、入出力が文字列バイト列のいずれであるかにも、 注意が必要です。

[188] 近代的なライブラリーでは、 UTF-8パーセント符号化と、 その逆演算 (パーセント復号してからUTF-8復号) の関数が用意されていることがあります。

JavaScriptencodeURIComponent/decodeURIComponent に相当するものですが、やはり細部が異なることがあります。

[216] encodeURIComponent を使っていればだいたいうまくいきますが、それでも困ることは稀にあります。

[217] 例えば encodeURIComponent(, )符号化しません。 CSSurl() の中に直接使うと構文誤りになります。 url("") の中でなら問題ありません。

[218] どちらかといえば CSSurl() の構文の方の欠陥に近いのですが、 url("") より url() の方が使いやすくて多用してしまうので、 うっかりには注意です。

歴史

RFC 2396 (URI) 2.4. Escape Sequences

Data must be escaped if it does not have a representation using an unreserved character; this includes data that does not correspond to a printable character of the US-ASCII coded character set, or that corresponds to any US-ASCII character that is disallowed, as explained below.

データは、非予約文字を使って表現することができない場合には、 escape しなければなりません。これには、 US‐ASCII 符号化文字集合の印字可能文字に対応しないデータや対応する US‐ASCII 文字が禁止されているデータを含みます。

2.4.1. Escaped Encoding

An escaped octet is encoded as a character triplet, consisting of the percent character "%" followed by the two hexadecimal digits representing the octet code. For example, "%20" is the escaped encoding for the US-ASCII space character.

Escape するオクテットは、百分率記号 % とそれに続くオクテット符号を表現する2つの16進数字で構成される3文字列として符号化されます。 例えば、 %29 は US‐ASCII 間隔文字の escape した符号化です。

2.4.2. When to Escape and Unescape

A URI is always in an "escaped" form, since escaping or unescaping a completed URI might change its semantics. Normally, the only time escape encodings can safely be made is when the URI is being created from its component parts; each component may have its own set of characters that are reserved, so only the mechanism responsible for generating or interpreting that component can determine whether or not escaping a character will change its semantics. Likewise, a URI must be separated into its components before the escaped characters within those components can be safely decoded.

URI は、常に「escape された」形です。 完全な URI を escape したり unescape したりすると、 その意味が変わってしまうかもしれません。 通常、 escape 符号化を安全に行うことができる唯一の機会は、 URI をその部品部分から作成するときです。 各部品は自身の予約されている文字の集合を持っているかもしれませんから、その部品を生成したり解釈したりするのに責を有する機構だけが文字を escape することでその意味が変わるかどうかを決定できます。 同様に、部品中の escape された文字を安全に復号する前には URI を部品群に分離しなければなりません。

In some cases, data that could be represented by an unreserved character may appear escaped; for example, some of the unreserved "mark" characters are automatically escaped by some systems. If the given URI scheme defines a canonicalization algorithm, then unreserved characters may be unescaped according to that algorithm. For example, "%7e" is sometimes used instead of "~" in an http URL path, but the two are equivalent for an http URL.

場合によっては、非予約文字で表現できるデータが escape されて現れることがあります。例えば、幾つかの非予約「マーク」文字を自動的に escape するシステムがあります。 その URI scheme が正規化算法を定義しているのなら、 非予約文字はその算法に従って escape を解いて構いません。 例えば、 %7ehttp URL 経路で時々 ~ の代わりに使われますが、 http URL では2つは同等です。

Because the percent "%" character always has the reserved purpose of being the escape indicator, it must be escaped as "%25" in order to be used as data within a URI. Implementers should be careful not to escape or unescape the same string more than once, since unescaping an already unescaped string might lead to misinterpreting a percent data character as another escaped character, or vice versa in the case of escaping an already escaped string.

百分率 % 文字は escape 指示子として使う目的で常に予約されているので、 URL 中でデータとして使うためには %25 と escape しなければなりません。 実装者は、同じ文字列を複数回 escape したり解いたりしないように注意を払うべきです。 既に escape を解いた文字列を更に escape 解除すると百分率データ文字を他の escape された文字列を誤解したり、逆に既に escape された文字列を escape してしまったりします。

RFC 1738 (URL) 2.2 の一部

No corresponding graphic US-ASCII
URLs are written only with the graphic printable characters of the US-ASCII coded character set. The octets 80-FF hexadecimal are not used in US-ASCII, and the octets 00-1F and 7F hexadecimal represent control characters; these must be encoded.
対応する図形が US‐ASCII にない
URL は US‐ASCII 符号化文字集合の図形印字可能文字のみによって書きます。 オクテット 80FF (16進) は US‐ASCII では使っておらず、 オクテット 007F (16進) は制御文字を表現します。 これらは符号化しなければなりません。

RFC 2396 (URI) 2.4.3. Excluded US-ASCII Characters

Although they are disallowed within the URI syntax, we include here a description of those US-ASCII characters that have been excluded and the reasons for their exclusion.

これらの US‐ASCII 文字は URI 構文では禁止されていますが、 これらの US‐ASCII 文字が除外されていることとその除外の理由を説明するためにここに含めます。

The control characters in the US-ASCII coded character set are not used within a URI, both because they are non-printable and because they are likely to be misinterpreted by some control mechanisms.

US‐ASCII 符号化文字集合の制御文字は URI 中では使いません。これらは非印字可能ですし。 誤解する制御機構もあるでしょうからです。

The space character is excluded because significant spaces may disappear and insignificant spaces may be introduced when URI are transcribed or typeset or subjected to the treatment of word-processing programs. Whitespace is also used to delimit URI in many contexts.

間隔文字は除外されていますが、これは、 URI が転記されたり植字されたり文書処理プログラムの処理対象になったりしたときに意味のある間隔が消滅したり、意味のない間隔が URI に加わったりするかもしれないからです。 空白は多くの場面で URI を区切るためにも使われます。

The angle-bracket "<" and ">" and double-quote (") characters are excluded because they are often used as the delimiters around URI in text documents and protocol fields. The character "#" is excluded because it is used to delimit a URI from a fragment identifier in URI references (Section 4). The percent character "%" is excluded because it is used for the encoding of escaped characters.

角括弧 < 及び > 並びに二重引用符 " は、 文章やプロトコル欄の中においてしばしば URI を囲む区切子として使われるので除外します。 文字 # は URI と素片識別子URI参照中で区切るのに使うので除外します。 百分率文字 % は escape 文字の符号化に使うので除外します。

  • delims = "<" | ">" | "#" | "%" | <">

Other characters are excluded because gateways and other transport agents are known to sometimes modify such characters, or they are used as delimiters.

他の文字は、関門や他の転送エージェントが時々これらの文字を修正したり区切子に使ったりすることが知られているので除外します。

  • unwise = "{" | "}" | "|" | "\" | "^" | "[" | "]" | "`"

Data corresponding to excluded characters must be escaped in order to be properly represented within a URI.

除外文字に対応するデータは、 URI 中で適切に表現するためには escape しなければなりません。

メモ

[81] BNF では escape とか escaped とかと表しています。

[82] なんにせよ、 URI 符号化はシフトJIS とか UTF-8 のような文字符号化とは層が異なることには注意しておいて損はないです。

[83] まあ、 URI 符号化も「文字」符号化には違いないけど... 言葉遊びは勘弁して。

[84] URI エスケープ符号化は SGML/XML文字参照と同じ層に位置すると考えればいいかなぁ。(細かいことをいうと SGML はあくまで文書文字集合中の文字を参照するのに対し、 URI エスケープ符号はオクテットを符号化したものに過ぎないのは重大な差異だけど、この際どうでもいいか。)

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

[32] XSLT 2.0 and XQuery 1.0 Serialization (Second Edition) ( ( 版)) http://www.w3.org/TR/2010/REC-xslt-xquery-serialization-20101214/#uri-escaping

[33] XSLT 2.0 and XQuery 1.0 Serialization (Second Edition) ( ( 版)) http://www.w3.org/TR/2010/REC-xslt-xquery-serialization-20101214/#XHTML_ESCAPE-URI-ATTRIBUTES

[34] Web Applications 1.0 r1835 Don't escape '%' when doing URL resolution. (bug 5802) (credit: hs) ( ( 版)) http://html5.org/tools/web-apps-tracker?from=1834&to=1835

[35] XQuery 1.0 and XPath 2.0 Functions and Operators (Second Edition) ( ( 版)) http://www.w3.org/TR/2010/REC-xpath-functions-20101214/#func-encode-for-uri

[41] Bug 24257 – "Percent-decoding + full-width characters + percent decoding" for domains is missing ( ( 版)) https://www.w3.org/Bugs/Public/show_bug.cgi?id=24257

[42] 309671 – Support %-escaped hostnames per RFC 3986 (3.2.2) / Cannot open IDN from other applications(e.g., from Thunderbird) ( ( 版)) https://bugzilla.mozilla.org/show_bug.cgi?id=309671

[93] XSLT and XQuery Serialization 3.0 ( ( 版)) http://www.w3.org/TR/xslt-xquery-serialization-30/#uri-escaping

[94] XSLT and XQuery Serialization 3.0 ( ( 版)) http://www.w3.org/TR/xslt-xquery-serialization-3/#uri-escaping

[102] draft-montenegro-httpbis-uri-encoding-00 - Deterministic URI Encoding ( ( 版)) https://tools.ietf.org/html/draft-montenegro-httpbis-uri-encoding-00

[68] Encode { and } in username/password/path to fix #16. Also acknowledge… · whatwg/url@c296e2f ( 版) https://github.com/whatwg/url/commit/c296e2f8519a1d6614d664708d368a342682c9a1

[69] Do not encode ` in query. Fixes #17. · whatwg/url@f54c44d ( 版) https://github.com/whatwg/url/commit/f54c44d1f790dd2b8913e955ba6d334c6f14a048

[70] RFC 2718 - Guidelines for new URL Schemes ( 版) https://tools.ietf.org/html/rfc2718#section-2.2.5

Unless there is some compelling reason for a particular scheme to do otherwise, translating character sequences into UTF-8 (RFC 2279) [3] and then subsequently using the %HH encoding for unsafe octets is recommended.

[72] Add a section on rendering URLs with some advice around bidirectional… · whatwg/url@d1152b9 ( 版) https://github.com/whatwg/url/commit/d1152b94a16ae91e1f72d128fd5ef589635f0e7c

[105] Fix #77: always decode "%2e" in a URL's path · whatwg/url@bee5ad8 ( 版) https://github.com/whatwg/url/commit/bee5ad8041adfe6fc676c527bbc3f3cf4562ef67

[106] Drop dependencies on Encoding Standard's decoder concept · whatwg/url@37f9329 ( 版) https://github.com/whatwg/url/commit/37f932928378c0df521034cfd223f4ba603ef476

[107] Use the "get an output encoding" from the Encoding Standard · whatwg/url@a9197f7 ( 版) https://github.com/whatwg/url/commit/a9197f7714e6b125f1f760ca1aa661530261773c

[139] Bug 157153 – Accessing form.action as property URI-encodes spaces but not curly braces ( ()) https://bugs.webkit.org/show_bug.cgi?id=157153

[157] 技術/HTTP/URLエンコードで 0x20(スペース) を "+" にすべきか "%20" にすべきか - Glamenv-Septzen.net () http://www.glamenv-septzen.net/view/1170

[170] PHP: http_build_query - Manual () http://php.net/manual/en/function.http-build-query.php

enc_type

By default, PHP_QUERY_RFC1738.

If enc_type is PHP_QUERY_RFC1738, then encoding is performed per » RFC 1738 and the application/x-www-form-urlencoded media type, which implies that spaces are encoded as plus (+) signs.

If enc_type is PHP_QUERY_RFC3986, then encoding is performed according to » RFC 3986, and spaces will be percent encoded (%20).

[179] Percent encode fragments too (annevk著, ) https://github.com/whatwg/url/commit/373dbedbbf0596f723ce8a195923da98b698aeb0

[180] Stop decoding all %2e's in paths (annevk著, ) https://github.com/whatwg/url/commit/fbff6834a8a03576261f777d0e0afea5c1bc5a09

[181] Percent-decode more stuff? · Issue #87 · whatwg/url () https://github.com/whatwg/url/issues/87

[189] XPath and XQuery Functions and Operators 3.1 () https://www.w3.org/TR/2017/REC-xpath-functions-31-20170321/#func-encode-for-uri

[190] XSLT and XQuery Serialization 3.1 () https://www.w3.org/TR/2017/REC-xslt-xquery-serialization-31-20170321/#uri-escaping

[191] Web Applications 1.0 r6112 clarify how to generate ifragment thingies ( ( 版)) http://html5.org/tools/web-apps-tracker?from=6111&to=6112

[192] Define percent decoding of strings (annevk著, ) https://github.com/whatwg/url/commit/e172261b0946036b485322976f93f50707159ce3

[197] data URLs: revised specification · Issue #234 · whatwg/fetch () https://github.com/whatwg/fetch/issues/234

[198] Define percent decoding of strings by annevk · Pull Request #340 · whatwg/url () https://github.com/whatwg/url/pull/340

[200] IE11 の互換性の変更点 (Windows) () https://msdn.microsoft.com/library/bg182625(v=vs.85).aspx

Internet Explorer 11 では、URL の文字エンコードが変更されています。 具体的には、クエリ文字列と XHR 要求に UTF-8 文字エンコードが使われます。

この変更は、以下を除き、すべての URL に影響します。

アンカー名コンポーネント (フラグメントとも呼ばれます)。

ユーザー名コンポーネントとパスワード コンポーネント。

file:// または ftp:// プロトコル リンク。

[202] Do not use percent decode on strings (annevk著, ) https://github.com/whatwg/html/commit/ce8404fa5d8c2c91725c5262fd69d0d45c227ec8

[203] Do not use percent decode on strings by annevk · Pull Request #3111 · whatwg/html () https://github.com/whatwg/html/pull/3111

[204] Change query state slightly to better deal with non-UTF-8 encodings (annevk著, ) https://github.com/whatwg/url/commit/f0e4390bf882446445e944215524ff3877aac95a

[205] "html" error mode somewhat incompatible with URLs · Issue #139 · whatwg/encoding () https://github.com/whatwg/encoding/issues/139

[206] Change query state slightly to better deal with non-UTF-8 encodings by annevk · Pull Request #386 · whatwg/url () https://github.com/whatwg/url/pull/386

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

[208] Percent-encode ' in queries of URLs with special schemes (achristensen07著, ) https://github.com/whatwg/url/commit/6ef17ebe1220a7e7c0cfff0785017502ee18808b

[209] percent-encode ' in queries of URLs with special schemes · Issue #348 · whatwg/url () https://github.com/whatwg/url/issues/348

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

[211] Change query state slightly to better deal with non-UTF-8 encodings (annevk著, ) https://github.com/whatwg/url/commit/f0e4390bf882446445e944215524ff3877aac95a

[212] Do not use percent decode on strings (annevk著, ) https://github.com/whatwg/html/commit/ce8404fa5d8c2c91725c5262fd69d0d45c227ec8

[213] Do not use percent decode on strings by annevk · Pull Request #3111 · whatwg/html () https://github.com/whatwg/html/pull/3111

[214] module URI (Ruby 2.6.0) () https://docs.ruby-lang.org/ja/latest/class/URI.html

[215] URLに含まれるとGoogle Chromeがクラッシュする文字列 | スラド IT, https://it.srad.jp/story/15/09/19/2352204/