인터넷 엔지니어링 태스크 포스 (IETF) R. Peon
의견 요청(Request for Comments): 7541 Google, Inc
카테고리: 표준 트랙 H. Ruellan
ISSN: 2070-1721 Canon CRF
2015년 5월

HPACK: HTTP/2용 헤더 압축


초록

이 규격은 HTTP/2에서 사용하기 위해 HTTP 헤더 필드를 효율적으로 표현하기 위한 압축 형식인 HPACK을 정의한다.

이 메모의 상태

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

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

이 문서의 현재 상태, 정정 사항, 및 이에 대한 피드백 제공 방법은 http://www.rfc-editor.org/info/rfc7541에서 확인할 수 있습니다.

Copyright Notice

Copyright (c) 2015 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 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.

1. 소개

HTTP/1.1(참조 [RFC7230])에서는 헤더 필드가 압축되지 않습니다. 웹 페이지가 수십에서 수백 개의 요청을 필요로 하게 되면서 이러한 요청들에 포함된 중복된 헤더 필드가 불필요하게 대역폭을 소비하여 지연을 유의하게 증가시킵니다.

SPDY [SPDY]는 처음에 DEFLATE [DEFLATE] 형식을 사용하여 헤더 필드를 압축함으로써 이 중복 문제를 해결했습니다. 이 방식은 중복된 헤더 필드를 효율적으로 표현하는 데 매우 효과적이었지만, CRIME(Compression Ratio Info-leak Made Easy) 공격에서 보여준 바와 같이 보안 위험을 노출시켰습니다(참조 [CRIME]).

이 규격은 중복 헤더 필드를 제거하고 알려진 보안 공격에 대한 취약성을 제한하며, 제약된 환경에서 사용하기 위한 유한한 메모리 요구사항을 가지는 새로운 압축기인 HPACK을 정의합니다. HPACK의 잠재적 보안 우려 사항은 섹션 7에 설명되어 있습니다.

HPACK 형식은 의도적으로 단순하고 유연하지 않게 설계되었습니다. 이러한 두 가지 특성은 구현 오류로 인한 상호운용성 또는 보안 문제의 위험을 줄여줍니다. 확장 메커니즘은 정의되어 있지 않으며; 형식의 변경은 완전한 대체를 정의함으로써만 가능됩니다.

1.1. 개요

이 규격에서 정의된 형식은 헤더 필드 목록을 중복 쌍을 포함할 수 있는 순서화된 이름-값 쌍의 모음으로 취급합니다. 이름과 값은 옥텟의 불투명한 연속으로 간주되며, 헤더 필드의 순서는 압축 및 해제압축 후에도 보존됩니다.

인코딩은 헤더 필드를 인덱스 값에 매핑하는 헤더 필드 테이블에 의해 영향을 받습니다. 이러한 헤더 필드 테이블은 새로운 헤더 필드가 인코딩되거나 디코딩될 때 점진적으로 업데이트될 수 있습니다.

인코딩된 형태에서는 헤더 필드가 리터럴로 표현되거나 헤더 필드 테이블의 항목을 참조하는 참조로 표현됩니다. 따라서 헤더 필드 목록은 참조와 리터럴 값을 혼합하여 인코딩될 수 있습니다.

리터럴 값은 직접 인코딩되거나 정적 허프만 코드를 사용할 수 있습니다.

인코더는 어떤 헤더 필드를 헤더 필드 테이블에 새로운 항목으로 삽입할지 결정할 책임이 있습니다. 디코더는 인코더가 지시한대로 헤더 필드 테이블의 수정을 실행하여 헤더 필드 목록을 재구성합니다. 이는 디코더가 단순하게 유지되면서 다양한 인코더와 상호운용되도록 합니다.

이러한 다양한 메커니즘을 사용하여 헤더 필드를 표현하는 예제는 부록 C에서 확인할 수 있습니다.

1.2. 규약

이 문서에서 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", 및 "OPTIONAL"이라는 주요 단어는 RFC 2119 [RFC2119]에 설명된 대로 해석됩니다.

모든 수치 값은 네트워크 바이트 순서입니다. 값은 별도 표시가 없는 한 부호 없는 값입니다. 리터럴 값은 적절하게 십진수나 16진수로 제공됩니다.

1.3. 용어

이 규격은 다음 용어들을 사용합니다:

Header Field:
이름-값 쌍. 이름과 값 모두 옥텟의 불투명한 연속으로 처리됩니다.
Dynamic Table:
동적 테이블(참조 섹션 2.3.2)은 저장된 헤더 필드를 인덱스 값과 연관시키는 테이블입니다. 이 테이블은 동적이며 인코딩 또는 디코딩 컨텍스트에 특정합니다.
Static Table:
정적 테이블(참조 섹션 2.3.1)은 자주 발생하는 헤더 필드를 인덱스 값과 정적으로 연관시키는 테이블입니다. 이 테이블은 정렬되어 있고 읽기 전용이며 항상 접근 가능하고 모든 인코딩 및 디코딩 컨텍스트 간에 공유될 수 있습니다.
Header List:
헤더 목록은 함께 인코딩되는 순서화된 헤더 필드의 모음이며 중복된 헤더 필드를 포함할 수 있습니다. HTTP/2 헤더 블록에 포함된 완전한 헤더 필드 목록이 헤더 목록입니다.
Header Field Representation:
헤더 필드는 인코딩된 형태에서 리터럴 또는 인덱스로 표현될 수 있습니다(참조 섹션 2.4).
Header Block:
헤더 필드 표현의 순서화된 목록으로, 디코딩하면 완전한 헤더 목록이 됩니다.

2. 압축 프로세스 개요

이 규격은 특정 인코더 알고리즘을 설명하지 않습니다. 대신 디코더가 어떻게 동작해야 하는지를 정확히 정의하여, 인코더가 이 정의가 허용하는 어떠한 인코딩도 생성할 수 있도록 합니다.

2.1. 헤더 목록 정렬

HPACK은 헤더 목록 내의 헤더 필드 순서를 보존합니다. 인코더는 원래 헤더 목록에서의 순서에 따라 헤더 블록 내의 헤더 필드 표현들을 정렬해야 합니다. 디코더는 헤더 블록에서의 순서에 따라 디코딩된 헤더 목록의 헤더 필드들을 정렬해야 합니다.

2.2. 인코딩 및 디코딩 컨텍스트

헤더 블록을 해제압축하려면 디코더는 디코딩 컨텍스트로서 동적 테이블(참조 섹션 2.3.2)만 유지하면 됩니다. 다른 동적 상태는 필요하지 않습니다.

HTTP와 같이 양방향 통신에 사용될 때, 엔드포인트가 유지하는 인코딩 및 디코딩 동적 테이블은 완전히 독립적입니다. 즉, 요청과 응답의 동적 테이블은 분리되어 있습니다.

2.3. 인덱싱 테이블

HPACK은 헤더 필드를 인덱스와 연관시키기 위해 두 개의 테이블을 사용합니다. 정적 테이블(참조 섹션 2.3.1)은 미리 정의되어 있으며 일반적인 헤더 필드를 포함합니다(대부분 비어 있는 값과 함께). 동적 테이블(참조 섹션 2.3.2)은 동적이며 인코더가 인코딩된 헤더 목록에서 반복되는 헤더 필드를 인덱싱하는 데 사용할 수 있습니다.

이 두 테이블은 인덱스 값을 정의하기 위해 단일 주소 공간으로 결합됩니다(참조 섹션 2.3.3).

2.3.1. 정적 테이블

정적 테이블은 미리 정의된 정적 헤더 필드 목록으로 구성됩니다. 그 항목들은 부록 A에 정의되어 있습니다.

2.3.2. 동적 테이블

동적 테이블은 선입선출 순서로 유지되는 헤더 필드 목록으로 구성됩니다. 동적 테이블의 첫 번째이자 최신 항목은 가장 낮은 인덱스에 있고, 가장 오래된 항목은 가장 높은 인덱스에 위치합니다.

동적 테이블은 처음에는 비어 있습니다. 항목들은 각 헤더 블록이 해제압축될 때 추가됩니다.

동적 테이블은 중복 항목(즉, 동일한 이름과 동일한 값을 가진 항목)을 포함할 수 있습니다. 따라서 디코더는 중복 항목을 오류로 처리해서는 안 됩니다.

인코더는 동적 테이블을 어떻게 업데이트할지 결정하므로 동적 테이블이 사용하는 메모리 양을 제어할 수 있습니다. 디코더의 메모리 요구사항을 제한하기 위해 동적 테이블 크기는 엄격하게 제한됩니다(참조 섹션 4.2).

디코더는 헤더 필드 표현 목록을 처리하는 동안 동적 테이블을 업데이트합니다(참조 섹션 3.2).

2.3.3. 인덱스 주소 공간

정적 테이블과 동적 테이블은 단일 인덱스 주소 공간으로 결합됩니다.

정적 테이블의 길이(포함) 사이의 인덱스들은 정적 테이블의 요소들을 가리킵니다(참조 섹션 2.3.1).

정적 테이블의 길이보다 큰 인덱스는 동적 테이블의 요소를 가리킵니다(참조 섹션 2.3.2). 동적 테이블로의 인덱스를 찾기 위해 정적 테이블의 길이를 빼야 합니다.

두 테이블의 길이 합보다 큰 인덱스는 디코딩 오류로 처리되어야 합니다.

정적 테이블 크기를 s, 동적 테이블 크기를 k라고 할 때, 다음 다이어그램은 전체 유효 인덱스 주소 공간을 보여줍니다.

        <----------  Index Address Space ---------->
        <-- Static  Table -->  <-- Dynamic Table -->
        +---+-----------+---+  +---+-----------+---+
        | 1 |    ...    | s |  |s+1|    ...    |s+k|
        +---+-----------+---+  +---+-----------+---+
                               ^                   |
                               |                   V
                        Insertion Point      Dropping Point

그림 1: 인덱스 주소 공간

2.4. 헤더 필드 표현

인코딩된 헤더 필드는 인덱스 또는 리터럴로 표현될 수 있습니다.

인덱스 표현은 정적 테이블 또는 동적 테이블의 항목에 대한 참조로서 헤더 필드를 정의합니다(참조 섹션 6.1).

리터럴 표현은 이름과 값을 지정하여 헤더 필드를 정의합니다. 헤더 필드 이름은 리터럴로 표현되거나 정적 테이블 또는 동적 테이블의 항목에 대한 참조로 표현될 수 있습니다. 헤더 필드 값은 리터럴로 표현됩니다.

세 가지 다른 리터럴 표현이 정의됩니다:

  • 동적 테이블의 시작 부분에 헤더 필드를 새 항목으로 추가하는 리터럴 표현(참조 섹션 6.2.1).
  • 헤더 필드를 동적 테이블에 추가하지 않는 리터럴 표현(참조 섹션 6.2.2).
  • 헤더 필드를 동적 테이블에 추가하지 않으며, 중개자가 재인코딩할 때 특히 이 헤더 필드는 항상 리터럴 표현을 사용해야 한다는 추가 규정이 있는 리터럴 표현(참조 섹션 6.2.3). 이 표현은 압축으로 인해 위험에 처하지 않아야 하는 헤더 필드 값을 보호하기 위한 목적입니다(자세한 내용은 섹션 7.1.3 참조).

이러한 리터럴 표현들 중 하나의 선택은 보안 고려사항에 의해 안내될 수 있으며, 민감한 헤더 필드 값을 보호하기 위해 사용됩니다(참조 섹션 7.1).

헤더 필드 이름 또는 값의 리터럴 표현은 옥텟의 연속을 직접 인코딩하거나 정적 허프만 코드를 사용하여 인코딩할 수 있습니다(참조 섹션 5.2).

3. 헤더 블록 디코딩

3.1. 헤더 블록 처리

