Internet Engineering Task Force (IETF) M. Nottingham
Request for Comments: 9651 Cloudflare
Obsoletes: 8941 P-H. Kamp
Category: Standards Track The Varnish Cache Project
ISSN: 2070-1721 September 2024

HTTP용 구조화된 필드 값


초록

이 문서는 HTTP 헤더 및 트레일러 필드(일명 "구조화된 필드", "구조화된 헤더", 또는 "구조화된 트레일러")를 정의하고 처리하기 쉽게 하고 안전하게 만들기 위한 일련의 데이터 타입과 관련 알고리즘을 설명합니다. 이는 새로운 HTTP 필드의 명세에서 사용하기 위한 것입니다.

이 문서는 RFC 8941을 대체합니다.

이 메모의 상태

이 문서는 인터넷 표준 트랙 문서입니다.

이 문서는 인터넷 엔지니어링 태스크 포스(IETF)의 산물입니다. 이는 IETF 커뮤니티의 합의를 나타냅니다. 공개 검토를 거쳤으며 인터넷 엔지니어링 운영 그룹(IESG)에 의해 출판 승인을 받았습니다. 인터넷 표준에 대한 자세한 정보는 RFC 7841의 섹션 2에서 확인할 수 있습니다.

이 문서의 현재 상태, 정정 사항(errata), 그리고 피드백 제공 방법에 대한 정보는 https://www.rfc-editor.org/info/rfc9651에서 확인할 수 있습니다.

Copyright Notice

