RFC 7230
[page X] : 원문의 해당 페이지를 적어놓었다.
- Webserv를 진행하는데 필요하다고 생각되는 부분만 취사번역한 것이다. Chatgpt에게 열심히 물어보면서 진행했다.
RFC 7230 원문
- RFC 7230 원문
- 하이퍼텍스트 전송 프로토콜 (HTTP/1.1) : 메세지 구문과 라우팅
- 1) Introduction
- 2) Architecture
- 3) Message Format
- 4) Transfer Coding
- 5) Message Routing
- 6) Connection Management (연결 관리)
하이퍼텍스트 전송 프로토콜 (HTTP/1.1) : 메세지 구문과 라우팅
[page 1] 초록
하이퍼 텍스트 전송 프로토콜(http)는 분산된, 협력적인 하이퍼 텍스트 정보 시스템을 위한 무상태 응용 프로그램 수준의 프로토콜입니다. 이 문서는 HTTP 구조에 대한 개요를 제공하고, 그와 관련된 용어, “http” 그리고 “https” 통합 자원 식별자 제도, HTTP/1.1 메세지 구문과 요구되는 파싱 처리를 정의하며 구현과 관련된 보안 사항을 기술합니다.
1) Introduction
Intro
[page 5] 하이퍼텍스트 전송 프로토콜(HTTP)은 무상태 응용 프로그램 수준의 요청/응답 프로토콜로, 확장 가능한 의미론과 자기 서술적인 메시지 페이 로드(payload)를 사용하여 네트워크 기반 하이퍼 텍스트 정보 시스템과 유연한 상호 작용을 가능하게 합니다. 이 문서는 HTTP/1.1 사양을 형성하는 일련의 문서 중 첫 번째 문서입니다.
1. **메세지 구문과 라우팅** (**이 문서 RFC 7230**)
2. 의미론과 그 내용 (RFC 7231)
3. 조건적 요청 (RFC 7232)
4. 범위 요청 (RFC 7233)
5. 캐싱 (RFC 7234)
6. 인증 (RFC 7235)
이 HTTP/1.1 사양은 RFC 2616 및 RFC 2145(HTTP 버전 지정에 대한)을 폐기합니다. 이 사양은 또한 이전에 RFC 2817에서 정의된 터널을 설정하기 위한 CONNECT의 사용을 업데이트하고, RFC 2818에서 비공식적으로 설명된 “https” URI 스킴을 정의합니다.
HTTP는 정보 시스템을 위한 범용 인터페이스 프로토콜입니다. 이는 서비스의 구현 세부 정보를 숨기기 위해 설계되어 클라이언트에게 제공되는 리소스의 유형과 독립적인, 일관된 인터페이스를 제공합니다. 마찬가지로 서버는 각 클라이언트의 목적을 알 필요가 없습니다. HTTP 요청은 특정 유형의 클라이언트나 사전에 정의된 응용 프로그램 단계의 일부로 연관되는 것이 아니라, 독립적으로 고려될 수 있습니다. 결과적으로, 이는 다양한 맥락에서 효과적으로 사용할 수 있는 프로토콜이며, 구현은 시간이 지남에 따라 독립적으로 진화할 수 있습니다.
HTTP는 또한 비-HTTP 정보 시스템과의 통신을 번역하기 위한 중개 프로토콜로 설계되었습니다. HTTP 프록시 및 게이트웨이는 다양한 프로토콜을 하이퍼텍스트 형식으로 변환하여 클라이언트가 HTTP 서비스와 동일한 방식으로 볼 수 있고 조작할 수 있도록 함으로써 대체 정보 서비스에 대한 액세스를 제공할 수 있습니다.
이 유연성의 한 가지 결과는 프로토콜을 인터페이스 뒤에서 발생하는 측면으로 정의할 수 없다는 점입니다. 대신, 우리는 통신의 구문, 수신된 통신의 의도, 그리고 수신자의 예상 동작을 정의하는 데 제한됩니다. 통신이 독립적으로 고려된다면, 성공적인 동작은 서버가 제공하는 관찰 가능한 인터페이스에 해당 변경 사항이 반영되어야 합니다. 그러나 여러 클라이언트가 동시에 작업하고 때로는 상충하는 목적으로 작동할 수 있기 때문에, 이러한 변경 사항이 단일 응답의 범위를 벗어나서 관찰 가능하도록 요구할 수는 없습니다.
이 문서는 HTTP에서 사용되거나 언급되는 아키텍처 요소를 설명하고, “http” 및 “https” URI 스킴을(scheme, 프로토콜) 정의하며, 전체적인 네트워크 운영 및 연결 관리를 설명하며, HTTP 메시지 프레임 및 전달 요구 사항을 정의합니다. 우리의 목표는 메시지 의미론과 독립적인 HTTP 메시지 처리에 필요한 모든 메커니즘을 정의함으로써 메시지 파서 및 메시지 전달 중개자의 완전한 요구 사항 집합을 정의하는 것입니다.
1.1. 요청 표기법
[page 6] “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, “OPTIONAL” 과 같은 단어는 다음과 같이 기술됩니다.
- MUST: 이 단어 또는 “REQUIRED” 또는 “SHALL”이라는 용어는 해당 정의가 사양의 절대 요구사항임을 의미합니다.
- MUST NOT: 이 구문 또는 “SHALL NOT”라는 구문은 해당 정의가 사양의 절대적인 금지사항임을 의미합니다.
- SHOULD: 이 단어 또는 “RECOMMENDED”라는 형용사는 특정 상황에서는 특정 항목을 무시할 수 있는 유효한 이유가 존재할 수 있지만, 다른 방식을 선택하기 전에 모든 영향을 이해하고 신중히 고려해야 함을 의미합니다.
- SHOULD NOT: 이 구문 또는 “NOT RECOMMENDED”라는 구문은 특정 상황에서는 특정 동작이 허용되거나 심지어 유용할 수 있는 유효한 이유가 존재할 수 있지만, 모든 영향을 이해하고 사례를 신중히 고려해야 함을 의미합니다. 이 레이블로 설명된 동작을 구현하기 전에 해당 동작의 전체적인 영향을 이해하고 사례를 신중히 고려해야 합니다.
MAY: 이 단어 또는 “OPTIONAL”이라는 형용사는 항목이 실제로 선택 사항임을 의미합니다. 특정 시장 요구사항을 충족시키기 위해 또는 제품을 향상시키는 데 도움이 될 것으로 생각되기 때문에 한 공급업체는 해당 항목을 포함할 수 있으며, 다른 공급업체는 동일한 항목을 생략할 수 있습니다. 특정 옵션을 포함하지 않는 구현은 해당 옵션을 포함하는 다른 구현과 상호 운용될 수 있어야 합니다. 다만 기능이 제한될 수는 있습니다. 마찬가지로, 특정 옵션을 포함하는 구현은 해당 옵션을 포함하지 않는 다른 구현과 상호 운용될 수 있어야 합니다(물론 해당 옵션이 제공하는 기능은 제외됩니다).
- 부합하는 기준과 에러 처리에 대한 고려는 섹션 2.5에 정의되어 있습니다.
1.2. 구문 표기
이 사양은 [RFC5234]의 확장된 Backus-Naur Form (ABNF) 표기법을 사용합니다. 이 표기법은 Section 7에서 정의된 목록 확장을 포함하고 있으며, ‘#’ 연산자를 사용하여 쉼표로 구분된 목록을 간결하게 정의할 수 있도록 합니다. (이는 ** 연산자가 반복을 나타내는 방식과 유사합니다). 부록 B에는 모든 목록 연산자가 표준 ABNF 표기법으로 확장된 수집된 문법이 표시되어 있습니다.
다음의 핵심 규칙은 [RFC5234], 부록 B.1에 정의된 대로 참조로 포함됩니다: ALPHA (문자), CR (캐리지 리턴), CRLF (CR LF), CTL (제어문자), DIGIT (10진수 0-9), DQUOTE (이중 인용부호), HEXDIG (16진수 0-9/A-F/a-f), HTAB (수평 탭), LF (줄 바꿈), OCTET (8비트 데이터 시퀀스), SP (공백), 그리고 VCHAR (가시적인 [USASCII] 문자).
관례적으로, “obs-“로 접두사가 붙은 ABNF 규칙 이름은 역사적인 이유로 인해 나타나는 “폐기된” 문법 규칙을 나타냅니다.
2) Architecture
HTTP는 World Wide Web (WWW) 아키텍처를 위해 만들어졌으며, 시간이 흐름에 따라 전 세계 하이퍼텍스트 시스템의 확장성 요구 사항을 지원하기 위해 발전해 왔습니다. 그 아키텍처의 많은 부분이 HTTP를 정의하는 용어와 구문 생성물에 반영되고 있습니다.
2.1 클라이언트 / 서버 메세징
[page 7] HTTP는 신뢰할 수 있는 전송 또는 세션 계층의 “연결”(Section 6)을 통해 메시지(Section 3)를 교환하여 동작하는 무상태 요청/응답 프로토콜입니다. HTTP “클라이언트”는 하나 이상의 HTTP 요청을 보내기 위해 서버와의 연결을 설정하는 프로그램입니다. HTTP “서버”는 HTTP 응답을 보내어 HTTP 요청을 처리하기 위해 연결을 수락하는 프로그램입니다.
“클라이언트”와 “서버”라는 용어는 이러한 프로그램들이 특정 연결에서 수행하는 역할에 대해서만 언급합니다. 동일한 프로그램이 어떤 연결에서는 클라이언트로 동작하고 어떤 연결에서는 서버로 동작할 수 있습니다. “유저 에이전트(UA)”라는 용어는 요청을 시작하는 다양한 클라이언트 프로그램을 의미하며, 브라우저, 스파이더 (웹 기반 로봇), 명령 줄 도구, 사용자 정의 애플리케이션 및 모바일 앱을 포함하지만 이에 국한되지는 않습니다. “원본 서버”라는 용어는 특정 대상 리소스에 대해 권위 있는 응답을 생성할 수 있는 프로그램을 가리킵니다. “송신자”와 “수신자”라는 용어는 각각 주어진 메시지를 송신하거나 수신하는 구현을 의미합니다.
HTTP는 리소스의 대상을 나타내기 위해 Uniform Resource Identifier (URI) 표준 [RFC3986]을 사용하며, 리소스 간의 관계를 나타냅니다. 메시지는 인터넷 메일 [RFC5322]과 Multi purpose Internet Mail Extensions (MIME) [RFC2045]에서 사용되는 형식과 유사한 형식으로 전달됩니다. HTTP와 MIME 메시지의 차이점에 대해서는 [RFC7231]의 부록 A를 참조하십시오.
대부분의 HTTP 통신은 URI로 식별된 어떤 리소스의 표현을 검색하기 위한 검색 요청(GET)으로 이루어집니다. 가장 간단한 경우에는 유저 에이전트 (UA) 와 원본 서버 (O) 간에 단일 양방향 연결( === )을 통해 이를 수행할 수 있습니다.
request >
UA ======================================= O
< response
클라이언트는 요청 메시지 형식으로 서버에 HTTP 요청을 보냅니다. 이 요청 메시지는 요청 라인(request-line) 으로 시작하며, 이는 메서드, URI 및 프로토콜 버전 (Section 3.1.1)을 포함합니다. 이후에는 요청 수정자, 클라이언트 정보 및 표현 메타데이터를 포함하는 헤더 필드 (Section 3.2)가 이어지고, 헤더 섹션의 끝을 나타내는 빈 줄이 옵니다. 마지막으로, 메시지 본문에는 페이로드 본문이 포함될 수 있습니다 (있는 경우, Section 3.3).
[page 8] 서버는 클라이언트의 요청에 대해 하나 이상의 HTTP 응답 메시지를 보내어 응답합니다. 각 응답 메시지는 상태 라인(status-line) 으로 시작하며, 이는 프로토콜 버전, 성공 또는 오류 코드 및 텍스트 형식의 이유 구문(reason phrase) (Section 3.1.2)을 포함합니다. 이후에는 서버 정보, 리소스 메타데이터 및 표현 메타데이터를 포함하는 헤더 필드 (Section 3.2) 가 이어지고, 헤더 섹션의 끝을 나타내는 빈 줄이 옵니다. 마지막으로, 메시지 본문에는 페이로드 본문이 포함될 수 있습니다 (있는 경우, Section 3.3).
섹션 6.3에서 정의된대로
다음 예제는 “http://www.example.com/hello.txt” URI에 대한 일반적인 GET 요청 (Section 4.3.1 of [RFC7231])에 대한 메시지 교환을 보여줍니다:
**클라이언트 요청:**
GET /hello.txt HTTP/1.1
User-Agent: curl/7.16.3 libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3
Host: [www.example.com](http://www.example.com/)
Accept-Language: en, mi
**서버 응답:**
HTTP/1.1 200 OK
Date: Mon, 27 Jul 2009 12:28:53 GMT
Server: Apache
Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT
ETag: "34aa387-d-1568eb00"
Accept-Ranges: bytes
Content-Length: 51
Vary: Accept-Encoding
Content-Type: text/plain
Hello World! My payload includes a trailing CRLF.
2.2 구현 다양성
HTTP의 설계를 고려할 때, 모든 유저 에이전트가 일반적인 웹 브라우저이고 모든 출처 서버가 대형 공개 웹사이트인 것으로 생각하기 쉽습니다. 그러나 실제로는 그렇지 않습니다. 일반적인 HTTP 유저 에이전트에는 가전제품, 스테레오, 저울, 펌웨어 업데이트 스크립트, 명령줄 프로그램, 모바일 앱 및 다양한 모양과 크기의 통신 장치 등이 포함됩니다. 마찬가지로, 일반적인 HTTP 출처 서버에는 홈 자동화 장치, 구성 가능한 네트워킹 구성 요소, 사무 기기, 자율 로봇, 뉴스 피드, 교통 카메라, 광고 선택기 및 비디오 전송 플랫폼이 포함됩니다.
[page 9] “유저 에이전트”라는 용어는 요청이 발생할 때 인간 사용자가 소프트웨어 에이전트와 직접 상호작용하는 것을 의미하지 않습니다. 많은 경우 유저 에이전트는 백그라운드에서 실행되거나 구성되어 나중에 결과를 검사하기 위해 저장됩니다 (또는 흥미로운 또는 오류가 될 수 있는 결과의 일부분만 저장됩니다). 예를 들어, 스파이더는 일반적으로 시작 URI를 지정하고 웹을 탐색하는 동안 특정 동작을 따르도록 구성됩니다.
HTTP의 구현 다양성은 모든 유저 에이전트가 사용자에게 대화식 제안을 제공하거나 보안 또는 개인 정보 보호에 대한 적절한 경고를 제공할 수 있는 것은 아니라는 것을 의미합니다. 이 명세에서 오류를 사용자에게 보고해야 하는 몇 가지 경우에는 해당 보고가 오류 콘솔이나 로그 파일에서만 관찰될 수 있는 것으로 허용됩니다. 마찬가지로, 자동화된 동작을 진행하기 전에 사용자로부터 확인이 필요한 요구 사항은 사전 구성 선택, 실행 시 옵션 또는 해당 위험한 동작을 피하는 간단한 조치로 충족될 수 있습니다. 확인은 특정 사용자 인터페이스나 정상 처리의 중단을 의미하지 않으며, 사용자가 이미 해당 선택을 했다면 정상 처리가 진행될 수 있습니다.
2.3 중재자들
HTTP는 연결 체인을 통해 중개자를 사용하여 요청을 충족시키는 기능을 제공합니다. HTTP 중개자에는 프록시(proxy), 게이트웨이(gateway) 및 터널(tunnel) 의 세 가지 일반적인 형태가 있습니다. 경우에 따라 단일 중개자가 각 요청의 성격에 따라 원 서버, 프록시, 게이트웨이 또는 터널로 작동할 수 있습니다.
-> -> -> ->
UA ===== A ===== B ===== C ===== O
<- <- <- <-
위의 도표는 유저 에이전트와 원 서버 사이에 A, B, C라는 세 개의 중개자를 보여줍니다. 전체 체인을 통과하는 요청 또는 응답 메시지는 네 개의 별개의 연결을 통과합니다. 일부 HTTP 통신 옵션은 가장 가까운 터널이 아닌 이웃과의 연결에만 적용되거나 체인의 끝점에만 적용되거나 체인 전체의 모든 연결에 적용될 수 있습니다. 그림은 선형적이지만 각 참가자는 여러 개의 동시 통신에 참여할 수 있습니다. 예를 들어, B는 A 외에도 다른 클라이언트로부터 요청을 받거나 C 이외의 서버로 요청을 전달하면서 A의 요청을 처리하는 동시에 여러 개의 통신을 수행할 수 있습니다. 마찬가지로 나중의 요청은 로드 밸런싱을 위한 동적 구성에 따라 다른 연결 경로를 통해 전송될 수 있습니다.
[page 10] “Upstream” 과 “downstream” 이라는 용어는 메시지의 흐름과 관련하여 방향성 요구사항을 설명하는 데 사용됩니다. 모든 메시지는 “upstream”에서 “downstream”으로 흐릅니다. “Inbound”와 “outbound”라는 용어는 요청 경로와 관련하여 방향성 요구사항을 설명하는 데 사용됩니다. “Inbound”는 원 서버 쪽으로의 방향을 의미하며, 메시지가 처리를 위해 서버 쪽으로 이동하는 것을 나타냅니다. 반면에 “outbound”는 유저 에이전트 쪽으로의 방향을 의미하며, 메시지가 유저 에이전트 쪽으로 이동하여 소비되거나 표시되는 것을 나타냅니다.
“프록시(proxy)“는 주로 로컬 설정 규칙을 경유하여, 클라이언트에 의해 선택되는 메시지 전달 에이전트로 일부 유형의 절대 URI를 요청 받고 HTTP 인터페이스를 통해 해당 요청을 만족시키기 위해 번역을 시도합니다. 일부 번역은 최소한으로 이루어지며, “http” URI에 대한 프록시 요청과 같은 경우입니다. 반면에 다른 요청은 완전히 다른 응용 계층 프로토콜로의 번역이 필요할 수도 있습니다. 프록시는 종종 보안, 주석 서비스 또는 공유 캐싱을 위해 조직의 HTTP 요청을 공통 중개자를 통해 그룹화하는 데 사용됩니다. 일부 프록시는 전달되는 동안 선택된 메시지나 페이로드에 변형을 적용하는 것이 설명된 섹션 5.7.2에서 설명된 대로 설계될 수 있습니다.
<Local Configuration Rule이란?>

“게이트웨이(gateway)” (또는 “리버스 프록시”)는 외부 연결(“outbound”)의 출발지 서버 역할을 하는 중개자로, 받은 요청을 번역하여 내부로 전달합니다. 게이트웨이는 종종 레거시 시스템이나 신뢰할 수 없는 정보 서비스를 캡슐화하거나, “가속기” 캐싱을 통해 서버 성능을 향상시키는 데 사용되며, HTTP 서비스를 여러 기기에 분할하거나 부하 분산을 가능하게 합니다.
모든 원본 서버에 적용되는 HTTP 요구사항은 게이트웨이의 외부 통신에도 적용됩니다. 게이트웨이는 원하는 프로토콜을 사용하여 인바운드 서버와 통신하며, 이는 이 명세의 범위를 벗어나는 HTTP에 대한 사적인 확장을 포함할 수 있습니다. 그러나 HTTP-to-HTTP 게이트웨이가 타사 HTTP 서버와 상호 운용하려는 경우에는 게이트웨이의 인바운드 연결에 대한 사용자 에이전트 요구사항을 준수하는 것이 좋습니다.
“터널(tunnel)“은 메시지를 변경하지 않으면서 두 연결 사이에서 블라인드 중계 역할을 수행합니다. 터널은 일단 활성화되면 HTTP 통신의 일부로 간주되지는 않지만, 그 자체는 HTTP 요청에 의해 시작될 수 있습니다. 터널은 양측의 연속적인 통신이 끝날 때 종료됩니다. 터널은 공유 방화벽 프록시를 통해 기밀 통신을 설정하기 위해 전송 계층 보안(TLS, [RFC5246])을 사용할 때와 같이 중개자를 통해 가상 연결을 확장하는 데 사용됩니다.
[page 11] 앞서 언급한 중개자에 대한 분류는 HTTP 통신의 참여자로서 작동하는 중개자만을 고려합니다. 그러나 메시지 발송자의 지식이나 허락 없이 HTTP 트래픽을 필터링하거나 리디렉션하는 등 네트워크 프로토콜 스택의 하위 계층에서 작동하는 중개자도 존재합니다. 이러한 네트워크 중개자는 프로토콜 수준에서 중간자 공격과 구별할 수 없으며, 종종 HTTP 의미론을 잘못 위반하여 보안 결함이나 상호 운용성 문제를 야기할 수 있습니다.
예를 들어, “interception proxy” [RFC3040] (일반적으로 “transparent proxy” [RFC1919] 또는 “captive portal”로도 알려짐)는 클라이언트에 의해 선택되지 않기 때문에 HTTP 프록시와는 다릅니다. 대신, 인터셉션 프록시는 나가는 TCP 포트 80 패킷(가끔 다른 일반적인 포트 트래픽도)을 필터링하거나 리디렉션합니다. 인터셉션 프록시는 일반적으로 공공 네트워크 접근 지점에서 찾을 수 있으며, 비로컬 인터넷 서비스 사용 전에 계정 구독을 강제하는 수단으로 사용되거나, 기업 방화벽에서 네트워크 사용 정책을 강제하는 용도로 사용됩니다.
HTTP는 무상태 프로토콜로 정의되어 있으며, 그것은 각각의 요청 메시지가 독립적으로 이해될 수 있다는 의미입니다. 많은 구현이 프록시된 연결을 재사용하거나 여러 서버에 동적으로 요청을 로드 밸런싱하기 위해 HTTP의 상태 없는 디자인에 의존합니다. 따라서 서버는 연결이 보안되고 특정한 에이전트에게 속한 것인 경우를 제외하고는 동일한 연결에서 온 두 개의 요청이 동일한 사용자 에이전트에 의한 것으로 가정해서는 안 됩니다(“MUST NOT”). 비표준 HTTP 확장 (예: [RFC4559]) 중 일부는 이 요구사항을 위반하여 보안 및 상호 운용성 문제를 야기하는 것으로 알려져 있습니다.
2.4 캐시
“캐시(cache)”는 이전 응답 메시지의 로컬 저장소와 해당 메시지의 저장, 검색 및 삭제를 제어하는 하위 시스템입니다. 캐시는 캐시 가능한 응답을 저장하여 이후 동등한 요청에 대한 응답 시간과 네트워크 대역폭 소비를 줄입니다. 클라이언트나 서버는 캐시를 사용할 수 있으나, 서버가 터널로 동작하는 동안에는 캐시를 사용할 수 없습니다.
[page 12] 캐시의 효과는 체인 상에 있는 참여자 중 하나가 해당 요청에 적용 가능한 캐시된 응답을 가지고 있을 경우, 요청/응답 체인이 단축된다는 것입니다. 다음은 UA 또는 A에 의해 캐시되지 않은 요청에 대해 B가 O(를 통해 C를 거쳐)의 이전 응답에 대한 캐시된 복사본을 가지고 있는 경우의 결과적인 체인을 보여줍니다.
----> ---->
UA =========== A =========== B - - - - - - C - - - - - - O
<-- <--
응답은 캐시가 해당 응답 메시지의 복사본을 저장하여 이후 요청에 대한 응답으로 사용할 수 있는 경우 “캐시 가능(cacheable)”하다고 할 수 있습니다. 응답이 캐시 가능하더라도 클라이언트나 원 서버에서 해당 캐시된 응답을 특정 요청에 사용할 때 추가적인 제약 사항이 있을 수 있습니다. 캐시 동작 및 캐시 가능한 응답에 대한 HTTP 요구사항은 [RFC7234]의 섹션 2에서 정의되어 있습니다.
세계적으로와 대규모 조직 내에서 다양한 아키텍처와 캐시 구성이 웹 전반에 걸쳐 배치되어 있습니다. 이에는 대양간 대역폭을 절약하기 위한 국가적인 프록시 캐시의 계층 구조, 캐시 항목을 브로드캐스트하거나 멀티캐스트하는 협업 시스템, 오프라인이나 높은 지연 환경에서 사용하기 위한 미리 가져온 캐시 항목의 아카이브 등이 포함됩니다.
2.5 표준 및 에러 처리
이 사양은 HTTP 통신의 참여자 역할에 따른 준수 기준을 대상으로 합니다. 따라서 요구 사항에 의해 제한되는 동작에 따라 발신자, 수신자, 클라이언트, 서버, 사용자 에이전트, 중개자, 출처 서버, 프록시, 게이트웨이 또는 캐시에 HTTP 요구 사항이 부여됩니다. 단일 통신의 범위를 벗어나는 경우 구현, 리소스 소유자 및 프로토콜 요소 등에 추가 (사회적) 요구 사항이 부여됩니다.
“generate”라는 동사는 요구 사항이 프로토콜 요소를 생성하는 것과 단순히 수신한 요소를 downstream으로 전달하는 것을 구분하는 경우 “send” 대신 사용됩니다.
HTTP에 참여하는 역할과 관련된 모든 요구 사항을 준수하는 경우 구현은 준수되는 것으로 간주됩니다.
준수는 프로토콜 요소의 구문 및 의미를 포함합니다. 발신자는 자신이 거짓으로 알고 있는 의미를 전달하는 프로토콜 요소를 생성해서는 안 됩니다. 발신자는 해당 ABNF 규칙에 의해 정의된 문법과 일치하지 않는 프로토콜 요소를 생성해서는 안 됩니다. 주어진 메시지 내에서 발신자는 다른 역할의 참여자만이 생성할 수 있는 프로토콜 요소나 구문 대안을 생성해서는 안 됩니다 (즉, 발신자가 해당 메시지에 대해 가지지 않은 역할).
수신된 프로토콜 요소가 구문 분석될 때, 수신자는 수신자의 역할에 적용 가능하고 해당 ABNF 규칙에 정의된 문법과 일치하는 합리적인 길이의 모든 값을 구문 분석할 수 있어야 합니다. 그러나 수신된 프로토콜 요소 중 일부는 구문 분석되지 않을 수도 있습니다. 예를 들어, 메시지를 전달하는 중개자는 헤더 필드를 일반적인 필드 이름과 필드 값 구성 요소로 구문 분석할 수 있지만, 필드 값 내에서 추가로 구문 분석하지 않고 헤더 필드를 전달할 수도 있습니다.
[page 13] HTTP는 많은 프로토콜 요소에 대해 특정 길이 제한을 갖고 있지 않습니다. 이는 적절한 길이가 배치 환경과 구현의 목적에 따라 크게 달라질 수 있기 때문입니다. 따라서 발신자와 수신자 간의 상호 운용성은 각 프로토콜 요소에 대해 어떤 길이가 합리적인지에 대한 공유된 기대에 따라 달려있습니다. 게다가, 몇 가지 프로토콜 요소에 대해 일반적으로 합리적인 길이로 인식되는 것은 HTTP 사용의 지난 20년 동안 변경되어왔으며, 미래에도 계속 변화할 것으로 예상됩니다.
최소한으로, 수신자는 다른 메시지에서 동일한 프로토콜 요소에 대해 생성하는 값과 동일한 길이 이상의 프로토콜 요소 길이를 구문 분석하고 처리할 수 있어야 합니다(“MUST”). 예를 들어, 자체 자원에 대해 매우 긴 URI 참조를 발행하는 출처 서버는 해당 참조를 요청 대상으로 수신받을 때 구문 분석하고 처리할 수 있어야 합니다.
수신자는 수신한 프로토콜 요소를 이 사양에 의해 정의된 의미에 따라 해석해야 합니다(“MUST”). 이 사양의 확장을 포함하여 의미에 의해 암시되는 것을 발신자가 잘못 구현한다고 판단하지 않은 한 (경험 또는 구성을 통해), 예외가 아닌 경우 프로토콜 요소를 사용자 정의해야 합니다. 예를 들어, 특정 콘텐츠 인코딩을 수신할 경우 실패하는 특정 구현 버전을 나타내는 User-Agent 헤더 필드 검사를 통해 Accept-Encoding 헤더 필드의 내용을 무시할 수 있습니다.
특별히 언급되지 않은 경우, 수신자는 잘못된 구조에서 사용 가능한 프로토콜 요소를 복구하려고 시도할 수 있습니다. HTTP는 프로토콜의 다양한 응용에 따라 다른 오류 처리 전략이 필요하기 때문에, 보안에 직접적인 영향을 미치는 경우를 제외하고는 특정 오류 처리 메커니즘을 정의하지 않습니다. 예를 들어, 웹 브라우저는 ABNF에 따라 구문 분석되지 않는 경우 Location 헤더 필드에서 투명하게 복구하려 할 수 있으나, 시스템 제어 클라이언트는 오류 복구의 어떤 형태도 위험하다고 간주할 수 있습니다.
2.6 프로토콜 버전 관리
HTTP는 프로토콜의 버전을 나타내기 위해 ‘major.minor’ 번호 스킴을 사용합니다. 이 명세서는 버전 “1.1”을 정의합니다. 프로토콜 버전은 해당 버전의 HTTP 명세서에 기술된 요구 사항 집합에 대한 발신자의 준수를 나타냅니다.
HTTP 메시지의 버전은 메시지의 첫 번째 줄에 있는 HTTP-version 필드로 나타냅니다. HTTP-version은 대소문자를 구분합니다.
HTTP-version = HTTP-name "/" DIGIT "." DIGIT
HTTP-name = %x48.54.54.50 ; "HTTP", 대소문자를 구분합니다.
HTTP 버전 번호는 “.” (점 또는 소수점)으로 구분된 두 개의 십진 숫자로 구성됩니다. 첫 번째 숫자(“주 버전”)는 HTTP 메시징 구문을 나타내며, 두 번째 숫자(“부 버전”)는 발신자가 준수하고 이해할 수 있는 주 버전 내에서의 가장 높은 부 버전을 나타냅니다. 부 버전은 발신자의 통신 능력을 알리며, 발신자가 프로토콜의 하위 호환성 부분 집합만 사용하는 경우에도 더 발전된 기능을 응답(서버에서)이나 미래의 요청(클라이언트에서)에서 사용할 수 있다는 것을 수신자에게 알려줍니다.
HTTP/1.1 메시지가 HTTP/1.0 수신자 [RFC1945] 또는 버전이 알려지지 않은 수신자에게 전송될 때, HTTP/1.1 메시지는 최신 기능을 무시하면 유효한 HTTP/1.0 메시지로 해석될 수 있도록 구성됩니다. 이 명세서는 수신자 버전에 대한 일부 새로운 기능의 요구 사항을 설정하여 준수하는 발신자가 HTTP/1.1을 지원하는 수신자를 확인하기 전까지 호환 가능한 기능만 사용하도록 합니다. 이는 구성 또는 메시지 수신을 통해 수신자가 HTTP/1.1을 지원하는 것을 확인하기 전까지입니다.
같은 주 버전의 부 버전 간에 헤더 필드의 해석은 변경되지 않지만, 해당 필드가 없을 때 수신자의 기본 동작은 변경될 수 있습니다. 특별히 명시되지 않은 경우, HTTP/1.1에서 정의된 헤더 필드는 모든 HTTP/1.x 버전에 대해 정의됩니다. 특히, Host 및 Connection 헤더 필드는 HTTP/1.1의 준수 여부와 관계없이 모든 HTTP/1.x 구현에서 구현되어야 합니다.
새로운 헤더 필드는 정의된 의미가 인식하지 못하는 수신자에게 안전하게 무시될 수 있도록 허용되는 경우에는 프로토콜 버전을 변경하지 않고도 도입될 수 있습니다. 헤더 필드의 확장성은 섹션 3.2.1에서 논의됩니다.
HTTP 메시지를 처리하는 중개자(즉, 터널로 동작하지 않는 모든 중개자)은 전달된 메시지에서 자체적인 HTTP-version을 보내야 합니다(“MUST”). 다시 말해, 중개자는 메시지의 첫 번째 줄을 맹목적으로 전달하는 것이 아니라, 해당 중개자가 수신 및 송신 메시지에 대해 준수하는 버전과 일치하는지 확인한 후에 메시지를 전달해야 합니다. HTTP-version을 재작성하지 않고 HTTP 메시지를 전달하는 것은, 하위 수신자가 메시지 전송자의 버전을 사용하여 이후 통신에 안전하게 사용할 수 있는 기능을 결정할 때 통신 오류가 발생할 수 있습니다.
[page 15] 클라이언트는 알고 있는 경우, 서버가 지원하는 가장 높은 버전보다 높지 않은 주 버전에 해당하고 클라이언트가 준수하는 가장 높은 버전과 동일한 요청 버전을 보내는 것이 좋습니다(“SHOULD”). 클라이언트는 자신이 준수하지 않는 버전을 보내서는 안 됩니다(“MUST NOT”).
클라이언트는 서버가 HTTP 사양을 잘못 구현하고 있음을 알고 있는 경우에만 정상적인 요청을 적어도 한 번 시도하고, 응답 상태 코드나 헤더 필드 (예: Server)에서 서버가 더 높은 요청 버전을 잘못 처리한다고 판단한 후에만 더 낮은 요청 버전을 보낼 수 있습니다(“MAY”).
서버는 요청으로 받은 주 버전보다 작거나 같은 주 버전을 준수하는 가장 높은 버전과 동일한 응답 버전을 보내는 것이 좋습니다(“SHOULD”). 서버는 자신이 준수하지 않는 버전을 보내서는 안 됩니다. 서버는 특정한 이유로 클라이언트의 주 프로토콜 버전의 서비스를 거부하고자 하는 경우 505 (HTTP Version Not Supported) 응답을 보낼 수 있습니다.
서버는 클라이언트가 HTTP 사양을 잘못 구현하고 후속 버전의 응답을 올바르게 처리할 수 없다고 의심되는 경우에만 요청에 HTTP/1.0 응답을 보낼 수 있습니다(“MAY”). 이는 클라이언트가 버전 번호를 올바르게 구문 분석하지 못하는 경우나 중개자가 프로토콜의 주 버전에 부합하지 않더라도 HTTP-version을 무조건 전달하는 경우 등이 있습니다. 이러한 프로토콜 다운그레이드는 특정 클라이언트 속성에 의해 트리거되지 않는 한 수행해서는 안 되며(“SHOULD NOT”, 예를 들어 요청 헤더 필드 (예: User-Agent) 중 하나 이상이 오류가 있는 클라이언트가 보낸 값과 일치하는 경우에만 수행되어야 합니다.
HTTP의 버전 설계의 의도는 호환되지 않는 메시지 구문이 도입될 때만 주 번호를 증가시키고, 프로토콜에 변경 사항이 추가되어 메시지 의미를 추가하거나 발신자의 추가 기능을 암시하는 경우에만 부 번호를 증가시키는 것입니다. 그러나 [RFC2068]과 [RFC2616] 사이에 도입된 변경 사항으로 인해 부 번호가 증가되지 않았으며, 이 개정판은 프로토콜에 어떠한 변경 사항도 포함하지 않도록 특별히 조치되었습니다.
수신자가 구현하는 주 번호와 일치하지만 수신자가 구현하는 부 번호보다 더 높은 부 번호를 가진 HTTP 메시지를 수신한 경우, 수신자는 수신자가 준수하는 해당 주 번호 내에서 가장 높은 부 번호로 메시지를 처리해야 합니다. 수신자는 아직 해당 높은 버전을 지원하지 않은 수신자에게 보내지만 충분히 하위 호환성이 있는 메시지를 안전하게 처리할 수 있는 것으로 가정할 수 있습니다. 이는 동일한 주 번호의 모든 구현에서 처리될 수 있다고 할 수 있습니다.
2.7. 통합 자원 식별자
[page 16] 통합 자원 식별자(Uniform Resource Identifiers, URIs) [RFC3986]는 HTTP에서 자원을 식별하는 수단으로 사용됩니다([RFC7231]의 2장). URI 참조는 요청을 대상으로 하거나 리디렉션을 나타내고 관계를 정의하는 데 사용됩니다.
“URI-reference(URI 참조)”, “absolute-URI(절대 URI)”, “relative-part(상대 경로)”, “scheme”, “authority(인증)”, “port(포트)”, “host(호스트)”, “path-abempty(빈 경로를 포함하는 경로)”, “segment(세그먼트)”, “query(쿼리)”, 그리고 “fragment”의 정의는 URI 일반 구문에서 채택되었습니다. 비어 있지 않은 경로 구성 요소를 포함할 수 있는 프로토콜 요소에 대해 “절대 경로” 규칙이 정의되었습니다. (이 규칙은 RFC 3986의 path-abempty 규칙과 약간 다르며, 참조에 빈 경로를 사용할 수 있게 허용하는 path-absolute 규칙과 “//”로 시작하는 경로를 허용하지 않는 path-absolute 규칙과 다릅니다.) 상대 URI를 포함할 수 있지만 프래그먼트 구성 요소를 포함할 수 없는 프로토콜 요소에 대해 “부분 URI” 규칙이 정의되었습니다.
URI-reference = <URI-reference, see [[RFC3986], Section 4.1](https://datatracker.ietf.org/doc/html/rfc3986#section-4.1)>
absolute-URI = <absolute-URI, see [[RFC3986], Section 4.3](https://datatracker.ietf.org/doc/html/rfc3986#section-4.3)>
relative-part = <relative-part, see [[RFC3986], Section 4.2](https://datatracker.ietf.org/doc/html/rfc3986#section-4.2)>
scheme = <scheme, see [[RFC3986], Section 3.1](https://datatracker.ietf.org/doc/html/rfc3986#section-3.1)>
authority = <authority, see [[RFC3986], Section 3.2](https://datatracker.ietf.org/doc/html/rfc3986#section-3.2)>
uri-host = <host, see [[RFC3986], Section 3.2.2](https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2)>
port = <port, see [[RFC3986], Section 3.2.3](https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.3)>
path-abempty = <path-abempty, see [[RFC3986], Section 3.3](https://datatracker.ietf.org/doc/html/rfc3986#section-3.3)>
segment = <segment, see [[RFC3986], Section 3.3](https://datatracker.ietf.org/doc/html/rfc3986#section-3.3)>
query = <query, see [[RFC3986], Section 3.4](https://datatracker.ietf.org/doc/html/rfc3986#section-3.4)>
fragment = <fragment, see [[RFC3986], Section 3.5](https://datatracker.ietf.org/doc/html/rfc3986#section-3.5)>
absolute-path = 1*( "/" segment )
partial-URI = relative-part [ "?" query ]
HTTP에서 URI 참조를 허용하는 각 프로토콜 요소는 해당 ABNF 표기법에서 요소가 어떤 형태의 참조를 허용하는지를 나타냅니다. 참조 형식(URI-reference), 절대 URI 형식 (absolute-URI), 경로와 선택적인 쿼리 구성 요소만 허용하는지 또는 이러한 요소들의 조합 중 어떤 것을 허용하는지를 나타냅니다. 그렇지 않은 한, URI 참조는 효과적인 요청 URI (Section 5.5)를 기준으로 상대적으로 구문 분석됩니다.
2.7 (1) http URI 스킴(scheme)
[page 17] “http” URI 스킴은 주어진 포트에서 TCP ([RFC0793]) 연결을 수신 대기하는 잠재적인 HTTP 오리진 서버와의 연관성에 따라 식별자를 생성하기 위해 여기에 정의됩니다.
http-URI = "http:" "//" authority path-abempty [ "?" query ]
[ "#" fragment ]
“HTTP” URI에 대한 오리진 서버는 authority 구성 요소에 의해 식별됩니다. 이는 호스트 식별자와 선택적인 TCP 포트([RFC3986], 섹션 3.2.2)를 포함합니다. 계층적인 경로 구성 요소와 선택적인 쿼리 구성 요소는 해당 오리진 서버의 네임스페이스 내에서 잠재적인 대상 리소스를 식별하는 데 사용됩니다. 선택적인 프래그먼트 구성 요소는 URI 스킴과 독립적인 보조 리소스의 간접적인 식별을 허용합니다. 이는 [RFC3986]의 섹션 3.5에서 정의되어 있습니다.
송신자는 빈 호스트 식별자를 가진 “http” URI를 생성해서는 안 됩니다. 이와 같은 URI 참조를 처리하는 수신자는 이를 잘못된 것으로 판단하여 거부해야 합니다(“MUST NOT”).
만약 호스트 식별자가 IP 주소로 제공된다면, 해당 IP 주소에서 지정된 TCP 포트에 대한 수신자(있을 경우)가 원 서버입니다. 호스트가 등록된 이름인 경우, 등록된 이름은 DNS와 같은 이름 해결 서비스와 함께 사용하기 위한 간접 식별자입니다. 만약 포트 하위 구성요소가 비어 있거나 주어지지 않은 경우, TCP 포트 80 (WWW 서비스를 위한 예약된 포트)가 기본값으로 사용됩니다.
주어진 권한 구성 요소를 가진 URI의 존재는 항상 해당 호스트와 포트에서 연결을 수신하는 HTTP 서버가 있는 것을 의미하지는 않습니다. 누구나 URI를 생성할 수 있습니다. 권한 구성 요소가 결정하는 것은 식별된 리소스를 대상으로 권위있게 응답할 권한을 가진 사람이 누구인지입니다. 등록된 이름과 IP 주소의 위임성은 HTTP 서버의 존재 유무와 상관없이 지정된 호스트와 포트에 대한 통제를 기반으로 한 연합된 네임스페이스를 생성합니다. 권한을 설정하는 데 관련된 보안 고려 사항에 대해서는 섹션 9.1을 참조하십시오.
“http” URI가 해당 리소스에 액세스할 필요가 있는 문맥에서 사용될 때, 클라이언트는 호스트를 IP 주소로 해석하고, 지정된 포트의 해당 주소에 TCP 연결을 설정하고, HTTP 요청 메시지 (섹션 3)를 서버로 보내는 것으로 액세스를 시도할 수 있습니다(“MAY”). 만약 서버가 그 요청에 대해 [RFC7231]의 섹션 6에 설명된대로 중간 응답이 아닌 HTTP 응답 메시지로 응답한다면, 그 응답은 클라이언트의 요청에 대한 권위있는 답변으로 간주됩니다.
[page 18] HTTP는 전송 프로토콜과 독립적이지만, “http” 스킴은 TCP 기반 서비스에 특화되어 있습니다. 이는 이름 위임 프로세스가 권한을 설정하기 위해 TCP에 의존하기 때문입니다. 다른 기반 연결 프로토콜을 사용하는 HTTP 서비스는 다른 URI 스킴을 사용하여 식별될 것으로 예상됩니다. 마찬가지로 “https” 스킴은 끝간 보안 연결이 필요한 리소스에 사용됩니다. 다른 프로토콜도 “http”로 식별된 리소스에 액세스를 제공하는 데 사용될 수 있지만, TCP에 대한 권한 인터페이스만이 특정되어 있습니다.
URI의 일반 구문인 authority에는 userinfo 하위 구성 요소도 포함되어 있습니다. userinfo는 URI에 사용자 인증 정보를 포함하는 데 사용되며 ([RFC3986], 섹션 3.2.1), 이는 사용자 식별자 또는 암호를 노출시킬 수 있는 경우가 있습니다. 일부 구현은 userinfo 구성 요소를 내부 인증 정보의 구성을 위해 사용할 수 있습니다. 이는 명령 호출 옵션, 구성 파일 또는 즐겨찾기 목록 내에서 사용될 수 있습니다. 그러나 이러한 사용은 사용자 식별자 또는 암호를 노출시킬 수 있습니다. “http” URI 참조가 요청 대상이나 헤더 필드 값으로 메시지 내에서 생성될 때, 보낸 사람은 userinfo 하위 구성 요소와 “@” 구분 기호를 생성해서는 안 됩니다. 신뢰할 수 없는 출처에서 수신한 “http” URI 참조를 사용하기 전에, 수신자는 userinfo를 구문 분석하고 존재 여부를 오류로 처리해야 합니다. 이는 피싱 공격을 위해 권한을 은닉하기 위해 사용되는 경우일 가능성이 있습니다.
2.7 (2) https URI 스킴(scheme)
“https” URI scheme은 TLS-보안 연결을 위해 지정된 TCP 포트에서 HTTP 원 서버를 수신 대기 중인 분산 네임스페이스와의 연관성을 기준으로 식별자를 생성하기 위해 정의됩니다 ([RFC5246]).
위에서 “http” scheme에 대해 나열된 요구 사항은 “https” scheme에 대해서도 동일하게 적용됩니다. 다만, 포트 하위 구성 요소가 비어 있거나 제공되지 않는 경우 TCP 포트 443이 기본값으로 사용되며, 사용자 에이전트는 첫 번째 HTTP 요청을 보내기 전에 강력한 암호화를 통해 원 서버와의 연결이 암호화되어 있는지 보장해야 합니다.
https-URI = "https:" "//" authority path-abempty [ "?" query ]
[ "#" fragment ]
“https” URI scheme은 권한을 설정하기 위해 TLS와 TCP 모두에 의존한다는 점에 주목해야 합니다. “https” scheme을 통해 제공되는 리소스는 리소스 식별자가 동일한 권한(동일한 호스트가 동일한 TCP 포트를 수신 대기 중인 경우)을 나타내더라도 “http” scheme과 공유된 식별자가 없습니다. 이들은 서로 다른 네임스페이스로 간주되며, 서로 다른 원 서버로 간주됩니다. 그러나 “Cookie protocol” [RFC6265]과 같이 전체 호스트 도메인에 적용되는 HTTP 확장 프로토콜은 한 서비스에서 설정한 정보가 해당 호스트 도메인의 다른 서비스와의 통신에 영향을 줄 수 있습니다.
“https” 식별된 리소스에 대한 권한 있는 액세스 과정은 [RFC2818]에 정의되어 있습니다.
**2.7 (3) http, 그리고 https URI 정규화와 비교
[page 19] “http” 및 “https” 스키마는 URI 일반 구문을 준수하므로 이러한 URI는 각 스키마에 대해 위에서 설명한 기본값을 사용하여 정규화되고 비교됩니다. 이를 위해 [RFC3986]의 6장에 정의된 알고리즘을 사용합니다.
만약 포트가 해당 스킴의 기본 포트와 동일한 경우, 일반적으로 포트 하위 구성요소를 생략하는 것이 정규 형식입니다. OPTIONS 요청의 요청 대상으로서 절대 형식으로 사용되지 않을 때, 빈 경로 구성요소는 “/”로 절대 경로와 동등하므로, 일반적으로 경로를 “/”로 제공하는 것이 정규 형식입니다. 스킴과 호스트는 대소문자를 구별하지 않으며, 일반적으로 소문자로 제공됩니다. 다른 모든 구성요소는 대소문자를 구별하여 비교됩니다. “예약”된 집합에 속하지 않는 문자는 해당하는 퍼센트 인코딩된 옥텟과 동일합니다. 즉, 일반적으로 인코딩하지 않는 것이 정규 형식입니다 ([RFC3986]의 2.1절과 2.2절을 참조하십시오).
예를 들어, 다음 세 개의 URI는 동등합니다:
[http://example.com:80/~smith/home.html](http://example.com/~smith/home.html)
[http://EXAMPLE.com/%7Esmith/home.html](http://example.com/~smith/home.html)
[http://EXAMPLE.com:/%7esmith/home.html](http://example.com/~smith/home.html)
3) Message Format
Introduction
모든 HTTP/1.1 메시지는 시작 줄(start-line)로 시작하며, 이어서 인터넷 메시지 형식 [RFC5322]과 유사한 형식의 옥텟 시퀀스가 따라옵니다. 이는 0개 혹은 더 많은 헤더 필드(헤더 또는 헤더 섹션으로 통칭됨)로 구성되며, 헤더 섹션의 끝을 나타내는 빈 줄이 있고, 선택적인 메시지 본문이 옵니다.
HTTP-메시지는 다음과 같은 구조를 갖습니다:
HTTP-메시지 = 시작-줄
(헤더-필드 CRLF)
CRLF
[메시지-본문]
(상세) 여기서:
시작-줄
은 메시지의 첫 줄로 구성되며, 요청 메시지인 경우 요청 라인(request line)이고, 응답 메시지인 경우 상태 라인(status line)입니다.헤더-필드
는 헤더 섹션의 각 필드를 나타내며, 이름과 값으로 구성됩니다.CRLF
는 캐리지 리턴(CR)과 개행 문자(LF)를 나타냅니다.메시지-본문
은 선택적으로 포함될 수 있는 메시지의 실제 내용입니다.- 아래는 예시입니다.
GET /example HTTP/1.1 (start-line)
Host: www.example.com (header field)
User-Agent: Mozilla/5.0
Accept-Language: en-US
Content-Length: 0
(CRLF)
[Message-body] (Message-body)
HTTP 메시지를 파싱하는 일반적인 절차는 다음과 같습니다:
start-line
을 구조체에 읽어들입니다.start-line
에는 HTTP 메소드, 요청 대상 (URI), 그리고 HTTP 버전과 같은 정보가 포함되어 있습니다.- 각각의
header field
를 읽어들여 필드 이름에 따라 해시 테이블 또는 딕셔너리와 같은 데이터 구조에 저장합니다. 각 header field는 콜론으로 구분된 필드 이름과 필드 값으로 구성됩니다. - 빈 줄이 나올 때까지 header field를 계속해서 읽습니다.
헤더 필드를 모두 읽은 후, 파싱된 데이터를 사용하여 메시지 본문이 예상되는지 여부를 판단합니다. 메시지 본문이 있는 경우, 메시지 본문 길이와 같은 개수의 옥텟이 읽힐 때까지 또는 연결이 닫힐 때까지 스트림으로 메시지 본문을 읽습니다.
[page 20] 수신자는 반드시 HTTP 메시지를 US-ASCII [USASCII]의 상위 집합으로 인코딩된 옥텟의 시퀀스로 파싱해야 합니다. 특정 인코딩을 고려하지 않고 유니코드 문자의 스트림으로 HTTP 메시지를 파싱하는 것은 보안 취약점을 초래할 수 있습니다. 이는 문자열 처리 라이브러리가 옥텟 LF (%x0A)를 포함하는 잘못된 다중바이트 문자 시퀀스를 처리하는 방식이 다양하기 때문입니다. 문자열 기반의 파서는 메시지에서 해당 요소가 추출된 후, 개별 필드를 구분한 메시지 파싱 이후에 헤더 필드 값과 같은 프로토콜 요소 내에서 안전하게 사용할 수 있습니다.
HTTP 메시지는 점진적인 처리나 하향으로의 전달을 위해 스트림으로 파싱될 수 있습니다. 그러나 수신자는 부분 메시지의 점진적인 전달에 의존할 수 없습니다. 왜냐하면 일부 구현은 네트워크 효율성, 보안 검사 또는 페이로드 변환을 위해 메시지 전달을 버퍼링하거나 지연시킬 수 있기 때문입니다.
송신자는 시작 줄과 첫 번째 헤더 필드 사이에 공백을 보내서는 안 됩니다(“MUST NOT”). 시작 줄과 첫 번째 헤더 필드 사이에 공백을 수신하는 수신자는 메시지를 잘못된 것으로 거부하거나 각 공백으로 시작하는 줄을 추가 처리하지 않고 사용해야 합니다(즉, 헤더 필드가 제대로 형식화되거나 헤더 섹션이 종료될 때까지 해당 줄과 공백으로 시작하는 임의의 후속 줄을 무시해야 함).
요청에서 이러한 공백이 존재하는 경우, 해당 필드를 무시하거나 그 후의 줄을 새로운 요청으로 처리하도록 서버를 속이려는 시도일 수 있습니다. 이는 요청 체인 내의 다른 구현이 동일한 메시지를 다르게 해석하는 경우 보안 취약점을 초래할 수 있습니다. 마찬가지로 응답에서 이러한 공백의 존재는 일부 클라이언트에서 무시되거나 다른 클라이언트에서 파싱을 중지시킬 수 있습니다.
3.1 Start Line
HTTP 메시지는 클라이언트에서 서버로의 요청이나 서버에서 클라이언트로의 응답일 수 있습니다. 구문적으로, 이 두 유형의 메시지는 시작 라인만 다르며, 요청일 경우에는 request-line이고 응답일 경우에는 status-line입니다. 또한 메시지 본문의 길이를 결정하는 알고리즘도 다릅니다 (3.3절).
이론적으로 클라이언트는 요청을 수신하고 서버는 응답을 수신할 수 있으며, 이들은 서로 다른 시작 라인 형식으로 구분될 수 있습니다. 그러나 실제로는 서버는 요청만 예상하도록 구현되어 있으며 (응답은 알 수 없거나 잘못된 요청 방법으로 해석됨), 클라이언트는 응답만 예상하도록 구현됩니다.
start-line = request-line / status-line
3.1 (1) Request Line
[page 21] 요청 라인은 메소드 토큰으로 시작하며, 그 뒤에는 단일 공백(Space, SP), 요청 대상(request-target), 다시 단일 공백(Space, SP), 프로토콜 버전, 그리고 CRLF(Carriage Return Line Feed)이 따릅니다.
- request-line = method SP request-target SP HTTP-version CRLF
메소드 토큰은 대상 리소스에 대해 수행할 요청 메소드를 나타냅니다. 요청 메소드는 대소문자를 구분합니다.
- method = token
이 사양에서 정의된 요청 메소드는 [RFC7231]의 섹션 4에 찾을 수 있으며, HTTP 메소드 레지스트리와 새로운 메소드를 정의하는 데 대한 고려 사항에 대한 정보도 해당 섹션에 포함되어 있습니다.
요청 대상은 요청을 적용할 대상 리소스를 식별합니다. 이에 대한 정의는 섹션 5.3에 설명되 어 있습니다.
수신자는 일반적으로 요청 라인을 구성 요소로 분할하기 위해 공백을 기준으로 분리합니다(섹션 3.5 참조). 각 구성 요소에는 공백이 허용되지 않기 때문입니다. 하지만, 일부 사용자 에이전트는 하이퍼텍스트 참조에서 발견된 공백을 올바르게 인코딩하거나 제외하지 못하여, 이러한 금지된 문자가 요청 대상으로 전송되는 경우가 있습니다.
유효하지 않은 요청 라인을 수신한 경우, 수신자는 400 (잘못된 요청) 오류 또는 301 (영구적으로 이동함) 리디렉션 중 하나로 응답해야 합니다. 응답할 때는 요청 대상을 올바르게 인코딩해야 합니다. 수신자는 리디렉션 없이 요청을 자동으로 수정하고 처리하려고 시도해서는 안 됩니다. 왜냐하면, 유효하지 않은 요청 라인은 요청 체인을 통해 보안 필터를 우회하기 위해 고의적으로 조작된 것일 수 있기 때문입니다.
HTTP는 요청 라인의 길이에 미리 정의된 제한을 두지 않습니다(Section 2.5 참조). 서버가 구현한 어떤 메서드보다 긴 메서드를 받은 경우, 501 (구현되지 않음) 상태 코드로 응답해야 합니다. 서버가 구문 분석하려는 URI보다 긴 요청 대상을 받은 경우, 414 (URI가 너무 긺) 상태 코드로 응답해야 합니다 ([RFC7231의 섹션 6.5.12 참조]).
실제로는 요청 라인 길이에 대한 다양한 임시 제한이 존재합니다. HTTP 송신자 및 수신자는 최소한 8000옥텟의 요청 라인 길이를 지원하는 것이 권장됩니다.
3.1 (2) Status Line
[page 22] 응답 메시지의 첫 번째 줄은 상태줄(status-line)로 구성되며, 프로토콜 버전, 공백(SP), 상태 코드, 다른 공백, 상태 코드를 설명하는 비어 있을 수도 있는 텍스트 구문, 그리고 CRLF로 끝납니다.
- status-line = HTTP-version SP "status-code" SP "reason-phrase" CRLF
status-code 요소는 서버가 클라이언트의 해당 요청을 이해하고 처리한 결과를 나타내는 3자리 정수 코드입니다. 응답 메시지의 나머지는 해당 상태 코드에 대해 정의된 의미에 따라 해석되어야 합니다. 상태 코드의 의미, 상태 코드의 클래스(첫 번째 숫자로 표시됨), 이 사양에서 정의된 상태 코드, 새로운 상태 코드를 정의하는 데 고려해야 할 사항 및 IANA 레지스트리에 대한 정보는 [RFC7231]의 섹션 6을 참조하십시오.
- status code = 3DIGIT
reason-phrase 요소는 숫자 상태 코드와 관련된 텍스트 설명을 제공하는 유일한 목적으로 존재합니다. 이는 이전에 대화형 텍스트 클라이언트와 더 자주 사용되는 인터넷 응용 프로토콜을 고려하여 제공됩니다. 클라이언트는 reason-phrase 콘텐츠를 무시해야 합니다.
- reason-phrase = * (HTAB / SP / VCHAR / obs-text)
3.2 Header Fields
각 헤더 필드는 대소문자를 구분하지 않는 필드 이름으로 시작하여 콜론 (“:”), 선택적인 선행 공백, 필드 값 및 선택적인 후행 공백으로 구성됩니다.
header-field = field-name ":" OWS field-value OWS
field-name = token
field-value = * (field-content / obs-fold)
field-content = field-vchar [1_(SP / HTAB) field-vchar]
field-vchar = VCHAR / obs-text
obs-fold = CRLF 1* (SP / HTAB)
; 구식 줄 접기 ;
섹션 3.2.4를 참조하세요.
field-name 토큰은 해당 필드 값이 해당 헤더 필드에서 정의된 의미를 가진다는 것을 나타냅니다. 예를 들어, Date 헤더 필드는 [RFC7231]의 7.1.1.2 섹션에서 해당 메시지에 대한 발생 시간 정보를 포함한다고 정의되어 있습니다.
3.2 (1) Field Extensibility
[page 23] 헤더 필드는 완전히 확장 가능합니다. 새로운 필드 이름의 도입에는 제한이 없으며, 각각은 새로운 의미를 정의할 것으로 예상됩니다. 또한, 특정 메시지에서 사용되는 헤더 필드의 수에도 제한이 없습니다. 기존 필드는 이 사양의 각 부분과 이 문서 세트 외의 많은 다른 사양에서도 정의되어 있습니다.
새로운 헤더 필드는 수신자가 이해하는 경우 이전에 정의된 헤더 필드의 해석을 무효화하거나 개선할 수 있으며, 요청 평가에 사전 조건을 정의하거나 응답의 의미를 더욱 명확하게 할 수 있습니다.
프록시는 Connection 헤더 필드 (섹션 6.1)에 나열된 field-name이 아닌 인식되지 않은 헤더 필드를 전달해야 합니다. 프록시는 특별히 이러한 필드를 차단하거나 변형하기 위해 구성되어 있어야 합니다. 다른 수신자는 인식되지 않은 헤더 필드를 무시해야 합니다. 이러한 요구 사항은 HTTP의 기능을 배포된 중개 서버를 미리 업데이트하지 않고도 향상시킬 수 있도록 합니다.
모든 정의된 헤더 필드는 “Message Headers” 레지스트리에 IANA에 등록되어야 합니다. 이에 대한 자세한 내용은 [RFC7231]의 섹션 8.3을 참조하십시오.
프록시는 필드 이름이 연결 헤더 필드에 나열되어 있거나, 프록시가 해당 필드를 차단하거나 다른 방식으로 변환하도록 특별히 구성되지 않은 한 인식할 수 없는 헤더 필드를 전달해야 합니다. 다른 수신자는 인식할 수 없는 헤더 필드를 무시해야 합니다(“SHOULD”). 이러한 요구 사항을 통해 배포된 중개자를 사전에 업데이트할 필요 없이 HTTP의 기능을 향상시킬 수 있습니다.
모든 정의된 헤더 필드는 “Message Headers” 레지스트리에 IANA에 등록되어야 합니다. 이에 대한 자세한 내용은 [RFC7231]의 섹션 8.3을 참조하십시오.
3.2 (2) Field Order
서로 다른 필드 이름을 가진 헤더 필드의 순서는 중요하지 않습니다. 그러나 Host(요청)와 Date(응답)와 같은 제어 데이터를 포함하는 헤더 필드를 가능한 빨리 보내는 것이 좋은 방법입니다. 이렇게 함으로써 구현체는 메시지를 더 이상 처리하지 않아도 되는 시점을 가능한 빠르게 결정할 수 있습니다. 서버는 전체 요청 헤더 섹션이 수신될 때까지 대상 리소스에 요청을 적용해서는 안 됩니다(“MUST NOT”). 이는 나중에 오는 헤더 필드에 조건절, 인증 자격 증명 또는 의도적으로 잘못된 중복 헤더 필드가 포함될 수 있기 때문에 요청 처리에 영향을 줄 수 있기 때문입니다.
[page 24] 메시지에서 발신자는 헤더 필드의 전체 필드 값이 쉼표로 구분된 목록으로 정의되었거나 헤더 필드가 잘 알려진 예외인 경우를 제외하고는 동일한 필드 이름으로 여러 헤더 필드를 생성해서는 안 됩니다(“MUST NOT”).
수신자는 동일한 필드 이름을 가진 여러 헤더 필드를 하나의 “field-name: field-value” 쌍으로 결합하여 메시지의 의미를 변경하지 않고, 각 후속 필드 값을 쉼표로 구분하여 결합된 필드 값에 추가할 수 있습니다. 따라서 동일한 필드 이름을 가진 헤더 필드가 수신되는 순서는 결합된 필드 값의 해석에 중요합니다. 프록시는 메시지를 전달할 때 이러한 필드 값의 순서를 변경해서는 안 됩니다.
참고: 실제로 응답 메시지에서는 “Set-Cookie” 헤더 필드([RFC6265])가 여러 번 나타나며 목록 구문을 사용하지 않으므로 동일한 이름을 가진 여러 헤더 필드에 대한 위의 요구 사항을 위반합니다. 단일 필드 값으로 결합할 수 없기 때문에 수신자는 헤더 필드를 처리하는 동안 “Set-Cookie”를 특별한 경우로 처리해야 합니다. (자세한 내용은 [Kri2001]의 부록 A.2.3을 참조하십시오.)
3.2 (3) Whitespace
이 사양에서는 선형 공백 사용을 나타내는 세 가지 규칙을 사용합니다: OWS (선택적 공백), RWS (필수 공백) 및 BWS (“나쁜” 공백).
OWS 규칙은 선형 공백 옥텟이 나타날 수 있는 경우에 사용됩니다. 가독성을 향상시키기 위해 선택적인 공백이 선호되는 프로토콜 요소에서는 송신자는 선택적 공백을 하나의 SP로 생성해야 합니다(“SHOULD”). 그 외의 경우에는 송신자는 잘못된 또는 원하지 않는 프로토콜 요소를 희석시키기 위해 필요한 경우를 제외하고 선택적 공백을 생성하지 않아야 합니다(“SHOULD NOT”).
RWS 규칙은 적어도 하나의 선형 공백 옥텟이 필요한 필드 토큰을 구분하는 데 사용됩니다. 송신자는 RWS를 하나의 SP로 생성해야 합니다(“SHOULD”).
BWS 규칙은 문법적(historical) 으로 선택적 공백이 허용되는 경우에만 사용됩니다. 발신자는 메시지에서 BWS를 생성해서는 안 됩니다(“MUST NOT”). 수신자는 이러한 잘못된 공백을 구문 분석하고 프로토콜 요소를 해석하기 전에 제거해야 합니다.
OWS = * ( SP / HTAB )
; optional whitespace
RWS = 1*( SP / HTAB )
; required whitespace
BWS = OWS
; "bad" whitespace
3.2 (4) Field Parsing
[page 25] 메시지는 개별 헤더 필드 이름과 독립적인 일반 알고리즘을 사용하여 구문 분석됩니다. 주어진 필드 값 내용은 메시지 해석의 나중 단계에서 (일반적으로 메시지의 전체 헤더 섹션이 처리된 후) 구문 분석됩니다. 따라서 이 사양은 이전 버전에서 “Field-Name: Field Value” 쌍을 정의하는 데 ABNF 규칙을 사용하지 않습니다. 대신, 이 사양은 각 등록된 필드 이름에 따라 이름이 지정된 ABNF 규칙을 사용합니다. 여기서 규칙은 해당 필드의 해당 필드 값에 대한 유효한 문법을 정의합니다 (즉, 일반 필드 구문 분석기에 의해 헤더 섹션에서 필드 값이 추출된 후).
헤더 필드 이름과 콜론 사이에는 공백이 허용되지 않습니다. 이전에 이러한 공백 처리의 차이로 인해 요청 라우팅 및 응답 처리에서 보안 취약점이 발생한 적이 있습니다. 서버는 헤더 필드 이름과 콜론 사이에 공백이 있는 요청 메시지를 수신하면 400 (Bad Request) 응답 코드로 해당 요청을 거부해야 합니다. 프록시는 메시지를 하향으로 전달하기 전에 응답 메시지에서 이러한 공백을 제거해야 합니다.
필드 값은 선택적인 공백 (OWS)로 선행되거나 후행될 수 있습니다. 필드 값 앞에 단일 SP가 있는 것이 가독성을 위해 일관성 있게 선호됩니다. 필드 값에는 선행 또는 후행하는 공백이 포함되지 않습니다. 필드 값의 첫 번째 비공백 옥텟 이전이나 마지막 비공백 옥텟 이후에 발생하는 OWS는 헤더 필드에서 필드 값을 추출할 때 파서에 의해 제외되어야 합니다.
과거에는 HTTP 헤더 필드 값은 각 추가 라인을 적어도 하나의 공백이나 수평 탭 (obs-fold)으로 선행하여 여러 줄로 확장할 수 있었습니다. 이 사양에서는 메시지/http 미디어 유형 (섹션 8.3.1) 내에서만 이러한 라인 접기를 사용하지 않도록 지정합니다. 발신자는 메시지가 메시지/http 미디어 유형 내에서 패키징되도록 의도되지 않는 한 라인 접기를 포함하는 메시지를 생성해서는 안 됩니다(“MUST NOT”) (즉, 어떤 필드 값이 obs-fold 규칙과 일치하는 것을 포함하는 메시지).
[page 26] obs-fold 형식의 요청 메시지를 받은 서버는 메시지/http 컨테이너 내에 없는 경우 해당 메시지를 400 (Bad Request) 상태 코드와 함께 거부해야 합니다. 가능하다면 구식의 라인 접기가 허용되지 않음을 설명하는 표현을 함께 보내야 합니다. 또는 obs-fold를 수신한 각 부분을 필드 값 해석이나 다운스트림으로 메시지를 전달하기 전에 하나 이상의 SP 옥텟으로 대체해야 합니다.
메시지/http 컨테이너 내에 없는 obs-fold 형식의 응답 메시지를 받은 유저 에이전트는 각 수신한 obs-fold를 필드 값을 해석하기 전에 하나 이상의 SP 옥텟으로 대체해야 합니다.
과거에는 HTTP가 ISO-8859-1 문자셋 [ISO-8859-1]의 텍스트가 포함된 필드 콘텐츠를 허용했으며, 다른 문자셋은 [RFC2047] 인코딩을 통해만 지원했습니다. 실제로 대부분의 HTTP 헤더 필드 값은 US-ASCII 문자셋 [USASCII]의 하위 집합만을 사용합니다. 새로 정의된 헤더 필드는 필드 값이 US-ASCII 옥텟으로 제한되도록 해야 합니다. 수신자는 필드 콘텐츠 (obs-text)의 다른 옥텟을 불투명 데이터로 처리해야 합니다.
3.2 (5) Field Limits
HTTP는 각 헤더 필드 또는 헤더 섹션 전체의 길이에 대해 미리 정의된 제한을 두지 않지만,(2.5절 참조). 실제로는 각각의 헤더 필드 길이에 대해 다양한 임시 제한이 있으며, 이는 특정 필드 의미에 따라 종종 달라집니다.
서버가 처리하길 원하는 것보다 큰 요청 헤더 필드 또는 필드 집합을 수신한 경우, 적절한 4xx (클라이언트 오류) 상태 코드로 응답해야 합니다. 이러한 헤더 필드를 무시하면 요청 스머글링 공격에 대한 서버의 취약성이 증가할 수 있습니다(9.5절 참조).
클라이언트는 헤더 필드의 의미가 메시지 프레이밍이나 응답 의미론을 변경하지 않고 안전하게 무시할 수 있는 경우, 수신한 헤더 필드가 처리를 원하는 크기보다 큰 경우 해당 필드 값을 삭제하거나 잘라낼 수 있습니다.
3.2 (6) Field Value Components
[page 27] 대부분의 HTTP 헤더 필드 값은 공백이나 특정 구분 문자로 구분된 일반 구문 구성 요소 (토큰, quoted-string 및 주석)를 사용하여 정의됩니다. 구분자는 토큰에서 허용되지 않는 US-ASCII 시각적 문자 집합에서 선택됩니다 (DQUOTE 및 “(),/:;<=>?@[]{}”).
- token = 1 * tchar
- tchar = "!" / "#" / "$" / "%" / "&" / "'" / " * "
/ "+" / "-" / "." / "^" / " _ " / "`"
/ "|" / "~"
/ DIGIT / ALPHA
; 구분자를 제외하는 모든 Vchar
만약 문자열이 이중 인용부호 (double-quote marks)로 묶여있는 경우, 해당 문자열은 단일 값으로 구문 분석됩니다.
quoted-string = DQUOTE * ( qdtext / quoted-pair ) DQUOTE
qdtext = HTAB / SP /%x21 / %x23-5B / %x5D-7E / obs-text
obs-text = %x80-FF
주석은 괄호로 둘러싸인 텍스트로 몇 가지 HTTP 헤더 필드에 포함될 수 있습니다. 주석은 “comment”를 필드 값 정의의 일부로 포함하는 필드에만 허용됩니다.
- comment = "(" * ( ctext / quoted-pair / comment ) ")"
- ctext = HTAB / SP / %x21-27 / %x2A-5B / %x5D-7E / obs-text
quoted-string 및 comment 구조 내에서 백슬래시 옥텟 (““)는 단일 옥텟 이스케이핑 메커니즘으로 사용될 수 있습니다. quoted-string의 값 처리를 수신자는 quoted-pair를 백슬래시 다음의 옥텟으로 대체한 것으로 처리해야 합니다.
- quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
quoted-string 내에서는 DQUOTE와 백슬래시 옥텟을 인용해야 하는 경우를 제외하고는 quoted-pair를 생성하지 말아야 합니다(“SHOULD NOT”). 마찬가지로, comment 내에서는 괄호 (“(“와 “)”)와 백슬래시 옥텟을 인용해야 하는 경우를 제외하고는 quoted-pair를 생성하지 말아야 합니다(“SHOULD NOT”).
3.3 Message Body
[page 28] HTTP 메시지의 메시지 본문(있는 경우)은 해당 요청 또는 응답의 페이로드 본문을 전달하는 데 사용됩니다. 메시지 본문은 전송 코딩이 적용되지 않은 경우 페이로드 본문과 동일합니다. 이에 대한 설명은 섹션 3.3.1에서 제공됩니다.
- message-body = * OCTET
요청과 응답에 대해 메시지 본문이 허용되는 경우의 규칙은 다릅니다.
요청에서 메시지 본문의 존재는 Content-Length 또는 Transfer-Encoding 헤더 필드에 의해 신호화됩니다. 요청 메시지의 프레이밍은 메서드 의미론과 독립적입니다. 즉, 메서드가 메시지 본문에 대한 사용을 정의하지 않더라도 메시지 본문이 존재할 수 있습니다.
응답에서 메시지 본문의 존재는 응답하는 요청 메서드와 응답 상태 코드에 따라 달라집니다. HEAD 요청 메서드에 대한 응답 (RFC7231의 섹션 4.3.2)은 항상 메시지 본문을 포함하지 않습니다. 왜냐하면 연관된 응답 헤더 필드 (예: Transfer-Encoding, Content-Length 등)가 있더라도 해당 값은 요청 메서드가 GET이었을 때의 값만 나타내기 때문입니다 (RFC7231의 섹션 4.3.1). CONNECT 요청 메서드에 대한 2xx (성공) 응답 (RFC7231의 섹션 4.3.6)은 메시지 본문 대신 터널 모드로 전환됩니다. 1xx (정보), 204 (콘텐츠 없음) 및 304 (수정되지 않음) 응답은 메시지 본문을 포함하지 않습니다. 다른 모든 응답은 메시지 본문을 포함하지만 본문의 길이가 0일 수도 있습니다.
3.3 (1) Transfer-Encoding
Transfer-Encoding 헤더 필드는 페이로드 본문에 적용된(또는 적용될) 전송 코딩의 순서에 해당하는 전송 코딩 이름을 나열합니다. 이를 통해 메시지 본문이 형성됩니다. 전송 코딩은 섹션 4에서 정의됩니다.
- Transfer-Encoding = 1#transfer-coding
Transfer-Encoding 헤더 필드는 MIME의 Content-Transfer-Encoding 필드와 유사합니다. Content-Transfer-Encoding은 7비트 전송 서비스를 통해 이진 데이터를 안전하게 전송하기 위해 설계되었습니다([RFC2045], 섹션 6). 그러나 8비트 클린 전송 프로토콜의 경우 안전한 전송은 다른 측면을 갖습니다. HTTP의 경우, Transfer-Encoding은 주로 동적으로 생성된 페이로드를 정확하게 구분하고, 전송 효율성이나 보안을 위해 적용되는 페이로드 인코딩을 선택한 리소스의 특성과 구별하기 위해 사용됩니다.
[page 29] 수신자는 페이로드 바디의 크기를 미리 알 수 없는 경우 메시지를 프레임화하는 중요한 역할을 하는 청크드 전송 코딩(chunked transfer coding, 섹션 4.1)을 구문 분석할 수 있어야 합니다(“MUST”). 발신자는 메시지 바디에 청크드 전송 코딩을 여러 번 적용해서는 안 됩니다(MUST NOT, 이미 청크드된 메시지에 청크드를 적용하는 것은 허용되지 않습니다). 요청 페이로드 바디에 청크드 이외의 전송 코딩이 적용된 경우, 발신자는 메시지가 올바르게 프레임화되도록 최종 전송 코딩으로 청크드를 적용해야 합니다(“MUST”). 응답 페이로드 바디에 청크드 이외의 전송 코딩이 적용된 경우, 발신자는 최종 전송 코딩으로 청크드를 적용하거나 연결을 닫아 메시지를 종료해야 합니다.
예를 들어 - Transfer-Encoding: gzip, chunked
는 페이로드 바디가 gzip 코딩을 사용하여 압축되고, 메시지 바디를 형성하는 동안 청크드 코딩을 사용하여 청크드되었음을 나타냅니다.
Content-Encoding (RFC7231의 섹션 3.1.2.1)과 달리 Transfer-Encoding은 표현이 아닌 메시지의 속성이며, 요청/응답 체인을 따라서 수신자는 전송 코딩을 해독하거나 메시지 바디에 추가 전송 코딩을 적용할 수 있습니다. 이 경우, Transfer-Encoding 필드값이 해당 변경 사항과 일치하도록 해야 합니다. 인코딩 매개변수에 대한 추가 정보는 이 사양에서 정의되지 않은 다른 헤더 필드로 제공될 수 있습니다.
Transfer-Encoding은 HEAD 요청이나 GET 요청에 대한 304 (Not Modified) 응답에도 전송될 수 있습니다(“MAY”). 이 경우 응답에는 메시지 본문이 포함되지 않지만, 만약 요청이 조건 없는 GET 요청이었다면 원 서버가 메시지 본문에 전송 인코딩을 적용했을 것을 나타내기 위해 사용될 수 있습니다. 그러나 이 표시는 필수적이지 않습니다. 응답 체인 상의 수신자(원 서버를 포함하여)는 전송 인코딩이 필요하지 않을 때 전송 인코딩을 제거할 수 있습니다.
서버는 상태 코드가 1xx (정보), 204 (내용 없음)인 응답에 Transfer-Encoding 헤더 필드를 보내서는 안 됩니다(“MUST NOT”). 또한, 서버는 CONNECT 요청 (RFC7231의 섹션 4.3.6)에 대한 2xx (성공) 응답에 Transfer-Encoding 헤더 필드를 보내서는 안 됩니다.
Transfer-Encoding은 HTTP/1.1에서 추가되었습니다. 일반적으로 HTTP/1.0 지원만을 알리는 구현에서는 전송 인코딩된 페이로드를 처리하는 방법을 이해하지 못할 것으로 가정됩니다. 클라이언트는 Transfer-Encoding을 포함한 요청을 보내기 전에 서버가 HTTP/1.1 (또는 그 이상) 요청을 처리할 수 있는지 알지 못하는 한 보내서는 안 됩니다(“MUST NOT”). 이러한 알림은 특정 사용자 설정이나 이전 수신된 응답의 버전을 기억하는 형태로 나타날 수 있습니다. 서버는 해당 요청이 HTTP/1.1 (또는 그 이상)을 나타낼 때만 Transfer-Encoding을 포함한 응답을 보내서는 안 됩니다(“MUST NOT”).
Transfer-Encoding는 HTTP/1.1에서 추가되었습니다. 일반적으로 HTTP/1.0만 지원하는 구현에서는 전송 인코딩된 페이로드를 처리하는 방법을 이해하지 못할 것으로 가정됩니다. 클라이언트는 서버가 HTTP/1.1 (또는 이후 버전) 요청을 처리할 수 있을 때만 Transfer-Encoding을 포함하는 요청을 보내야 합니다(“MUST NOT”). 이러한 정보는 특정 사용자 설정이나 이전에 받은 응답의 버전을 기억함으로써 얻을 수 있습니다. 서버는 해당 요청이 HTTP/1.1 (또는 이후 버전)을 지시하지 않는 한 Transfer-Encoding을 포함하는 응답을 보내서는 안 됩니다(“MUST NOT”).
Transfer-Encoding을 이해하지 못하는 서버는 전송 코딩이 포함된 요청 메시지를 받으면 501 (구현되지 않음)으로 응답해야 합니다. (“SHOULD”)
3.3 (2) Content-Length
[page 30] Transfer-Encoding 헤더 필드가 없는 메시지의 경우, Content-Length 헤더 필드는 잠재적인 페이로드 본문의 예상 크기를 8진수로 나타낸 바이트 단위로 제공할 수 있습니다. 페이로드 본문을 포함하는 메시지의 경우, Content-Length 필드 값은 본문(및 메시지)의 끝을 결정하는 데 필요한 프레이밍 정보를 제공합니다. 페이로드 본문을 포함하지 않는 메시지의 경우, Content-Length는 선택된 표현의 크기를 나타냅니다 ([RFC7231]의 섹션 3).
Content-Length = 1 * DIGIT
예시:
Content-Length: 3495
Transfer-Encoding 헤더 필드가 포함된 메시지에는 발신자는 Content-Length 헤더 필드를 전송해서는 안 됩니다. (“MUST NOT”)
유저 에이전트는 Transfer-Encoding이 전송되지 않고 요청 메소드가 포함된 페이로드 본문의 의미를 정의할 때, 요청 메시지에 Content-Length를 보내는 것이 좋습니다(“SHOULD”). 예를 들어, 0 값을 가지는 Content-Length 헤더 필드는 일반적으로 POST 요청에서도 보내집니다(빈 페이로드 본문을 나타냄). 사용자 에이전트는 요청 메시지에 페이로드 본문이 없고 메소드 의미론이 해당 본문을 예상하지 않을 경우 Content-Length 헤더 필드를 보내지 않아야 합니다. (“SHOULD NOT”)
서버는 HEAD 요청에 대한 응답에서 Content-Length 헤더 필드를 보낼 수 있습니다(“MAY”) ([RFC7231]의 섹션 4.3.2). 그러나, 해당 응답에서 Content-Length를 보내기 위해서는, GET 메소드를 사용한 동일한 요청에 대한 응답의 페이로드 본문으로 보냈을 때의 8진수로 나타낸 바이트 개수와 동일한 필드값을 가져야 합니다. 이와 같은 조건이 충족되지 않으면 서버는 해당 응답에서 Content-Length를 보내서는 안 됩니다 (“MUST NOT”).
서버는 조건부 GET 요청에 대한 304 (변경되지 않음) 응답에서 Content-Length 헤더 필드를 보낼 수 있습니다 (“MAY”) ([RFC7232]의 섹션 4.1). 그러나, 해당 응답에서 Content-Length를 보내기 위해서는, 동일한 요청에 대한 200 (OK) 응답의 페이로드 본문으로 보냈을 때의 8진수로 나타낸 바이트 개수와 동일한 필드값을 가져야 합니다. 이와 같은 조건이 충족되지 않으면 서버는 해당 응답에서 Content-Length를 보내서는 안 됩니다 (“MUST NOT”).
[page 31] 서버는 상태 코드가 1xx (정보성 응답) 또는 204 (컨텐츠 없음)인 응답에는 Content-Length 헤더 필드를 전송해서는 안 됩니다 (“MUST NOT”). 또한, 서버는 CONNECT 요청에 대한 2xx (성공적인) 응답에도 Content-Length 헤더 필드를 전송해서는 안 됩니다 (“MUST NOT”) ([RFC7231]의 섹션 4.3.6).
앞에서 정의된 경우를 제외하고, Transfer-Encoding이 없는 경우, 원 서버는 헤더 섹션을 완전히 보내기 전에 페이로드 본문의 크기가 알려진 경우 Content-Length 헤더 필드를 보내는 것이 좋습니다 (“SHOULD”). 이를 통해 하향 스트림 수신자는 전송 진행 상황을 측정하고, 수신된 메시지가 완전히 도착했는지 알 수 있으며, 추가 요청에 대해 연결을 재사용할 수도 있습니다.
Content-Length 필드 값은 0 이상인 어떤 값이든 유효합니다. 페이로드의 길이에는 미리 정의된 제한이 없으므로, 수신자는 잠재적으로 큰 10진수 숫자를 예상하고, 정수 변환 오버플로우로 인한 구문 분석 오류를 방지해야 합니다 (“MUST”) (섹션 9.3).**
만약 동일한 10진수 값으로 구성된 여러 개의 Content-Length 헤더 필드 또는 동일한 10진수 값의 목록을 포함하는 단일 Content-Length 헤더 필드 (예: “Content-Length: 42, 42”)가 있는 메시지를 수신하면, 이는 중복된 Content-Length 헤더 필드가 상위 메시지 프로세서에 의해 생성되거나 결합된 것을 나타냅니다. 수신자는 메시지를 잘못된 것으로 거부하거나 중복된 필드 값을 해당 10진수 값으로 대체하여 메시지 본문의 길이를 결정하거나 메시지를 전달하기 전에 유효한 단일 Content-Length 필드로 대체해야 합니다 (“MUST”).
참고: HTTP에서 메시지 프레임에 Content-Length을 사용하는 방법은 MIME에서 동일한 필드의 사용과 크게 다릅니다. MIME에서는 Content-Length이 “message/external-body” 미디어 유형 내에서만 사용되는 선택적인 필드입니다.
3.3 (3) Message Body Length
메시지 본문의 길이는 다음 중 하나에 의해 결정됩니다 (우선순위 순서대로):
1. [page 32] HEAD 요청에 대한 응답 및 1xx (정보성), 204 (컨텐츠 없음), 304 (수정되지 않음) 상태 코드를 가진 응답은
항상 헤더 필드 이후 첫 번째 빈 줄로 종료되며, 메시지에 존재하는 헤더 필드와 관계없이 메시지 본문을 포함할 수 없습니다.
2. CONNECT 요청에 대한 2xx (성공적인) 응답은 헤더 필드를 마치는 빈 줄 이후에 연결이 즉시 터널이 되는 것을 의미합니다.
클라이언트는 이러한 메시지에서 받은 Content-Length 또는 Transfer-Encoding 헤더 필드를 무시해야 합니다(**"MUST"**).
3. Transfer-Encoding 헤더 필드가 존재하고 청크 전송 코딩 (섹션 4.1)이 최종 인코딩인 경우, 메시지 본문의 길이는 데이터가
완전히 전달되었다는 것이 나타날 때까지 청크드 데이터를 읽고 해독하는 것으로 결정됩니다.
응답에 Transfer-Encoding 헤더 필드가 존재하고 청크 전송 코딩이 최종 인코딩이 아닌 경우, 메시지 본문의 길이는 서버가 연결을 닫을 때까지 연결을 읽어서 결정됩니다. 요청에 Transfer-Encoding 헤더 필드가 존재하고 청크 전송 코딩이 최종 인코딩이 아닌 경우, 메시지 본문의 길이를 신뢰할 수 없습니다. 서버는 400 (잘못된 요청) 상태 코드로 응답하고 연결을 닫아야 합니다(“MUST”).
Transfer-Encoding과 Content-Length 헤더 필드가 모두 있는 메시지를 받으면, Transfer-Encoding이 Content-Length를 무시합니다. 이러한 메시지는 요청 스마글링 (섹션 9.5) 또는 응답 분할 (섹션 9.4)을 시도하는 것을 나타낼 수 있으며 오류로 처리되어야 합니다. 송신자는 이러한 메시지를 하향으로 전달하기 전에 수신한 Content-Length 필드를 제거해야 합니다.
4. 만약 Transfer-Encoding이 없는 메시지를 받고, 서로 다른 필드값을 가지는 여러 개의 Content-Length 헤더 필드 또는
잘못된 값을 가지는 단일 Content-Length 헤더 필드가 있는 경우, 메시지의 프레임이 잘못되었으며 수신자는 이를 복구할 수 없는
오류로 처리해야 합니다. 이것이 요청 메시지인 경우, 서버는 400 (잘못된 요청) 상태 코드로 응답한 다음 연결을 닫아야 합니다
(**"MUST"**). 이것이 프록시에 의해 수신된 응답 메시지인 경우, 프록시는 서버와의 연결을 닫고 수신된 응답을 폐기한 다음 502
(Bad Gateway) 응답을 클라이언트에게 보내야 합니다. 이것이 사용자 에이전트에 의해 수신된 응답 메시지인 경우, 사용자
에이전트는 서버와의 연결을 닫고 수신된 응답을 폐기해야 합니다("**MUST**").
5. [page 33] 유효한 Content-Length 헤더 필드가 Transfer-Encoding 없이 존재하는 경우, 해당 필드의 십진 값은 예상되는
메시지 바디의 길이를 옥텟으로 정의합니다. 송신자가 연결을 닫거나 수신자가 지정된 옥텟 수를 받기 전에 타임아웃이 발생하는
경우, 수신자는 메시지를 불완전하다고 간주하고 연결을 닫아야 합니다. (**MUST**)
6. 이것이 요청 메시지이고 위의 어떤 조건도 충족되지 않는 경우, 메시지 바디의 길이는 0입니다 (메시지 바디가 없음).
7. 그렇지 않으면, 이것은 선언된 메시지 바디 길이가 없는 응답 메시지이므로, 메시지 바디의 길이는 서버가 연결을 닫기 전에
수신된 옥텟 수에 의해 결정됩니다.
성공적으로 완료된, 네트워크 장애로 인해 일부 수신이 중단된 메시지를 구별할 수 있는 방법이 없기 때문에, 서버는 가능한 경우 인코딩 또는 길이 제한된 메시지를 생성해야 합니다(SHOULD). 이러한 close-delimiting 기능은 주로 HTTP/1.0과의 하위 호환성을 위해 존재합니다.
서버는 메시지 바디가 포함되지만 Content-Length가 없는 요청을 411 (Length Required)로 응답하여 거부할 수 있습니다(“MAY”).
만약 청크드(chunked)를 제외한 다른 전송 인코딩이 적용되지 않았다면, 메시지 바디의 길이를 미리 알고 있는 경우, 클라이언트는 청크드 전송 인코딩 대신 유효한 Content-Length 헤더 필드를 사용해야 합니다(“SHOULD”). 일부 기존 서비스는 청크드 전송 인코딩을 이해하더라도 411 (Length Required) 상태 코드로 응답하는 경우가 있습니다. 이는 주로 게이트웨이를 통해 구현된 서비스에서 요청을 처리하기 전에 미리 콘텐츠 길이를 요구하며, 서버가 전체 요청을 버퍼링할 수 없거나 원하지 않기 때문입니다.
메시지 바디를 포함하는 요청을 보내는 사용자 에이전트는, 서버가 HTTP/1.1(또는 그 이후 버전) 요청을 처리할 것인지를 알지 못하는 경우, 유효한 Content-Length 헤더 필드를 보내야 합니다(“MUST”). 이러한 정보는 특정 사용자 설정이나 이전 수신한 응답의 버전을 기억함으로써 얻을 수 있습니다.
연결에 대한 마지막 요청에 대한 최종 응답이 완전히 수신되었고 추가로 읽어야 할 데이터가 남아있는 경우, 사용자 에이전트는 남은 데이터를 버릴 수 있으며 또는 이전 응답 바디의 일부로 포함되어야 할지 확인할 수도 있습니다. 이는 이전 메시지의 Content-Length 값이 잘못된 경우에 해당될 수 있습니다. 클라이언트는 이러한 추가 데이터를 별도의 응답으로 처리, 캐시 또는 전달해서는 안 되며(“MUST NOT”), 이는 캐시 오염에 취약한 동작이 될 수 있기 때문입니다.
3.4 Handling Incomplete Messages
[page 34] 미완성된 요청 메시지를 받은 서버는 일반적으로 요청이 취소되거나 타임아웃 예외가 발생한 결과로 인해 연결을 닫기 전에 오류 응답을 보낼 수 있습니다(“MAY”).
불완전한 응답 메시지를 받은 클라이언트는 연결이 이르게 닫히거나, 예상되는 청크 전송 코딩 의 디코딩이 실패한 경우와 같이 미완성 상태로 기록해야 합니다(“MUST”). 미완성 응답에 대한 캐시 요구 사항은 [RFC7234]의 섹션 3에서 정의되어 있습니다.
응답이 헤더 섹션 중간(빈 줄을 받기 전)에서 종료되고 상태 코드가 응답의 전체 의미를 전달하기 위해 헤더 필드에 의존할 수 있는 경우, 클라이언트는 의미가 전달되었다고 가정해서는 안 됩니다. 클라이언트는 다음에 어떤 조치를 취해야 할지 알아내기 위해 요청을 반복해야 할 수도 있습니다.
청크 전송 코딩을 사용하는 메시지 본문은 인코딩을 종료하는 크기가 0인 청크를 받지 않은 경우 불완전합니다. 유효한 Content-Length를 사용하는 메시지는 수신된 메시지 본문의 크기(옥텟 단위)가 Content-Length로 지정된 값보다 작은 경우 불완전합니다. 청크 전송 코딩이나 Content-Length가 없는 응답은 연결이 닫힘으로써 종료되며, 따라서 헤더 섹션이 정확하게 수신된 경우 메시지 본문 옥텟 수에 관계없이 완전한 것으로 간주됩니다.
3.5 Message Parsing Robustness
이전 HTTP/1.0 사용자 에이전트 구현은 일부 초기 서버 애플리케이션에서 줄 끝으로 끝나지 않은 메시지 본문 콘텐츠를 읽지 못하는 문제를 해결하기 위해 POST 요청 이후에 추가적인 CRLF(Carriage Return Line Feed)을 전송할 수 있습니다. 하지만 HTTP/1.1 사용자 에이전트는 요청을 전송하기 전이나 후에 추가적인 CRLF를 사용해서는 안 됩니다(“MUST NOT”). 요청 메시지 본문을 줄 끝으로 끝내려는 경우, 사용자 에이전트는 끝내는 CRLF 옥텟을 메시지 본문의 길이에 포함해야 합니다.
강건성을 위해, 요청 라인을 받고 구문 분석할 것으로 기대하는 서버는 요청 라인 이전에 받은 하나 이상의 빈 줄(CRLF)을 무시해야 합니다(“SHOULD”). 시작 라인과 헤더 필드의 줄 종결자는 CRLF 시퀀스이지만, 수신자는 단일 LF를 줄 종결자로 인식하고 앞에 오는 CR을 무시할 수 있습니다(“MAY”).
[page 35] 요청 라인과 상태 라인 구문 규칙은 각 구성 요소 요소가 단일 SP 옥텟으로 구분되어야 한다고 요구하지만, 수신자는 대신 공백으로 구분된 단어 경계에서 구문 분석할 수 있으며, CRLF 종결자를 제외하고는 이전이나 후행 공백을 무시하면서 어떤 형태의 공백이든 SP 구분자로 처리할 수 있습니다. 이러한 공백에는 SP, HTAB, VT (%x0B), FF (%x0C) 또는 벌어진 CR을 포함할 수 있습니다. 그러나 관대한 구문 분석은 메시지의 여러 수신자가 있고 각각이 강건성에 대해 고유한 해석을 가지는 경우 보안 취약점을 초래할 수 있습니다(Section 9.5 참조).
HTTP 요청 메시지만 수신하는 서버 또는 시작 라인에서부터 HTTP 요청 메시지로 보이는 것을 처리하는 서버가 HTTP-메시지 문법과 관련된 강건성 예외를 제외한 옥텟 시퀀스를 수신하면, 서버는 400 (잘못된 요청) 응답을 반환해야 합니다.
4) Transfer Coding
전송 코딩 이름은 네트워크를 통해 “안전한 전송”을 보장하기 위해 페이로드 본문에 적용되거나 적용되었을 수 있는 인코딩 변환을 나타내기 위해 사용됩니다. 전송 코딩은 전송되는 표현의 속성이 아닌 메시지의 속성이라는 점에서 내용 코딩과는 다릅니다.
- transfer-coding = "chunked" ; 섹션 4.1
/ "compress" ; 섹션 4.2.1
/ "deflate" ; 섹션 4.2.2
/ "gzip" ; 섹션 4.2.3
/ transfer-extension
- transfer-extension = token * ( OWS ";" OWS transfer-parameter )
매개변수는 이름 또는 이름 = 값 쌍으로 구성됩니다.
- transfer-parameter = token BWS "=" BWS ( token / quoted-string )
모든 전송 코딩 이름은 대소문자를 구분하지 않으며, HTTP 전송 코딩 레지스트리에 등록되어야 합니다(섹션 8.4에서 정의됨). 이들은 TE (섹션 4.3) 및 Transfer-Encoding (섹션 3.3.1) 헤더 필드에서 사용됩니다.
4.1 Chunked Transfer Coding
[page 36] 청크 전송 코딩은 페이로드 본문을 청크라고 하는 각각이 크기 표시자를 가진 일련의 청크로 래핑한 후, 선택적으로 헤더 필드를 포함하는 트레일러로 전송합니다(“OPTIONAL”). 청크 전송 코딩을 사용하면 크기를 알 수 없는 콘텐츠 스트림을 길이로 제한된 버퍼의 시퀀스로 전송할 수 있으며, 이를 통해 발신자는 연결 지속성을 유지하고 수신자는 전체 메시지를 수신한 것을 알 수 있게 됩니다.
chunked-body = * chunk
last-chunk
trailer-part
CRLF
chunk = chunk-size [ chunk-ext ] CRLF
chunk-data CRLF
chunk-size = 1 * HEXDIG
last-chunk = 1 * ("0") [ chunk-ext ] CRLF
chunk-data = 1 * OCTET ; a sequence of chunk-size octets
청크 크기 필드는 청크 데이터의 크기를 16진수 숫자로 표시한 것으로, 옥텟 단위로 측정됩니다. 청크 전송 코딩은 청크 크기가 0인 청크를 받은 후(이후로는 트레일러가 올 수 있음) 빈 줄로 끝나면 완료됩니다.
수신자는 청크 전송 코딩을 파싱하고 디코딩할 수 있어야 합니다(“MUST”).
4.1 (1) Chunk Extensions
청크 인코딩은 각 청크가 청크 크기 바로 뒤에 올 수 있는 청크 확장을 포함하여, 청크별 메타데이터(예: 서명 또는 해시), 메시지 중간 제어 정보 또는 메시지 본문 크기의 무작위화를 제공하기 위해 사용될 수 있습니다.
청크 확장은 다음과 같은 형식으로 구성됩니다.
chunk-ext = * ( ";" chunk-ext-name [ "=" chunk-ext-val ] ) chunk-ext-name = token
chunk-ext-val = token / quoted-string`
청크 인코딩은 각 연결에 특정하며, 일반적으로 각 수신자(중간 단계 포함)가 청크 확장을 검사하기 전에 제거하거나 재코딩할 수 있습니다. 따라서 청크 확장의 사용은 일반적으로 “롱 폴링(long polling)”과 같은 특수한 HTTP 서비스(클라이언트와 서버 간에 청크 확장의 사용에 대한 공유된 기대가 있는 경우) 또는 엔드 투 엔드 보안 연결 내의 패딩과 같은 특정한 경우에 제한적입니다.
수신자는 인식되지 않는 청크 확장을 무시해야 합니다(“MUST”). 서버는 요청으로 수신된 청크 확장의 총 길이를 제공되는 서비스에 적절한 한도로 제한해야 하며, 메시지의 다른 부분에 대한 길이 제한과 시간 초과를 적용하는 방식과 동일하게 처리해야 합니다. 그리고 해당 한도를 초과하는 경우에는 적절한 4xx (클라이언트 오류) 응답을 생성해야 합니다(“MUST”).
4.1 (2) Chunked Trailer Part
[page 37] 트레일러는 메시지 본문이 전송되는 동안 동적으로 생성될 수 있는 메타데이터를 제공하기 위해 청크된 메시지의 끝에 추가 필드를 포함할 수 있게 합니다. 이러한 추가 필드는 메시지 무결성 검사, 디지털 서명 또는 후처리 상태와 같은 정보를 제공할 수 있습니다. 트레일러 필드는 메시지의 헤더 섹션 대신 청크된 트레일러에서 전송되는데, 헤더 필드와 동일한 형식을 가지고 있습니다
- trailer-part = * ( header-field CRLF )
송신자는 메시지의 프레임 구성에 필요한 필드 (예: Transfer-Encoding 및 Content-Length), 라우팅에 필요한 필드 (예: Host), 요청 수정자 (예: [RFC7231]의 제 5 섹션에 기술된 제어 및 조건), 인증 (예: [RFC7235] 및 [RFC6265] 참조), 응답 제어 데이터 (예: [RFC7231]의 제 7.1 섹션 참조) 또는 페이로드 처리 방법을 결정하는 데 필요한 필드 (예: Content-Encoding, Content-Type, Content-Range 및 Trailer)를 포함하는 트레일러를 생성해서는 안 됩니다(“MUST NOT”).
비어 있지 않은 트레일러가 포함된 청크된 메시지를 수신하는 경우, 수신자는 위에서 금지된 필드를 제외하고 트레일러의 필드를 메시지의 헤더 섹션에 추가된 것으로 처리할 수 있습니다(“MAY”). 수신자는 트레일러에 전송할 수 없는 필드를 무시하거나 오류로 간주해야 합니다. 헤더 섹션에 있는 것처럼 처리하면 외부 보안 필터를 우회할 수 있기 때문입니다(“MUST”).
4.3 절에서 설명된대로 TE 헤더 필드가 “trailers”를 허용한다고 나타내는 요청이 포함되지 않은 경우, 서버는 사용자 에이전트가 수신해야 할 필요가 있다고 믿는 트레일러 필드를 생성해서는 안 됩니다(“SHOULD NOT”). “trailers”를 포함하지 않은 TE를 가진 경우, 서버는 트레일러 필드가 사용자 에이전트로 전달되는 동안 경로에서 무시될 수 있음을 가정해야 합니다. 이 요구 사항은 중개자가 전체 응답을 버퍼링하지 않고도 HTTP/1.0 수신자에게 비청크된 메시지를 전달할 수 있도록 합니다.
4.1 (3) Decoding Chunked
[page 38] 체크된 전송 코딩(chunked transfer coding)을 디코딩하는 과정은 의사 코드로 다음과 같이 나타낼 수 있습니다:
length := 0
read chunk-size, chunk-ext (if any), and CRLF
while (chunk-size > 0) {
read chunk-data and CRLF
append chunk-data to decoded-body
length := length + chunk-size
read chunk-size, chunk-ext (if any), and CRLF
}
read trailer field
while (trailer field is not empty) {
if (trailer field is allowed to be sent in a trailer) {
append trailer field to existing header fields
}
read trailer-field
}
Content-Length := length
Remove "chunked" from Transfer-Encoding
Remove Trailer from existing header fields
4.2 Compression Codings
아래 정의된 인코딩들은 페이 로드 메세지를 압축하는 것에 사용될 수 있습니다.
4.2 (1) Compress Coding
“compress” 코딩은 주로 UNIX 파일 압축 프로그램 “compress”에서 생성되는 적응형 Lempel-Ziv-Welch (LZW) 코딩 [Welch]입니다. 수신자는 “x-compress”를 “compress”와 동등한 것으로 간주해야 합니다(“SHOULD”).
4.2 (2) Deflate Coding
“deflate” 코딩은 “deflate” 압축된 데이터 스트림 [RFC1951]과 Lempel-Ziv (LZ77) 압축 알고리즘과 Huffman 코딩의 조합을 사용하는 “zlib” 데이터 형식 [RFC1950]입니다.
참고: 일부 규격에 맞지 않는 구현은 zlib 래퍼 없이 “deflate” 압축된 데이터를 전송합니다.
4.2 (3) Gzip Coding
[page 39] “gzip” 코딩은 32비트 순환 중복 검사 (CRC)를 가진 LZ77 코딩으로, 일반적으로 gzip 파일 압축 프로그램 [RFC1952]에서 생성됩니다. 수신자는 “x-gzip”를 “gzip”와 동등한 것으로 간주해야 합니다 (SHOULD).
4.3. TE
요청의 “TE” 헤더 필드는 클라이언트가 응답에서 청크 이외의 어떤 전송 코딩을 수용할 것인지, 그리고 청크 전송 코딩에서 트레일러 필드를 수용할지 여부를 나타냅니다.
TE 필드 값은 쉼표로 구분된 전송 코딩 이름의 목록으로 구성되며, 각각은 선택적 매개변수를 허용합니다(4장에서 설명된대로), 그리고/또는 “trailers” 키워드를 포함할 수 있습니다. 클라이언트는 TE에서 청크 전송 코딩 이름을 보내서는 안 됩니다(“MUST NOT”). chunked는 항상 HTTP/1.1 수신자에게 허용되기 때문입니다.
TE = #t-codings
t-codings = "trailers" / ( transfer-coding [ t-ranking ] )
t-ranking = OWS ";" OWS "q=" rank
rank = ( "0" [ "." 0 * 3DIGIT ] )
/ ( "1" [ "." 0* 3("0") ] )
아래는 TE가 사용된 세 가지 예시
TE: deflate
TE:
TE: trailers, deflate;q=0.5
키워드 “trailers”의 존재는 클라이언트가 자신과 하위 클라이언트를 대신하여 Section 4.1.2에서 정의된대로 청크 전송 코딩에서 트레일러 필드를 수락할 의사가 있다는 것을 나타냅니다. 중계자로부터의 요청의 경우, 이는 다음 중 하나를 의미합니다: (a) 모든 하위 클라이언트가 전달된 응답에서 트레일러 필드를 수락할 의사가 있는 것이거나, (b) 중계자가 하위 수신자를 대신하여 응답을 버퍼링하려고 시도할 것입니다. HTTP/1.1은 청크 응답의 크기를 제한하는 수단을 정의하지 않으므로, 중계자가 전체 응답을 버퍼링할 수 있다는 보장을 할 수 없다는 점에 유의해야 합니다.
여러 전송 코딩이 허용되는 경우, 클라이언트는 대소문자를 구분하지 않는 “q” 매개변수를 사용하여 우선순위에 따라 코딩을 순위화할 수 있습니다 (MAY) (콘텐츠 협상 필드에서 사용되는 q값과 유사함, [RFC7231]의 5.3.1절). 순위 값은 0부터 1 사이의 실수이며, 0.001은 가장 선호하지 않는 값이고 1은 가장 선호하는 값입니다. 0의 값은 “수용할 수 없음”을 의미합니다.
만약 TE 필드 값이 비어 있거나 TE 필드 자체가 존재하지 않는 경우, 유일하게 허용되는 전송 코딩은 청크 전송 코딩입니다. 전송 코딩이 없는 메시지는 항상 허용됩니다.
TE 헤더 필드는 직접적인 연결에만 적용되기 때문에, TE를 전송하는 측은 중계자들이 해당 의미를 지원하지 않는 경우 TE 필드가 전달되는 것을 방지하기 위해 Connection 헤더 필드(6.1절) 내에 “TE” 연결 옵션도 함께 전송해야 합니다 (MUST).
4.4. Trailer
[page 40] 메시지가 청크 전송 코딩으로 인코딩된 메시지 본문을 포함하고 발신자가 메시지의 끝에 트레일러 필드 형식의 메타데이터를 전송하려는 경우, 발신자는 메시지 본문 이전에 Trailer 헤더 필드를 생성하여 트레일러에 포함될 필드를 나타내야 합니다 (SHOULD). 이는 수신자가 본문 처리를 시작하기 전에 해당 메타데이터의 수령 준비를 할 수 있게 하여, 메시지가 스트리밍되고 수신자가 실시간으로 무결성 검사를 확인하려는 경우 유용합니다.
- Trailer = 1#field-name
5) Message Routing
HTTP 요청 메시지의 라우팅은 각 클라이언트마다 대상 리소스, 클라이언트의 프록시 설정 및 Inbound 연결의 설정 또는 재사용에 따라 결정됩니다. 해당하는 응답 라우팅은 동일한 연결 체인을 따라 클라이언트로 돌아갑니다.
5.1 Identifying a Target Resource (타겟 리소스 식별)
HTTP는 일반용 컴퓨터에서부터 가정용 가전제품에 이르기까지 다양한 응용 프로그램에서 사용됩니다. 일부 경우에는 통신 옵션이 클라이언트의 설정에 하드 코딩되어 있을 수 있습니다. 그러나 대부분의 HTTP 클라이언트는 일반 웹 브라우저와 동일한 리소스 식별 메커니즘과 설정 기술에 의존합니다.
HTTP 통신은 사용자 에이전트에 의해 특정 목적을 위해 시작됩니다. 이 목적은 [RFC7231]에서 정의된 요청 의미론과 그 의미론을 적용할 대상 리소스의 조합입니다. “대상 리소스”를 식별하기 위해 일반적으로 URI 참조(Section 2.7)가 사용됩니다. 사용자 에이전트는 “대상 URI”를 얻기 위해 이를 절대 형식으로 해석합니다. 대상 URI에는 참조의 프래그먼트 구성요소가 있을 경우 해당 부분은 제외됩니다. 이는 프래그먼트 식별자가 클라이언트 측 처리를 위해 예약되어 있기 때문입니다 ([RFC3986], 3.5절).
5.2 Connecting Inbound (인바운드 연결)
[page 41] 대상 URI가 결정되면 클라이언트는 원하는 의미를 달성하기 위해 네트워크 요청이 필요한지 여부와 필요한 경우 해당 요청이 어디로 전송되어야 하는지를 결정해야 합니다.
만약 클라이언트에 캐시 [RFC7234]가 있고 요청이 캐시로 충족될 수 있다면, 대개 요청은 먼저 캐시로 전송됩니다.
요청이 캐시로 충족되지 않는 경우, 일반적인 클라이언트는 요청을 충족하기 위해 프록시를 사용해야 하는지 여부를 판단하기 위해 자신의 구성을 확인합니다. 프록시 구성은 구현에 따라 다르지만, 일반적으로 URI 접두사 일치, 선택적 권한 일치 또는 둘 다를 기반으로 하며, 프록시 자체는 일반적으로 “http” 또는 “https” URI로 식별됩니다. 프록시가 적용되는 경우, 클라이언트는 해당 프록시로 연결을 설정(또는 재사용)하여 들어오는 연결을 수립합니다.
프록시가 적용되지 않는 경우, 일반적인 클라이언트는 일반적으로 대상 URI의 스킴에 특화된 핸들러 루틴을 호출하여 대상 리소스의 권한에 직접 연결합니다. 이는 대상 URI 스킴에 따라 다르며 해당 스킴의 관련 사양에 의해 정의됩니다. 이는 이 사양이 “http” (2.7.1절) 및 “https” (2.7.2절) 스킴의 해결을 위한 오리진 서버 액세스를 정의하는 방식과 유사합니다.
HTTP에 대한 연결 관리와 관련된 요구 사항은 6장에서 정의됩니다.
5.3 Request Target (타겟 요청)
인바운드 연결을 획득한 후, 클라이언트는 대상 URI에서 유도된 request-target을 가진 HTTP 요청 메시지 (3장)를 보냅니다. 요청하는 메서드와 요청이 프록시로 전송되는지 여부에 따라 request-target에는 네 가지 서로 다른 형식이 있습니다.
request-target = **origin-form**
/ **absolute-form**
/ **authority-form**
/ **asterisk-form**
5.3 (1) origin form
[page 42] 가장 일반적인 request-target 형식은 origin-form입니다.
origin-form = absolute-path [ “?” query ]
원 서버로 직접 요청을 보낼 때 (아래에서 설명하는 CONNECT 또는 서버 전체 OPTIONS 요청 제외), 클라이언트는 요청-타겟으로 대상 URI의 절대 경로와 쿼리 구성 요소만을 보내야 합니다(MUST). 대상 URI의 경로 구성 요소가 비어 있는 경우, 클라이언트는 요청-타겟의 origin-form 내에서 경로로 “/”를 보내야 합니다(MUST). Host 헤더 필드도 Section 5.4에서 정의된대로 보내야 합니다.
예를 들어, 원 서버로부터 직접
[http://www.example.org/where?q=now](http://www.example.org/where?q=now)
로 식별된 리소스의 표현을 검색하려는 클라이언트는 “www.example.org” 호스트의 80번 포트에 대한 TCP 연결을 열거나 재사용하고 다음 라인을 보냅니다:
GET /where?q=now HTTP/1.1 Host: [www.example.org](http://www.example.org/)
그 후에 요청 메시지의 나머지 부분을 보냅니다.
5.3 (2) absolute-form
프록시에 요청을 보낼 때 (아래에서 설명하는 CONNECT 또는 서버 전체 OPTIONS 요청 제외), 클라이언트는 요청-타겟으로 대상 URI를 absolute-form으로 보내야 합니다.
absolute-form = absolute-URI
프록시에게는 가능하면 유효한 캐시에서 해당 요청을 처리하거나, 클라이언트를 대신하여 요청-타겟에 지정된 다음 들어오는 프록시 서버 또는 원 서버로 동일한 요청을 수행하도록 요청합니다. 메시지의 “전달(forwarding)”에 대한 요구 사항은 5.7절에서 정의됩니다.
request-line의 예로는 다음과 같은 absolute-form이 있습니다:
GET [http://www.example.org/pub/WWW/TheProject.html](http://www.example.org/pub/WWW/TheProject.html) HTTP/1.1
앞으로 어떤 버전의 HTTP에서든 모든 요청에 대해 absolute-form으로의 전환을 허용하기 위해, 서버는 요청에서 absolute-form을 받아들여야 합니다. HTTP/1.1 클라이언트는 프록시에게만 이를 요청에서 보낼 것입니다.
5.3 (3) authority-form
[page 43] The authority-form의 request-target은 CONNECT 요청에만 사용됩니다 ([RFC7231]의 4.3.6절).
authority-form = authority
하나 이상의 프록시를 통해 터널을 설정하기 위해 CONNECT 요청을 보낼 때, 클라이언트는 요청-타겟으로 대상 URI의 권한 구성 요소(사용자 정보와 “@” 구분자 제외)만을 보내야 합니다. 예를 들어,
CONNECT www.example.com:80 HTTP/1.1
5.3 (4) asterisk-form
asterisk-form의 request-target은 서버 전체 OPTIONS 요청에만 사용됩니다 ([RFC7231]의 4.3.7절).
asterisk-form = " * "
특정한 이름을 가진 리소스가 아닌 서버 전체에 대한 OPTIONS를 요청하려는 경우, 클라이언트는 요청-타겟으로 “ * “ (%x2A)만을 보내야 합니다. 예를 들어,
OPTIONS * HTTP/1.1
만약 프록시가 요청-타겟이 절대 형식인 OPTIONS 요청을 받아들이고 URI에 비어있는 경로와 쿼리 구성 요소가 있는 경우, 요청 체인에서 마지막 프록시는 해당 서버로 요청을 전달할 때 요청-타겟으로 “ * “을 보내야 합니다.
예를 들어, 다음 요청: OPTIONS http://www.example.org:8001 HTTP/1.1 은 마지막 프록시에 의해 다음과 같이 전달됩니다.
OPTIONS * HTTP/1.1 Host: [www.example.org:8001](http://www.example.org:8001/)
프록시는 "[www.example.org](http://www.example.org/)" 호스트의 8001 포트에 연결한 후 전달합니다.
5.4 Host
[page 44] 요청에서의 “Host” 헤더 필드는 대상 URI에서 호스트와 포트 정보를 제공하여 원 서버가 단일 IP 주소에서 여러 호스트 이름에 대한 요청을 처리하면서 리소스를 구별할 수 있게 합니다.
Host = uri-host [ ":" port ] ; Section 2.7.1
모든 HTTP/1.1 요청 메시지에서 클라이언트는 Host 헤더 필드를 보내야 합니다(“MUST”). 대상 URI에 권한 구성 요소가 포함된 경우, 클라이언트는 Host에 대한 필드값을 권한 구성 요소와 동일하게 보내야 합니다. 이 때 userinfo 하위 구성 요소와 “@” 구분자는 제외되어야 합니다 (Section 2.7.1). 대상 URI에 권한 구성 요소가 누락되거나 정의되지 않은 경우, 클라이언트는 빈 필드값을 가진 Host 헤더 필드를 보내야 합니다(MUST).
Host 필드값은 요청 처리에 필수적인 정보이므로, 사용자 에이전트는 요청 라인 다음에 Host를 첫 번째 헤더 필드로 생성하는 것이 좋습니다 (**SHOULD**).
예를 들어, 원 서버에 대한 GET 요청인 경우 http://www.example.org/pub/WWW/ 다음과 같이 시작합니다:
GET /pub/WWW/ HTTP/1.1 Host: [www.example.org](http://www.example.org/)
HTTP/1.1 요청에서는 요청-타겟이 절대 형식인 경우에도 클라이언트는 Host 헤더 필드를 보내야 합니다(MUST). 이는 Host 정보가 Host를 구현하지 않을 수 있는 옛날 HTTP/1.0 프록시를 통해 전달될 수 있도록 합니다.
프록시가 절대 형식의 요청-타겟을 받으면 수신한 Host 헤더 필드 (있는 경우)를 무시하고 대신 요청-타겟의 호스트 정보로 교체해야 합니다. 이와 같은 요청을 전달하는 프록시는 수신한 Host 헤더 필드를 전달하는 대신 수신한 요청-타겟을 기반으로 새로운 Host 필드값을 생성해야 합니다.
Host 헤더 필드는 응용 수준의 라우팅 메커니즘으로 작동하므로, 공유 캐시를 오염시키거나 의도하지 않은 서버로 요청을 리디렉션하기 위해 악성 코드의 대상이 될 수 있습니다. Host 필드값에 의존하여 요청을 내부 서버로 리디렉션하거나 공유 캐시에서 캐시 키로 사용하는 경우, 중간 프록시는 먼저 가로챈 연결이 해당 호스트의 유효한 IP 주소를 대상으로 하는지 확인하지 않으면 취약점이 노출될 수 있습니다.
서버는 Host 헤더 필드가 없는 HTTP/1.1 요청 메시지나 여러 개의 Host 헤더 필드 또는 잘못된 필드값을 가진 Host 헤더 필드를 포함한 요청 메시지에 대해 400 (Bad Request) 상태 코드로 응답해야 합니다 (MUST).
5.5 Effective Request URI (효과적인 요청 URI)
[page 45] 요청-타겟은 사용자 에이전트의 대상 URI의 일부만을 포함하는 경우가 많으므로, 서버는 요청을 올바르게 처리하기 위해 “효과적인 요청 URI”로 의도된 대상을 재구성합니다. 이 재구성은 서버의 로컬 구성 및 요청-타겟, Host 헤더 필드 및 연결 컨텍스트로 전달된 정보를 포함합니다.
유저 에이전트에 대해서는 효과적인 요청 URI는 대상 URI입니다.
요청-타겟이 absolute-form인 경우, 효과적인 요청 URI는 요청-타겟과 동일합니다. 그렇지 않은 경우, 효과적인 요청 URI는 다음과 같이 구성됩니다.
서버의 구성 (또는 아웃바운드 게이트웨이)이 고정된 URI 스킴을 제공하는 경우, 해당 스킴이 효과적인 요청 URI에 사용됩니다. 그렇지 않은 경우, 요청이 TLS로 보호된 TCP 연결을 통해 수신된 경우, 효과적인 요청 URI의 스킴은 “https”가 됩니다. 그렇지 않은 경우, 스킴은 “http”입니다.
서버의 구성 (또는 아웃바운드 게이트웨이)이 고정된 URI 권한 구성 요소를 제공하는 경우, 해당 권한이 효과적인 요청 URI에 사용됩니다. 그렇지 않은 경우, 요청-타겟이 권한 형식인 경우, 효과적인 요청 URI의 권한 구성 요소는 요청-타겟과 동일합니다. 그렇지 않은 경우, 비어 있지 않은 필드값을 가진 Host 헤더 필드가 제공된 경우, 권한 구성 요소는 Host 필드값과 동일합니다. 그렇지 않은 경우, 권한 구성 요소는 서버에 대해 구성된 기본 이름이 할당되며, 연결의 들어오는 TCP 포트 번호가 효과적인 요청 URI의 스킴에 대한 기본 포트 번호와 다른 경우, 콜론 (“:”)과 들어오는 포트 번호 (10진수 형식)가 권한 구성 요소에 추가됩니다.
요청-타겟이 authority-form이거나 asterisk-form인 경우, 효과적인 요청 URI의 결합된 경로와 쿼리 구성 요소는 비어 있습니다. 그렇지 않은 경우, 결합된 경로와 쿼리 구성 요소는 요청-타겟과 동일합니다.
위에서 결정된 효과적인 요청 URI의 구성 요소는 스킴, “://”, 권한 및 결합된 경로와 쿼리 구성 요소를 연결하여 절대-URI 형식으로 결합될 수 있습니다.
[page 46] 예제 1: 보안되지 않은 TCP 연결을 통해 수신된 다음 메시지
GET /pub/WWW/TheProject.html HTTP/1.1 Host: [www.example.org:8080](http://www.example.org:8080/)
효과적인 요청 URI는 다음과 같습니다.
[http://www.example.org:8080/pub/WWW/TheProject.html](http://www.example.org:8080/pub/WWW/TheProject.html)
예제 2: TLS로 보호된 TCP 연결을 통해 수신된 다음 메시지
OPTIONS * HTTP/1.1 Host: [www.example.org](http://www.example.org/)
효과적인 요청 URI는 다음과 같습니다.
[https://www.example.org](https://www.example.org/)
Host 헤더 필드가 없는 HTTP/1.0 요청을 수신하는 수신자는 효과적인 요청 URI의 권한 구성 요소를 추측하기 위해 휴리스틱(예: 특정 호스트와 관련된 고유한 URI 경로의 검사)을 사용할 수도 있습니다.
효과적인 요청 URI가 구성되면, 원 서버는 해당 URI를 통해 서비스를 제공할지 여부를 결정해야 합니다. 예를 들어, 요청이 잘못되거나 의도적이거나 우연히 잘못되어 요청-타겟이나 Host 헤더 필드의 정보가 연결이 수립된 호스트나 포트와 다른 경우가 있을 수 있습니다. 신뢰할 수 있는 게이트웨이에서 연결이 수신된 경우에는 이러한 일관성이 예상될 수 있지만, 그렇지 않은 경우에는 보안 필터를 우회하려는 시도, 서버로부터 비공개 콘텐츠를 전달하려는 속임수, 또는 캐시를 오염시키려는 의도를 나타낼 수도 있습니다. 메시지 라우팅과 관련된 보안 고려 사항에 대해서는 섹션 9를 참조하십시오.
5.6. Associating a Response to a Request (응답과 요청의 연결)
HTTP는 주어진 요청 메시지와 해당하는 하나 이상의 응답 메시지를 연결하기 위한 요청 식별자를 포함하지 않습니다. 따라서, 응답의 도착 순서가 동일한 연결에서 요청이 발생한 순서와 정확히 대응되어야 합니다. 하나의 요청에 대해 여러 개의 응답 메시지가 발생하는 경우는 정보성 응답 (1xx, [RFC7231]의 섹션 6.2 참조)이 동일한 요청에 대한 최종 응답 이전에 있을 때만 발생합니다. 연결에 여러 개의 미처리된 요청이 있는 클라이언트는 전송한 순서대로 미처리된 요청 목록을 유지해야 하며, 해당 연결에서 수신한 각 응답 메시지를 아직 최종 (non-1xx) 응답을 받지 않은 가장 순서가 높은 요청과 연관시켜야 합니다.
5.7 Message Forwarding (메세지 전달)
[page 47] 2.3절에서 설명한 대로 중개자는 HTTP 요청 및 응답 처리에 다양한 역할을 할 수 있습니다. 일부 중개자는 성능이나 가용성을 향상시키기 위해 사용됩니다. 다른 중개자는 액세스 제어나 콘텐츠 필터링을 위해 사용됩니다. HTTP 스트림은 파이프 및 필터 아키텍처와 유사한 특성을 가지므로 중개자가 스트림의 어느 방향에서든지 향상시킬 수 있는 한도가 없습니다.
터널로 동작하지 않는 중개자는 6.1절에서 명시된대로 Connection 헤더 필드를 구현하고, 수신 연결을 위한 것으로만 사용되는 필드를 전달하지 않아야 합니다(MUST).
중개자는 무한한 요청 루프로부터 보호되지 않는 한 자체에게 메시지를 전달해서는 안 됩니다(“MUST NOT”). 일반적으로 중개자는 자체 서버 이름, 별칭, 로컬 변형 또는 리터럴 IP 주소와 같은 자신의 서버 이름을 인식하고 해당 요청에 직접 응답해야 합니다.
5.7 (1) Via
“Via” 헤더 필드는 사용자 에이전트와 서버 간(요청에서) 또는 오리진 서버와 클라이언트 간(응답에서)에 위치한 중간 프로토콜 및 수신자의 존재를 나타냅니다. 이는 이메일의 “Received” 헤더 필드와 유사합니다 ([RFC5322]의 3.6.7절). Via는 메시지 전달의 추적, 요청 루프 방지, 그리고 요청/응답 체인 상에서 발송자의 프로토콜 기능 식별과 같은 용도로 사용될 수 있습니다.
Via = 1#( received-protocol RWS received-by [ RWS COMMENT ] )
received-protocol = [ protocol-name "/" ] protocol-version
; see [Section 6.7](https://datatracker.ietf.org/doc/html/rfc7230#section-6.7)
received-by = ( uri-host [ ":" port ] ) / pseudonym
pseudonym = token
여러 개의 Via 필드 값은 메시지를 전달한 각 프록시 또는 게이트웨이를 나타냅니다. 각 중개자는 메시지 수신 방법에 대한 자체 정보를 추가하여, 최종 결과는 전달 수신자의 순서에 따라 정렬됩니다.
프록시는 전달하는 각 메시지에 아래에서 설명하는 대로 적절한 Via 헤더 필드를 보내야 합니다(MUST). HTTP-to-HTTP 게이트웨이는 들어오는 각 요청 메시지에 적절한 Via 헤더 필드를 보내야 하며(MUST), 전달된 응답 메시지에도 Via 헤더 필드를 보낼 수 있습니다.
각 중개자에 대해 received-protocol은 메시지의 상위 송신자가 사용한 프로토콜과 프로토콜 버전을 나타냅니다. 따라서 Via 필드 값은 요청/응답 체인의 프로토콜 기능을 기록하여 하위 수신자가 볼 수 있도록 유지됩니다. 이는 Section 2.6에서 설명한 대로 응답에서 사용할 수 있는 하위 호환되지 않는 기능을 결정하는 데 유용할 수 있습니다. 간결성을 위해 HTTP인 경우 protocol-name은 생략됩니다.
received-by 부분은 일반적으로 메시지를 이후에 전달한 수신 서버나 클라이언트의 호스트와 선택적인 포트 번호입니다. 그러나 실제 호스트가 민감한 정보로 간주된다면 송신자는 이를 익명화할 수 있습니다(MAY). 포트가 제공되지 않은 경우 수신자는 해당 프로토콜의 기본 TCP 포트(있는 경우)에서 수신된 것으로 해석할 수 있습니다(MAY).
송신자는 Via 헤더 필드에서 각 수신자의 소프트웨어를 식별하기 위해 주석을 생성할 수 있습니다(MAY). 이는 User-Agent와 Server 헤더 필드와 유사합니다. 그러나 Via 필드의 모든 주석은 선택 사항이며, 수신자는 메시지를 전달하기 전에 주석을 제거할 수 있습니다(MAY).
예를 들어, HTTP/1.0 사용자 에이전트에서 내부 프록시인 “fred”로 요청 메시지를 보내고, “fred”는 HTTP/1.1을 사용하여 요청을 p.example.net의 공개 프록시로 전달하며, p.example.net은 요청을 www.example.com의 오리진 서버로 전달하여 요청을 완료합니다. 그럼 www.example.com에서 수신된 요청은 다음과 같은 Via 헤더 필드를 가지게 됩니다:
Via: 1.0 fred, 1.1 p.example.net
네트워크 방화벽을 통한 중개자는 명시적으로 그렇게 허용되지 않은 한 방화벽 영역 내의 호스트의 이름과 포트를 전달해서는 안 됩니다(SHOULD). 허용되지 않은 경우, 해당 중개자는 방화벽 뒤의 모든 호스트의 received-by 호스트를 해당 호스트에 대한 적절한 익명 이름으로 대체해야 합니다.
[page 49] 중개자는 동일한 received-protocol 값을 가지는 Via 헤더 필드 항목들의 순서가 지정된 부분집합을 하나의 항목으로 결합할 수 있습니다(MAY). 예를 들어,
Via: 1.0 ricky, 1.1 ethel, 1.1 fred, 1.0 lucy
을 다음과 같이 축소할 수 있습니다.
Via: 1.0 ricky, 1.1 mertz, 1.0 lucy
송신자는 여러 항목을 결합해서는 안 되며, 이들이 모두 같은 조직적 제어 하에 있고 호스트가 이미 익명 이름으로 대체된 경우에만 결합해야 합니다(SHOULD NOT). 또한, 다른 received-protocol 값을 가지는 항목은 결합해서는 안 됩니다(MUST NOT).
5.7 (2) Transformations
[page 49] 일부 중개자는 메시지와 페이로드를 변환하는 기능을 포함할 수 있습니다. 예를 들어, 프록시는 이미지 형식을 변환하여 캐시 공간을 절약하거나 느린 링크에서의 트래픽 양을 줄이는 등의 작업을 수행할 수 있습니다. 그러나 이러한 변환 작업이 의료 영상이나 과학적 데이터 분석과 같은 중요한 응용 프로그램을 위한 페이로드에 적용될 때 문제가 발생할 수 있습니다. 특히, 페이로드의 무결성 검사나 디지털 서명이 사용되어 수신된 페이로드가 원본과 동일한지 확인하는 경우에는 더욱 그렇습니다.
HTTP-to-HTTP 프록시는 메시지를 의미 있는 방식으로 수정하는 경우 “변환 프록시”라고 합니다. 이는 정상적인 HTTP 처리에 필요한 변환을 넘어서 원래 송신자에게 중요하거나 하향 스트림 수신자에게 잠재적으로 중요한 메시지를 변경하는 것을 의미합니다. 예를 들어, 변환 프록시는 공유 주석 서버로 작동하거나 (로컬 주석 데이터베이스를 참조하는 응답을 수정하는) 악성 코드 필터, 형식 변환기 또는 개인 정보 필터로 작동할 수 있습니다. 이러한 변환은 프록시를 선택한 클라이언트(또는 클라이언트 조직)가 원하는 것으로 가정됩니다.
프록시가 호스트 이름이 완전히 정규화된 도메인 이름이 아닌 요청 대상을 수신하는 경우, 프록시는 요청을 전달할 때 수신한 호스트 이름에 자체 도메인을 추가할 수 있습니다(MAY). 그러나 요청 대상이 완전히 정규화된 도메인 이름을 포함하는 경우 프록시는 호스트 이름을 변경해서는 안 됩니다(MUST NOT).
[page 50] 프록시는 다음 들어오는 서버로 전달할 때 받은 요청 대상의 “absolute-path”와 “query” 부분을 수정해서는 안 됩니다. 예외적으로 빈 경로를 “/” 또는 “*“로 대체하기 위해 수정할 수 있습니다.
프록시는 전송 코딩 (Section 4)을 통해 메시지 본문을 수정하거나 삭제할 수 있습니다.
프록시는 “no-transform” 캐시 제어 지시문 (Section 5.2 of [RFC7234])을 포함하는 메시지의 페이로드 (Section 3.3 of [RFC7231])를 변환해서는 안 됩니다.
“no-transform” 캐시 제어 지시문을 포함하지 않는 메시지의 페이로드는 프록시가 변환할 수 있습니다. 페이로드를 변환하는 프록시는 메시지에 이미 Warning 헤더 필드가 없는 경우에는 warn-code 214 (“Transformation Applied”)를 가진 Warning 헤더 필드를 추가해야 합니다(Section 5.5 of [RFC7234] 참조). 200 (OK) 응답의 페이로드를 변환하는 프록시는 응답 상태 코드를 203 (Non-Authoritative Information)로 변경하여 하향 스트림 수신자에게 변환이 적용되었음을 알릴 수도 있습니다 (Section 6.3.4 of [RFC7231] 참조).
프록시는 통신 체인의 끝점, 리소스 상태 또는 선택된 표현에 대한 정보를 제공하는 헤더 필드를 (페이로드 이외의 부분에서) 수정해서는 안 됩니다. 단, 해당 필드의 정의에서 명시적으로 수정을 허용하거나 개인 정보 보호 또는 보안을 위해 수정이 필요하다고 판단된 경우에는 예외입니다
6) Connection Management (연결 관리)
HTTP 메시징은 기반 전송 또는 세션 계층 연결 프로토콜과 독립적입니다. HTTP는 요청의 순서대로 전송되고 해당 요청에 대한 응답이 순서대로 전달되는 신뢰성 있는 전송을 가정합니다. HTTP 요청과 응답 구조를 기반 전송 프로토콜의 데이터 단위와 매핑하는 것은 이 명세의 범위를 벗어납니다.
5.2절에서 설명한대로, HTTP 상호작용에 사용될 구체적인 연결 프로토콜은 클라이언트 구성과 대상 URI에 의해 결정됩니다. 예를 들어, “http” URI scheme (2.7.1절)은 기본적으로 IP 상의 TCP 연결과 80번 기본 TCP 포트를 가리키지만, 클라이언트는 다른 연결, 포트 또는 프로토콜을 통해 프록시를 사용하도록 구성될 수 있습니다.
[page 51] HTTP 구현은 연결 관리에 참여하는 것으로 예상되며, 이는 현재 연결의 상태 유지, 새로운 연결 설정 또는 기존 연결 재사용, 연결에서 수신된 메시지 처리, 연결 장애 감지 및 각 연결 종료를 포함합니다. 대부분의 클라이언트는 여러 개의 연결을 병렬로 유지하며, 각 서버 엔드포인트 당 하나 이상의 연결을 포함합니다. 대부분의 서버는 수천 개의 동시 연결을 유지하도록 설계되었으며, 요청 대기열을 제어하여 공정한 사용을 가능하게 하고 서비스 거부 공격을 탐지할 수 있도록 합니다.
6.1 Connection
[page 51] “Connection” 헤더 필드는 발신자가 현재 연결에 대한 원하는 제어 옵션을 나타낼 수 있도록 합니다. 하위 수신자(downstream recipient)를 혼동시키지 않기 위해 프록시나 게이트웨이는 메시지를 전달하기 전에 수신한 연결 옵션을 제거하거나 대체해야 합니다(“MUST”).
“Connection” 이외의 헤더 필드가 현재 연결에 대한 제어 정보를 제공하는 경우, 발신자는 해당 필드 이름을 “Connection” 헤더 필드 내에 나열해야 합니다. 프록시나 게이트웨이는 메시지를 전달하기 전에 수신한 “Connection” 헤더 필드를 구문 분석하고, 이 필드의 각 연결 옵션에 대해 메시지에서 해당 이름과 동일한 헤더 필드(들)를 제거한 다음, “Connection” 헤더 필드 자체를 제거하거나 전달된 메시지를 위해 중계자의 연결 옵션으로 대체해야 합니다.
따라서, “Connection” 헤더 필드는 즉시 수신자에게만 적용되는 헤더 필드(“hop-by-hop”)와 모든 수신자에게 적용되는 필드(“end-to-end”)를 구분하기 위한 선언적인 방법을 제공하여 메시지가 스스로를 설명하고, 오래된 중계자에서도 맹목적으로 전달되지 않을 것임을 보장하며, 미래의 연결별 확장을 두려움 없이 배포할 수 있게 합니다.
"Connection" 헤더 필드의 값은 다음 문법을 따릅니다:
`Connection = 1#connection-option`
`Connection-option = token`
연결 옵션은 대소문자를 구분하지 않습니다.
발신자는 페이로드의 모든 수신자를 대상으로 하는 헤더 필드에 해당하는 연결 옵션을 보내서는 안 됩니다(MUST NOT). 예를 들어, Cache-Control은 연결 옵션으로 사용하는 것이 적절하지 않습니다 ([RFC7234]의 5.2절). 연결 옵션은 항상 메시지에 존재하는 헤더 필드와 일치하지 않을 수 있습니다. 연결 옵션에 연결된 매개변수가 없는 경우 연결별 헤더 필드는 필요하지 않을 수 있습니다. 반대로, 연결 옵션과 대응하는 연결별 헤더 필드가 없는 경우, 이는 중계자에 의해 잘못 전달된 필드를 나타내며 수신자는 무시해야 합니다.
[page 52] 새로운 연결 옵션을 정의할 때, 사양 작성자는 기존의 헤더 필드 이름을 조사하고 새로운 연결 옵션이 이미 배포된 헤더 필드와 동일한 이름을 공유하지 않도록 해야 합니다. 새로운 연결 옵션을 정의함으로써 해당 잠재적인 필드 이름은 연결 옵션과 관련된 추가 정보를 전달하기 위해 예약된 것으로 간주됩니다. 따라서 발신자가 해당 필드 이름을 다른 용도로 사용하는 것은 현명하지 않습니다.
“close” 연결 옵션은 발신자가 응답 완료 후에 이 연결이 닫힐 것임을 알리기 위해 정의됩니다. 예를 들어,
-> Connection : close
요청이나 응답 헤더 필드에서 위와 같이 사용되면, 발신자는 현재 요청/응답이 완료된 후 연결을 닫을 것임을 나타냅니다 (6.6절).
지속적인 연결을 지원하지 않는 클라이언트는 모든 요청 메시지에 “close” 연결 옵션을 보내야 합니다.
지속적인 연결을 지원하지 않는 서버는 1xx (정보성) 상태 코드를 가지지 않는 모든 응답 메시지에 “close” 연결 옵션을 보내야 합니다.
6.2 Establishment
이 사양의 범위를 벗어나서, 다양한 전송 또는 세션 계층 프로토콜을 통해 연결이 어떻게 설정되는지 설명하는 것은 아닙니다. 각 연결은 단일 전송 링크에만 적용됩니다.
6.3 Persistence
HTTP/1.1은 기본적으로 “지속적인 연결(persistent connections)”의 사용을 지원하며, 단일 연결을 통해 여러 요청과 응답을 처리할 수 있습니다. “close” 연결 옵션은 현재 요청/응답 후 연결이 지속되지 않을 것임을 신호로 사용됩니다. HTTP 구현은 지속적인 연결을 지원해야 합니다.
[page 53] 수신자는 가장 최근에 수신한 메시지의 프로토콜 버전과 Connection 헤더 필드 (있는 경우)를 기반으로 연결이 지속적인지 아닌지를 결정합니다:
- "close" 연결 옵션이 존재하면, 현재 응답 후 연결이 지속되지 않을 것입니다.
- 수신된 프로토콜이 HTTP/1.1(또는 그 이상)인 경우, 현재 응답 후 연결이 지속됩니다.
- 수신된 프로토콜이 HTTP/1.0인 경우, "keep-alive" 연결 옵션이 존재하고 수신자가 프록시가 아니며 HTTP/1.0 "keep-alive" 메커니즘을 사용하고자 하는 경우, 현재 응답 후 연결이 지속됩니다.
- 그렇지 않은 경우, 현재 응답 후 연결이 종료됩니다.
클라이언트는 “close” 연결 옵션을 보내거나 받거나, “keep-alive” 연결 옵션이 없는 HTTP/1.0 응답을 받을 때까지 지속 연결 상에서 추가 요청을 보낼 수 있습니다.
지속 연결을 유지하기 위해서는 연결 상의 모든 메시지가 자체적으로 정의된 메시지 길이를 가져야 합니다(즉, 연결 종료로 정의되지 않은 길이). 이에 대한 자세한 내용은 섹션 3.3에서 설명되어 있습니다. 서버는 응답을 보낸 후 요청 메시지 본문 전체를 읽거나 연결을 종료해야 하며, 그렇지 않으면 지속 연결의 남은 데이터가 다음 요청으로 잘못 해석될 수 있습니다. 마찬가지로, 클라이언트는 동일한 연결을 재사용하려면 응답 메시지 본문 전체를 읽어야 합니다.
프록시 서버는 HTTP/1.0 클라이언트와 지속적인 연결을 유지해서는 안 됩니다 ([RFC2068]의 섹션 19.7.1에 많은 HTTP/1.0 클라이언트에서 구현된 Keep-Alive 헤더 필드의 문제에 대한 정보와 논의 참조).
HTTP/1.0 클라이언트와의 하위 호환성에 대한 자세한 내용은 부록 A.1.2를 참조하십시오.
6.3 (1) Retrying Requests
연결은 의도와 상관없이 언제든지 닫힐 수 있습니다. 구현은 비동기적인 연결 종료 이벤트에서의 복구 필요성을 예상해야 합니다.
들어오는 연결이 예상보다 일찍 닫힐 때, 클라이언트는 모든 요청이 멱등 메서드를 사용하는 경우 (4.2.2절 [RFC7231] 참조) 중단된 요청 시퀀스를 자동으로 재전송하기 위해 새로운 연결을 열 수 있습니다. 프록시는 비멱등 요청을 자동으로 재시도해서는 안 됩니다.
[page 54] 유저 에이전트는 비멱등 메서드를 사용한 요청을 자동으로 재시도해서는 안 됩니다. 단, 요청의 의미가 실제로 멱등하다는 것을 알 수 있는 방법이 있거나, 원본 요청이 적용되지 않았음을 감지할 수 있는 방법이 있는 경우에만 자동으로 재시도할 수 있습니다. 예를 들어, 특정 리소스에 대한 POST 요청이 안전하다는 것을 (설계나 구성을 통해) 알고 있는 사용자 에이전트는 해당 요청을 자동으로 반복할 수 있습니다. 마찬가지로, 버전 관리 리포지토리에서 작동하는 특정 사용자 에이전트는 실패한 연결 이후 대상 리소스의 개정본을 확인하고, 부분적으로 적용된 변경 사항을 복구하거나 수정한 다음, 실패한 요청을 자동으로 재시도할 수 있을 수도 있습니다.
클라이언트는 실패한 자동 재시도를 자동으로 다시 시도해서는 안 됩니다(SHOULD NOT).
6.3 (2) Pipe lining
지속적인 연결을 지원하는 클라이언트는 요청을 “파이프라인”할 수 있습니다(즉, 각 응답을 기다리지 않고 여러 요청을 보낼 수 있습니다). 서버는 모든 안전한 메서드(Section 4.2.1 of [RFC7231])를 가진 파이프라인 요청의 순차열을 병렬로 처리할 수 있지만, 해당 요청이 수신된 순서대로 응답을 보내야 합니다.
파이프라인된 요청에 대한 응답을 모두 수신하기 전에 연결이 닫히는 경우, 파이프라인된 요청을 재시도해야 합니다. 이전 파이프라인에서 연결 실패 후(서버가 마지막 완전한 응답에서 명시적으로 닫지 않은 연결) 파이프라인된 요청을 재시도할 때, 클라이언트는 연결 설정 후 즉시 파이프라인을 사용해서는 안 됩니다. 이전 파이프라인에서 첫 번째 남은 요청이 오류 응답을 일으킬 수 있으며, 연결이 조기에 닫힌 경우 여러 요청이 다시 손실될 수 있습니다(Section 6.6에서 설명하는 TCP 리셋 문제 참조).
파이프라이닝에서 중요한 이중적 메서드(Section 4.2.2 of [RFC7231])는 연결 실패 후 자동으로 다시 시도될 수 있습니다. 사용자 에이전트는 비이중 메서드 이후에는 파이프라인 요청을 진행하지 말아야 하며, 해당 메서드에 대한 최종 응답 상태 코드를 수신하기 전까지는 파이프라인 요청과 관련하여 부분적인 실패 상황을 감지하고 복구할 수 있는 수단이 있어야 합니다.
[page 55] 파이프라인된 요청을 수신하는 중계자는 파이프라인된 요청을 안전하게 파이프라인할 수 있는 아웃바운드 사용자 에이전트에 의존할 수 있으므로, 이러한 요청을 수신받을 때 파이프라이닝 중계자는 파이프라인될 수 있습니다. 응답을 받기 전에 수신 연결이 실패하는 경우, 파이프라이닝 중계자는 모든 이중적 메서드를 가진 요청의 순차열을 재시도할 수 있습니다. 그렇지 않은 경우, 파이프라이닝 중계자는 수신된 응답을 전달하고 이에 따라 아웃바운드 사용자 에이전트가 복구할 수 있도록 해당하는 아웃바운드 연결을 닫아야 합니다.
6.4 Concurrency
클라이언트는 유지하는 동시 열린 연결의 수를 특정 서버로 제한해야 합니다.
이전 버전의 HTTP는 특정 연결 수를 천장으로 제공했지만, 많은 응용 프로그램에서는 이는 비실용적이라는 것이 확인되었습니다. 결과적으로, 이 명세서는 특정 최대 연결 수를 규정하지 않고, 대신 클라이언트가 여러 연결을 여는 경우 보수적으로 조치할 것을 권장합니다.
여러 연결은 일반적으로 “head-of-line blocking” 문제를 피하기 위해 사용됩니다. 이는 서버 측 처리 시간이 오래 걸리거나 큰 페이로드를 가진 요청이 동일한 연결에서 이후 요청을 차단하는 문제입니다. 그러나 각 연결은 서버 리소스를 소비합니다. 게다가 여러 연결을 사용하면 혼잡한 네트워크에서 원하지 않는 부작용을 일으킬 수 있습니다.
서버는 하나의 클라이언트로부터 과도한 개방된 연결 수와 같은 학대적이거나 서비스 거부 공격의 특성으로 판단하는 트래픽을 거부할 수 있습니다.
6.5 Failure and Timeouts
서버는 일반적으로 비활성 연결을 유지하지 않을 시간 제한(timeout) 값을 갖습니다. 프록시 서버는 동일한 프록시 서버를 통해 클라이언트가 더 많은 연결을 만들 가능성이 있으므로 이 값을 더 크게 설정할 수 있습니다. 지속적인 연결의 사용은 클라이언트나 서버의 시간 제한 길이(또는 존재 여부)에 대한 요구사항을 갖지 않습니다.
시간 초과를 원하는 클라이언트나 서버는 우아하게(close) 연결을 종료해야 합니다. 구현은 받은 종료 신호를 지속적으로 모니터링하고 적절하게 응답해야 합니다. 연결의 양쪽을 신속하게 종료함으로써 할당된 시스템 리소스를 회수할 수 있기 때문입니다.
[page 56] 클라이언트, 서버 또는 프록시는 언제든지 전송 연결을 종료할 수 있습니다. 예를 들어, 클라이언트가 “유휴(idle)” 연결을 닫기로 결정한 동시에 새로운 요청을 보내기 시작할 수 있습니다. 서버의 관점에서는 연결이 유휴 상태일 때 닫히지만, 클라이언트의 관점에서는 요청이 진행 중입니다.
서버는 가능한 경우 지속적인 연결을 유지하고, 일시적인 과부하를 해결하기 위해 기반 전송의 흐름 제어 메커니즘에게 해결하도록 허용해야 합니다. 이는 클라이언트가 다시 시도할 것으로 기대하며 연결을 종료하는 것보다 네트워크 혼잡을 악화시킬 수 있는 후자의 기술입니다.
메시지 본문을 전송하는 클라이언트는 요청을 전송하는 동안 네트워크 연결을 오류 응답에 대해 모니터링해야 합니다. 클라이언트가 서버가 메시지 본문을 받고 연결을 종료하고자 하지 않는다는 응답을 받으면 클라이언트는 즉시 본문 전송을 중단하고 자신의 연결을 종료해야 합니다.
6.6 Tear-down
Connection 헤더 필드(6.1절)는 발신자가 현재 요청/응답 쌍 이후에 연결을 종료하고자 할 때 보내야 하는 “close” 연결 옵션을 제공합니다.
“close” 연결 옵션을 포함한 요청 이후에 클라이언트는 해당 연결에서 더 이상의 요청을 보내지 않아야 하며, 이 요청에 해당하는 최종 응답 메시지를 읽은 후에 연결을 종료해야 합니다.
“close” 연결 옵션을 받은 서버는 “close”를 포함한 요청에 대한 최종 응답을 보낸 후에 연결을 종료해야 합니다. 서버는 해당 연결의 최종 응답에서 “close” 연결 옵션을 보내어야 합니다. 서버는 해당 연결에서 추가로 수신된 요청을 처리해서는 안 됩니다.
“close” 연결 옵션을 포함한 응답을 보낸 서버는 응답을 보낸 후에 연결을 종료해야 합니다. 서버는 해당 연결에서 추가로 수신된 요청을 처리해서는 안 됩니다.
“close” 연결 옵션을 받은 클라이언트는 “close”를 포함한 응답 메시지를 읽은 후에 해당 연결에서 요청을 보내지 않고 연결을 종료해야 합니다. 만약 해당 연결에 대해 파이프라인으로 보내진 추가 요청이 있었다면, 클라이언트는 이러한 요청이 서버에서 처리될 것으로 가정해서는 안 됩니다.
[page 57] 만약 서버가 TCP 연결을 즉시 닫는다면, 클라이언트가 마지막 HTTP 응답을 읽을 수 없는 큰 위험이 있습니다. 서버가 완전히 닫힌 연결에서 클라이언트로부터 추가 데이터를 수신하는 경우(예: 서버의 응답을 받기 전에 클라이언트가 보낸 다른 요청), 서버의 TCP 스택은 클라이언트에게 리셋 패킷을 보냅니다. 불행하게도, 리셋 패킷은 클라이언트의 확인되지 않은 입력 버퍼를 클라이언트의 HTTP 파서가 읽고 해석하기 전에 지울 수 있습니다.
TCP 리셋 문제를 피하기 위해 서버는 일반적으로 연결을 단계적으로 닫습니다. 먼저, 서버는 읽기/쓰기 연결의 쓰기 측만 닫아 반 닫힘(half-close)을 수행합니다. 그런 다음 서버는 클라이언트로부터 해당 연결의 대응하는 닫힘을 받을 때까지 계속해서 연결에서 읽기 작업을 수행하거나, 서버 자체의 TCP 스택이 서버의 마지막 응답을 포함하는 패킷의 클라이언트의 확인을 받은 것으로 충분히 확신할 때까지 계속해서 읽기 작업을 수행합니다. 마지막으로, 서버는 연결을 완전히 닫습니다.
리셋 문제가 TCP에만 존재하는지 아니면 다른 전송 연결 프로토콜에서도 발견될 수 있는지는 알 수 없습니다.
6.7 Upgrade
“Upgrade” 헤더 필드는 동일한 연결에서 HTTP/1.1에서 다른 프로토콜로 전환하기 위한 간단한 메커니즘을 제공하기 위해 사용됩니다. 클라이언트는 요청의 Upgrade 헤더 필드에 프로토콜 목록을 보낼 수 있으며, 이를 통해 서버에게 해당 프로토콜 중 하나 이상으로 전환할 것을 요청할 수 있습니다. 이때 프로토콜은 우선순위에 따라 내림차순으로 나열됩니다. 서버는 해당 연결에서 현재 프로토콜을 계속 사용하고자 할 경우 수신한 Upgrade 헤더 필드를 무시할 수 있습니다. Upgrade는 프로토콜 변경을 강요하는 데 사용할 수 없습니다.
Upgrade = 1#protocol
protocol = protocol-name ["/" protocol-version]
protocol-name = token
protocol-version = token
서버는 101 (프로토콜 전환) 응답을 보내면서 연결이 전환되는 새로운 프로토콜을 나타내기 위해 Upgrade 헤더 필드를 보내야 합니다. 여러 개의 프로토콜 레이어가 전환되는 경우, 전송자는 프로토콜의 계층 순서대로 나열해야 합니다. 서버는 대응하는 요청의 Upgrade 헤더 필드에 나타나지 않은 프로토콜로 전환해서는 안 됩니다. 서버는 클라이언트에 의해 지정된 선호도 순서를 무시하고 요청의 성격이나 서버의 현재 부하와 같은 다른 요소를 고려하여 새로운 프로토콜을 선택할 수 있습니다.
[page 58] 426 (Upgrade Required) 응답을 보내는 서버는 우선순위에 따라 허용 가능한 프로토콜을 나타내기 위해 Upgrade 헤더 필드를 보내야 합니다.
서버는 적절한 경우에 새로운 요청을 위해 나중에 사용될 수 있도록 프로토콜 업그레이드 지원을 알리기 위해 다른 응답에서도 Upgrade 헤더 필드를 보낼 수 있습니다.
다음은 클라이언트가 보낸 가상의 예시입니다:
`GET /hello.txt HTTP/1.1`
`Host: www.example.com`
`Connection: upgrade`
`Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11`
프로토콜 변경 후의 응용 프로그램 수준의 통신 기능 및 특성은 선택된 새로운 프로토콜에 완전히 의존합니다. 그러나 101 (프로토콜 전환) 응답을 보낸 직후에 서버는 새로운 프로토콜에 따른 상응하는 응답을 받은 것처럼 원래의 요청에 계속 응답해야 합니다. 즉, 프로토콜이 변경된 후에도 서버는 아직 처리되지 않은 요청을 만족시키기 위해 동일한 방식으로 응답해야 합니다. 이는 추가적인 라운드트립의 지연 비용 없이 HTTP와 동일한 의미를 가진 프로토콜로 연결을 업그레이드할 수 있도록 합니다. 서버는 새로운 프로토콜로 전환하지 않아야 합니다. 새로운 프로토콜에서 수신된 메시지 의미를 존중할 수 없는 경우입니다. OPTIONS 요청은 어떤 프로토콜에서도 지원될 수 있습니다.
[page 59] 다음은 위 가상의 요청에 대한 응답 예시입니다:
`HTTP/1.1 101 Switching Protocols`
`Connection: upgrade`
`Upgrade: HTTP/2.0`
`[... 데이터 스트림이 HTTP/2.0으로 전환되며 "GET /hello.txt" 요청에 대한 적절한 응답 (새로운 프로토콜에 정의된대로)이 이어집니다 ...]`
Upgrade가 전송될 때, 발신자는 또한 Upgrade가 목록에 있는 프로토콜을 구현하지 않을 수 있는 중간 프락시에서 우연히 전달되는 것을 방지하기 위해 “upgrade” 연결 옵션을 포함하는 Connection 헤더 필드(섹션 6.1)를 전송해야 합니다. 서버는 HTTP/1.0 요청에서 수신된 Upgrade 헤더 필드를 무시해야 합니다.
클라이언트는 요청 메시지를 완전히 보내기 전까지 업그레이드된 프로토콜을 연결에서 사용할 수 없습니다(즉, 클라이언트는 메시지 중간에서 보내는 프로토콜을 변경할 수 없습니다). 서버는 Upgrade와 함께 “100-continue” 기대값을 갖는 Expect 헤더 필드를 동시에 받으면 101 (Switching Protocols) 응답을 보내기 전에 100 (Continue) 응답을 보내야 합니다.
Upgrade 헤더 필드는 기존 연결 위에 프로토콜을 전환하기 위해서만 적용됩니다. 기존 통신을 다른 연결로 전환하거나 기존 연결의 기반(전송) 프로토콜을 전환하기 위해 사용할 수 없습니다. 이러한 목적을 위해서는 3xx (Redirection) 응답(섹션 6.4 of [RFC7231])을 사용하는 것이 더 적절합니다.
이 사양은 Hypertext Transfer Protocols 패밀리에 대해 “HTTP”라는 프로토콜 이름만을 정의합니다. 이는 섹션 2.6의 HTTP 버전 규칙과 이 명세서의 미래 업데이트에 따라 정의됩니다. 추가 토큰은 섹션 8.6에 정의된 등록 절차를 사용하여 IANA에 등록되어야 합니다.