디코더는 원래 헤더 목록을 재구성하기 위해 헤더 블록을 순차적으로 처리합니다.

헤더 블록은 헤더 필드 표현들의 연결(concatenation)입니다. 다양한 가능한 헤더 필드 표현은 섹션 6에 설명되어 있습니다.

헤더 필드가 디코딩되어 재구성된 헤더 목록에 추가되면 그 헤더 필드는 제거될 수 없습니다. 헤더 목록에 추가된 헤더 필드는 안전하게 애플리케이션으로 전달될 수 있습니다.

결과 헤더 필드를 애플리케이션으로 전달함으로써, 디코더는 동적 테이블에 필요한 메모리 외에 최소한의 일시적 메모리만으로 구현될 수 있습니다.

3.2. 헤더 필드 표현 처리

헤더 블록을 처리하여 헤더 목록을 얻는 과정은 이 섹션에 정의되어 있습니다. 디코딩이 성공적으로 헤더 목록을 생성하게 하려면, 디코더는 다음 규칙들을 준수해야 합니다.

헤더 블록에 포함된 모든 헤더 필드 표현은 아래에 명시된 대로 나타나는 순서로 처리됩니다. 다양한 헤더 필드 표현의 형식에 대한 세부사항과 몇 가지 추가 처리 지침은 섹션 6에 있습니다.

인덱스 표현은 다음 동작을 수반합니다:

  • 정적 테이블 또는 동적 테이블의 참조된 항목에 해당하는 헤더 필드가 디코딩된 헤더 목록에 추가됩니다.

동적 테이블에 추가되지 않는 리터럴 표현은 다음 동작을 수반합니다:

  • 헤더 필드가 디코딩된 헤더 목록에 추가됩니다.

동적 테이블에 추가되는 리터럴 표현은 다음 동작들을 수반합니다:

  • 헤더 필드가 디코딩된 헤더 목록에 추가됩니다.
  • 헤더 필드가 동적 테이블의 시작 부분에 삽입됩니다. 이 삽입은 동적 테이블의 이전 항목들이 축출되는 결과를 초래할 수 있습니다(참조 섹션 4.4).

4. 동적 테이블 관리

디코더 측의 메모리 요구를 제한하기 위해 동적 테이블의 크기는 제약됩니다.

4.1. 테이블 크기 계산

동적 테이블의 크기는 그 항목들의 크기의 합입니다.

항목의 크기는 이름의 옥텟 길이(섹션 5.2에 정의된 대로), 값의 옥텟 길이, 그리고 32의 합입니다.

항목의 크기는 이름과 값의 길이를 허프만 인코딩을 적용하지 않은 상태로 계산합니다.

4.2. 최대 테이블 크기

HPACK을 사용하는 프로토콜은 인코더가 동적 테이블에 사용할 수 있도록 허용된 최대 크기를 결정합니다. HTTP/2에서는 이 값이 SETTINGS_HEADER_TABLE_SIZE 설정에 의해 결정됩니다(자세한 내용은 [Section 6.5.2][HTTP2]를 참조하십시오).

인코더는 이 최대 크기보다 작은 용량을 사용하도록 선택할 수 있습니다(섹션 6.3 참조). 그러나 선택된 크기는 프로토콜에 의해 설정된 최대값보다 작거나 같아야 합니다.

동적 테이블의 최대 크기 변경은 동적 테이블 크기 업데이트로 신호됩니다(섹션 6.3 참조). 이 동적 테이블 크기 업데이트는 동적 테이블 크기 변경 이후 첫 번째 헤더 블록의 시작 부분에서 발생해야 합니다. HTTP/2에서는 이 변경이 설정 설정의 확인(settings acknowledgment)에 이어서 발생합니다(자세한 내용은 [Section 6.5.3][HTTP2] 참조).

두 개의 헤더 블록 전송 사이에 최대 테이블 크기에 대한 여러 업데이트가 발생할 수 있습니다. 이 구간 내에서 이 크기가 한 번 이상 변경된 경우, 그 구간에서 발생한 가장 작은 최대 테이블 크기가 동적 테이블 크기 업데이트로 신호되어야 합니다. 최종 최대 크기는 항상 신호되며, 결과적으로 최대 두 번의 동적 테이블 크기 업데이트가 발생합니다. 이는 디코더가 동적 테이블 크기 감소에 따라 항목 축출을 수행할 수 있도록 보장합니다(섹션 4.3 참조).

이 메커니즘은 최대 크기를 0으로 설정하여 동적 테이블의 항목을 완전히 지우는 데 사용할 수 있으며, 이후 복원될 수 있습니다.

4.3. 동적 테이블 크기 변경 시 항목 축출

동적 테이블의 최대 크기가 축소될 때마다, 동적 테이블의 끝에서부터 항목들이 축출되어 동적 테이블의 크기가 최대 크기 이하가 될 때까지 진행됩니다.

4.4. 새 항목 추가 시 항목 축출

새 항목이 동적 테이블에 추가되기 전에, 동적 테이블의 끝에서부터 항목들이 축출되어 동적 테이블의 크기가 (최대 크기 - 새 항목 크기) 이하가 되거나 테이블이 비어 있을 때까지 진행됩니다.

새 항목의 크기가 최대 크기보다 작거나 같으면 해당 항목은 테이블에 추가됩니다. 새 항목이 최대 크기보다 큰 경우 추가 시도가 오류는 아니며, 최대 크기보다 큰 항목을 추가하려는 시도는 기존의 모든 항목을 비우고 결과적으로 빈 테이블을 초래합니다.

새 항목은 동적 테이블에 이 새 항목을 추가할 때 축출될 항목의 이름을 참조할 수 있습니다. 구현에서는 참조된 항목이 새 항목을 삽입하기 전에 동적 테이블에서 축출되는 경우 참조된 이름을 삭제하지 않도록 주의해야 합니다.

5. 원시 타입 표현

HPACK 인코딩은 두 가지 원시 타입을 사용합니다: 부호 없는 가변 길이 정수와 옥텟 문자열.

5.1. 정수 표현

정수는 이름 인덱스, 헤더 필드 인덱스 또는 문자열 길이를 나타내는 데 사용됩니다. 정수 표현은 옥텟 내의 어느 위치에서나 시작할 수 있습니다. 최적화된 처리를 허용하기 위해 정수 표현은 항상 옥텟의 끝에서 종료됩니다.

정수는 두 부분으로 표현됩니다: 현재 옥텟을 채우는 접두사와, 정수 값이 접두사에 맞지 않는 경우 사용되는 선택적 옥텟 목록. 접두사의 비트 수(N)는 정수 표현의 매개변수입니다.

정수 값이 충분히 작아, 즉 2N-1보다 엄격히 작으면 N비트 접두사 내에 인코딩됩니다.

  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| ? | ? | ? |       Value       |
+---+---+---+-------------------+

그림 2: 접두사 내에 인코딩된 정수 값 (N = 5에 해당)

그렇지 않은 경우, 접두사의 모든 비트는 1로 설정되고, 값에서 2N-1을 뺀 결과가 하나 이상의 옥텟 목록을 사용하여 인코딩됩니다. 각 옥텟의 최상위 비트는 연속 플래그로 사용되며, 목록의 마지막 옥텟을 제외하고는 1로 설정됩니다. 옥텟의 나머지 비트들은 감소된 값을 인코딩하는 데 사용됩니다.

  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| ? | ? | ? | 1   1   1   1   1 |
+---+---+---+-------------------+
| 1 |    Value-(2^N-1) LSB      |
+---+---------------------------+
               ...
+---+---------------------------+
| 0 |    Value-(2^N-1) MSB      |
+---+---------------------------+

그림 3: 접두사 뒤에 인코딩된 정수 값 (N = 5에 해당)

옥텟 목록에서 정수 값을 디코딩할 때는 목록의 옥텟 순서를 역으로 뒤집는 것부터 시작합니다. 그 다음 각 옥텟에 대해 최상위 비트를 제거합니다. 옥텟들의 나머지 비트들을 이어 붙이고, 결과 값에 2N-1을 더하여 정수 값을 얻습니다.

접두사 크기 N은 항상 1에서 8 비트 사이입니다. 옥텟 경계에서 시작하는 정수는 8비트 접두사를 가집니다.

정수 I를 표현하는 의사코드는 다음과 같습니다:

if I < 2^N - 1, encode I on N bits
else
    encode (2^N - 1) on N bits
    I = I - (2^N - 1)
    while I >= 128
         encode (I % 128 + 128) on 8 bits
         I = I / 128
    encode I on 8 bits

정수 I를 디코드하는 의사코드는 다음과 같습니다:

decode I from the next N bits
if I < 2^N - 1, return I
else
    M = 0
    repeat
        B = next octet
        I = I + (B & 127) * 2^M
        M = M + 7
    while B & 128 == 128
    return I

정수 인코딩 예제는 부록 C.1에서 확인할 수 있습니다.

이 정수 표현은 무한한 크기의 값을 허용합니다. 또한 인코더가 많은 수의 0 값을 보낼 수 있어 옥텟을 낭비하고 정수 값을 오버플로우시키는 데 사용될 수 있습니다. 구현 한도를 초과하는 정수 인코딩(값 또는 옥텟 길이에서)은 디코딩 오류로 처리되어야 합니다. 서로 다른 사용 사례별로 구현 제약에 따라 서로 다른 한도를 설정할 수 있습니다.

5.2. 문자열 리터럴 표현

헤더 필드 이름과 헤더 필드 값은 문자열 리터럴로 표현될 수 있습니다. 문자열 리터럴은 문자열 리터럴의 옥텟을 직접 인코딩하거나 허프만 코드를 사용하여 옥텟 시퀀스로 인코딩됩니다(참조 [HUFFMAN]).

  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| H |    String Length (7+)     |
+---+---------------------------+
|  String Data (Length octets)  |
+-------------------------------+

그림 4: 문자열 리터럴 표현

문자열 리터럴 표현은 다음 필드를 포함합니다:

H:
문자열의 옥텟이 허프만 인코딩되었는지를 나타내는 1비트 플래그입니다.
String Length:
문자열 리터럴을 인코딩하는 데 사용된 옥텟 수로, 7비트 접두사를 가진 정수로 인코딩됩니다(섹션 5.1 참조).
String Data:
문자열 리터럴의 인코딩된 데이터입니다. H가 '0'이면 인코딩된 데이터는 문자열 리터럴의 원시 옥텟입니다. H가 '1'이면 인코딩된 데이터는 문자열 리터럴의 허프만 인코딩입니다.

허프만 인코딩을 사용하는 문자열 리터럴은 부록 B에 정의된 허프만 코드로 인코딩됩니다(요청 예제는 부록 C.4, 응답 예제는 부록 C.6 참조). 인코딩된 데이터는 문자열 리터럴의 각 옥텟에 해당하는 코드들의 비트 단위 연결입니다.

허프만 인코딩된 데이터가 항상 옥텟 경계에서 끝나지 않기 때문에, 다음 옥텟 경계까지 패딩이 삽입됩니다. 이 패딩이 문자열 리터럴의 일부로 오해되는 것을 방지하기 위해, EOS(문자열 종료) 기호에 해당하는 코드의 최상위 비트들이 사용됩니다.

디코딩 시 인코딩된 데이터 끝에 있는 불완전한 코드는 패딩으로 간주되어 폐기되어야 합니다. 7비트보다 긴 패딩은 디코딩 오류로 처리되어야 합니다. EOS 기호의 최상위 비트에 대응하지 않는 패딩은 디코딩 오류로 처리되어야 합니다. EOS 기호를 포함하는 허프만 인코딩된 문자열 리터럴은 디코딩 오류로 처리되어야 합니다.

6. 이진 형식

이 섹션에서는 서로 다른 헤더 필드 표현 각각의 상세 형식과 동적 테이블 크기 업데이트 명령을 설명합니다.

6.1. 인덱스된 헤더 필드 표현

