RFC 6570 - URIテンプレート
- ステータス: Proposed Standard
- 発行日: March 2012
- ストリーム: IETF
- エラッタ: エラッタなし
概要 (Abstract)
URIテンプレート (URI Template) は、変数展開を通じて一連の統一資源識別子 (Uniform Resource Identifiers) を記述するためのコンパクトな文字列です。本仕様は、URIテンプレートの構文と、URIテンプレートをURI参照に展開するプロセスを定義し、インターネット上でURIテンプレートを使用するためのガイドラインを提供します。
目次 (Contents)
- 1. Introduction (はじめに)
- 1.1. Overview (概要)
- 1.2. Levels and Expression Types (レベルと式の型)
- 1.3. Design Considerations (設計上の考慮事項)
- 1.4. Limitations (制限事項)
- 1.5. Notational Conventions (表記規則)
- 1.6. Character Encoding and Unicode Normalization (文字エンコーディングとUnicode正規化)
- 2. Syntax (構文)
- 2.1. Literals (リテラル)
- 2.2. Expressions (式)
- 2.3. Variables (変数)
- 2.4. Value Modifiers (値修飾子)
- 2.4.1. Prefix Values (プレフィックス値)
- 2.4.2. Composite Values (複合値)
- 3. Expansion (展開)
- 3.1. Literal Expansion (リテラル展開)
- 3.2. Expression Expansion (式の展開)
- 3.2.1. Variable Expansion (変数展開)
- 3.2.2. Simple String Expansion:
{var}(単純文字列展開) - 3.2.3. Reserved Expansion:
{+var}(予約文字展開) - 3.2.4. Fragment Expansion:
{#var}(フラグメント展開) - 3.2.5. Label Expansion with Dot-Prefix:
{.var}(ドットプレフィックス付きラベル展開) - 3.2.6. Path Segment Expansion:
{/var}(パスセグメント展開) - 3.2.7. Path-Style Parameter Expansion:
{;var}(パス形式パラメータ展開) - 3.2.8. Form-Style Query Expansion:
{?var}(フォーム形式クエリ展開) - 3.2.9. Form-Style Query Continuation:
{&var}(フォーム形式クエリ継続)
- 4. Security Considerations (セキュリティに関する考慮事項)
- 5. Acknowledgments (謝辞)
- 6. References (参考文献)
- 6.1. Normative References (規範的参考文献)
- 6.2. Informative References (参考情報)
付録 (Appendices)
関連リソース
- 公式原文: RFC 6570
- 公式ページ: RFC 6570 DataTracker
- 正誤表: RFC Editor Errata
2. Syntax (構文)
URIテンプレートは、印刷可能なUnicode文字の文字列であり、ゼロ個以上の埋め込まれた変数式 (Variable Expressions) を含み、各式は対応する波括弧 ('{', '}') のペアで区切られます。
URI-Template = *( literals / expression )
テンプレート(およびテンプレートプロセッサ実装)は上記で4つの段階的なレベルで説明されていますが、URIテンプレート構文はLevel 4のABNFで定義します。低レベルのテンプレートに限定されたテンプレートプロセッサは、より高いレベルにのみ適用されるABNF規則を除外してもよい (MAY) です。ただし、すべてのパーサーが完全な構文を実装して、サポートされていないレベルをエンドユーザーに適切に識別できるようにすることが推奨されます (RECOMMENDED)。
2.1. Literals (リテラル)
URIテンプレート文字列の式の外側の文字は、その文字がURIで許可されている場合 (reserved / unreserved / pct-encoded)、URI参照に文字通りコピーされることを意図しています。許可されていない場合は、UTF-8 [RFC3629] でのその文字のエンコーディングに対応するパーセントエンコードされたトリプレットのシーケンスとしてURI参照にコピーされます。
literals = %x21 / %x23-24 / %x26 / %x28-3B / %x3D / %x3F-5B
/ %x5D / %x5F / %x61-7A / %x7E / ucschar / iprivate
/ pct-encoded
; 任意のUnicode文字、ただし次を除く: CTL, SP,
; DQUOTE, "'", "%" (pct-encoded以外),
; "<", ">", "\", "^", "`", "{", "|", "}"
2.2. Expressions (式)
テンプレート式はURIテンプレートのパラメータ化された部分です。各式には、式の型とそれに対応する展開プロセスを定義するオプションの演算子 (Operator) と、それに続くカンマ区切りの変数指定子 (Variable Specifiers) のリスト(変数名とオプションの値修飾子)が含まれます。演算子が提供されていない場合、式はデフォルトで予約されていない値の単純な変数展開になります。
expression = "{" [ operator ] variable-list "}"
operator = op-level2 / op-level3 / op-reserve
op-level2 = "+" / "#"
op-level3 = "." / "/" / ";" / "?" / "&"
op-reserve = "=" / "," / "!" / "@" / "|"
演算子文字は、URI一般構文における予約文字としての役割を反映するように選択されています。本仕様の第3節で定義されている演算子には以下が含まれます:
+予約文字列 (Reserved character strings)#"#" で接頭辞が付けられたフラグメント識別子 (Fragment identifiers)."." で接頭辞が付けられた名前ラベルまたは拡張 (Name labels or extensions)/"/" で接頭辞が付けられたパスセグメント (Path segments);";" で接頭辞が付けられたパスパラメータ名またはname=valueペア (Path parameter name or name=value pairs)?"?" で始まり "&" で区切られたname=valueペアで構成されるクエリコンポーネント (Query component)&リテラルクエリコンポーネント内のクエリ形式 &name=valueペアの継続 (Continuation of query-style pairs)
演算子文字の等号 ("=")、カンマ (",")、感嘆符 ("!")、アットマーク ("@")、およびパイプ ("|") は将来の拡張のために予約されています。
式構文は、ドル記号 ("$") と括弧 ["(" および ")"] 文字の使用を特に除外しているため、本仕様の範囲外で使用できるようになっています。たとえば、マクロ言語は、文字列をURIテンプレートとして処理する前に、これらの文字を使用して文字列にマクロ置換を適用する場合があります。
2.3. Variables (変数)
演算子(存在する場合)の後、各式には1つ以上のカンマ区切りの変数指定子 (varspec) のリストが含まれます。変数名には複数の目的があります:期待される値の種類のドキュメント、テンプレートプロセッサ内で値を関連付けるための識別子、およびname=value展開で名前に使用するリテラル文字列(関連配列を展開する場合を除く)。変数名は大文字と小文字を区別します。これは、名前が大文字と小文字を区別するURIコンポーネント内で展開される可能性があるためです。
variable-list = varspec *( "," varspec )
varspec = varname [ modifier-level4 ]
varname = varchar *( ["."] varchar )
varchar = ALPHA / DIGIT / "_" / pct-encoded
varname には1つ以上のパーセントエンコードされたトリプレットを含めることができます (MAY)。これらのトリプレットは変数名の本質的な部分と見なされ、処理中にデコードされません。パーセントエンコードされた文字を含む varname は、これらの同じ文字がデコードされた varname とは異なる変数です。URIテンプレートを提供するアプリケーションは、変数名内でパーセントエンコードを一貫して使用することが期待されます。
式は、テンプレートプロセッサに不明な変数、または値が特別な "undefined (未定義)" 値(undef や null など)に設定されている変数を参照してもよい (MAY) です。このような未定義の変数は、展開プロセスで特別な扱いを受けます(第3.2.1節)。
長さゼロの文字列の変数値は未定義とは見なされません。空の文字列の定義された値を持ちます。
Level 4テンプレートでは、変数は値のリストまたは (name, value) ペアの連想配列の形式で複合値 (Composite Value) を持つことができます。このような値型はテンプレート構文によって直接示されませんが、展開プロセスに影響を与えます(第3.2.1節)。
リストにゼロメンバーが含まれている場合、リスト値として定義された変数は未定義と見なされます。配列にゼロメンバーが含まれているか、配列内のすべてのメンバー名が未定義の値に関連付けられている場合、(name, value) ペアの連想配列として定義された変数は未定義と見なされます。
2.4. Value Modifiers (値修飾子)
Level 4テンプレート式の各変数には、その展開が変数値文字列の接頭辞に制限されることを示す修飾子、または値のリストまたは (name, value) ペアの連想配列の形式で複合値として展開されることを示す修飾子を持つことができます。
modifier-level4 = prefix / explode
2.4.1. Prefix Values (プレフィックス値)
プレフィックス修飾子 (Prefix Modifier) は、変数展開が変数値文字列のプレフィックスに制限されることを示します。プレフィックス修飾子は、参照インデックスやハッシュベースのストレージで一般的なように、識別子空間を階層的に分割するためによく使用されます。また、展開された値を最大文字数に制限する役割も果たします。プレフィックス修飾子は複合値を持つ変数には適用されません。
prefix = ":" max-length
max-length = %x31-39 0*3DIGIT ; 正の整数 < 10000
max-length は、Unicode文字列としての変数値の先頭からの最大文字数を参照する正の整数です。この番号付けは、マルチオクテットエンコード文字のオクテット間またはパーセントエンコードされたトリプレット内での分割を避けるため、オクテットではなく文字単位であることに注意してください。max-length が変数値の長さよりも大きい場合、値文字列全体が使用されます。
例:
変数割り当て
var := "value"
semi := ";"
テンプレート例 展開
{var} value
{var:20} value
{var:3} val
{semi} %3B
{semi:2} %3B
2.4.2. Composite Values (複合値)
展開修飾子 (Explode Modifier) ("*") は、変数が値のリストまたは (name, value) ペアの連想配列で構成される複合値として扱われることを示します。したがって、展開プロセスは、複合の各メンバーが個別の変数としてリストされているかのように適用されます。この種の変数指定は、変数名と展開後のURI参照の表示方法との対応が少ないため、非展開変数よりも自己文書化の程度が大幅に低くなります。
explode = "*"
URIテンプレートには型やスキーマの指示が含まれていないため、展開された変数の型はコンテキストによって決定されると想定されます。たとえば、プロセッサは、文字列、リスト、または連想配列として値を区別する形式で値を提供される場合があります。同様に、テンプレートが使用されるコンテキスト(スクリプト、マークアップ言語、インターフェース定義言語など)は、変数名を型、構造、またはスキーマに関連付けるルールを定義する場合があります。
展開修飾子はURIテンプレート構文の簡潔性を向上させます。たとえば、特定の住所の地理的マップを提供するリソースは、部分的な住所(市区町村や郵便番号のみなど)を含む、住所入力のフィールドに対する数百の順列を受け入れる場合があります。このようなリソースは、すべての住所コンポーネントを順番にリストしたテンプレートとして記述することも、展開修飾子を使用したはるかにシンプルなテンプレートとして記述することもできます:
/mapper{?address*}
"address" という名前の変数に何を含めることができるかを定義するコンテキストとともに、たとえば住所に関する他の標準(例:[UPU-S42])への参照によって。スキーマを認識している受信者は、次のような適切な展開を提供できます:
/mapper?city=Newport%20Beach&state=CA
展開変数の展開プロセスは、使用されている演算子と、複合値を値のリストとして扱うか、(name, value) ペアの連想配列として扱うかの両方に依存します。構造は、構造定義のフィールドに対応する名前を持つ連想配列として処理され、"." セパレータを使用してサブ構造の名前階層を示します。
変数が複合構造を持ち、その構造のフィールドの一部のみが定義された値を持つ場合、展開には定義されたペアのみが存在します。これは、多数の潜在的なクエリ用語で構成されるテンプレートに役立ちます。
リスト変数に適用される展開修飾子は、各リストメンバーに対して演算子に従って変数の展開を繰り返す展開を引き起こします。
3. Expansion (展開)
URIテンプレート展開のプロセスは、テンプレート文字列を最初から最後までスキャンし、リテラル文字をコピーし、各式を式の演算子を式内で名前が付けられた各変数の値に適用した結果で置き換えることです。各変数の値は、テンプレート展開前に形成されなければなりません (MUST)。
本セクションでは、URIテンプレート文法の各側面に対する展開の要件を定義します。展開プロセス全体の非規範的なアルゴリズムは付録Aで提供されています。
テンプレートプロセッサが式の外側で <URI-Template> 文法に一致しない文字シーケンスに遭遇した場合、テンプレートの処理を停止すべきであり (SHOULD)、URI参照結果はテンプレートの展開された部分の後に未展開の残りを含むべきであり (SHOULD)、エラーの位置とタイプを呼び出し元アプリケーションに示すべきです (SHOULD)。
式内でエラーに遭遇した場合、例えばテンプレートプロセッサが認識しない、またはまだサポートしていない演算子または値修飾子、あるいは <expression> 文法で許可されていない文字が見つかった場合、式の未処理部分は未展開のまま結果にコピーされるべきであり (SHOULD)、テンプレートの残りの処理は続行されるべきであり (SHOULD)、エラーの位置とタイプを呼び出し元アプリケーションに示すべきです (SHOULD)。
エラーが発生した場合、返される結果は有効なURI参照ではない可能性があります。これは診断目的でのみ意図された、不完全に展開されたテンプレート文字列になります。
3.1. Literal Expansion (リテラル展開)
リテラル文字がURI構文のどこでも許可されている場合 (unreserved / reserved / pct-encoded)、それは結果文字列に直接コピーされます。そうでない場合、リテラル文字のパーセントエンコードされた等価物が結果文字列にコピーされます。これは、まず文字をUTF-8でのオクテットシーケンスとしてエンコードし、次に各オクテットをパーセントエンコードされたトリプレットとしてエンコードすることによって行われます。
3.2. Expression Expansion (式展開)
各式は開き中括弧 ("{") 文字で示され、次の閉じ中括弧 ("}") まで続きます。式はネストできません。
式の展開は、その式タイプを決定し、式内の各カンマ区切りのvarspecに対してそのタイプの展開プロセスに従うことによって行われます。Level 1テンプレートは、デフォルト演算子(単純な文字列値展開)と式ごとに単一の変数に制限されています。Level 2テンプレートは、式ごとに単一のvarspecに制限されています。
式タイプは、開き中括弧の後の最初の文字を調べることによって決定されます。文字が演算子である場合、後の展開決定のためにその演算子に関連付けられた式タイプを記憶し、変数リストの次の文字にスキップします。最初の文字が演算子でない場合、式タイプは単純な文字列展開であり、最初の文字は変数リストの始まりです。
以下のサブセクションの例では、次の変数値定義を使用します:
count := ("one", "two", "three")
dom := ("example", "com")
dub := "me/too"
hello := "Hello World!"
half := "50%"
var := "value"
who := "fred"
base := "http://example.com/home/"
path := "/foo/bar"
list := ("red", "green", "blue")
keys := [("semi",";"),("dot","."),("comma",",")]
v := "6"
x := "1024"
y := "768"
empty := ""
empty_keys := []
undef := null
3.2.1. Variable Expansion (変数展開)
未定義 (セクション2.3) の変数は値を持たず、展開プロセスによって無視されます。式内のすべての変数が未定義の場合、式の展開は空文字列になります。
定義された非空の値の変数展開は、許可されたURI文字のサブストリングを生成します。セクション1.6で説明されているように、展開プロセスはUnicodeコードポイントの観点から定義されており、結果のURI参照で非ASCII文字が一貫してパーセントエンコードされることを保証します。テンプレートプロセッサが一貫した展開を得る1つの方法は、値文字列をUTF-8にトランスコードし(まだUTF-8でない場合)、許可されたセット内にない各オクテットを対応するパーセントエンコードされたトリプレットに変換することです。
特定の展開に対する許可されたセットは式タイプに依存します:予約済み ("+") およびフラグメント ("#") 展開は、(unreserved / reserved / pct-encoded) の和集合の文字セットをパーセントエンコードなしで通過させることを許可しますが、他のすべての式タイプは、パーセントエンコードなしで通過できる文字を非予約文字のみに制限します。パーセント文字 ("%") は、パーセントエンコードされたトリプレットの一部としてのみ許可され、予約済み/フラグメント展開の場合のみです:他のすべてのケースでは、値文字 "%" は変数展開によって "%25" としてパーセントエンコードされなければなりません (MUST)。
変数が式内で複数回、またはURIテンプレートの複数の式内で出現する場合、その変数の値は展開プロセス全体を通じて静的のままでなければなりません (MUST)(つまり、各展開を計算する目的で変数は同じ値を持つ必要があります)。ただし、予約文字またはパーセントエンコードされたトリプレットが値に出現する場合、一部の式タイプではパーセントエンコードされ、他の式タイプではパーセントエンコードされません。
単純な文字列値の変数の場合、展開はエンコードされた値を結果文字列に追加することで構成されます。爆発修飾子は効果がありません。プレフィックス修飾子は、展開をデコードされた値の最初のmax-length文字に制限します。値にマルチオクテットまたはパーセントエンコードされた文字が含まれている場合、文字の途中で値を分割しないように注意する必要があります:各Unicodeコードポイントを1文字としてカウントします。
連想配列の変数の場合、展開は式タイプと爆発修飾子の存在の両方に依存します。爆発修飾子がない場合、展開は定義された値を持つ各 (name, value) ペアのカンマ区切りの連結を追加することで構成されます。爆発修飾子がある場合、展開は定義された値を持つ各ペアを "name=value" として、または値が空文字列で式タイプがフォームスタイルパラメータを示さない場合(つまり、"?" または "&" タイプでない場合)、単に "name" として追加することで構成されます。nameとvalue文字列の両方は、単純な文字列値と同じ方法でエンコードされます。定義されたペア間には、次の表で定義されている式タイプに従って、セパレータ文字列が追加されます:
タイプ セパレータ
"," (デフォルト)
+ ","
# ","
. "."
/ "/"
; ";"
? "&"
& "&"
リスト値の変数の場合、爆発修飾子がない場合、展開は定義された値を持つ各リストメンバー値のカンマ区切りの連結をその変数の単一名の値として追加することで構成されます。爆発修飾子がある場合、展開は定義された値を持つ各リストメンバー値をその変数名を持つ個別の値として追加するか、名前付き変数を持たない式タイプ(";"、"?"、または "&" なし)の場合、各値をタイプ固有のセパレータで区切って追加することで構成されます。
リスト値または連想配列値のプレフィックス修飾子は効果がありません。
3.2.2. Simple String Expansion: {var} (単純文字列展開)
演算子が指定されていない場合、単純文字列展開がデフォルトの式タイプです。
変数リスト内の定義された各変数に対して、セクション3.2.1で定義されているように変数展開を実行し、許可される文字は非予約セットの文字です。複数の変数が定義された値を持つ場合、カンマ (",") を変数展開間のセパレータとして結果文字列に追加します。
例テンプレート 展開結果
{var} value
{hello} Hello%20World%21
{half} 50%25
O{empty}X OX
O{undef}X OX
{x,y} 1024,768
{x,hello,y} 1024,Hello%20World%21,768
?{x,empty} ?1024,
?{x,undef} ?1024
?{undef,y} ?768
{var:3} val
{var:30} value
{list} red,green,blue
{list*} red,green,blue
{keys} semi,%3B,dot,.,comma,%2C
{keys*} semi=%3B,dot=.,comma=%2C
3.2.3. Reserved Expansion: {+var} (予約済み展開)
予約済み展開は、Level 2以上のテンプレートのプラス ("+") 演算子で示され、単純文字列展開と同じですが、置換される値にもパーセントエンコードされたトリプレットと予約済みセットの文字が含まれる可能性があります。
変数リスト内の定義された各変数に対して、セクション3.2.1で定義されているように変数展開を実行し、許可される文字は (unreserved / reserved / pct-encoded) セットの文字です。複数の変数が定義された値を持つ場合、カンマ (",") を変数展開間のセパレータとして結果文字列に追加します。
例テンプレート 展開結果
{+var} value
{+hello} Hello%20World!
{+half} 50%25
{base}index http%3A%2F%2Fexample.com%2Fhome%2Findex
{+base}index http://example.com/home/index
O{+empty}X OX
O{+undef}X OX
{+path}/here /foo/bar/here
here?ref={+path} here?ref=/foo/bar
{+x,hello,y} 1024,Hello%20World!,768
{+path,x}/here /foo/bar,1024/here
{+path:6}/here /foo/b,1024/here
{+list} red,green,blue
{+list*} red,green,blue
{+keys} semi,;,dot,.,comma,,
{+keys*} semi=;,dot=.,comma=,
3.2.4. Fragment Expansion: \{#var} (フラグメント展開)
フラグメント展開は、Level 2以上のテンプレートのクロスハッシュ ("#") 演算子で示され、予約済み展開と同じですが、いずれかの変数が定義されている場合、最初にクロスハッシュ文字(フラグメント区切り文字)が結果文字列に追加されます。
例テンプレート 展開結果
{#var} #value
{#hello} #Hello%20World!
{#half} #50%25
foo{#empty} foo#
foo{#undef} foo
{#x,hello,y} #1024,Hello%20World!,768
{#path,x}/here #/foo/bar,1024/here
{#path:6}/here #/foo/b/here
{#list} #red,green,blue
{#list*} #red,green,blue
{#keys} #semi,;,dot,.,comma,,
{#keys*} #semi=;,dot=.,comma=,
3.2.5. Label Expansion with Dot-Prefix: {.var} (ドット接頭辞付きラベル展開)
ラベル展開は、Level 3以上のテンプレートのドット (".") 演算子で示され、異なるドメイン名またはパスセレクター(例:ファイル拡張子)を持つURIスペースを記述するのに役立ちます。
変数リスト内の定義された各変数に対して、"." を結果文字列に追加し、次にセクション3.2.1で定義されているように変数展開を実行し、許可される文字は非予約セットの文字です。
"." は非予約セットに含まれているため、"." を含む値は複数のラベルを追加する効果があります。
例テンプレート 展開結果
{.who} .fred
{.who,who} .fred.fred
{.half,who} .50%25.fred
www{.dom*} www.example.com
X{.var} X.value
X{.empty} X.
X{.undef} X
X{.var:3} X.val
X{.list} X.red,green,blue
X{.list*} X.red.green.blue
X{.keys} X.semi,%3B,dot,.,comma,%2C
X{.keys*} X.semi=%3B.dot=..comma=%2C
X{.empty_keys} X
X{.empty_keys*} X
3.2.6. Path Segment Expansion: {/var} (パスセグメント展開)
パスセグメント展開は、Level 3以上のテンプレートのスラッシュ ("/") 演算子で示され、URIパス階層を記述するのに役立ちます。
変数リスト内の定義された各変数に対して、"/" を結果文字列に追加し、次にセクション3.2.1で定義されているように変数展開を実行し、許可される文字は非予約セットの文字です。
パスセグメント展開の展開プロセスは、"." の代わりに "/" を置換することを除いて、ラベル展開と同じです。ただし、"." とは異なり、"/" は予約文字であり、値に見つかった場合はパーセントエンコードされます。
例テンプレート 展開結果
{/who} /fred
{/who,who} /fred/fred
{/half,who} /50%25/fred
{/who,dub} /fred/me%2Ftoo
{/var} /value
{/var,empty} /value/
{/var,undef} /value
{/var,x}/here /value/1024/here
{/var:1,var} /v/value
{/list} /red,green,blue
{/list*} /red/green/blue
{/list*,path:4} /red/green/blue/%2Ffoo
{/keys} /semi,%3B,dot,.,comma,%2C
{/keys*} /semi=%3B/dot=./comma=%2C
3.2.7. Path-Style Parameter Expansion: {;var} (パススタイルパラメータ展開)
パススタイルパラメータ展開は、Level 3以上のテンプレートのセミコロン (";") 演算子で示され、"path;property" や "path;name=value" などのURIパスパラメータを記述するのに役立ちます。
変数リスト内の定義された各変数に対して:
- ";" を結果文字列に追加します;
- 変数が単純な文字列値を持つか、爆発修飾子が指定されていない場合:
- 変数名(リテラル文字列としてエンコード)を結果文字列に追加します;
- 変数の値が空でない場合、"=" を結果文字列に追加します;
- セクション3.2.1で定義されているように変数展開を実行し、許可される文字は非予約セットの文字です。
例テンプレート 展開結果
{;who} ;who=fred
{;half} ;half=50%25
{;empty} ;empty
{;v,empty,who} ;v=6;empty;who=fred
{;v,bar,who} ;v=6;who=fred
{;x,y} ;x=1024;y=768
{;x,y,empty} ;x=1024;y=768;empty
{;x,y,undef} ;x=1024;y=768
{;hello:5} ;hello=Hello
{;list} ;list=red,green,blue
{;list*} ;list=red;list=green;list=blue
{;keys} ;keys=semi,%3B,dot,.,comma,%2C
{;keys*} ;semi=%3B;dot=.;comma=%2C
3.2.8. Form-Style Query Expansion: {?var} (フォームスタイルクエリ展開)
フォームスタイルクエリ展開は、Level 3以上のテンプレートのクエスチョンマーク ("?") 演算子で示され、全体のオプションのクエリコンポーネントを記述するのに役立ちます。
変数リスト内の定義された各変数に対して:
- これが最初の定義された値である場合は "?" を結果文字列に追加し、それ以降は "&" を追加します;
- 変数が単純な文字列値を持つか、爆発修飾子が指定されていない場合、変数名(リテラル文字列としてエンコード)と等号文字 ("=") を結果文字列に追加します;そして、
- セクション3.2.1で定義されているように変数展開を実行し、許可される文字は非予約セットの文字です。
例テンプレート 展開結果
{?who} ?who=fred
{?half} ?half=50%25
{?x,y} ?x=1024&y=768
{?x,y,empty} ?x=1024&y=768&empty=
{?x,y,undef} ?x=1024&y=768
{?var:3} ?var=val
{?list} ?list=red,green,blue
{?list*} ?list=red&list=green&list=blue
{?keys} ?keys=semi,%3B,dot,.,comma,%2C
{?keys*} ?semi=%3B&dot=.&comma=%2C
3.2.9. Form-Style Query Continuation: {&var} (フォームスタイルクエリ継続)
フォームスタイルクエリ継続は、Level 3以上のテンプレートのアンパサンド ("&") 演算子で示され、固定パラメータを持つリテラルクエリコンポーネントを既に含むテンプレート内でオプションの &name=value ペアを記述するのに役立ちます。
変数リスト内の定義された各変数に対して:
- "&" を結果文字列に追加します;
- 変数が単純な文字列値を持つか、爆発修飾子が指定されていない場合、変数名(リテラル文字列としてエンコード)と等号文字 ("=") を結果文字列に追加します;そして、
- セクション3.2.1で定義されているように変数展開を実行し、許可される文字は非予約セットの文字です。
例テンプレート 展開結果
{&who} &who=fred
{&half} &half=50%25
?fixed=yes{&x} ?fixed=yes&x=1024
{&x,y,empty} &x=1024&y=768&empty=
{&x,y,undef} &x=1024&y=768
{&var:3} &var=val
{&list} &list=red,green,blue
{&list*} &list=red&list=green&list=blue
{&keys} &keys=semi,%3B,dot,.,comma,%2C
{&keys*} &semi=%3B&dot=.&comma=%2C
4. Security Considerations (セキュリティ考慮事項)
URIテンプレートには、アクティブまたは実行可能なコンテンツは含まれていません。ただし、攻撃者がテンプレートを制御した場合、または展開で予約文字を許可する式内の変数値を制御した場合、予期しないURIを作成する可能性があります。いずれの場合でも、セキュリティ上の考慮事項は、主に次の要因によって決まります:誰がテンプレートを提供するか、誰がテンプレート内の変数の値を提供するか、展開がどの実行コンテキスト(クライアントまたはサーバー)で発生するか、および結果のURIがどこで使用されるか。
この仕様は、URIテンプレートが使用される場所を制限しません。現在の実装は、サーバー側開発フレームワーク内および計算されたリンクまたはフォーム用のクライアント側JavaScriptに存在します。
フレームワーク内では、テンプレートは通常、クライアント要求内の後の(リクエスト時の)URIでデータが発生する可能性のある場所のガイドとして機能します。したがって、セキュリティ上の懸念はテンプレート自体にあるのではなく、サーバーが通常のWeb要求内でユーザー提供データを抽出および処理する方法にあります。
クライアント側の実装内では、URIテンプレートはHTMLフォームと同じプロパティの多くを持っていますが、URI文字に制限され、メッセージ本文コンテンツだけでなくHTTPヘッダーフィールド値に含まれる可能性があります。テンプレートと値の両方が信頼できるソースによって提供されない限り、"javascript:"で始まる文字列など、潜在的に危険なURI参照文字列が展開に現れないように注意する必要があります。
その他のセキュリティ上の考慮事項は、[RFC3986]のセクション7で説明されているURIの考慮事項と同じです。
Appendix A. Implementation Hints (実装のヒント)
展開に関する規範的なセクションでは、記述の明確性のために、各演算子に個別の展開プロセスを記述しています。実際の実装では、式は各演算子ごとにプロセスにわずかな変更のみがある共通のアルゴリズムを使用して左から右に処理されることが期待されます。この非規範的な付録では、そのようなアルゴリズムの1つを説明します。
空の結果文字列とその非エラー状態を初期化します。
テンプレートをスキャンし、"{"で示される式、"{"以外の非リテラル文字の存在で示されるエラー、またはテンプレートの終わりまで、リテラルを結果文字列にコピーします(セクション3.1のように)。終わったら、結果文字列とその現在のエラーまたは非エラー状態を返します。
- 式が見つかった場合、テンプレートを次の
"}"までスキャンし、中括弧の間の文字を抽出します。 - テンプレートが
"}"の前に終了した場合、"{"と抽出された文字を結果文字列に追加し、式が不正であることを示すエラー状態で返します。
演算子を探すために、抽出された式の最初の文字を調べます。
- 式が終了した場合(つまり、"{}")、未知または未実装の演算子が見つかった場合、または文字がvarcharセット(セクション2.3)にない場合、"{"、抽出された式、および"}"を結果文字列に追加し、結果がエラー状態にあることを記憶し、テンプレートの残りをスキャンに戻ります。
- 既知で実装された演算子が見つかった場合、演算子を格納し、varspecリストを開始するために次の文字にスキップします。
- それ以外の場合、演算子をNUL(単純な文字列展開)として格納します。
次の値テーブルを使用して、式タイプ演算子ごとの処理動作を決定します。"first"エントリは、式の変数のいずれかが定義されている場合に最初に結果に追加する文字列です。"sep"エントリは、2番目(またはそれ以降)の定義された変数展開の前に結果に追加するセパレータです。"named"エントリは、explode修飾子が指定されていない場合に展開に変数またはキー名を含めるかどうかのブール値です。"ifemp"エントリは、対応する値が空の場合に名前に追加する文字列です。"allow"エントリは、値展開内でエンコードされずに許可される文字を示します:(U) は、unreservedセットにない任意の文字がエンコードされることを意味します;(U+R) は、(unreserved / reserved / pct-encoding) の和集合にない任意の文字がエンコードされることを意味します;両方のケースで、各許可されない文字は、最初にUTF-8でのオクテットシーケンスとしてエンコードされ、次に各オクテットがパーセントエンコードされたトリプレットとしてエンコードされます。
┌──────────────────────────────────────────────────────────────┐
│ NUL + . / ; ? & #│
├──────────────────────────────────────────────────────────────┤
│ first │ "" "" "." "/" ";" "?" "&" "#"│
│ sep │ "," "," "." "/" ";" "&" "&" "," │
│ named │ false false false false true true true false│
│ ifemp │ "" "" "" "" "" "=" "=" "" │
│ allow │ U U+R U U U U U U+R │
└──────────────────────────────────────────────────────────────┘
上記のテーブルを念頭に置いて、次のように変数リストを処理します:
各varspecについて、varnameセットにない文字が見つかるか式の終わりに達するまで変数リストをスキャンして、式から変数名とオプションの修飾子を抽出します。
- 式の終わりでvarnameが空の場合、テンプレートの残りのスキャンに戻ります。
- 式の終わりでなく、見つかった最後の文字が修飾子(""または":")を示している場合、その修飾子を記憶します。explode("")の場合、次の文字をスキャンします。prefix(":")の場合、10進整数として表されるmax-lengthの次の1〜4文字をスキャンし続け、それでも式の終わりでない場合は次の文字をスキャンします。
- 式の終わりでなく、見つかった最後の文字がカンマ(",")でない場合、"{"、格納された演算子(ある場合)、スキャンされたvarnameと修飾子、残りの式、および"}"を結果文字列に追加し、結果がエラー状態にあることを記憶し、テンプレートの残りのスキャンに戻ります。
スキャンされた変数名の値を検索し、次に
- varnameが不明であるか、未定義の値を持つ変数に対応している場合(セクション2.3)、次のvarspecにスキップします。
- これがこの式の最初の定義された変数である場合、この式タイプのfirst文字列を結果文字列に追加し、それが完了したことを記憶します。それ以外の場合、sep文字列を結果文字列に追加します。
- この変数の値が文字列の場合、
- namedがtrueの場合、リテラルと同じエンコードプロセスを使用してvarnameを結果文字列に追加し、
- 値が空の場合、ifemp文字列を結果文字列に追加し、次のvarspecにスキップします;
- それ以外の場合、"="を結果文字列に追加します。
- prefix修飾子が存在し、プレフィックス長がUnicode文字数での値文字列長より小さい場合、allowセットにない文字をパーセントエンコードした後、値文字列の先頭からその数の文字を結果文字列に追加します。単一のUnicodeコードポイントを表すマルチオクテットまたはパーセントエンコードされたトリプレット文字を分割しないように注意してください;
- それ以外の場合、allowセットにない文字をパーセントエンコードした後、値を結果文字列に追加します。
- namedがtrueの場合、リテラルと同じエンコードプロセスを使用してvarnameを結果文字列に追加し、
- それ以外で、explode修飾子が指定されていない場合、
- namedがtrueの場合、リテラルと同じエンコードプロセスを使用してvarnameを結果文字列に追加し、
- 値が空の場合、ifemp文字列を結果文字列に追加し、次のvarspecにスキップします;
- それ以外の場合、"="を結果文字列に追加します;そして
- この変数の値がリストの場合、allowセットにない文字をパーセントエンコードした後、各定義されたリストメンバーを結果文字列に追加し、各定義されたリストメンバーの間にカンマ(",")を結果に追加します;
- この変数の値が連想配列またはその他の形式のペア(name, value)構造の場合、allowセットにない文字をパーセントエンコードした後、定義された値を持つ各ペアを"name,value"として結果文字列に追加し、各定義されたペアの間にカンマ(",")を結果に追加します。
- namedがtrueの場合、リテラルと同じエンコードプロセスを使用してvarnameを結果文字列に追加し、
- それ以外で、explode修飾子が指定されている場合、
- namedがtrueの場合、定義された値を持つ各定義されたリストメンバーまたは配列(name, value)ペアに対して:
- これが最初の定義されたメンバー/値でない場合、sep文字列を結果文字列に追加します;
- これがリストの場合、リテラルと同じエンコードプロセスを使用してvarnameを結果文字列に追加します;
- これがペアの場合、リテラルと同じエンコードプロセスを使用してnameを結果文字列に追加します;
- メンバー/値が空の場合、ifemp文字列を結果文字列に追加します;それ以外の場合、allowセットにないメンバー/値文字をパーセントエンコードした後、"="とメンバー/値を結果文字列に追加します。
- それ以外で、namedがfalseの場合、
- これがリストの場合、allowセットにない文字をパーセントエンコードした後、各定義されたリストメンバーを結果文字列に追加し、各定義されたリストメンバーの間にsep文字列を結果に追加します。
- これが(name, value)ペアの配列の場合、allowセットにない文字をパーセントエンコードした後、定義された値を持つ各ペアを"name=value"として結果文字列に追加し、各定義されたペアの間にsep文字列を結果に追加します。
- namedがtrueの場合、定義された値を持つ各定義されたリストメンバーまたは配列(name, value)ペアに対して:
この式の変数リストが使い果たされたら、テンプレートの残りのスキャンに戻ります。