Copyright (c) 2024 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 (https://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 include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.


1. 소개

새로운 HTTP 헤더(및 트레일러) 필드의 문법을 지정하는 것은 부담스러운 작업입니다; Section 16.3.2 of [HTTP]에 있는 지침이 있더라도, 잠재적 HTTP 필드 작성자는 많은 결정과 함정에 직면합니다.

필드가 정의되면 종종 맞춤 파서와 직렬화기가 작성되어야 하는데, 그 이유는 각 필드 값이 비슷해 보이는 공통 문법을 약간씩 다르게 처리하기 때문입니다.

이 문서는 이러한 문제를 해결하기 위해 새로운 HTTP 필드 값의 정의에 사용할 공통 데이터 구조 집합을 소개합니다. 특히, 이를 위한 일반적이고 추상적인 모델을 정의하고, 그 모델을 HTTP [HTTP] 헤더 및 트레일러 필드에서 표현하기 위한 구체적인 직렬화를 제공합니다.

"Structured Header" 또는 "Structured Trailer"(필드가 둘 다 가능하면 "Structured Field")로 정의된 HTTP 필드는 이 명세에 정의된 타입을 사용하여 그 구문과 기본 처리 규칙을 정의하며, 이로써 명세 작성자에 의한 정의와 구현에 의한 처리를 단순화합니다.

또한, 향후 HTTP 버전은 이러한 구조의 추상 모델에 대한 대체 직렬화를 정의할 수 있으므로, 해당 모델을 사용하는 필드를 재정의하지 않고도 더 효율적으로 전송할 수 있게 합니다.

이 문서의 목적은 기존 HTTP 필드의 문법을 재정의하는 것이 아님을 유의하십시오; 여기서 설명된 메커니즘은 명시적으로 이를 채택한 필드에서만 사용하도록 설계되어 있습니다.

섹션 2는 구조화 필드를 명세하는 방법을 설명합니다.

섹션 3은 구조화 필드에서 사용할 수 있는 여러 추상 데이터 타입을 정의합니다.

이러한 추상 타입들은 섹션 4에 설명된 알고리즘을 사용하여 HTTP 필드 값으로 직렬화되거나 HTTP 필드 값에서 구문 분석될 수 있습니다.

1.1. 의도적으로 엄격한 처리

이 명세는 의도적으로 단계별 알고리즘을 사용하여 엄격한 구문 분석 및 직렬화 동작을 정의합니다; 정의된 유일한 오류 처리는 전체 작업을 완전히 실패시키는 것입니다.

이는 충실한 구현과 양호한 상호운용성을 장려하도록 설계되었습니다. 따라서 입력에 더 관대하게 처리하려는 구현은 다른 구현들이 유사하지만 미세하게 다른 해결책을 구현하도록 압력을 가하게 되어 오히려 상호운용성을 악화시킬 수 있습니다.

다시 말해, 엄격한 처리는 이 명세의 의도된 특징으로, 비준수 입력이 생산자에 의해 조기에 발견되고 수정될 수 있게 하며 그렇지 않았더라면 발생했을 상호운용성 및 보안 문제를 방지합니다.

이 엄격성의 결과로, 필드가 여러 당사자(예: 중개자나 송신자 내의 다른 구성요소)에 의해 추가되는 경우, 한 당사자의 값에 있는 오류가 전체 필드 값의 구문 분석 실패를 초래할 가능성이 있음을 유의하십시오.

1.2. 표기 규칙

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

이 문서는 문자를 지정하기 위해 상황에 따라 VCHAR, SP, DIGIT, ALPHA 및 DQUOTE 규칙을 [RFC5234]에서 사용합니다. 동일한 목적을 위해 tchar 및 OWS 규칙을 [HTTP]에서 사용합니다.

이 문서는 구문 분석 및 직렬화 동작을 지정하기 위해 알고리즘을 사용합니다. HTTP 필드에서 구문 분석할 때, 구현은 알고리즘을 따르는 것과 구별할 수 없는 동작을 가져야 합니다.

HTTP 필드로의 직렬화에 대해, 알고리즘은 이를 생성하는 권장 방법을 정의합니다. 구현은 출력이 여전히 섹션 4.2에 설명된 구문 분석 알고리즘에 의해 올바르게 처리되는 한 지정된 동작과 다르게 할 수 있습니다.


2. 새 구조화 필드 정의

HTTP 필드를 구조화 필드로 지정하려면, 해당 필드의 작성자는 다음을 수행해야 합니다:

  • 이 명세를 규범적으로 참조하십시오. 필드의 수신자와 생성자는 이 문서의 요구사항이 적용된다는 것을 알아야 합니다.

  • 필드가 Structured Header(즉, 헤더 섹션에서만 사용되는 경우 -- 일반적인 경우), Structured Trailer(트레일러 섹션에서만), 또는 Structured Field(둘 다)인지 식별하십시오.

  • 필드 값의 타입을 지정하십시오; List (섹션 3.1), Dictionary (섹션 3.2), 또는 Item (섹션 3.3) 중 하나입니다.

  • 필드 값의 의미를 정의하십시오.

  • 필드 값에 대한 추가 제약과 그 제약이 위반될 경우의 결과를 지정하십시오.

일반적으로, 이는 필드 정의가 최상위 타입 -- List, Dictionary, 또는 Item -- 을 지정한 다음 허용 가능한 타입과 그에 대한 제약을 정의함을 의미합니다. 예를 들어, List로 정의된 헤더는 모든 멤버가 Integer일 수도 있고, 타입이 혼합되어 있을 수도 있습니다; Item으로 정의된 헤더는 오직 Strings만 허용할 수 있으며, 추가로 문자 "Q"로 시작하는 문자열만 허용하거나 소문자 문자열만 허용할 수 있습니다. 마찬가지로 Inner Lists (섹션 3.1.1)는 필드 정의에서 명시적으로 허용하는 경우에만 유효합니다.

Display String 타입을 사용하는 필드는 허용되는 유니코드 코드 포인트를 신중하게 지정하는 것이 권장됩니다; 예를 들어 [PRECIS]의 프로파일 사용을 지정하는 것처럼 말입니다.

필드 정의는 필드 값 전체에 대해서만 이 명세를 사용할 수 있으며, 그 일부에 대해서만 사용할 수는 없습니다.

명세는 적절하게 필드 이름을 "Structured Header name", "Structured Trailer name", 또는 "Structured Field name"으로 지칭할 수 있습니다. 마찬가지로 필요에 따라 필드 값을 "Structured Header value", "Structured Trailer value", 또는 "Structured Field value"로 지칭할 수 있습니다.

이 명세는 구현이 지원해야 하는 다양한 구조의 길이 또는 수에 대한 최소값을 정의합니다. 대부분의 경우 최대 크기는 지정하지 않지만, 작성자는 HTTP 구현이 개별 필드의 크기, 전체 필드 수 및/또는 전체 헤더 또는 트레일러 섹션의 크기에 대해 다양한 제한을 부과한다는 점을 인지해야 합니다.

2.1. 예제

가상의 Foo-Example 헤더 필드는 다음과 같이 명세될 수 있습니다:

42. Foo-Example Header Field

Foo-Example HTTP 헤더 필드는 메시지에 포함된 Foo의 양에 대한 정보를 전달합니다.

Foo-Example은 Item Structured Header Field [RFC9651]입니다. 그 값은 MUST Integer (Section 3.3.1 of [RFC9651]) 여야 합니다.

그 값은 메시지 내의 Foo의 양을 나타내며, MUST 0에서 10 사이(양끝 포함)이어야 합니다; 다른 값은 전체 헤더 필드가 무시되도록 MUST 합니다.

다음 매개변수가 정의됩니다:

  • 키가 "foourl"인 매개변수로, 그 값은 String (Section 3.3.3 of [RFC9651])이며 메시지의 Foo URL을 전달합니다. 처리 요구사항은 아래를 참조하십시오.

"foourl"은 URI-reference (Section 4.1 of [RFC3986])를 포함합니다. 그 값이 유효한 URI-reference가 아니면 전체 헤더 필드는 MUST 무시되어야 합니다. 그 값이 상대 참조(Section 4.2 of [RFC3986])인 경우 사용 전에 MUST 해결되어야 합니다 (Section 5 of [RFC3986]).

예를 들면:

  Foo-Example: 2; foourl="https://foo.example.com/"

2.2. 오류 처리

구문 분석이 실패하면 전체 필드는 무시됩니다 (참조: 섹션 4.2). 필드 정의는 이를 재정의할 수 없는데, 그렇게 하면 일반 소프트웨어로 처리하는 것을 불가능하게 만들기 때문입니다; 필드 정의는 추가 제약(예: Integer 및 Decimal의 숫자 범위, Strings 및 Tokens의 형식, Dictionary 값에 허용되는 타입, List의 항목 수 등)을 추가할 수만 있습니다.

필드별 제약이 위반되면, 해당 필드 정의가 다른 처리 요구사항을 명시하지 않는 한 전체 필드는 무시됩니다. 예를 들어, 헤더 필드가 Item으로 정의되고 Integer여야 하는데 String이 수신된 경우, 그 필드 정의가 명시적으로 달리 지정하지 않는 한 무시되어야 합니다.

2.3. 확장성 유지

구조화 필드는 확장 가능하도록 설계되었습니다. 실제 경험은 예측하지 못한 경우에도 필드의 허용되는 구문 및 의미를 통제된 방식으로 수정하고 추가해야 하는 경우가 자주 있음을 보여주었습니다.

Items와 Inner Lists는 확장 메커니즘으로서 Parameters를 허용하므로, 필요에 따라 나중에 그 값들이 더 많은 정보를 수용하도록 확장될 수 있습니다. 향후 호환성을 유지하려면 필드 명세는 인식하지 못하는 매개변수의 존재를 오류 조건으로 정의하는 것을 권장하지 않습니다.

필드 명세는 확장성을 유지하기 위해 Item, List 또는 Dictionary 중 하나여야 합니다. 잘못하여 다른 타입(e.g., Integer)으로 정의된 필드는 Item으로 간주됩니다(즉, Parameters를 허용합니다).

이 확장성이 미래에도 사용 가능하도록 보장하고 수신자가 완전한 파서 구현을 사용하도록 장려하기 위해, 필드 정의는 송신자가 "grease" 매개변수를 추가하도록 지정할 수 있습니다. 명세는 특정 패턴에 맞는 모든 매개변수를 이 용도로 예약하고 일부 요청에 대해 전송하도록 권장할 수 있습니다. 이는 수신자가 Parameters를 고려하지 않는 파서를 작성하는 것을 억제하는 데 도움이 됩니다.

Dictionary를 사용하는 명세는 또한 알 수 없는 키의 존재뿐만 아니라 그와 관련된 값과 타입을 무시하도록 요구함으로써 향후 호환성을 허용할 수 있습니다. 이후의 명세는 적절하게 제약을 지정하면서 추가 키를 도입할 수 있습니다.

구조화 필드에 대한 확장은, 그 확장을 이해하는 수신자가 그 확장에 정의된 제약이 충족되지 않을 경우 전체 필드 값을 무시하도록 요구할 수 있습니다.

2.4. 확장에 새 구조화 타입 사용

필드 정의는 구조화 필드에 대한 특정 RFC를 참조해야 하므로, 필드 값에서 사용할 수 있는 타입은 해당 RFC에 정의된 것들로 제한됩니다. 예를 들어, 이 문서를 참조하는 필드는 Date 타입(섹션 3.3.7)을 사용할 수 있지만, RFC 8941을 참조하는 필드는 이를 사용할 수 없으며 그 경우 해당 구현은 유효하지 않은 것으로 처리(따라서 폐기)할 것입니다.

이 제한은 필드에 대한 향후 확장에도 적용됩니다; 예를 들어, RFC 8941을 참조하여 정의된 필드는 일부 수신자가 여전히 RFC 8941 기반 파서를 사용하여 처리할 수 있기 때문에 Date 타입을 사용할 수 없습니다.

그러나 이 문서는 RFC 8941과의 하위 호환성을 고려하여 설계되었습니다; 이 요구사항을 구현하는 파서는 RFC 8941을 참조하는 유효한 구조화 필드도 파싱할 수 있습니다.

구조화 필드 구현을 이 명세(예: 본 문서)의 최신 개정판을 지원하도록 업그레이드하면 이전 RFC에 따라 유효하지 않았던 일부 필드 값이 처리 시 유효해질 가능성이 생깁니다.

예를 들어, 필드 인스턴스가 문법적으로 유효한 Date (섹션 3.3.7)를 포함하고 있을 수 있는데, 그 필드의 정의는 Date를 수용하지 않을 수 있습니다. RFC 8941 기반 구현은 해당 명세에 정의되어 있지 않기 때문에 그러한 필드 인스턴스의 파싱에 실패할 것입니다. 만약 해당 구현이 이 명세로 업그레이드되면 파싱이 성공할 수 있습니다. 경우에 따라 결과 Date 값은 필드별 로직에 의해 거부될 수 있지만, 확장 매개변수처럼 본래 무시되던 필드의 값들은 탐지되지 않을 수 있으며, 그 결과 필드가 수락되어 처리될 수 있습니다.


3. 구조화된 데이터 타입

이 섹션은 구조화된 필드가 사용하는 추상 타입의 개요를 제공하며, 각 타입이 텍스트 형식의 HTTP 필드로 어떻게 직렬화되는지에 대한 간단한 설명과 예를 제공합니다. Section 4에서는 이러한 타입들이 텍스트형 HTTP 필드에서 어떻게 구문 분석되고 직렬화되는지에 대한 세부사항을 규정합니다.

요약하면:

  • HTTP 필드는 세 가지 최상위 타입 중 하나로 정의될 수 있습니다: 리스트(Lists), 딕셔너리(Dictionaries), 그리고 항목(Items).

  • 리스트와 딕셔너리는 컨테이너로서 그 멤버들은 항목(Items) 또는 내부 리스트(Inner Lists)가 될 수 있습니다(내부 리스트는 자체적으로 항목들의 배열입니다).

  • 항목과 내부 리스트는 모두 매개변수(Parameters)를 가질 수 있습니다.

3.1. 리스트

리스트는 0개 이상의 멤버로 이루어진 배열이며, 각 멤버는 항목(섹션 3.3) 또는 내부 리스트(섹션 3.1.1)일 수 있고, 양쪽 모두 매개변수(섹션 3.1.2)를 가질 수 있습니다.

빈 리스트는 필드를 전혀 직렬화하지 않음으로써 표시됩니다. 이는 리스트로 정의된 필드가 기본적으로 빈값을 가짐을 의미합니다.

텍스트형 HTTP 필드로 직렬화될 때, 각 멤버는 쉼표와 선택적 공백으로 구분됩니다. 예를 들어, 값이 토큰의 리스트로 정의된 필드는 다음과 같을 수 있습니다:

Example-List: sugar, tea, rum

리스트의 멤버는 RFC 9110 섹션 5.3에 따라 동일한 헤더 또는 트레일러 섹션의 여러 줄에 나눠서 있을 수 있습니다. 예를 들어, 다음은 동등합니다:

Example-List: sugar, tea, rum

그리고

Example-List: sugar, tea
Example-List: rum

그러나 리스트의 개별 멤버는 안전하게 여러 줄에 나눌 수 없습니다; 자세한 내용은 섹션 4.2를 참조하십시오.

파서는 최소한 1024개의 멤버를 포함하는 리스트를 지원해야 합니다. 필드 명세는 필요에 따라 개별 리스트 값의 타입과 기수성(cardinality)을 제약할 수 있습니다.

3.1.1. 내부 리스트

내부 리스트는 0개 이상의 항목(섹션 3.3)으로 이루어진 배열입니다. 개별 항목과 내부 리스트 자체 모두 매개변수(섹션 3.1.2)를 가질 수 있습니다.

텍스트형 HTTP 필드로 직렬화될 때, 내부 리스트는 괄호로 둘러싸여 표시되고 그 값들은 하나 이상의 공백으로 구분됩니다. 값이 문자열의 내부 리스트들인 리스트는 다음과 같을 수 있습니다:

Example-List: ("foo" "bar"), ("baz"), ("bat" "one"), ()

이 예에서 마지막 멤버가 빈 내부 리스트라는 점을 주의하십시오.

두 수준 모두에서 매개변수가 있는 내부 리스트의 값을 가지는 헤더 필드는 다음과 같을 수 있습니다:

Example-List: ("foo"; a=1;b=2);lvl=5, ("bar" "baz");lvl=1

파서는 최소한 256개의 멤버를 포함하는 내부 리스트를 지원해야 합니다. 필드 명세는 필요에 따라 개별 내부 리스트 멤버의 타입과 기수성을 제약할 수 있습니다.

3.1.2. 매개변수

매개변수는 항목(섹션 3.3) 또는 내부 리스트(섹션 3.1.1)와 연관된 순서가 있는 키-값 쌍의 맵입니다. 키는 해당 매개변수 범위 내에서 고유하며, 값은 베어 아이템(즉, 그 자체로 매개변수를 가질 수 없음; 섹션 3.3 참조)입니다.

구현체는 인덱스와 키로 모두 매개변수에 접근할 수 있어야 합니다. 명세는 둘 중 어느 방식을 사용할지 선택할 수 있습니다.

매개변수는 순서가 있으며, 매개변수 키에는 대문자를 포함할 수 없습니다.

텍스트형 HTTP 필드로 직렬화될 때, 매개변수는 항목 또는 내부 리스트와 다른 매개변수들로부터 세미콜론으로 구분됩니다. 예를 들면:

Example-List: abc;a=1;b=2; cde_456, (ghi;jk=4 l);q="9";r=w

값이 불리언(섹션 3.3.6)인 매개변수는 직렬화될 때 true인 경우 그 값을 생략해야 합니다. 예를 들어, 여기서 "a" 매개변수는 true이고 "b" 매개변수는 false입니다:

Example-Integer: 1; a; b=?0

이 요구사항은 직렬화에만 적용된다는 점을 유의하십시오; 파서는 매개변수에 true 값이 나타날 때 이를 올바르게 처리해야 합니다.

파서는 항목 또는 내부 리스트에 대해 최소 256개의 매개변수를 지원해야 하며, 최소 64자의 매개변수 키를 지원해야 합니다. 필드 명세는 필요에 따라 개별 매개변수의 순서나 값의 타입을 제약할 수 있습니다.

3.2. 딕셔너리

딕셔너리는 키가 짧은 텍스트 문자열인 키-값 쌍의 순서가 있는 맵이며, 값은 항목(섹션 3.3) 또는 항목들의 배열일 수 있고, 둘 다 매개변수(섹션 3.1.2)를 가질 수 있습니다. 멤버는 0개 이상일 수 있으며, 키는 해당 딕셔너리 범위 내에서 고유합니다.

구현체는 딕셔너리에 대해 인덱스와 키로 모두 접근할 수 있어야 합니다. 명세는 멤버에 접근할 때 어느 방식을 사용할지 선택할 수 있습니다.

리스트와 마찬가지로, 빈 딕셔너리는 전체 필드를 생략함으로써 표현됩니다. 이는 딕셔너리로 정의된 필드가 기본적으로 빈값을 가짐을 의미합니다.

일반적으로 필드 명세는 멤버별 허용 타입을 키로 지정하고 해당 멤버의 존재가 필수인지 선택적인지를 명시함으로써 딕셔너리의 의미를 정의합니다. 수신자는 키가 정의되지 않았거나 알려지지 않은 멤버를 해당 필드 명세가 명시적으로 금지하지 않는 한 무시해야 합니다.

텍스트형 HTTP 필드로 직렬화될 때, 멤버는 직렬화된 순서대로 정렬되며 쉼표와 선택적 공백으로 구분됩니다. 멤버 키에는 대문자를 포함할 수 없습니다. 키와 값은 "="로 구분됩니다(공백 없음). 예를 들면:

Example-Dict: en="Applepie", da=:w4ZibGV0w6ZydGU=:

이 예에서 마지막 "=" 문자는 바이트 시퀀스의 포함으로 인한 것임을 주의하십시오; 섹션 3.3.5를 참조하십시오.

값이 불리언(섹션 3.3.6)인 멤버는 true인 경우 직렬화 시 그 값을 생략해야 합니다. 예를 들어, 여기서 "b"와 "c"는 true입니다:

Example-Dict: a=?0, b, c; foo=bar

이 요구사항은 직렬화에만 해당하므로 파서는 딕셔너리 값에 true 불리언 값이 나타날 때 이를 올바르게 처리해야 합니다.

값이 토큰의 내부 리스트인 멤버를 가진 딕셔너리:

Example-Dict: rating=1.5, feelings=(joy sadness)

항목과 내부 리스트가 혼합되어 있고 일부는 매개변수를 가진 딕셔너리:

Example-Dict: a=(1 2), b=3, c=4;aa=bb, d=(5 6);valid

딕셔너리의 멤버는 동일한 헤더 또는 트레일러 섹션의 여러 줄에 걸쳐 분할될 수 있습니다. 예를 들어, 다음은 동등합니다:

Example-Dict: foo=1, bar=2

그리고

Example-Dict: foo=1
Example-Dict: bar=2

그러나 딕셔너리의 개별 멤버는 안전하게 여러 줄로 나눌 수 없습니다; 자세한 내용은 섹션 4.2를 참조하십시오.

파서는 최소한 1024개의 키/값 쌍과 최소 64자의 키를 포함하는 딕셔너리를 지원해야 합니다. 필드 명세는 필요에 따라 개별 딕셔너리 멤버의 순서나 값의 타입을 제약할 수 있습니다.

3.3. 항목

항목은 정수(섹션 3.3.1), 소수(섹션 3.3.2), 문자열(섹션 3.3.3), 토큰(섹션 3.3.4), 바이트 시퀀스(섹션 3.3.5), 불리언(섹션 3.3.6), 또는 날짜(섹션 3.3.7)일 수 있으며, 매개변수(섹션 3.1.2)를 가질 수 있습니다.

예를 들어, 항목이 정수로 정의된 헤더 필드는 다음과 같을 수 있습니다:

Example-Integer: 5

또는 매개변수와 함께:

Example-Integer: 5; foo=bar

3.3.1. 정수

정수는 -999,999,999,999,999에서 999,999,999,999,999까지(즉, 부호를 포함하여 최대 15자리)의 범위를 가지며, 이는 IEEE 754 호환성을 위한 것입니다 [IEEE754].

예를 들면:

Example-Integer: 42

15자리보다 큰 정수는 문자열(섹션 3.3.3), 바이트 시퀀스(섹션 3.3.5), 또는 정수에 대해 스케일링 인자로 동작하는 매개변수를 사용하는 등 다양한 방법으로 지원할 수 있습니다.

선행 0(예: "0002", "-01") 또는 부호 있는 0("-0")로 정수를 직렬화하는 것은 가능하지만, 이러한 구분은 구현에 의해 보존되지 않을 수 있습니다.

이 섹션의 본문에서 가독성을 위해 사용된 쉼표는 유선 포맷에서는 사용되지 않는다는 점에 유의하십시오.

3.3.2. 소수

소수는 정수부와 소수부를 가진 숫자입니다. 정수부는 최대 12자리, 소수부는 최대 3자리를 가집니다.

예를 들어, 값이 소수로 정의된 헤더는 다음과 같을 수 있습니다:

Example-Decimal: 4.5

선행 0(예: "0002.5", "-01.334"), 후행 0(예: "5.230", "-0.40"), 또는 부호 있는 0(예: "-0.0")로 소수를 직렬화하는 것은 가능하지만, 이러한 구분은 구현에 의해 보존되지 않을 수 있습니다.

직렬화 알고리즘(섹션 4.1.5)은 소수부가 세 자리를 초과하는 입력을 반올림합니다. 다른 반올림 전략을 원하면, 직렬화 전에 필드 정의에서 이를 지정해야 합니다.

3.3.3. 문자열

문자열은 0개 이상의 인쇄 가능한 ASCII 문자([RFC0020])로 이루어지며(즉, %x20에서 %x7E 범위), 탭, 줄바꿈, 캐리지 리턴 등은 제외됩니다.

비-ASCII 문자는 상호운용성 문제를 초래하므로 문자열에서 직접 지원되지 않으며, 예외적인 경우를 제외하고는 필드 값에 필요하지 않습니다.

필드 값에 비-ASCII 내용을 전달해야 할 경우에는 표시 문자열(Display String; 섹션 3.3.8)을 지정할 수 있습니다.

텍스트형 HTTP 필드로 직렬화될 때, 문자열은 큰따옴표로 구분되며 큰따옴표와 백슬래시는 역슬래시("\"")로 이스케이프합니다. 예를 들면:

Example-String: "hello world"

문자열은 구분자로 DQUOTE만 사용하며, 작은따옴표는 문자열을 구분하지 않습니다. 또한 "\" 다음에 올 수 있는 문자들 중에서 DQUOTE와 "\"만 이스케이프할 수 있으며, 그 외의 문자가 "\" 다음에 오면 구문 분석 실패를 일으켜야 합니다.

파서는 (디코딩 후) 최소 1024자 길이의 문자열을 지원해야 합니다.

3.3.4. 토큰

토큰은 알파벳 문자 또는 "*"로 시작하고 그 뒤에 0개 이상의 토큰 문자가 따르는 짧은 텍스트 단어입니다. 토큰 문자는 [HTTP]에 정의된 "token" ABNF 규칙에서 허용되는 문자와 ":" 및 "/" 문자를 포함합니다.

예를 들면:

Example-Token: foo123/456

파서는 최소 512자 길이의 토큰을 지원해야 합니다.

토큰은 주로 기존 HTTP 필드의 데이터 모델과의 호환성을 위해 정의되었으며, 일부 구현에서는 사용하기 위해 추가 처리 단계가 필요할 수 있습니다. 따라서 새로운 필드는 문자열을 사용하는 것이 권장됩니다.

3.3.5. 바이트 시퀀스

바이트 시퀀스는 구조화된 필드에서 전달될 수 있습니다.

텍스트형 HTTP 필드로 직렬화될 때, 바이트 시퀀스는 콜론으로 둘러싸여 표시되며 base64([RFC4648], Section 4)로 인코딩됩니다. 예를 들면:

Example-ByteSequence: :cHJldGVuZCB0aGlzIGlzIGJpbmFyeSBjb250ZW50Lg==:

파서는 디코딩 후 최소 16384 옥텟의 바이트 시퀀스를 지원해야 합니다.

3.3.6. 불리언

불리언 값은 구조화된 필드에서 전달될 수 있습니다.

텍스트형 HTTP 필드로 직렬화될 때, 불리언은 앞에 "?" 문자를 붙이고 그 다음에 true는 "1", false는 "0"으로 표시합니다. 예를 들면:

Example-Boolean: ?1

딕셔너리(섹션 3.2) 및 매개변수(섹션 3.1.2) 값에서는 불리언 true가 직렬화 시 값 생략으로 표시된다는 점에 유의하십시오.

3.3.7. 날짜

날짜 값은 구조화된 필드에서 전달될 수 있습니다.

날짜는 정수와 유사한 데이터 모델을 가지며, 윤초를 제외한 1970-01-01T00:00:00Z로부터의(음수일 수 있는) 초 단위 델타를 나타냅니다. 따라서 텍스트형 HTTP 필드에서의 직렬화는 정수와 유사하지만 선행 "@"로 구분됩니다.

예를 들면:

Example-Date: @1659578233

파서는 연도 1년부터 9999년까지의 모든 날짜를 포함하는 값(즉, 1970-01-01T00:00:00Z로부터 -62,135,596,800에서 253,402,214,400까지의 델타 초)을 지원해야 합니다.

3.3.8. 표시 문자열

표시 문자열은 문자열과 유사하게 0개 이상의 문자로 구성되지만, 문자열과 달리 유니코드 스칼라 값(대리 항목(surrogates)을 제외한 모든 유니코드 코드 포인트)을 허용합니다.

표시 문자열은 최종 사용자에게 표시되는 값에 사용되며 비-ASCII 내용을 전달해야 하는 경우에 의도된 타입입니다. 다만 유니코드는 정규화와 같은 처리 고려사항 및 동형문자 공격과 같은 보안 고려사항이 있어 올바르게 처리하기 어렵기 때문에, 문자열(섹션 3.3.3)이나 토큰(섹션 3.3.4)으로 충분한 상황에서는 표시 문자열 사용을 권장하지 않습니다.

표시 문자열은 값에 사용된 언어를 표시하지 않습니다; 필요한 경우(예: 매개변수로) 별도로 지정할 수 있습니다.

텍스트형 HTTP 필드에서 표시 문자열은 문자열과 유사하게 표현되지만, 비-ASCII 문자는 퍼센트 인코딩되고 앞에 "%"가 있어 문자열과 구분됩니다.

예를 들면:

Example-DisplayString: %"This is intended for display to %c3%bcsers."

표시 문자열을 처리할 때의 추가 보안 고려사항은 섹션 6을 참조하십시오.


4. HTTP에서 구조화된 필드 작업

이 섹션은 섹션 3에 정의된 추상 타입들을 텍스트형 HTTP 필드 값 및 그것들과 호환되는 다른 인코딩(예: 압축 전에 HPACK을 사용하는 HTTP/2의 경우)에 직렬화하고 구문 분석하는 방법을 정의합니다.

4.1. 구조화된 필드 직렬화

이 명세에 정의된 구조가 주어지면, HTTP 필드 값으로 사용하기에 적합한 ASCII 문자열을 반환하십시오.

  1. 구조가 Dictionary 또는 List이고 그 값이 비어 있는 경우(즉, 멤버가 없음) 필드를 전혀 직렬화하지 마십시오(즉, field-name과 field-value 둘 다 생략).

  2. 구조가 List인 경우, output_string을 구조에 대해 "Serializing a List"(섹션 4.1.1)을 실행한 결과로 하십시오.

  3. 그렇지 않고 구조가 Dictionary이면, output_string을 구조에 대해 "Serializing a Dictionary"(섹션 4.1.2)을 실행한 결과로 하십시오.

  4. 그렇지 않고 구조가 Item이면, output_string을 구조에 대해 "Serializing an Item"(섹션 4.1.3)을 실행한 결과로 하십시오.

  5. 그 외에는 직렬화에 실패하십시오.

  6. output_string을 ASCII 인코딩([RFC0020])을 사용하여 바이트 배열로 변환하여 반환하십시오.

4.1.1. 리스트 직렬화

(member_value, parameters) 튜플들의 배열인 input_list가 주어지면, HTTP 필드 값으로 사용하기에 적합한 ASCII 문자열을 반환하십시오.

  1. output을 빈 문자열로 하십시오.

  2. input_list의 각 (member_value, parameters)에 대해:

    1. member_value가 배열이면, (member_value, parameters)에 대해 "Serializing an Inner List"(섹션 4.1.1.1)을 실행한 결과를 output에 추가하십시오.

    2. 그렇지 않으면, (member_value, parameters)에 대해 "Serializing an Item"(섹션 4.1.3)을 실행한 결과를 output에 추가하십시오.

    3. input_list에 더 많은 member_values가 남아 있으면:

      1. ","를 output에 추가하십시오.

      2. 단일 SP를 output에 추가하십시오.

  3. output을 반환하십시오.

4.1.1.1. 내부 리스트 직렬화

inner_list로 (member_value, parameters) 튜플들의 배열이 주어지고 list_parameters가 주어지면, HTTP 필드 값으로 사용하기에 적합한 ASCII 문자열을 반환하십시오.

  1. output을 문자열 "("로 하십시오.

  2. inner_list의 각 (member_value, parameters)에 대해:

    1. (member_value, parameters)에 대해 "Serializing an Item"(섹션 4.1.3)을 실행한 결과를 output에 추가하십시오.

    2. inner_list에 더 많은 값이 남아 있으면 단일 SP를 output에 추가하십시오.

  3. ")"를 output에 추가하십시오.

  4. list_parameters에 대해 "Serializing Parameters"(섹션 4.1.1.2)을 실행한 결과를 output에 추가하십시오.

  5. output을 반환하십시오.

4.1.1.2. 매개변수 직렬화

각 멤버가 param_key와 param_value를 가지는 정렬된 Dictionary인 input_parameters가 주어지면, HTTP 필드 값으로 사용하기에 적합한 ASCII 문자열을 반환하십시오.

  1. output을 빈 문자열로 하십시오.

  2. input_parameters에서 param_key와 param_value를 순회할 때:

    1. ";"를 output에 추가하십시오.

    2. param_key에 대해 "Serializing a Key"(섹션 4.1.1.3)을 실행한 결과를 output에 추가하십시오.

    3. param_value가 Boolean true가 아니면:

      1. "="를 output에 추가하십시오.

      2. param_value에 대해 "Serializing a bare Item"(섹션 4.1.3.1)을 실행한 결과를 output에 추가하십시오.

  3. output을 반환하십시오.

4.1.1.3. 키 직렬화

input_key라는 키가 주어지면, HTTP 필드 값으로 사용하기에 적합한 ASCII 문자열을 반환하십시오.

  1. input_key를 ASCII 문자 시퀀스로 변환하십시오; 변환에 실패하면 직렬화에 실패하십시오.

  2. input_key에 lcalpha, DIGIT, "_", "-", ".", 또는 "*"에 해당하지 않는 문자가 포함되어 있으면 직렬화에 실패하십시오.

  3. input_key의 첫 문자가 lcalpha나 "*"가 아니면 직렬화에 실패하십시오.

  4. output을 빈 문자열로 하십시오.

  5. input_key를 output에 추가하십시오.

  6. output을 반환하십시오.

4.1.2. 딕셔너리 직렬화

각 멤버가 member_key와 (member_value, parameters) 튜플 값을 가지는 정렬된 Dictionary인 input_dictionary가 주어지면, HTTP 필드 값으로 사용하기에 적합한 ASCII 문자열을 반환하십시오.

  1. output을 빈 문자열로 하십시오.

  2. input_dictionary의 각 member_key와 (member_value, parameters)를 순회할 때:

    1. member_key에 대해 "Serializing a Key"(섹션 4.1.1.3)을 실행한 결과를 output에 추가하십시오.

    2. member_value가 Boolean true이면:

      1. parameters에 대해 "Serializing Parameters"(섹션 4.1.1.2)을 실행한 결과를 output에 추가하십시오.

    3. 그렇지 않으면:

      1. "="를 output에 추가하십시오.

      2. member_value가 배열이면, (member_value, parameters)에 대해 "Serializing an Inner List"(섹션 4.1.1.1)을 실행한 결과를 output에 추가하십시오.

      3. 그렇지 않으면, (member_value, parameters)에 대해 "Serializing an Item"(섹션 4.1.3)을 실행한 결과를 output에 추가하십시오.

    4. input_dictionary에 더 많은 멤버가 남아 있으면:

      1. ","를 output에 추가하십시오.

      2. 단일 SP를 output에 추가하십시오.

  3. output을 반환하십시오.

4.1.3. 항목 직렬화

bare_item이라는 Item과 item_parameters라는 Parameters가 주어지면, HTTP 필드 값으로 사용하기에 적합한 ASCII 문자열을 반환하십시오.

  1. output을 빈 문자열로 하십시오.

  2. bare_item에 대해 "Serializing a Bare Item"(섹션 4.1.3.1)을 실행한 결과를 output에 추가하십시오.

  3. item_parameters에 대해 "Serializing Parameters"(섹션 4.1.1.2)을 실행한 결과를 output에 추가하십시오.

  4. output을 반환하십시오.

4.1.3.1. 베어 항목 직렬화

input_item이라는 Item이 주어지면, HTTP 필드 값으로 사용하기에 적합한 ASCII 문자열을 반환하십시오.

  1. input_item이 Integer이면 input_item에 대해 "Serializing an Integer"(섹션 4.1.4)을 실행한 결과를 반환하십시오.

  2. input_item이 Decimal이면 input_item에 대해 "Serializing a Decimal"(섹션 4.1.5)을 실행한 결과를 반환하십시오.

  3. input_item이 String이면 input_item에 대해 "Serializing a String"(섹션 4.1.6)을 실행한 결과를 반환하십시오.

  4. input_item이 Token이면 input_item에 대해 "Serializing a Token"(섹션 4.1.7)을 실행한 결과를 반환하십시오.

  5. input_item이 Byte Sequence이면 input_item에 대해 "Serializing a Byte Sequence"(섹션 4.1.8)을 실행한 결과를 반환하십시오.

  6. input_item이 Boolean이면 input_item에 대해 "Serializing a Boolean"(섹션 4.1.9)을 실행한 결과를 반환하십시오.

  7. input_item이 Date이면 input_item에 대해 "Serializing a Date"(섹션 4.1.10)을 실행한 결과를 반환하십시오.

  8. input_item이 Display String이면 input_item에 대해 "Serializing a Display String"(섹션 4.1.11)을 실행한 결과를 반환하십시오.

  9. 그 외에는 직렬화에 실패하십시오.

4.1.4. 정수 직렬화

input_integer라는 Integer가 주어지면, HTTP 필드 값으로 사용하기에 적합한 ASCII 문자열을 반환하십시오.

  1. input_integer가 포함 범위 -999,999,999,999,999에서 999,999,999,999,999 사이의 정수가 아니면 직렬화에 실패하십시오.

  2. output을 빈 문자열로 하십시오.

  3. input_integer가 0보다 작으면(0과 같지 않은 경우) "-"를 output에 추가하십시오.

  4. input_integer의 숫자 값을 10진수로만 표현한 것을 output에 추가하십시오.

  5. output을 반환하십시오.

4.1.5. 소수 직렬화

input_decimal이라는 소수 숫자가 주어지면, HTTP 필드 값으로 사용하기에 적합한 ASCII 문자열을 반환하십시오.

  1. input_decimal이 소수가 아니면 직렬화에 실패하십시오.

  2. input_decimal의 소수점 오른쪽 유효 자릿수가 3자리를 초과하면, 소수점 이하 셋째 자리로 반올림하십시오. 마지막 자리를 반올림할 때는 가장 가까운 값으로 반올림하되, 정확히 중간일 경우에는 짝수로 반올림하십시오.

  3. 반올림 후 input_decimal의 소수점 왼쪽 유효 자릿수가 12자리를 초과하면 직렬화에 실패하십시오.

  4. output을 빈 문자열로 하십시오.

  5. input_decimal이 0보다 작으면(0과 같지 않은 경우) "-"를 output에 추가하십시오.

  6. input_decimal의 정수 부분을 10진수(숫자만)로 표현한 것을 output에 추가하십시오; 정수 부분이 0이면 "0"을 추가하십시오.

  7. "."를 output에 추가하십시오.

  8. input_decimal의 소수 부분이 0이면 "0"을 output에 추가하십시오.

  9. 그렇지 않으면 input_decimal의 소수 부분의 유효 숫자들을 10진수로 표현한 것을 output에 추가하십시오.

  10. output을 반환하십시오.

4.1.6. 문자열 직렬화

input_string이라는 String이 주어지면, HTTP 필드 값으로 사용하기에 적합한 ASCII 문자열을 반환하십시오.

  1. input_string을 ASCII 문자 시퀀스로 변환하십시오; 변환에 실패하면 직렬화에 실패하십시오.

  2. input_string에 %x00-1f 또는 %x7f-ff 범위의 문자가 포함되어 있으면(즉, VCHAR 또는 SP에 속하지 않음) 직렬화에 실패하십시오.

  3. output을 문자열 DQUOTE로 하십시오.

  4. input_string의 각 문자 char에 대해:

    1. char가 "\" 또는 DQUOTE이면:

      1. "\"를 output에 추가하십시오.

    2. char를 output에 추가하십시오.

  5. DQUOTE를 output에 추가하십시오.

  6. output을 반환하십시오.

4.1.7. 토큰 직렬화

input_token이라는 Token이 주어지면, HTTP 필드 값으로 사용하기에 적합한 ASCII 문자열을 반환하십시오.

  1. input_token을 ASCII 문자 시퀀스로 변환하십시오; 변환에 실패하면 직렬화에 실패하십시오.

  2. input_token의 첫 문자가 ALPHA나 "*"가 아니거나, 나머지 부분에 tchar, ":" 또는 "/"에 속하지 않는 문자가 포함되어 있으면 직렬화에 실패하십시오.

  3. output을 빈 문자열로 하십시오.

  4. input_token을 output에 추가하십시오.

  5. output을 반환하십시오.

4.1.8. 바이트 시퀀스 직렬화

input_bytes라는 Byte Sequence가 주어지면, HTTP 필드 값으로 사용하기에 적합한 ASCII 문자열을 반환하십시오.

  1. input_bytes가 바이트의 시퀀스가 아니면 직렬화에 실패하십시오.

  2. output을 빈 문자열로 하십시오.

  3. ":"를 output에 추가하십시오.

  4. [RFC4648]에 따라 input_bytes를 base64로 인코딩한 결과를 output에 추가하십시오(아래 요구사항을 고려).

  5. ":"를 output에 추가하십시오.

  6. output을 반환하십시오.

인코딩된 데이터는 [RFC4648]에 따라 "="로 패딩되어야 합니다.

또한, 구현 제약으로 불가능한 경우를 제외하고는 인코딩된 데이터의 패드 비트가 0으로 설정되는 것이 권장됩니다([RFC4648] 참조).

4.1.9. 불리언 직렬화

input_boolean이라는 Boolean이 주어지면, HTTP 필드 값으로 사용하기에 적합한 ASCII 문자열을 반환하십시오.

  1. input_boolean이 불리언이 아니면 직렬화에 실패하십시오.

  2. output을 빈 문자열로 하십시오.

  3. "?"를 output에 추가하십시오.

  4. input_boolean이 true이면 "1"을 output에 추가하십시오.

  5. input_boolean이 false이면 "0"을 output에 추가하십시오.

  6. output을 반환하십시오.

4.1.10. 날짜 직렬화

input_date라는 Date가 주어지면, HTTP 필드 값으로 사용하기에 적합한 ASCII 문자열을 반환하십시오.

  1. output을 "@"로 하십시오.

  2. input_date에 대해 "Serializing an Integer"(섹션 4.1.4)을 실행한 결과를 output에 추가하십시오.

  3. output을 반환하십시오.

4.1.11. 표시 문자열 직렬화

input_sequence라는 유니코드 코드 포인트 시퀀스가 주어지면, HTTP 필드 값으로 사용하기에 적합한 ASCII 문자열을 반환하십시오.

  1. input_sequence가 유니코드 코드 포인트의 시퀀스가 아니면 직렬화에 실패하십시오.

  2. byte_array를 input_sequence에 UTF-8 인코딩(섹션 3 of [UTF8])을 적용한 결과로 하십시오. 인코딩에 실패하면 직렬화에 실패하십시오.

  3. encoded_string을 "%" 다음에 DQUOTE가 있는 문자열로 하십시오.

  4. byte_array의 각 바이트에 대해:

    1. 바이트가 %x25("%"), %x22(DQUOTE), 또는 %x00-1f 혹은 %x7f-ff 범위에 속하면:

      1. "%"를 encoded_string에 추가하십시오.

      2. byte에 대해 base16 인코딩을 적용한 결과를 encoded_byte라 하십시오(Section 8 of [RFC4648]), 알파벳 문자는 소문자로 변환하십시오.

      3. encoded_byte를 encoded_string에 추가하십시오.

    2. 그렇지 않으면, 바이트를 ASCII 문자로 디코드하여 결과를 encoded_string에 추가하십시오.

  5. DQUOTE를 encoded_string에 추가하십시오.

  6. encoded_string을 반환하십시오.

[UTF8]는 U+D800에서 U+DFFF 사이(대리 항목)를 인코딩하는 것을 금지합니다; input_sequence에 그러한 코드 포인트가 포함되면 직렬화는 실패합니다.

4.2. 구조화된 필드 구문 분석

수신 구현체가 구조화된 필드로 알려진 HTTP 필드를 구문 분석할 때는 주의가 필요합니다. 여러 엣지 케이스가 상호운용성 또는 보안 문제를 일으킬 수 있기 때문입니다. 이 섹션은 이를 수행하는 알고리즘을 규정합니다.

선택된 필드의 field-value를 나타내는 바이트 배열인 input_bytes(해당 필드가 존재하지 않으면 비어 있음)와 field_type("dictionary", "list" 또는 "item" 중 하나)이 주어지면, 파싱된 필드 값을 반환하십시오.

  1. input_bytes를 ASCII 문자열 input_string으로 변환하십시오; 변환에 실패하면 파싱에 실패하십시오.

  2. input_string의 선행 SP 문자를 모두 제거하십시오.

  3. field_type이 "list"이면 input_string에 대해 "Parsing a List"(섹션 4.2.1)을 실행한 결과를 output으로 하십시오.

  4. field_type이 "dictionary"이면 input_string에 대해 "Parsing a Dictionary"(섹션 4.2.2)을 실행한 결과를 output으로 하십시오.

  5. field_type이 "item"이면 input_string에 대해 "Parsing an Item"(섹션 4.2.3)을 실행한 결과를 output으로 하십시오.

  6. input_string의 선행 SP 문자를 모두 제거하십시오.

  7. input_string이 비어 있지 않으면 파싱에 실패하십시오.

  8. 그렇지 않으면 output을 반환하십시오.

input_bytes를 생성할 때, 파서는 동일한 섹션(헤더 또는 트레일러)에 있는 필드 이름과 대소문자를 구분하지 않고 일치하는 모든 필드 라인을 하나의 쉼표로 구분된 field-value로 결합해야 합니다(RFC 9110 섹션 5.2 참조). 이렇게 하면 전체 필드 값이 올바르게 처리됩니다.

리스트와 딕셔너리의 경우, 이는 개별 최상위 데이터 구조의 멤버들이 여러 필드 인스턴스에 걸쳐 분할되지 않는 한 필드의 모든 라인을 올바르게 이어붙이는 효과가 있습니다. 두 타입의 파싱 알고리즘은 일부 구현이 필드 라인을 결합하는 데 탭 문자를 사용할 수 있으므로 탭 문자를 허용합니다.

여러 필드 라인에 걸쳐 분할된 문자열은 예측할 수 없는 결과를 낳습니다. 하나 이상의 쉼표(선택적 공백 포함)가 파서의 출력 문자열의 일부가 되기 때문입니다. 연결은 상류 중개자에 의해 수행될 수 있으므로, 직렬화자나 파서가 동일한 당사자의 제어 하에 있어도 결과는 그들의 제어 하에 있지 않습니다.

토큰, 정수, 소수 및 바이트 시퀀스는 삽입된 쉼표 때문에 여러 필드 라인으로 분할될 수 없습니다; 분할되면 파싱이 실패합니다.

파서는 동일한 섹션에 걸쳐 분포된 필드 값을 처리할 때, 그 라인 중 하나가 해당 필드로 파싱되지 않으면 실패할 수 있습니다. 예를 들어, sf-string으로 정의된 Example-String 필드를 처리하는 파싱기는 다음과 같은 필드 섹션을 처리할 때 실패할 수 있습니다:

Example-String: "foo
Example-String: bar"

파싱에 실패하면 전체 필드 값은 무시되어야 하거나(즉, 섹션에 필드가 없는 것처럼 처리), 또는 전체 HTTP 메시지는 잘못된 것으로 처리되어야 합니다. 이는 상호운용성과 안전성을 향상시키기 위해 의도적으로 엄격한 요구사항이며, 구조화된 필드를 사용하는 필드 명세는 이 요구사항을 완화할 수 없습니다.

이 요구사항은 필드를 파싱하지 않는 구현체에는 적용되지 않습니다; 예를 들어 중개자는 전달하기 전에 실패하는 필드를 메시지에서 제거할 의무가 없습니다.

4.2.1. 리스트 파싱

ASCII 문자열 input_string이 주어지면 (item_or_inner_list, parameters) 튜플들의 배열을 반환하십시오. input_string은 파싱된 값을 제거하도록 수정됩니다.

  1. members를 빈 배열로 하십시오.

  2. input_string이 비어 있지 않은 동안:

    1. input_string에 대해 "Parsing an Item or Inner List"(섹션 4.2.1.1)을 실행한 결과를 members에 추가하십시오.

    2. input_string의 선행 OWS 문자를 제거하십시오.

    3. input_string이 비어 있으면 members를 반환하십시오.

    4. input_string의 첫 문자를 소비하십시오; 그것이 ","가 아니면 파싱에 실패하십시오.

    5. input_string의 선행 OWS 문자를 제거하십시오.

    6. input_string이 비어 있으면 후행 쉼표가 있으므로 파싱에 실패하십시오.

  3. 구조화된 데이터가 발견되지 않았으므로 members(빈 상태)를 반환하십시오.

4.2.1.1. 항목 또는 내부 리스트 파싱

ASCII 문자열 input_string이 주어지면 (item_or_inner_list, parameters) 튜플을 반환하십시오. item_or_inner_list는 단일 베어 항목이거나 (bare_item, parameters) 튜플들의 배열일 수 있습니다. input_string은 파싱된 값을 제거하도록 수정됩니다.

  1. input_string의 첫 문자가 "("이면 input_string에 대해 "Parsing an Inner List"(섹션 4.2.1.2)을 실행한 결과를 반환하십시오.

  2. 그렇지 않으면 input_string에 대해 "Parsing an Item"(섹션 4.2.3)을 실행한 결과를 반환하십시오.

4.2.1.2. 내부 리스트 파싱

ASCII 문자열 input_string이 주어지면 (inner_list, parameters) 튜플을 반환하십시오. inner_list는 (bare_item, parameters) 튜플들의 배열입니다. input_string은 파싱된 값을 제거하도록 수정됩니다.

  1. input_string의 첫 문자를 소비하십시오; 그것이 "("가 아니면 파싱에 실패하십시오.

  2. inner_list를 빈 배열로 하십시오.

  3. input_string이 비어 있지 않은 동안:

    1. input_string의 선행 SP 문자를 제거하십시오.

    2. input_string의 첫 문자가 ")"이면:

      1. input_string의 첫 문자를 소비하십시오.

      2. input_string에 대해 "Parsing Parameters"(섹션 4.2.3.2)을 실행한 결과를 parameters로 하십시오.

      3. (inner_list, parameters) 튜플을 반환하십시오.

    3. input_string에 대해 "Parsing an Item"(섹션 4.2.3)을 실행한 결과를 item으로 하십시오.

    4. item을 inner_list에 추가하십시오.

    5. input_string의 첫 문자가 SP나 ")"가 아니면 파싱에 실패하십시오.

  4. 내부 리스트의 끝을 찾지 못했으므로 파싱에 실패하십시오.

4.2.2. 딕셔너리 파싱

ASCII 문자열 input_string이 주어지면, 그 값들이 (item_or_inner_list, parameters) 튜플인 정렬된 맵을 반환하십시오. input_string은 파싱된 값을 제거하도록 수정됩니다.

  1. dictionary를 빈 정렬된 맵으로 하십시오.

  2. input_string이 비어 있지 않은 동안:

    1. input_string에 대해 "Parsing a Key"(섹션 4.2.3.3)을 실행한 결과를 this_key로 하십시오.

    2. input_string의 첫 문자가 "="이면:

      1. input_string의 첫 문자를 소비하십시오.

      2. input_string에 대해 "Parsing an Item or Inner List"(섹션 4.2.1.1)을 실행한 결과를 member로 하십시오.

    3. 그렇지 않으면:

      1. value를 Boolean true로 하십시오.

      2. input_string에 대해 "Parsing Parameters"(섹션 4.2.3.2)을 실행한 결과를 parameters로 하십시오.

      3. member를 (value, parameters) 튜플로 하십시오.

    4. dictionary가 이미 this_key 키를 포함하면(문자 그대로 비교) 그 값을 member로 덮어쓰십시오.

    5. 그렇지 않으면 키 this_key와 값 member를 dictionary에 추가하십시오.

    6. input_string의 선행 OWS 문자를 제거하십시오.

    7. input_string이 비어 있으면 dictionary를 반환하십시오.

    8. input_string의 첫 문자를 소비하십시오; 그것이 ","가 아니면 파싱에 실패하십시오.

    9. input_string의 선행 OWS 문자를 제거하십시오.

    10. input_string이 비어 있으면 후행 쉼표가 있으므로 파싱에 실패하십시오.

  3. 구조화된 데이터가 발견되지 않았으므로 dictionary(빈 상태)를 반환하십시오.

중복된 Dictionary 키가 발견되면 마지막 인스턴스를 제외한 모든 것은 무시된다는 점에 유의하십시오.

4.2.3. 항목 파싱

ASCII 문자열 input_string이 주어지면 (bare_item, parameters) 튜플을 반환하십시오. input_string은 파싱된 값을 제거하도록 수정됩니다.

  1. input_string에 대해 "Parsing a Bare Item"(섹션 4.2.3.1)을 실행한 결과를 bare_item으로 하십시오.

  2. input_string에 대해 "Parsing Parameters"(섹션 4.2.3.2)을 실행한 결과를 parameters로 하십시오.

  3. (bare_item, parameters) 튜플을 반환하십시오.

4.2.3.1. 베어 항목 파싱

ASCII 문자열 input_string이 주어지면 베어 항목을 반환하십시오. input_string은 파싱된 값을 제거하도록 수정됩니다.

  1. input_string의 첫 문자가 "-" 또는 DIGIT이면 input_string에 대해 "Parsing an Integer or Decimal"(섹션 4.2.4)을 실행한 결과를 반환하십시오.

  2. input_string의 첫 문자가 DQUOTE이면 input_string에 대해 "Parsing a String"(섹션 4.2.5)을 실행한 결과를 반환하십시오.

  3. input_string의 첫 문자가 ALPHA 또는 "*"이면 input_string에 대해 "Parsing a Token"(섹션 4.2.6)을 실행한 결과를 반환하십시오.

  4. input_string의 첫 문자가 ":"이면 input_string에 대해 "Parsing a Byte Sequence"(섹션 4.2.7)을 실행한 결과를 반환하십시오.

  5. input_string의 첫 문자가 "?"이면 input_string에 대해 "Parsing a Boolean"(섹션 4.2.8)을 실행한 결과를 반환하십시오.

  6. input_string의 첫 문자가 "@"이면 input_string에 대해 "Parsing a Date"(섹션 4.2.9)을 실행한 결과를 반환하십시오.

  7. input_string의 첫 문자가 "%"이면 input_string에 대해 "Parsing a Display String"(섹션 4.2.10)을 실행한 결과를 반환하십시오.

  8. 그 외에는 항목 타입을 인식할 수 없으므로 파싱에 실패하십시오.

4.2.3.2. 매개변수 파싱

ASCII 문자열 input_string이 주어지면 값들이 베어 항목인 정렬된 맵을 반환하십시오. input_string은 파싱된 값을 제거하도록 수정됩니다.

  1. parameters를 빈 정렬된 맵으로 하십시오.

  2. input_string이 비어 있지 않은 동안:

    1. input_string의 첫 문자가 ";"가 아니면 루프를 종료하십시오.

    2. input_string의 시작에서 ";" 문자를 소비하십시오.

    3. input_string의 선행 SP 문자를 제거하십시오.

    4. input_string에 대해 "Parsing a Key"(섹션 4.2.3.3)을 실행한 결과를 param_key로 하십시오.

    5. param_value를 Boolean true로 하십시오.

    6. input_string의 첫 문자가 "="이면:

      1. input_string 시작의 "=" 문자를 소비하십시오.

      2. input_string에 대해 "Parsing a Bare Item"(섹션 4.2.3.1)을 실행한 결과를 param_value로 하십시오.

    7. parameters가 이미 param_key를 포함하면(문자 그대로 비교) 그 값을 param_value로 덮어쓰십시오.

    8. 그렇지 않으면 키 param_key와 값 param_value를 parameters에 추가하십시오.

  3. parameters를 반환하십시오.

중복된 매개변수 키가 발견되면 마지막 인스턴스를 제외한 모든 것은 무시된다는 점에 유의하십시오.

4.2.3.3. 키 파싱

ASCII 문자열 input_string이 주어지면 키를 반환하십시오. input_string은 파싱된 값을 제거하도록 수정됩니다.

  1. input_string의 첫 문자가 lcalpha나 "*"가 아니면 파싱에 실패하십시오.

  2. output_string을 빈 문자열로 하십시오.

  3. input_string이 비어 있지 않은 동안:

    1. input_string의 첫 문자가 lcalpha, DIGIT, "_", "-", ".", 또는 "*" 중 하나가 아니면 output_string을 반환하십시오.

    2. input_string의 첫 문자를 소비한 결과를 char라 하십시오.

    3. char를 output_string에 추가하십시오.

  4. output_string을 반환하십시오.

4.2.4. 정수 또는 소수 파싱

ASCII 문자열 input_string이 주어지면 Integer 또는 Decimal을 반환하십시오. input_string은 파싱된 값을 제거하도록 수정됩니다.

참고: 이 알고리즘은 Integer(섹션 3.3.1)와 Decimal(섹션 3.3.2)을 모두 파싱하고 해당 구조체를 반환합니다.

  1. type을 "integer"로 하십시오.

  2. sign을 1로 하십시오.

  3. input_number를 빈 문자열로 하십시오.

  4. input_string의 첫 문자가 "-"이면 그것을 소비하고 sign을 -1로 설정하십시오.

  5. input_string이 비어 있으면 빈 정수가 있으므로 파싱에 실패하십시오.

  6. input_string의 첫 문자가 DIGIT이 아니면 파싱에 실패하십시오.

  7. input_string이 비어 있지 않은 동안:

    1. input_string의 첫 문자를 소비한 결과를 char라 하십시오.

    2. char가 DIGIT이면 input_number에 추가하십시오.

    3. 그렇지 않고 type이 "integer"이고 char가 "."이면:

      1. input_number가 12자리를 초과하면 파싱에 실패하십시오.

      2. 그렇지 않으면 char를 input_number에 추가하고 type을 "decimal"로 설정하십시오.

    4. 그렇지 않으면 char를 input_string 앞에 다시 추가하고 루프를 종료하십시오.

    5. type이 "integer"이고 input_number가 15자를 초과하면 파싱에 실패하십시오.

    6. type이 "decimal"이고 input_number가 16자를 초과하면 파싱에 실패하십시오.

  8. type이 "integer"이면:

    1. output_number를 input_number를 정수로 파싱한 Integer로 하십시오.

  9. 그렇지 않으면:

    1. input_number의 마지막 문자가 "."이면 파싱에 실패하십시오.

    2. input_number에서 "." 이후의 문자 수가 3자를 초과하면 파싱에 실패하십시오.

    3. output_number를 input_number를 소수로 파싱한 Decimal로 하십시오.

  10. output_number에 sign을 곱하십시오.

  11. output_number를 반환하십시오.

4.2.5. 문자열 파싱

ASCII 문자열 input_string이 주어지면 인용이 제거된 String을 반환하십시오. input_string은 파싱된 값을 제거하도록 수정됩니다.

  1. output_string을 빈 문자열로 하십시오.

  2. input_string의 첫 문자가 DQUOTE가 아니면 파싱에 실패하십시오.

  3. input_string의 첫 문자를 제거하십시오.

  4. input_string이 비어 있지 않은 동안:

    1. input_string의 첫 문자를 소비한 결과를 char라 하십시오.

    2. char가 백슬래시("\")이면:

      1. 지금 input_string이 비어 있으면 파싱에 실패하십시오.

      2. input_string의 첫 문자를 소비한 결과를 next_char라 하십시오.

      3. next_char가 DQUOTE나 "\"가 아니면 파싱에 실패하십시오.

      4. next_char를 output_string에 추가하십시오.

    3. char가 DQUOTE이면 output_string을 반환하십시오.

    4. char가 %x00-1f 또는 %x7f-ff 범위에 속하면(즉, VCHAR 또는 SP에 속하지 않음) 파싱에 실패하십시오.

    5. 그렇지 않으면 char를 output_string에 추가하십시오.

  5. 닫는 DQUOTE를 찾지 못하고 input_string의 끝에 도달했으므로 파싱에 실패하십시오.

4.2.6. 토큰 파싱

ASCII 문자열 input_string이 주어지면 Token을 반환하십시오. input_string은 파싱된 값을 제거하도록 수정됩니다.

  1. input_string의 첫 문자가 ALPHA나 "*"가 아니면 파싱에 실패하십시오.

  2. output_string을 빈 문자열로 하십시오.

  3. input_string이 비어 있지 않은 동안:

    1. input_string의 첫 문자가 tchar, ":" 또는 "/"에 해당하지 않으면 output_string을 반환하십시오.

    2. input_string의 첫 문자를 소비한 결과를 char라 하십시오.

    3. char를 output_string에 추가하십시오.

  4. output_string을 반환하십시오.

4.2.7. 바이트 시퀀스 파싱

ASCII 문자열 input_string이 주어지면 Byte Sequence를 반환하십시오. input_string은 파싱된 값을 제거하도록 수정됩니다.

  1. input_string의 첫 문자가 ":"가 아니면 파싱에 실패하십시오.

  2. input_string의 첫 문자를 제거하십시오.

  3. input_string의 끝 전에 ":" 문자가 없으면 파싱에 실패하십시오.

  4. b64_content를 input_string에서 첫 ":" 문자 직전까지의 내용을 소비한 결과로 하십시오(첫 ":" 포함하지 않음).

  5. input_string의 처음에 있는 ":" 문자를 소비하십시오.

  6. b64_content에 ALPHA, DIGIT, "+", "/", "="에 포함되지 않는 문자가 있으면 파싱에 실패하십시오.

  7. b64_content를 base64로 디코딩한 결과를 binary_content로 하십시오([RFC4648]), 필요하면 패딩을 합성하십시오(수신자 동작에 대한 요구사항 참조). base64 디코딩에 실패하면 파싱에 실패합니다.

  8. binary_content를 반환하십시오.

일부 base64 구현은 "="로 적절히 패딩되지 않은 인코딩 데이터를 거부하지 못하므로([RFC4648] 참조), 파서는 "=" 패딩이 없을 때 실패해서는 안되나 구성 불가능한 경우는 예외입니다.

일부 base64 구현은 0이 아닌 패드 비트를 가진 인코딩 데이터를 거부하지 못하므로, 파서는 0이 아닌 패드 비트가 있을 때 실패해서는 안되나 구성 불가능한 경우는 예외입니다.

이 명세는 [RFC4648]의 섹션 3.1 및 3.3의 요구사항을 완화하지 않습니다; 따라서 파서는 base64 알파벳 외의 문자 및 인코딩된 데이터의 줄 바꿈에 대해서는 실패해야 합니다.

4.2.8. 불리언 파싱

ASCII 문자열 input_string이 주어지면 Boolean을 반환하십시오. input_string은 파싱된 값을 제거하도록 수정됩니다.

  1. input_string의 첫 문자가 "?"가 아니면 파싱에 실패하십시오.

  2. input_string의 첫 문자를 제거하십시오.

  3. input_string의 첫 문자가 "1"이면 그 문자를 제거하고 true를 반환하십시오.

  4. input_string의 첫 문자가 "0"이면 그 문자를 제거하고 false를 반환하십시오.

  5. 일치하는 값이 없으면 파싱에 실패하십시오.

4.2.9. 날짜 파싱

ASCII 문자열 input_string이 주어지면 Date를 반환하십시오. input_string은 파싱된 값을 제거하도록 수정됩니다.

  1. input_string의 첫 문자가 "@"가 아니면 파싱에 실패하십시오.

  2. input_string의 첫 문자를 제거하십시오.

  3. input_string에 대해 "Parsing an Integer or Decimal"(섹션 4.2.4)을 실행한 결과를 output_date로 하십시오.

  4. output_date가 Decimal이면 파싱에 실패하십시오.

  5. output_date를 반환하십시오.

4.2.10. 표시 문자열 파싱

ASCII 문자열 input_string이 주어지면 유니코드 코드 포인트 시퀀스를 반환하십시오. input_string은 파싱된 값을 제거하도록 수정됩니다.

  1. input_string의 처음 두 문자가 "%" 다음에 DQUOTE가 아니면 파싱에 실패하십시오.

  2. input_string의 처음 두 문자를 제거하십시오.

  3. byte_array를 빈 바이트 배열로 하십시오.

  4. input_string이 비어 있지 않은 동안:

    1. input_string의 첫 문자를 소비한 결과를 char라 하십시오.

    2. char가 %x00-1f 또는 %x7f-ff 범위에 속하면(즉, VCHAR 또는 SP에 속하지 않음) 파싱에 실패하십시오.

    3. char가 "%"이면:

      1. octet_hex를 input_string에서 두 문자 소비한 결과로 하십시오; 두 문자가 없으면 파싱에 실패하십시오.

      2. octet_hex가 %x30-39 또는 %x61-66 범위를 벗어나면(즉 0-9 또는 소문자 a-f가 아니면) 파싱에 실패하십시오.

      3. octet_hex를 16진 디코딩한 결과를 octet로 하십시오(Section 8 of [RFC4648]).

      4. octet을 byte_array에 추가하십시오.

    4. char가 DQUOTE이면:

      1. byte_array를 UTF-8 문자열로 디코딩한 결과를 unicode_sequence로 하십시오(Section 3 of [UTF8]). 디코딩에 실패하면 파싱에 실패하십시오.

      2. unicode_sequence를 반환하십시오.

    5. 그렇지 않고 char가 "%"나 DQUOTE가 아니면:

      1. char에 ASCII 인코딩을 적용한 결과를 byte로 하십시오.

      2. byte를 byte_array에 추가하십시오.

  5. 닫는 DQUOTE를 찾지 못하고 input_string의 끝에 도달했으므로 파싱에 실패하십시오.


5. IANA 고려사항

IANA는 "Hypertext Transfer Protocol (HTTP) Field Name Registry"에 다음 주석을 추가했습니다:

"Structured Type" 열은 해당되는 경우 필드의 타입(RFC 9651에 따라)을 나타내며, "Dictionary", "List" 또는 "Item"이 될 수 있습니다.

ALPHA 또는 "*" 이외의 문자로 시작하는 필드 이름은 Structured Fields Token으로 표현할 수 없으므로, 이를 참조하는 필드 값으로 매핑할 때 호환되지 않을 수 있음을 주의하십시오.

레지스트리에 새 열 "Structured Type"이 추가되었습니다.

표 1(Existing Fields)에 나열된 각 기존 레지스트리 항목에 대해 표시된 Structured Type도 추가되었습니다.

Table 1: Existing Fields
Field Name Structured Type
Accept-CH List
Cache-Status List
CDN-Cache-Control Dictionary
Cross-Origin-Embedder-Policy Item
Cross-Origin-Embedder-Policy-Report-Only Item
Cross-Origin-Opener-Policy Item
Cross-Origin-Opener-Policy-Report-Only Item
Origin-Agent-Cluster Item
Priority Dictionary
Proxy-Status List

6. 보안 고려사항

Structured Fields로 정의된 대부분의 타입은 크기 제한이 없으므로, 매우 큰 필드가 리소스 소비 공격 등의 공격 벡터가 될 수 있습니다. 대부분의 HTTP 구현은 그러한 공격을 완화하기 위해 개별 필드의 크기뿐만 아니라 전체 헤더 또는 트레일러 섹션의 크기를 제한합니다.

새 HTTP 필드를 주입할 수 있는 당사자가 Structured Field의 의미를 변경할 수 있습니다. 어떤 상황에서는 이것이 구문 분석 실패를 초래할 수 있지만, 모든 상황에서 신뢰할 수 있게 실패하게 하는 것은 불가능합니다.

Display String 타입은 정제 없이 모든 유니코드 코드 포인트를 전달할 수 있습니다. 예를 들어, 할당되지 않은 코드 포인트, 제어 포인트(널 포함), 또는 비문자 등이 포함될 수 있습니다. 따라서 Display String을 소비하는 애플리케이션은 표시 전에 신뢰되지 않는 콘텐츠를 필터링하거나 이스케이프하는 등의 전략을 고려해야 합니다. 자세한 내용은 [PRECIS][UNICODE-SECURITY]를 참조하십시오.

7. 참조

7.2. 정보 제공 참조

[HPACK]
Peon, R. and H. Ruellan, “HPACK: Header Compression for HTTP/2”, RFC 7541, DOI 10.17487/RFC7541, May 2015, <https://www.rfc-editor.org/info/rfc7541>.
[HTTP/2]
Thomson, M., Ed. and C. Benfield, Ed., “HTTP/2”, RFC 9113, DOI 10.17487/RFC9113, June 2022, <https://www.rfc-editor.org/info/rfc9113>.
[IEEE754]
IEEE, “IEEE Standard for Floating-Point Arithmetic”, IEEE Std 754-2019, DOI 10.1109/IEEESTD.2019.8766229, ISBN 978-1-5044-5924-2, July 2019, <https://ieeexplore.ieee.org/document/8766229>.
[PRECIS]
Saint-Andre, P. and M. Blanchet, “PRECIS Framework: Preparation, Enforcement, and Comparison of Internationalized Strings in Application Protocols”, RFC 8264, DOI 10.17487/RFC8264, October 2017, <https://www.rfc-editor.org/info/rfc8264>.
[RFC5234]
Crocker, D., Ed. and P. Overell, “Augmented BNF for Syntax Specifications: ABNF”, STD 68, RFC 5234, DOI 10.17487/RFC5234, January 2008, <https://www.rfc-editor.org/info/rfc5234>.
[RFC7493]
Bray, T., Ed., “The I-JSON Message Format”, RFC 7493, DOI 10.17487/RFC7493, March 2015, <https://www.rfc-editor.org/info/rfc7493>.
[RFC8259]
Bray, T., Ed., “The JavaScript Object Notation (JSON) Data Interchange Format”, STD 90, RFC 8259, DOI 10.17487/RFC8259, December 2017, <https://www.rfc-editor.org/info/rfc8259>.
[UNICODE-SECURITY]
Davis, M. and M. Suignard, “Unicode Security Considerations”, Unicode Technical Report #36, September 2014, <https://www.unicode.org/reports/tr36/tr36-15.html>.
Latest version available at <https://www.unicode.org/reports/tr36/>.

Appendix A. 자주 묻는 질문

A.1. 왜 JSON이 아닌가?

이전의 Structured Fields 제안들은 JSON([RFC8259])을 기반으로 했습니다. 그러나 HTTP 필드에 적합하도록 그 사용을 제약하려면 송신자와 수신자가 특정한 추가 처리를 구현해야 했습니다.

예를 들어, JSON은 큰 숫자와 중복 멤버가 있는 객체와 관련된 명세 문제를 가지고 있습니다. 이러한 문제를 피하기 위한 권고가 존재하지만(예: [RFC7493]), 신뢰할 수는 없습니다.

마찬가지로, JSON 문자열은 기본적으로 유니코드 문자열이므로 비교 등에서 여러 상호운용성 문제를 야기할 수 있습니다. 구현자들에게 불필요한 경우 비-ASCII 내용을 피하도록 권고할 수는 있으나, 이를 강제하기는 어렵습니다.

또 다른 예로 JSON은 임의 깊이로 콘텐츠를 중첩할 수 있습니다. 그로 인해 필요한 메모리 할당이 적합하지 않을 수 있으므로(예: 임베디드 및 리소스가 제한된 서버 배포 환경) 어떤 방식으로든 이를 제한할 필요가 있습니다. 그러나 기존 JSON 구현에는 이러한 제한이 없고 제한을 지정하더라도 일부 필드 정의는 이를 위반할 필요가 있을 것입니다.

JSON이 널리 채택되고 구현되어 있기 때문에 모든 구현에 걸쳐 이러한 추가 제약을 강제하기 어렵습니다; 일부 배포는 이를 준수하지 못해 상호운용성에 해를 끼칠 수 있습니다. 요컨대, 필드 값이 JSON처럼 보이면 사람들은 필드 값에 JSON 파서/직렬화기를 사용하려는 유혹을 받을 것입니다.

Structured Fields의 주요 목표 중 하나가 상호운용성을 개선하고 구현을 단순화하는 것이므로, 이러한 우려는 전용 파서와 직렬화기를 요구하는 형식을 선택하도록 이끌었습니다.

또한, 많은 사람들이 JSON이 HTTP 필드에 '어울리지 않는다'는 인식을 공유하고 있었습니다.


Appendix B. 구현 노트

이 명세의 일반적인 구현체는 최상위 serialize(섹션 4.1) 및 parse(섹션 4.2) 함수를 노출해야 합니다. 이것들이 반드시 함수일 필요는 없으며, 예를 들어 서로 다른 최상위 타입에 대한 메서드를 가진 객체로 구현할 수도 있습니다.

상호운용성을 위해, 일반 구현체는 완전하고 알고리즘을 충실히 따라야 합니다; 섹션 1.1을 참조하십시오. 이를 돕기 위해 커뮤니티에서 공통 테스트 스위트가 <https://github.com/httpwg/structured-field-tests>에 의해 유지되고 있습니다.

구현자는 Dictionaries와 Parameters가 순서를 보존하는 맵이라는 점을 유념해야 합니다. 일부 필드는 이러한 데이터 타입의 순서에 의미를 부여하지 않을 수 있지만, 이를 노출하여 이를 필요로 하는 애플리케이션에서 사용할 수 있게 해야 합니다.

마찬가지로, 구현체는 Tokens와 Strings 사이의 구분을 보존하는 것이 중요하다는 점을 유의해야 합니다. 대부분의 프로그래밍 언어는 다른 타입들과 잘 매핑되는 내장 타입을 제공하지만, 이러한 타입들을 분리된 상태로 유지하려면 "token" 래퍼 객체를 생성하거나 함수에 매개변수를 추가해야 할 수 있습니다.

직렬화 알고리즘은 모든 경우에 섹션 3에 정의된 데이터 타입으로 엄격히 제한되지 않도록 정의되어 있습니다. 예를 들어, Decimals는 더 광범위한 입력을 받아 허용되는 값으로 반올림하도록 설계되었습니다.

구현체는 각 타입에 대해 정의된 최소값을 준수하는 범위 내에서 다양한 구조의 크기를 제한할 수 있습니다. 구조가 구현 한도를 초과하면 해당 구조는 파싱 또는 직렬화에 실패합니다.


Appendix C. ABNF

이 섹션은 증강 백우스-나우어 형식(ABNF) 표기법([RFC5234])을 사용하여 Structured Fields의 예상 문법을 설명합니다. 다만, 모든 요구사항을 포착하지 못하므로 문법 검증에 사용해서는 안 됩니다.

이 섹션은 비규범적입니다. 구문 분석 알고리즘과 ABNF 사이에 불일치가 있을 경우에는 명시된 알고리즘이 우선합니다.

sf-list       = list-member *( OWS "," OWS list-member )
list-member   = sf-item / inner-list

inner-list    = "(" *SP [ sf-item *( 1*SP sf-item ) *SP ] ")"
                parameters

parameters    = *( ";" *SP parameter )
parameter     = param-key [ "=" param-value ]
param-key     = key
key           = ( lcalpha / "*" )
                *( lcalpha / DIGIT / "_" / "-" / "." / "*" )
lcalpha       = %x61-7A ; a-z
param-value   = bare-item

sf-dictionary = dict-member *( OWS "," OWS dict-member )
dict-member   = member-key ( parameters / ( "=" member-value ))
member-key    = key
member-value  = sf-item / inner-list

sf-item   = bare-item parameters
bare-item = sf-integer / sf-decimal / sf-string / sf-token
            / sf-binary / sf-boolean / sf-date / sf-displaystring

sf-integer       = ["-"] 1*15DIGIT
sf-decimal       = ["-"] 1*12DIGIT "." 1*3DIGIT
sf-string        = DQUOTE *( unescaped / "%" / bs-escaped ) DQUOTE
sf-token         = ( ALPHA / "*" ) *( tchar / ":" / "/" )
sf-binary        = ":" base64 ":"
sf-boolean       = "?" ( "0" / "1" )
sf-date          = "@" sf-integer
sf-displaystring = "%" DQUOTE *( unescaped / "\" / pct-encoded )
                   DQUOTE

base64       = *( ALPHA / DIGIT / "+" / "/" ) *"="

unescaped    = %x20-21 / %x23-24 / %x26-5B / %x5D-7E
bs-escaped   = "\" ( DQUOTE / "\" )

pct-encoded  = "%" lc-hexdig lc-hexdig
lc-hexdig = DIGIT / %x61-66 ; 0-9, a-f

Appendix D. RFC 8941에서의 변경 사항

"HTTP용 구조화된 필드 값" 명세의 이 개정판은 다음과 같은 변경을 포함합니다:

  • Date Structured Type를 추가했습니다. (섹션 3.3.7)

  • 새로운 Structured Fields 정의에서 ABNF 사용을 권장하는 것을 중단했습니다. (섹션 2)

  • ABNF를 정보성 부록으로 이동했습니다. (부록 C)

  • "Hypertext Transfer Protocol (HTTP) Field Name Registry"에 "Structured Type" 열을 추가했습니다. (섹션 5)

  • 파싱 실패 처리 방식을 정교화했습니다. (섹션 4.2)

  • Display String Structured Type를 추가했습니다. (섹션 3.3.8)


감사의 글

이 명세의 개발 과정에서 상세한 피드백과 신중한 검토를 제공한 Matthew Kerwin에게 깊이 감사드립니다.

또한 Ian Clelland, Roy Fielding, Anne van Kesteren, Kazuho Oku, Evert Pot, Julian Reschke, Martin Thomson, Mike West, Jeffrey Yasskin의 기여에도 감사드립니다.


저자 주소

Mark Nottingham
Cloudflare
Prahran, VIC
Australia
EMail: mnot@mnot.net
URI: https://www.mnot.net/
Poul-Henning Kamp
The Varnish Cache Project
EMail: phk@varnish-cache.org