인덱스된 헤더 필드 표현은 정적 테이블 또는 동적 테이블의 항목을 식별합니다(섹션 2.3 참조).

인덱스된 헤더 필드 표현은 섹션 3.2에 설명된 대로 해당 헤더 필드를 디코딩된 헤더 목록에 추가하게 합니다.

  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 1 |        Index (7+)         |
+---+---------------------------+

그림 5: 인덱스된 헤더 필드

인덱스된 헤더 필드는 '1' 1비트 패턴으로 시작하며, 그 뒤에 7비트 접두사를 가진 정수로 표현된 일치하는 헤더 필드의 인덱스가 옵니다(섹션 5.1 참조).

인덱스 값 0은 사용되지 않습니다. 인덱스된 헤더 필드 표현에서 0이 발견되면 디코딩 오류로 처리되어야 합니다.

6.2. 리터럴 헤더 필드 표현

리터럴 헤더 필드 표현은 리터럴 헤더 필드 값을 포함합니다. 헤더 필드 이름은 리터럴로 제공되거나 정적 테이블이나 동적 테이블의 기존 항목을 참조하여 제공될 수 있습니다(섹션 2.3 참조).

이 규격은 인덱싱이 있는 표현, 인덱싱이 없는 표현, 그리고 절대 인덱싱되지 않는 표현의 세 가지 형태의 리터럴 헤더 필드 표현을 정의합니다.

6.2.1. 증분 인덱싱이 있는 리터럴 헤더 필드

증분 인덱싱이 있는 리터럴 헤더 필드 표현은 헤더 필드를 디코딩된 헤더 목록에 추가하고 이를 동적 테이블에 새 항목으로 삽입하는 결과를 초래합니다.

  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 1 |      Index (6+)       |
+---+---+-----------------------+
| H |     Value Length (7+)     |
+---+---------------------------+
| Value String (Length octets)  |
+-------------------------------+

그림 6: 증분 인덱싱이 있는 리터럴 헤더 필드 — 인덱스된 이름

  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 1 |           0           |
+---+---+-----------------------+
| H |     Name Length (7+)      |
+---+---------------------------+
|  Name String (Length octets)  |
+---+---------------------------+
| H |     Value Length (7+)     |
+---+---------------------------+
| Value String (Length octets)  |
+-------------------------------+

그림 7: 증분 인덱싱이 있는 리터럴 헤더 필드 — 새 이름

증분 인덱싱이 있는 리터럴 헤더 필드 표현은 '01' 2비트 패턴으로 시작합니다.

헤더 필드 이름이 정적 테이블 또는 동적 테이블에 저장된 항목의 헤더 필드 이름과 일치하면, 해당 항목의 인덱스를 사용하여 헤더 필드 이름을 표현할 수 있습니다. 이 경우 항목의 인덱스는 6비트 접두사를 가진 정수로 표현됩니다(섹션 5.1 참조). 이 값은 항상 0이 아닙니다.

그렇지 않으면 헤더 필드 이름은 문자열 리터럴로 표현됩니다(섹션 5.2 참조). 이 경우 6비트 인덱스 대신 값 0이 사용되며, 그 뒤에 헤더 필드 이름이 옵니다.

어떤 형태의 헤더 필드 이름 표현이든 그 뒤에는 문자열 리터럴로 표현된 헤더 필드 값이 옵니다(섹션 5.2 참조).

6.2.2. 인덱싱 없는 리터럴 헤더 필드

인덱싱 없는 리터럴 헤더 필드 표현은 동적 테이블을 변경하지 않고 헤더 필드를 디코딩된 헤더 목록에 추가하는 결과를 초래합니다.

  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 0 |  Index (4+)   |
+---+---+-----------------------+
| H |     Value Length (7+)     |
+---+---------------------------+
| Value String (Length octets)  |
+-------------------------------+

그림 8: 인덱싱 없는 리터럴 헤더 필드 — 인덱스된 이름

  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 0 |       0       |
+---+---+-----------------------+
| H |     Name Length (7+)      |
+---+---------------------------+
|  Name String (Length octets)  |
+---+---------------------------+
| H |     Value Length (7+)     |
+---+---------------------------+
| Value String (Length octets)  |
+-------------------------------+

그림 9: 인덱싱 없는 리터럴 헤더 필드 — 새 이름

인덱싱 없는 리터럴 헤더 필드 표현은 '0000' 4비트 패턴으로 시작합니다.

헤더 필드 이름이 정적 테이블 또는 동적 테이블에 저장된 항목의 헤더 필드 이름과 일치하면, 해당 항목의 인덱스를 사용하여 헤더 필드 이름을 표현할 수 있습니다. 이 경우 항목의 인덱스는 4비트 접두사를 가진 정수로 표현됩니다(섹션 5.1 참조). 이 값은 항상 0이 아닙니다.

그렇지 않으면 헤더 필드 이름은 문자열 리터럴로 표현됩니다(섹션 5.2 참조). 이 경우 4비트 인덱스 대신 값 0이 사용되며, 그 뒤에 헤더 필드 이름이 옵니다.

어떤 형태의 헤더 필드 이름 표현이든 그 뒤에는 문자열 리터럴로 표현된 헤더 필드 값이 옵니다(섹션 5.2 참조).

6.2.3. 절대 인덱싱되지 않는 리터럴 헤더 필드

절대 인덱싱되지 않는 리터럴 헤더 필드 표현은 동적 테이블을 변경하지 않고 헤더 필드를 디코딩된 헤더 목록에 추가합니다. 중개자는 이 헤더 필드를 인코딩할 때 동일한 표현을 사용해야 합니다.

  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 1 |  Index (4+)   |
+---+---+-----------------------+
| H |     Value Length (7+)     |
+---+---------------------------+
| Value String (Length octets)  |
+-------------------------------+

그림 10: 절대 인덱싱되지 않는 리터럴 헤더 필드 — 인덱스된 이름

  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 1 |       0       |
+---+---+-----------------------+
| H |     Name Length (7+)      |
+---+---------------------------+
|  Name String (Length octets)  |
+---+---------------------------+
| H |     Value Length (7+)     |
+---+---------------------------+
| Value String (Length octets)  |
+-------------------------------+

그림 11: 절대 인덱싱되지 않는 리터럴 헤더 필드 — 새 이름

절대 인덱싱되지 않는 리터럴 헤더 필드 표현은 '0001' 4비트 패턴으로 시작합니다.

헤더 필드가 절대 인덱싱되지 않는 리터럴로 표현되는 경우, 항상 이 특정 리터럴 표현으로 인코딩되어야 합니다. 특히, 피어가 절대 인덱싱되지 않는 리터럴로 표현된 헤더 필드를 수신하고 이를 전달할 때는 동일한 표현을 사용해야 합니다.

이 표현은 압축으로 인해 위험에 노출되어서는 안 되는 헤더 필드 값을 보호하기 위한 것입니다(자세한 내용은 섹션 7.1 참조).

이 표현의 인코딩은 인덱싱 없는 리터럴 헤더 필드(섹션 6.2.2)와 동일합니다.

6.3. 동적 테이블 크기 업데이트

동적 테이블 크기 업데이트는 동적 테이블의 크기 변경을 알립니다.

  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 1 |   Max size (5+)   |
+---+---------------------------+

그림 12: 최대 동적 테이블 크기 변경

동적 테이블 크기 업데이트는 '001' 3비트 패턴으로 시작하며, 뒤에 5비트 접두사를 가진 정수로 표현된 새로운 최대 크기가 옵니다(섹션 5.1 참조).

새로운 최대 크기는 HPACK을 사용하는 프로토콜이 결정한 한도보다 작거나 같아야 합니다. 이 한도를 초과하는 값은 디코딩 오류로 처리되어야 합니다. HTTP/2에서는 이 한도가 디코더로부터 수신되고 인코더가 확인한 SETTINGS_HEADER_TABLE_SIZE 매개변수의 마지막 값입니다(자세한 내용은 Section 6.5.2Section 6.5.3을 참조하십시오).

동적 테이블의 최대 크기를 줄이면 항목이 축출될 수 있습니다(섹션 4.3 참조).

7. 보안 고려사항

이 섹션에서는 HPACK과 관련된 잠재적 보안 우려 영역을 설명합니다:

  • 공유된 압축 컨텍스트에 압축되어 들어가는 비밀에 관한 추측을 길이 기반 오라클로 확인하는 데 압축을 사용하는 것.
  • 디코더에서 처리 능력이나 메모리 용량을 고갈시켜 발생하는 서비스 거부(DoS).

7.1. 동적 테이블 상태 탐지

HPACK은 HTTP와 같은 프로토콜에 내재된 중복성을 활용하여 헤더 필드 인코딩의 길이를 줄입니다. 궁극적 목표는 HTTP 요청이나 응답을 전송하는 데 필요한 데이터 양을 줄이는 것입니다.

헤더 필드를 인코딩하는 데 사용되는 압축 컨텍스트는, 인코딩되어 전송될 헤더 필드를 정의하고 인코딩된 후 그 길이를 관찰할 수 있는 공격자에 의해 탐지될 수 있습니다. 공격자가 두 가지를 모두 수행할 수 있을 때, 동적 테이블 상태에 대한 추측을 확인하기 위해 적응적으로 요청을 수정할 수 있습니다. 추측이 더 짧게 압축되면 공격자는 인코딩된 길이를 관찰하여 그 추측이 맞았음을 추론할 수 있습니다.

이것은 전송 계층 보안(Transport Layer Security, TLS) 프로토콜을 통해서도 가능할 수 있습니다(참조 [TLS12]), TLS가 콘텐츠에 대한 기밀성 보호를 제공하더라도 그 길이에 대해서는 제한된 정도의 보호만 제공하기 때문입니다.

CRIME [CRIME]와 같은 공격은 이러한 일반적인 공격자 능력의 존재를 보여주었습니다. 특정 공격은 DEFLATE [DEFLATE]가 접두사 일치를 기반으로 중복을 제거한다는 사실을 악용했습니다. 이로 인해 공격자는 한 번에 한 문자씩 추측을 확인할 수 있었고, 지수 시간 공격을 선형 시간 공격으로 줄일 수 있었습니다.

7.1.1. HPACK 및 HTTP에 대한 적용성

HPACK은 추측이 개별 문자가 아닌 전체 헤더 필드 값과 일치하도록 강제함으로써 CRIME [CRIME]를 모델로 한 공격을 완화하지만 완전히 방지하지는 않습니다. 공격자는 추측이 맞는지 여부만 알 수 있으므로 헤더 필드 값에 대해서는 무차별 대입에 의존하게 됩니다.

따라서 특정 헤더 필드 값을 회수할 수 있는 가능성은 값의 엔트로피에 따라 달라집니다. 결과적으로 엔트로피가 높은 값은 성공적으로 회수될 가능성이 낮습니다. 그러나 엔트로피가 낮은 값은 여전히 취약합니다.

이러한 성격의 공격은 두 개의 상호 불신하는 엔터티가 단일 HTTP/2 연결에 배치된 요청이나 응답을 제어할 때 언제든지 가능할 수 있습니다. 공유된 HPACK 압축기가 한 엔터티가 동적 테이블에 항목을 추가하도록 허용하고 다른 엔터티가 해당 항목에 접근할 수 있게 하면, 테이블의 상태를 학습할 수 있습니다.

상호 불신하는 엔터티의 요청 또는 응답이 발생하는 경우는 중개자가 다음 중 하나를 수행할 때 발생합니다:

  • 여러 클라이언트로부터의 요청을 하나의 연결로 원본 서버 쪽으로 전송하는 경우, 또는
  • 여러 원본 서버로부터의 응답을 받아 클라이언트 쪽으로의 공유된 연결에 배치하는 경우.

