From 64eebd32db143499fe73679f21419222ba37ca7c Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Mon, 14 May 2012 18:11:12 +0200 Subject: [PATCH] Updated URI Template to follow official RFC6570 --- library/protocol/uri_template/README.md | 4 + library/protocol/uri_template/doc/REAMDE.txt | 5 +- library/protocol/uri_template/doc/rfc6570.txt | 1907 +++++++++++++++++ .../uri_template/doc/uritemplate-RFC6570 | 1907 +++++++++++++++++ .../doc/uritemplate-draft-gregorio-trunk.xml | 1259 ----------- .../src/draft_05/uri_template_constants.e | 52 - .../protocol/uri_template/src/uri_template.e | 11 +- .../uri_template/src/uri_template_constants.e | 10 +- .../src/uri_template_expression.e | 17 +- .../src/uri_template_expression_variable.e | 43 +- .../src/uri_template_match_result.e | 30 +- .../uri_template/tests/test_uri_template.e | 952 ++++---- ...e_draft_05.e => test_uri_template_draft.e} | 355 +-- .../tests/test_uri_template_matcher.e | 142 ++ .../tests/test_uri_template_parser.e | 87 + .../uri_template/tests/tests-safe.ecf | 28 +- .../uri_template/uri_template-safe.ecf | 17 +- .../protocol/uri_template/uri_template.ecf | 17 +- 18 files changed, 4631 insertions(+), 2212 deletions(-) create mode 100644 library/protocol/uri_template/doc/rfc6570.txt create mode 100644 library/protocol/uri_template/doc/uritemplate-RFC6570 delete mode 100644 library/protocol/uri_template/doc/uritemplate-draft-gregorio-trunk.xml delete mode 100644 library/protocol/uri_template/src/draft_05/uri_template_constants.e rename library/protocol/uri_template/tests/{draft_50/test_uri_template_draft_05.e => test_uri_template_draft.e} (58%) create mode 100644 library/protocol/uri_template/tests/test_uri_template_matcher.e create mode 100644 library/protocol/uri_template/tests/test_uri_template_parser.e diff --git a/library/protocol/uri_template/README.md b/library/protocol/uri_template/README.md index 9cbb2e26..6c9aa840 100644 --- a/library/protocol/uri_template/README.md +++ b/library/protocol/uri_template/README.md @@ -1,6 +1,10 @@ # URI Template ## Overview +Implement URI Template as described at http://tools.ietf.org/rfc/rfc6570.txt + +Support for URI template string expansion +But also partial URI Template matching ## Usage diff --git a/library/protocol/uri_template/doc/REAMDE.txt b/library/protocol/uri_template/doc/REAMDE.txt index fb6cbc62..3bd59c1d 100644 --- a/library/protocol/uri_template/doc/REAMDE.txt +++ b/library/protocol/uri_template/doc/REAMDE.txt @@ -1,4 +1,5 @@ -Most recent spec/draft/in-progress http://code.google.com/p/uri-templates/source/browse/trunk/spec/draft-gregorio-uritemplate.xml +Most recent http://code.google.com/p/uri-templates/source/browse/trunk -svn cat http://uri-templates.googlecode.com/svn/trunk/spec/draft-gregorio-uritemplate.xml > uritemplate-draft-gregorio-trunk.xml +wget http://tools.ietf.org/rfc/rfc6570.txt -O uritemplate-RFC6570 +# Check http://code.google.com/p/uri-templates/source/browse/trunk for work in progress diff --git a/library/protocol/uri_template/doc/rfc6570.txt b/library/protocol/uri_template/doc/rfc6570.txt new file mode 100644 index 00000000..12d5c0f9 --- /dev/null +++ b/library/protocol/uri_template/doc/rfc6570.txt @@ -0,0 +1,1907 @@ + + + + + + +Internet Engineering Task Force (IETF) J. Gregorio +Request for Comments: 6570 Google +Category: Standards Track R. Fielding +ISSN: 2070-1721 Adobe + M. Hadley + MITRE + M. Nottingham + Rackspace + D. Orchard + Salesforce.com + March 2012 + + + URI Template + +Abstract + + A URI Template is a compact sequence of characters for describing a + range of Uniform Resource Identifiers through variable expansion. + This specification defines the URI Template syntax and the process + for expanding a URI Template into a URI reference, along with + guidelines for the use of URI Templates on the Internet. + +Status of This Memo + + This is an Internet Standards Track document. + + This document is a product of the Internet Engineering Task Force + (IETF). It represents the consensus of the IETF community. It has + received public review and has been approved for publication by the + Internet Engineering Steering Group (IESG). Further information on + Internet Standards is available in Section 2 of RFC 5741. + + Information about the current status of this document, any errata, + and how to provide feedback on it may be obtained at + http://www.rfc-editor.org/info/rfc6570. + +Copyright Notice + + Copyright (c) 2012 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + + + +Gregorio, et al. Standards Track [Page 1] + +RFC 6570 URI Template March 2012 + + + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + +Table of Contents + + 1. Introduction ....................................................3 + 1.1. Overview ...................................................3 + 1.2. Levels and Expression Types ................................5 + 1.3. Design Considerations ......................................9 + 1.4. Limitations ...............................................10 + 1.5. Notational Conventions ....................................11 + 1.6. Character Encoding and Unicode Normalization ..............12 + 2. Syntax .........................................................13 + 2.1. Literals ..................................................13 + 2.2. Expressions ...............................................13 + 2.3. Variables .................................................14 + 2.4. Value Modifiers ...........................................15 + 2.4.1. Prefix Values ......................................15 + 2.4.2. Composite Values ...................................16 + 3. Expansion ......................................................18 + 3.1. Literal Expansion .........................................18 + 3.2. Expression Expansion ......................................18 + 3.2.1. Variable Expansion .................................19 + 3.2.2. Simple String Expansion: {var} .....................21 + 3.2.3. Reserved Expansion: {+var} .........................22 + 3.2.4. Fragment Expansion: {#var} .........................23 + 3.2.5. Label Expansion with Dot-Prefix: {.var} ............24 + 3.2.6. Path Segment Expansion: {/var} .....................24 + 3.2.7. Path-Style Parameter Expansion: {;var} .............25 + 3.2.8. Form-Style Query Expansion: {?var} .................26 + 3.2.9. Form-Style Query Continuation: {&var} ..............27 + 4. Security Considerations ........................................27 + 5. Acknowledgments ................................................28 + 6. References .....................................................28 + 6.1. Normative References ......................................28 + 6.2. Informative References ....................................29 + Appendix A. Implementation Hints ..................................30 + + + + + + + + + + + + + +Gregorio, et al. Standards Track [Page 2] + +RFC 6570 URI Template March 2012 + + +1. Introduction + +1.1. Overview + + A Uniform Resource Identifier (URI) [RFC3986] is often used to + identify a specific resource within a common space of similar + resources (informally, a "URI space"). For example, personal web + spaces are often delegated using a common pattern, such as + + http://example.com/~fred/ + http://example.com/~mark/ + + or a set of dictionary entries might be grouped in a hierarchy by the + first letter of the term, as in + + http://example.com/dictionary/c/cat + http://example.com/dictionary/d/dog + + or a service interface might be invoked with various user input in a + common pattern, as in + + http://example.com/search?q=cat&lang=en + http://example.com/search?q=chien&lang=fr + + A URI Template is a compact sequence of characters for describing a + range of Uniform Resource Identifiers through variable expansion. + + URI Templates provide a mechanism for abstracting a space of resource + identifiers such that the variable parts can be easily identified and + described. URI Templates can have many uses, including the discovery + of available services, configuring resource mappings, defining + computed links, specifying interfaces, and other forms of + programmatic interaction with resources. For example, the above + resources could be described by the following URI Templates: + + http://example.com/~{username}/ + http://example.com/dictionary/{term:1}/{term} + http://example.com/search{?q,lang} + + We define the following terms: + + expression: The text between '{' and '}', including the enclosing + braces, as defined in Section 2. + + expansion: The string result obtained from a template expression + after processing it according to its expression type, list of + variable names, and value modifiers, as defined in Section 3. + + + + +Gregorio, et al. Standards Track [Page 3] + +RFC 6570 URI Template March 2012 + + + template processor: A program or library that, given a URI Template + and a set of variables with values, transforms the template string + into a URI reference by parsing the template for expressions and + substituting each one with its corresponding expansion. + + A URI Template provides both a structural description of a URI space + and, when variable values are provided, machine-readable instructions + on how to construct a URI corresponding to those values. A URI + Template is transformed into a URI reference by replacing each + delimited expression with its value as defined by the expression type + and the values of variables named within the expression. The + expression types range from simple string expansion to multiple + name=value lists. The expansions are based on the URI generic + syntax, allowing an implementation to process any URI Template + without knowing the scheme-specific requirements of every possible + resulting URI. + + For example, the following URI Template includes a form-style + parameter expression, as indicated by the "?" operator appearing + before the variable names. + + http://www.example.com/foo{?query,number} + + The expansion process for expressions beginning with the question- + mark ("?") operator follows the same pattern as form-style interfaces + on the World Wide Web: + + http://www.example.com/foo{?query,number} + \_____________/ + | + | + For each defined variable in [ 'query', 'number' ], + substitute "?" if it is the first substitution or "&" + thereafter, followed by the variable name, '=', and the + variable's value. + + If the variables have the values + + query := "mycelium" + number := 100 + + then the expansion of the above URI Template is + + http://www.example.com/foo?query=mycelium&number=100 + + Alternatively, if 'query' is undefined, then the expansion would be + + http://www.example.com/foo?number=100 + + + +Gregorio, et al. Standards Track [Page 4] + +RFC 6570 URI Template March 2012 + + + or if both variables are undefined, then it would be + + http://www.example.com/foo + + A URI Template may be provided in absolute form, as in the examples + above, or in relative form. A template is expanded before the + resulting reference is resolved from relative to absolute form. + + Although the URI syntax is used for the result, the template string + is allowed to contain the broader set of characters that can be found + in Internationalized Resource Identifier (IRI) references [RFC3987]. + Therefore, a URI Template is also an IRI template, and the result of + template processing can be transformed to an IRI by following the + process defined in Section 3.2 of [RFC3987]. + +1.2. Levels and Expression Types + + URI Templates are similar to a macro language with a fixed set of + macro definitions: the expression type determines the expansion + process. The default expression type is simple string expansion, + wherein a single named variable is replaced by its value as a string + after pct-encoding any characters not in the set of unreserved URI + characters (Section 1.5). + + Since most template processors implemented prior to this + specification have only implemented the default expression type, we + refer to these as Level 1 templates. + + .-----------------------------------------------------------------. + | Level 1 examples, with variables having values of | + | | + | var := "value" | + | hello := "Hello World!" | + | | + |-----------------------------------------------------------------| + | Op Expression Expansion | + |-----------------------------------------------------------------| + | | Simple string expansion (Sec 3.2.2) | + | | | + | | {var} value | + | | {hello} Hello%20World%21 | + `-----------------------------------------------------------------' + + Level 2 templates add the plus ("+") operator, for expansion of + values that are allowed to include reserved URI characters + (Section 1.5), and the crosshatch ("#") operator for expansion of + fragment identifiers. + + + + +Gregorio, et al. Standards Track [Page 5] + +RFC 6570 URI Template March 2012 + + + .-----------------------------------------------------------------. + | Level 2 examples, with variables having values of | + | | + | var := "value" | + | hello := "Hello World!" | + | path := "/foo/bar" | + | | + |-----------------------------------------------------------------| + | Op Expression Expansion | + |-----------------------------------------------------------------| + | + | Reserved string expansion (Sec 3.2.3) | + | | | + | | {+var} value | + | | {+hello} Hello%20World! | + | | {+path}/here /foo/bar/here | + | | here?ref={+path} here?ref=/foo/bar | + |-----+-----------------------------------------------------------| + | # | Fragment expansion, crosshatch-prefixed (Sec 3.2.4) | + | | | + | | X{#var} X#value | + | | X{#hello} X#Hello%20World! | + `-----------------------------------------------------------------' + + Level 3 templates allow multiple variables per expression, each + separated by a comma, and add more complex operators for dot-prefixed + labels, slash-prefixed path segments, semicolon-prefixed path + parameters, and the form-style construction of a query syntax + consisting of name=value pairs that are separated by an ampersand + character. + + .-----------------------------------------------------------------. + | Level 3 examples, with variables having values of | + | | + | var := "value" | + | hello := "Hello World!" | + | empty := "" | + | path := "/foo/bar" | + | x := "1024" | + | y := "768" | + | | + |-----------------------------------------------------------------| + | Op Expression Expansion | + |-----------------------------------------------------------------| + | | String expansion with multiple variables (Sec 3.2.2) | + | | | + | | map?{x,y} map?1024,768 | + | | {x,hello,y} 1024,Hello%20World%21,768 | + | | | + + + +Gregorio, et al. Standards Track [Page 6] + +RFC 6570 URI Template March 2012 + + + |-----+-----------------------------------------------------------| + | + | Reserved expansion with multiple variables (Sec 3.2.3) | + | | | + | | {+x,hello,y} 1024,Hello%20World!,768 | + | | {+path,x}/here /foo/bar,1024/here | + | | | + |-----+-----------------------------------------------------------| + | # | Fragment expansion with multiple variables (Sec 3.2.4) | + | | | + | | {#x,hello,y} #1024,Hello%20World!,768 | + | | {#path,x}/here #/foo/bar,1024/here | + | | | + |-----+-----------------------------------------------------------| + | . | Label expansion, dot-prefixed (Sec 3.2.5) | + | | | + | | X{.var} X.value | + | | X{.x,y} X.1024.768 | + | | | + |-----+-----------------------------------------------------------| + | / | Path segments, slash-prefixed (Sec 3.2.6) | + | | | + | | {/var} /value | + | | {/var,x}/here /value/1024/here | + | | | + |-----+-----------------------------------------------------------| + | ; | Path-style parameters, semicolon-prefixed (Sec 3.2.7) | + | | | + | | {;x,y} ;x=1024;y=768 | + | | {;x,y,empty} ;x=1024;y=768;empty | + | | | + |-----+-----------------------------------------------------------| + | ? | Form-style query, ampersand-separated (Sec 3.2.8) | + | | | + | | {?x,y} ?x=1024&y=768 | + | | {?x,y,empty} ?x=1024&y=768&empty= | + | | | + |-----+-----------------------------------------------------------| + | & | Form-style query continuation (Sec 3.2.9) | + | | | + | | ?fixed=yes{&x} ?fixed=yes&x=1024 | + | | {&x,y,empty} &x=1024&y=768&empty= | + | | | + `-----------------------------------------------------------------' + + Finally, Level 4 templates add value modifiers as an optional suffix + to each variable name. A prefix modifier (":") indicates that only a + limited number of characters from the beginning of the value are used + by the expansion (Section 2.4.1). An explode ("*") modifier + + + +Gregorio, et al. Standards Track [Page 7] + +RFC 6570 URI Template March 2012 + + + indicates that the variable is to be treated as a composite value, + consisting of either a list of names or an associative array of + (name, value) pairs, that is expanded as if each member were a + separate variable (Section 2.4.2). + + .-----------------------------------------------------------------. + | Level 4 examples, with variables having values of | + | | + | var := "value" | + | hello := "Hello World!" | + | path := "/foo/bar" | + | list := ("red", "green", "blue") | + | keys := [("semi",";"),("dot","."),("comma",",")] | + | | + | Op Expression Expansion | + |-----------------------------------------------------------------| + | | String expansion with value modifiers (Sec 3.2.2) | + | | | + | | {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 | + | | | + |-----+-----------------------------------------------------------| + | + | Reserved expansion with value modifiers (Sec 3.2.3) | + | | | + | | {+path:6}/here /foo/b/here | + | | {+list} red,green,blue | + | | {+list*} red,green,blue | + | | {+keys} semi,;,dot,.,comma,, | + | | {+keys*} semi=;,dot=.,comma=, | + | | | + |-----+-----------------------------------------------------------| + | # | Fragment expansion with value modifiers (Sec 3.2.4) | + | | | + | | {#path:6}/here #/foo/b/here | + | | {#list} #red,green,blue | + | | {#list*} #red,green,blue | + | | {#keys} #semi,;,dot,.,comma,, | + | | {#keys*} #semi=;,dot=.,comma=, | + | | | + |-----+-----------------------------------------------------------| + | . | Label expansion, dot-prefixed (Sec 3.2.5) | + | | | + | | X{.var:3} X.val | + | | X{.list} X.red,green,blue | + + + +Gregorio, et al. Standards Track [Page 8] + +RFC 6570 URI Template March 2012 + + + | | X{.list*} X.red.green.blue | + | | X{.keys} X.semi,%3B,dot,.,comma,%2C | + | | X{.keys*} X.semi=%3B.dot=..comma=%2C | + | | | + |-----+-----------------------------------------------------------| + | / | Path segments, slash-prefixed (Sec 3.2.6) | + | | | + | | {/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 | + | | | + |-----+-----------------------------------------------------------| + | ; | Path-style parameters, semicolon-prefixed (Sec 3.2.7) | + | | | + | | {;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 | + | | | + |-----+-----------------------------------------------------------| + | ? | Form-style query, ampersand-separated (Sec 3.2.8) | + | | | + | | {?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 | + | | | + |-----+-----------------------------------------------------------| + | & | Form-style query continuation (Sec 3.2.9) | + | | | + | | {&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 | + | | | + `-----------------------------------------------------------------' + +1.3. Design Considerations + + Mechanisms similar to URI Templates have been defined within several + specifications, including WSDL [WSDL], WADL [WADL], and OpenSearch + [OpenSearch]. This specification extends and formally defines the + + + +Gregorio, et al. Standards Track [Page 9] + +RFC 6570 URI Template March 2012 + + + syntax so that URI Templates can be used consistently across multiple + Internet applications and within Internet message fields, while at + the same time retaining compatibility with those earlier definitions. + + The URI Template syntax has been designed to carefully balance the + need for a powerful expansion mechanism with the need for ease of + implementation. The syntax is designed to be trivial to parse while + at the same time providing enough flexibility to express many common + template scenarios. Implementations are able to parse the template + and perform the expansions in a single pass. + + Templates are simple and readable when used with common examples + because the single-character operators match the URI generic syntax + delimiters. The operator's associated delimiter (".", ";", "/", "?", + "&", and "#") is omitted when none of the listed variables are + defined. Likewise, the expansion process for ";" (path-style + parameters) will omit the "=" when the variable value is empty, + whereas the process for "?" (form-style parameters) will not omit the + "=" when the value is empty. Multiple variables and list values have + their values joined with "," if there is no predefined joining + mechanism for the operator. The "+" and "#" operators will + substitute unencoded reserved characters found inside the variable + values; the other operators will pct-encode reserved characters found + in the variable values prior to expansion. + + The most common cases for URI spaces can be described with Level 1 + template expressions. If we were only concerned with URI generation, + then the template syntax could be limited to just simple variable + expansion, since more complex forms could be generated by changing + the variable values. However, URI Templates have the additional goal + of describing the layout of identifiers in terms of preexisting data + values. Therefore, the template syntax includes operators that + reflect how resource identifiers are commonly allocated. Likewise, + since prefix substrings are often used to partition large spaces of + resources, modifiers on variable values provide a way to specify both + the substring and the full value string with a single variable name. + +1.4. Limitations + + Since a URI Template describes a superset of the identifiers, there + is no implication that every possible expansion for each delimited + variable expression corresponds to a URI of an existing resource. + Our expectation is that an application constructing URIs according to + the template will be provided with an appropriate set of values for + the variables being substituted, or at least a means of validating + user data-entry for those values. + + + + + +Gregorio, et al. Standards Track [Page 10] + +RFC 6570 URI Template March 2012 + + + URI Templates are not URIs: they do not identify an abstract or + physical resource, they are not parsed as URIs, and they should not + be used in places where a URI would be expected unless the template + expressions will be expanded by a template processor prior to use. + Distinct field, element, or attribute names should be used to + differentiate protocol elements that carry a URI Template from those + that expect a URI reference. + + Some URI Templates can be used in reverse for the purpose of variable + matching: comparing the template to a fully formed URI in order to + extract the variable parts from that URI and assign them to the named + variables. Variable matching only works well if the template + expressions are delimited by the beginning or end of the URI or by + characters that cannot be part of the expansion, such as reserved + characters surrounding a simple string expression. In general, + regular expression languages are better suited for variable matching. + +1.5. Notational Conventions + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [RFC2119]. + + This specification uses the Augmented Backus-Naur Form (ABNF) + notation of [RFC5234]. The following ABNF rules are imported from + the normative references [RFC5234], [RFC3986], and [RFC3987]. + + ALPHA = %x41-5A / %x61-7A ; A-Z / a-z + DIGIT = %x30-39 ; 0-9 + HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F" + ; case-insensitive + + pct-encoded = "%" HEXDIG HEXDIG + unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + reserved = gen-delims / sub-delims + gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" + sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + / "*" / "+" / "," / ";" / "=" + + ucschar = %xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF + / %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD + / %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD + / %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD + / %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD + / %xD0000-DFFFD / %xE1000-EFFFD + + iprivate = %xE000-F8FF / %xF0000-FFFFD / %x100000-10FFFD + + + + +Gregorio, et al. Standards Track [Page 11] + +RFC 6570 URI Template March 2012 + + +1.6. Character Encoding and Unicode Normalization + + This specification uses the terms "character", "character encoding + scheme", "code point", "coded character set", "glyph", "non-ASCII", + "normalization", "protocol element", and "regular expression" as they + are defined in [RFC6365]. + + The ABNF notation defines its terminal values to be non-negative + integers (code points) that are a superset of the US-ASCII coded + character set [ASCII]. This specification defines terminal values as + code points within the Unicode coded character set [UNIV6]. + + In spite of the syntax and template expansion process being defined + in terms of Unicode code points, it should be understood that + templates occur in practice as a sequence of characters in whatever + form or encoding is suitable for the context in which they occur, + whether that be octets embedded in a network protocol element or + glyphs painted on the side of a bus. This specification does not + mandate any particular character encoding scheme for mapping between + URI Template characters and the octets used to store or transmit + those characters. When a URI Template appears in a protocol element, + the character encoding scheme is defined by that protocol; without + such a definition, a URI Template is assumed to be in the same + character encoding scheme as the surrounding text. It is only during + the process of template expansion that a string of characters in a + URI Template is REQUIRED to be processed as a sequence of Unicode + code points. + + The Unicode Standard [UNIV6] defines various equivalences between + sequences of characters for various purposes. Unicode Standard Annex + #15 [UTR15] defines various Normalization Forms for these + equivalences. The normalization form determines how to consistently + encode equivalent strings. In theory, all URI processing + implementations, including template processors, should use the same + normalization form for generating a URI reference. In practice, they + do not. If a value has been provided by the same server as the + resource, then it can be assumed that the string is already in the + form expected by that server. If a value is provided by a user, such + as via a data-entry dialog, then the string SHOULD be normalized as + Normalization Form C (NFC: Canonical Decomposition, followed by + Canonical Composition) prior to being used in expansions by a + template processor. + + Likewise, when non-ASCII data that represents readable strings is + pct-encoded for use in a URI reference, a template processor MUST + first encode the string as UTF-8 [RFC3629] and then pct-encode any + octets that are not allowed in a URI reference. + + + + +Gregorio, et al. Standards Track [Page 12] + +RFC 6570 URI Template March 2012 + + +2. Syntax + + A URI Template is a string of printable Unicode characters that + contains zero or more embedded variable expressions, each expression + being delimited by a matching pair of braces ('{', '}'). + + URI-Template = *( literals / expression ) + + Although templates (and template processor implementations) are + described above in terms of four gradual levels, we define the URI- + Template syntax in terms of the ABNF for Level 4. A template + processor limited to lower-level templates MAY exclude the ABNF rules + applicable only to higher levels. However, it is RECOMMENDED that + all parsers implement the full syntax such that unsupported levels + can be properly identified as such to the end user. + +2.1. Literals + + The characters outside of expressions in a URI Template string are + intended to be copied literally to the URI reference if the character + is allowed in a URI (reserved / unreserved / pct-encoded) or, if not + allowed, copied to the URI reference as the sequence of pct-encoded + triplets corresponding to that character's encoding in UTF-8 + [RFC3629]. + + literals = %x21 / %x23-24 / %x26 / %x28-3B / %x3D / %x3F-5B + / %x5D / %x5F / %x61-7A / %x7E / ucschar / iprivate + / pct-encoded + ; any Unicode character except: CTL, SP, + ; DQUOTE, "'", "%" (aside from pct-encoded), + ; "<", ">", "\", "^", "`", "{", "|", "}" + +2.2. Expressions + + Template expressions are the parameterized parts of a URI Template. + Each expression contains an optional operator, which defines the + expression type and its corresponding expansion process, followed by + a comma-separated list of variable specifiers (variable names and + optional value modifiers). If no operator is provided, the + expression defaults to simple variable expansion of unreserved + values. + + expression = "{" [ operator ] variable-list "}" + operator = op-level2 / op-level3 / op-reserve + op-level2 = "+" / "#" + op-level3 = "." / "/" / ";" / "?" / "&" + op-reserve = "=" / "," / "!" / "@" / "|" + + + + +Gregorio, et al. Standards Track [Page 13] + +RFC 6570 URI Template March 2012 + + + The operator characters have been chosen to reflect each of their + roles as reserved characters in the URI generic syntax. The + operators defined in Section 3 of this specification include: + + + Reserved character strings; + + # Fragment identifiers prefixed by "#"; + + . Name labels or extensions prefixed by "."; + + / Path segments prefixed by "/"; + + ; Path parameter name or name=value pairs prefixed by ";"; + + ? Query component beginning with "?" and consisting of + name=value pairs separated by "&"; and, + + & Continuation of query-style &name=value pairs within + a literal query component. + + The operator characters equals ("="), comma (","), exclamation ("!"), + at sign ("@"), and pipe ("|") are reserved for future extensions. + + The expression syntax specifically excludes use of the dollar ("$") + and parentheses ["(" and ")"] characters so that they remain + available for use outside the scope of this specification. For + example, a macro language might use these characters to apply macro + substitution to a string prior to that string being processed as a + URI Template. + +2.3. Variables + + After the operator (if any), each expression contains a list of one + or more comma-separated variable specifiers (varspec). The variable + names serve multiple purposes: documentation for what kinds of values + are expected, identifiers for associating values within a template + processor, and the literal string to use for the name in name=value + expansions (aside from when exploding an associative array). + Variable names are case-sensitive because the name might be expanded + within a case-sensitive URI component. + + variable-list = varspec *( "," varspec ) + varspec = varname [ modifier-level4 ] + varname = varchar *( ["."] varchar ) + varchar = ALPHA / DIGIT / "_" / pct-encoded + + + + + + +Gregorio, et al. Standards Track [Page 14] + +RFC 6570 URI Template March 2012 + + + A varname MAY contain one or more pct-encoded triplets. These + triplets are considered an essential part of the variable name and + are not decoded during processing. A varname containing pct-encoded + characters is not the same variable as a varname with those same + characters decoded. Applications that provide URI Templates are + expected to be consistent in their use of pct-encoding within + variable names. + + An expression MAY reference variables that are unknown to the + template processor or whose value is set to a special "undefined" + value, such as undef or null. Such undefined variables are given + special treatment by the expansion process (Section 3.2.1). + + A variable value that is a string of length zero is not considered + undefined; it has the defined value of an empty string. + + In Level 4 templates, a variable may have a composite value in the + form of a list of values or an associative array of (name, value) + pairs. Such value types are not directly indicated by the template + syntax, but they do have an impact on the expansion process + (Section 3.2.1). + + A variable defined as a list value is considered undefined if the + list contains zero members. A variable defined as an associative + array of (name, value) pairs is considered undefined if the array + contains zero members or if all member names in the array are + associated with undefined values. + +2.4. Value Modifiers + + Each of the variables in a Level 4 template expression can have a + modifier indicating either that its expansion is limited to a prefix + of the variable's value string or that its expansion is exploded as a + composite value in the form of a value list or an associative array + of (name, value) pairs. + + modifier-level4 = prefix / explode + +2.4.1. Prefix Values + + A prefix modifier indicates that the variable expansion is limited to + a prefix of the variable's value string. Prefix modifiers are often + used to partition an identifier space hierarchically, as is common in + reference indices and hash-based storage. It also serves to limit + the expanded value to a maximum number of characters. Prefix + modifiers are not applicable to variables that have composite values. + + + + + +Gregorio, et al. Standards Track [Page 15] + +RFC 6570 URI Template March 2012 + + + prefix = ":" max-length + max-length = %x31-39 0*3DIGIT ; positive integer < 10000 + + The max-length is a positive integer that refers to a maximum number + of characters from the beginning of the variable's value as a Unicode + string. Note that this numbering is in characters, not octets, in + order to avoid splitting between the octets of a multi-octet-encoded + character or within a pct-encoded triplet. If the max-length is + greater than the length of the variable's value, then the entire + value string is used. + + For example, + + Given the variable assignments + + var := "value" + semi := ";" + + Example Template Expansion + + {var} value + {var:20} value + {var:3} val + {semi} %3B + {semi:2} %3B + +2.4.2. Composite Values + + An explode ("*") modifier indicates that the variable is to be + treated as a composite value consisting of either a list of values or + an associative array of (name, value) pairs. Hence, the expansion + process is applied to each member of the composite as if it were + listed as a separate variable. This kind of variable specification + is significantly less self-documenting than non-exploded variables, + since there is less correspondence between the variable name and how + the URI reference appears after expansion. + + explode = "*" + + Since URI Templates do not contain an indication of type or schema, + the type for an exploded variable is assumed to be determined by + context. For example, the processor might be supplied values in a + form that differentiates values as strings, lists, or associative + arrays. Likewise, the context in which the template is used (script, + mark-up language, Interface Definition Language, etc.) might define + rules for associating variable names with types, structures, or + schema. + + + + +Gregorio, et al. Standards Track [Page 16] + +RFC 6570 URI Template March 2012 + + + Explode modifiers improve brevity in the URI Template syntax. For + example, a resource that provides a geographic map for a given street + address might accept a hundred permutations on fields for address + input, including partial addresses (e.g., just the city or postal + code). Such a resource could be described as a template with each + and every address component listed in order, or with a far more + simple template that makes use of an explode modifier, as in + + /mapper{?address*} + + along with some context that defines what the variable named + "address" can include, such as by reference to some other standard + for addressing (e.g., [UPU-S42]). A recipient aware of the schema + can then provide appropriate expansions, such as: + + /mapper?city=Newport%20Beach&state=CA + + The expansion process for exploded variables is dependent on both the + operator being used and whether the composite value is to be treated + as a list of values or as an associative array of (name, value) + pairs. Structures are processed as if they are an associative array + with names corresponding to the fields in the structure definition + and "." separators used to indicate name hierarchy in substructures. + + If a variable has a composite structure and only some of the fields + in that structure have defined values, then only the defined pairs + are present in the expansion. This can be useful for templates that + consist of a large number of potential query terms. + + An explode modifier applied to a list variable causes the expansion + to iterate over the list's member values. For path and query + parameter expansions, each member value is paired with the variable's + name as a (varname, value) pair. This allows path and query + parameters to be repeated for multiple values, as in + + Given the variable assignments + + year := ("1965", "2000", "2012") + dom := ("example", "com") + + Example Template Expansion + + find{?year*} find?year=1965&year=2000&year=2012 + www{.dom*} www.example.com + + + + + + + +Gregorio, et al. Standards Track [Page 17] + +RFC 6570 URI Template March 2012 + + +3. Expansion + + The process of URI Template expansion is to scan the template string + from beginning to end, copying literal characters and replacing each + expression with the result of applying the expression's operator to + the value of each variable named in the expression. Each variable's + value MUST be formed prior to template expansion. + + The requirements on expansion for each aspect of the URI Template + grammar are defined in this section. A non-normative algorithm for + the expansion process as a whole is provided in Appendix A. + + If a template processor encounters a character sequence outside an + expression that does not match the grammar, then + processing of the template SHOULD cease, the URI reference result + SHOULD contain the expanded part of the template followed by the + remainder unexpanded, and the location and type of error SHOULD be + indicated to the invoking application. + + If an error is encountered in an expression, such as an operator or + value modifier that the template processor does not recognize or does + not yet support, or a character is found that is not allowed by the + grammar, then the unprocessed parts of the expression + SHOULD be copied to the result unexpanded, processing of the + remainder of the template SHOULD continue, and the location and type + of error SHOULD be indicated to the invoking application. + + If an error occurs, the result returned might not be a valid URI + reference; it will be an incompletely expanded template string that + is only intended for diagnostic use. + +3.1. Literal Expansion + + If the literal character is allowed anywhere in the URI syntax + (unreserved / reserved / pct-encoded ), then it is copied directly to + the result string. Otherwise, the pct-encoded equivalent of the + literal character is copied to the result string by first encoding + the character as its sequence of octets in UTF-8 and then encoding + each such octet as a pct-encoded triplet. + +3.2. Expression Expansion + + Each expression is indicated by an opening brace ("{") character and + continues until the next closing brace ("}"). Expressions cannot be + nested. + + + + + + +Gregorio, et al. Standards Track [Page 18] + +RFC 6570 URI Template March 2012 + + + An expression is expanded by determining its expression type and then + following that type's expansion process for each comma-separated + varspec in the expression. Level 1 templates are limited to the + default operator (simple string value expansion) and a single + variable per expression. Level 2 templates are limited to a single + varspec per expression. + + The expression type is determined by looking at the first character + after the opening brace. If the character is an operator, then + remember the expression type associated with that operator for later + expansion decisions and skip to the next character for the variable- + list. If the first character is not an operator, then the expression + type is simple string expansion and the first character is the + beginning of the variable-list. + + The examples in the subsections below use the following definitions + for variable values: + + 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 + + A variable that is undefined (Section 2.3) has no value and is + ignored by the expansion process. If all of the variables in an + expression are undefined, then the expression's expansion is the + empty string. + + Variable expansion of a defined, non-empty value results in a + substring of allowed URI characters. As described in Section 1.6, + the expansion process is defined in terms of Unicode code points in + order to ensure that non-ASCII characters are consistently pct- + encoded in the resulting URI reference. One way for a template + + + +Gregorio, et al. Standards Track [Page 19] + +RFC 6570 URI Template March 2012 + + + processor to obtain a consistent expansion is to transcode the value + string to UTF-8 (if it is not already in UTF-8) and then transform + each octet that is not in the allowed set into the corresponding pct- + encoded triplet. Another is to map directly from the value's native + character encoding to the set of allowed URI characters, with any + remaining disallowed characters mapping to the sequence of pct- + encoded triplets that correspond to the octet(s) of that character + when encoded as UTF-8 [RFC3629]. + + The allowed set for a given expansion depends on the expression type: + reserved ("+") and fragment ("#") expansions allow the set of + characters in the union of ( unreserved / reserved / pct-encoded ) to + be passed through without pct-encoding, whereas all other expression + types allow only unreserved characters to be passed through without + pct-encoding. Note that the percent character ("%") is only allowed + as part of a pct-encoded triplet and only for reserved/fragment + expansion: in all other cases, a value character of "%" MUST be pct- + encoded as "%25" by variable expansion. + + If a variable appears more than once in an expression or within + multiple expressions of a URI Template, the value of that variable + MUST remain static throughout the expansion process (i.e., the + variable must have the same value for the purpose of calculating each + expansion). However, if reserved characters or pct-encoded triplets + occur in the value, they will be pct-encoded by some expression types + and not by others. + + For a variable that is a simple string value, expansion consists of + appending the encoded value to the result string. An explode + modifier has no effect. A prefix modifier limits the expansion to + the first max-length characters of the decoded value. If the value + contains multi-octet or pct-encoded characters, care must be taken to + avoid splitting the value in mid-character: count each Unicode code + point as one character. + + For a variable that is an associative array, expansion depends on + both the expression type and the presence of an explode modifier. If + there is no explode modifier, expansion consists of appending a + comma-separated concatenation of each (name, value) pair that has a + defined value. If there is an explode modifier, expansion consists + of appending each pair that has a defined value as either + "name=value" or, if the value is the empty string and the expression + type does not indicate form-style parameters (i.e., not a "?" or "&" + type), simply "name". Both name and value strings are encoded in the + same way as simple string values. A separator string is appended + between defined pairs according to the expression type, as defined by + the following table: + + + + +Gregorio, et al. Standards Track [Page 20] + +RFC 6570 URI Template March 2012 + + + Type Separator + "," (default) + + "," + # "," + . "." + / "/" + ; ";" + ? "&" + & "&" + + For a variable that is a list of values, expansion depends on both + the expression type and the presence of an explode modifier. If + there is no explode modifier, the expansion consists of a comma- + separated concatenation of the defined member string values. If + there is an explode modifier and the expression type expands named + parameters (";", "?", or "&"), then the list is expanded as if it + were an associative array in which each member value is paired with + the list's varname. Otherwise, the value will be expanded as if it + were a list of separate variable values, each value separated by the + expression type's associated separator as defined by the table above. + + Example Template Expansion + + {count} one,two,three + {count*} one,two,three + {/count} /one,two,three + {/count*} /one/two/three + {;count} ;count=one,two,three + {;count*} ;count=one;count=two;count=three + {?count} ?count=one,two,three + {?count*} ?count=one&count=two&count=three + {&count*} &count=one&count=two&count=three + +3.2.2. Simple String Expansion: {var} + + Simple string expansion is the default expression type when no + operator is given. + + For each defined variable in the variable-list, perform variable + expansion, as defined in Section 3.2.1, with the allowed characters + being those in the unreserved set. If more than one variable has a + defined value, append a comma (",") to the result string as a + separator between variable expansions. + + + + + + + + +Gregorio, et al. Standards Track [Page 21] + +RFC 6570 URI Template March 2012 + + + Example Template Expansion + + {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} + + Reserved expansion, as indicated by the plus ("+") operator for Level + 2 and above templates, is identical to simple string expansion except + that the substituted values may also contain pct-encoded triplets and + characters in the reserved set. + + For each defined variable in the variable-list, perform variable + expansion, as defined in Section 3.2.1, with the allowed characters + being those in the set (unreserved / reserved / pct-encoded). If + more than one variable has a defined value, append a comma (",") to + the result string as a separator between variable expansions. + + + + + + + + + + + + + + + + + + + + +Gregorio, et al. Standards Track [Page 22] + +RFC 6570 URI Template March 2012 + + + Example Template Expansion + + {+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 + up{+path}{var}/here up/foo/barvalue/here + {+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.4. Fragment Expansion: {#var} + + Fragment expansion, as indicated by the crosshatch ("#") operator for + Level 2 and above templates, is identical to reserved expansion + except that a crosshatch character (fragment delimiter) is appended + first to the result string if any of the variables are defined. + + Example Template Expansion + + {#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=, + + + + + + + +Gregorio, et al. Standards Track [Page 23] + +RFC 6570 URI Template March 2012 + + +3.2.5. Label Expansion with Dot-Prefix: {.var} + + Label expansion, as indicated by the dot (".") operator for Level 3 + and above templates, is useful for describing URI spaces with varying + domain names or path selectors (e.g., filename extensions). + + For each defined variable in the variable-list, append "." to the + result string and then perform variable expansion, as defined in + Section 3.2.1, with the allowed characters being those in the + unreserved set. + + Since "." is in the unreserved set, a value that contains a "." has + the effect of adding multiple labels. + + Example Template Expansion + + {.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} + + Path segment expansion, as indicated by the slash ("/") operator in + Level 3 and above templates, is useful for describing URI path + hierarchies. + + For each defined variable in the variable-list, append "/" to the + result string and then perform variable expansion, as defined in + Section 3.2.1, with the allowed characters being those in the + unreserved set. + + Note that the expansion process for path segment expansion is + identical to that of label expansion aside from the substitution of + "/" instead of ".". However, unlike ".", a "/" is a reserved + character and will be pct-encoded if found in a value. + + + + + +Gregorio, et al. Standards Track [Page 24] + +RFC 6570 URI Template March 2012 + + + Example Template Expansion + + {/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} + + Path-style parameter expansion, as indicated by the semicolon (";") + operator in Level 3 and above templates, is useful for describing URI + path parameters, such as "path;property" or "path;name=value". + + For each defined variable in the variable-list: + + o append ";" to the result string; + + o if the variable has a simple string value or no explode modifier + is given, then: + + * append the variable name (encoded as if it were a literal + string) to the result string; + + * if the variable's value is not empty, append "=" to the result + string; + + o perform variable expansion, as defined in Section 3.2.1, with the + allowed characters being those in the unreserved set. + + + + + + + + + + + + + +Gregorio, et al. Standards Track [Page 25] + +RFC 6570 URI Template March 2012 + + + Example Template Expansion + + {;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} + + Form-style query expansion, as indicated by the question-mark ("?") + operator in Level 3 and above templates, is useful for describing an + entire optional query component. + + For each defined variable in the variable-list: + + o append "?" to the result string if this is the first defined value + or append "&" thereafter; + + o if the variable has a simple string value or no explode modifier + is given, append the variable name (encoded as if it were a + literal string) and an equals character ("=") to the result + string; and, + + o perform variable expansion, as defined in Section 3.2.1, with the + allowed characters being those in the unreserved set. + + + Example Template Expansion + + {?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 + + + +Gregorio, et al. Standards Track [Page 26] + +RFC 6570 URI Template March 2012 + + +3.2.9. Form-Style Query Continuation: {&var} + + Form-style query continuation, as indicated by the ampersand ("&") + operator in Level 3 and above templates, is useful for describing + optional &name=value pairs in a template that already contains a + literal query component with fixed parameters. + + For each defined variable in the variable-list: + + o append "&" to the result string; + + o if the variable has a simple string value or no explode modifier + is given, append the variable name (encoded as if it were a + literal string) and an equals character ("=") to the result + string; and, + + o perform variable expansion, as defined in Section 3.2.1, with the + allowed characters being those in the unreserved set. + + + Example Template Expansion + + {&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 + + A URI Template does not contain active or executable content. + However, it might be possible to craft unanticipated URIs if an + attacker is given control over the template or over the variable + values within an expression that allows reserved characters in the + expansion. In either case, the security considerations are largely + determined by who provides the template, who provides the values to + use for variables within the template, in what execution context the + expansion occurs (client or server), and where the resulting URIs are + used. + + + + + + +Gregorio, et al. Standards Track [Page 27] + +RFC 6570 URI Template March 2012 + + + This specification does not limit where URI Templates might be used. + Current implementations exist within server-side development + frameworks and within client-side javascript for computed links or + forms. + + Within frameworks, templates usually act as guides for where data + might occur within later (request-time) URIs in client requests. + Hence, the security concerns are not in the templates themselves, but + rather in how the server extracts and processes the user-provided + data within a normal Web request. + + Within client-side implementations, a URI Template has many of the + same properties as HTML forms, except limited to URI characters and + possibly included in HTTP header field values instead of just message + body content. Care ought to be taken to ensure that potentially + dangerous URI reference strings, such as those beginning with + "javascript:", do not appear in the expansion unless both the + template and the values are provided by a trusted source. + + Other security considerations are the same as those for URIs, as + described in Section 7 of [RFC3986]. + +5. Acknowledgments + + The following people made contributions to this specification: Mike + Burrows, Michaeljohn Clement, DeWitt Clinton, John Cowan, Stephen + Farrell, Robbie Gates, Vijay K. Gurbani, Peter Johanson, Murray S. + Kucherawy, James H. Manger, Tom Petch, Marc Portier, Pete Resnick, + James Snell, and Jiankang Yao. + +6. References + +6.1. Normative References + + [ASCII] American National Standards Institute, "Coded Character + Set - 7-bit American Standard Code for Information + Interchange", ANSI X3.4, 1986. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", STD 63, RFC 3629, November 2003. + + [RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, + "Uniform Resource Identifier (URI): Generic Syntax", + STD 66, RFC 3986, January 2005. + + + + +Gregorio, et al. Standards Track [Page 28] + +RFC 6570 URI Template March 2012 + + + [RFC3987] Duerst, M. and M. Suignard, "Internationalized Resource + Identifiers (IRIs)", RFC 3987, January 2005. + + [RFC5234] Crocker, D. and P. Overell, "Augmented BNF for Syntax + Specifications: ABNF", STD 68, RFC 5234, January 2008. + + [RFC6365] Hoffman, P. and J. Klensin, "Terminology Used in + Internationalization in the IETF", BCP 166, RFC 6365, + September 2011. + + [UNIV6] The Unicode Consortium, "The Unicode Standard, Version + 6.0.0", (Mountain View, CA: The Unicode Consortium, + 2011. ISBN 978-1-936213-01-6), + . + + [UTR15] Davis, M. and M. Duerst, "Unicode Normalization Forms", + Unicode Standard Annex # 15, April 2003, + . + +6.2. Informative References + + [OpenSearch] Clinton, D., "OpenSearch 1.1", Draft 5, December 2011, + . + + [UPU-S42] Universal Postal Union, "International Postal Address + Components and Templates", UPU S42-1, November 2002, + . + + [WADL] Hadley, M., "Web Application Description Language", + World Wide Web Consortium Member Submission + SUBM-wadl-20090831, August 2009, + . + + [WSDL] Weerawarana, S., Moreau, J., Ryman, A., and R. + Chinnici, "Web Services Description Language (WSDL) + Version 2.0 Part 1: Core Language", World Wide Web + Consortium Recommendation REC-wsdl20-20070626, + June 2007, . + + + + + + + + + +Gregorio, et al. Standards Track [Page 29] + +RFC 6570 URI Template March 2012 + + +Appendix A. Implementation Hints + + The normative sections on expansion describe each operator with a + separate expansion process for the sake of descriptive clarity. In + actual implementations, we expect the expressions to be processed + left-to-right using a common algorithm that has only minor variations + in process per operator. This non-normative appendix describes one + such algorithm. + + Initialize an empty result string and its non-error state. + + Scan the template and copy literals to the result string (as in + Section 3.1) until an expression is indicated by a "{", an error is + indicated by the presence of a non-literals character other than "{", + or the template ends. When it ends, return the result string and its + current error or non-error state. + + o If an expression is found, scan the template to the next "}" and + extract the characters in between the braces. + + o If the template ends before a "}", then append the "{" and + extracted characters to the result string and return with an error + status indicating the expression is malformed. + + Examine the first character of the extracted expression for an + operator. + + o If the expression ended (i.e., is "{}"), an operator is found that + is unknown or unimplemented, or the character is not in the + varchar set (Section 2.3), then append "{", the extracted + expression, and "}" to the result string, remember that the result + is in an error state, and then go back to scan the remainder of + the template. + + o If a known and implemented operator is found, store the operator + and skip to the next character to begin the varspec-list. + + o Otherwise, store the operator as NUL (simple string expansion). + + Use the following value table to determine the processing behavior by + expression type operator. The entry for "first" is the string to + append to the result first if any of the expression's variables are + defined. The entry for "sep" is the separator to append to the + result before any second (or subsequent) defined variable expansion. + The entry for "named" is a boolean for whether or not the expansion + includes the variable or key name when no explode modifier is given. + The entry for "ifemp" is a string to append to the name if its + corresponding value is empty. The entry for "allow" indicates what + + + +Gregorio, et al. Standards Track [Page 30] + +RFC 6570 URI Template March 2012 + + + characters to allow unencoded within the value expansion: (U) means + any character not in the unreserved set will be encoded; (U+R) means + any character not in the union of (unreserved / reserved / pct- + encoding) will be encoded; and, for both cases, each disallowed + character is first encoded as its sequence of octets in UTF-8 and + then each such octet is encoded as a pct-encoded triplet. + + .------------------------------------------------------------------. + | NUL + . / ; ? & # | + |------------------------------------------------------------------| + | first | "" "" "." "/" ";" "?" "&" "#" | + | sep | "," "," "." "/" ";" "&" "&" "," | + | named | false false false false true true true false | + | ifemp | "" "" "" "" "" "=" "=" "" | + | allow | U U+R U U U U U U+R | + `------------------------------------------------------------------' + + With the above table in mind, process the variable-list as follows: + + For each varspec, extract a variable name and optional modifier from + the expression by scanning the variable-list until a character not in + the varname set is found or the end of the expression is reached. + + o If it is the end of the expression and the varname is empty, go + back to scan the remainder of the template. + + o If it is not the end of the expression and the last character + found indicates a modifier ("*" or ":"), remember that modifier. + If it is an explode ("*"), scan the next character. If it is a + prefix (":"), continue scanning the next one to four characters + for the max-length represented as a decimal integer and then, if + it is still not the end of the expression, scan the next + character. + + o If it is not the end of the expression and the last character + found is not a comma (","), append "{", the stored operator (if + any), the scanned varname and modifier, the remaining expression, + and "}" to the result string, remember that the result is in an + error state, and then go back to scan the remainder of the + template. + + Lookup the value for the scanned variable name, and then + + o If the varname is unknown or corresponds to a variable with an + undefined value (Section 2.3), then skip to the next varspec. + + + + + + +Gregorio, et al. Standards Track [Page 31] + +RFC 6570 URI Template March 2012 + + + o If this is the first defined variable for this expression, append + the first string for this expression type to the result string and + remember that it has been done. Otherwise, append the sep string + to the result string. + + o If this variable's value is a string, then + + * if named is true, append the varname to the result string using + the same encoding process as for literals, and + + + if the value is empty, append the ifemp string to the result + string and skip to the next varspec; + + + otherwise, append "=" to the result string. + + * if a prefix modifier is present and the prefix length is less + than the value string length in number of Unicode characters, + append that number of characters from the beginning of the + value string to the result string, after pct-encoding any + characters that are not in the allow set, while taking care not + to split multi-octet or pct-encoded triplet characters that + represent a single Unicode code point; + + * otherwise, append the value to the result string after pct- + encoding any characters that are not in the allow set. + + o else if no explode modifier is given, then + + * if named is true, append the varname to the result string using + the same encoding process as for literals, and + + + if the value is empty, append the ifemp string to the result + string and skip to the next varspec; + + + otherwise, append "=" to the result string; and + + * if this variable's value is a list, append each defined list + member to the result string, after pct-encoding any characters + that are not in the allow set, with a comma (",") appended to + the result between each defined list member; + + * if this variable's value is an associative array or any other + form of paired (name, value) structure, append each pair with a + defined value to the result string as "name,value", after pct- + encoding any characters that are not in the allow set, with a + comma (",") appended to the result between each defined pair. + + + + + +Gregorio, et al. Standards Track [Page 32] + +RFC 6570 URI Template March 2012 + + + o else if an explode modifier is given, then + + * if named is true, then for each defined list member or array + (name, value) pair with a defined value, do: + + + if this is not the first defined member/value, append the + sep string to the result string; + + + if this is a list, append the varname to the result string + using the same encoding process as for literals; + + + if this is a pair, append the name to the result string + using the same encoding process as for literals; + + + if the member/value is empty, append the ifemp string to the + result string; otherwise, append "=" and the member/value to + the result string, after pct-encoding any member/value + characters that are not in the allow set. + + * else if named is false, then + + + if this is a list, append each defined list member to the + result string, after pct-encoding any characters that are + not in the allow set, with the sep string appended to the + result between each defined list member. + + + if this is an array of (name, value) pairs, append each pair + with a defined value to the result string as "name=value", + after pct-encoding any characters that are not in the allow + set, with the sep string appended to the result between each + defined pair. + + When the variable-list for this expression is exhausted, go back to + scan the remainder of the template. + + + + + + + + + + + + + + + + + +Gregorio, et al. Standards Track [Page 33] + +RFC 6570 URI Template March 2012 + + +Authors' Addresses + + Joe Gregorio + Google + + EMail: joe@bitworking.org + URI: http://bitworking.org/ + + + Roy T. Fielding + Adobe Systems Incorporated + + EMail: fielding@gbiv.com + URI: http://roy.gbiv.com/ + + + Marc Hadley + The MITRE Corporation + + EMail: mhadley@mitre.org + URI: http://mitre.org/ + + + Mark Nottingham + Rackspace + + EMail: mnot@mnot.net + URI: http://www.mnot.net/ + + + David Orchard + Salesforce.com + + EMail: orchard@pacificspirit.com + URI: http://www.pacificspirit.com/ + + + + + + + + + + + + + + + + +Gregorio, et al. Standards Track [Page 34] + diff --git a/library/protocol/uri_template/doc/uritemplate-RFC6570 b/library/protocol/uri_template/doc/uritemplate-RFC6570 new file mode 100644 index 00000000..12d5c0f9 --- /dev/null +++ b/library/protocol/uri_template/doc/uritemplate-RFC6570 @@ -0,0 +1,1907 @@ + + + + + + +Internet Engineering Task Force (IETF) J. Gregorio +Request for Comments: 6570 Google +Category: Standards Track R. Fielding +ISSN: 2070-1721 Adobe + M. Hadley + MITRE + M. Nottingham + Rackspace + D. Orchard + Salesforce.com + March 2012 + + + URI Template + +Abstract + + A URI Template is a compact sequence of characters for describing a + range of Uniform Resource Identifiers through variable expansion. + This specification defines the URI Template syntax and the process + for expanding a URI Template into a URI reference, along with + guidelines for the use of URI Templates on the Internet. + +Status of This Memo + + This is an Internet Standards Track document. + + This document is a product of the Internet Engineering Task Force + (IETF). It represents the consensus of the IETF community. It has + received public review and has been approved for publication by the + Internet Engineering Steering Group (IESG). Further information on + Internet Standards is available in Section 2 of RFC 5741. + + Information about the current status of this document, any errata, + and how to provide feedback on it may be obtained at + http://www.rfc-editor.org/info/rfc6570. + +Copyright Notice + + Copyright (c) 2012 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + + + +Gregorio, et al. Standards Track [Page 1] + +RFC 6570 URI Template March 2012 + + + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + +Table of Contents + + 1. Introduction ....................................................3 + 1.1. Overview ...................................................3 + 1.2. Levels and Expression Types ................................5 + 1.3. Design Considerations ......................................9 + 1.4. Limitations ...............................................10 + 1.5. Notational Conventions ....................................11 + 1.6. Character Encoding and Unicode Normalization ..............12 + 2. Syntax .........................................................13 + 2.1. Literals ..................................................13 + 2.2. Expressions ...............................................13 + 2.3. Variables .................................................14 + 2.4. Value Modifiers ...........................................15 + 2.4.1. Prefix Values ......................................15 + 2.4.2. Composite Values ...................................16 + 3. Expansion ......................................................18 + 3.1. Literal Expansion .........................................18 + 3.2. Expression Expansion ......................................18 + 3.2.1. Variable Expansion .................................19 + 3.2.2. Simple String Expansion: {var} .....................21 + 3.2.3. Reserved Expansion: {+var} .........................22 + 3.2.4. Fragment Expansion: {#var} .........................23 + 3.2.5. Label Expansion with Dot-Prefix: {.var} ............24 + 3.2.6. Path Segment Expansion: {/var} .....................24 + 3.2.7. Path-Style Parameter Expansion: {;var} .............25 + 3.2.8. Form-Style Query Expansion: {?var} .................26 + 3.2.9. Form-Style Query Continuation: {&var} ..............27 + 4. Security Considerations ........................................27 + 5. Acknowledgments ................................................28 + 6. References .....................................................28 + 6.1. Normative References ......................................28 + 6.2. Informative References ....................................29 + Appendix A. Implementation Hints ..................................30 + + + + + + + + + + + + + +Gregorio, et al. Standards Track [Page 2] + +RFC 6570 URI Template March 2012 + + +1. Introduction + +1.1. Overview + + A Uniform Resource Identifier (URI) [RFC3986] is often used to + identify a specific resource within a common space of similar + resources (informally, a "URI space"). For example, personal web + spaces are often delegated using a common pattern, such as + + http://example.com/~fred/ + http://example.com/~mark/ + + or a set of dictionary entries might be grouped in a hierarchy by the + first letter of the term, as in + + http://example.com/dictionary/c/cat + http://example.com/dictionary/d/dog + + or a service interface might be invoked with various user input in a + common pattern, as in + + http://example.com/search?q=cat&lang=en + http://example.com/search?q=chien&lang=fr + + A URI Template is a compact sequence of characters for describing a + range of Uniform Resource Identifiers through variable expansion. + + URI Templates provide a mechanism for abstracting a space of resource + identifiers such that the variable parts can be easily identified and + described. URI Templates can have many uses, including the discovery + of available services, configuring resource mappings, defining + computed links, specifying interfaces, and other forms of + programmatic interaction with resources. For example, the above + resources could be described by the following URI Templates: + + http://example.com/~{username}/ + http://example.com/dictionary/{term:1}/{term} + http://example.com/search{?q,lang} + + We define the following terms: + + expression: The text between '{' and '}', including the enclosing + braces, as defined in Section 2. + + expansion: The string result obtained from a template expression + after processing it according to its expression type, list of + variable names, and value modifiers, as defined in Section 3. + + + + +Gregorio, et al. Standards Track [Page 3] + +RFC 6570 URI Template March 2012 + + + template processor: A program or library that, given a URI Template + and a set of variables with values, transforms the template string + into a URI reference by parsing the template for expressions and + substituting each one with its corresponding expansion. + + A URI Template provides both a structural description of a URI space + and, when variable values are provided, machine-readable instructions + on how to construct a URI corresponding to those values. A URI + Template is transformed into a URI reference by replacing each + delimited expression with its value as defined by the expression type + and the values of variables named within the expression. The + expression types range from simple string expansion to multiple + name=value lists. The expansions are based on the URI generic + syntax, allowing an implementation to process any URI Template + without knowing the scheme-specific requirements of every possible + resulting URI. + + For example, the following URI Template includes a form-style + parameter expression, as indicated by the "?" operator appearing + before the variable names. + + http://www.example.com/foo{?query,number} + + The expansion process for expressions beginning with the question- + mark ("?") operator follows the same pattern as form-style interfaces + on the World Wide Web: + + http://www.example.com/foo{?query,number} + \_____________/ + | + | + For each defined variable in [ 'query', 'number' ], + substitute "?" if it is the first substitution or "&" + thereafter, followed by the variable name, '=', and the + variable's value. + + If the variables have the values + + query := "mycelium" + number := 100 + + then the expansion of the above URI Template is + + http://www.example.com/foo?query=mycelium&number=100 + + Alternatively, if 'query' is undefined, then the expansion would be + + http://www.example.com/foo?number=100 + + + +Gregorio, et al. Standards Track [Page 4] + +RFC 6570 URI Template March 2012 + + + or if both variables are undefined, then it would be + + http://www.example.com/foo + + A URI Template may be provided in absolute form, as in the examples + above, or in relative form. A template is expanded before the + resulting reference is resolved from relative to absolute form. + + Although the URI syntax is used for the result, the template string + is allowed to contain the broader set of characters that can be found + in Internationalized Resource Identifier (IRI) references [RFC3987]. + Therefore, a URI Template is also an IRI template, and the result of + template processing can be transformed to an IRI by following the + process defined in Section 3.2 of [RFC3987]. + +1.2. Levels and Expression Types + + URI Templates are similar to a macro language with a fixed set of + macro definitions: the expression type determines the expansion + process. The default expression type is simple string expansion, + wherein a single named variable is replaced by its value as a string + after pct-encoding any characters not in the set of unreserved URI + characters (Section 1.5). + + Since most template processors implemented prior to this + specification have only implemented the default expression type, we + refer to these as Level 1 templates. + + .-----------------------------------------------------------------. + | Level 1 examples, with variables having values of | + | | + | var := "value" | + | hello := "Hello World!" | + | | + |-----------------------------------------------------------------| + | Op Expression Expansion | + |-----------------------------------------------------------------| + | | Simple string expansion (Sec 3.2.2) | + | | | + | | {var} value | + | | {hello} Hello%20World%21 | + `-----------------------------------------------------------------' + + Level 2 templates add the plus ("+") operator, for expansion of + values that are allowed to include reserved URI characters + (Section 1.5), and the crosshatch ("#") operator for expansion of + fragment identifiers. + + + + +Gregorio, et al. Standards Track [Page 5] + +RFC 6570 URI Template March 2012 + + + .-----------------------------------------------------------------. + | Level 2 examples, with variables having values of | + | | + | var := "value" | + | hello := "Hello World!" | + | path := "/foo/bar" | + | | + |-----------------------------------------------------------------| + | Op Expression Expansion | + |-----------------------------------------------------------------| + | + | Reserved string expansion (Sec 3.2.3) | + | | | + | | {+var} value | + | | {+hello} Hello%20World! | + | | {+path}/here /foo/bar/here | + | | here?ref={+path} here?ref=/foo/bar | + |-----+-----------------------------------------------------------| + | # | Fragment expansion, crosshatch-prefixed (Sec 3.2.4) | + | | | + | | X{#var} X#value | + | | X{#hello} X#Hello%20World! | + `-----------------------------------------------------------------' + + Level 3 templates allow multiple variables per expression, each + separated by a comma, and add more complex operators for dot-prefixed + labels, slash-prefixed path segments, semicolon-prefixed path + parameters, and the form-style construction of a query syntax + consisting of name=value pairs that are separated by an ampersand + character. + + .-----------------------------------------------------------------. + | Level 3 examples, with variables having values of | + | | + | var := "value" | + | hello := "Hello World!" | + | empty := "" | + | path := "/foo/bar" | + | x := "1024" | + | y := "768" | + | | + |-----------------------------------------------------------------| + | Op Expression Expansion | + |-----------------------------------------------------------------| + | | String expansion with multiple variables (Sec 3.2.2) | + | | | + | | map?{x,y} map?1024,768 | + | | {x,hello,y} 1024,Hello%20World%21,768 | + | | | + + + +Gregorio, et al. Standards Track [Page 6] + +RFC 6570 URI Template March 2012 + + + |-----+-----------------------------------------------------------| + | + | Reserved expansion with multiple variables (Sec 3.2.3) | + | | | + | | {+x,hello,y} 1024,Hello%20World!,768 | + | | {+path,x}/here /foo/bar,1024/here | + | | | + |-----+-----------------------------------------------------------| + | # | Fragment expansion with multiple variables (Sec 3.2.4) | + | | | + | | {#x,hello,y} #1024,Hello%20World!,768 | + | | {#path,x}/here #/foo/bar,1024/here | + | | | + |-----+-----------------------------------------------------------| + | . | Label expansion, dot-prefixed (Sec 3.2.5) | + | | | + | | X{.var} X.value | + | | X{.x,y} X.1024.768 | + | | | + |-----+-----------------------------------------------------------| + | / | Path segments, slash-prefixed (Sec 3.2.6) | + | | | + | | {/var} /value | + | | {/var,x}/here /value/1024/here | + | | | + |-----+-----------------------------------------------------------| + | ; | Path-style parameters, semicolon-prefixed (Sec 3.2.7) | + | | | + | | {;x,y} ;x=1024;y=768 | + | | {;x,y,empty} ;x=1024;y=768;empty | + | | | + |-----+-----------------------------------------------------------| + | ? | Form-style query, ampersand-separated (Sec 3.2.8) | + | | | + | | {?x,y} ?x=1024&y=768 | + | | {?x,y,empty} ?x=1024&y=768&empty= | + | | | + |-----+-----------------------------------------------------------| + | & | Form-style query continuation (Sec 3.2.9) | + | | | + | | ?fixed=yes{&x} ?fixed=yes&x=1024 | + | | {&x,y,empty} &x=1024&y=768&empty= | + | | | + `-----------------------------------------------------------------' + + Finally, Level 4 templates add value modifiers as an optional suffix + to each variable name. A prefix modifier (":") indicates that only a + limited number of characters from the beginning of the value are used + by the expansion (Section 2.4.1). An explode ("*") modifier + + + +Gregorio, et al. Standards Track [Page 7] + +RFC 6570 URI Template March 2012 + + + indicates that the variable is to be treated as a composite value, + consisting of either a list of names or an associative array of + (name, value) pairs, that is expanded as if each member were a + separate variable (Section 2.4.2). + + .-----------------------------------------------------------------. + | Level 4 examples, with variables having values of | + | | + | var := "value" | + | hello := "Hello World!" | + | path := "/foo/bar" | + | list := ("red", "green", "blue") | + | keys := [("semi",";"),("dot","."),("comma",",")] | + | | + | Op Expression Expansion | + |-----------------------------------------------------------------| + | | String expansion with value modifiers (Sec 3.2.2) | + | | | + | | {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 | + | | | + |-----+-----------------------------------------------------------| + | + | Reserved expansion with value modifiers (Sec 3.2.3) | + | | | + | | {+path:6}/here /foo/b/here | + | | {+list} red,green,blue | + | | {+list*} red,green,blue | + | | {+keys} semi,;,dot,.,comma,, | + | | {+keys*} semi=;,dot=.,comma=, | + | | | + |-----+-----------------------------------------------------------| + | # | Fragment expansion with value modifiers (Sec 3.2.4) | + | | | + | | {#path:6}/here #/foo/b/here | + | | {#list} #red,green,blue | + | | {#list*} #red,green,blue | + | | {#keys} #semi,;,dot,.,comma,, | + | | {#keys*} #semi=;,dot=.,comma=, | + | | | + |-----+-----------------------------------------------------------| + | . | Label expansion, dot-prefixed (Sec 3.2.5) | + | | | + | | X{.var:3} X.val | + | | X{.list} X.red,green,blue | + + + +Gregorio, et al. Standards Track [Page 8] + +RFC 6570 URI Template March 2012 + + + | | X{.list*} X.red.green.blue | + | | X{.keys} X.semi,%3B,dot,.,comma,%2C | + | | X{.keys*} X.semi=%3B.dot=..comma=%2C | + | | | + |-----+-----------------------------------------------------------| + | / | Path segments, slash-prefixed (Sec 3.2.6) | + | | | + | | {/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 | + | | | + |-----+-----------------------------------------------------------| + | ; | Path-style parameters, semicolon-prefixed (Sec 3.2.7) | + | | | + | | {;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 | + | | | + |-----+-----------------------------------------------------------| + | ? | Form-style query, ampersand-separated (Sec 3.2.8) | + | | | + | | {?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 | + | | | + |-----+-----------------------------------------------------------| + | & | Form-style query continuation (Sec 3.2.9) | + | | | + | | {&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 | + | | | + `-----------------------------------------------------------------' + +1.3. Design Considerations + + Mechanisms similar to URI Templates have been defined within several + specifications, including WSDL [WSDL], WADL [WADL], and OpenSearch + [OpenSearch]. This specification extends and formally defines the + + + +Gregorio, et al. Standards Track [Page 9] + +RFC 6570 URI Template March 2012 + + + syntax so that URI Templates can be used consistently across multiple + Internet applications and within Internet message fields, while at + the same time retaining compatibility with those earlier definitions. + + The URI Template syntax has been designed to carefully balance the + need for a powerful expansion mechanism with the need for ease of + implementation. The syntax is designed to be trivial to parse while + at the same time providing enough flexibility to express many common + template scenarios. Implementations are able to parse the template + and perform the expansions in a single pass. + + Templates are simple and readable when used with common examples + because the single-character operators match the URI generic syntax + delimiters. The operator's associated delimiter (".", ";", "/", "?", + "&", and "#") is omitted when none of the listed variables are + defined. Likewise, the expansion process for ";" (path-style + parameters) will omit the "=" when the variable value is empty, + whereas the process for "?" (form-style parameters) will not omit the + "=" when the value is empty. Multiple variables and list values have + their values joined with "," if there is no predefined joining + mechanism for the operator. The "+" and "#" operators will + substitute unencoded reserved characters found inside the variable + values; the other operators will pct-encode reserved characters found + in the variable values prior to expansion. + + The most common cases for URI spaces can be described with Level 1 + template expressions. If we were only concerned with URI generation, + then the template syntax could be limited to just simple variable + expansion, since more complex forms could be generated by changing + the variable values. However, URI Templates have the additional goal + of describing the layout of identifiers in terms of preexisting data + values. Therefore, the template syntax includes operators that + reflect how resource identifiers are commonly allocated. Likewise, + since prefix substrings are often used to partition large spaces of + resources, modifiers on variable values provide a way to specify both + the substring and the full value string with a single variable name. + +1.4. Limitations + + Since a URI Template describes a superset of the identifiers, there + is no implication that every possible expansion for each delimited + variable expression corresponds to a URI of an existing resource. + Our expectation is that an application constructing URIs according to + the template will be provided with an appropriate set of values for + the variables being substituted, or at least a means of validating + user data-entry for those values. + + + + + +Gregorio, et al. Standards Track [Page 10] + +RFC 6570 URI Template March 2012 + + + URI Templates are not URIs: they do not identify an abstract or + physical resource, they are not parsed as URIs, and they should not + be used in places where a URI would be expected unless the template + expressions will be expanded by a template processor prior to use. + Distinct field, element, or attribute names should be used to + differentiate protocol elements that carry a URI Template from those + that expect a URI reference. + + Some URI Templates can be used in reverse for the purpose of variable + matching: comparing the template to a fully formed URI in order to + extract the variable parts from that URI and assign them to the named + variables. Variable matching only works well if the template + expressions are delimited by the beginning or end of the URI or by + characters that cannot be part of the expansion, such as reserved + characters surrounding a simple string expression. In general, + regular expression languages are better suited for variable matching. + +1.5. Notational Conventions + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [RFC2119]. + + This specification uses the Augmented Backus-Naur Form (ABNF) + notation of [RFC5234]. The following ABNF rules are imported from + the normative references [RFC5234], [RFC3986], and [RFC3987]. + + ALPHA = %x41-5A / %x61-7A ; A-Z / a-z + DIGIT = %x30-39 ; 0-9 + HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F" + ; case-insensitive + + pct-encoded = "%" HEXDIG HEXDIG + unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + reserved = gen-delims / sub-delims + gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" + sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + / "*" / "+" / "," / ";" / "=" + + ucschar = %xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF + / %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD + / %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD + / %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD + / %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD + / %xD0000-DFFFD / %xE1000-EFFFD + + iprivate = %xE000-F8FF / %xF0000-FFFFD / %x100000-10FFFD + + + + +Gregorio, et al. Standards Track [Page 11] + +RFC 6570 URI Template March 2012 + + +1.6. Character Encoding and Unicode Normalization + + This specification uses the terms "character", "character encoding + scheme", "code point", "coded character set", "glyph", "non-ASCII", + "normalization", "protocol element", and "regular expression" as they + are defined in [RFC6365]. + + The ABNF notation defines its terminal values to be non-negative + integers (code points) that are a superset of the US-ASCII coded + character set [ASCII]. This specification defines terminal values as + code points within the Unicode coded character set [UNIV6]. + + In spite of the syntax and template expansion process being defined + in terms of Unicode code points, it should be understood that + templates occur in practice as a sequence of characters in whatever + form or encoding is suitable for the context in which they occur, + whether that be octets embedded in a network protocol element or + glyphs painted on the side of a bus. This specification does not + mandate any particular character encoding scheme for mapping between + URI Template characters and the octets used to store or transmit + those characters. When a URI Template appears in a protocol element, + the character encoding scheme is defined by that protocol; without + such a definition, a URI Template is assumed to be in the same + character encoding scheme as the surrounding text. It is only during + the process of template expansion that a string of characters in a + URI Template is REQUIRED to be processed as a sequence of Unicode + code points. + + The Unicode Standard [UNIV6] defines various equivalences between + sequences of characters for various purposes. Unicode Standard Annex + #15 [UTR15] defines various Normalization Forms for these + equivalences. The normalization form determines how to consistently + encode equivalent strings. In theory, all URI processing + implementations, including template processors, should use the same + normalization form for generating a URI reference. In practice, they + do not. If a value has been provided by the same server as the + resource, then it can be assumed that the string is already in the + form expected by that server. If a value is provided by a user, such + as via a data-entry dialog, then the string SHOULD be normalized as + Normalization Form C (NFC: Canonical Decomposition, followed by + Canonical Composition) prior to being used in expansions by a + template processor. + + Likewise, when non-ASCII data that represents readable strings is + pct-encoded for use in a URI reference, a template processor MUST + first encode the string as UTF-8 [RFC3629] and then pct-encode any + octets that are not allowed in a URI reference. + + + + +Gregorio, et al. Standards Track [Page 12] + +RFC 6570 URI Template March 2012 + + +2. Syntax + + A URI Template is a string of printable Unicode characters that + contains zero or more embedded variable expressions, each expression + being delimited by a matching pair of braces ('{', '}'). + + URI-Template = *( literals / expression ) + + Although templates (and template processor implementations) are + described above in terms of four gradual levels, we define the URI- + Template syntax in terms of the ABNF for Level 4. A template + processor limited to lower-level templates MAY exclude the ABNF rules + applicable only to higher levels. However, it is RECOMMENDED that + all parsers implement the full syntax such that unsupported levels + can be properly identified as such to the end user. + +2.1. Literals + + The characters outside of expressions in a URI Template string are + intended to be copied literally to the URI reference if the character + is allowed in a URI (reserved / unreserved / pct-encoded) or, if not + allowed, copied to the URI reference as the sequence of pct-encoded + triplets corresponding to that character's encoding in UTF-8 + [RFC3629]. + + literals = %x21 / %x23-24 / %x26 / %x28-3B / %x3D / %x3F-5B + / %x5D / %x5F / %x61-7A / %x7E / ucschar / iprivate + / pct-encoded + ; any Unicode character except: CTL, SP, + ; DQUOTE, "'", "%" (aside from pct-encoded), + ; "<", ">", "\", "^", "`", "{", "|", "}" + +2.2. Expressions + + Template expressions are the parameterized parts of a URI Template. + Each expression contains an optional operator, which defines the + expression type and its corresponding expansion process, followed by + a comma-separated list of variable specifiers (variable names and + optional value modifiers). If no operator is provided, the + expression defaults to simple variable expansion of unreserved + values. + + expression = "{" [ operator ] variable-list "}" + operator = op-level2 / op-level3 / op-reserve + op-level2 = "+" / "#" + op-level3 = "." / "/" / ";" / "?" / "&" + op-reserve = "=" / "," / "!" / "@" / "|" + + + + +Gregorio, et al. Standards Track [Page 13] + +RFC 6570 URI Template March 2012 + + + The operator characters have been chosen to reflect each of their + roles as reserved characters in the URI generic syntax. The + operators defined in Section 3 of this specification include: + + + Reserved character strings; + + # Fragment identifiers prefixed by "#"; + + . Name labels or extensions prefixed by "."; + + / Path segments prefixed by "/"; + + ; Path parameter name or name=value pairs prefixed by ";"; + + ? Query component beginning with "?" and consisting of + name=value pairs separated by "&"; and, + + & Continuation of query-style &name=value pairs within + a literal query component. + + The operator characters equals ("="), comma (","), exclamation ("!"), + at sign ("@"), and pipe ("|") are reserved for future extensions. + + The expression syntax specifically excludes use of the dollar ("$") + and parentheses ["(" and ")"] characters so that they remain + available for use outside the scope of this specification. For + example, a macro language might use these characters to apply macro + substitution to a string prior to that string being processed as a + URI Template. + +2.3. Variables + + After the operator (if any), each expression contains a list of one + or more comma-separated variable specifiers (varspec). The variable + names serve multiple purposes: documentation for what kinds of values + are expected, identifiers for associating values within a template + processor, and the literal string to use for the name in name=value + expansions (aside from when exploding an associative array). + Variable names are case-sensitive because the name might be expanded + within a case-sensitive URI component. + + variable-list = varspec *( "," varspec ) + varspec = varname [ modifier-level4 ] + varname = varchar *( ["."] varchar ) + varchar = ALPHA / DIGIT / "_" / pct-encoded + + + + + + +Gregorio, et al. Standards Track [Page 14] + +RFC 6570 URI Template March 2012 + + + A varname MAY contain one or more pct-encoded triplets. These + triplets are considered an essential part of the variable name and + are not decoded during processing. A varname containing pct-encoded + characters is not the same variable as a varname with those same + characters decoded. Applications that provide URI Templates are + expected to be consistent in their use of pct-encoding within + variable names. + + An expression MAY reference variables that are unknown to the + template processor or whose value is set to a special "undefined" + value, such as undef or null. Such undefined variables are given + special treatment by the expansion process (Section 3.2.1). + + A variable value that is a string of length zero is not considered + undefined; it has the defined value of an empty string. + + In Level 4 templates, a variable may have a composite value in the + form of a list of values or an associative array of (name, value) + pairs. Such value types are not directly indicated by the template + syntax, but they do have an impact on the expansion process + (Section 3.2.1). + + A variable defined as a list value is considered undefined if the + list contains zero members. A variable defined as an associative + array of (name, value) pairs is considered undefined if the array + contains zero members or if all member names in the array are + associated with undefined values. + +2.4. Value Modifiers + + Each of the variables in a Level 4 template expression can have a + modifier indicating either that its expansion is limited to a prefix + of the variable's value string or that its expansion is exploded as a + composite value in the form of a value list or an associative array + of (name, value) pairs. + + modifier-level4 = prefix / explode + +2.4.1. Prefix Values + + A prefix modifier indicates that the variable expansion is limited to + a prefix of the variable's value string. Prefix modifiers are often + used to partition an identifier space hierarchically, as is common in + reference indices and hash-based storage. It also serves to limit + the expanded value to a maximum number of characters. Prefix + modifiers are not applicable to variables that have composite values. + + + + + +Gregorio, et al. Standards Track [Page 15] + +RFC 6570 URI Template March 2012 + + + prefix = ":" max-length + max-length = %x31-39 0*3DIGIT ; positive integer < 10000 + + The max-length is a positive integer that refers to a maximum number + of characters from the beginning of the variable's value as a Unicode + string. Note that this numbering is in characters, not octets, in + order to avoid splitting between the octets of a multi-octet-encoded + character or within a pct-encoded triplet. If the max-length is + greater than the length of the variable's value, then the entire + value string is used. + + For example, + + Given the variable assignments + + var := "value" + semi := ";" + + Example Template Expansion + + {var} value + {var:20} value + {var:3} val + {semi} %3B + {semi:2} %3B + +2.4.2. Composite Values + + An explode ("*") modifier indicates that the variable is to be + treated as a composite value consisting of either a list of values or + an associative array of (name, value) pairs. Hence, the expansion + process is applied to each member of the composite as if it were + listed as a separate variable. This kind of variable specification + is significantly less self-documenting than non-exploded variables, + since there is less correspondence between the variable name and how + the URI reference appears after expansion. + + explode = "*" + + Since URI Templates do not contain an indication of type or schema, + the type for an exploded variable is assumed to be determined by + context. For example, the processor might be supplied values in a + form that differentiates values as strings, lists, or associative + arrays. Likewise, the context in which the template is used (script, + mark-up language, Interface Definition Language, etc.) might define + rules for associating variable names with types, structures, or + schema. + + + + +Gregorio, et al. Standards Track [Page 16] + +RFC 6570 URI Template March 2012 + + + Explode modifiers improve brevity in the URI Template syntax. For + example, a resource that provides a geographic map for a given street + address might accept a hundred permutations on fields for address + input, including partial addresses (e.g., just the city or postal + code). Such a resource could be described as a template with each + and every address component listed in order, or with a far more + simple template that makes use of an explode modifier, as in + + /mapper{?address*} + + along with some context that defines what the variable named + "address" can include, such as by reference to some other standard + for addressing (e.g., [UPU-S42]). A recipient aware of the schema + can then provide appropriate expansions, such as: + + /mapper?city=Newport%20Beach&state=CA + + The expansion process for exploded variables is dependent on both the + operator being used and whether the composite value is to be treated + as a list of values or as an associative array of (name, value) + pairs. Structures are processed as if they are an associative array + with names corresponding to the fields in the structure definition + and "." separators used to indicate name hierarchy in substructures. + + If a variable has a composite structure and only some of the fields + in that structure have defined values, then only the defined pairs + are present in the expansion. This can be useful for templates that + consist of a large number of potential query terms. + + An explode modifier applied to a list variable causes the expansion + to iterate over the list's member values. For path and query + parameter expansions, each member value is paired with the variable's + name as a (varname, value) pair. This allows path and query + parameters to be repeated for multiple values, as in + + Given the variable assignments + + year := ("1965", "2000", "2012") + dom := ("example", "com") + + Example Template Expansion + + find{?year*} find?year=1965&year=2000&year=2012 + www{.dom*} www.example.com + + + + + + + +Gregorio, et al. Standards Track [Page 17] + +RFC 6570 URI Template March 2012 + + +3. Expansion + + The process of URI Template expansion is to scan the template string + from beginning to end, copying literal characters and replacing each + expression with the result of applying the expression's operator to + the value of each variable named in the expression. Each variable's + value MUST be formed prior to template expansion. + + The requirements on expansion for each aspect of the URI Template + grammar are defined in this section. A non-normative algorithm for + the expansion process as a whole is provided in Appendix A. + + If a template processor encounters a character sequence outside an + expression that does not match the grammar, then + processing of the template SHOULD cease, the URI reference result + SHOULD contain the expanded part of the template followed by the + remainder unexpanded, and the location and type of error SHOULD be + indicated to the invoking application. + + If an error is encountered in an expression, such as an operator or + value modifier that the template processor does not recognize or does + not yet support, or a character is found that is not allowed by the + grammar, then the unprocessed parts of the expression + SHOULD be copied to the result unexpanded, processing of the + remainder of the template SHOULD continue, and the location and type + of error SHOULD be indicated to the invoking application. + + If an error occurs, the result returned might not be a valid URI + reference; it will be an incompletely expanded template string that + is only intended for diagnostic use. + +3.1. Literal Expansion + + If the literal character is allowed anywhere in the URI syntax + (unreserved / reserved / pct-encoded ), then it is copied directly to + the result string. Otherwise, the pct-encoded equivalent of the + literal character is copied to the result string by first encoding + the character as its sequence of octets in UTF-8 and then encoding + each such octet as a pct-encoded triplet. + +3.2. Expression Expansion + + Each expression is indicated by an opening brace ("{") character and + continues until the next closing brace ("}"). Expressions cannot be + nested. + + + + + + +Gregorio, et al. Standards Track [Page 18] + +RFC 6570 URI Template March 2012 + + + An expression is expanded by determining its expression type and then + following that type's expansion process for each comma-separated + varspec in the expression. Level 1 templates are limited to the + default operator (simple string value expansion) and a single + variable per expression. Level 2 templates are limited to a single + varspec per expression. + + The expression type is determined by looking at the first character + after the opening brace. If the character is an operator, then + remember the expression type associated with that operator for later + expansion decisions and skip to the next character for the variable- + list. If the first character is not an operator, then the expression + type is simple string expansion and the first character is the + beginning of the variable-list. + + The examples in the subsections below use the following definitions + for variable values: + + 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 + + A variable that is undefined (Section 2.3) has no value and is + ignored by the expansion process. If all of the variables in an + expression are undefined, then the expression's expansion is the + empty string. + + Variable expansion of a defined, non-empty value results in a + substring of allowed URI characters. As described in Section 1.6, + the expansion process is defined in terms of Unicode code points in + order to ensure that non-ASCII characters are consistently pct- + encoded in the resulting URI reference. One way for a template + + + +Gregorio, et al. Standards Track [Page 19] + +RFC 6570 URI Template March 2012 + + + processor to obtain a consistent expansion is to transcode the value + string to UTF-8 (if it is not already in UTF-8) and then transform + each octet that is not in the allowed set into the corresponding pct- + encoded triplet. Another is to map directly from the value's native + character encoding to the set of allowed URI characters, with any + remaining disallowed characters mapping to the sequence of pct- + encoded triplets that correspond to the octet(s) of that character + when encoded as UTF-8 [RFC3629]. + + The allowed set for a given expansion depends on the expression type: + reserved ("+") and fragment ("#") expansions allow the set of + characters in the union of ( unreserved / reserved / pct-encoded ) to + be passed through without pct-encoding, whereas all other expression + types allow only unreserved characters to be passed through without + pct-encoding. Note that the percent character ("%") is only allowed + as part of a pct-encoded triplet and only for reserved/fragment + expansion: in all other cases, a value character of "%" MUST be pct- + encoded as "%25" by variable expansion. + + If a variable appears more than once in an expression or within + multiple expressions of a URI Template, the value of that variable + MUST remain static throughout the expansion process (i.e., the + variable must have the same value for the purpose of calculating each + expansion). However, if reserved characters or pct-encoded triplets + occur in the value, they will be pct-encoded by some expression types + and not by others. + + For a variable that is a simple string value, expansion consists of + appending the encoded value to the result string. An explode + modifier has no effect. A prefix modifier limits the expansion to + the first max-length characters of the decoded value. If the value + contains multi-octet or pct-encoded characters, care must be taken to + avoid splitting the value in mid-character: count each Unicode code + point as one character. + + For a variable that is an associative array, expansion depends on + both the expression type and the presence of an explode modifier. If + there is no explode modifier, expansion consists of appending a + comma-separated concatenation of each (name, value) pair that has a + defined value. If there is an explode modifier, expansion consists + of appending each pair that has a defined value as either + "name=value" or, if the value is the empty string and the expression + type does not indicate form-style parameters (i.e., not a "?" or "&" + type), simply "name". Both name and value strings are encoded in the + same way as simple string values. A separator string is appended + between defined pairs according to the expression type, as defined by + the following table: + + + + +Gregorio, et al. Standards Track [Page 20] + +RFC 6570 URI Template March 2012 + + + Type Separator + "," (default) + + "," + # "," + . "." + / "/" + ; ";" + ? "&" + & "&" + + For a variable that is a list of values, expansion depends on both + the expression type and the presence of an explode modifier. If + there is no explode modifier, the expansion consists of a comma- + separated concatenation of the defined member string values. If + there is an explode modifier and the expression type expands named + parameters (";", "?", or "&"), then the list is expanded as if it + were an associative array in which each member value is paired with + the list's varname. Otherwise, the value will be expanded as if it + were a list of separate variable values, each value separated by the + expression type's associated separator as defined by the table above. + + Example Template Expansion + + {count} one,two,three + {count*} one,two,three + {/count} /one,two,three + {/count*} /one/two/three + {;count} ;count=one,two,three + {;count*} ;count=one;count=two;count=three + {?count} ?count=one,two,three + {?count*} ?count=one&count=two&count=three + {&count*} &count=one&count=two&count=three + +3.2.2. Simple String Expansion: {var} + + Simple string expansion is the default expression type when no + operator is given. + + For each defined variable in the variable-list, perform variable + expansion, as defined in Section 3.2.1, with the allowed characters + being those in the unreserved set. If more than one variable has a + defined value, append a comma (",") to the result string as a + separator between variable expansions. + + + + + + + + +Gregorio, et al. Standards Track [Page 21] + +RFC 6570 URI Template March 2012 + + + Example Template Expansion + + {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} + + Reserved expansion, as indicated by the plus ("+") operator for Level + 2 and above templates, is identical to simple string expansion except + that the substituted values may also contain pct-encoded triplets and + characters in the reserved set. + + For each defined variable in the variable-list, perform variable + expansion, as defined in Section 3.2.1, with the allowed characters + being those in the set (unreserved / reserved / pct-encoded). If + more than one variable has a defined value, append a comma (",") to + the result string as a separator between variable expansions. + + + + + + + + + + + + + + + + + + + + +Gregorio, et al. Standards Track [Page 22] + +RFC 6570 URI Template March 2012 + + + Example Template Expansion + + {+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 + up{+path}{var}/here up/foo/barvalue/here + {+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.4. Fragment Expansion: {#var} + + Fragment expansion, as indicated by the crosshatch ("#") operator for + Level 2 and above templates, is identical to reserved expansion + except that a crosshatch character (fragment delimiter) is appended + first to the result string if any of the variables are defined. + + Example Template Expansion + + {#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=, + + + + + + + +Gregorio, et al. Standards Track [Page 23] + +RFC 6570 URI Template March 2012 + + +3.2.5. Label Expansion with Dot-Prefix: {.var} + + Label expansion, as indicated by the dot (".") operator for Level 3 + and above templates, is useful for describing URI spaces with varying + domain names or path selectors (e.g., filename extensions). + + For each defined variable in the variable-list, append "." to the + result string and then perform variable expansion, as defined in + Section 3.2.1, with the allowed characters being those in the + unreserved set. + + Since "." is in the unreserved set, a value that contains a "." has + the effect of adding multiple labels. + + Example Template Expansion + + {.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} + + Path segment expansion, as indicated by the slash ("/") operator in + Level 3 and above templates, is useful for describing URI path + hierarchies. + + For each defined variable in the variable-list, append "/" to the + result string and then perform variable expansion, as defined in + Section 3.2.1, with the allowed characters being those in the + unreserved set. + + Note that the expansion process for path segment expansion is + identical to that of label expansion aside from the substitution of + "/" instead of ".". However, unlike ".", a "/" is a reserved + character and will be pct-encoded if found in a value. + + + + + +Gregorio, et al. Standards Track [Page 24] + +RFC 6570 URI Template March 2012 + + + Example Template Expansion + + {/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} + + Path-style parameter expansion, as indicated by the semicolon (";") + operator in Level 3 and above templates, is useful for describing URI + path parameters, such as "path;property" or "path;name=value". + + For each defined variable in the variable-list: + + o append ";" to the result string; + + o if the variable has a simple string value or no explode modifier + is given, then: + + * append the variable name (encoded as if it were a literal + string) to the result string; + + * if the variable's value is not empty, append "=" to the result + string; + + o perform variable expansion, as defined in Section 3.2.1, with the + allowed characters being those in the unreserved set. + + + + + + + + + + + + + +Gregorio, et al. Standards Track [Page 25] + +RFC 6570 URI Template March 2012 + + + Example Template Expansion + + {;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} + + Form-style query expansion, as indicated by the question-mark ("?") + operator in Level 3 and above templates, is useful for describing an + entire optional query component. + + For each defined variable in the variable-list: + + o append "?" to the result string if this is the first defined value + or append "&" thereafter; + + o if the variable has a simple string value or no explode modifier + is given, append the variable name (encoded as if it were a + literal string) and an equals character ("=") to the result + string; and, + + o perform variable expansion, as defined in Section 3.2.1, with the + allowed characters being those in the unreserved set. + + + Example Template Expansion + + {?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 + + + +Gregorio, et al. Standards Track [Page 26] + +RFC 6570 URI Template March 2012 + + +3.2.9. Form-Style Query Continuation: {&var} + + Form-style query continuation, as indicated by the ampersand ("&") + operator in Level 3 and above templates, is useful for describing + optional &name=value pairs in a template that already contains a + literal query component with fixed parameters. + + For each defined variable in the variable-list: + + o append "&" to the result string; + + o if the variable has a simple string value or no explode modifier + is given, append the variable name (encoded as if it were a + literal string) and an equals character ("=") to the result + string; and, + + o perform variable expansion, as defined in Section 3.2.1, with the + allowed characters being those in the unreserved set. + + + Example Template Expansion + + {&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 + + A URI Template does not contain active or executable content. + However, it might be possible to craft unanticipated URIs if an + attacker is given control over the template or over the variable + values within an expression that allows reserved characters in the + expansion. In either case, the security considerations are largely + determined by who provides the template, who provides the values to + use for variables within the template, in what execution context the + expansion occurs (client or server), and where the resulting URIs are + used. + + + + + + +Gregorio, et al. Standards Track [Page 27] + +RFC 6570 URI Template March 2012 + + + This specification does not limit where URI Templates might be used. + Current implementations exist within server-side development + frameworks and within client-side javascript for computed links or + forms. + + Within frameworks, templates usually act as guides for where data + might occur within later (request-time) URIs in client requests. + Hence, the security concerns are not in the templates themselves, but + rather in how the server extracts and processes the user-provided + data within a normal Web request. + + Within client-side implementations, a URI Template has many of the + same properties as HTML forms, except limited to URI characters and + possibly included in HTTP header field values instead of just message + body content. Care ought to be taken to ensure that potentially + dangerous URI reference strings, such as those beginning with + "javascript:", do not appear in the expansion unless both the + template and the values are provided by a trusted source. + + Other security considerations are the same as those for URIs, as + described in Section 7 of [RFC3986]. + +5. Acknowledgments + + The following people made contributions to this specification: Mike + Burrows, Michaeljohn Clement, DeWitt Clinton, John Cowan, Stephen + Farrell, Robbie Gates, Vijay K. Gurbani, Peter Johanson, Murray S. + Kucherawy, James H. Manger, Tom Petch, Marc Portier, Pete Resnick, + James Snell, and Jiankang Yao. + +6. References + +6.1. Normative References + + [ASCII] American National Standards Institute, "Coded Character + Set - 7-bit American Standard Code for Information + Interchange", ANSI X3.4, 1986. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", STD 63, RFC 3629, November 2003. + + [RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, + "Uniform Resource Identifier (URI): Generic Syntax", + STD 66, RFC 3986, January 2005. + + + + +Gregorio, et al. Standards Track [Page 28] + +RFC 6570 URI Template March 2012 + + + [RFC3987] Duerst, M. and M. Suignard, "Internationalized Resource + Identifiers (IRIs)", RFC 3987, January 2005. + + [RFC5234] Crocker, D. and P. Overell, "Augmented BNF for Syntax + Specifications: ABNF", STD 68, RFC 5234, January 2008. + + [RFC6365] Hoffman, P. and J. Klensin, "Terminology Used in + Internationalization in the IETF", BCP 166, RFC 6365, + September 2011. + + [UNIV6] The Unicode Consortium, "The Unicode Standard, Version + 6.0.0", (Mountain View, CA: The Unicode Consortium, + 2011. ISBN 978-1-936213-01-6), + . + + [UTR15] Davis, M. and M. Duerst, "Unicode Normalization Forms", + Unicode Standard Annex # 15, April 2003, + . + +6.2. Informative References + + [OpenSearch] Clinton, D., "OpenSearch 1.1", Draft 5, December 2011, + . + + [UPU-S42] Universal Postal Union, "International Postal Address + Components and Templates", UPU S42-1, November 2002, + . + + [WADL] Hadley, M., "Web Application Description Language", + World Wide Web Consortium Member Submission + SUBM-wadl-20090831, August 2009, + . + + [WSDL] Weerawarana, S., Moreau, J., Ryman, A., and R. + Chinnici, "Web Services Description Language (WSDL) + Version 2.0 Part 1: Core Language", World Wide Web + Consortium Recommendation REC-wsdl20-20070626, + June 2007, . + + + + + + + + + +Gregorio, et al. Standards Track [Page 29] + +RFC 6570 URI Template March 2012 + + +Appendix A. Implementation Hints + + The normative sections on expansion describe each operator with a + separate expansion process for the sake of descriptive clarity. In + actual implementations, we expect the expressions to be processed + left-to-right using a common algorithm that has only minor variations + in process per operator. This non-normative appendix describes one + such algorithm. + + Initialize an empty result string and its non-error state. + + Scan the template and copy literals to the result string (as in + Section 3.1) until an expression is indicated by a "{", an error is + indicated by the presence of a non-literals character other than "{", + or the template ends. When it ends, return the result string and its + current error or non-error state. + + o If an expression is found, scan the template to the next "}" and + extract the characters in between the braces. + + o If the template ends before a "}", then append the "{" and + extracted characters to the result string and return with an error + status indicating the expression is malformed. + + Examine the first character of the extracted expression for an + operator. + + o If the expression ended (i.e., is "{}"), an operator is found that + is unknown or unimplemented, or the character is not in the + varchar set (Section 2.3), then append "{", the extracted + expression, and "}" to the result string, remember that the result + is in an error state, and then go back to scan the remainder of + the template. + + o If a known and implemented operator is found, store the operator + and skip to the next character to begin the varspec-list. + + o Otherwise, store the operator as NUL (simple string expansion). + + Use the following value table to determine the processing behavior by + expression type operator. The entry for "first" is the string to + append to the result first if any of the expression's variables are + defined. The entry for "sep" is the separator to append to the + result before any second (or subsequent) defined variable expansion. + The entry for "named" is a boolean for whether or not the expansion + includes the variable or key name when no explode modifier is given. + The entry for "ifemp" is a string to append to the name if its + corresponding value is empty. The entry for "allow" indicates what + + + +Gregorio, et al. Standards Track [Page 30] + +RFC 6570 URI Template March 2012 + + + characters to allow unencoded within the value expansion: (U) means + any character not in the unreserved set will be encoded; (U+R) means + any character not in the union of (unreserved / reserved / pct- + encoding) will be encoded; and, for both cases, each disallowed + character is first encoded as its sequence of octets in UTF-8 and + then each such octet is encoded as a pct-encoded triplet. + + .------------------------------------------------------------------. + | NUL + . / ; ? & # | + |------------------------------------------------------------------| + | first | "" "" "." "/" ";" "?" "&" "#" | + | sep | "," "," "." "/" ";" "&" "&" "," | + | named | false false false false true true true false | + | ifemp | "" "" "" "" "" "=" "=" "" | + | allow | U U+R U U U U U U+R | + `------------------------------------------------------------------' + + With the above table in mind, process the variable-list as follows: + + For each varspec, extract a variable name and optional modifier from + the expression by scanning the variable-list until a character not in + the varname set is found or the end of the expression is reached. + + o If it is the end of the expression and the varname is empty, go + back to scan the remainder of the template. + + o If it is not the end of the expression and the last character + found indicates a modifier ("*" or ":"), remember that modifier. + If it is an explode ("*"), scan the next character. If it is a + prefix (":"), continue scanning the next one to four characters + for the max-length represented as a decimal integer and then, if + it is still not the end of the expression, scan the next + character. + + o If it is not the end of the expression and the last character + found is not a comma (","), append "{", the stored operator (if + any), the scanned varname and modifier, the remaining expression, + and "}" to the result string, remember that the result is in an + error state, and then go back to scan the remainder of the + template. + + Lookup the value for the scanned variable name, and then + + o If the varname is unknown or corresponds to a variable with an + undefined value (Section 2.3), then skip to the next varspec. + + + + + + +Gregorio, et al. Standards Track [Page 31] + +RFC 6570 URI Template March 2012 + + + o If this is the first defined variable for this expression, append + the first string for this expression type to the result string and + remember that it has been done. Otherwise, append the sep string + to the result string. + + o If this variable's value is a string, then + + * if named is true, append the varname to the result string using + the same encoding process as for literals, and + + + if the value is empty, append the ifemp string to the result + string and skip to the next varspec; + + + otherwise, append "=" to the result string. + + * if a prefix modifier is present and the prefix length is less + than the value string length in number of Unicode characters, + append that number of characters from the beginning of the + value string to the result string, after pct-encoding any + characters that are not in the allow set, while taking care not + to split multi-octet or pct-encoded triplet characters that + represent a single Unicode code point; + + * otherwise, append the value to the result string after pct- + encoding any characters that are not in the allow set. + + o else if no explode modifier is given, then + + * if named is true, append the varname to the result string using + the same encoding process as for literals, and + + + if the value is empty, append the ifemp string to the result + string and skip to the next varspec; + + + otherwise, append "=" to the result string; and + + * if this variable's value is a list, append each defined list + member to the result string, after pct-encoding any characters + that are not in the allow set, with a comma (",") appended to + the result between each defined list member; + + * if this variable's value is an associative array or any other + form of paired (name, value) structure, append each pair with a + defined value to the result string as "name,value", after pct- + encoding any characters that are not in the allow set, with a + comma (",") appended to the result between each defined pair. + + + + + +Gregorio, et al. Standards Track [Page 32] + +RFC 6570 URI Template March 2012 + + + o else if an explode modifier is given, then + + * if named is true, then for each defined list member or array + (name, value) pair with a defined value, do: + + + if this is not the first defined member/value, append the + sep string to the result string; + + + if this is a list, append the varname to the result string + using the same encoding process as for literals; + + + if this is a pair, append the name to the result string + using the same encoding process as for literals; + + + if the member/value is empty, append the ifemp string to the + result string; otherwise, append "=" and the member/value to + the result string, after pct-encoding any member/value + characters that are not in the allow set. + + * else if named is false, then + + + if this is a list, append each defined list member to the + result string, after pct-encoding any characters that are + not in the allow set, with the sep string appended to the + result between each defined list member. + + + if this is an array of (name, value) pairs, append each pair + with a defined value to the result string as "name=value", + after pct-encoding any characters that are not in the allow + set, with the sep string appended to the result between each + defined pair. + + When the variable-list for this expression is exhausted, go back to + scan the remainder of the template. + + + + + + + + + + + + + + + + + +Gregorio, et al. Standards Track [Page 33] + +RFC 6570 URI Template March 2012 + + +Authors' Addresses + + Joe Gregorio + Google + + EMail: joe@bitworking.org + URI: http://bitworking.org/ + + + Roy T. Fielding + Adobe Systems Incorporated + + EMail: fielding@gbiv.com + URI: http://roy.gbiv.com/ + + + Marc Hadley + The MITRE Corporation + + EMail: mhadley@mitre.org + URI: http://mitre.org/ + + + Mark Nottingham + Rackspace + + EMail: mnot@mnot.net + URI: http://www.mnot.net/ + + + David Orchard + Salesforce.com + + EMail: orchard@pacificspirit.com + URI: http://www.pacificspirit.com/ + + + + + + + + + + + + + + + + +Gregorio, et al. Standards Track [Page 34] + diff --git a/library/protocol/uri_template/doc/uritemplate-draft-gregorio-trunk.xml b/library/protocol/uri_template/doc/uritemplate-draft-gregorio-trunk.xml deleted file mode 100644 index bfaec3fa..00000000 --- a/library/protocol/uri_template/doc/uritemplate-draft-gregorio-trunk.xml +++ /dev/null @@ -1,1259 +0,0 @@ - - - - - - - - - - - ]> - - - - - - - - - - - - - - - - - - URI Template - - - Google -
- joe@bitworking.org - http://bitworking.org/ -
-
- - - Adobe Systems Incorporated -
- fielding@gbiv.com - http://roy.gbiv.com/ -
-
- - - Oracle -
- Marc.Hadley@oracle.com - http://oracle.com/ -
-
- - - -
- mnot@pobox.com - http://mnot.net/ -
-
- - - -
- http://www.pacificspirit.com/ -
-
- - - - - A URI Template is a compact sequence of characters - for describing a range of Uniform Resource Identifiers - through variable expansion. - This specification defines the URI Template - syntax and the process for expanding a URI Template into a - URI reference, along with guidelines for the - use of URI Templates on the Internet. - - - - - - To provide feedback on this Internet-Draft, join the - W3C URI - mailing list (http://lists.w3.org/Archives/Public/uri/). - - -
- - -
-
- - A Uniform Resource Identifier (URI) - is often used to identify a specific resource within a common - space of similar resources. For example, personal web spaces - are often delegated using a common pattern, such as - -
- http://example.com/~fred/ - http://example.com/~mark/ -
- - or a set of dictionary entries might be grouped in a hierarchy - by the first letter of the term, as in - -
- http://example.com/dictionary/c/cat - http://example.com/dictionary/d/dog -
- - or a service interface might be invoked with various user input - in a common pattern, as in - -
- http://example.com/search?q=cat&lang=en - http://example.com/search?q=chien&lang=fr -
- - URI Templates provide a mechanism for abstracting a space of - resource identifiers such that the variable parts can be easily - identified and described. URI templates can have many uses, - including discovery of available services, configuring resource - mappings, defining computed links, specifying interfaces, and - other forms of programmatic interaction with resources. - For example, the above resources could be described by the - following URI templates: - -
- http://example.com/~{username}/ - http://example.com/dictionary/{term:1}/{term} - http://example.com/search{?q,lang} -
- - We define the following terms: - - expression - - The text between '{' and '}', including the enclosing braces, - as defined in . - expansion - - The string result obtained from a template expression after - processing it according to its expression type, list of variable - names, and value modifiers, as defined in . - template processor - - A program or library that, given a URI Template and a set of - variables with values, transforms the template string into a - URI-reference by parsing the template for expressions and - substituting each one with its corresponding expansion. - - - - A URI Template provides both a structural description of a URI - space and, when variable values are provided, a simple instruction - on how to construct a URI corresponding to those values. - A URI Template is transformed into a URI-reference by replacing each - delimited expression with its value as defined by the - expression type and the values of variables named within the - expression. The expression types range from simple string - expansion to multiple key=value lists. The expansions - are based on the URI generic syntax, allowing an implementation - to process any URI Template without knowing the scheme-specific - requirements of every possible resulting URI. - - - For example, the following URI Template includes a - form-style parameter expression, as indicated by the "?" operator - appearing before the variable names. - -
- http://www.example.com/foo{?query,number} -
- - Each template expression describes, in a machine-readable manner, - how a URI is to be constructed. In this example, - the expansion process for templates beginning with the - question-mark ("?") operator follows the same pattern - as form-style interfaces on the World Wide Web. - -
- http://www.example.com/foo{?query,number} - \_____________/ - | - | - For each defined variable in [ 'query', 'number' ], - substitute "?" if it is the first substitution or "&" - thereafter, followed by the variable name, '=', and the - variable's value. -
- - If the variables have the values - -
- query := "mycelium" - number := 100 -
- - then the expansion of the above URI Template is - -
- http://www.example.com/foo?query=mycelium&number=100 -
- - Alternatively, if 'query' is undefined, then the expansion - would be - -
- http://www.example.com/foo?number=100 -
- - or if both variables are undefined, then it would be - -
- http://www.example.com/foo -
- - A URI Template may be provided in absolute form, as in the examples - above, or in relative form. A template MUST be expanded before the - resulting reference can be resolved from relative to absolute form. - - - Although the URI syntax is used for the result, the template - string is allowed to contain the broader set of characters - that can be found in IRI references . - A URI Template is therefore also an IRI template, and the result - of template processing can be transformed to an IRI by following - the process defined in Section 3.2 of . - -
- -
- - URI Templates are similar to a macro language with a fixed set of - macro definitions: the expression type determines the expansion - process. The default expression type is simple string expansion, wherein - a single named variable is replaced by its value as a string after UTF-8 - encoding the characters and then pct-encoding any octets that are - not in the unreserved set. - - - Since most template processors implemented prior to this specification - have only implemented the default expression type, we refer to these as - Level 1 templates. - -
-.-----------------------------------------------------------------. -| Level 1 examples, with variables having values of | -| | -| var := "value" | -| hello := "Hello World!" | -| empty := "" | -| undef := null | -| | -|-----------------------------------------------------------------| -| Op Expression Expansion | -|-----------------------------------------------------------------| -| | Simple string expansion (Sec 3.2.2) | -| | | -| | {var} value | -| | {hello} Hello%20World%21 | -| | O{empty}X OX | -| | O{undef}X OX | -`-----------------------------------------------------------------' -
- - Level 2 templates add the plus ("+") operator for expansion of - values that are allowed to include reserved characters. - -
-.-----------------------------------------------------------------. -| Level 2 examples, with variables having values of | -| | -| var := "value" | -| hello := "Hello World!" | -| empty := "" | -| undef := null | -| path := "/foo/bar" | -| | -|-----------------------------------------------------------------| -| Op Expression Expansion | -|-----------------------------------------------------------------| -| + | Reserved string expansion (Sec 3.2.3) | -| | | -| | {+var} value | -| | {+hello} Hello%20World! | -| | O{+empty}X OX | -| | O{+undef}X OX | -| | {+path}/here /foo/bar/here | -| | here?ref={+path} here?ref=/foo/bar | -| | up{+path}{var}/here up/foo/barvalue/here | -| | | -`-----------------------------------------------------------------' -
- - Level 3 templates add more complex operators for lists of - comma-separated values, dot-prefixed labels, slash-prefixed path - segments, semicolon-prefixed path parameters, and the forms-style - construction of a query syntax consisting of key=value pairs that - are separated by an ampersand character. - -
-.-----------------------------------------------------------------. -| Level 3 examples, with variables having values of | -| | -| var := "value" | -| hello := "Hello World!" | -| empty := "" | -| undef := null | -| path := "/foo/bar" | -| x := "1024" | -| y := "768" | -| | -|-----------------------------------------------------------------| -| Op Expression Expansion | -|-----------------------------------------------------------------| -| | String expansion with multiple variables (Sec 3.2.2) | -| | | -| | {x,y} 1024,768 | -| | {x,hello,y} 1024,Hello%20World%21,768 | -| | ?{x,empty} ?1024, | -| | ?{x,undef} ?1024 | -| | ?{undef,y} ?768 | -| | | -|-----+-----------------------------------------------------------| -| + | Reserved expansion with multiple variables (Sec 3.2.3) | -| | | -| | {+x,hello,y} 1024,Hello%20World!,768 | -| | {+path,x}/here /foo/bar,1024/here | -| | | -|-----+-----------------------------------------------------------| -| . | Label expansion, dot-prefixed (Sec 3.2.4) | -| | | -| | X{.var} X.value | -| | X{.empty} X. | -| | X{.undef} X | -| | | -|-----+-----------------------------------------------------------| -| / | Path segments, slash-prefixed (Sec 3.2.5) | -| | | -| | {/var} /value | -| | {/var,empty} /value/ | -| | {/var,undef} /value | -| | {/var,x}/here /value/1024/here | -| | | -|-----+-----------------------------------------------------------| -| ; | Path-style parameters, semicolon-prefixed (Sec 3.2.6) | -| | | -| | {;x,y} ;x=1024;y=768 | -| | {;x,y,empty} ;x=1024;y=768;empty | -| | {;x,y,undef} ;x=1024;y=768 | -| | | -|-----+-----------------------------------------------------------| -| ? | Form-style query, ampersand-separated (Sec 3.2.7) | -| | | -| | {?x,y} ?x=1024&y=768 | -| | {?x,y,empty} ?x=1024&y=768&empty= | -| | {?x,y,undef} ?x=1024&y=768 | -| | | -`-----------------------------------------------------------------' -
- - Finally, Level 4 templates add the ability to specify value modifiers - as a suffix to the variable name. The prefix modifier (":") indicates - that only a limited number of characters from the beginning of the - value are used by the expansion. The explode ("*") modifier tells - the expansion process to treat the value as a multivalued structure --- - a list of values or key=value pairs -- rather than as a single string. - -
-.-----------------------------------------------------------------. -| Level 4 examples, with variables having values of | -| | -| var := "value" | -| hello := "Hello World!" | -| path := "/foo/bar" | -| list := [ "red", "green", "blue" ] | -| keys := [("semi",";"),("dot","."),("comma",",")] | -| empty_keys := [] | -| | -| Op Expression Expansion | -|-----------------------------------------------------------------| -| | String expansion with value modifiers (Sec 3.2.2) | -| | | -| | {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 | -| | | -|-----+-----------------------------------------------------------| -| + | Reserved expansion with value modifiers (Sec 3.2.3) | -| | | -| | {+path:6}/here /foo/b/here | -| | {+list} red,green,blue | -| | {+list*} red,green,blue | -| | {+keys} semi,;,dot,.,comma,, | -| | {+keys*} semi=;,dot=.,comma=, | -| | | -|-----+-----------------------------------------------------------| -| . | Label expansion, dot-prefixed (Sec 3.2.4) | -| | | -| | 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 | -| | | -|-----+-----------------------------------------------------------| -| / | Path segments, slash-prefixed (Sec 3.2.5) | -| | | -| | {/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 | -| | | -|-----+-----------------------------------------------------------| -| ; | Path-style parameters, semicolon-prefixed (Sec 3.2.6) | -| | | -| | {;hello:5} ;hello=Hello | -| | {;list} ;list=red,green,blue | -| | {;list*} ;red;green;blue | -| | {;keys} ;keys=semi,%3B,dot,.,comma,%2C | -| | {;keys*} ;semi=%3B;dot=.;comma=%2C | -| | | -|-----+-----------------------------------------------------------| -| ? | Form-style query, ampersand-separated (Sec 3.2.7) | -| | | -| | {?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 | -| | | -`-----------------------------------------------------------------' -
-
- -
- - Mechanisms similar to URI Templates have been defined within - several specifications, including WSDL, WADL and OpenSearch. - This specification extends and formally defines the syntax so - that URI Templates can be used consistently across multiple - Internet applications and within Internet message fields, - while at the same time retaining compatibility with those - earlier definitions. - - - The URI Template syntax has been designed to carefully balance - the need for a powerful expansion mechanism with the need for - ease of implementation. The syntax is designed to be trivial - to parse while at the same time providing enough flexibility to - express many common template scenarios. Implementations are able - to parse the template and perform the expansions in a single pass. - - - Templates are simple and readable when used with common - examples because the single-character operators match the URI - generic syntax delimiters. The operator's associated delimiter - (";", "?", "/", and ".") is omitted when none of the listed variables - are defined. Likewise, the expansion process for ";" - (path-style parameters) will omit the "=" when the variable value - is empty, whereas the process for "?" (form-style parameters) - will not omit the "=" when the value is empty. Multiple variables - and list values have their values joined with "," if there is no - predefined joining mechanism for the operator. Only one operator, - plus ("+"), will substitute unencoded reserved characters found - inside the variable values; the other operators will pct-encode - reserved characters found in the variable values prior to expansion. - - - The most common cases for URI spaces can be described with - Level 1 template expressions. If we were only concerned with - URI generation, then the template syntax could be limited to - just simple variable expansion, since more complex forms could - be generated by changing the variable values. However, URI - Templates have the additional goal of describing the layout of - identifiers in terms of preexisting data values. The template - syntax therefore includes operators that reflect how - resource identifiers are commonly allocated. Likewise, since - prefix substrings are often used to partition large spaces of - resources, modifiers on variable values provide a way - to specify both the substring and the full value string - with a single variable name. - -
- -
- - Since a URI Template describes a superset of the identifiers, - there is no implication that every possible expansion for - each delimited variable expression corresponds to a URI of an - existing resource. Our expectation is that an application - constructing URIs according to the template will be provided - with an appropriate set of values for the variables being - substituted and will be able to cope with any errors that might - occur when the resulting URI is used for name resolution or access. - - - URI Templates are not URIs: they do not identify - an abstract or physical resource, they are not parsed as URIs, - and should not be used in places where a URI would be expected - unless the template expressions will be expanded by a template - processor prior to use. Distinct field, element, or attribute - names should be used to differentiate protocol elements that - carry a URI Template from those that expect a URI reference. - - - Some URI Templates can be used in reverse for the purpose of - variable matching: comparing the template to a fully formed - URI in order to extract the variable parts from that URI and - assign them to the named variables. Variable matching only works - well if the template expressions are delimited by the beginning or - end of the URI or by characters that cannot be part of the - expansion, such as reserved characters surrounding a simple - string expression. In general, regular expression languages - are better suited for variable matching. - -
- -
- - The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", - "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", - "MAY", and "OPTIONAL" in this document are to be - interpreted as described in . - - - This specification uses the Augmented Backus-Naur Form (ABNF) - notation of . The following ABNF rules - are imported from the normative references , - , and . - -
- ALPHA = %x41-5A / %x61-7A ; A-Z / a-z - DIGIT = %x30-39 ; 0-9 - HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F" - - pct-encoded = "%" HEXDIG HEXDIG - unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" - reserved = gen-delims / sub-delims - gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" - sub-delims = "!" / "$" / "&" / "'" / "(" / ")" - / "*" / "+" / "," / ";" / "=" - - ucschar = %xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF - / %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD - / %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD - / %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD - / %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD - / %xD0000-DFFFD / %xE1000-EFFFD - - iprivate = %xE000-F8FF / %xF0000-FFFFD / %x100000-10FFFD -
-
- -
- - This specification uses the terms "character" and "coded - character set" in accordance with the definitions provided - in , and "character encoding" in - place of what refers to as a "charset". - - - The ABNF notation defines its terminal values to be - non-negative integers (codepoints) that are a superset of the - US-ASCII coded character set . This - specification defines terminal values as codepoints within the - Unicode coded character set . - - - In spite of the syntax and template expansion process being defined - in terms of Unicode codepoints, it should be understood that - templates occur in practice as a sequence of characters in - whatever form or encoding is suitable for the context in which - they occur, whether that be octets embedded in a network protocol - element or paint applied to the side of a bus. - This specification does not mandate any particular character encoding - for mapping between URI Template characters and the octets used to - store or transmit those characters. - When a URI Template appears in a protocol element, the character - encoding is defined by that protocol; without such a definition, - a URI Template is assumed to be in the same character encoding as - the surrounding text. It is only during the process of template - expansion that a string of characters in a URI Template is REQUIRED - to be processed as a sequence of Unicode codepoints. - - - The Unicode Standard defines various - equivalences between sequences of characters for various purposes. - Unicode Standard Annex #15 defines various - Normalization Forms for these equivalences. The normalization form - determines how to consistently encode equivalent strings. - In theory, all URI processing implementations, including template - processors, should use the same normalization form for generating - a URI reference. In practice, they do not. If a value has been - provided by the same server as the resource, then it can be assumed - that the string is already in the form expected by that server. - If a value is provided by a user, such as via a data-entry dialog, - then the string SHOULD be normalized as Normalization Form C - (NFC: Canonical Decomposition, followed by Canonical Composition) - prior to being used in expansions by a template processor. - - - Likewise, when non-ASCII data that represents readable strings is - pct-encoded for use in a URI reference, a template processor MUST - first encode the string as UTF-8 and then - pct-encode any octets that are not allowed in a URI reference. - -
-
- -
- - A URI Template is a string of printable Unicode characters - that contains zero or more embedded variable expressions, each - expression being delimited by a matching pair of braces ('{', '}'). - -
- URI-Template = *( literals / expression ) -
- - Although templates (and template processor implementations) are - described above in terms of four gradual levels, we define the - URI-Template syntax in terms of the ABNF for Level 4. A template - processor limited to lower level templates MAY exclude the ABNF - rules applicable only to higher levels. However, it is RECOMMENDED - that all parsers implement the full syntax such that unsupported - levels can be properly identified as such to the end user. - - -
- - The characters outside of expressions in a URI Template string - are intended to be copied literally to the URI-reference if the - character is allowed in a URI (reserved / unreserved / pct-encoded) - or, if not allowed, copied to the URI-reference in its UTF-8 - pct-encoded form. - -
- literals = %x21 / %x23-24 / %x26 / %x28-3B / %x3D / %x3F-5B - / %x5D-5F / %x61-7A / %x7E / ucschar / iprivate - / pct-encoded - ; any Unicode character except: CTL, SP, - ; DQUOTE, "'", "%" (aside from pct-encoded), - ; "<", ">", "\", "^", "`", "{", "|", "}" -
-
- -
- - Template expressions are the parameterized parts of a URI Template. - Each expression contains an optional operator, which defines the - expression type and its corresponding expansion process, followed by a - comma-separated list of variable specifiers (variable names and - optional value modifiers). If no operator is provided, the expression - defaults to simple variable expansion of unreserved values. - -
- expression = "{" [ operator ] variable-list "}" - operator = "+" / "." / "/" / ";" / "?" / op-reserve - op-reserve = "=" / "," / "!" / "@" / "|" - ; reserved for local use: "$" / "(" / ")" -
- - - - The operator characters have been chosen to reflect each of their roles - as reserved characters in the URI generic syntax. The operators defined - by this specification include: - plus ("+") for substituting values that may contain reserved characters; - dot (".") for substituting values as a sequence of name labels prefixed - by "."; - slash ("/") for substituting values as a sequence of path segments - prefixed by "/"; - semicolon (";") for substituting key=value pairs as path parameters - prefixed by ";"; and, - question-mark ("?") for substituting a query component beginning - with "?" and consisting of key=value pairs separated by "&". - These operators will be described in detail in . - - - The operator characters equals ("="), comma (","), exclamation ("!"), - at-sign ("@"), and pipe ("|") are reserved for future extensions. - - - The expression syntax specifically excludes use of the dollar ("$") - and parentheses ["(" and ")"] characters so that they remain - available for local language extensions outside the scope of this - specification. - -
- -
- - After the operator (if any), each expression contains a list of - one or more comma-separated variable specifiers (varspec). - The variable names serve multiple purposes: documentation for - what kinds of values are expected, identifiers for associating - values within a template processor, and the string to use - for each key on key=value expansions. - -
- variable-list = varspec *( "," varspec ) - varspec = varname [ modifier ] - varname = varchar *( varchar / "." ) - varchar = ALPHA / DIGIT / "_" / ucschar / iprivate - / pct-encoded -
- - A varname MAY contain one or more pct-encoded triplets. If so, - these triplets MUST be decoded to octets prior to mapping the - varname to a variable name. If the expression type calls for the - variable name to be included in the expansion result, then the - template processor MAY use either the original pct-encoded varname - or the string corresponding to a minimally encoded version of - the mapped variable name. I.e., a varname containing unnecessarily - pct-encoded characters might be expanded to use those characters - directly instead. - - - An expression MAY reference variables that are unknown - to the template processor or whose value is set to a special - "undefined" value, such as undef or null. Such undefined - variables are given special treatment by the expansion process. - - - A variable value that is a string of length zero is not considered - undefined; it has the defined value of an empty string. - - - A variable may have a composite or structured value, such as a - list of values, an associative array of (key, value) pairs, or - a structure of components defined by some separate schema. - Such value types are not directly indicated by the template - syntax, but do have an impact on the expansion process. A - composite or structured value with zero member values is - considered undefined. - - - If a variable appears more than once in an expression or - within multiple expressions of a URI Template, the value of - that variable MUST remain static throughout the expansion - process (i.e., the variable must have the same value for the - purpose of calculating each expansion). - -
- -
- - Each of the variables in a Level 4 template expression can have - a modifier indicating either that its expansion is limited to a - prefix of the variable's value string or that its expansion is - exploded into components based on an external type or schema - associated with that variable. - -
- modifier = prefix / explode -
- -
- - A prefix modifier indicates that the variable expansion is limited - to a prefix of the variable's value string. Prefix modifiers are - often used to partition an identifier space hierarchically, as is - common in reference indices and hash-based storage. It also serves - to limit the expanded value to a maximum number of characters. - -
- prefix = ":" max-length - max-length = %x31-39 *DIGIT ; positive integer -
- - The max-length is a positive integer that refers to a maximum number - of characters from the beginning of the variable's value as a - Unicode string. - Note that this numbering is in characters, not octets, in order to - avoid splitting between the octets of a multi-octet UTF-8 encoded - character or within a pct-encoded triplet. - If the max-length is greater than the length of the variable's - value, then the entire value string is used. - - - For example, - -
- Given the variable assignments - - var := "value" - semi := ";" - - Example Template Expansion - - {var} value - {var:20} value - {var:3} val - {semi} %3B - {semi:2} %3B -
-
- -
- - An explode modifier ("*") indicates that the - variable represents a composite value that may be substituted - in full or partial forms, depending on the variable's type or - schema. Since URI Templates do not contain an indication of - type or schema, this is assumed to be determined by context. - An example context is a mark-up element or header field that - contains one attribute that is a template and one or more other - attributes that define the schema applicable to variables found - in the template. Likewise, a typed programming language might - differentiate variables as strings, lists, associative arrays, - or structures. - -
- explode = "*" -
- - Explode modifiers improve brevity in the URI Template syntax. - For example, a resource that provides a geographic map for a - given street address might accept a hundred permutations on - fields for address input, including partial addresses (e.g., - just the city or postal code). Such a resource could be - described as a template with each and every address component - listed in order, or with a far more simple template that makes - use of an explode modifier, as in - -
- /mapper{?address*} -
- - along with some context that defines what the variable named - "address" can include, such as by reference to some other - standard for addressing (e.g., UPU S42 or AS/NZS 4819:2003). - A recipient aware of the schema can then provide appropriate - expansions, such as: - -
- /mapper?city=Newport%20Beach&state=CA -
- - If an explode modifier is present, the expansion process for that - variable, as defined in , is dependent on - both the operator being used and the type or schema of the value - being substituted. - -
- -
- -
- -
- - The process of URI Template expansion is to scan the template - string from beginning to end, copying literal characters as-is - and replacing each expression with the result of applying the - expression's operator to the value of each variable named in - the expression. Each variable's value MUST be formed prior to - template expansion. - - - If a template processor encounters an error outside of an expression, - such as a character sequence that does not match the <URI-Template> - grammar, then processing of the template SHOULD cease, the URI-reference - result SHOULD be undefined, and the location and type of error SHOULD be - indicated to the invoking application. If an error is encountered inside - an expression, such as an operator or value modifier that it does not - recognize or cannot support, then the expression SHOULD be copied to - the result unexpanded, processing of the remainder of the template - SHOULD continue, and the location and type of error SHOULD be indicated - to the invoking application. In this latter case, the result returned - will not be a valid URI reference; it will be an incompletely expanded - template string that is only intended for diagnostic use. - - -
- - If the literal character is allowed anywhere in the URI - syntax (unreserved / reserved / pct-encoded ), then it is copied - directly to the result string. Otherwise, the pct-encoded equivalent - of the literal character is copied to the result string by - encoding the character in UTF-8 (a sequence of octets) and - then encoding each octet as a pct-encoded triplet. - -
- -
- - Each expression is indicated by an opening brace ("{") character - and continues until the next closing brace ("}"). The expression - is expanded by determining the expression type and then following - that type's expansion process for each comma-separated varspec - in the expression. Level 1 templates are limited to the default - operator (simple string value expansion) and a single variable - per expression. Level 2 templates are limited to a single - varspec per expression. - - - The expression type is determined by looking at the first - character after the opening brace. If the character is an - operator, then remember the expression type associated with - that operator for later expansion decisions and skip to the - next character for the varspec list. If the first character - is not an operator, then the expression type is simple - expansion and the first character is the beginning of the - varspec list. - - -
- - Regardless of the expression type, a variable that is undefined has - no value. A variable defined as a list or structure of component - values is considered undefined if the list contains zero members or - all of the structure's components are undefined. - - - If all of the variables in an expression are undefined, then the - expression's expansion is the empty string. - -
- -
- - Simple string expansion is the default expression type when no - operator is given. For each defined variable in the - variable-list, modify its value as indicated by the optional - modifiers (if any), encode the value as UTF-8, pct-encode any - octets that are not in the unreserved set, and then append - the encoded value to the result string. If more than one - value is appended, separate each value with a comma (","). - -
For example, - foo := "fred" - - "{foo}" -> "fred" - "{foo,foo}" -> "fred,fred" - "{bar,foo}" -> "fred" - "{bar|wilma}" -> "wilma" -
- - Level 1 and 2 templates are limited to single variable expressions - without modifiers or value structures. - Level 3 templates allow a list of variables. - Level 4 templates add compound variable types and value modifiers, - as follows: - - - For a variable defined as a single value string, the explode - modifier has no effect. The prefix modifier limits the - expansion to the first max-length characters of that single - value. If the value contains pct-encoded triplets, - multibyte UTF-8, or both, care must be taken to avoid - splitting the value in mid-character: count each Unicode - codepoint as one character. - - - For a variable defined as a list of values, when no value - modifier is present or the explode modifier is given, the - variable's string expansion consists of a concatenation - of the individual values with each value separated by a - comma (","). A prefix modifier has no effect. - - - A variable defined as an associative array is expanded as a list - of alternating key and value pairs, excluding any keys for which - the corresponding value is undefined, when no value modifier is - present. If the explode modifier is given, then the keys with - defined values are expanded as "key=value" pairs instead of - "key,value". A prefix modifier has no effect. - -
- -
- - Reserved expansion is identical to simple expansion except that the - substituted values may contain characters in the reserved set. - The reserved expansion operator "+" is defined for Level 2 - templates (and above). - -
For example, - foo := "That's right!" - - "{foo}" -> "That%27s%20right%21" - "{+foo}" -> "That%27s%20right!" - - base := "http://example.com/home/" - - "{base}index" -> "http%3A%2F%2Fexample.com%2Fhome%2Findex" - "{+base}index" -> "http://example.com/home/index" -
- - The same expansion process is followed as in - except that, instead of "pct-encode any octets that are not in - the unreserved set", we pct-encode any octets that are not in - either the reserved or unreserved sets. - -
- -
- - The dot (".") operator indicates that the expression type is label - expansion, which can be useful for describing URI spaces with - varying domain names or path selectors (e.g., filename extensions). - -
- For each variable in the variable-list that has a defined value: - - 1) modify its value as indicated by any optional modifiers; - - 2) encode the value as UTF-8; - - 3) pct-encode any octets that are not in the unreserved set; - - 4) append "." to the result string; and, - - 5) append the encoded value to the result string. -
- - Since "." is not in the reserved set, a value that contains - a "." has the effect of adding multiple labels. - -
For example, - foo := "fred" - - "{.foo}" -> ".fred" - "{.foo,foo}" -> ".fred.fred" - "{.bar,foo}" -> ".fred" - "{.bar|wilma}" -> ".wilma" -
- - Label expansion only applies to Level 3 and Level 4 templates. - Level 4 templates add compound variable types and value modifiers, - as follows: - - - For a variable defined as a single value string, the explode - modifier has no effect. The prefix modifier limits the - expansion to the first max-length characters of that single - value. If the value contains pct-encoded triplets, - multibyte UTF-8, or both, care must be taken to avoid - splitting the value in mid-character: count each Unicode - codepoint as one character. - - - For a variable defined as a list of values, when no value - modifier is present or the explode modifier is given, the - variable's string expansion consists of a concatenation - of the individual defined values with each value prepended - by a dot ("."). A prefix modifier has no effect. - - - When no value modifier is present, a variable defined as an - associative array is expanded by appending the (key, value) - pairs as alternating labels (i.e., ".key.value"), but - excluding any keys for which the corresponding value is - undefined. If the explode modifier is given, then the keys with - defined values are expanded as ".key=value" instead of - ".key.value". A prefix modifier has no effect. - -
- -
- - The slash ("/") operator indicates that the expression type is - hierarchical path segment expansion, which can be useful for - describing URI path hierarchies. - -
- For each variable in the variable-list with a defined value: - - 1) modify its value as indicated by any optional modifiers; - - 2) encode the value as UTF-8; - - 3) pct-encode any octets that are not in the unreserved set; - - 4) append "/" to the result string; and, - - 5) append the encoded value to the result string. -
- - Note that the expansion process for path segment expansion is - identical to that of label expansion aside from the substitution - of "/" instead of ".". - -
For example, - foo := "fred" - - "{/foo}" -> "/fred" - "{/foo,foo}" -> "/fred/fred" - "{/bar,foo}" -> "/fred" - "{/bar|wilma}" -> "/wilma" -
- - Label expansion only applies to Level 3 and Level 4 templates. - Level 4 templates add compound variable types and value modifiers, - as follows: - - - For a variable defined as a single value string, the explode - modifier has no effect. The prefix modifier limits the - expansion to the first max-length characters of that single - value. If the value contains pct-encoded triplets, - multibyte UTF-8, or both, care must be taken to avoid - splitting the value in mid-character: count each Unicode - codepoint as one character. - - - For a variable defined as a list of values, when no value - modifier is present or the explode modifier is given, the - variable's string expansion consists of a concatenation - of the individual defined values with each value prepended - by a slash ("/"). A prefix modifier has no effect. - - - When no value modifier is present, a variable defined as an - associative array is expanded by appending the (key, value) - pairs as alternating segments (i.e., "/key/value"), but - excluding any keys for which the corresponding value is - undefined. If the explode modifier is given, then the keys with - defined values are expanded as "/key=value" instead of - "/key/value". A prefix modifier has no effect. - -
- -
- - TBD. - -
- -
- - TBD. - -
- -
-
- -
- - A URI Template does not contain active or executable content. Other - security considerations are the same as those for URIs, as described - in section 7 of . - -
- -
- - No IANA actions are required by this document. - -
- -
- - The following people made significant contributions to this - specification: Mike Burrows, Michaeljohn Clement, DeWitt Clinton, - John Cowan, James H. Manger, Marc Portier, and James Snell. - -
-
- - - - &ASCII; - &UNIV4; - &UTR15; - &rfc2119; - &rfc2978; - &rfc3986; - &rfc3987; - &rfc3629; - &rfc5234; - - -
- - Parsing a valid URI Template expression does not require - building a parser from the given ABNF. Instead, the set of allowed - characters in each part of URI Template expression has been - chosen to avoid complex parsing, and breaking an expression into - its component parts can be achieved by a series of splits - of the character string. - - - TBD. - -
- -
- 06 - Removed template defaults for undefined variables. - Added paragraph on limitations of variable matching templates. - Replaced "offset" with "max-length" in definition of prefix. - Noted that IRI literals may need to be pct-encoded for the URI. - Removed NFKC requirement -- state that NFC should be applied only - for user-supplied data-entry values. - Removed pct-decode normalization process for entire template, since - that is a lot more than necessary -- just normalize the variable - names before mapping. - Fixed a lot of last-minute paste-o's in the examples. - Fixed Level 4 examples for unexploded keys to include the keys= - in the expansion. - - 05 - Introduced levels to differentiate between legacy, partial, - and full implementations of URI Templates. - Changed the default indicator to pipe ("|") to allow the defaults - to contain the equals character and thus remove the need for complex - defaulting for the different variable types. - Removed suffix, remainder, and labelled value expansion because - there didn't seem much interest in them. - Clarified that templates and values are processed as sequences of - Unicode codepoints rather than prematurely encoded as UTF-8, since - that is easier to explain and more consistent with common language - routines for processing Unicode strings. - - 04 - Changed the operator syntax to a single character that is - analogous to its reserved role within the URI generic syntax, - resulting in templates that are far more readable for the common - cases. Added value modifiers for prefix and suffix expansion. - Added explode modifiers to allow expansion of complex variables - and lists according to (external) variable types or schema. - Replaced use of "expansion" with "expression", since expansion - is traditionally used to refer to the result after expanding - a macro (not the macro itself). Made applicable to any hypertext - reference string, such that the process for template expansion - also includes transforming the surrounding string into a proper - URI-reference rather than assuming it is already in absolute URI form. - Rewrote the text accordingly. - 03 - Added more examples. Introduced error conditions and defined - their handling. Changed listjoin to list. Changed -append to -suffix, - and allowed -prefix and -suffix to accept list variables. Clarified - the handling of unicode. - 02 - Added operators and came up with coherent - percent-encoding and reserved character story. - Added large examples section which is extracted - and tested against the implementation. - - 01 - - 00 - Initial Revision. - -
-
-
diff --git a/library/protocol/uri_template/src/draft_05/uri_template_constants.e b/library/protocol/uri_template/src/draft_05/uri_template_constants.e deleted file mode 100644 index 6fc51bc2..00000000 --- a/library/protocol/uri_template/src/draft_05/uri_template_constants.e +++ /dev/null @@ -1,52 +0,0 @@ -note - description: "[ - Summary description for {URI_TEMPLATE_CONSTANTS}. - - see http://tools.ietf.org/html/draft-gregorio-uritemplate-05 - ]" - author: "" - date: "$Date$" - revision: "$Revision$" - -class - URI_TEMPLATE_CONSTANTS - -feature -- Operator - - Reserved_operator: CHARACTER = '+' - - Form_style_query_operator: CHARACTER = '?' - - Path_style_parameters_operator: CHARACTER = ';' - - Path_segment_operator: CHARACTER = '/' - - Label_operator: CHARACTER = '.' - -feature -- Separator - - Default_delimiter: CHARACTER = '|' --| Draft 05 - -feature -- Explode - - Explode_plus: CHARACTER = '+' - - Explode_star: CHARACTER = '*' - -feature -- Modified - - Modifier_substring: CHARACTER = ':' - - Modifier_remainder: CHARACTER = '^' - -note - copyright: "2011-2011, Eiffel Software and others" - license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" - source: "[ - Eiffel Software - 5949 Hollister Ave., Goleta, CA 93117 USA - Telephone 805-685-1006, Fax 805-685-6869 - Website http://www.eiffel.com - Customer support http://support.eiffel.com - ]" -end diff --git a/library/protocol/uri_template/src/uri_template.e b/library/protocol/uri_template/src/uri_template.e index be085f76..1a7587d5 100644 --- a/library/protocol/uri_template/src/uri_template.e +++ b/library/protocol/uri_template/src/uri_template.e @@ -1,12 +1,9 @@ note description: "[ - Summary description for {URI_TEMPLATE}. - - See http://tools.ietf.org/html/draft-gregorio-uritemplate-04 - - note for draft 05, check {URI_TEMPLATE_CONSTANTS}.Default_delimiter + Implementation of URI Template RFC6570. - ]" + See http://tools.ietf.org/html/rfc6570 + ]" legal: "See notice at end of class." status: "See notice at end of class." date: "$Date$" @@ -513,7 +510,7 @@ feature {NONE} -- Implementation end note - copyright: "2011-2012, Eiffel Software and others" + copyright: "2011-2012, Jocelyn Fiat, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/protocol/uri_template/src/uri_template_constants.e b/library/protocol/uri_template/src/uri_template_constants.e index eb66ad3e..86314e2a 100644 --- a/library/protocol/uri_template/src/uri_template_constants.e +++ b/library/protocol/uri_template/src/uri_template_constants.e @@ -2,9 +2,9 @@ note description: "[ Summary description for {URI_TEMPLATE_CONSTANTS}. - see http://tools.ietf.org/html/draft-gregorio-uritemplate-04 + see http://tools.ietf.org/html/rfc6570 ]" - author: "" + author: "Jocelyn Fiat" date: "$Date$" revision: "$Revision$" @@ -17,15 +17,19 @@ feature -- Operator Form_style_query_operator: CHARACTER = '?' + Form_style_query_continuation: CHARACTER = '&' + Path_style_parameters_operator: CHARACTER = ';' Path_segment_operator: CHARACTER = '/' + Fragment_expansion: CHARACTER = '#' + Label_operator: CHARACTER = '.' feature -- Separator - Default_delimiter: CHARACTER = '=' --| Draft 0.4 , change to '|' for Draft 0.5 + Default_delimiter: CHARACTER = '=' --| Not included in the RFC, but was part of previous Draft feature -- Explode diff --git a/library/protocol/uri_template/src/uri_template_expression.e b/library/protocol/uri_template/src/uri_template_expression.e index 3b10c095..7f658f4f 100644 --- a/library/protocol/uri_template/src/uri_template_expression.e +++ b/library/protocol/uri_template/src/uri_template_expression.e @@ -12,7 +12,7 @@ inherit DEBUG_OUTPUT export {NONE} all end - + URI_TEMPLATE_CONSTANTS export {NONE} all end @@ -72,6 +72,17 @@ feature -- Processing operator := '?' op_prefix := '?' op_delimiter := '&' + when form_style_query_continuation then + --| '&' + operator := '&' + op_prefix := '&' + op_delimiter := '&' + when fragment_expansion then + --| '#' + reserved := True + operator := '#' + op_prefix := '#' + op_delimiter := ',' when '|', '!', '@' then operator := exp[1] else @@ -238,7 +249,7 @@ feature {NONE} -- Implementation else a_buffer.append_character (delimiter_char) end - if l_use_default and (operator = Form_style_query_operator) and not vi.has_explode_star then + if l_use_default and (operator = Form_style_query_operator or operator = form_style_query_continuation or operator = path_style_parameters_operator) and not vi.has_explode_star then a_buffer.append (vi.name) if vi.has_explode_plus then a_buffer.append_character ('.') @@ -262,7 +273,7 @@ feature -- Status report end ;note - copyright: "2011-2011, Eiffel Software and others" + copyright: "2011-2012, Jocelyn Fiat, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/protocol/uri_template/src/uri_template_expression_variable.e b/library/protocol/uri_template/src/uri_template_expression_variable.e index eecff43b..d4aca4ac 100644 --- a/library/protocol/uri_template/src/uri_template_expression_variable.e +++ b/library/protocol/uri_template/src/uri_template_expression_variable.e @@ -45,12 +45,19 @@ feature {NONE} -- Initialization when Form_style_query_operator then --| '?' op_prefix := '?' op_separator := '&' + when form_style_query_continuation then --| '&' + op_prefix := '&' + op_separator := '&' when Path_style_parameters_operator then --| ';' op_prefix := ';' op_separator := ';' when Path_segment_operator then --| '/' op_prefix := '/' op_separator := '/' + when fragment_expansion then --| '#' + reserved := True + op_prefix := '#' + op_separator := ',' when Label_operator then --| '.' op_prefix := '.' op_separator := '.' @@ -169,7 +176,7 @@ feature -- Report create Result.make (20) if attached {READABLE_STRING_GENERAL} d as l_string then v_enc := url_encoded_string (modified_string (l_string), not reserved) - if op = Form_style_query_operator then + if op = Form_style_query_operator or op = form_style_query_continuation then Result.append (name) Result.append_character ('=') elseif op = Path_style_parameters_operator then @@ -183,7 +190,7 @@ feature -- Report if l_array.is_empty then if dft /= Void then inspect op - when Form_style_query_operator, Path_style_parameters_operator then + when Path_style_parameters_operator,Form_style_query_operator, form_style_query_continuation then if not l_has_explode then Result.append (name) Result.append_character ('=') @@ -195,6 +202,16 @@ feature -- Report end Result.append (dft.out) end + +-- if not explode_is_plus then +-- Result.append (name) +-- Result.append_character ('=') +-- Result.append (dft.out) +-- else +-- Result.append (name) +-- Result.append_character ('.') +-- Result.append (dft.out) +-- end when Path_segment_operator then if explode_is_plus then Result.append (name) @@ -220,7 +237,7 @@ feature -- Report else l_delimiter := ',' inspect op - when Form_style_query_operator then + when Form_style_query_operator, form_style_query_continuation, path_style_parameters_operator then Result.append (name) Result.append_character ('=') else @@ -242,6 +259,7 @@ feature -- Report if explode_is_plus then if (op = Form_style_query_operator and explode_is_plus) or + (op = form_style_query_continuation and explode_is_plus) or (op = Path_style_parameters_operator and l_has_explode) then Result.append (name) @@ -250,7 +268,7 @@ feature -- Report Result.append (name) Result.append_character ('.') end - elseif explode_is_star and op = Form_style_query_operator then + elseif explode_is_star and (op = Form_style_query_operator or op = form_style_query_continuation or op = path_style_parameters_operator) then Result.append (name) Result.append_character ('=') end @@ -269,7 +287,7 @@ feature -- Report if l_table.is_empty then if dft /= Void then inspect op - when Form_style_query_operator, Path_style_parameters_operator then + when Path_style_parameters_operator, Form_style_query_operator, form_style_query_continuation then if not l_has_explode then Result.append (name) Result.append_character ('=') @@ -281,6 +299,15 @@ feature -- Report end Result.append (dft.out) end +-- if not explode_is_plus then +-- Result.append (name) +-- Result.append_character ('=') +-- Result.append (dft.out) +-- else +-- Result.append (name) +-- Result.append_character ('.') +-- Result.append (dft.out) +-- end when Path_segment_operator then if explode_is_plus then Result.append (name) @@ -306,7 +333,7 @@ feature -- Report else l_delimiter := ',' inspect op - when Form_style_query_operator then + when Form_style_query_operator, form_style_query_continuation, path_style_parameters_operator then Result.append (name) Result.append_character ('=') else @@ -358,7 +385,7 @@ feature -- Report else v_enc := default_value end - if op = Form_style_query_operator then + if op = Form_style_query_operator or op = form_style_query_continuation then Result.append (name) if v_enc /= Void then Result.append_character ('=') @@ -400,7 +427,7 @@ feature {NONE} -- Implementation end ;note - copyright: "2011-2011, Eiffel Software and others" + copyright: "2011-2012, Jocelyn Fiat, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/protocol/uri_template/src/uri_template_match_result.e b/library/protocol/uri_template/src/uri_template_match_result.e index de475bfd..126178c6 100644 --- a/library/protocol/uri_template/src/uri_template_match_result.e +++ b/library/protocol/uri_template/src/uri_template_match_result.e @@ -57,26 +57,37 @@ feature -- Query feature -- Query: url-decoded - url_decoded_query_variable (n: READABLE_STRING_8): detachable READABLE_STRING_32 + encoded_name (n: READABLE_STRING_GENERAL): READABLE_STRING_8 + -- URL encoded name `n' + -- to be used with ..._variable functions + do + if attached {READABLE_STRING_32} n as n32 then + Result := url_encoded_string (n32) + else + Result := n.as_string_8 + end + end + + url_decoded_query_variable (n: READABLE_STRING_GENERAL): detachable READABLE_STRING_32 -- Unencoded value related to variable name `n' do - if attached query_variable (n) as v then + if attached query_variable (encoded_name (n)) as v then Result := url_decoded_string (v) end end - url_decoded_path_variable (n: READABLE_STRING_8): detachable READABLE_STRING_32 + url_decoded_path_variable (n: READABLE_STRING_GENERAL): detachable READABLE_STRING_32 -- Unencoded value related to variable name `n' do - if attached path_variable (n) as v then + if attached path_variable (encoded_name (n)) as v then Result := url_decoded_string (v) end end - url_decoded_variable (n: READABLE_STRING_8): detachable READABLE_STRING_32 + url_decoded_variable (n: READABLE_STRING_GENERAL): detachable READABLE_STRING_32 -- Unencoded value related to variable name `n' do - if attached variable (n) as v then + if attached variable (encoded_name (n)) as v then Result := url_decoded_string (v) end end @@ -85,7 +96,12 @@ feature {NONE} -- Implementation url_decoded_string (s: READABLE_STRING_8): READABLE_STRING_32 do - Result := url_encoder.decoded_string (s.as_string_8) + Result := url_encoder.decoded_string (s) + end + + url_encoded_string (s: READABLE_STRING_32): READABLE_STRING_8 + do + Result := url_encoder.encoded_string (s) end url_encoder: URL_ENCODER diff --git a/library/protocol/uri_template/tests/test_uri_template.e b/library/protocol/uri_template/tests/test_uri_template.e index 4c1a2a1d..847012b0 100644 --- a/library/protocol/uri_template/tests/test_uri_template.e +++ b/library/protocol/uri_template/tests/test_uri_template.e @@ -13,551 +13,462 @@ class inherit EQA_TEST_SET -feature -- Test routines +feature -- Expander https://github.com/uri-templates/uritemplate-test/blob/master/spec-examples.json - test_uri_template_parser + expander_level_1 note - testing: "uri-template" - do - uri_template_parse ("api/foo/{foo_id}/{?id,extra}", <<"foo_id">>, <<"id", "extra">>) - uri_template_parse ("weather/{state}/{city}?forecast={day}", <<"state", "city">>, <<"day">>) - uri_template_parse ("/hello/{name}.{format}", <<"name", "format">>, <<>>) - uri_template_parse ("/hello.{format}/{name}", <<"format", "name">>, <<>>) --- uri_template_parse ("/hello/{name}.{format}/foo{?foobar};crazy=IDEA", <<"name", "format">>, <<"foobar">>) - end - - test_uri_template_matcher - note - testing: "uri-template" - local - tpl: URI_TEMPLATE - do - create tpl.make ("/hello.{format}{/vars}") - uri_template_match (tpl, "/hello.json/foo/bar", <<["format", "json"], ["vars", "/foo/bar"], ["vars[1]", "foo"], ["vars[2]", "bar"]>>, <<>>) - - create tpl.make ("/hello.{format}{?op}") - uri_template_match (tpl, "/hello.json?op=foobar", <<["format", "json"]>>, << ["op", "foobar"]>>) - - - create tpl.make ("{version}/{id}") - uri_template_match (tpl, "v2/123", <<["version", "v2"], ["id" , "123"]>>, <<>>) - - create tpl.make ("api/{foo}{bar}/id/{id}") - uri_template_mismatch (tpl, "api/foobar/id/123") - - - create tpl.make ("api/foo/{foo_id}/{?id,extra}") - uri_template_match (tpl, "api/foo/bar/", <<["foo_id", "bar"]>>, <<>>) - uri_template_match (tpl, "api/foo/bar/?id=123", <<["foo_id", "bar"]>>, <<["id", "123"]>>) - uri_template_match (tpl, "api/foo/bar/?id=123&extra=test", <<["foo_id", "bar"]>>, <<["id", "123"], ["extra", "test"]>>) - uri_template_match (tpl, "api/foo/bar/?id=123&extra=test&one=more", <<["foo_id", "bar"]>>, <<["id", "123"], ["extra", "test"]>>) - uri_template_mismatch (tpl, "") - uri_template_mismatch (tpl, "/") - uri_template_mismatch (tpl, "foo/bar/?id=123") - uri_template_mismatch (tpl, "/api/foo/bar/") - uri_template_mismatch (tpl, "api/foo/bar") - - create tpl.make ("weather/{state}/{city}?forecast={day}") - uri_template_match (tpl, "weather/California/Goleta?forecast=today", <<["state", "California"], ["city", "Goleta"]>>, <<["day", "today"]>>) - - create tpl.make ("/hello") - uri_template_match (tpl, "/hello", <<>>, <<>>) - uri_template_mismatch (tpl, "/hello/Foo2") -- longer - uri_template_mismatch (tpl, "/hell") -- shorter - - create tpl.make ("/hello.{format}") - uri_template_match (tpl, "/hello.xml", <<["format", "xml"]>>, <<>>) - uri_template_mismatch (tpl, "/hello.xml/Bar") - - - create tpl.make ("/hello.{format}/{name}") - uri_template_match (tpl, "/hello.xml/Joce", <<["format", "xml"], ["name", "Joce"]>>, <<>>) - - create tpl.make ("/hello/{name}.{format}") - uri_template_match (tpl, "/hello/Joce.json", <<["name", "Joce"], ["format", "json"]>>, <<>>) - - create tpl.make ("/hello/{name}.{format}/foo") - uri_template_match (tpl, "/hello/Joce.xml/foo", <<["name", "Joce"], ["format", "xml"]>>, <<>>) - uri_template_mismatch (tpl, "/hello/Joce.xml/fooBAR") - - create tpl.make ("/hello{/vars}") - uri_template_match (tpl, "/hello/foo/bar", <<["vars", "/foo/bar"], ["vars[1]", "foo"], ["vars[2]", "bar"]>>, <<>>) - - --- create tpl.make ("/hello/{name}.{format}/foo{?foo};crazy={idea}") ----- uri_template_match (tpl, "/hello/Joce.xml/foo", <<["name", "Joce"], ["format", "xml"]>>, <<>>) --- uri_template_match (tpl, "/hello/Joce.xml/foo?foo=FOO", <<["name", "Joce"], ["format", "xml"]>>, <<["foo", "FOO"]>>) --- uri_template_match (tpl, "/hello/Joce.xml/foo;crazy=IDEA", <<["name", "Joce"], ["format", "xml"]>>, <<["idea", "IDEA"], ["crazy", "IDEA"]>>) - - end - - uri_template_string_errors: detachable LIST [STRING] - - test_uri_template_string_builder - note - testing: "uri-template" + testing: "uri-template-rfc" local ht: HASH_TABLE [detachable ANY, STRING] - empty_keys: HASH_TABLE [STRING, STRING] - empty_list: ARRAY [STRING] - favs: HASH_TABLE [detachable ANY, STRING] - keys: HASH_TABLE [STRING, STRING] - colors: ARRAY [STRING] - names: ARRAY [STRING] - semi_dot: HASH_TABLE [STRING, STRING] - vals: ARRAY [STRING] do - create ht.make (3) - ht.force ("FooBar", "foo_id") - ht.force ("That's right!", "extra") - ht.force ("123", "id") - ht.force ("California", "state") - ht.force ("Goleta", "city") - ht.force ("today", "day") + create ht.make (2) + ht.force ("value", "var") + ht.force ("Hello World!", "hello") + uri_template_string (ht, "{var}", "value") + uri_template_string (ht, "{hello}", "Hello%%20World%%21") + end + + expander_level_2 + note + testing: "uri-template-rfc" + local + ht: HASH_TABLE [detachable ANY, STRING] + do + create ht.make (2) + ht.force ("value", "var") + ht.force ("Hello World!", "hello") + ht.force ("/foo/bar", "path") + + uri_template_string (ht, "{+var}", "value") + uri_template_string (ht, "{+hello}", "Hello%%20World!") + uri_template_string (ht, "{+path}/here", "/foo/bar/here") + uri_template_string (ht, "here?ref={+path}", "here?ref=/foo/bar") + end + + expander_level_3 + note + testing: "uri-template-rfc" + local + ht: HASH_TABLE [detachable ANY, STRING] + do + create ht.make (2) ht.force ("value", "var") ht.force ("Hello World!", "hello") ht.force ("", "empty") ht.force ("/foo/bar", "path") ht.force ("1024", "x") ht.force ("768", "y") - ht.force ("fred", "foo") - ht.force ("That's right!", "foo2") - ht.force ("http://example.com/home/", "base") - names := <<"Fred", "Wilma", "Pebbles">> - ht.force (names, "name") - create favs.make (2) - favs.force ("red", "color") - favs.force ("high", "volume") - ht.force (favs, "favs") + uri_template_string (ht, "map?{x,y}", "map?1024,768") + uri_template_string (ht, "{x,hello,y}", "1024,Hello%%20World%%21,768") + uri_template_string (ht, "{+x,hello,y}", "1024,Hello%%20World!,768") + uri_template_string (ht, "{+path,x}/here", "/foo/bar,1024/here") + uri_template_string (ht, "{#x,hello,y}", "#1024,Hello%%20World!,768") + uri_template_string (ht, "{#path,x}/here", "#/foo/bar,1024/here") + uri_template_string (ht, "X{.var}", "X.value") + uri_template_string (ht, "X{.x,y}", "X.1024.768") + uri_template_string (ht, "{/var}", "/value") + uri_template_string (ht, "{/var,x}/here", "/value/1024/here") + uri_template_string (ht, "{;x,y}", ";x=1024;y=768") + uri_template_string (ht, "{;x,y,empty}", ";x=1024;y=768;empty") + uri_template_string (ht, "{?x,y}", "?x=1024&y=768") + uri_template_string (ht, "{?x,y,empty}", "?x=1024&y=768&empty=") + uri_template_string (ht, "?fixed=yes{&x}", "?fixed=yes&x=1024") + uri_template_string (ht, "{&x,y,empty}", "&x=1024&y=768&empty=") + end - create empty_list.make_empty - ht.force (empty_list,"empty_list") - - create empty_keys.make (0) - ht.force (empty_keys,"empty_keys") - - vals := <<"val1", "val2", "val3">> - ht.force (vals, "list") - create keys.make (2) - keys.force ("val1", "key1") - keys.force ("val2", "key2") - ht.force (keys, "keys") - - colors := <<"red", "green", "blue">> - create semi_dot.make (3) - semi_dot.force (";", "semi") - semi_dot.force (".", "dot") - semi_dot.force (",", "comma") + expander_level_4 + note + testing: "uri-template-rfc" + local + ht: HASH_TABLE [detachable ANY, STRING] + keys: HASH_TABLE [detachable ANY, STRING] + do + create ht.make (2) + ht.force ("value", "var") + ht.force ("Hello World!", "hello") + ht.force ("/foo/bar", "path") + ht.force (<<"red", "green", "blue">>, "list") + create keys.make (2) + keys.force (";", "semi") + keys.force (".", "dot") + keys.force (",", "comma") + ht.force (keys, "keys") create {ARRAYED_LIST [STRING]} uri_template_string_errors.make (10) - - --| Simple string expansion - uri_template_string (ht, "{var}", "value") - uri_template_string (ht, "{hello}", "Hello+World%%21") - uri_template_string (ht, "O{empty}X", "OX") - uri_template_string (ht, "O{undef}X", "OX") - - --| String expansion with defaults - uri_template_string (ht, "{var=default}", "value") - uri_template_string (ht, "O{empty=default}X", "OX") - uri_template_string (ht, "O{undef=default}X", "OdefaultX") - - --| Reserved expansion with defaults - uri_template_string (ht, "{+var}", "value") - uri_template_string (ht, "{+hello}", "Hello+World!") - uri_template_string (ht, "{+path}/here", "/foo/bar/here") - uri_template_string (ht, "here?ref={+path}", "here?ref=/foo/bar") - uri_template_string (ht, "up{+path}{x}/here", "up/foo/bar1024/here") - uri_template_string (ht, "up{+empty=/1}/here", "up/here") - uri_template_string (ht, "up{+undef=/1}/here", "up/1/here") - - --| String expansion with multiple variables - uri_template_string (ht, "{x,y}", "1024,768") - uri_template_string (ht, "{x,hello,y}", "1024,Hello+World%%21,768") - uri_template_string (ht, "?{x,empty}", "?1024,") - uri_template_string (ht, "?{x,undef}", "?1024") - uri_template_string (ht, "?{undef,y}", "?768") - uri_template_string (ht, "?{x,undef=0}", "?1024,0") - - --| Reserved expansion with multiple variables - uri_template_string (ht, "{+x,hello,y}", "1024,Hello+World!,768") - uri_template_string (ht, "{+path,x}/here", "/foo/bar,1024/here") - --| Label expansion, dot-prefixed - uri_template_string (ht, "X{.var}", "X.value") - uri_template_string (ht, "X{.empty}", "X.") - uri_template_string (ht, "X{.undef}", "X") - - --| Path segments, slash-prefixed - uri_template_string (ht, "{/var}", "/value") - uri_template_string (ht, "{/var,empty}", "/value/") - uri_template_string (ht, "{/var,undef}", "/value") - - --| Path-style parameters, semicolon-prefixed - uri_template_string (ht, "{;x,y}", ";x=1024;y=768") - uri_template_string (ht, "{;x,y,empty}", ";x=1024;y=768;empty") - uri_template_string (ht, "{;x,y,undef}", ";x=1024;y=768") - - --| Form-style query, ampersand-separated - uri_template_string (ht, "{?x,y}", "?x=1024&y=768") - uri_template_string (ht, "{?x,y,empty}", "?x=1024&y=768&empty=") - uri_template_string (ht, "{?x,y,undef}", "?x=1024&y=768") - - - ht.force (colors, "list") - ht.force (semi_dot, "keys") - --| String expansion with value modifiers uri_template_string (ht, "{var:3}", "val") uri_template_string (ht, "{var:30}", "value") - uri_template_string (ht, "{var^3}", "ue") - uri_template_string (ht, "{var^-3}", "va") - uri_template_string (ht, "{list}", "red,green,blue") uri_template_string (ht, "{list*}", "red,green,blue") - uri_template_string (ht, "{keys}", "semi,%%3B,dot,.,comma,%%2C") - uri_template_string (ht, "{keys*}", "semi=%%3B,dot=.,comma=%%2C") - --| Reserved expansion with value modifiers + + uri_template_string_x (ht, "{keys}", <<"comma,%%2C,dot,.,semi,%%3B", "comma,%%2C,semi,%%3B,dot,.", "dot,.,comma,%%2C,semi,%%3B", "dot,.,semi,%%3B,comma,%%2C", "semi,%%3B,comma,%%2C,dot,.", "semi,%%3B,dot,.,comma,%%2C" >>) + uri_template_string_x (ht, "{keys*}", <<"comma=%%2C,dot=.,semi=%%3B", "comma=%%2C,semi=%%3B,dot=.", "dot=.,comma=%%2C,semi=%%3B", "dot=.,semi=%%3B,comma=%%2C", "semi=%%3B,comma=%%2C,dot=.", "semi=%%3B,dot=.,comma=%%2C" >>) uri_template_string (ht, "{+path:6}/here", "/foo/b/here") uri_template_string (ht, "{+list}", "red,green,blue") uri_template_string (ht, "{+list*}", "red,green,blue") - uri_template_string (ht, "{+keys}", "semi,;,dot,.,comma,,") - uri_template_string (ht, "{+keys*}", "semi=;,dot=.,comma=,") - --| Label expansion, dot-prefixed + + uri_template_string_x (ht, "{+keys}", <<"comma,,,dot,.,semi,;", "comma,,,semi,;,dot,.", "dot,.,comma,,,semi,;", "dot,.,semi,;,comma,,", "semi,;,comma,,,dot,.", "semi,;,dot,.,comma,," >>) + uri_template_string_x (ht, "{+keys*}", <<"comma=,,dot=.,semi=;", "comma=,,semi=;,dot=.", "dot=.,comma=,,semi=;", "dot=.,semi=;,comma=,", "semi=;,comma=,,dot=.", "semi=;,dot=.,comma=," >>) + uri_template_string (ht, "{#path:6}/here", "#/foo/b/here") + uri_template_string (ht, "{#list}", "#red,green,blue") + uri_template_string (ht, "{#list*}", "#red,green,blue") + uri_template_string_x (ht, "{#keys}", <<"#comma,,,dot,.,semi,;", "#comma,,,semi,;,dot,.", "#dot,.,comma,,,semi,;", "#dot,.,semi,;,comma,,", "#semi,;,comma,,,dot,.", "#semi,;,dot,.,comma,," >>) + uri_template_string_x (ht, "{#keys*}", <<"#comma=,,dot=.,semi=;", "#comma=,,semi=;,dot=.", "#dot=.,comma=,,semi=;", "#dot=.,semi=;,comma=,", "#semi=;,comma=,,dot=.", "#semi=;,dot=.,comma=," >>) uri_template_string (ht, "X{.var:3}", "X.val") uri_template_string (ht, "X{.list}", "X.red,green,blue") uri_template_string (ht, "X{.list*}", "X.red.green.blue") - uri_template_string (ht, "X{.keys}", "X.semi,%%3B,dot,.,comma,%%2C") - uri_template_string (ht, "X{.keys*}", "X.semi=%%3B.dot=..comma=%%2C") - - --| Path segments, slash-prefixed + uri_template_string_x (ht, "X{.keys}", <<"X.comma,%%2C,dot,.,semi,%%3B", "X.comma,%%2C,semi,%%3B,dot,.", "X.dot,.,comma,%%2C,semi,%%3B", "X.dot,.,semi,%%3B,comma,%%2C", "X.semi,%%3B,comma,%%2C,dot,.", "X.semi,%%3B,dot,.,comma,%%2C" >>) uri_template_string (ht, "{/var:1,var}", "/v/value") uri_template_string (ht, "{/list}", "/red,green,blue") uri_template_string (ht, "{/list*}", "/red/green/blue") uri_template_string (ht, "{/list*,path:4}", "/red/green/blue/%%2Ffoo") - uri_template_string (ht, "{/keys}", "/semi,%%3B,dot,.,comma,%%2C") - uri_template_string (ht, "{/keys*}", "/semi=%%3B/dot=./comma=%%2C") - - --| Path-style parameters, semicolon-prefixed + uri_template_string_x (ht, "{/keys}", <<"/comma,%%2C,dot,.,semi,%%3B", "/comma,%%2C,semi,%%3B,dot,.", + "/dot,.,comma,%%2C,semi,%%3B", "/dot,.,semi,%%3B,comma,%%2C", + "/semi,%%3B,comma,%%2C,dot,.", "/semi,%%3B,dot,.,comma,%%2C" >>) + uri_template_string_x (ht, "{/keys*}", <<"/comma=%%2C/dot=./semi=%%3B", "/comma=%%2C/semi=%%3B/dot=.", + "/dot=./comma=%%2C/semi=%%3B", "/dot=./semi=%%3B/comma=%%2C", + "/semi=%%3B/comma=%%2C/dot=.", "/semi=%%3B/dot=./comma=%%2C" >>) uri_template_string (ht, "{;hello:5}", ";hello=Hello") - uri_template_string (ht, "{;list}", ";red,green,blue") - uri_template_string (ht, "{;list*}", ";red;green;blue") - uri_template_string (ht, "{;keys}", ";semi,%%3B,dot,.,comma,%%2C") - uri_template_string (ht, "{;keys*}", ";semi=%%3B;dot=.;comma=%%2C") - - --| Form-style query, ampersand-separated + uri_template_string (ht, "{;list}", ";list=red,green,blue") + uri_template_string (ht, "{;list*}", ";list=red;list=green;list=blue") + uri_template_string_x (ht, "{;keys}", <<";keys=comma,%%2C,dot,.,semi,%%3B", ";keys=comma,%%2C,semi,%%3B,dot,.", ";keys=dot,.,comma,%%2C,semi,%%3B", ";keys=dot,.,comma,%%2C,semi,%%3B", ";keys=semi,%%3B,comma,%%2C,dot,.", ";keys=semi,%%3B,dot,.,comma,%%2C" >>) + uri_template_string_x (ht, "{;keys*}", <<";comma=%%2C;dot=.;semi=%%3B", ";comma=%%2C;semi=%%3B;dot=.", ";dot=.;comma=%%2C;semi=%%3B", ";dot=.;semi=%%3B;comma=%%2C", ";semi=%%3B;comma=%%2C;dot=.", ";semi=%%3B;dot=.;comma=%%2C" >>) uri_template_string (ht, "{?var:3}", "?var=val") uri_template_string (ht, "{?list}", "?list=red,green,blue") uri_template_string (ht, "{?list*}", "?list=red&list=green&list=blue") - uri_template_string (ht, "{?keys}", "?keys=semi,%%3B,dot,.,comma,%%2C") - uri_template_string (ht, "{?keys*}", "?semi=%%3B&dot=.&comma=%%2C") + uri_template_string_x (ht, "{?keys}", <<"?keys=comma,%%2C,dot,.,semi,%%3B", "?keys=comma,%%2C,semi,%%3B,dot,.", "?keys=dot,.,comma,%%2C,semi,%%3B", "?keys=dot,.,semi,%%3B,comma,%%2C", "?keys=semi,%%3B,comma,%%2C,dot,.", "?keys=semi,%%3B,dot,.,comma,%%2C" >>) + uri_template_string_x (ht, "{?keys*}", <<"?comma=%%2C&dot=.&semi=%%3B", "?comma=%%2C&semi=%%3B&dot=.", "?dot=.&comma=%%2C&semi=%%3B", "?dot=.&semi=%%3B&comma=%%2C", "?semi=%%3B&comma=%%2C&dot=.", "?semi=%%3B&dot=.&comma=%%2C" >>) + uri_template_string (ht, "{&var:3}", "&var=val") + uri_template_string (ht, "{&list}", "&list=red,green,blue") + uri_template_string (ht, "{&list*}", "&list=red&list=green&list=blue") + uri_template_string_x (ht, "{&keys}", <<"&keys=comma,%%2C,dot,.,semi,%%3B", "&keys=comma,%%2C,semi,%%3B,dot,.", "&keys=dot,.,comma,%%2C,semi,%%3B", "&keys=dot,.,semi,%%3B,comma,%%2C", "&keys=semi,%%3B,comma,%%2C,dot,.", "&keys=semi,%%3B,dot,.,comma,%%2C" >>) + uri_template_string_x (ht, "{&keys*}", <<"&comma=%%2C&dot=.&semi=%%3B", "&comma=%%2C&semi=%%3B&dot=.", "&dot=.&comma=%%2C&semi=%%3B", "&dot=.&semi=%%3B&comma=%%2C", "&semi=%%3B&comma=%%2C&dot=.", "&semi=%%3B&dot=.&comma=%%2C" >>) assert ("all strings built", uri_template_string_errors = Void or (attached uri_template_string_errors as err and then err.is_empty)) end - test_uri_template_string_builder_extra - note - testing: "uri-template" +feature -- Expander https://github.com/uri-templates/uritemplate-test/blob/master/spec-examples-by-section.json + + examples_by_section_variables: HASH_TABLE [detachable ANY, STRING] local ht: HASH_TABLE [detachable ANY, STRING] - empty_keys: HASH_TABLE [STRING, STRING] - empty_list: ARRAY [STRING] - favs: HASH_TABLE [detachable ANY, STRING] - keys: HASH_TABLE [STRING, STRING] - colors: ARRAY [STRING] - names: ARRAY [STRING] - semi_dot: HASH_TABLE [STRING, STRING] - vals: ARRAY [STRING] + keys: HASH_TABLE [detachable ANY, STRING] do - create ht.make (3) - ht.force ("FooBar", "foo_id") - ht.force ("That's right!", "extra") - ht.force ("123", "id") - ht.force ("California", "state") - ht.force ("Goleta", "city") - ht.force ("today", "day") - - ht.force ("value", "var") + create ht.make (2) + ht.force (<<"one", "two", "three">>, "count") + ht.force (<<"example", "com">>, "dom") + ht.force ("me/too", "dub") ht.force ("Hello World!", "hello") - ht.force ("", "empty") + ht.force ("50%%", "half") + ht.force ("value", "var") + ht.force ("fred", "who") + ht.force ("http://example.com/home/", "base") ht.force ("/foo/bar", "path") + ht.force (<<"red", "green", "blue">>, "list") + create keys.make (2) + keys.force (",", "comma") + keys.force (".", "dot") + keys.force (";", "semi") + ht.force (keys, "keys") + ht.force ("6", "v") ht.force ("1024", "x") ht.force ("768", "y") - ht.force ("fred", "foo") - ht.force ("That's right!", "foo2") - ht.force ("http://example.com/home/", "base") + ht.force ("", "empty") + create keys.make (0) + ht.force (keys, "empty_keys") + ht.force (Void, "undef") + Result := ht + end - names := <<"Fred", "Wilma", "Pebbles">> - ht.force (names, "name") - create favs.make (2) - favs.force ("red", "color") - favs.force ("high", "volume") - ht.force (favs, "favs") + expander_variable_expansion + -- "3.2.1 Variable Expansion" + note + testing: "uri-template-rfc-ex" + local + ht: HASH_TABLE [detachable ANY, STRING] + do + ht := examples_by_section_variables - create empty_list.make_empty - ht.force (empty_list,"empty_list") + create {ARRAYED_LIST [STRING]} uri_template_string_errors.make (10) + uri_template_string (ht, "{count}", "one,two,three") + uri_template_string (ht, "{count*}", "one,two,three") + uri_template_string (ht, "{/count}", "/one,two,three") + uri_template_string (ht, "{/count*}", "/one/two/three") + uri_template_string (ht, "{;count}", ";count=one,two,three") + uri_template_string (ht, "{;count*}", ";count=one;count=two;count=three") + uri_template_string (ht, "{?count}", "?count=one,two,three") + uri_template_string (ht, "{?count*}", "?count=one&count=two&count=three") + uri_template_string (ht, "{&count*}", "&count=one&count=two&count=three") - create empty_keys.make (0) - ht.force (empty_keys,"empty_keys") + assert ("all strings built", uri_template_string_errors = Void or (attached uri_template_string_errors as err and then err.is_empty)) + end - vals := <<"val1", "val2", "val3">> - ht.force (vals, "list") - create keys.make (2) - keys.force ("val1", "key1") - keys.force ("val2", "key2") - ht.force (keys, "keys") - - colors := <<"red", "green", "blue">> - create semi_dot.make (3) - semi_dot.force (";", "semi") - semi_dot.force (".", "dot") - semi_dot.force (",", "comma") + expander_simple_string_expansion + -- "3.2.2 Simple String Expansion" + note + testing: "uri-template-rfc-ex" + local + ht: HASH_TABLE [detachable ANY, STRING] + do + ht := examples_by_section_variables create {ARRAYED_LIST [STRING]} uri_template_string_errors.make (10) - --| Addition to the spec - uri_template_string (ht, "api/foo/{foo_id}/{?id,extra}", - "api/foo/FooBar/?id=123&extra=That%%27s+right%%21") - - uri_template_string (ht, "api/foo/{foo_id}/{?id,empty,undef,extra}", - "api/foo/FooBar/?id=123&empty=&extra=That%%27s+right%%21") - - uri_template_string (ht, "weather/{state}/{city}?forecast={day}", - "weather/California/Goleta?forecast=today") - - - uri_template_string (ht, "{var=default}", "value") - uri_template_string (ht, "{undef=default}", "default") - uri_template_string (ht, "{undef:3=default}", "default") - - uri_template_string (ht, "x{empty}y", "xy") - uri_template_string (ht, "x{empty=_}y", "xy") - uri_template_string (ht, "x{undef}y", "xy") - uri_template_string (ht, "x{undef=_}y", "x_y") - - uri_template_string (ht, "x{.name=none}", "x.Fred,Wilma,Pebbles") - uri_template_string (ht, "x{.name*=none}", "x.Fred.Wilma.Pebbles") - uri_template_string (ht, "x{.empty}", "x.") - uri_template_string (ht, "x{.empty=none}", "x.") - uri_template_string (ht, "x{.undef}", "x") - uri_template_string (ht, "x{.undef=none}", "x.none") - - uri_template_string (ht, "x{/name=none}", "x/Fred,Wilma,Pebbles") - uri_template_string (ht, "x{/name*=none}", "x/Fred/Wilma/Pebbles") - uri_template_string (ht, "x{/undef}", "x") - uri_template_string (ht, "x{/undef=none}", "x/none") - uri_template_string (ht, "x{/empty}", "x/") - uri_template_string (ht, "x{/empty=none}", "x/") - uri_template_string (ht, "x{/empty_keys}", "x") - uri_template_string (ht, "x{/empty_keys=none}", "x/none") - uri_template_string (ht, "x{/empty_keys*}", "x") - uri_template_string (ht, "x{/empty_keys*=none}", "x/none") - - uri_template_string (ht, "x{;name=none}", "x;name=Fred,Wilma,Pebbles") - uri_template_string (ht, "x{;favs=none}", "x;favs=color,red,volume,high") - uri_template_string (ht, "x{;favs*=none}", "x;color=red;volume=high") - uri_template_string (ht, "x{;empty}", "x;empty") - uri_template_string (ht, "x{;empty=none}", "x;empty") - - uri_template_string (ht, "x{;undef}", "x") - uri_template_string (ht, "x{;undef=none}", "x;none") - uri_template_string (ht, "x{;undef=foo=y}", "x;foo=y") - - uri_template_string (ht, "x{?var=none}", "x?var=value") - uri_template_string (ht, "x{?favs=none}", "x?favs=color,red,volume,high") - uri_template_string (ht, "x{?favs*=none}", "x?color=red&volume=high") - uri_template_string (ht, "x{?empty}", "x?empty=") - uri_template_string (ht, "x{?empty=foo=none}", "x?empty=") - uri_template_string (ht, "x{?undef}", "x") - uri_template_string (ht, "x{?undef=foo=none}", "x?foo=none") - uri_template_string (ht, "x{?empty_keys}", "x") - uri_template_string (ht, "x{?empty_keys=none}", "x?none") - uri_template_string (ht, "x{?empty_keys=y=z}", "x?y=z") - uri_template_string (ht, "x{?empty_keys*=y=z}", "x?y=z") - - - ------ - - uri_template_string (ht, "x{empty_list}y", "xy") - uri_template_string (ht, "x{empty_list=_}y", "xy") - uri_template_string (ht, "x{empty_list*}y", "xy") - uri_template_string (ht, "x{empty_list*=_}y", "x_y") - uri_template_string (ht, "x{empty_list+}y", "xy") - uri_template_string (ht, "x{empty_list+=_}y", "xempty_list._y") - - uri_template_string (ht, "x{empty_keys}y", "xy") - uri_template_string (ht, "x{empty_keys=_}y", "xy") - uri_template_string (ht, "x{empty_keys*}y", "xy") - uri_template_string (ht, "x{empty_keys*=_}y", "x_y") - uri_template_string (ht, "x{empty_keys+}y", "xy") - uri_template_string (ht, "x{empty_keys+=_}y", "xempty_keys._y") - - uri_template_string (ht, "x{?name=none}", "x?name=Fred,Wilma,Pebbles") - uri_template_string (ht, "x{?favs=none}", "x?favs=color,red,volume,high") - uri_template_string (ht, "x{?favs*=none}", "x?color=red&volume=high") - uri_template_string (ht, "x{?favs+=none}", "x?favs.color=red&favs.volume=high") - - uri_template_string (ht, "x{?undef}", "x") - uri_template_string (ht, "x{?undef=none}", "x?undef=none") - uri_template_string (ht, "x{?empty}", "x?empty=") - uri_template_string (ht, "x{?empty=none}", "x?empty=") - - uri_template_string (ht, "x{?empty_list}", "x") - uri_template_string (ht, "x{?empty_list=none}", "x?empty_list=none") - uri_template_string (ht, "x{?empty_list*}", "x") - uri_template_string (ht, "x{?empty_list*=none}", "x?none") - uri_template_string (ht, "x{?empty_list+}", "x") - uri_template_string (ht, "x{?empty_list+=none}", "x?empty_list.none") - - uri_template_string (ht, "x{?empty_keys}", "x") - uri_template_string (ht, "x{?empty_keys=none}", "x?empty_keys=none") - uri_template_string (ht, "x{?empty_keys*}", "x") - uri_template_string (ht, "x{?empty_keys*=none}", "x?none") - uri_template_string (ht, "x{?empty_keys+}", "x") - uri_template_string (ht, "x{?empty_keys+=none}", "x?empty_keys.none") - - uri_template_string (ht, "x{;name=none}", "x;name=Fred,Wilma,Pebbles") - uri_template_string (ht, "x{;favs=none}", "x;favs=color,red,volume,high") - uri_template_string (ht, "x{;favs*=none}", "x;color=red;volume=high") - uri_template_string (ht, "x{;favs+=none}", "x;favs.color=red;favs.volume=high") - uri_template_string (ht, "x{;undef}", "x") - uri_template_string (ht, "x{;undef=none}", "x;undef=none") - uri_template_string (ht, "x{;undef=none}", "x;none") - uri_template_string (ht, "x{;empty}", "x;empty") - uri_template_string (ht, "x{;empty=none}", "x;empty") - - uri_template_string (ht, "x{;empty_list}", "x") - uri_template_string (ht, "x{;empty_list=none}", "x;empty_list=none") - uri_template_string (ht, "x{;empty_list*}", "x") - uri_template_string (ht, "x{;empty_list*=none}", "x;none") - uri_template_string (ht, "x{;empty_list+}", "x") - uri_template_string (ht, "x{;empty_list+=none}", "x;empty_list.none") - - uri_template_string (ht, "x{;empty_keys}", "x") - uri_template_string (ht, "x{;empty_keys=none}", "x;empty_keys=none") - uri_template_string (ht, "x{;empty_keys*}", "x") - uri_template_string (ht, "x{;empty_keys*=none}", "x;none") - uri_template_string (ht, "x{;empty_keys+}", "x") - uri_template_string (ht, "x{;empty_keys+=none}", "x;empty_keys.none") - - uri_template_string (ht, "x{/name=none}", "x/Fred,Wilma,Pebbles") - uri_template_string (ht, "x{/name*=none}", "x/Fred/Wilma/Pebbles") - uri_template_string (ht, "x{/name+=none}", "x/name.Fred/name.Wilma/name.Pebbles") - uri_template_string (ht, "x{/favs=none}", "x/color,red,volume,high") - uri_template_string (ht, "x{/favs*=none}", "x/color/red/volume/high") - uri_template_string (ht, "x{/favs+=none}", "x/favs.color/red/favs.volume/high") - - uri_template_string (ht, "x{/undef}", "x") - uri_template_string (ht, "x{/undef=none}", "x/none") - uri_template_string (ht, "x{/empty}", "x/") - uri_template_string (ht, "x{/empty=none}", "x/") - - uri_template_string (ht, "x{/empty_list}", "x") - uri_template_string (ht, "x{/empty_list=none}", "x/none") - uri_template_string (ht, "x{/empty_list*}", "x") - uri_template_string (ht, "x{/empty_list*=none}", "x/none") - uri_template_string (ht, "x{/empty_list+}", "x") - uri_template_string (ht, "x{/empty_list+=none}", "x/empty_list.none") - - uri_template_string (ht, "x{/empty_keys}", "x") - uri_template_string (ht, "x{/empty_keys=none}", "x/none") - uri_template_string (ht, "x{/empty_keys*}", "x") - uri_template_string (ht, "x{/empty_keys*=none}", "x/none") - uri_template_string (ht, "x{/empty_keys+}", "x") - uri_template_string (ht, "x{/empty_keys+=none}", "x/empty_keys.none") - - --| Simple expansion with comma-separated values uri_template_string (ht, "{var}", "value") - uri_template_string (ht, "{hello}", "Hello+World%%21") - uri_template_string (ht, "{path}/here", "%%2Ffoo%%2Fbar/here") + uri_template_string (ht, "{hello}", "Hello%%20World%%21") + uri_template_string (ht, "{half}", "50%%25") + uri_template_string (ht, "O{empty}X", "OX") + uri_template_string (ht, "O{undef}X", "OX") uri_template_string (ht, "{x,y}", "1024,768") - uri_template_string (ht, "{var=default}", "value") - uri_template_string (ht, "{undef=default}", "default") - uri_template_string (ht, "{list}", "val1,val2,val3") - uri_template_string (ht, "{list*}", "val1,val2,val3") - uri_template_string (ht, "{list+}", "list.val1,list.val2,list.val3") - uri_template_string (ht, "{keys}", "key1,val1,key2,val2") - uri_template_string (ht, "{keys*}", "key1,val1,key2,val2") - uri_template_string (ht, "{keys+}", "keys.key1,val1,keys.key2,val2") + uri_template_string (ht, "{x,hello,y}", "1024,Hello%%20World%%21,768") + uri_template_string (ht, "?{x,empty}", "?1024,") + uri_template_string (ht, "?{x,undef}", "?1024") + uri_template_string (ht, "?{undef,y}", "?768") + uri_template_string (ht, "{var:3}", "val") + uri_template_string (ht, "{var:30}", "value") + uri_template_string (ht, "{list}", "red,green,blue") + uri_template_string (ht, "{list*}", "red,green,blue") + uri_template_string (ht, "{keys}", "comma,%%2C,dot,.,semi,%%3B") + uri_template_string (ht, "{keys*}", "comma=%%2C,dot=.,semi=%%3B") + + assert ("all strings built", uri_template_string_errors = Void or (attached uri_template_string_errors as err and then err.is_empty)) + end + + expander_reserved_expansion + -- "3.2.3 Reserved Expansion" + note + testing: "uri-template-rfc-ex" + local + ht: HASH_TABLE [detachable ANY, STRING] + do + ht := examples_by_section_variables + + create {ARRAYED_LIST [STRING]} uri_template_string_errors.make (10) - --| Reserved expansion with comma-separated values uri_template_string (ht, "{+var}", "value") - uri_template_string (ht, "{+hello}", "Hello+World!") + uri_template_string (ht, "{+hello}", "Hello%%20World!") + uri_template_string (ht, "{+half}", "50%%25") + uri_template_string (ht, "{base}index", "http%%3A%%2F%%2Fexample.com%%2Fhome%%2Findex") + uri_template_string (ht, "{+base}index", "http://example.com/home/index") + uri_template_string (ht, "O{+empty}X", "OX") + uri_template_string (ht, "O{+undef}X", "OX") uri_template_string (ht, "{+path}/here", "/foo/bar/here") + uri_template_string (ht, "{+path:6}/here", "/foo/b/here") + uri_template_string (ht, "here?ref={+path}", "here?ref=/foo/bar") + uri_template_string (ht, "up{+path}{var}/here", "up/foo/barvalue/here") + uri_template_string (ht, "{+x,hello,y}", "1024,Hello%%20World!,768") uri_template_string (ht, "{+path,x}/here", "/foo/bar,1024/here") - uri_template_string (ht, "{+path}{x}/here", "/foo/bar1024/here") - uri_template_string (ht, "{+empty}/here", "/here") - uri_template_string (ht, "{+undef}/here", "/here") - uri_template_string (ht, "{+list}", "val1,val2,val3") - uri_template_string (ht, "{+list*}", "val1,val2,val3") - uri_template_string (ht, "{+list+}", "list.val1,list.val2,list.val3") - uri_template_string (ht, "{+keys}", "key1,val1,key2,val2") - uri_template_string (ht, "{+keys*}", "key1,val1,key2,val2") - uri_template_string (ht, "{+keys+}", "keys.key1,val1,keys.key2,val2") + uri_template_string (ht, "{+list}", "red,green,blue") + uri_template_string (ht, "{+list*}", "red,green,blue") + uri_template_string (ht, "{+keys}", "comma,,,dot,.,semi,;") + uri_template_string (ht, "{+keys*}", "comma=,,dot=.,semi=;") - --| Path-style parameters, semicolon-prefixed - uri_template_string (ht, "{;x,y}", ";x=1024;y=768") - uri_template_string (ht, "{;x,y,empty}", ";x=1024;y=768;empty") - uri_template_string (ht, "{;x,y,undef}", ";x=1024;y=768") - uri_template_string (ht, "{;list}", ";list=val1,val2,val3") -- DIFF - uri_template_string (ht, "{;list*}", ";val1;val2;val3") - uri_template_string (ht, "{;list+}", ";list=val1;list=val2;list=val3") - uri_template_string (ht, "{;keys}", ";key1,val1,key2,val2") - uri_template_string (ht, "{;keys*}", ";key1=val1;key2=val2") - uri_template_string (ht, "{;keys+}", ";keys.key1=val1;keys.key2=val2") + assert ("all strings built", uri_template_string_errors = Void or (attached uri_template_string_errors as err and then err.is_empty)) + end - --| Form-style parameters, ampersand-separated - uri_template_string (ht, "{?x,y}", "?x=1024&y=768") - uri_template_string (ht, "{?x,y,empty}", "?x=1024&y=768&empty=") - uri_template_string (ht, "{?x,y,undef}", "?x=1024&y=768") - uri_template_string (ht, "{?list}", "?list=val1,val2,val3") - uri_template_string (ht, "{?list*}", "?val1&val2&val3") - uri_template_string (ht, "{?list+}", "?list=val1&list=val2&list=val3") - uri_template_string (ht, "{?keys}", "?keys=key1,val1,key2,val2") - uri_template_string (ht, "{?keys*}", "?key1=val1&key2=val2") - uri_template_string (ht, "{?keys+}", "?keys.key1=val1&keys.key2=val2") + expander_fragment_expansion + -- "3.2.4 Fragment Expansion" + note + testing: "uri-template-rfc-ex" + local + ht: HASH_TABLE [detachable ANY, STRING] + do + ht := examples_by_section_variables - --| Hierarchical path segments, slash-separated + create {ARRAYED_LIST [STRING]} uri_template_string_errors.make (10) + + uri_template_string (ht, "{#var}", "#value") + uri_template_string (ht, "{#hello}", "#Hello%%20World!") + uri_template_string (ht, "{#half}", "#50%%25") + uri_template_string (ht, "foo{#empty}", "foo#") + uri_template_string (ht, "foo{#undef}", "foo") + uri_template_string (ht, "{#x,hello,y}", "#1024,Hello%%20World!,768") + uri_template_string (ht, "{#path,x}/here", "#/foo/bar,1024/here") + uri_template_string (ht, "{#path:6}/here", "#/foo/b/here") + uri_template_string (ht, "{#list}", "#red,green,blue") + uri_template_string (ht, "{#list*}", "#red,green,blue") + uri_template_string (ht, "{#keys}", "#comma,,,dot,.,semi,;") + + assert ("all strings built", uri_template_string_errors = Void or (attached uri_template_string_errors as err and then err.is_empty)) + end + + expander_label_expansion_with_dot_prefix + -- "3.2.5 Label Expansion with Dot-Prefix" + note + testing: "uri-template-rfc-ex" + local + ht: HASH_TABLE [detachable ANY, STRING] + do + ht := examples_by_section_variables + + create {ARRAYED_LIST [STRING]} uri_template_string_errors.make (10) + + uri_template_string (ht, "{.who}", ".fred") + uri_template_string (ht, "{.who,who}", ".fred.fred") + uri_template_string (ht, "{.half,who}", ".50%%25.fred") + uri_template_string (ht, "www{.dom*}", "www.example.com") + uri_template_string (ht, "X{.var}", "X.value") + uri_template_string (ht, "X{.var:3}", "X.val") + uri_template_string (ht, "X{.empty}", "X.") + uri_template_string (ht, "X{.undef}", "X") + uri_template_string (ht, "X{.list}", "X.red,green,blue") + uri_template_string (ht, "X{.list*}", "X.red.green.blue") + uri_template_string (ht, "X{.keys}", "X.comma,%%2C,dot,.,semi,%%3B") + uri_template_string (ht, "X{.keys*}", "X.comma=%%2C.dot=..semi=%%3B") + uri_template_string (ht, "X{.empty_keys}", "X") + uri_template_string (ht, "X{.empty_keys*}", "X") + + assert ("all strings built", uri_template_string_errors = Void or (attached uri_template_string_errors as err and then err.is_empty)) + end + + expander_path_segment_expansion + -- "3.2.6 Path Segment Expansion" + note + testing: "uri-template-rfc-ex" + local + ht: HASH_TABLE [detachable ANY, STRING] + do + ht := examples_by_section_variables + + create {ARRAYED_LIST [STRING]} uri_template_string_errors.make (10) + + uri_template_string (ht, "{/who}", "/fred") + uri_template_string (ht, "{/who,who}", "/fred/fred") + uri_template_string (ht, "{/half,who}", "/50%%25/fred") + uri_template_string (ht, "{/who,dub}", "/fred/me%%2Ftoo") uri_template_string (ht, "{/var}", "/value") uri_template_string (ht, "{/var,empty}", "/value/") uri_template_string (ht, "{/var,undef}", "/value") - uri_template_string (ht, "{/list}", "/val1,val2,val3") - uri_template_string (ht, "{/list*}", "/val1/val2/val3") - uri_template_string (ht, "{/list*,x}", "/val1/val2/val3/1024") - uri_template_string (ht, "{/list+}", "/list.val1/list.val2/list.val3") - uri_template_string (ht, "{/keys}", "/key1,val1,key2,val2") - uri_template_string (ht, "{/keys*}", "/key1/val1/key2/val2") - uri_template_string (ht, "{/keys+}", "/keys.key1/val1/keys.key2/val2") - - --| Label expansion, dot-prefixed - uri_template_string (ht, "X{.var}", "X.value") - uri_template_string (ht, "X{.empty}", "X.") - uri_template_string (ht, "X{.undef}", "X") - uri_template_string (ht, "X{.list}", "X.val1,val2,val3") - uri_template_string (ht, "X{.list*}", "X.val1.val2.val3") - uri_template_string (ht, "X{.list*,x}", "X.val1.val2.val3.1024") - uri_template_string (ht, "X{.list+}", "X.list.val1.list.val2.list.val3") - uri_template_string (ht, "X{.keys}", "X.key1,val1,key2,val2") - uri_template_string (ht, "X{.keys*}", "X.key1.val1.key2.val2") - uri_template_string (ht, "X{.keys+}", "X.keys.key1.val1.keys.key2.val2") - - --| Simple Expansion - uri_template_string (ht, "{foo}", "fred") - uri_template_string (ht, "{foo,foo}", "fred,fred") - uri_template_string (ht, "{bar,foo}", "fred") - uri_template_string (ht, "{bar=wilma}", "wilma") - - --| Reserved Expansion - uri_template_string (ht, "{foo2}", "That%%27s+right%%21") - uri_template_string (ht, "{+foo2}", "That%%27s+right!") - uri_template_string (ht, "{base}index", "http%%3A%%2F%%2Fexample.com%%2Fhome%%2Findex") - uri_template_string (ht, "{+base}index", "http://example.com/home/index") + uri_template_string (ht, "{/var,x}/here", "/value/1024/here") + uri_template_string (ht, "{/var:1,var}", "/v/value") + uri_template_string (ht, "{/list}", "/red,green,blue") + uri_template_string (ht, "{/list*}", "/red/green/blue") + uri_template_string (ht, "{/list*,path:4}", "/red/green/blue/%%2Ffoo") + uri_template_string (ht, "{/keys}", "/comma,%%2C,dot,.,semi,%%3B") + uri_template_string (ht, "{/keys*}", "/comma=%%2C/dot=./semi=%%3B") assert ("all strings built", uri_template_string_errors = Void or (attached uri_template_string_errors as err and then err.is_empty)) end + expander_path_style_parameter_expansion + -- "3.2.7 Path-Style Parameter Expansion" + note + testing: "uri-template-rfc-ex" + local + ht: HASH_TABLE [detachable ANY, STRING] + do + ht := examples_by_section_variables + + create {ARRAYED_LIST [STRING]} uri_template_string_errors.make (10) + + uri_template_string (ht, "{;who}", ";who=fred") + uri_template_string (ht, "{;half}", ";half=50%%25") + uri_template_string (ht, "{;empty}", ";empty") + uri_template_string (ht, "{;hello:5}", ";hello=Hello") + uri_template_string (ht, "{;v,empty,who}", ";v=6;empty;who=fred") + uri_template_string (ht, "{;v,bar,who}", ";v=6;who=fred") + uri_template_string (ht, "{;x,y}", ";x=1024;y=768") + uri_template_string (ht, "{;x,y,empty}", ";x=1024;y=768;empty") + uri_template_string (ht, "{;x,y,undef}", ";x=1024;y=768") + uri_template_string (ht, "{;list}", ";list=red,green,blue") + uri_template_string (ht, "{;list*}", ";list=red;list=green;list=blue") + uri_template_string (ht, "{;keys}", ";keys=comma,%%2C,dot,.,semi,%%3B") + uri_template_string (ht, "{;keys*}", ";comma=%%2C;dot=.;semi=%%3B") + + assert ("all strings built", uri_template_string_errors = Void or (attached uri_template_string_errors as err and then err.is_empty)) + end + + expander_form_style_query_expansion + -- "3.2.8 Form-Style Query Expansion" + note + testing: "uri-template-rfc-ex" + local + ht: HASH_TABLE [detachable ANY, STRING] + do + ht := examples_by_section_variables + + create {ARRAYED_LIST [STRING]} uri_template_string_errors.make (10) + + uri_template_string (ht, "{?who}", "?who=fred") + uri_template_string (ht, "{?half}", "?half=50%%25") + uri_template_string (ht, "{?x,y}", "?x=1024&y=768") + uri_template_string (ht, "{?x,y,empty}", "?x=1024&y=768&empty=") + uri_template_string (ht, "{?x,y,undef}", "?x=1024&y=768") + uri_template_string (ht, "{?var:3}", "?var=val") + uri_template_string (ht, "{?list}", "?list=red,green,blue") + uri_template_string (ht, "{?list*}", "?list=red&list=green&list=blue") + uri_template_string (ht, "{?keys}", "?keys=comma,%%2C,dot,.,semi,%%3B") + uri_template_string (ht, "{?keys*}", "?comma=%%2C&dot=.&semi=%%3B") + + assert ("all strings built", uri_template_string_errors = Void or (attached uri_template_string_errors as err and then err.is_empty)) + end + + expander_form_style_query_continuation + -- "3.2.9 Form-Style Query Continuation" + note + testing: "uri-template-rfc-ex" + local + ht: HASH_TABLE [detachable ANY, STRING] + do + ht := examples_by_section_variables + + create {ARRAYED_LIST [STRING]} uri_template_string_errors.make (10) + + uri_template_string (ht, "{&who}", "&who=fred") + uri_template_string (ht, "{&half}", "&half=50%%25") + uri_template_string (ht, "?fixed=yes{&x}", "?fixed=yes&x=1024") + uri_template_string (ht, "{&var:3}", "&var=val") + uri_template_string (ht, "{&x,y,empty}", "&x=1024&y=768&empty=") + uri_template_string (ht, "{&x,y,undef}", "&x=1024&y=768") + uri_template_string (ht, "{&list}", "&list=red,green,blue") + uri_template_string (ht, "{&list*}", "&list=red&list=green&list=blue") + uri_template_string (ht, "{&keys}", "&keys=comma,%%2C,dot,.,semi,%%3B") + uri_template_string (ht, "{&keys*}", "&comma=%%2C&dot=.&semi=%%3B") + + assert ("all strings built", uri_template_string_errors = Void or (attached uri_template_string_errors as err and then err.is_empty)) + end + +feature {NONE} -- Implementation + + uri_template_string_errors: detachable LIST [STRING] + + uri_template_string_x (a_ht: HASH_TABLE [detachable ANY, STRING]; a_expression: STRING; a_expected: ARRAY [STRING]) + local + tpl: URI_TEMPLATE + s: STRING + m: STRING + b: BOOLEAN + do + create tpl.make (a_expression) + s := tpl.expanded_string (a_ht) + across + a_expected as c + until + b + loop + b := b or s.same_string (c.item) + end + + if not b then + m := "Unexpected string for %"" + a_expression + "%" got %"" + s + "%" but expected either of " + across + a_expected as c + loop + m.append ("%"" + c.item + "%" ") + end + m.append ("%N") + if attached uri_template_string_errors as err then + print (m) + err.force (m) + else + assert (m, False) + end + end + end + uri_template_string (a_ht: HASH_TABLE [detachable ANY, STRING]; a_expression: STRING; a_expected: STRING) local tpl: URI_TEMPLATE @@ -577,95 +488,6 @@ feature -- Test routines end end - uri_template_parse (s: STRING_8; path_vars: ARRAY [STRING]; query_vars: ARRAY [STRING]) - local - u: URI_TEMPLATE - matched: BOOLEAN - i: INTEGER - do - create u.make (s) - u.parse - assert ("Template %""+ s +"%" is valid", u.is_valid) - if attached u.path_variable_names as vars then - matched := vars.count = path_vars.count - from - i := path_vars.lower - vars.start - until - not matched or i > path_vars.upper - loop - matched := vars.item.same_string (path_vars[i]) - vars.forth - i := i + 1 - end - else - matched := path_vars.is_empty - end - assert ("path variables matched for %""+ s +"%"", matched) - - if attached u.query_variable_names as vars then - matched := vars.count = query_vars.count - from - i := query_vars.lower - vars.start - until - not matched or i > query_vars.upper - loop - matched := vars.item.same_string (query_vars[i]) - vars.forth - i := i + 1 - end - else - matched := query_vars.is_empty - end - assert ("query variables matched %""+ s +"%"", matched) - end - - uri_template_mismatch (a_uri_template: URI_TEMPLATE; a_uri: STRING) - local - l_match: detachable URI_TEMPLATE_MATCH_RESULT - do - l_match := a_uri_template.match (a_uri) - assert ("uri %"" + a_uri + "%" does not match template %"" + a_uri_template.template + "%"", l_match = Void) - end - - uri_template_match (a_uri_template: URI_TEMPLATE; a_uri: STRING; path_res: ARRAY [TUPLE [name: STRING; value: STRING]]; query_res: ARRAY [TUPLE [name: STRING; value: STRING]]) - local - b: BOOLEAN - i: INTEGER - l_match: detachable URI_TEMPLATE_MATCH_RESULT - do - l_match := a_uri_template.match (a_uri) - if l_match /= Void then - if attached l_match.path_variables as path_ht then - b := path_ht.count = path_res.count - from - i := path_res.lower - until - not b or i > path_res.upper - loop - b := attached path_ht.item (path_res[i].name) as s and then s.same_string (path_res[i].value) - i := i + 1 - end - assert ("uri %"" + a_uri + "%" matched path variables", b) - end - if attached l_match.query_variables as query_ht then - b := query_ht.count >= query_res.count - from - i := query_res.lower - until - not b or i > query_res.upper - loop - b := attached query_ht.item (query_res[i].name) as s and then s.same_string (query_res[i].value) - i := i + 1 - end - assert ("uri %"" + a_uri + "%" matched query variables", b) - end - else - assert ("uri %"" + a_uri + "%" matched", False) - end - end - note copyright: "2011-2011, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" @@ -677,5 +499,3 @@ note Customer support http://support.eiffel.com ]" end - - diff --git a/library/protocol/uri_template/tests/draft_50/test_uri_template_draft_05.e b/library/protocol/uri_template/tests/test_uri_template_draft.e similarity index 58% rename from library/protocol/uri_template/tests/draft_50/test_uri_template_draft_05.e rename to library/protocol/uri_template/tests/test_uri_template_draft.e index e6cac60c..e6e8f95e 100644 --- a/library/protocol/uri_template/tests/draft_50/test_uri_template_draft_05.e +++ b/library/protocol/uri_template/tests/test_uri_template_draft.e @@ -8,53 +8,16 @@ note testing: "type/manual" class - TEST_URI_TEMPLATE_DRAFT_05 + TEST_URI_TEMPLATE_DRAFT inherit - EQA_TEST_SET + TEST_URI_TEMPLATE -feature -- Test routines - - test_uri_template_parser - note - testing: "uri-template-05" - do - uri_template_parse ("api/foo/{foo_id}/{?id,extra}", <<"foo_id">>, <<"id", "extra">>) - uri_template_parse ("weather/{state}/{city}?forecast={day}", <<"state", "city">>, <<"day">>) - end - - test_uri_template_matcher - note - testing: "uri-template-05" - local - tpl: URI_TEMPLATE - do - create tpl.make ("{version}/{id}") - uri_template_match (tpl, "v2/123", <<["version", "v2"], ["id" , "123"]>>, <<>>) - - create tpl.make ("api/{foo}{bar}/id/{id}") - uri_template_mismatch (tpl, "api/foobar/id/123") - - create tpl.make ("api/foo/{foo_id}/{?id,extra}") - uri_template_match (tpl, "api/foo/bar/", <<["foo_id", "bar"]>>, <<>>) - uri_template_match (tpl, "api/foo/bar/?id=123", <<["foo_id", "bar"]>>, <<["id", "123"]>>) - uri_template_match (tpl, "api/foo/bar/?id=123&extra=test", <<["foo_id", "bar"]>>, <<["id", "123"], ["extra", "test"]>>) - uri_template_match (tpl, "api/foo/bar/?id=123&extra=test&one=more", <<["foo_id", "bar"]>>, <<["id", "123"], ["extra", "test"]>>) - uri_template_mismatch (tpl, "") - uri_template_mismatch (tpl, "/") - uri_template_mismatch (tpl, "foo/bar/?id=123") - uri_template_mismatch (tpl, "/api/foo/bar/") - uri_template_mismatch (tpl, "api/foo/bar") - - create tpl.make ("weather/{state}/{city}?forecast={day}") - uri_template_match (tpl, "weather/California/Goleta?forecast=today", <<["state", "California"], ["city", "Goleta"]>>, <<["day", "today"]>>) - end - - uri_template_string_errors: detachable LIST [STRING] +feature -- Expander test_uri_template_string_builder note - testing: "uri-template-05" + testing: "uri-template" local ht: HASH_TABLE [detachable ANY, STRING] empty_keys: HASH_TABLE [STRING, STRING] @@ -115,34 +78,34 @@ feature -- Test routines --| Simple string expansion uri_template_string (ht, "{var}", "value") - uri_template_string (ht, "{hello}", "Hello+World%%21") + uri_template_string (ht, "{hello}", "Hello%%20World%%21") uri_template_string (ht, "O{empty}X", "OX") uri_template_string (ht, "O{undef}X", "OX") --| String expansion with defaults - uri_template_string (ht, "{var|default}", "value") - uri_template_string (ht, "O{empty|default}X", "OX") - uri_template_string (ht, "O{undef|default}X", "OdefaultX") + uri_template_string (ht, "{var=default}", "value") + uri_template_string (ht, "O{empty=default}X", "OX") + uri_template_string (ht, "O{undef=default}X", "OdefaultX") --| Reserved expansion with defaults uri_template_string (ht, "{+var}", "value") - uri_template_string (ht, "{+hello}", "Hello+World!") + uri_template_string (ht, "{+hello}", "Hello%%20World!") uri_template_string (ht, "{+path}/here", "/foo/bar/here") uri_template_string (ht, "here?ref={+path}", "here?ref=/foo/bar") uri_template_string (ht, "up{+path}{x}/here", "up/foo/bar1024/here") - uri_template_string (ht, "up{+empty|/1}/here", "up/here") - uri_template_string (ht, "up{+undef|/1}/here", "up/1/here") + uri_template_string (ht, "up{+empty=/1}/here", "up/here") + uri_template_string (ht, "up{+undef=/1}/here", "up/1/here") --| String expansion with multiple variables uri_template_string (ht, "{x,y}", "1024,768") - uri_template_string (ht, "{x,hello,y}", "1024,Hello+World%%21,768") + uri_template_string (ht, "{x,hello,y}", "1024,Hello%%20World%%21,768") uri_template_string (ht, "?{x,empty}", "?1024,") uri_template_string (ht, "?{x,undef}", "?1024") uri_template_string (ht, "?{undef,y}", "?768") - uri_template_string (ht, "?{x,undef|0}", "?1024,0") + uri_template_string (ht, "?{x,undef=0}", "?1024,0") --| Reserved expansion with multiple variables - uri_template_string (ht, "{+x,hello,y}", "1024,Hello+World!,768") + uri_template_string (ht, "{+x,hello,y}", "1024,Hello%%20World!,768") uri_template_string (ht, "{+path,x}/here", "/foo/bar,1024/here") --| Label expansion, dot-prefixed uri_template_string (ht, "X{.var}", "X.value") @@ -200,9 +163,9 @@ feature -- Test routines --| Path-style parameters, semicolon-prefixed uri_template_string (ht, "{;hello:5}", ";hello=Hello") - uri_template_string (ht, "{;list}", ";red,green,blue") - uri_template_string (ht, "{;list*}", ";red;green;blue") - uri_template_string (ht, "{;keys}", ";semi,%%3B,dot,.,comma,%%2C") + uri_template_string (ht, "{;list}", ";list=red,green,blue") + uri_template_string (ht, "{;list*}", ";list=red;list=green;list=blue") + uri_template_string (ht, "{;keys}", ";keys=semi,%%3B,dot,.,comma,%%2C") uri_template_string (ht, "{;keys*}", ";semi=%%3B;dot=.;comma=%%2C") --| Form-style query, ampersand-separated @@ -218,7 +181,7 @@ feature -- Test routines test_uri_template_string_builder_extra note - testing: "uri-template-05" + testing: "uri-template" local ht: HASH_TABLE [detachable ANY, STRING] empty_keys: HASH_TABLE [STRING, STRING] @@ -278,162 +241,162 @@ feature -- Test routines --| Addition to the spec uri_template_string (ht, "api/foo/{foo_id}/{?id,extra}", - "api/foo/FooBar/?id=123&extra=That%%27s+right%%21") + "api/foo/FooBar/?id=123&extra=That%%27s%%20right%%21") uri_template_string (ht, "api/foo/{foo_id}/{?id,empty,undef,extra}", - "api/foo/FooBar/?id=123&empty=&extra=That%%27s+right%%21") + "api/foo/FooBar/?id=123&empty=&extra=That%%27s%%20right%%21") uri_template_string (ht, "weather/{state}/{city}?forecast={day}", "weather/California/Goleta?forecast=today") - uri_template_string (ht, "{var|default}", "value") - uri_template_string (ht, "{undef|default}", "default") - uri_template_string (ht, "{undef:3|default}", "default") + uri_template_string (ht, "{var=default}", "value") + uri_template_string (ht, "{undef=default}", "default") + uri_template_string (ht, "{undef:3=default}", "default") uri_template_string (ht, "x{empty}y", "xy") - uri_template_string (ht, "x{empty|_}y", "xy") + uri_template_string (ht, "x{empty=_}y", "xy") uri_template_string (ht, "x{undef}y", "xy") - uri_template_string (ht, "x{undef|_}y", "x_y") + uri_template_string (ht, "x{undef=_}y", "x_y") - uri_template_string (ht, "x{.name|none}", "x.Fred,Wilma,Pebbles") - uri_template_string (ht, "x{.name*|none}", "x.Fred.Wilma.Pebbles") + uri_template_string (ht, "x{.name=none}", "x.Fred,Wilma,Pebbles") + uri_template_string (ht, "x{.name*=none}", "x.Fred.Wilma.Pebbles") uri_template_string (ht, "x{.empty}", "x.") - uri_template_string (ht, "x{.empty|none}", "x.") + uri_template_string (ht, "x{.empty=none}", "x.") uri_template_string (ht, "x{.undef}", "x") - uri_template_string (ht, "x{.undef|none}", "x.none") + uri_template_string (ht, "x{.undef=none}", "x.none") - uri_template_string (ht, "x{/name|none}", "x/Fred,Wilma,Pebbles") - uri_template_string (ht, "x{/name*|none}", "x/Fred/Wilma/Pebbles") + uri_template_string (ht, "x{/name=none}", "x/Fred,Wilma,Pebbles") + uri_template_string (ht, "x{/name*=none}", "x/Fred/Wilma/Pebbles") uri_template_string (ht, "x{/undef}", "x") - uri_template_string (ht, "x{/undef|none}", "x/none") + uri_template_string (ht, "x{/undef=none}", "x/none") uri_template_string (ht, "x{/empty}", "x/") - uri_template_string (ht, "x{/empty|none}", "x/") + uri_template_string (ht, "x{/empty=none}", "x/") uri_template_string (ht, "x{/empty_keys}", "x") - uri_template_string (ht, "x{/empty_keys|none}", "x/none") + uri_template_string (ht, "x{/empty_keys=none}", "x/none") uri_template_string (ht, "x{/empty_keys*}", "x") - uri_template_string (ht, "x{/empty_keys*|none}", "x/none") + uri_template_string (ht, "x{/empty_keys*=none}", "x/none") - uri_template_string (ht, "x{;name|none}", "x;name=Fred,Wilma,Pebbles") - uri_template_string (ht, "x{;favs|none}", "x;favs=color,red,volume,high") - uri_template_string (ht, "x{;favs*|none}", "x;color=red;volume=high") + uri_template_string (ht, "x{;name=none}", "x;name=Fred,Wilma,Pebbles") + uri_template_string (ht, "x{;favs=none}", "x;favs=color,red,volume,high") + uri_template_string (ht, "x{;favs*=none}", "x;color=red;volume=high") uri_template_string (ht, "x{;empty}", "x;empty") - uri_template_string (ht, "x{;empty|none}", "x;empty") + uri_template_string (ht, "x{;empty=none}", "x;empty") uri_template_string (ht, "x{;undef}", "x") - uri_template_string (ht, "x{;undef|none}", "x;none") - uri_template_string (ht, "x{;undef|foo=y}", "x;foo=y") + uri_template_string (ht, "x{;undef=none}", "x;none") + uri_template_string (ht, "x{;undef=foo=y}", "x;foo=y") - uri_template_string (ht, "x{?var|none}", "x?var=value") - uri_template_string (ht, "x{?favs|none}", "x?favs=color,red,volume,high") - uri_template_string (ht, "x{?favs*|none}", "x?color=red&volume=high") + uri_template_string (ht, "x{?var=none}", "x?var=value") + uri_template_string (ht, "x{?favs=none}", "x?favs=color,red,volume,high") + uri_template_string (ht, "x{?favs*=none}", "x?color=red&volume=high") uri_template_string (ht, "x{?empty}", "x?empty=") - uri_template_string (ht, "x{?empty|foo=none}", "x?empty=") + uri_template_string (ht, "x{?empty=foo=none}", "x?empty=") uri_template_string (ht, "x{?undef}", "x") - uri_template_string (ht, "x{?undef|foo=none}", "x?foo=none") + uri_template_string (ht, "x{?undef=foo=none}", "x?foo=none") uri_template_string (ht, "x{?empty_keys}", "x") - uri_template_string (ht, "x{?empty_keys|none}", "x?none") - uri_template_string (ht, "x{?empty_keys|y=z}", "x?y=z") - uri_template_string (ht, "x{?empty_keys*|y=z}", "x?y=z") + uri_template_string (ht, "x{?empty_keys=none}", "x?none") + uri_template_string (ht, "x{?empty_keys=y=z}", "x?y=z") + uri_template_string (ht, "x{?empty_keys*=y=z}", "x?y=z") ------ uri_template_string (ht, "x{empty_list}y", "xy") - uri_template_string (ht, "x{empty_list|_}y", "xy") + uri_template_string (ht, "x{empty_list=_}y", "xy") uri_template_string (ht, "x{empty_list*}y", "xy") - uri_template_string (ht, "x{empty_list*|_}y", "x_y") + uri_template_string (ht, "x{empty_list*=_}y", "x_y") uri_template_string (ht, "x{empty_list+}y", "xy") - uri_template_string (ht, "x{empty_list+|_}y", "xempty_list._y") + uri_template_string (ht, "x{empty_list+=_}y", "xempty_list._y") uri_template_string (ht, "x{empty_keys}y", "xy") - uri_template_string (ht, "x{empty_keys|_}y", "xy") + uri_template_string (ht, "x{empty_keys=_}y", "xy") uri_template_string (ht, "x{empty_keys*}y", "xy") - uri_template_string (ht, "x{empty_keys*|_}y", "x_y") + uri_template_string (ht, "x{empty_keys*=_}y", "x_y") uri_template_string (ht, "x{empty_keys+}y", "xy") - uri_template_string (ht, "x{empty_keys+|_}y", "xempty_keys._y") + uri_template_string (ht, "x{empty_keys+=_}y", "xempty_keys._y") - uri_template_string (ht, "x{?name|none}", "x?name=Fred,Wilma,Pebbles") - uri_template_string (ht, "x{?favs|none}", "x?favs=color,red,volume,high") - uri_template_string (ht, "x{?favs*|none}", "x?color=red&volume=high") - uri_template_string (ht, "x{?favs+|none}", "x?favs.color=red&favs.volume=high") + uri_template_string (ht, "x{?name=none}", "x?name=Fred,Wilma,Pebbles") + uri_template_string (ht, "x{?favs=none}", "x?favs=color,red,volume,high") + uri_template_string (ht, "x{?favs*=none}", "x?color=red&volume=high") + uri_template_string (ht, "x{?favs+=none}", "x?favs.color=red&favs.volume=high") uri_template_string (ht, "x{?undef}", "x") - uri_template_string (ht, "x{?undef|none}", "x?undef=none") + uri_template_string (ht, "x{?undef=none}", "x?undef=none") uri_template_string (ht, "x{?empty}", "x?empty=") - uri_template_string (ht, "x{?empty|none}", "x?empty=") + uri_template_string (ht, "x{?empty=none}", "x?empty=") uri_template_string (ht, "x{?empty_list}", "x") - uri_template_string (ht, "x{?empty_list|none}", "x?empty_list=none") + uri_template_string (ht, "x{?empty_list=none}", "x?empty_list=none") uri_template_string (ht, "x{?empty_list*}", "x") - uri_template_string (ht, "x{?empty_list*|none}", "x?none") + uri_template_string (ht, "x{?empty_list*=none}", "x?none") uri_template_string (ht, "x{?empty_list+}", "x") - uri_template_string (ht, "x{?empty_list+|none}", "x?empty_list.none") + uri_template_string (ht, "x{?empty_list+=none}", "x?empty_list.none") uri_template_string (ht, "x{?empty_keys}", "x") - uri_template_string (ht, "x{?empty_keys|none}", "x?empty_keys=none") + uri_template_string (ht, "x{?empty_keys=none}", "x?empty_keys=none") uri_template_string (ht, "x{?empty_keys*}", "x") - uri_template_string (ht, "x{?empty_keys*|none}", "x?none") + uri_template_string (ht, "x{?empty_keys*=none}", "x?none") uri_template_string (ht, "x{?empty_keys+}", "x") - uri_template_string (ht, "x{?empty_keys+|none}", "x?empty_keys.none") + uri_template_string (ht, "x{?empty_keys+=none}", "x?empty_keys.none") - uri_template_string (ht, "x{;name|none}", "x;name=Fred,Wilma,Pebbles") - uri_template_string (ht, "x{;favs|none}", "x;favs=color,red,volume,high") - uri_template_string (ht, "x{;favs*|none}", "x;color=red;volume=high") - uri_template_string (ht, "x{;favs+|none}", "x;favs.color=red;favs.volume=high") + uri_template_string (ht, "x{;name=none}", "x;name=Fred,Wilma,Pebbles") + uri_template_string (ht, "x{;favs=none}", "x;favs=color,red,volume,high") + uri_template_string (ht, "x{;favs*=none}", "x;color=red;volume=high") + uri_template_string (ht, "x{;favs+=none}", "x;favs.color=red;favs.volume=high") uri_template_string (ht, "x{;undef}", "x") - uri_template_string (ht, "x{;undef|none}", "x;undef=none") - uri_template_string (ht, "x{;undef|none}", "x;none") + uri_template_string (ht, "x{;undef=none}", "x;undef=none") + uri_template_string (ht, "x{;undef=none}", "x;none") uri_template_string (ht, "x{;empty}", "x;empty") - uri_template_string (ht, "x{;empty|none}", "x;empty") + uri_template_string (ht, "x{;empty=none}", "x;empty") uri_template_string (ht, "x{;empty_list}", "x") - uri_template_string (ht, "x{;empty_list|none}", "x;empty_list=none") + uri_template_string (ht, "x{;empty_list=none}", "x;empty_list=none") uri_template_string (ht, "x{;empty_list*}", "x") - uri_template_string (ht, "x{;empty_list*|none}", "x;none") + uri_template_string (ht, "x{;empty_list*=none}", "x;none") uri_template_string (ht, "x{;empty_list+}", "x") - uri_template_string (ht, "x{;empty_list+|none}", "x;empty_list.none") + uri_template_string (ht, "x{;empty_list+=none}", "x;empty_list.none") uri_template_string (ht, "x{;empty_keys}", "x") - uri_template_string (ht, "x{;empty_keys|none}", "x;empty_keys=none") + uri_template_string (ht, "x{;empty_keys=none}", "x;empty_keys=none") uri_template_string (ht, "x{;empty_keys*}", "x") - uri_template_string (ht, "x{;empty_keys*|none}", "x;none") + uri_template_string (ht, "x{;empty_keys*=none}", "x;none") uri_template_string (ht, "x{;empty_keys+}", "x") - uri_template_string (ht, "x{;empty_keys+|none}", "x;empty_keys.none") + uri_template_string (ht, "x{;empty_keys+=none}", "x;empty_keys.none") - uri_template_string (ht, "x{/name|none}", "x/Fred,Wilma,Pebbles") - uri_template_string (ht, "x{/name*|none}", "x/Fred/Wilma/Pebbles") - uri_template_string (ht, "x{/name+|none}", "x/name.Fred/name.Wilma/name.Pebbles") - uri_template_string (ht, "x{/favs|none}", "x/color,red,volume,high") - uri_template_string (ht, "x{/favs*|none}", "x/color/red/volume/high") - uri_template_string (ht, "x{/favs+|none}", "x/favs.color/red/favs.volume/high") + uri_template_string (ht, "x{/name=none}", "x/Fred,Wilma,Pebbles") + uri_template_string (ht, "x{/name*=none}", "x/Fred/Wilma/Pebbles") + uri_template_string (ht, "x{/name+=none}", "x/name.Fred/name.Wilma/name.Pebbles") + uri_template_string (ht, "x{/favs=none}", "x/color,red,volume,high") + uri_template_string (ht, "x{/favs*=none}", "x/color/red/volume/high") + uri_template_string (ht, "x{/favs+=none}", "x/favs.color/red/favs.volume/high") uri_template_string (ht, "x{/undef}", "x") - uri_template_string (ht, "x{/undef|none}", "x/none") + uri_template_string (ht, "x{/undef=none}", "x/none") uri_template_string (ht, "x{/empty}", "x/") - uri_template_string (ht, "x{/empty|none}", "x/") + uri_template_string (ht, "x{/empty=none}", "x/") uri_template_string (ht, "x{/empty_list}", "x") - uri_template_string (ht, "x{/empty_list|none}", "x/none") + uri_template_string (ht, "x{/empty_list=none}", "x/none") uri_template_string (ht, "x{/empty_list*}", "x") - uri_template_string (ht, "x{/empty_list*|none}", "x/none") + uri_template_string (ht, "x{/empty_list*=none}", "x/none") uri_template_string (ht, "x{/empty_list+}", "x") - uri_template_string (ht, "x{/empty_list+|none}", "x/empty_list.none") + uri_template_string (ht, "x{/empty_list+=none}", "x/empty_list.none") uri_template_string (ht, "x{/empty_keys}", "x") - uri_template_string (ht, "x{/empty_keys|none}", "x/none") + uri_template_string (ht, "x{/empty_keys=none}", "x/none") uri_template_string (ht, "x{/empty_keys*}", "x") - uri_template_string (ht, "x{/empty_keys*|none}", "x/none") + uri_template_string (ht, "x{/empty_keys*=none}", "x/none") uri_template_string (ht, "x{/empty_keys+}", "x") - uri_template_string (ht, "x{/empty_keys+|none}", "x/empty_keys.none") + uri_template_string (ht, "x{/empty_keys+=none}", "x/empty_keys.none") --| Simple expansion with comma-separated values uri_template_string (ht, "{var}", "value") - uri_template_string (ht, "{hello}", "Hello+World%%21") + uri_template_string (ht, "{hello}", "Hello%%20World%%21") uri_template_string (ht, "{path}/here", "%%2Ffoo%%2Fbar/here") uri_template_string (ht, "{x,y}", "1024,768") - uri_template_string (ht, "{var|default}", "value") - uri_template_string (ht, "{undef|default}", "default") + uri_template_string (ht, "{var=default}", "value") + uri_template_string (ht, "{undef=default}", "default") uri_template_string (ht, "{list}", "val1,val2,val3") uri_template_string (ht, "{list*}", "val1,val2,val3") uri_template_string (ht, "{list+}", "list.val1,list.val2,list.val3") @@ -443,7 +406,7 @@ feature -- Test routines --| Reserved expansion with comma-separated values uri_template_string (ht, "{+var}", "value") - uri_template_string (ht, "{+hello}", "Hello+World!") + uri_template_string (ht, "{+hello}", "Hello%%20World!") uri_template_string (ht, "{+path}/here", "/foo/bar/here") uri_template_string (ht, "{+path,x}/here", "/foo/bar,1024/here") uri_template_string (ht, "{+path}{x}/here", "/foo/bar1024/here") @@ -463,16 +426,16 @@ feature -- Test routines uri_template_string (ht, "{;list}", ";list=val1,val2,val3") -- DIFF uri_template_string (ht, "{;list*}", ";val1;val2;val3") uri_template_string (ht, "{;list+}", ";list=val1;list=val2;list=val3") - uri_template_string (ht, "{;keys}", ";key1,val1,key2,val2") + uri_template_string (ht, "{;keys}", ";keys=key1,val1,key2,val2") uri_template_string (ht, "{;keys*}", ";key1=val1;key2=val2") - uri_template_string (ht, "{;keys+}", ";keys.key1=val1;keys.key2=val2") + uri_template_string (ht, "{;keys+}", ";key1=val1;key2=val2") --| Form-style parameters, ampersand-separated uri_template_string (ht, "{?x,y}", "?x=1024&y=768") uri_template_string (ht, "{?x,y,empty}", "?x=1024&y=768&empty=") uri_template_string (ht, "{?x,y,undef}", "?x=1024&y=768") uri_template_string (ht, "{?list}", "?list=val1,val2,val3") - uri_template_string (ht, "{?list*}", "?val1&val2&val3") + uri_template_string (ht, "{?list*}", "?list=val1&list=val2&list=val3") uri_template_string (ht, "{?list+}", "?list=val1&list=val2&list=val3") uri_template_string (ht, "{?keys}", "?keys=key1,val1,key2,val2") uri_template_string (ht, "{?keys*}", "?key1=val1&key2=val2") @@ -487,8 +450,8 @@ feature -- Test routines uri_template_string (ht, "{/list*,x}", "/val1/val2/val3/1024") uri_template_string (ht, "{/list+}", "/list.val1/list.val2/list.val3") uri_template_string (ht, "{/keys}", "/key1,val1,key2,val2") - uri_template_string (ht, "{/keys*}", "/key1/val1/key2/val2") - uri_template_string (ht, "{/keys+}", "/keys.key1/val1/keys.key2/val2") + uri_template_string (ht, "{/keys*}", "/key1=val1/key2=val2") + uri_template_string (ht, "{/keys+}", "/keys.key1=val1/keys.key2=val2") --| Label expansion, dot-prefixed uri_template_string (ht, "X{.var}", "X.value") @@ -506,123 +469,17 @@ feature -- Test routines uri_template_string (ht, "{foo}", "fred") uri_template_string (ht, "{foo,foo}", "fred,fred") uri_template_string (ht, "{bar,foo}", "fred") - uri_template_string (ht, "{bar|wilma}", "wilma") + uri_template_string (ht, "{bar=wilma}", "wilma") --| Reserved Expansion - uri_template_string (ht, "{foo2}", "That%%27s+right%%21") - uri_template_string (ht, "{+foo2}", "That%%27s+right!") + uri_template_string (ht, "{foo2}", "That%%27s%%20right%%21") + uri_template_string (ht, "{+foo2}", "That%%27s%%20right!") uri_template_string (ht, "{base}index", "http%%3A%%2F%%2Fexample.com%%2Fhome%%2Findex") uri_template_string (ht, "{+base}index", "http://example.com/home/index") assert ("all strings built", uri_template_string_errors = Void or (attached uri_template_string_errors as err and then err.is_empty)) end - uri_template_string (a_ht: HASH_TABLE [detachable ANY, STRING]; a_expression: STRING; a_expected: STRING) - local - tpl: URI_TEMPLATE - s: STRING - m: STRING - do - create tpl.make (a_expression) - s := tpl.expanded_string (a_ht) - if not s.same_string (a_expected) then - m := "Expected string for %"" + a_expression + "%" expected=%""+ a_expected +"%" but got %"" + s + "%"%N" - if attached uri_template_string_errors as err then - print (m) - err.force (m) - else - assert (m, False) - end - end - end - - uri_template_parse (s: STRING_8; path_vars: ARRAY [STRING]; query_vars: ARRAY [STRING]) - local - u: URI_TEMPLATE - matched: BOOLEAN - i: INTEGER - do - create u.make (s) - if attached u.path_variable_names as vars then - matched := vars.count = path_vars.count - from - i := path_vars.lower - vars.start - until - not matched or i > path_vars.upper - loop - matched := vars.item.same_string (path_vars[i]) - vars.forth - i := i + 1 - end - else - matched := path_vars.is_empty - end - assert ("path variables matched", matched) - - if attached u.query_variable_names as vars then - matched := vars.count = query_vars.count - from - i := query_vars.lower - vars.start - until - not matched or i > query_vars.upper - loop - matched := vars.item.same_string (query_vars[i]) - vars.forth - i := i + 1 - end - else - matched := query_vars.is_empty - end - assert ("query variables matched", matched) - end - - uri_template_mismatch (a_uri_template: URI_TEMPLATE; a_uri: STRING) - local - l_match: detachable URI_TEMPLATE_MATCH_RESULT - do - l_match := a_uri_template.match (a_uri) - assert ("uri %"" + a_uri + "%" does not match template %"" + a_uri_template.template + "%"", l_match = Void) - end - - uri_template_match (a_uri_template: URI_TEMPLATE; a_uri: STRING; path_res: ARRAY [TUPLE [name: STRING; value: STRING]]; query_res: ARRAY [TUPLE [name: STRING; value: STRING]]) - local - b: BOOLEAN - i: INTEGER - l_match: detachable URI_TEMPLATE_MATCH_RESULT - do - l_match := a_uri_template.match (a_uri) - if l_match /= Void then - if attached l_match.path_variables as path_ht then - b := path_ht.count = path_res.count - from - i := path_res.lower - until - not b or i > path_res.upper - loop - b := attached path_ht.item (path_res[i].name) as s and then s.same_string (path_res[i].value) - i := i + 1 - end - assert ("uri matched path variables", b) - end - if attached l_match.query_variables as query_ht then - b := query_ht.count >= query_res.count - from - i := query_res.lower - until - not b or i > query_res.upper - loop - b := attached query_ht.item (query_res[i].name) as s and then s.same_string (query_res[i].value) - i := i + 1 - end - assert ("uri matched query variables", b) - end - else - assert ("uri matched", False) - end - end - note copyright: "2011-2011, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" diff --git a/library/protocol/uri_template/tests/test_uri_template_matcher.e b/library/protocol/uri_template/tests/test_uri_template_matcher.e new file mode 100644 index 00000000..e0caf791 --- /dev/null +++ b/library/protocol/uri_template/tests/test_uri_template_matcher.e @@ -0,0 +1,142 @@ +note + description: "[ + Eiffel tests that can be executed by testing tool. + ]" + author: "EiffelStudio test wizard" + date: "$Date$" + revision: "$Revision$" + testing: "type/manual" + +class + TEST_URI_TEMPLATE_MATCHER + +inherit + TEST_URI_TEMPLATE + +feature -- Matcher + + test_uri_template_matcher + note + testing: "uri-template" + local + tpl: URI_TEMPLATE + do + create tpl.make ("/hello.{format}{/vars}") + uri_template_match (tpl, "/hello.json/foo/bar", <<["format", "json"], ["vars", "/foo/bar"], ["vars[1]", "foo"], ["vars[2]", "bar"]>>, <<>>) + + create tpl.make ("/hello.{format}{?op}") + uri_template_match (tpl, "/hello.json?op=foobar", <<["format", "json"]>>, << ["op", "foobar"]>>) + + + create tpl.make ("{version}/{id}") + uri_template_match (tpl, "v2/123", <<["version", "v2"], ["id" , "123"]>>, <<>>) + + create tpl.make ("api/{foo}{bar}/id/{id}") + uri_template_mismatch (tpl, "api/foobar/id/123") + + + create tpl.make ("api/foo/{foo_id}/{?id,extra}") + uri_template_match (tpl, "api/foo/bar/", <<["foo_id", "bar"]>>, <<>>) + uri_template_match (tpl, "api/foo/bar/?id=123", <<["foo_id", "bar"]>>, <<["id", "123"]>>) + uri_template_match (tpl, "api/foo/bar/?id=123&extra=test", <<["foo_id", "bar"]>>, <<["id", "123"], ["extra", "test"]>>) + uri_template_match (tpl, "api/foo/bar/?id=123&extra=test&one=more", <<["foo_id", "bar"]>>, <<["id", "123"], ["extra", "test"]>>) + uri_template_mismatch (tpl, "") + uri_template_mismatch (tpl, "/") + uri_template_mismatch (tpl, "foo/bar/?id=123") + uri_template_mismatch (tpl, "/api/foo/bar/") + uri_template_mismatch (tpl, "api/foo/bar") + + create tpl.make ("weather/{state}/{city}?forecast={day}") + uri_template_match (tpl, "weather/California/Goleta?forecast=today", <<["state", "California"], ["city", "Goleta"]>>, <<["day", "today"]>>) + + create tpl.make ("/hello") + uri_template_match (tpl, "/hello", <<>>, <<>>) + uri_template_mismatch (tpl, "/hello/Foo2") -- longer + uri_template_mismatch (tpl, "/hell") -- shorter + + create tpl.make ("/hello.{format}") + uri_template_match (tpl, "/hello.xml", <<["format", "xml"]>>, <<>>) + uri_template_mismatch (tpl, "/hello.xml/Bar") + + + create tpl.make ("/hello.{format}/{name}") + uri_template_match (tpl, "/hello.xml/Joce", <<["format", "xml"], ["name", "Joce"]>>, <<>>) + + create tpl.make ("/hello/{name}.{format}") + uri_template_match (tpl, "/hello/Joce.json", <<["name", "Joce"], ["format", "json"]>>, <<>>) + + create tpl.make ("/hello/{name}.{format}/foo") + uri_template_match (tpl, "/hello/Joce.xml/foo", <<["name", "Joce"], ["format", "xml"]>>, <<>>) + uri_template_mismatch (tpl, "/hello/Joce.xml/fooBAR") + + create tpl.make ("/hello{/vars}") + uri_template_match (tpl, "/hello/foo/bar", <<["vars", "/foo/bar"], ["vars[1]", "foo"], ["vars[2]", "bar"]>>, <<>>) + + +-- create tpl.make ("/hello/{name}.{format}/foo{?foo};crazy={idea}") +---- uri_template_match (tpl, "/hello/Joce.xml/foo", <<["name", "Joce"], ["format", "xml"]>>, <<>>) +-- uri_template_match (tpl, "/hello/Joce.xml/foo?foo=FOO", <<["name", "Joce"], ["format", "xml"]>>, <<["foo", "FOO"]>>) +-- uri_template_match (tpl, "/hello/Joce.xml/foo;crazy=IDEA", <<["name", "Joce"], ["format", "xml"]>>, <<["idea", "IDEA"], ["crazy", "IDEA"]>>) + + end + +feature {NONE} -- Implementations + + uri_template_mismatch (a_uri_template: URI_TEMPLATE; a_uri: STRING) + local + l_match: detachable URI_TEMPLATE_MATCH_RESULT + do + l_match := a_uri_template.match (a_uri) + assert ("uri %"" + a_uri + "%" does not match template %"" + a_uri_template.template + "%"", l_match = Void) + end + + uri_template_match (a_uri_template: URI_TEMPLATE; a_uri: STRING; path_res: ARRAY [TUPLE [name: STRING; value: STRING]]; query_res: ARRAY [TUPLE [name: STRING; value: STRING]]) + local + b: BOOLEAN + i: INTEGER + l_match: detachable URI_TEMPLATE_MATCH_RESULT + do + l_match := a_uri_template.match (a_uri) + if l_match /= Void then + if attached l_match.path_variables as path_ht then + b := path_ht.count = path_res.count + from + i := path_res.lower + until + not b or i > path_res.upper + loop + b := attached path_ht.item (path_res[i].name) as s and then s.same_string (path_res[i].value) + i := i + 1 + end + assert ("uri %"" + a_uri + "%" matched path variables", b) + end + if attached l_match.query_variables as query_ht then + b := query_ht.count >= query_res.count + from + i := query_res.lower + until + not b or i > query_res.upper + loop + b := attached query_ht.item (query_res[i].name) as s and then s.same_string (query_res[i].value) + i := i + 1 + end + assert ("uri %"" + a_uri + "%" matched query variables", b) + end + else + assert ("uri %"" + a_uri + "%" matched", False) + end + end + +note + copyright: "2011-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end + + diff --git a/library/protocol/uri_template/tests/test_uri_template_parser.e b/library/protocol/uri_template/tests/test_uri_template_parser.e new file mode 100644 index 00000000..49aacbd1 --- /dev/null +++ b/library/protocol/uri_template/tests/test_uri_template_parser.e @@ -0,0 +1,87 @@ +note + description: "[ + Eiffel tests that can be executed by testing tool. + ]" + author: "EiffelStudio test wizard" + date: "$Date$" + revision: "$Revision$" + testing: "type/manual" + +class + TEST_URI_TEMPLATE_PARSER + +inherit + TEST_URI_TEMPLATE + +feature -- Parser + + test_uri_template_parser + note + testing: "uri-template" + do + uri_template_parse ("api/foo/{foo_id}/{?id,extra}", <<"foo_id">>, <<"id", "extra">>) + uri_template_parse ("weather/{state}/{city}?forecast={day}", <<"state", "city">>, <<"day">>) + uri_template_parse ("/hello/{name}.{format}", <<"name", "format">>, <<>>) + uri_template_parse ("/hello.{format}/{name}", <<"format", "name">>, <<>>) +-- uri_template_parse ("/hello/{name}.{format}/foo{?foobar};crazy=IDEA", <<"name", "format">>, <<"foobar">>) + end + +feature {NONE} -- Implementation + + uri_template_parse (s: STRING_8; path_vars: ARRAY [STRING]; query_vars: ARRAY [STRING]) + local + u: URI_TEMPLATE + matched: BOOLEAN + i: INTEGER + do + create u.make (s) + u.parse + assert ("Template %""+ s +"%" is valid", u.is_valid) + if attached u.path_variable_names as vars then + matched := vars.count = path_vars.count + from + i := path_vars.lower + vars.start + until + not matched or i > path_vars.upper + loop + matched := vars.item.same_string (path_vars[i]) + vars.forth + i := i + 1 + end + else + matched := path_vars.is_empty + end + assert ("path variables matched for %""+ s +"%"", matched) + + if attached u.query_variable_names as vars then + matched := vars.count = query_vars.count + from + i := query_vars.lower + vars.start + until + not matched or i > query_vars.upper + loop + matched := vars.item.same_string (query_vars[i]) + vars.forth + i := i + 1 + end + else + matched := query_vars.is_empty + end + assert ("query variables matched %""+ s +"%"", matched) + end + +note + copyright: "2011-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end + + diff --git a/library/protocol/uri_template/tests/tests-safe.ecf b/library/protocol/uri_template/tests/tests-safe.ecf index 7293d653..a06d669e 100644 --- a/library/protocol/uri_template/tests/tests-safe.ecf +++ b/library/protocol/uri_template/tests/tests-safe.ecf @@ -1,5 +1,5 @@ - + @@ -7,32 +7,12 @@ /EIFGENs$ /.svn$ - - - - - - - - /.git$ - /EIFGENs$ - /.svn$ - - - - - - - - - /test_uri_template.e$ - - + + diff --git a/library/protocol/uri_template/uri_template-safe.ecf b/library/protocol/uri_template/uri_template-safe.ecf index e0231a25..29c4aca1 100644 --- a/library/protocol/uri_template/uri_template-safe.ecf +++ b/library/protocol/uri_template/uri_template-safe.ecf @@ -13,21 +13,6 @@ - - - /draft_05$ - - - /uri_template_constants.e - - - - - - - - - - + diff --git a/library/protocol/uri_template/uri_template.ecf b/library/protocol/uri_template/uri_template.ecf index f534cd8e..41e920c2 100644 --- a/library/protocol/uri_template/uri_template.ecf +++ b/library/protocol/uri_template/uri_template.ecf @@ -16,21 +16,6 @@ - - - /draft_05$ - - - /uri_template_constants.e - - - - - - - - - - +