Skip to content

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

消息体的长度由以下规则确定(按优先顺序):

  1. 对于 HEAD 请求的任何响应,以及状态码为 1xx、204 或 304 的响应,消息体长度为零。
  2. 对于 CONNECT 请求的 2xx 响应,消息体长度为零。
  3. 如果同时存在 Transfer-Encoding 和 Content-Length,Transfer-Encoding 优先。
  4. 如果存在 Transfer-Encoding 且最终编码为 chunked,则通过解码 chunked 数据确定消息体长度。
  5. 如果存在无效的 Content-Length,则视为不可恢复的错误。
  6. 如果存在有效的 Content-Length,则其值为消息体长度。
  7. 如果是请求消息且不符合上述任何条件,则消息体长度为零。
  8. 否则,响应消息的长度由服务器关闭连接前接收到的八位字节数决定。

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

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>