웹 브라우저는 또한 동일한 연결에서 서로 다른 웹 오리진(web origins)에 의해 이루어지는 요청이 상호 불신하는 엔터티에 의해 만들어진 것으로 가정해야 합니다(참조 web origins [ORIGIN]).

7.1.2. 완화책

헤더 필드에 대한 기밀성이 필요한 HTTP 사용자는 추측이 불가능할 정도의 충분한 엔트로피를 가진 값을 사용할 수 있습니다. 그러나 이는 모든 HTTP 사용자가 공격을 완화하기 위해 조치를 취하도록 강제하므로 일반적인 해결책으로는 비현실적입니다. 또한 HTTP 사용 방식에 새로운 제약을 부과하게 됩니다.

HTTP 사용자를 제약하는 대신, HPACK의 구현은 동적 테이블 탐지 가능성을 제한하기 위해 압축 적용 방식을 제약할 수 있습니다.

이상적인 해결책은 헤더 필드를 구성하는 엔터티에 따라 동적 테이블에 대한 접근을 분리하는 것입니다. 테이블에 추가된 헤더 필드 값은 특정 엔터티에 귀속되고, 특정 값을 생성한 엔터티만 그 값을 추출할 수 있어야 합니다.

이 옵션의 압축 성능을 개선하기 위해 일부 항목은 공개(public)로 태그될 수 있습니다. 예를 들어 웹 브라우저는 Accept-Encoding 헤더 필드의 값을 모든 요청에서 사용 가능하게 만들 수 있습니다.

헤더 필드의 출처(provenance)를 잘 알지 못하는 인코더는 대신 값이 많이 변하는 헤더 필드에 페널티를 도입할 수 있습니다. 즉, 헤더 필드 값에 대해 많은 수의 추측 시도가 발생하면 해당 헤더 필드는 이후 메시지에서 더 이상 동적 테이블 항목과 비교되지 않도록 하여 추가 추측을 효과적으로 방지할 수 있습니다.

이러한 응답은 헤더 필드 값의 길이에 반비례하도록 만들 수 있습니다. 즉, 짧은 값에 대해서는 더 빨리 또는 더 높은 확률로 해당 헤더 필드가 더 이상 동적 테이블을 사용하지 않도록 표시할 수 있습니다.

7.1.3. 절대 인덱싱되지 않는 리터럴

구현체는 민감한 헤더 필드를 압축하지 않고 대신 그 값을 리터럴로 인코딩함으로써 보호하기로 선택할 수 있습니다.

헤더 필드에 대해 인덱스된 표현을 생성하지 않기로 하는 것은 모든 홉(hop)에서 압축이 회피될 경우에만 효과적입니다. 절대 인덱싱되지 않는 리터럴(참조 섹션 6.2.3)은 특정 값이 의도적으로 리터럴로 전송되었음을 중개자에게 알리는 데 사용될 수 있습니다.

중개자는 절대 인덱싱되지 않는 리터럴로 표현된 값을 다른 인덱스형 표현으로 재인코딩해서는 안 됩니다. HPACK이 재인코딩에 사용된다면 절대 인덱싱되지 않는 리터럴 표현을 사용해야 합니다.

헤더 필드에 대해 절대 인덱싱되지 않는 리터럴 표현을 사용할지 여부는 여러 요소에 따라 달라집니다. HPACK이 전체 헤더 필드 값을 추측하는 것을 막아주지 않기 때문에, 짧거나 엔트로피가 낮은 값은 공격자에게 더 쉽게 회수될 수 있습니다. 따라서 인코더는 엔트로피가 낮은 값을 인덱싱하지 않기로 선택할 수 있습니다.

인코더는 Cookie 또는 Authorization과 같이 회수될 경우 가치가 높거나 민감한 헤더 필드 값에 대해 인덱싱하지 않기로 선택할 수도 있습니다.

반대로 인코더는 노출되더라도 별다른 가치가 없는 헤더 필드 값에 대해서는 인덱싱을 선호할 수 있습니다. 예를 들어 User-Agent 헤더 필드 값은 요청 간에 거의 변하지 않으며 어떤 서버에든 전송됩니다. 그런 경우 특정 User-Agent 값이 사용되었음을 확인하는 것은 거의 가치가 없습니다.

이러한 절대 인덱싱되지 않는 리터럴 표현을 사용할지 결정하는 기준은 새로운 공격이 발견됨에 따라 시간이 지나면서 진화할 것임을 유의하십시오.

7.2. 정적 허프만 인코딩

정적 허프만 인코딩에 대한 알려진 공격은 현재 없습니다. 연구 결과 정적 허프만 인코딩 테이블을 사용하는 것이 정보 누출을 발생시킨다고 보고되었으나, 동일한 연구는 공격자가 이 정보 누출을 이용해 의미 있는 양의 정보를 회수할 수는 없다고 결론지었습니다(참조 [PETAL]).

7.3. 메모리 소비

공격자는 엔드포인트가 메모리를 고갈하도록 시도할 수 있습니다. HPACK은 엔드포인트가 할당하는 최대 및 상태 메모리 양을 제한하도록 설계되었습니다.

압축기의 메모리 사용량은 동적 테이블의 최대 크기 정의를 통해 HPACK을 사용하는 프로토콜에 의해 제한됩니다. HTTP/2에서는 이 값이 디코더가 제어하는 SETTINGS_HEADER_TABLE_SIZE 설정 매개변수로 제어됩니다(참조 Section 6.5.2[HTTP2]).

디코더는 동적 테이블의 최대 크기에 적절한 값을 설정함으로써 상태 메모리 사용량을 제한할 수 있습니다. HTTP/2에서는 SETTINGS_HEADER_TABLE_SIZE 매개변수에 적절한 값을 설정함으로써 이를 실현합니다. 인코더는 디코더가 허용하는 값보다 더 낮은 동적 테이블 크기를 신호하여 자신이 사용하는 상태 메모리 양을 제한할 수 있습니다(섹션 6.3 참조).

인코더 또는 디코더가 소비하는 일시적 메모리 양은 헤더 필드를 순차적으로 처리함으로써 제한할 수 있습니다. 구현은 완전한 헤더 필드 목록을 보존할 필요가 없습니다. 다만 애플리케이션 측에서 다른 이유로 완전한 헤더 목록을 보존해야 할 수도 있다는 점을 유의하십시오; HPACK 자체가 이를 강제하지는 않습니다.

7.4. 구현 한계

HPACK 구현체는 정수의 큰 값, 정수의 긴 인코딩, 또는 긴 문자열 리터럴이 보안 약점을 만들지 않도록 보장해야 합니다.

구현체는 정수에 대해 수용할 값의 한계뿐만 아니라 인코딩된 길이에 대한 한계를 설정해야 합니다(섹션 5.1 참조). 마찬가지로 문자열 리터럴에 대해 수용할 길이의 한계를 설정해야 합니다(섹션 5.2 참조).

8. References

8.2. Informative References

[CANONICAL]
Schwartz, E. and B. Kallick, “Generating a canonical prefix encoding”, Communications of the ACM, Volume 7 Issue 3, pp. 166-169, March 1964, <https://dl.acm.org/citation.cfm?id=363991>.
[CRIME]
Wikipedia, “CRIME”, May 2015, <http://en.wikipedia.org/w/index.php?title=CRIME&oldid=660948120>.
[DEFLATE]
Deutsch, P., “DEFLATE Compressed Data Format Specification version 1.3”, RFC 1951, DOI 10.17487/RFC1951, May 1996, <http://www.rfc-editor.org/info/rfc1951>.
[HUFFMAN]
Huffman, D., “A Method for the Construction of Minimum-Redundancy Codes”, Proceedings of the Institute of Radio Engineers, Volume 40, Number 9, pp. 1098-1101, September 1952, <http://ieeexplore.ieee.org/xpl/articleDetails.jsp?arnumber=4051119>.
[ORIGIN]
Barth, A., “The Web Origin Concept”, RFC 6454, DOI 10.17487/RFC6454, December 2011, <http://www.rfc-editor.org/info/rfc6454>.
[PETAL]
Tan, J. and J. Nahata, “PETAL: Preset Encoding Table Information Leakage”, April 2013, <http://www.pdl.cmu.edu/PDL-FTP/associated/CMU-PDL-13-106.pdf>.
[SPDY]
Belshe, M. and R. Peon, “SPDY Protocol”, Work in Progress, draft-mbelshe-httpbis-spdy-00, February 2012.
[TLS12]
Dierks, T. and E. Rescorla, “The Transport Layer Security (TLS) Protocol Version 1.2”, RFC 5246, DOI 10.17487/RFC5246, August 2008, <http://www.rfc-editor.org/info/rfc5246>.

부록 A. 정적 테이블 정의

정적 테이블(참조 섹션 2.3.1)은 미리 정의되고 변경할 수 없는 헤더 필드 목록으로 구성됩니다.

정적 테이블은 인기 있는 웹사이트에서 자주 사용되는 헤더 필드들을 바탕으로 생성되었으며, HTTP/2 특정의 의사 헤더 필드도 추가되었습니다(자세한 내용은 RFC 7540 섹션 8.1.2.1[HTTP2] 참조). 값이 몇 가지로 자주 나타나는 헤더 필드의 경우, 이러한 빈도 높은 각 값에 대해 항목이 추가되었습니다. 다른 헤더 필드의 경우, 빈 값으로 항목이 추가되었습니다.

표 1은 정적 테이블을 구성하는 미리 정의된 헤더 필드들을 나열하고 각 항목의 인덱스를 제공합니다.

표 1: 정적 테이블 항목
인덱스 헤더 이름 헤더 값
1 :authority
2 :method GET
3 :method POST
4 :path /
5 :path /index.html
6 :scheme http
7 :scheme https
8 :status 200
9 :status 204
10 :status 206
11 :status 304
12 :status 400
13 :status 404
14 :status 500
15 accept-charset
16 accept-encoding gzip, deflate
17 accept-language
18 accept-ranges
19 accept
20 access-control-allow-origin
21 age
22 allow
23 authorization
24 cache-control
25 content-disposition
26 content-encoding
27 content-language
28 content-length
29 content-location
30 content-range
31 content-type
32 cookie
33 date
34 etag
35 expect
36 expires
37 from
38 host
39 if-match
40 if-modified-since
41 if-none-match
42 if-range
43 if-unmodified-since
44 last-modified
45 link
46 location
47 max-forwards
48 proxy-authenticate
49 proxy-authorization
50 range
51 referer
52 refresh
53 retry-after
54 server
55 set-cookie
56 strict-transport-security
57 transfer-encoding
58 user-agent
59 vary
60 via
61 www-authenticate

부록 B. 허프만 코드

다음 허프만 코드는 문자열 리터럴을 허프만 코딩으로 인코딩할 때 사용됩니다(참조 섹션 5.2).

이 허프만 코드는 대규모 HTTP 헤더 샘플에서 얻은 통계로 생성되었습니다. 이는 표준화된 허프만 코드(canonical Huffman code, 참조 [CANONICAL])이며, 일부 심볼이 고유한 코드 길이를 갖지 않도록 약간 조정되었습니다.

표의 각 행은 심볼을 표현하기 위해 사용되는 코드를 정의합니다:

sym:
표현할 심볼입니다. 이는 옥텟의 십진수 값이며, 필요에 따라 ASCII 표기가 앞에 붙을 수 있습니다. 특별한 심볼 "EOS"는 문자열 리터럴의 끝을 나타내는 데 사용됩니다.
code as bits:
심볼을 표현하기 위한 허프만 코드로, 최상위 비트(MSB)에 정렬된 2진 정수로 표시됩니다.
code as hex:
심볼에 대한 허프만 코드를 16진수 정수로 표시한 것으로, 최하위 비트(LSB)에 정렬되어 있습니다.
len:
심볼을 표현하는 코드의 비트 수입니다.

