인터넷 엔지니어링 태스크 포스(IETF) J. Gregorio
RFC 요청 문서: 6570 Google
분류: 표준 트랙 R. Fielding
ISSN: 2070-1721 Adobe
M. Hadley
MITRE
M. Nottingham
Rackspace
D. Orchard
Salesforce.com
2012년 3월
URI 템플릿
초록
URI 템플릿은 변수 확장을 통해 일정 범위의
Uniform Resource Identifier를 설명하기 위한 간결한 문자 시퀀스이다.
이 명세는 URI 템플릿 구문과 URI 템플릿을 URI 참조로 확장하는
절차를 정의하고, 인터넷에서 URI 템플릿을 사용하는 데 필요한
지침을 함께 제공한다.
이 메모의 상태
이 문서는 인터넷 표준 트랙 문서이다.
이 문서는 인터넷 엔지니어링 태스크 포스(IETF)의 산출물이다.
이는 IETF 커뮤니티의 합의를 나타낸다. 이 문서는 공개 검토를
거쳤으며, 인터넷 엔지니어링 운영 그룹(IESG)에 의해 출판 승인을
받았다. 인터넷 표준에 관한 추가 정보는 RFC 5741의 제 2절에서 확인할 수 있다.
이 문서의 현재 상태, 모든 정오표, 그리고 이에 대한 피드백을
제공하는 방법에 관한 정보는
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 등 표준 트랙 [1쪽]
RFC 6570 URI 템플릿 2012년 3월
신탁 법적 조항의 제4.e절에 설명된 Simplified BSD License 텍스트를
포함하며, Simplified BSD License에 설명된 대로 어떠한 보증도 없이
제공된다.
목차
1. 소개 ..........................................................3
1.1. 개요 .....................................................3
1.2. 레벨과 표현식 유형 .......................................5
1.3. 설계 고려사항 ............................................9
1.4. 제한사항 ................................................10
1.5. 표기 규칙 ...............................................11
1.6. 문자 인코딩과 유니코드 정규화 ............................12
2. 구문 .........................................................13
2.1. 리터럴 ..................................................13
2.2. 표현식 ..................................................13
2.3. 변수 ....................................................14
2.4. 값 수정자 ...............................................15
2.4.1. 접두사 값 ........................................15
2.4.2. 복합 값 ..........................................16
3. 확장 .........................................................18
3.1. 리터럴 확장 .............................................18
3.2. 표현식 확장 .............................................18
3.2.1. 변수 확장 ........................................19
3.2.2. 단순 문자열 확장: {var} .........................21
3.2.3. 예약 확장: {+var} ...............................22
3.2.4. 프래그먼트 확장: {#var} .........................23
3.2.5. 점 접두 레이블 확장: {.var} .....................24
3.2.6. 경로 세그먼트 확장: {/var} ......................24
3.2.7. 경로 스타일 매개변수 확장: {;var} ...............25
3.2.8. 폼 스타일 질의 확장: {?var} .....................26
3.2.9. 폼 스타일 질의 연속: {&var} .....................27
4. 보안 고려사항 ................................................27
5. 감사의 말 ...................................................28
6. 참조문헌 .....................................................28
6.1. 규범적 참조문헌 .........................................28
6.2. 참고 참조문헌 ...........................................29
부록 A. 구현 힌트 ................................................30
Gregorio 등 표준 트랙 [2쪽]
RFC 6570 URI 템플릿 2012년 3월
1. 소개
1.1. 개요
Uniform Resource Identifier(URI) [RFC3986]는 흔히
유사한 자원들의 공통 공간(비공식적으로 "URI 공간") 안에서
특정 자원을 식별하는 데 사용된다. 예를 들어, 개인 웹
공간은 흔히 다음과 같은 공통 패턴을 사용해 위임된다.
http://example.com/~fred/
http://example.com/~mark/
또는 사전 항목 집합은 다음과 같이 용어의 첫 글자에 따라
계층으로 묶일 수 있다.
http://example.com/dictionary/c/cat
http://example.com/dictionary/d/dog
또는 서비스 인터페이스는 다음과 같이 다양한 사용자 입력을
공통 패턴으로 받아 호출될 수 있다.
http://example.com/search?q=cat&lang=en
http://example.com/search?q=chien&lang=fr
URI 템플릿은 변수 확장을 통해 일정 범위의 Uniform Resource
Identifier를 설명하기 위한 간결한 문자 시퀀스이다.
URI 템플릿은 자원 식별자 공간을 추상화하는 메커니즘을
제공하여, 변수 부분을 쉽게 식별하고 설명할 수 있게 한다.
URI 템플릿은 사용 가능한 서비스의 발견, 자원 매핑 구성,
계산된 링크 정의, 인터페이스 지정, 그리고 자원과의 다른
형태의 프로그램적 상호작용을 포함하여 많은 용도를 가질 수
있다. 예를 들어, 위의 자원들은 다음 URI 템플릿으로 설명될 수
있다.
http://example.com/~{username}/
http://example.com/dictionary/{term:1}/{term}
http://example.com/search{?q,lang}
다음 용어들을 정의한다.
expression: 제2절에 정의된 대로, 둘러싸는 중괄호를 포함하여
'{'와 '}' 사이에 있는 텍스트.
expansion: 제3절에 정의된 대로, 템플릿 표현식을 그 표현식
유형, 변수 이름 목록, 값 수정자에 따라 처리한 뒤 얻는
문자열 결과.
Gregorio 등 표준 트랙 [3쪽]
RFC 6570 URI 템플릿 2012년 3월
template processor: URI 템플릿과 값을 가진 변수 집합이 주어지면,
템플릿에서 표현식을 파싱하고 각 표현식을 해당 확장으로
대체함으로써 템플릿 문자열을 URI 참조로 변환하는 프로그램
또는 라이브러리.
URI 템플릿은 URI 공간의 구조적 설명과, 변수 값이 제공될 때
그 값에 해당하는 URI를 구성하는 방법에 대한 기계 판독 가능
지시를 함께 제공한다. URI 템플릿은 각 구분된 표현식을 표현식
유형과 그 표현식 안에 이름이 지정된 변수 값에 의해 정의된
값으로 대체함으로써 URI 참조로 변환된다. 표현식 유형은 단순
문자열 확장에서 여러 name=value 목록에 이르기까지 다양하다.
확장은 URI 일반 구문에 기반하므로, 구현은 가능한 모든 결과
URI의 스킴별 요구사항을 알지 못해도 어떤 URI 템플릿이든
처리할 수 있다.
예를 들어, 다음 URI 템플릿은 변수 이름 앞에 "?" 연산자가
나타나는 것으로 표시되는 폼 스타일 매개변수 표현식을 포함한다.
http://www.example.com/foo{?query,number}
물음표("?") 연산자로 시작하는 표현식의 확장 과정은 World Wide
Web의 폼 스타일 인터페이스와 같은 패턴을 따른다.
http://www.example.com/foo{?query,number}
\_____________/
|
|
[ 'query', 'number' ] 안의 정의된 각 변수에 대해,
첫 번째 대체라면 "?"를, 그 이후에는 "&"를
대체하고, 이어서 변수 이름, '=', 변수 값을 붙인다.
변수들이 다음 값을 가진다면
query := "mycelium"
number := 100
위 URI 템플릿의 확장은 다음과 같다.
http://www.example.com/foo?query=mycelium&number=100
또는 'query'가 정의되지 않은 경우, 확장은 다음과 같다.
http://www.example.com/foo?number=100
Gregorio 등 표준 트랙 [4쪽]
RFC 6570 URI 템플릿 2012년 3월
또는 두 변수가 모두 정의되지 않은 경우, 다음과 같다.
http://www.example.com/foo
URI 템플릿은 위 예와 같이 절대 형식으로 제공될 수도 있고,
상대 형식으로 제공될 수도 있다. 템플릿은 결과 참조가 상대
형식에서 절대 형식으로 해석되기 전에 확장된다.
결과에는 URI 구문이 사용되지만, 템플릿 문자열에는
Internationalized Resource Identifier(IRI) 참조 [RFC3987]에서
찾을 수 있는 더 넓은 문자 집합을 포함할 수 있다. 따라서 URI
템플릿은 IRI 템플릿이기도 하며, 템플릿 처리의 결과는
[RFC3987]의 제 3.2절에 정의된 과정을 따름으로써 IRI로
변환될 수 있다.
1.2. 레벨과 표현식 유형
URI 템플릿은 고정된 매크로 정의 집합을 가진 매크로 언어와
유사하다. 표현식 유형이 확장 과정을 결정한다. 기본 표현식
유형은 단순 문자열 확장으로, 여기서는 단일 이름 변수 하나가
예약되지 않은 URI 문자 집합(제1.5절)에 속하지 않는 문자를
pct-encoding한 뒤 그 값의 문자열로 대체된다.
이 명세 이전에 구현된 대부분의 템플릿 프로세서는 기본 표현식
유형만 구현했으므로, 이를 레벨 1 템플릿이라고 부른다.
.-----------------------------------------------------------------.
| 다음 값을 가진 변수를 사용하는 레벨 1 예 |
| |
| var := "value" |
| hello := "Hello World!" |
| |
|-----------------------------------------------------------------|
| Op 표현식 확장 |
|-----------------------------------------------------------------|
| | 단순 문자열 확장 (Sec 3.2.2) |
| | |
| | {var} value |
| | {hello} Hello%20World%21 |
`-----------------------------------------------------------------'
레벨 2 템플릿은 예약 URI 문자(제1.5절)를 포함할 수 있는 값의
확장을 위해 더하기("+") 연산자를 추가하고, 프래그먼트 식별자의
확장을 위해 crosshatch("#") 연산자를 추가한다.
Gregorio 등 표준 트랙 [5쪽]
RFC 6570 URI 템플릿 2012년 3월
.-----------------------------------------------------------------.
| 다음 값을 가진 변수를 사용하는 레벨 2 예 |
| |
| var := "value" |
| hello := "Hello World!" |
| path := "/foo/bar" |
| |
|-----------------------------------------------------------------|
| Op 표현식 확장 |
|-----------------------------------------------------------------|
| + | 예약 문자열 확장 (Sec 3.2.3) |
| | |
| | {+var} value |
| | {+hello} Hello%20World! |
| | {+path}/here /foo/bar/here |
| | here?ref={+path} here?ref=/foo/bar |
|-----+-----------------------------------------------------------|
| # | crosshatch 접두 프래그먼트 확장 (Sec 3.2.4) |
| | |
| | X{#var} X#value |
| | X{#hello} X#Hello%20World! |
`-----------------------------------------------------------------'
레벨 3 템플릿은 표현식마다 쉼표로 구분된 여러 변수를 허용하며,
점 접두 레이블, 슬래시 접두 경로 세그먼트, 세미콜론 접두 경로
매개변수, 그리고 앰퍼샌드 문자로 구분되는 name=value 쌍으로
이루어진 질의 구문을 폼 스타일로 구성하기 위한 더 복잡한
연산자들을 추가한다.
.-----------------------------------------------------------------.
| 다음 값을 가진 변수를 사용하는 레벨 3 예 |
| |
| var := "value" |
| hello := "Hello World!" |
| empty := "" |
| path := "/foo/bar" |
| x := "1024" |
| y := "768" |
| |
|-----------------------------------------------------------------|
| Op 표현식 확장 |
|-----------------------------------------------------------------|
| | 여러 변수를 사용하는 문자열 확장 (Sec 3.2.2) |
| | |
| | map?{x,y} map?1024,768 |
| | {x,hello,y} 1024,Hello%20World%21,768 |
| | |
Gregorio 등 표준 트랙 [6쪽]
RFC 6570 URI 템플릿 2012년 3월
|-----+-----------------------------------------------------------|
| + | 여러 변수를 사용하는 예약 확장 (Sec 3.2.3) |
| | |
| | {+x,hello,y} 1024,Hello%20World!,768 |
| | {+path,x}/here /foo/bar,1024/here |
| | |
|-----+-----------------------------------------------------------|
| # | 여러 변수를 사용하는 프래그먼트 확장 (Sec 3.2.4) |
| | |
| | {#x,hello,y} #1024,Hello%20World!,768 |
| | {#path,x}/here #/foo/bar,1024/here |
| | |
|-----+-----------------------------------------------------------|
| . | 점 접두 레이블 확장 (Sec 3.2.5) |
| | |
| | X{.var} X.value |
| | X{.x,y} X.1024.768 |
| | |
|-----+-----------------------------------------------------------|
| / | 슬래시 접두 경로 세그먼트 (Sec 3.2.6) |
| | |
| | {/var} /value |
| | {/var,x}/here /value/1024/here |
| | |
|-----+-----------------------------------------------------------|
| ; | 세미콜론 접두 경로 스타일 매개변수 (Sec 3.2.7) |
| | |
| | {;x,y} ;x=1024;y=768 |
| | {;x,y,empty} ;x=1024;y=768;empty |
| | |
|-----+-----------------------------------------------------------|
| ? | 앰퍼샌드로 구분되는 폼 스타일 질의 (Sec 3.2.8) |
| | |
| | {?x,y} ?x=1024&y=768 |
| | {?x,y,empty} ?x=1024&y=768&empty= |
| | |
|-----+-----------------------------------------------------------|
| & | 폼 스타일 질의 연속 (Sec 3.2.9) |
| | |
| | ?fixed=yes{&x} ?fixed=yes&x=1024 |
| | {&x,y,empty} &x=1024&y=768&empty= |
| | |
`-----------------------------------------------------------------'
마지막으로, 레벨 4 템플릿은 각 변수 이름에 선택적 접미사로 값
수정자를 추가한다. 접두사 수정자(":")는 값의 시작 부분에서
제한된 수의 문자만 확장에 사용됨을 나타낸다(제2.4.1절).
explode("*") 수정자는
Gregorio 등 표준 트랙 [7쪽]
RFC 6570 URI 템플릿 2012년 3월
변수가 이름 목록 또는 (이름, 값) 쌍의 연관 배열로 이루어진
복합 값으로 취급되어야 하며, 각 멤버가 별도의 변수인 것처럼
확장됨을 나타낸다(제2.4.2절).
.-----------------------------------------------------------------.
| 다음 값을 가진 변수를 사용하는 레벨 4 예 |
| |
| var := "value" |
| hello := "Hello World!" |
| path := "/foo/bar" |
| list := ("red", "green", "blue") |
| keys := [("semi",";"),("dot","."),("comma",",")] |
| |
| Op 표현식 확장 |
|-----------------------------------------------------------------|
| | 값 수정자를 사용하는 문자열 확장 (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 |
| | |
|-----+-----------------------------------------------------------|
| + | 값 수정자를 사용하는 예약 확장 (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=, |
| | |
|-----+-----------------------------------------------------------|
| # | 값 수정자를 사용하는 프래그먼트 확장 (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=, |
| | |
|-----+-----------------------------------------------------------|
| . | 점 접두 레이블 확장 (Sec 3.2.5) |
| | |
| | X{.var:3} X.val |
| | X{.list} X.red,green,blue |
Gregorio 등 표준 트랙 [8쪽]
RFC 6570 URI 템플릿 2012년 3월
| | X{.list*} X.red.green.blue |
| | X{.keys} X.semi,%3B,dot,.,comma,%2C |
| | X{.keys*} X.semi=%3B.dot=..comma=%2C |
| | |
|-----+-----------------------------------------------------------|
| / | 슬래시 접두 경로 세그먼트 (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 |
| | |
|-----+-----------------------------------------------------------|
| ; | 세미콜론 접두 경로 스타일 매개변수 (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 |
| | |
|-----+-----------------------------------------------------------|
| ? | 앰퍼샌드로 구분되는 폼 스타일 질의 (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 |
| | |
|-----+-----------------------------------------------------------|
| & | 폼 스타일 질의 연속 (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. 설계 고려사항
URI 템플릿과 유사한 메커니즘은 WSDL [WSDL], WADL [WADL],
OpenSearch [OpenSearch]를 비롯한 여러 명세 안에서 정의되어 왔다.
이 명세는 그 구문을 확장하고 공식적으로 정의하여
Gregorio 등 표준 트랙 [9쪽]
RFC 6570 URI 템플릿 2012년 3월
URI 템플릿을 여러 인터넷 애플리케이션과 인터넷 메시지 필드 안에서
일관되게 사용할 수 있게 하는 동시에, 이러한 이전 정의들과의
호환성을 유지한다.
URI 템플릿 구문은 강력한 확장 메커니즘의 필요성과 구현 용이성의
필요성 사이에서 신중하게 균형을 이루도록 설계되었다. 이 구문은
파싱하기 쉽도록 설계되었으며, 동시에 많은 일반적인 템플릿
시나리오를 표현하기에 충분한 유연성을 제공한다. 구현은 템플릿을
파싱하고 확장을 단일 패스로 수행할 수 있다.
템플릿은 일반적인 예와 함께 사용될 때 단순하고 읽기 쉽다.
이는 단일 문자 연산자가 URI 일반 구문의 구분자와 일치하기
때문이다. 나열된 변수 중 어느 것도 정의되어 있지 않으면,
연산자에 연결된 구분자(".", ";", "/", "?", "&", "#")는
생략된다. 마찬가지로 ";"(경로 스타일 매개변수)의 확장 과정은
변수 값이 비어 있으면 "="를 생략하지만, "?"(폼 스타일
매개변수)의 과정은 값이 비어 있어도 "="를 생략하지 않는다.
여러 변수와 목록 값은 연산자에 미리 정의된 결합 메커니즘이
없으면 ","로 그 값을 결합한다. "+"와 "#" 연산자는 변수 값
안에서 발견되는 인코딩되지 않은 예약 문자를 대체하며, 다른
연산자들은 확장 전에 변수 값 안에서 발견되는 예약 문자를
pct-encode한다.
URI 공간의 가장 일반적인 경우는 레벨 1 템플릿 표현식으로
설명될 수 있다. 우리가 URI 생성에만 관심이 있었다면, 더
복잡한 형식은 변수 값을 변경하여 생성할 수 있으므로 템플릿
구문을 단순 변수 확장으로만 제한할 수 있었을 것이다. 그러나
URI 템플릿에는 기존 데이터 값의 관점에서 식별자의 배치를
설명한다는 추가 목표가 있다. 따라서 템플릿 구문에는 자원
식별자가 일반적으로 할당되는 방식을 반영하는 연산자가 포함된다.
마찬가지로, 접두 부분 문자열은 큰 자원 공간을 분할하는 데
자주 사용되므로, 변수 값에 대한 수정자는 하나의 변수 이름으로
부분 문자열과 전체 값 문자열을 모두 지정하는 방법을 제공한다.
1.4. 제한사항
URI 템플릿은 식별자의 상위 집합을 설명하므로, 각 구분된 변수
표현식의 가능한 모든 확장이 기존 자원의 URI에 해당한다는
의미는 없다. 템플릿에 따라 URI를 구성하는 애플리케이션에는
대체되는 변수에 대한 적절한 값 집합, 또는 적어도 그러한 값에
대한 사용자 데이터 입력을 검증할 수단이 제공될 것으로
예상한다.
Gregorio 등 표준 트랙 [10쪽]
RFC 6570 URI 템플릿 2012년 3월
URI 템플릿은 URI가 아니다. URI 템플릿은 추상적 또는 물리적
자원을 식별하지 않으며, URI로 파싱되지 않고, 템플릿 표현식이
사용 전에 템플릿 프로세서에 의해 확장되지 않는 한 URI가
기대되는 위치에서 사용되어서는 안 된다. URI 템플릿을 담는
프로토콜 요소와 URI 참조를 기대하는 프로토콜 요소를 구별하기
위해 서로 다른 필드, 요소 또는 속성 이름을 사용해야 한다.
일부 URI 템플릿은 변수 매칭의 목적으로 역방향으로 사용될 수
있다. 즉, 완성된 URI와 템플릿을 비교하여 그 URI에서 변수
부분을 추출하고 이름이 지정된 변수에 할당하는 것이다. 변수
매칭은 템플릿 표현식이 URI의 시작이나 끝, 또는 단순 문자열
표현식을 둘러싸는 예약 문자처럼 확장의 일부가 될 수 없는
문자로 구분되어 있을 때에만 잘 작동한다. 일반적으로 정규
표현식 언어가 변수 매칭에 더 적합하다.
1.5. 표기 규칙
이 문서의 핵심 단어 "MUST", "MUST NOT", "REQUIRED", "SHALL",
"SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY",
"OPTIONAL"은 [RFC2119]에 설명된 대로 해석되어야 한다.
이 명세는 [RFC5234]의 Augmented Backus-Naur Form(ABNF)
표기법을 사용한다. 다음 ABNF 규칙은 규범적 참조문헌
[RFC5234], [RFC3986], [RFC3987]에서 가져온다.
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
Gregorio 등 표준 트랙 [11쪽]
RFC 6570 URI 템플릿 2012년 3월
1.6. 문자 인코딩과 유니코드 정규화
이 명세는 "character", "character encoding scheme", "code point",
"coded character set", "glyph", "non-ASCII", "normalization",
"protocol element", "regular expression"이라는 용어를 [RFC6365]에
정의된 의미로 사용한다.
ABNF 표기법은 그 터미널 값을 US-ASCII 부호화 문자 집합 [ASCII]의
상위 집합인 음이 아닌 정수(코드 포인트)로 정의한다. 이 명세는
터미널 값을 Unicode 부호화 문자 집합 [UNIV6] 안의 코드
포인트로 정의한다.
구문과 템플릿 확장 과정이 유니코드 코드 포인트의 관점에서
정의되어 있음에도 불구하고, 실제로 템플릿은 그것이 나타나는
문맥에 적합한 어떤 형식이나 인코딩으로든 된 문자 시퀀스로
존재한다는 점을 이해해야 한다. 이는 네트워크 프로토콜 요소에
포함된 옥텟일 수도 있고, 버스 옆면에 그려진 글리프일 수도
있다. 이 명세는 URI 템플릿 문자와 그 문자를 저장하거나 전송하는
데 사용되는 옥텟 사이의 매핑을 위한 특정 문자 인코딩 방식을
요구하지 않는다. URI 템플릿이 프로토콜 요소에 나타날 때,
문자 인코딩 방식은 해당 프로토콜에 의해 정의된다. 그러한 정의가
없으면 URI 템플릿은 주변 텍스트와 같은 문자 인코딩 방식에
있다고 가정한다. URI 템플릿 안의 문자 문자열이 유니코드 코드
포인트의 시퀀스로 처리되어야 하는 것은 템플릿 확장 과정에서만
REQUIRED이다.
Unicode Standard [UNIV6]는 다양한 목적을 위한 문자 시퀀스 사이의
여러 동등성을 정의한다. Unicode Standard Annex #15 [UTR15]는
이러한 동등성을 위한 여러 Normalization Form을 정의한다.
정규화 형식은 동등한 문자열을 일관되게 인코딩하는 방법을
결정한다. 이론적으로는 템플릿 프로세서를 포함한 모든 URI 처리
구현이 URI 참조를 생성하기 위해 같은 정규화 형식을 사용해야
한다. 실제로는 그렇지 않다. 값이 자원과 같은 서버에 의해
제공된 경우, 그 문자열은 이미 해당 서버가 기대하는 형식에
있다고 가정할 수 있다. 값이 데이터 입력 대화상자 등을 통해
사용자에 의해 제공된 경우, 그 문자열은 템플릿 프로세서의
확장에 사용되기 전에 Normalization Form C(NFC: Canonical
Decomposition 뒤 Canonical Composition)로 정규화되는 것이
SHOULD이다.
마찬가지로, 읽을 수 있는 문자열을 나타내는 비 ASCII 데이터가
URI 참조에서 사용되도록 pct-encoded될 때, 템플릿 프로세서는
먼저 문자열을 UTF-8 [RFC3629]로 인코딩한 뒤 URI 참조에서
허용되지 않는 모든 옥텟을 pct-encode해야 한다.
Gregorio 등 표준 트랙 [12쪽]
RFC 6570 URI 템플릿 2012년 3월
2. 구문
URI 템플릿은 0개 이상의 내장 변수 표현식을 포함하는 출력 가능한
유니코드 문자들의 문자열이며, 각 표현식은 서로 맞는 한 쌍의
중괄호('{', '}')로 구분된다.
URI-Template = *( literals / expression )
위에서 템플릿(및 템플릿 프로세서 구현)을 네 개의 점진적인
레벨의 관점에서 설명했지만, 여기서는 URI-Template 구문을
레벨 4의 ABNF 관점에서 정의한다. 더 낮은 레벨의 템플릿으로
제한된 템플릿 프로세서는 더 높은 레벨에만 적용되는 ABNF 규칙을
제외할 MAY 수 있다. 그러나 모든 파서가 전체 구문을 구현하여
지원되지 않는 레벨을 최종 사용자에게 적절히 식별할 수 있게
하는 것이 RECOMMENDED이다.
2.1. 리터럴
URI 템플릿 문자열에서 표현식 바깥의 문자는 그 문자가 URI에서
허용되는 경우(reserved / unreserved / pct-encoded) URI 참조로
문자 그대로 복사되며, 허용되지 않는 경우에는 그 문자의 UTF-8
인코딩 [RFC3629]에 해당하는 pct-encoded 삼중항 시퀀스로 URI
참조에 복사되도록 의도된다.
literals = %x21 / %x23-24 / %x26 / %x28-3B / %x3D / %x3F-5B
/ %x5D / %x5F / %x61-7A / %x7E / ucschar / iprivate
/ pct-encoded
; 다음을 제외한 모든 유니코드 문자: CTL, SP,
; DQUOTE, "'", "%" (pct-encoded 제외),
; "<", ">", "\", "^", "`", "{", "|", "}"
2.2. 표현식
템플릿 표현식은 URI 템플릿의 매개변수화된 부분이다. 각 표현식은
표현식 유형과 그에 대응하는 확장 과정을 정의하는 선택적
연산자를 포함하며, 그 뒤에 쉼표로 구분된 변수 지정자 목록
(변수 이름과 선택적 값 수정자)이 온다. 연산자가 제공되지 않으면,
표현식은 예약되지 않은 값의 단순 변수 확장을 기본값으로 한다.
expression = "{" [ operator ] variable-list "}"
operator = op-level2 / op-level3 / op-reserve
op-level2 = "+" / "#"
op-level3 = "." / "/" / ";" / "?" / "&"
op-reserve = "=" / "," / "!" / "@" / "|"
Gregorio 등 표준 트랙 [13쪽]
RFC 6570 URI 템플릿 2012년 3월
연산자 문자는 URI 일반 구문에서 예약 문자로서 수행하는 각각의
역할을 반영하도록 선택되었다. 이 명세의 제3절에서 정의하는
연산자에는 다음이 포함된다.
+ 예약 문자 문자열;
# "#"가 접두된 프래그먼트 식별자;
. "."가 접두된 이름 레이블 또는 확장자;
/ "/"가 접두된 경로 세그먼트;
; ";"가 접두된 경로 매개변수 이름 또는 name=value 쌍;
? "?"로 시작하고 "&"로 구분된 name=value 쌍으로 이루어진
질의 컴포넌트; 그리고,
& 리터럴 질의 컴포넌트 안에서 query-style &name=value 쌍의
연속.
등호("="), 쉼표(","), 느낌표("!"), at sign("@"), 파이프("|")
연산자 문자는 향후 확장을 위해 예약되어 있다.
표현식 구문은 달러("$")와 괄호 ["(" 및 ")"] 문자의 사용을
명시적으로 제외하여, 이들이 이 명세의 범위 밖에서 계속 사용할
수 있도록 한다. 예를 들어, 매크로 언어는 문자열이 URI 템플릿으로
처리되기 전에 그 문자열에 매크로 치환을 적용하기 위해 이러한
문자를 사용할 수 있다.
2.3. 변수
연산자(있는 경우) 뒤에서 각 표현식은 하나 이상의 쉼표로 구분된
변수 지정자(varspec) 목록을 포함한다. 변수 이름은 여러 목적을
수행한다. 어떤 종류의 값이 기대되는지에 대한 문서화, 템플릿
프로세서 안에서 값을 연결하기 위한 식별자, 그리고 name=value
확장에서 이름으로 사용할 리터럴 문자열(연관 배열을 explode하는
경우는 제외)이다. 변수 이름은 값이 대소문자를 구분하는 URI
컴포넌트 안에서 확장될 수 있으므로 대소문자를 구분한다.
variable-list = varspec *( "," varspec )
varspec = varname [ modifier-level4 ]
varname = varchar *( ["."] varchar )
varchar = ALPHA / DIGIT / "_" / pct-encoded
Gregorio 등 표준 트랙 [14쪽]
RFC 6570 URI 템플릿 2012년 3월
varname은 하나 이상의 pct-encoded 삼중항을 포함할 MAY 수 있다.
이러한 삼중항은 변수 이름의 필수적인 일부로 간주되며 처리 중에
디코딩되지 않는다. pct-encoded 문자를 포함하는 varname은
동일한 문자를 디코딩한 varname과 같은 변수가 아니다. URI
템플릿을 제공하는 애플리케이션은 변수 이름 안에서 pct-encoding을
일관되게 사용할 것으로 기대된다.
표현식은 템플릿 프로세서가 알지 못하는 변수, 또는 undef나
null 같은 특별한 "undefined" 값으로 설정된 변수를 참조할 MAY
수 있다. 이러한 정의되지 않은 변수는 확장 과정에서 특별히
처리된다(제3.2.1절).
길이가 0인 문자열인 변수 값은 정의되지 않은 것으로 간주되지
않는다. 그것은 빈 문자열이라는 정의된 값을 가진다.
레벨 4 템플릿에서 변수는 값 목록 또는 (name, value) 쌍의
연관 배열 형식의 복합 값을 가질 수 있다. 이러한 값 유형은
템플릿 구문에 의해 직접 표시되지는 않지만, 확장 과정에는
영향을 미친다(제3.2.1절).
목록 값으로 정의된 변수는 그 목록에 멤버가 0개이면 정의되지
않은 것으로 간주된다. (name, value) 쌍의 연관 배열로 정의된
변수는 배열에 멤버가 0개이거나 배열 안의 모든 멤버 이름이
정의되지 않은 값과 연결되어 있으면 정의되지 않은 것으로
간주된다.
2.4. 값 수정자
레벨 4 템플릿 표현식의 각 변수는 그 확장이 변수 값 문자열의
접두부로 제한됨을 나타내거나, 값 목록 또는 (name, value) 쌍의
연관 배열 형식의 복합 값으로 explode되어 확장됨을 나타내는
수정자를 가질 수 있다.
modifier-level4 = prefix / explode
2.4.1. 접두사 값
접두사 수정자는 변수 확장이 변수 값 문자열의 접두부로 제한됨을
나타낸다. 접두사 수정자는 참조 색인과 해시 기반 저장소에서
흔히 그렇듯 식별자 공간을 계층적으로 분할하는 데 자주 사용된다.
또한 확장된 값을 최대 문자 수로 제한하는 역할도 한다. 접두사
수정자는 복합 값을 가진 변수에는 적용되지 않는다.
Gregorio 등 표준 트랙 [15쪽]
RFC 6570 URI 템플릿 2012년 3월
prefix = ":" max-length
max-length = %x31-39 0*3DIGIT ; 양의 정수 < 10000
max-length는 유니코드 문자열로서 변수 값의 시작 부분에서 가져올
최대 문자 수를 나타내는 양의 정수이다. 이 번호 매김은 옥텟이
아니라 문자 단위임에 유의한다. 이는 다중 옥텟으로 인코딩된
문자 안의 옥텟 사이 또는 pct-encoded 삼중항 안에서 분리되는
일을 피하기 위한 것이다. max-length가 변수 값의 길이보다 크면
전체 값 문자열이 사용된다.
예를 들어,
다음 변수 할당이 주어졌을 때
var := "value"
semi := ";"
예제 템플릿 확장
{var} value
{var:20} value
{var:3} val
{semi} %3B
{semi:2} %3B
2.4.2. 복합 값
explode("*") 수정자는 변수가 값 목록 또는 (name, value) 쌍의
연관 배열로 이루어진 복합 값으로 취급되어야 함을 나타낸다.
따라서 확장 과정은 복합 값의 각 멤버가 별도의 변수로 나열된
것처럼 각 멤버에 적용된다. 이런 종류의 변수 지정은 explode되지
않은 변수보다 자기 문서화 성격이 상당히 약하다. 변수 이름과
확장 후 URI 참조가 나타나는 방식 사이의 대응이 더 적기 때문이다.
explode = "*"
URI 템플릿에는 유형이나 스키마를 나타내는 표시가 없으므로,
explode된 변수의 유형은 문맥에 의해 결정된다고 가정한다. 예를
들어, 프로세서에는 값을 문자열, 목록, 연관 배열로 구분하는
형식의 값들이 제공될 수 있다. 마찬가지로, 템플릿이 사용되는
문맥(스크립트, 마크업 언어, 인터페이스 정의 언어 등)이 변수
이름을 유형, 구조 또는 스키마와 연결하기 위한 규칙을 정의할
수 있다.
Gregorio 등 표준 트랙 [16쪽]
RFC 6570 URI 템플릿 2012년 3월
explode 수정자는 URI 템플릿 구문의 간결성을 향상시킨다. 예를
들어, 주어진 도로명 주소에 대한 지리 지도를 제공하는 자원은
부분 주소(예: 도시나 우편번호만)를 포함하여 주소 입력 필드에
대한 수백 가지 순열을 받을 수 있다. 이러한 자원은 모든 주소
구성요소를 순서대로 나열한 템플릿으로 설명될 수도 있고, 다음과
같이 explode 수정자를 사용하는 훨씬 더 단순한 템플릿으로
설명될 수도 있다.
/mapper{?address*}
그리고 "address"라는 변수 이름이 무엇을 포함할 수 있는지
정의하는 어떤 문맥이 함께 제공된다. 예를 들어 주소 지정에 관한
다른 표준(예: [UPU-S42])을 참조할 수 있다. 그러면 스키마를
알고 있는 수신자는 다음과 같은 적절한 확장을 제공할 수 있다.
/mapper?city=Newport%20Beach&state=CA
explode된 변수의 확장 과정은 사용되는 연산자와 복합 값을 값
목록으로 취급할지, 아니면 (name, value) 쌍의 연관 배열로 취급할지
모두에 의존한다. 구조는 구조 정의의 필드에 해당하는 이름을 가진
연관 배열인 것처럼 처리되며, 하위 구조의 이름 계층을 나타내기
위해 "." 구분자가 사용된다.
변수가 복합 구조를 가지고 있고 그 구조 안의 일부 필드에만
정의된 값이 있다면, 확장에는 정의된 쌍만 존재한다. 이는 가능한
질의 용어가 많은 템플릿에 유용할 수 있다.
목록 변수에 적용된 explode 수정자는 확장이 목록의 멤버 값들을
순회하도록 한다. 경로 및 질의 매개변수 확장에서는 각 멤버 값이
변수 이름과 (varname, value) 쌍으로 짝지어진다. 이를 통해 경로
및 질의 매개변수가 여러 값에 대해 반복될 수 있다. 예를 들면
다음과 같다.
다음 변수 할당이 주어졌을 때
year := ("1965", "2000", "2012")
dom := ("example", "com")
예제 템플릿 확장
find{?year*} find?year=1965&year=2000&year=2012
www{.dom*} www.example.com
Gregorio 등 표준 트랙 [17쪽]
RFC 6570 URI 템플릿 2012년 3월
3. 확장
URI 템플릿 확장의 과정은 템플릿 문자열을 처음부터 끝까지
스캔하면서 리터럴 문자를 복사하고, 각 표현식을 그 표현식의
연산자를 표현식 안에 이름이 지정된 각 변수의 값에 적용한
결과로 대체하는 것이다. 각 변수의 값은 템플릿 확장 전에 형성되어
있어야 MUST 한다.
URI 템플릿 문법의 각 측면에 대한 확장 요구사항은 이 절에서
정의한다. 전체 확장 과정에 대한 비규범적 알고리즘은
부록 A에 제공된다.
템플릿 프로세서가 표현식 바깥에서 <URI-Template> 문법과
일치하지 않는 문자 시퀀스를 만나면, 템플릿 처리는 중단되어야
SHOULD 하고, URI 참조 결과는 템플릿의 확장된 부분 뒤에 나머지
미확장 부분을 포함해야 SHOULD 하며, 오류의 위치와 유형이 호출
애플리케이션에 표시되어야 SHOULD 한다.
표현식에서 오류가 발생한 경우, 예를 들어 템플릿 프로세서가
인식하지 못하거나 아직 지원하지 않는 연산자 또는 값 수정자가
있거나, <expression> 문법에서 허용하지 않는 문자가 발견되면,
표현식의 처리되지 않은 부분은 미확장 상태로 결과에 복사되어야
SHOULD 하고, 템플릿의 나머지 부분 처리는 계속되어야 SHOULD 하며,
오류의 위치와 유형이 호출 애플리케이션에 표시되어야 SHOULD 한다.
오류가 발생하면 반환되는 결과는 유효한 URI 참조가 아닐 수 있다.
그것은 진단용으로만 의도된 불완전하게 확장된 템플릿 문자열이 될
것이다.
3.1. 리터럴 확장
리터럴 문자가 URI 구문 어디에서나 허용되는 경우(unreserved /
reserved / pct-encoded)에는 그 문자가 결과 문자열에 직접 복사된다.
그렇지 않은 경우, 리터럴 문자를 먼저 UTF-8의 옥텟 시퀀스로
인코딩한 다음, 그러한 각 옥텟을 pct-encoded 삼중항으로 인코딩하여
리터럴 문자의 pct-encoded 등가물이 결과 문자열에 복사된다.
3.2. 표현식 확장
각 표현식은 여는 중괄호("{") 문자로 표시되고 다음 닫는
중괄호("}")까지 계속된다. 표현식은 중첩될 수 없다.
Gregorio 등 표준 트랙 [18쪽]
RFC 6570 URI 템플릿 2012년 3월
표현식은 그 표현식 유형을 결정한 다음, 표현식 안에서 쉼표로
구분된 각 varspec에 대해 해당 유형의 확장 과정을 따름으로써
확장된다. 레벨 1 템플릿은 기본 연산자(단순 문자열 값 확장)와
표현식당 단일 변수로 제한된다. 레벨 2 템플릿은 표현식당 단일
varspec으로 제한된다.
표현식 유형은 여는 중괄호 뒤의 첫 번째 문자를 살펴보아 결정한다.
그 문자가 연산자이면, 이후 확장 결정을 위해 그 연산자와 연결된
표현식 유형을 기억하고 variable-list를 위해 다음 문자로 건너뛴다.
첫 번째 문자가 연산자가 아니면 표현식 유형은 단순 문자열 확장이고,
첫 번째 문자가 variable-list의 시작이다.
아래 하위 절의 예는 변수 값에 대해 다음 정의를 사용한다.
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. 변수 확장
정의되지 않은 변수(제2.3절)는 값이 없으며 확장 과정에서
무시된다. 표현식 안의 모든 변수가 정의되지 않았으면, 그 표현식의
확장은 빈 문자열이다.
정의된 비어 있지 않은 값의 변수 확장은 허용된 URI 문자로 이루어진
부분 문자열을 생성한다. 제1.6절에 설명된 것처럼, 확장 과정은
결과 URI 참조에서 비 ASCII 문자가 일관되게 pct-encoded되도록
하기 위해 유니코드 코드 포인트의 관점에서 정의된다. 템플릿
Gregorio 등 표준 트랙 [19쪽]
RFC 6570 URI 템플릿 2012년 3월
프로세서가 일관된 확장을 얻는 한 방법은 값 문자열을 UTF-8로
변환하고(아직 UTF-8이 아닌 경우), 허용 집합에 속하지 않는 각
옥텟을 해당 pct-encoded 삼중항으로 변환하는 것이다. 다른 방법은
값의 원래 문자 인코딩에서 허용된 URI 문자 집합으로 직접
매핑하고, 남은 허용되지 않는 문자는 UTF-8 [RFC3629]로
인코딩되었을 때 그 문자에 해당하는 옥텟(들)의 pct-encoded
삼중항 시퀀스로 매핑하는 것이다.
주어진 확장에 대한 허용 집합은 표현식 유형에 따라 달라진다.
예약("+") 및 프래그먼트("#") 확장은 ( unreserved / reserved /
pct-encoded )의 합집합에 속하는 문자가 pct-encoding 없이 통과할
수 있도록 허용하는 반면, 다른 모든 표현식 유형은 unreserved
문자만 pct-encoding 없이 통과하도록 허용한다. 퍼센트 문자("%")는
pct-encoded 삼중항의 일부로만, 그리고 예약/프래그먼트 확장에서만
허용된다는 점에 유의한다. 다른 모든 경우에는 값 문자 "%"가 변수
확장에 의해 "%25"로 pct-encoded되어야 MUST 한다.
변수가 표현식에서 한 번 이상 나타나거나 URI 템플릿의 여러
표현식 안에 나타나면, 그 변수의 값은 확장 과정 전체에서 정적으로
유지되어야 MUST 한다(즉, 각 확장을 계산할 목적으로 변수는 같은
값을 가져야 한다). 그러나 값 안에 예약 문자나 pct-encoded 삼중항이
있으면, 일부 표현식 유형에서는 그것들이 pct-encoded되고 다른
유형에서는 그렇지 않다.
단순 문자열 값인 변수의 경우, 확장은 인코딩된 값을 결과 문자열에
덧붙이는 것으로 이루어진다. explode 수정자는 아무 효과가 없다.
접두사 수정자는 확장을 디코딩된 값의 처음 max-length 문자로
제한한다. 값에 다중 옥텟 문자나 pct-encoded 문자가 포함되어 있으면,
값이 문자 중간에서 분리되지 않도록 주의해야 한다. 각 유니코드
코드 포인트를 하나의 문자로 센다.
연관 배열인 변수의 경우, 확장은 표현식 유형과 explode 수정자의
존재 여부 모두에 의존한다. explode 수정자가 없으면, 확장은 정의된
값을 가진 각 (name, value) 쌍을 쉼표로 구분해 이어 붙인 것을
덧붙이는 것으로 이루어진다. explode 수정자가 있으면, 확장은
정의된 값을 가진 각 쌍을 "name=value"로, 또는 값이 빈 문자열이고
표현식 유형이 폼 스타일 매개변수(즉, "?"나 "&" 유형)가 아니면
단순히 "name"으로 덧붙이는 것으로 이루어진다. name 문자열과 value
문자열은 모두 단순 문자열 값과 같은 방식으로 인코딩된다. 다음
표에 정의된 것처럼 표현식 유형에 따라 정의된 쌍 사이에 구분자
문자열이 덧붙여진다.
Gregorio 등 표준 트랙 [20쪽]
RFC 6570 URI 템플릿 2012년 3월
유형 구분자
"," (기본값)
+ ","
# ","
. "."
/ "/"
; ";"
? "&"
& "&"
값 목록인 변수의 경우, 확장은 표현식 유형과 explode 수정자의 존재
여부 모두에 의존한다. explode 수정자가 없으면, 확장은 정의된
멤버 문자열 값들을 쉼표로 구분해 이어 붙이는 것으로 이루어진다.
explode 수정자가 있고 표현식 유형이 이름 있는 매개변수(";", "?",
또는 "&")로 확장되면, 목록은 각 멤버 값이 목록의 varname과
짝지어진 연관 배열인 것처럼 확장된다. 그렇지 않으면 값은 각각의
값이 위 표에 정의된 표현식 유형의 관련 구분자로 구분되는 별도의
변수 값 목록인 것처럼 확장된다.
예제 템플릿 확장
{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. 단순 문자열 확장: {var}
단순 문자열 확장은 연산자가 주어지지 않았을 때의 기본 표현식
유형이다.
variable-list 안의 정의된 각 변수에 대해, 허용 문자가 unreserved
집합에 속하는 문자라고 하여 제3.2.1절에 정의된 변수 확장을
수행한다. 정의된 값을 가진 변수가 둘 이상이면, 변수 확장 사이의
구분자로 결과 문자열에 쉼표(",")를 덧붙인다.
Gregorio 등 표준 트랙 [21쪽]
RFC 6570 URI 템플릿 2012년 3월
예제 템플릿 확장
{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. 예약 확장: {+var}
레벨 2 이상 템플릿에서 더하기("+") 연산자로 표시되는 예약 확장은,
대체된 값이 pct-encoded 삼중항과 reserved 집합의 문자를 포함할
수도 있다는 점을 제외하면 단순 문자열 확장과 동일하다.
variable-list 안의 정의된 각 변수에 대해, 허용 문자가
(unreserved / reserved / pct-encoded) 집합에 속하는 문자라고 하여
제3.2.1절에 정의된 변수 확장을 수행한다. 정의된 값을 가진
변수가 둘 이상이면, 변수 확장 사이의 구분자로 결과 문자열에
쉼표(",")를 덧붙인다.
Gregorio 등 표준 트랙 [22쪽]
RFC 6570 URI 템플릿 2012년 3월
예제 템플릿 확장
{+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. 프래그먼트 확장: {#var}
레벨 2 이상 템플릿에서 crosshatch("#") 연산자로 표시되는 프래그먼트
확장은, 변수 중 어느 하나라도 정의되어 있으면 먼저 crosshatch
문자(프래그먼트 구분자)가 결과 문자열에 덧붙여진다는 점을 제외하면
예약 확장과 동일하다.
예제 템플릿 확장
{#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 등 표준 트랙 [23쪽]
RFC 6570 URI 템플릿 2012년 3월
3.2.5. 점 접두 레이블 확장: {.var}
레벨 3 이상 템플릿에서 점(".") 연산자로 표시되는 레이블 확장은
다양한 도메인 이름이나 경로 선택자(예: 파일 이름 확장자)를 가진
URI 공간을 설명하는 데 유용하다.
variable-list 안의 정의된 각 변수에 대해, 결과 문자열에 "."를
덧붙인 다음, 허용 문자가 unreserved 집합에 속하는 문자라고 하여
제3.2.1절에 정의된 변수 확장을 수행한다.
"."는 unreserved 집합에 있으므로, "."를 포함하는 값은 여러
레이블을 추가하는 효과를 가진다.
예제 템플릿 확장
{.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. 경로 세그먼트 확장: {/var}
레벨 3 이상 템플릿에서 슬래시("/") 연산자로 표시되는 경로 세그먼트
확장은 URI 경로 계층을 설명하는 데 유용하다.
variable-list 안의 정의된 각 변수에 대해, 결과 문자열에 "/"를
덧붙인 다음, 허용 문자가 unreserved 집합에 속하는 문자라고 하여
제3.2.1절에 정의된 변수 확장을 수행한다.
경로 세그먼트 확장의 확장 과정은 "." 대신 "/"를 대체한다는 점을
제외하면 레이블 확장과 동일하다는 점에 유의한다. 그러나 "."와
달리 "/"는 reserved 문자이며, 값 안에서 발견되면 pct-encoded된다.
Gregorio 등 표준 트랙 [24쪽]
RFC 6570 URI 템플릿 2012년 3월
예제 템플릿 확장
{/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. 경로 스타일 매개변수 확장: {;var}
레벨 3 이상 템플릿에서 세미콜론(";") 연산자로 표시되는 경로
스타일 매개변수 확장은 "path;property" 또는 "path;name=value"와
같은 URI 경로 매개변수를 설명하는 데 유용하다.
variable-list 안의 정의된 각 변수에 대해:
o 결과 문자열에 ";"를 덧붙인다;
o 변수가 단순 문자열 값을 가지거나 explode 수정자가 주어지지
않았으면:
* 변수 이름(리터럴 문자열인 것처럼 인코딩됨)을 결과 문자열에
덧붙인다;
* 변수 값이 비어 있지 않으면, 결과 문자열에 "="를 덧붙인다;
o 허용 문자가 unreserved 집합에 속하는 문자라고 하여
제3.2.1절에 정의된 변수 확장을 수행한다.
Gregorio 등 표준 트랙 [25쪽]
RFC 6570 URI 템플릿 2012년 3월
예제 템플릿 확장
{;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. 폼 스타일 질의 확장: {?var}
레벨 3 이상 템플릿에서 물음표("?") 연산자로 표시되는 폼 스타일
질의 확장은 전체 선택적 질의 컴포넌트를 설명하는 데 유용하다.
variable-list 안의 정의된 각 변수에 대해:
o 이것이 첫 번째 정의된 값이면 결과 문자열에 "?"를 덧붙이고,
그 이후에는 "&"를 덧붙인다;
o 변수가 단순 문자열 값을 가지거나 explode 수정자가 주어지지
않았으면, 변수 이름(리터럴 문자열인 것처럼 인코딩됨)과 등호
문자("=")를 결과 문자열에 덧붙인다; 그리고,
o 허용 문자가 unreserved 집합에 속하는 문자라고 하여
제3.2.1절에 정의된 변수 확장을 수행한다.
예제 템플릿 확장
{?who} ?who=fred
{?half} ?half=50%25
{?x,y} ?x=1024&y=768
{?x,y,empty} ?x=1024&y=768&empty=
{?x,y,undef} ?x=1024&y=768
{?var:3} ?var=val
{?list} ?list=red,green,blue
{?list*} ?list=red&list=green&list=blue
{?keys} ?keys=semi,%3B,dot,.,comma,%2C
{?keys*} ?semi=%3B&dot=.&comma=%2C
Gregorio 등 표준 트랙 [26쪽]
RFC 6570 URI 템플릿 2012년 3월
3.2.9. 폼 스타일 질의 연속: {&var}
레벨 3 이상 템플릿에서 앰퍼샌드("&") 연산자로 표시되는 폼 스타일
질의 연속은 고정 매개변수를 가진 리터럴 질의 컴포넌트를 이미
포함하는 템플릿 안에서 선택적 &name=value 쌍을 설명하는 데
유용하다.
variable-list 안의 정의된 각 변수에 대해:
o 결과 문자열에 "&"를 덧붙인다;
o 변수가 단순 문자열 값을 가지거나 explode 수정자가 주어지지
않았으면, 변수 이름(리터럴 문자열인 것처럼 인코딩됨)과 등호
문자("=")를 결과 문자열에 덧붙인다; 그리고,
o 허용 문자가 unreserved 집합에 속하는 문자라고 하여
제3.2.1절에 정의된 변수 확장을 수행한다.
예제 템플릿 확장
{&who} &who=fred
{&half} &half=50%25
?fixed=yes{&x} ?fixed=yes&x=1024
{&x,y,empty} &x=1024&y=768&empty=
{&x,y,undef} &x=1024&y=768
{&var:3} &var=val
{&list} &list=red,green,blue
{&list*} &list=red&list=green&list=blue
{&keys} &keys=semi,%3B,dot,.,comma,%2C
{&keys*} &semi=%3B&dot=.&comma=%2C
4. 보안 고려사항
URI 템플릿은 능동적이거나 실행 가능한 콘텐츠를 포함하지 않는다.
그러나 공격자가 템플릿을 제어하거나, 확장에서 예약 문자를
허용하는 표현식 안의 변수 값을 제어할 수 있다면 예상치 못한
URI를 만들어낼 수 있을지도 모른다. 어느 경우든 보안 고려사항은
주로 누가 템플릿을 제공하는지, 누가 템플릿 안의 변수에 사용할
값을 제공하는지, 확장이 어떤 실행 문맥(클라이언트 또는 서버)에서
일어나는지, 그리고 결과 URI가 어디에서 사용되는지에 따라
결정된다.
Gregorio 등 표준 트랙 [27쪽]
RFC 6570 URI 템플릿 2012년 3월
이 명세는 URI 템플릿이 사용될 수 있는 위치를 제한하지 않는다.
현재 구현은 서버 측 개발 프레임워크와 계산된 링크 또는 폼을
위한 클라이언트 측 javascript 안에 존재한다.
프레임워크 안에서 템플릿은 일반적으로 클라이언트 요청의 이후
(요청 시점) URI 안에서 데이터가 어디에 나타날 수 있는지를
안내하는 역할을 한다. 따라서 보안상의 우려는 템플릿 자체가
아니라, 서버가 일반 Web 요청 안에서 사용자가 제공한 데이터를
어떻게 추출하고 처리하는지에 있다.
클라이언트 측 구현 안에서 URI 템플릿은 HTML 폼과 동일한 속성을
많이 가지지만, URI 문자로 제한되고 메시지 본문 콘텐츠뿐 아니라
HTTP 헤더 필드 값 안에도 포함될 수 있다는 차이가 있다. 템플릿과
값이 모두 신뢰할 수 있는 출처에서 제공되지 않는 한,
"javascript:"로 시작하는 것과 같은 잠재적으로 위험한 URI 참조
문자열이 확장에 나타나지 않도록 주의해야 한다.
그 밖의 보안 고려사항은 [RFC3986]의 제 7절에 설명된 URI의
보안 고려사항과 같다.
5. 감사의 말
다음 사람들은 이 명세에 기여하였다: 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. 참조문헌
6.1. 규범적 참조문헌
[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 등 표준 트랙 [28쪽]
RFC 6570 URI 템플릿 2012년 3월
[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),
<http://www.unicode.org/versions/Unicode6.0.0/>.
[UTR15] Davis, M. and M. Duerst, "Unicode Normalization Forms",
Unicode Standard Annex # 15, April 2003,
<http://www.unicode.org/unicode/reports/tr15/
tr15-23.html>.
6.2. 참고 참조문헌
[OpenSearch] Clinton, D., "OpenSearch 1.1", Draft 5, December 2011,
<http://www.opensearch.org/Specifications/OpenSearch>.
[UPU-S42] Universal Postal Union, "International Postal Address
Components and Templates", UPU S42-1, November 2002,
<http://www.upu.int/en/activities/addressing/
standards.html>.
[WADL] Hadley, M., "Web Application Description Language",
World Wide Web Consortium Member Submission
SUBM-wadl-20090831, August 2009,
<http://www.w3.org/Submission/2009/
SUBM-wadl-20090831/>.
[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, <http://www.w3.org/TR/2007/
REC-wsdl20-20070626>.
Gregorio 등 표준 트랙 [29쪽]
RFC 6570 URI 템플릿 2012년 3월
부록 A. 구현 힌트
확장에 관한 규범적 절들은 설명의 명확성을 위해 각 연산자를
별도의 확장 과정으로 설명한다. 실제 구현에서는 표현식이 연산자마다
과정상 사소한 차이만 있는 공통 알고리즘을 사용하여 왼쪽에서
오른쪽으로 처리될 것으로 기대한다. 이 비규범적 부록은 그러한
알고리즘 하나를 설명한다.
빈 결과 문자열과 그 비오류 상태를 초기화한다.
템플릿을 스캔하고, 표현식이 "{"로 표시되거나, "{" 이외의
non-literals 문자가 있어 오류가 표시되거나, 템플릿이 끝날 때까지
리터럴을 결과 문자열에 복사한다(제3.1절처럼). 끝나면 결과
문자열과 현재 오류 또는 비오류 상태를 반환한다.
o 표현식이 발견되면, 템플릿을 다음 "}"까지 스캔하고 중괄호
사이의 문자를 추출한다.
o 템플릿이 "}" 전에 끝나면, "{"와 추출된 문자를 결과 문자열에
덧붙이고, 표현식이 잘못 형성되었음을 나타내는 오류 상태로
반환한다.
추출된 표현식의 첫 번째 문자를 검사하여 연산자를 확인한다.
o 표현식이 끝났거나(즉, "{}"), 알 수 없거나 구현되지 않은
연산자가 발견되었거나, 문자가 varchar 집합(제2.3절)에
없으면, "{", 추출된 표현식, "}"를 결과 문자열에 덧붙이고,
결과가 오류 상태임을 기억한 다음 템플릿의 나머지를 스캔하는
곳으로 되돌아간다.
o 알려져 있고 구현된 연산자가 발견되면, 연산자를 저장하고
varspec-list를 시작하기 위해 다음 문자로 건너뛴다.
o 그렇지 않으면, 연산자를 NUL(단순 문자열 확장)로 저장한다.
다음 값 표를 사용하여 표현식 유형 연산자별 처리 동작을 결정한다.
"first" 항목은 표현식의 변수 중 어느 하나라도 정의되어 있으면
결과에 먼저 덧붙일 문자열이다. "sep" 항목은 두 번째(또는 그 이후)
정의된 변수 확장 전에 결과에 덧붙일 구분자이다. "named" 항목은
explode 수정자가 주어지지 않았을 때 확장에 변수 또는 키 이름이
포함되는지 여부를 나타내는 불리언이다. "ifemp" 항목은 해당 값이
비어 있을 때 이름에 덧붙일 문자열이다. "allow" 항목은
Gregorio 등 표준 트랙 [30쪽]
RFC 6570 URI 템플릿 2012년 3월
값 확장 안에서 인코딩되지 않은 채 허용할 문자를 나타낸다. (U)는
unreserved 집합에 속하지 않는 모든 문자가 인코딩됨을 의미하고,
(U+R)은 (unreserved / reserved / pct-encoding)의 합집합에 속하지
않는 모든 문자가 인코딩됨을 의미한다. 두 경우 모두 허용되지 않는
각 문자는 먼저 UTF-8의 옥텟 시퀀스로 인코딩된 다음, 그러한 각
옥텟이 pct-encoded 삼중항으로 인코딩된다.
.------------------------------------------------------------------.
| NUL + . / ; ? & # |
|------------------------------------------------------------------|
| first | "" "" "." "/" ";" "?" "&" "#" |
| sep | "," "," "." "/" ";" "&" "&" "," |
| named | false false false false true true true false |
| ifemp | "" "" "" "" "" "=" "=" "" |
| allow | U U+R U U U U U U+R |
`------------------------------------------------------------------'
위 표를 염두에 두고 variable-list를 다음과 같이 처리한다.
각 varspec에 대해, varname 집합에 속하지 않는 문자를 찾거나
표현식 끝에 도달할 때까지 variable-list를 스캔하여 변수 이름과
선택적 수정자를 추출한다.
o 표현식 끝이고 varname이 비어 있으면, 템플릿의 나머지를
스캔하는 곳으로 되돌아간다.
o 표현식 끝이 아니고 마지막으로 찾은 문자가 수정자("*" 또는
":")를 나타내면, 그 수정자를 기억한다. 그것이 explode("*")이면,
다음 문자를 스캔한다. 접두사(":")이면, 십진 정수로 표현된
max-length를 위해 다음 1개에서 4개의 문자를 계속 스캔하고,
그래도 표현식 끝이 아니면 다음 문자를 스캔한다.
o 표현식 끝이 아니고 마지막으로 찾은 문자가 쉼표(",")가 아니면,
"{", 저장된 연산자(있는 경우), 스캔한 varname과 수정자, 남은
표현식, "}"를 결과 문자열에 덧붙이고, 결과가 오류 상태임을
기억한 다음 템플릿의 나머지를 스캔하는 곳으로 되돌아간다.
스캔한 변수 이름에 대한 값을 조회한 다음,
o varname이 알려져 있지 않거나 정의되지 않은 값을 가진 변수에
해당하면(제2.3절), 다음 varspec으로 건너뛴다.
Gregorio 등 표준 트랙 [31쪽]
RFC 6570 URI 템플릿 2012년 3월
o 이것이 이 표현식의 첫 번째 정의된 변수이면, 이 표현식 유형의
first 문자열을 결과 문자열에 덧붙이고 그것이 수행되었음을
기억한다. 그렇지 않으면 sep 문자열을 결과 문자열에 덧붙인다.
o 이 변수의 값이 문자열이면,
* named가 true이면, 리터럴에 사용하는 것과 같은 인코딩 과정을
사용하여 varname을 결과 문자열에 덧붙이고,
+ 값이 비어 있으면, ifemp 문자열을 결과 문자열에 덧붙이고
다음 varspec으로 건너뛴다;
+ 그렇지 않으면, 결과 문자열에 "="를 덧붙인다.
* 접두사 수정자가 있고 접두사 길이가 유니코드 문자 수로
측정한 값 문자열 길이보다 작으면, 값 문자열의 시작 부분에서
그 수만큼의 문자를 결과 문자열에 덧붙이되, allow 집합에
속하지 않는 문자는 pct-encode하고, 단일 유니코드 코드
포인트를 나타내는 다중 옥텟 또는 pct-encoded 삼중항 문자가
분리되지 않도록 주의한다;
* 그렇지 않으면, allow 집합에 속하지 않는 문자를 pct-encode한
뒤 값을 결과 문자열에 덧붙인다.
o 아니면 explode 수정자가 주어지지 않았으면,
* named가 true이면, 리터럴에 사용하는 것과 같은 인코딩 과정을
사용하여 varname을 결과 문자열에 덧붙이고,
+ 값이 비어 있으면, ifemp 문자열을 결과 문자열에 덧붙이고
다음 varspec으로 건너뛴다;
+ 그렇지 않으면, 결과 문자열에 "="를 덧붙인다; 그리고
* 이 변수의 값이 목록이면, 정의된 각 목록 멤버를 결과 문자열에
덧붙이되, allow 집합에 속하지 않는 문자를 pct-encode하고,
정의된 목록 멤버 사이의 결과에는 쉼표(",")를 덧붙인다;
* 이 변수의 값이 연관 배열 또는 다른 형태의 짝지어진
(name, value) 구조이면, 정의된 값을 가진 각 쌍을 "name,value"로
결과 문자열에 덧붙이되, allow 집합에 속하지 않는 문자를
pct-encode하고, 정의된 각 쌍 사이의 결과에는 쉼표(",")를
덧붙인다.
Gregorio 등 표준 트랙 [32쪽]
RFC 6570 URI 템플릿 2012년 3월
o 아니면 explode 수정자가 주어졌으면,
* named가 true이면, 정의된 값을 가진 각 정의된 목록 멤버 또는
배열 (name, value) 쌍에 대해 다음을 수행한다.
+ 이것이 첫 번째 정의된 멤버/값이 아니면, sep 문자열을
결과 문자열에 덧붙인다;
+ 이것이 목록이면, 리터럴에 사용하는 것과 같은 인코딩
과정을 사용하여 varname을 결과 문자열에 덧붙인다;
+ 이것이 쌍이면, 리터럴에 사용하는 것과 같은 인코딩 과정을
사용하여 name을 결과 문자열에 덧붙인다;
+ 멤버/값이 비어 있으면, ifemp 문자열을 결과 문자열에
덧붙인다. 그렇지 않으면, allow 집합에 속하지 않는
멤버/값 문자를 pct-encode한 뒤 "="와 멤버/값을 결과
문자열에 덧붙인다.
* 아니면 named가 false이면,
+ 이것이 목록이면, 정의된 각 목록 멤버를 결과 문자열에
덧붙이되, allow 집합에 속하지 않는 문자를 pct-encode하고,
정의된 각 목록 멤버 사이의 결과에는 sep 문자열을 덧붙인다.
+ 이것이 (name, value) 쌍의 배열이면, 정의된 값을 가진 각
쌍을 "name=value"로 결과 문자열에 덧붙이되, allow 집합에
속하지 않는 문자를 pct-encode하고, 정의된 각 쌍 사이의
결과에는 sep 문자열을 덧붙인다.
이 표현식에 대한 variable-list가 소진되면, 템플릿의 나머지를
스캔하는 곳으로 되돌아간다.
Gregorio 등 표준 트랙 [33쪽]
RFC 6570 URI 템플릿 2012년 3월
저자 주소
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 등 표준 트랙 [34쪽]