HTTP/1.1
1. Introduction
HTTP/1.1
HTTP(Hypertext Transfer Protocol)是一种无状态的应用层协议,用于分布式、协作式的超文本信息系统。HTTP/1.1 版本定义了消息语法、消息解析、连接管理及相关的安全问题。
2. Message
2.1 Message Format
HTTP/1.1 消息由一个起始行(start-line),后跟一个 CRLF(回车换行),然后是零个或多个头字段行(header fields),再一个空行表示头部结束,最后是可选的消息体(message body)。
2.2 Message Parsing
解析 HTTP 消息时,必须将消息视为 US-ASCII 编码的八位字节序列。解析时需特别注意避免安全漏洞,例如单独的 LF 字符可能会导致解析错误。
2.3 HTTP Version
HTTP 使用 "<major>.<minor>" 的版本号格式。HTTP/1.1 消息的版本在起始行中通过 HTTP-version 字段指示。
3. Request Line
3.1 Method
请求方法(method)是一个标记,用于指示对目标资源执行的操作。请求方法是区分大小写的。
3.2 Request Target
请求目标(request-target)标识要应用请求的目标资源。它有四种格式:origin-form、absolute-form、authority-form 和 asterisk-form。
3.2.1 origin-form
这是最常见的请求目标形式,通常用于直接向原始服务器发送请求。
3.2.2 absolute-form
用于向代理服务器发送请求,包含完整的 URI。
3.2.3 authority-form
仅用于 CONNECT 请求,包含主机和端口。
3.2.4 asterisk-form
仅用于服务器范围的 OPTIONS 请求。
4. Status Line
响应消息的第一行是状态行(status-line),包含协议版本、状态码和可选的原因短语。
5. Field Syntax
每个头字段行由不区分大小写的字段名、冒号、可选的前导空白、字段值和可选的尾随空白组成。
6. Message Body
消息体用于携带请求或响应的内容。消息体的存在由 Content-Length 或 Transfer-Encoding 头字段指示。
6.1 Transfer-Encoding
Transfer-Encoding 头字段列出了应用于内容的传输编码。接收者必须能够解析 chunked 传输编码,因为它在内容大小未知时起着至关重要的作用。
6.2 Content-Length
Content-Length 头字段提供了消息体的预期大小(以八位字节为单位)。如果消息包含 Transfer-Encoding 头字段,则不得包含 Content-Length 头字段。
6.3 Message Body Length
消息体的长度由以下规则确定(按优先顺序):
- 对于 HEAD 请求的任何响应,以及状态码为 1xx、204 或 304 的响应,消息体长度为零。
- 对于 CONNECT 请求的 2xx 响应,消息体长度为零。
- 如果同时存在 Transfer-Encoding 和 Content-Length,Transfer-Encoding 优先。
- 如果存在 Transfer-Encoding 且最终编码为 chunked,则通过解码 chunked 数据确定消息体长度。
- 如果存在无效的 Content-Length,则视为不可恢复的错误。
- 如果存在有效的 Content-Length,则其值为消息体长度。
- 如果是请求消息且不符合上述任何条件,则消息体长度为零。
- 否则,响应消息的长度由服务器关闭连接前接收到的八位字节数决定。
7. Transfer Codings
传输编码用于指示应用于消息内容的编码转换,以确保安全传输。所有传输编码名称不区分大小写。
7.1 Chunked Transfer Coding
chunked 传输编码将内容分块传输,每个块都有自己的大小指示符,最后是一个可选的 trailer 部分。chunked 编码允许传输未知大小的内容流。
7.2 Transfer Codings for Compression
定义了以下压缩传输编码名称:compress、deflate 和 gzip。
8. Handling Incomplete Messages
服务器接收到不完整的请求消息时,可以在关闭连接之前发送错误响应。客户端接收到不完整的响应消息时,必须将其记录为不完整。
9. Connection Management
HTTP 消息传输独立于底层传输或会话层连接协议。HTTP 仅假定可靠的传输和按顺序传递请求和响应。
9.3 Persistence
HTTP/1.1 默认使用持久连接,允许在单个连接上传输多个请求和响应。接收者根据协议版本和 Connection 头字段确定连接是否持久。
9.3.2 Pipelining
支持持久连接的客户端可以并行发送多个请求(即流水线化请求)。服务器可以并行处理这些请求,但必须按接收顺序发送响应。
9.4 Concurrency
客户端应限制与给定服务器的同时打开连接数。尽管没有强制的最大连接数,但鼓励客户端在打开多个连接时要保守。
9.6 Tear-down
"close" 连接选项用于指示发送方将在响应完成后关闭连接。
9.7 TLS Connection Initiation
HTTP/TLS 是通过 TLS 连接发送 HTTP 消息。客户端在适当的端口上发起连接并发送 TLS ClientHello 开始握手。
9.8 TLS Connection Closure
TLS 使用关闭警报交换来提供安全的连接关闭。当接收到有效的关闭警报时,表示不会再接收到数据。
10. Enclosing Messages as Data
10.1 Media Type message/http
"message/http" 媒体类型可用于封装单个 HTTP 请求或响应消息。
10.2 Media Type application/http
"application/http" 媒体类型可用于封装一个或多个 HTTP 请求或响应消息(不混合)。
11. Security Considerations
11.1 Response Splitting
响应拆分(CRLF 注入)是一种常见攻击技术,利用 HTTP 消息框架的行基性质和持久连接上请求与响应的有序关联。
11.2 Request Smuggling
请求走私是一种利用不同接收者之间协议解析差异的技术,隐藏附加请求以绕过策略限制。
11.3 Message Integrity
HTTP 没有定义特定的消息完整性机制,而是依赖底层传输协议的错误检测能力和长度或分块定界框架来检测完整性。
11.4 Message Confidentiality
HTTP 依赖底层传输协议提供消息机密性。"https" 方案可用于标识需要机密连接的资源。
12. IANA Considerations
IANA 更新了以下注册表:
12.1 Field Name Registration
新增了以下字段名到 "Hypertext Transfer Protocol (HTTP) Field Name Registry":
- Close
- MIME-Version
- Transfer-Encoding
12.2 Media Type Registration
更新了 "Media Types" 注册表,新增了 "message/http" 和 "application/http" 媒体类型。
12.3 Transfer Coding Registration
更新了 "HTTP Transfer Coding Registry",新增了以下传输编码名称:
- chunked
- compress
- deflate
- gzip
- trailers (reserved)
- x-compress (deprecated)
- x-gzip (deprecated)
12.4 ALPN Protocol ID Registration
更新了 "TLS Application-Layer Protocol Negotiation (ALPN) Protocol IDs" 注册表,新增了 "HTTP/1.1" 协议 ID。
ABNF
BWS = <BWS, see [HTTP], Section 5.6.3>
HTTP-message = start-line CRLF *( field-line CRLF ) CRLF [ message-body ]
HTTP-name = %x48.54.54.50 ; HTTP
HTTP-version = HTTP-name "/" DIGIT "." DIGIT
OWS = <OWS, see [HTTP], Section 5.6.3>
RWS = <RWS, see [HTTP], Section 5.6.3>
Transfer-Encoding = [ transfer-coding *( OWS "," OWS transfer-coding ) ]
absolute-URI = <absolute-URI, see [URI], Section 4.3>
absolute-form = absolute-URI
absolute-path = <absolute-path, see [HTTP], Section 4.1>
asterisk-form = "*"
authority = <authority, see [URI], Section 3.2>
authority-form = uri-host ":" port
chunk = chunk-size [ chunk-ext ] CRLF chunk-data CRLF
chunk-data = 1*OCTET
chunk-ext = *( BWS ";" BWS chunk-ext-name [ BWS "=" BWS chunk-ext-val ] )
chunk-ext-name = token
chunk-ext-val = token / quoted-string
chunk-size = 1*HEXDIG
chunked-body = *chunk last-chunk trailer-section CRLF
field-line = field-name ":" OWS field-value OWS
field-name = <field-name, see [HTTP], Section 5.1>
field-value = <field-value, see [HTTP], Section 5.5>
last-chunk = 1*"0" [ chunk-ext ] CRLF
message-body = *OCTET
method = token
obs-fold = OWS CRLF RWS
obs-text = <obs-text, see [HTTP], Section 5.6.4>
origin-form = absolute-path [ "?" query ]
port = <port, see [URI], Section 3.2.3>
query = <query, see [URI], Section 3.4>
quoted-string = <quoted-string, see [HTTP], Section 5.6.4>
reason-phrase = 1*( HTAB / SP / VCHAR / obs-text )
request-line = method SP request-target SP HTTP-version
request-target = origin-form / absolute-form / authority-form / asterisk-form
start-line = request-line / status-line
status-code = 3DIGIT
status-line = HTTP-version SP status-code SP [ reason-phrase ]
token = <token, see [HTTP], Section 5.6.2>
trailer-section = *( field-line CRLF )
transfer-coding = <transfer-coding, see [HTTP], Section 10.1.4>
uri-host = <host, see [URI], Section 3.2.2>