예를 들어, 심볼 47(ASCII 문자 "/")의 코드는 6비트 "0", "1", "1", "0", "0", "0"으로 구성됩니다. 이는 6비트로 인코딩된 16진수 값 0x18에 해당합니다.

                                                     code
                       code as bits                 as hex   len
     sym              aligned to MSB                aligned   in
                                                    to LSB   bits
    (  0)  |11111111|11000                             1ff8  [13]
    (  1)  |11111111|11111111|1011000                7fffd8  [23]
    (  2)  |11111111|11111111|11111110|0010         fffffe2  [28]
    (  3)  |11111111|11111111|11111110|0011         fffffe3  [28]
    (  4)  |11111111|11111111|11111110|0100         fffffe4  [28]
    (  5)  |11111111|11111111|11111110|0101         fffffe5  [28]
    (  6)  |11111111|11111111|11111110|0110         fffffe6  [28]
    (  7)  |11111111|11111111|11111110|0111         fffffe7  [28]
    (  8)  |11111111|11111111|11111110|1000         fffffe8  [28]
    (  9)  |11111111|11111111|11101010               ffffea  [24]
    ( 10)  |11111111|11111111|11111111|111100      3ffffffc  [30]
    ( 11)  |11111111|11111111|11111110|1001         fffffe9  [28]
    ( 12)  |11111111|11111111|11111110|1010         fffffea  [28]
    ( 13)  |11111111|11111111|11111111|111101      3ffffffd  [30]
    ( 14)  |11111111|11111111|11111110|1011         fffffeb  [28]
    ( 15)  |11111111|11111111|11111110|1100         fffffec  [28]
    ( 16)  |11111111|11111111|11111110|1101         fffffed  [28]
    ( 17)  |11111111|11111111|11111110|1110         fffffee  [28]
    ( 18)  |11111111|11111111|11111110|1111         fffffef  [28]
    ( 19)  |11111111|11111111|11111111|0000         ffffff0  [28]
    ( 20)  |11111111|11111111|11111111|0001         ffffff1  [28]
    ( 21)  |11111111|11111111|11111111|0010         ffffff2  [28]
    ( 22)  |11111111|11111111|11111111|111110      3ffffffe  [30]
    ( 23)  |11111111|11111111|11111111|0011         ffffff3  [28]
    ( 24)  |11111111|11111111|11111111|0100         ffffff4  [28]
    ( 25)  |11111111|11111111|11111111|0101         ffffff5  [28]
    ( 26)  |11111111|11111111|11111111|0110         ffffff6  [28]
    ( 27)  |11111111|11111111|11111111|0111         ffffff7  [28]
    ( 28)  |11111111|11111111|11111111|1000         ffffff8  [28]
    ( 29)  |11111111|11111111|11111111|1001         ffffff9  [28]
    ( 30)  |11111111|11111111|11111111|1010         ffffffa  [28]
    ( 31)  |11111111|11111111|11111111|1011         ffffffb  [28]
' ' ( 32)  |010100                                       14  [ 6]
'!' ( 33)  |11111110|00                                 3f8  [10]
'"' ( 34)  |11111110|01                                 3f9  [10]
'#' ( 35)  |11111111|1010                               ffa  [12]
'$' ( 36)  |11111111|11001                             1ff9  [13]
'%' ( 37)  |010101                                       15  [ 6]
'&' ( 38)  |11111000                                     f8  [ 8]
''' ( 39)  |11111111|010                                7fa  [11]
'(' ( 40)  |11111110|10                                 3fa  [10]
')' ( 41)  |11111110|11                                 3fb  [10]
'*' ( 42)  |11111001                                     f9  [ 8]
'+' ( 43)  |11111111|011                                7fb  [11]
',' ( 44)  |11111010                                     fa  [ 8]
'-' ( 45)  |010110                                       16  [ 6]
'.' ( 46)  |010111                                       17  [ 6]
'/' ( 47)  |011000                                       18  [ 6]
'0' ( 48)  |00000                                         0  [ 5]
'1' ( 49)  |00001                                         1  [ 5]
'2' ( 50)  |00010                                         2  [ 5]
'3' ( 51)  |011001                                       19  [ 6]
'4' ( 52)  |011010                                       1a  [ 6]
'5' ( 53)  |011011                                       1b  [ 6]
'6' ( 54)  |011100                                       1c  [ 6]
'7' ( 55)  |011101                                       1d  [ 6]
'8' ( 56)  |011110                                       1e  [ 6]
'9' ( 57)  |011111                                       1f  [ 6]
':' ( 58)  |1011100                                      5c  [ 7]
';' ( 59)  |11111011                                     fb  [ 8]
'<' ( 60)  |11111111|1111100                           7ffc  [15]
'=' ( 61)  |100000                                       20  [ 6]
'>' ( 62)  |11111111|1011                               ffb  [12]
'?' ( 63)  |11111111|00                                 3fc  [10]
'@' ( 64)  |11111111|11010                             1ffa  [13]
'A' ( 65)  |100001                                       21  [ 6]
'B' ( 66)  |1011101                                      5d  [ 7]
'C' ( 67)  |1011110                                      5e  [ 7]
'D' ( 68)  |1011111                                      5f  [ 7]
'E' ( 69)  |1100000                                      60  [ 7]
'F' ( 70)  |1100001                                      61  [ 7]
'G' ( 71)  |1100010                                      62  [ 7]
'H' ( 72)  |1100011                                      63  [ 7]
'I' ( 73)  |1100100                                      64  [ 7]
'J' ( 74)  |1100101                                      65  [ 7]
'K' ( 75)  |1100110                                      66  [ 7]
'L' ( 76)  |1100111                                      67  [ 7]
'M' ( 77)  |1101000                                      68  [ 7]
'N' ( 78)  |1101001                                      69  [ 7]
'O' ( 79)  |1101010                                      6a  [ 7]
'P' ( 80)  |1101011                                      6b  [ 7]
'Q' ( 81)  |1101100                                      6c  [ 7]
'R' ( 82)  |1101101                                      6d  [ 7]
'S' ( 83)  |1101110                                      6e  [ 7]
'T' ( 84)  |1101111                                      6f  [ 7]
'U' ( 85)  |1110000                                      70  [ 7]
'V' ( 86)  |1110001                                      71  [ 7]
'W' ( 87)  |1110010                                      72  [ 7]
'X' ( 88)  |11111100                                     fc  [ 8]
'Y' ( 89)  |1110011                                      73  [ 7]
'Z' ( 90)  |11111101                                     fd  [ 8]
'[' ( 91)  |11111111|11011                             1ffb  [13]
'\' ( 92)  |11111111|11111110|000                     7fff0  [19]
']' ( 93)  |11111111|11100                             1ffc  [13]
'^' ( 94)  |11111111|111100                            3ffc  [14]
'_' ( 95)  |100010                                       22  [ 6]
'`' ( 96)  |11111111|1111101                           7ffd  [15]
'a' ( 97)  |00011                                         3  [ 5]
'b' ( 98)  |100011                                       23  [ 6]
'c' ( 99)  |00100                                         4  [ 5]
'd' (100)  |100100                                       24  [ 6]
'e' (101)  |00101                                         5  [ 5]
'f' (102)  |100101                                       25  [ 6]
'g' (103)  |100110                                       26  [ 6]
'h' (104)  |100111                                       27  [ 6]
'i' (105)  |00110                                         6  [ 5]
'j' (106)  |1110100                                      74  [ 7]
'k' (107)  |1110101                                      75  [ 7]
'l' (108)  |101000                                       28  [ 6]
'm' (109)  |101001                                       29  [ 6]
'n' (110)  |101010                                       2a  [ 6]
'o' (111)  |00111                                         7  [ 5]
'p' (112)  |101011                                       2b  [ 6]
'q' (113)  |1110110                                      76  [ 7]
'r' (114)  |101100                                       2c  [ 6]
's' (115)  |01000                                         8  [ 5]
't' (116)  |01001                                         9  [ 5]
'u' (117)  |101101                                       2d  [ 6]
'v' (118)  |1110111                                      77  [ 7]
'w' (119)  |1111000                                      78  [ 7]
'x' (120)  |1111001                                      79  [ 7]
'y' (121)  |1111010                                      7a  [ 7]
'z' (122)  |1111011                                      7b  [ 7]
'{' (123)  |11111111|1111110                           7ffe  [15]
'|' (124)  |11111111|100                                7fc  [11]
'}' (125)  |11111111|111101                            3ffd  [14]
'~' (126)  |11111111|11101                             1ffd  [13]
    (127)  |11111111|11111111|11111111|1100         ffffffc  [28]
    (128)  |11111111|11111110|0110                    fffe6  [20]
    (129)  |11111111|11111111|010010                 3fffd2  [22]
    (130)  |11111111|11111110|0111                    fffe7  [20]
    (131)  |11111111|11111110|1000                    fffe8  [20]
    (132)  |11111111|11111111|010011                 3fffd3  [22]
    (133)  |11111111|11111111|010100                 3fffd4  [22]
    (134)  |11111111|11111111|010101                 3fffd5  [22]
    (135)  |11111111|11111111|1011001                7fffd9  [23]
    (136)  |11111111|11111111|010110                 3fffd6  [22]
    (137)  |11111111|11111111|1011010                7fffda  [23]
    (138)  |11111111|11111111|1011011                7fffdb  [23]
    (139)  |11111111|11111111|1011100                7fffdc  [23]
    (140)  |11111111|11111111|1011101                7fffdd  [23]
    (141)  |11111111|11111111|1011110                7fffde  [23]
    (142)  |11111111|11111111|11101011               ffffeb  [24]
    (143)  |11111111|11111111|1011111                7fffdf  [23]
    (144)  |11111111|11111111|11101100               ffffec  [24]
    (145)  |11111111|11111111|11101101               ffffed  [24]
    (146)  |11111111|11111111|010111                 3fffd7  [22]
    (147)  |11111111|11111111|1100000                7fffe0  [23]
    (148)  |11111111|11111111|11101110               ffffee  [24]
    (149)  |11111111|11111111|1100001                7fffe1  [23]
    (150)  |11111111|11111111|1100010                7fffe2  [23]
    (151)  |11111111|11111111|1100011                7fffe3  [23]
    (152)  |11111111|11111111|1100100                7fffe4  [23]
    (153)  |11111111|11111110|11100                  1fffdc  [21]
    (154)  |11111111|11111111|011000                 3fffd8  [22]
    (155)  |11111111|11111111|1100101                7fffe5  [23]
    (156)  |11111111|11111111|011001                 3fffd9  [22]
    (157)  |11111111|11111111|1100110                7fffe6  [23]
    (158)  |11111111|11111111|1100111                7fffe7  [23]
    (159)  |11111111|11111111|11101111               ffffef  [24]
    (160)  |11111111|11111111|011010                 3fffda  [22]
    (161)  |11111111|11111110|11101                  1fffdd  [21]
    (162)  |11111111|11111110|1001                    fffe9  [20]
    (163)  |11111111|11111111|011011                 3fffdb  [22]
    (164)  |11111111|11111111|011100                 3fffdc  [22]
    (165)  |11111111|11111111|1101000                7fffe8  [23]
    (166)  |11111111|11111111|1101001                7fffe9  [23]
    (167)  |11111111|11111110|11110                  1fffde  [21]
    (168)  |11111111|11111111|1101010                7fffea  [23]
    (169)  |11111111|11111111|011101                 3fffdd  [22]
    (170)  |11111111|11111111|011110                 3fffde  [22]
    (171)  |11111111|11111111|11110000               fffff0  [24]
    (172)  |11111111|11111110|11111                  1fffdf  [21]
    (173)  |11111111|11111111|011111                 3fffdf  [22]
    (174)  |11111111|11111111|1101011                7fffeb  [23]
    (175)  |11111111|11111111|1101100                7fffec  [23]
    (176)  |11111111|11111111|00000                  1fffe0  [21]
    (177)  |11111111|11111111|00001                  1fffe1  [21]
    (178)  |11111111|11111111|100000                 3fffe0  [22]
    (179)  |11111111|11111111|00010                  1fffe2  [21]
    (180)  |11111111|11111111|1101101                7fffed  [23]
    (181)  |11111111|11111111|100001                 3fffe1  [22]
    (182)  |11111111|11111111|1101110                7fffee  [23]
    (183)  |11111111|11111111|1101111                7fffef  [23]
    (184)  |11111111|11111110|1010                    fffea  [20]
    (185)  |11111111|11111111|100010                 3fffe2  [22]
    (186)  |11111111|11111111|100011                 3fffe3  [22]
    (187)  |11111111|11111111|100100                 3fffe4  [22]
    (188)  |11111111|11111111|1110000                7ffff0  [23]
    (189)  |11111111|11111111|100101                 3fffe5  [22]
    (190)  |11111111|11111111|100110                 3fffe6  [22]
    (191)  |11111111|11111111|1110001                7ffff1  [23]
    (192)  |11111111|11111111|11111000|00           3ffffe0  [26]
    (193)  |11111111|11111111|11111000|01           3ffffe1  [26]
    (194)  |11111111|11111110|1011                    fffeb  [20]
    (195)  |11111111|11111110|001                     7fff1  [19]
    (196)  |11111111|11111111|100111                 3fffe7  [22]
    (197)  |11111111|11111111|1110010                7ffff2  [23]
    (198)  |11111111|11111111|101000                 3fffe8  [22]
    (199)  |11111111|11111111|11110110|0            1ffffec  [25]
    (200)  |11111111|11111111|11111000|10           3ffffe2  [26]
    (201)  |11111111|11111111|11111000|11           3ffffe3  [26]
    (202)  |11111111|11111111|11111001|00           3ffffe4  [26]
    (203)  |11111111|11111111|11111011|110          7ffffde  [27]
    (204)  |11111111|11111111|11111011|111          7ffffdf  [27]
    (205)  |11111111|11111111|11111001|01           3ffffe5  [26]
    (206)  |11111111|11111111|11110001               fffff1  [24]
    (207)  |11111111|11111111|11110110|1            1ffffed  [25]
    (208)  |11111111|11111110|010                     7fff2  [19]
    (209)  |11111111|11111111|00011                  1fffe3  [21]
    (210)  |11111111|11111111|11111001|10           3ffffe6  [26]
    (211)  |11111111|11111111|11111100|000          7ffffe0  [27]
    (212)  |11111111|11111111|11111100|001          7ffffe1  [27]
    (213)  |11111111|11111111|11111001|11           3ffffe7  [26]
    (214)  |11111111|11111111|11111100|010          7ffffe2  [27]
    (215)  |11111111|11111111|11110010               fffff2  [24]
    (216)  |11111111|11111111|00100                  1fffe4  [21]
    (217)  |11111111|11111111|00101                  1fffe5  [21]
    (218)  |11111111|11111111|11111010|00           3ffffe8  [26]
    (219)  |11111111|11111111|11111010|01           3ffffe9  [26]
    (220)  |11111111|11111111|11111111|1101         ffffffd  [28]
    (221)  |11111111|11111111|11111100|011          7ffffe3  [27]
    (222)  |11111111|11111111|11111100|100          7ffffe4  [27]
    (223)  |11111111|11111111|11111100|101          7ffffe5  [27]
    (224)  |11111111|11111110|1100                    fffec  [20]
    (225)  |11111111|11111111|11110011               fffff3  [24]
    (226)  |11111111|11111110|1101                    fffed  [20]
    (227)  |11111111|11111111|00110                  1fffe6  [21]
    (228)  |11111111|11111111|101001                 3fffe9  [22]
    (229)  |11111111|11111111|00111                  1fffe7  [21]
    (230)  |11111111|11111111|01000                  1fffe8  [21]
    (231)  |11111111|11111111|1110011                7ffff3  [23]
    (232)  |11111111|11111111|101010                 3fffea  [22]
    (233)  |11111111|11111111|101011                 3fffeb  [22]
    (234)  |11111111|11111111|11110111|0            1ffffee  [25]
    (235)  |11111111|11111111|11110111|1            1ffffef  [25]
    (236)  |11111111|11111111|11110100               fffff4  [24]
    (237)  |11111111|11111111|11110101               fffff5  [24]
    (238)  |11111111|11111111|11111010|10           3ffffea  [26]
    (239)  |11111111|11111111|1110100                7ffff4  [23]
    (240)  |11111111|11111111|11111010|11           3ffffeb  [26]
    (241)  |11111111|11111111|11111100|110          7ffffe6  [27]
    (242)  |11111111|11111111|11111011|00           3ffffec  [26]
    (243)  |11111111|11111111|11111011|01           3ffffed  [26]
    (244)  |11111111|11111111|11111100|111          7ffffe7  [27]
    (245)  |11111111|11111111|11111101|000          7ffffe8  [27]
    (246)  |11111111|11111111|11111101|001          7ffffe9  [27]
    (247)  |11111111|11111111|11111101|010          7ffffea  [27]
    (248)  |11111111|11111111|11111101|011          7ffffeb  [27]
    (249)  |11111111|11111111|11111111|1110         ffffffe  [28]
    (250)  |11111111|11111111|11111101|100          7ffffec  [27]
    (251)  |11111111|11111111|11111101|101          7ffffed  [27]
    (252)  |11111111|11111111|11111101|110          7ffffee  [27]
    (253)  |11111111|11111111|11111101|111          7ffffef  [27]
    (254)  |11111111|11111111|11111110|000          7fffff0  [27]
    (255)  |11111111|11111111|11111011|10           3ffffee  [26]
EOS (256)  |11111111|11111111|11111111|111111      3fffffff  [30]

부록 C. 예제

이 부록에는 정수 인코딩, 헤더 필드 표현, 그리고 요청 및 응답에 대한 전체 헤더 필드 목록의 인코딩 예제가 허프만 코딩 사용/미사용에 대해 포함되어 있습니다.

C.1. 정수 표현 예제

이 절은 정수 값의 표현을 상세히 보여줍니다(참조 섹션 5.1).

C.1.1. 예제 1: 5비트 접두사를 사용하여 10 인코딩

값 10은 5비트 접두사로 인코딩됩니다.

  • 10은 31(25 - 1)보다 작으므로 5비트 접두사를 사용하여 표현됩니다.
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| X | X | X | 0 | 1 | 0 | 1 | 0 |   10 stored on 5 bits
+---+---+---+---+---+---+---+---+

C.1.2. 예제 2: 5비트 접두사를 사용하여 1337 인코딩

값 I = 1337을 5비트 접두사로 인코딩합니다.

  • 1337은 31(25 - 1)보다 큽니다.
    • 5비트 접두사는 최대값(31)으로 채워집니다.
  • I = 1337 - (25 - 1) = 1306.
    • I(1306)는 128 이상이므로 while 루프 본문이 실행됩니다:
      • I % 128 == 26
      • 26 + 128 == 154
      • 154는 8비트로 10011010으로 인코딩됩니다
      • I는 10으로 설정됩니다(1306 / 128 == 10)
      • I는 더 이상 128 이상이 아니므로 while 루프가 종료됩니다.
    • 이제 I인 10은 8비트로 00001010으로 인코딩됩니다.
  • 과정이 완료됩니다.
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| X | X | X | 1 | 1 | 1 | 1 | 1 |  Prefix = 31, I = 1306
| 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 |  1306>=128, encode(154), I=1306/128
| 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |  10<128, encode(10), done
+---+---+---+---+---+---+---+---+

C.1.3. 예제 3: 옥텟 경계에서 시작하여 42 인코딩

값 42는 옥텟 경계에서 시작하여 인코딩됩니다. 이는 8비트 접두사가 사용됨을 의미합니다.

  • 42는 255(28 - 1)보다 작으므로 8비트 접두사를 사용하여 표현됩니다.
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |   42 stored on 8 bits
+---+---+---+---+---+---+---+---+

C.2. 헤더 필드 표현 예제

이 절은 몇 가지 독립적인 표현 예제를 보여줍니다.

C.2.1. 인덱싱이 있는 리터럴 헤더 필드

헤더 필드 표현은 리터럴 이름과 리터럴 값을 사용합니다. 해당 헤더 필드는 동적 테이블에 추가됩니다.

인코딩할 헤더 목록:

custom-key: custom-header

인코딩된 데이터의 16진수 덤프:

400a 6375 7374 6f6d 2d6b 6579 0d63 7573 | @.custom-key.cus
746f 6d2d 6865 6164 6572                | tom-header

디코딩 과정:

40                                      | == Literal indexed ==
0a                                      |   Literal name (len = 10)
6375 7374 6f6d 2d6b 6579                | custom-key
0d                                      |   Literal value (len = 13)
6375 7374 6f6d 2d68 6561 6465 72        | custom-header
                                        | -> custom-key:
                                        |   custom-header

디코딩 후 동적 테이블:

[  1] (s =  55) custom-key: custom-header
      Table size:  55

디코딩된 헤더 목록:

custom-key: custom-header

C.2.2. 인덱싱 없는 리터럴 헤더 필드

이 표현은 인덱스된 이름과 리터럴 값을 사용합니다. 해당 헤더 필드는 동적 테이블에 추가되지 않습니다.

인코딩할 헤더 목록:

:path: /sample/path

인코딩된 데이터의 16진수 덤프:

040c 2f73 616d 706c 652f 7061 7468      | ../sample/path

디코딩 과정:

04                                      | == Literal not indexed ==
                                        |   Indexed name (idx = 4)
                                        |     :path
0c                                      |   Literal value (len = 12)
2f73 616d 706c 652f 7061 7468           | /sample/path
                                        | -> :path: /sample/path

디코딩 후 동적 테이블: 비어 있음.

디코딩된 헤더 목록:

:path: /sample/path

C.2.3. 절대 인덱싱되지 않는 리터럴 헤더 필드

이 표현은 리터럴 이름과 리터럴 값을 사용합니다. 해당 헤더 필드는 동적 테이블에 추가되지 않으며, 중개자가 재인코딩할 경우 동일한 표현을 사용해야 합니다.

인코딩할 헤더 목록:

password: secret

인코딩된 데이터의 16진수 덤프:

1008 7061 7373 776f 7264 0673 6563 7265 | ..password.secre
74                                      | t

디코딩 과정:

10                                      | == Literal never indexed ==
08                                      |   Literal name (len = 8)
7061 7373 776f 7264                     | password
06                                      |   Literal value (len = 6)
7365 6372 6574                          | secret
                                        | -> password: secret

디코딩 후 동적 테이블: 비어 있음.

디코딩된 헤더 목록:

password: secret

C.2.4. 인덱스된 헤더 필드

이 표현은 정적 테이블의 인덱스된 헤더 필드를 사용합니다.

인코딩할 헤더 목록:

:method: GET

인코딩된 데이터의 16진수 덤프:

82                                      | .

디코딩 과정:

82                                      | == Indexed - Add ==
                                        |   idx = 2
                                        | -> :method: GET

디코딩 후 동적 테이블: 비어 있음.

디코딩된 헤더 목록:

:method: GET

C.3. 허프만 코딩 없는 요청 예제

이 절은 동일한 연결 상에서 연속되는 여러 헤더 목록(HTTP 요청에 해당)을 보여줍니다.

C.3.1. 첫 번째 요청

인코딩할 헤더 목록:

:method: GET
:scheme: http
:path: /
:authority: www.example.com

인코딩된 데이터의 16진수 덤프:

8286 8441 0f77 7777 2e65 7861 6d70 6c65 | ...A.www.example
2e63 6f6d                               | .com

디코딩 과정:

82                                      | == Indexed - Add ==
                                        |   idx = 2
                                        | -> :method: GET
86                                      | == Indexed - Add ==
                                        |   idx = 6
                                        | -> :scheme: http
84                                      | == Indexed - Add ==
                                        |   idx = 4
                                        | -> :path: /
41                                      | == Literal indexed ==
                                        |   Indexed name (idx = 1)
                                        |     :authority
0f                                      |   Literal value (len = 15)
7777 772e 6578 616d 706c 652e 636f 6d   | www.example.com
                                        | -> :authority: 
                                        |   www.example.com

디코딩 후 동적 테이블:

[  1] (s =  57) :authority: www.example.com
      Table size:  57

디코딩된 헤더 목록:

:method: GET
:scheme: http
:path: /
:authority: www.example.com

C.3.2. 두 번째 요청

인코딩할 헤더 목록:

:method: GET
:scheme: http
:path: /
:authority: www.example.com
cache-control: no-cache

인코딩된 데이터의 16진수 덤프:

8286 84be 5808 6e6f 2d63 6163 6865      | ....X.no-cache

디코딩 과정:

82                                      | == Indexed - Add ==
                                        |   idx = 2
                                        | -> :method: GET
86                                      | == Indexed - Add ==
                                        |   idx = 6
                                        | -> :scheme: http
84                                      | == Indexed - Add ==
                                        |   idx = 4
                                        | -> :path: /
be                                      | == Indexed - Add ==
                                        |   idx = 62
                                        | -> :authority:
                                        |   www.example.com
58                                      | == Literal indexed ==
                                        |   Indexed name (idx = 24)
                                        |     cache-control
08                                      |   Literal value (len = 8)
6e6f 2d63 6163 6865                     | no-cache
                                        | -> cache-control: no-cache

디코딩 후 동적 테이블:

[  1] (s =  53) cache-control: no-cache
[  2] (s =  57) :authority: www.example.com
      Table size: 110

디코딩된 헤더 목록:

:method: GET
:scheme: http
:path: /
:authority: www.example.com
cache-control: no-cache

C.3.3. 세 번째 요청

인코딩할 헤더 목록:

:method: GET
:scheme: https
:path: /index.html
:authority: www.example.com
custom-key: custom-value

인코딩된 데이터의 16진수 덤프:

8287 85bf 400a 6375 7374 6f6d 2d6b 6579 | ....@.custom-key
0c63 7573 746f 6d2d 7661 6c75 65        | .custom-value

디코딩 과정:

82                                      | == Indexed - Add ==
                                        |   idx = 2
                                        | -> :method: GET
87                                      | == Indexed - Add ==
                                        |   idx = 7
                                        | -> :scheme: https
85                                      | == Indexed - Add ==
                                        |   idx = 5
                                        | -> :path: /index.html
bf                                      | == Indexed - Add ==
                                        |   idx = 63
                                        | -> :authority:
                                        |   www.example.com
40                                      | == Literal indexed ==
0a                                      |   Literal name (len = 10)
6375 7374 6f6d 2d6b 6579                | custom-key
0c                                      |   Literal value (len = 12)
6375 7374 6f6d 2d76 616c 7565           | custom-value
                                        | -> custom-key:
                                        |   custom-value

디코딩 후 동적 테이블:

[  1] (s =  54) custom-key: custom-value
[  2] (s =  53) cache-control: no-cache
[  3] (s =  57) :authority: www.example.com
      Table size: 164

디코딩된 헤더 목록:

:method: GET
:scheme: https
:path: /index.html
:authority: www.example.com
custom-key: custom-value

C.4. 허프만 코딩 있는 요청 예제

이 절은 이전 절과 동일한 예제들을 보여주되 리터럴 값에 대해 허프만 인코딩을 사용합니다.

C.4.1. 첫 번째 요청

인코딩할 헤더 목록:

:method: GET
:scheme: http
:path: /
:authority: www.example.com

인코딩된 데이터의 16진수 덤프:

8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4 | ...A......:k....
ff                                      | .

디코딩 과정:

82                                      | == Indexed - Add ==
                                        |   idx = 2
                                        | -> :method: GET
86                                      | == Indexed - Add ==
                                        |   idx = 6
                                        | -> :scheme: http
84                                      | == Indexed - Add ==
                                        |   idx = 4
                                        | -> :path: /
41                                      | == Literal indexed ==
                                        |   Indexed name (idx = 1)
                                        |     :authority
8c                                      |   Literal value (len = 12)
                                        |     Huffman encoded:
f1e3 c2e5 f23a 6ba0 ab90 f4ff           | .....:k.....
                                        |     Decoded:
                                        | www.example.com
                                        | -> :authority:
                                        |   www.example.com

디코딩 후 동적 테이블:

[  1] (s =  57) :authority: www.example.com
      Table size:  57

디코딩된 헤더 목록:

:method: GET
:scheme: http
:path: /
:authority: www.example.com

C.4.2. 두 번째 요청

인코딩할 헤더 목록:

:method: GET
:scheme: http
:path: /
:authority: www.example.com
cache-control: no-cache

인코딩된 데이터의 16진수 덤프:

8286 84be 5886 a8eb 1064 9cbf           | ....X....d..

디코딩 과정:

82                                      | == Indexed - Add ==
                                        |   idx = 2
                                        | -> :method: GET
86                                      | == Indexed - Add ==
                                        |   idx = 6
                                        | -> :scheme: http
84                                      | == Indexed - Add ==
                                        |   idx = 4
                                        | -> :path: /
be                                      | == Indexed - Add ==
                                        |   idx = 62
                                        | -> :authority:
                                        |   www.example.com
58                                      | == Literal indexed ==
                                        |   Indexed name (idx = 24)
                                        |     cache-control
86                                      |   Literal value (len = 6)
                                        |     Huffman encoded:
a8eb 1064 9cbf                          | ...d..
                                        |     Decoded:
                                        | no-cache
                                        | -> cache-control: no-cache

디코딩 후 동적 테이블:

[  1] (s =  53) cache-control: no-cache
[  2] (s =  57) :authority: www.example.com
      Table size: 110

디코딩된 헤더 목록:

:method: GET
:scheme: http
:path: /
:authority: www.example.com
cache-control: no-cache

C.4.3. 세 번째 요청

인코딩할 헤더 목록:

:method: GET
:scheme: https
:path: /index.html
:authority: www.example.com
custom-key: custom-value

인코딩된 데이터의 16진수 덤프:

8287 85bf 4088 25a8 49e9 5ba9 7d7f 8925 | ....@.%.I.[.}..%
a849 e95b b8e8 b4bf                     | .I.[....

디코딩 과정:

82                                      | == Indexed - Add ==
                                        |   idx = 2
                                        | -> :method: GET
87                                      | == Indexed - Add ==
                                        |   idx = 7
                                        | -> :scheme: https
85                                      | == Indexed - Add ==
                                        |   idx = 5
                                        | -> :path: /index.html
bf                                      | == Indexed - Add ==
                                        |   idx = 63
                                        | -> :authority:
                                        |   www.example.com
40                                      | == Literal indexed ==
88                                      |   Literal name (len = 8)
                                        |     Huffman encoded:
25a8 49e9 5ba9 7d7f                     | %.I.[.}.
                                        |     Decoded:
                                        | custom-key
89                                      |   Literal value (len = 9)
                                        |     Huffman encoded:
25a8 49e9 5bb8 e8b4 bf                  | %.I.[....
                                        |     Decoded:
                                        | custom-value
                                        | -> custom-key:
                                        |   custom-value

디코딩 후 동적 테이블:

[  1] (s =  54) custom-key: custom-value
[  2] (s =  53) cache-control: no-cache
[  3] (s =  57) :authority: www.example.com
      Table size: 164

디코딩된 헤더 목록:

:method: GET
:scheme: https
:path: /index.html
:authority: www.example.com
custom-key: custom-value

C.5. 허프만 코딩 없는 응답 예제

이 절은 동일한 연결 상에서 연속되는 여러 헤더 목록(HTTP 응답에 해당)을 보여줍니다. HTTP/2 설정 매개변수 SETTINGS_HEADER_TABLE_SIZE가 256 옥텟으로 설정되어 일부 항목 축출이 발생합니다.

C.5.1. 첫 번째 응답

인코딩할 헤더 목록:

:status: 302
cache-control: private
date: Mon, 21 Oct 2013 20:13:21 GMT
location: https://www.example.com

인코딩된 데이터의 16진수 덤프:

4803 3330 3258 0770 7269 7661 7465 611d | H.302X.privatea.
4d6f 6e2c 2032 3120 4f63 7420 3230 3133 | Mon, 21 Oct 2013
2032 303a 3133 3a32 3120 474d 546e 1768 |  20:13:21 GMTn.h
7474 7073 3a2f 2f77 7777 2e65 7861 6d70 | ttps://www.examp
6c65 2e63 6f6d                          | le.com

디코딩 과정:

48                                      | == Literal indexed ==
                                        |   Indexed name (idx = 8)
                                        |     :status
03                                      |   Literal value (len = 3)
3330 32                                 | 302
                                        | -> :status: 302
58                                      | == Literal indexed ==
                                        |   Indexed name (idx = 24)
                                        |     cache-control
07                                      |   Literal value (len = 7)
7072 6976 6174 65                       | private
                                        | -> cache-control: private
61                                      | == Literal indexed ==
                                        |   Indexed name (idx = 33)
                                        |     date
1d                                      |   Literal value (len = 29)
4d6f 6e2c 2032 3120 4f63 7420 3230 3133 | Mon, 21 Oct 2013
2032 303a 3133 3a32 3120 474d 54        |  20:13:21 GMT
                                        | -> date: Mon, 21 Oct 2013
                                        |   20:13:21 GMT
6e                                      | == Literal indexed ==
                                        |   Indexed name (idx = 46)
                                        |     location
17                                      |   Literal value (len = 23)
6874 7470 733a 2f2f 7777 772e 6578 616d | https://www.exam
706c 652e 636f 6d                       | ple.com
                                        | -> location:
                                        |   https://www.example.com

디코딩 후 동적 테이블:

[  1] (s =  63) location: https://www.example.com
[  2] (s =  65) date: Mon, 21 Oct 2013 20:13:21 GMT
[  3] (s =  52) cache-control: private
[  4] (s =  42) :status: 302
      Table size: 222

디코딩된 헤더 목록:

:status: 302
cache-control: private
date: Mon, 21 Oct 2013 20:13:21 GMT
location: https://www.example.com

C.5.2. 두 번째 응답

(":status", "302") 헤더 필드는 (":status", "307") 헤더 필드를 추가하기 위한 공간을 마련하기 위해 동적 테이블에서 축출됩니다.

인코딩할 헤더 목록:

:status: 307
cache-control: private
date: Mon, 21 Oct 2013 20:13:21 GMT
location: https://www.example.com

인코딩된 데이터의 16진수 덤프:

4803 3330 37c1 c0bf                     | H.307...

디코딩 과정:

48                                      | == Literal indexed ==
                                        |   Indexed name (idx = 8)
                                        |     :status
03                                      |   Literal value (len = 3)
3330 37                                 | 307
                                        | - evict: :status: 302
                                        | -> :status: 307
c1                                      | == Indexed - Add ==
                                        |   idx = 65
                                        | -> cache-control: private
c0                                      | == Indexed - Add ==
                                        |   idx = 64
                                        | -> date: Mon, 21 Oct 2013
                                        |   20:13:21 GMT
bf                                      | == Indexed - Add ==
                                        |   idx = 63
                                        | -> location:
                                        |   https://www.example.com

디코딩 후 동적 테이블:

[  1] (s =  42) :status: 307
[  2] (s =  63) location: https://www.example.com
[  3] (s =  65) date: Mon, 21 Oct 2013 20:13:21 GMT
[  4] (s =  52) cache-control: private
      Table size: 222

디코딩된 헤더 목록:

:status: 307
cache-control: private
date: Mon, 21 Oct 2013 20:13:21 GMT
location: https://www.example.com

C.5.3. 세 번째 응답

이 헤더 목록을 처리하는 동안 동적 테이블에서 여러 헤더 필드가 축출됩니다.

인코딩할 헤더 목록:

:status: 200
cache-control: private
date: Mon, 21 Oct 2013 20:13:22 GMT
location: https://www.example.com
content-encoding: gzip
set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1

인코딩된 데이터의 16진수 덤프:

88c1 611d 4d6f 6e2c 2032 3120 4f63 7420 | ..a.Mon, 21 Oct
3230 3133 2032 303a 3133 3a32 3220 474d | 2013 20:13:22 GM
54c0 5a04 677a 6970 7738 666f 6f3d 4153 | T.Z.gzipw8foo=AS
444a 4b48 514b 425a 584f 5157 454f 5049 | DJKHQKBZXOQWEOPI
5541 5851 5745 4f49 553b 206d 6178 2d61 | UAXQWEOIU; max-a
6765 3d33 3630 303b 2076 6572 7369 6f6e | ge=3600; version
3d31                                    | =1

디코딩 과정:

88                                      | == Indexed - Add ==
                                        |   idx = 8
                                        | -> :status: 200
c1                                      | == Indexed - Add ==
                                        |   idx = 65
                                        | -> cache-control: private
61                                      | == Literal indexed ==
                                        |   Indexed name (idx = 33)
                                        |     date
1d                                      |   Literal value (len = 29)
4d6f 6e2c 2032 3120 4f63 7420 3230 3133 | Mon, 21 Oct 2013
2032 303a 3133 3a32 3220 474d 54        |  20:13:22 GMT
                                        | - evict: cache-control:
                                        |   private
                                        | -> date: Mon, 21 Oct 2013
                                        |   20:13:22 GMT
c0                                      | == Indexed - Add ==
                                        |   idx = 64
                                        | -> location: 
                                        |   https://www.example.com
5a                                      | == Literal indexed ==
                                        |   Indexed name (idx = 26)
                                        |     content-encoding
04                                      |   Literal value (len = 4)
677a 6970                               | gzip
                                        | - evict: date: Mon, 21 Oct 
                                        |    2013 20:13:21 GMT
                                        | -> content-encoding: gzip
77                                      | == Literal indexed ==
                                        |   Indexed name (idx = 55)
                                        |     set-cookie
38                                      |   Literal value (len = 56)
666f 6f3d 4153 444a 4b48 514b 425a 584f | foo=ASDJKHQKBZXO
5157 454f 5049 5541 5851 5745 4f49 553b | QWEOPIUAXQWEOIU;
206d 6178 2d61 6765 3d33 3630 303b 2076 |  max-age=3600; v
6572 7369 6f6e 3d31                     | ersion=1
                                        | - evict: location:
                                        |   https://www.example.com
                                        | - evict: :status: 307
                                        | -> set-cookie: foo=ASDJKHQ
                                        |   KBZXOQWEOPIUAXQWEOIU; ma
                                        |   x-age=3600; version=1

디코딩 후 동적 테이블:

[  1] (s =  98) set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;
                 max-age=3600; version=1
[  2] (s =  52) content-encoding: gzip
[  3] (s =  65) date: Mon, 21 Oct 2013 20:13:22 GMT
      Table size: 215

디코딩된 헤더 목록:

:status: 200
cache-control: private
date: Mon, 21 Oct 2013 20:13:22 GMT
location: https://www.example.com
content-encoding: gzip
set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1

C.6. 허프만 코딩 있는 응답 예제

이 절은 이전 절과 동일한 예제들을 보여주되 리터럴 값에 대해 허프만 인코딩을 사용합니다. HTTP/2 설정 매개변수 SETTINGS_HEADER_TABLE_SIZE가 256 옥텟으로 설정되어 일부 항목 축출이 발생합니다. 축출 메커니즘은 디코딩된 리터럴 값의 길이를 사용하므로 이전 절과 동일한 축출이 발생합니다.

C.6.1. 첫 번째 응답

인코딩할 헤더 목록:

:status: 302
cache-control: private
date: Mon, 21 Oct 2013 20:13:21 GMT
location: https://www.example.com

인코딩된 데이터의 16진수 덤프:

4882 6402 5885 aec3 771a 4b61 96d0 7abe | H.d.X...w.Ka..z.
9410 54d4 44a8 2005 9504 0b81 66e0 82a6 | ..T.D. .....f...
2d1b ff6e 919d 29ad 1718 63c7 8f0b 97c8 | -..n..)...c.....
e9ae 82ae 43d3                          | ....C.

디코딩 과정:

48                                      | == Literal indexed ==
                                        |   Indexed name (idx = 8)
                                        |     :status
82                                      |   Literal value (len = 2)
                                        |     Huffman encoded:
6402                                    | d.
                                        |     Decoded:
                                        | 302
                                        | -> :status: 302
58                                      | == Literal indexed ==
                                        |   Indexed name (idx = 24)
                                        |     cache-control
85                                      |   Literal value (len = 5)
                                        |     Huffman encoded:
aec3 771a 4b                            | ..w.K
                                        |     Decoded:
                                        | private
                                        | -> cache-control: private
61                                      | == Literal indexed ==
                                        |   Indexed name (idx = 33)
                                        |     date
96                                      |   Literal value (len = 22)
                                        |     Huffman encoded:
d07a be94 1054 d444 a820 0595 040b 8166 | .z...T.D. .....f
e082 a62d 1bff                          | ...-..
                                        |     Decoded:
                                        | Mon, 21 Oct 2013 20:13:21
                                        | GMT
                                        | -> date: Mon, 21 Oct 2013
                                        |   20:13:21 GMT
6e                                      | == Literal indexed ==
                                        |   Indexed name (idx = 46)
                                        |     location
91                                      |   Literal value (len = 17)
                                        |     Huffman encoded:
9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 | .)...c.........C
d3                                      | .
                                        |     Decoded:
                                        | https://www.example.com
                                        | -> location:
                                        |   https://www.example.com

디코딩 후 동적 테이블:

[  1] (s =  63) location: https://www.example.com
[  2] (s =  65) date: Mon, 21 Oct 2013 20:13:21 GMT
[  3] (s =  52) cache-control: private
[  4] (s =  42) :status: 302
      Table size: 222

디코딩된 헤더 목록:

:status: 302
cache-control: private
date: Mon, 21 Oct 2013 20:13:21 GMT
location: https://www.example.com

C.6.2. 두 번째 응답

(":status", "302") 헤더 필드는 (":status", "307") 헤더 필드를 추가하기 위한 공간을 마련하기 위해 동적 테이블에서 축출됩니다.

인코딩할 헤더 목록:

:status: 307
cache-control: private
date: Mon, 21 Oct 2013 20:13:21 GMT
location: https://www.example.com

인코딩된 데이터의 16진수 덤프:

4883 640e ffc1 c0bf                     | H.d.....

디코딩 과정:

48                                      | == Literal indexed ==
                                        |   Indexed name (idx = 8)
                                        |     :status
83                                      |   Literal value (len = 3)
                                        |     Huffman encoded:
640e ff                                 | d..
                                        |     Decoded:
                                        | 307
                                        | - evict: :status: 302
                                        | -> :status: 307
c1                                      | == Indexed - Add ==
                                        |   idx = 65
                                        | -> cache-control: private
c0                                      | == Indexed - Add ==
                                        |   idx = 64
                                        | -> date: Mon, 21 Oct 2013
                                        |   20:13:21 GMT
bf                                      | == Indexed - Add ==
                                        |   idx = 63
                                        | -> location:
                                        |   https://www.example.com

디코딩 후 동적 테이블:

[  1] (s =  42) :status: 307
[  2] (s =  63) location: https://www.example.com
[  3] (s =  65) date: Mon, 21 Oct 2013 20:13:21 GMT
[  4] (s =  52) cache-control: private
      Table size: 222

디코딩된 헤더 목록:

:status: 307
cache-control: private
date: Mon, 21 Oct 2013 20:13:21 GMT
location: https://www.example.com

C.6.3. 세 번째 응답

이 헤더 목록을 처리하는 동안 동적 테이블에서 여러 헤더 필드가 축출됩니다.

인코딩할 헤더 목록:

:status: 200
cache-control: private
date: Mon, 21 Oct 2013 20:13:22 GMT
location: https://www.example.com
content-encoding: gzip
set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1

인코딩된 데이터의 16진수 덤프:

88c1 6196 d07a be94 1054 d444 a820 0595 | ..a..z...T.D. ..
040b 8166 e084 a62d 1bff c05a 839b d9ab | ...f...-...Z....
77ad 94e7 821d d7f2 e6c7 b335 dfdf cd5b | w..........5...[
3960 d5af 2708 7f36 72c1 ab27 0fb5 291f | 9`..'..6r..'..).
9587 3160 65c0 03ed 4ee5 b106 3d50 07   | ..1`e...N...=P.

디코딩 과정:

88                                      | == Indexed - Add ==
                                        |   idx = 8
                                        | -> :status: 200
c1                                      | == Indexed - Add ==
                                        |   idx = 65
                                        | -> cache-control: private
61                                      | == Literal indexed ==
                                        |   Indexed name (idx = 33)
                                        |     date
96                                      |   Literal value (len = 22)
                                        |     Huffman encoded:
d07a be94 1054 d444 a820 0595 040b 8166 | .z...T.D. .....f
e084 a62d 1bff                          | ...-..
                                        |     Decoded:
                                        | Mon, 21 Oct 2013 20:13:22
                                        | GMT
                                        | - evict: cache-control:
                                        |   private
                                        | -> date: Mon, 21 Oct 2013 
                                        |   20:13:22 GMT
c0                                      | == Indexed - Add ==
                                        |   idx = 64
                                        | -> location:
                                        |   https://www.example.com
5a                                      | == Literal indexed ==
                                        |   Indexed name (idx = 26)
                                        |     content-encoding
83                                      |   Literal value (len = 3)
                                        |     Huffman encoded:
9bd9 ab                                 | ...
                                        |     Decoded:
                                        | gzip
                                        | - evict: date: Mon, 21 Oct
                                        |    2013 20:13:21 GMT
                                        | -> content-encoding: gzip
77                                      | == Literal indexed ==
                                        |   Indexed name (idx = 55)
                                        |     set-cookie
ad                                      |   Literal value (len = 45)
                                        |     Huffman encoded:
94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 | .........5...[9`
d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 | ..'..6r..'..)...
3160 65c0 03ed 4ee5 b106 3d50 07        | 1`e...N...=P.
                                        |     Decoded:
                                        | foo=ASDJKHQKBZXOQWEOPIUAXQ
                                        | WEOIU; max-age=3600; versi
                                        | on=1
                                        | - evict: location:
                                        |   https://www.example.com
                                        | - evict: :status: 307
                                        | -> set-cookie: foo=ASDJKHQ
                                        |   KBZXOQWEOPIUAXQWEOIU; ma
                                        |   x-age=3600; version=1

디코딩 후 동적 테이블:

[  1] (s =  98) set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;
                 max-age=3600; version=1
[  2] (s =  52) content-encoding: gzip
[  3] (s =  65) date: Mon, 21 Oct 2013 20:13:22 GMT
      Table size: 215

디코딩된 헤더 목록:

:status: 200
cache-control: private
date: Mon, 21 Oct 2013 20:13:22 GMT
location: https://www.example.com
content-encoding: gzip
set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1

감사의 글

이 규격에는 다음 개인들로부터의 상당한 입력이 포함되어 있습니다:

  • Mike Bishop, Jeff Pinner, Julian Reschke, and Martin Thomson (중요한 편집 기여).
  • Johnny Graettinger (허프만 코드 통계).

저자 주소

Roberto Peon
Google, Inc
이메일: fenix@google.com
Hervé Ruellan
Canon CRF
이메일: herve.ruellan@crf.canon.fr