2. 消息
HTTP/1.1 客户端和服务器通过发送消息进行通信. 有关 HTTP 的通用术语和核心概念, 参见 [HTTP] 的 Section 3.
2.1. 消息格式
HTTP/1.1 消息由起始行 (start-line) 后接 CRLF, 再后接一串八位组组成, 其格式类似于 Internet Message Format [RFC5322]: 零个或多个头部字段行 (统称为 "headers" 或 "header section"), 一个表示头部区段结束的空行, 以及一个可选的消息体 (message body).
HTTP-message = start-line CRLF
*( field-line CRLF )
CRLF
[ message-body ]
消息可以是从客户端发往服务器的请求, 也可以是从服务器发往客户端的响应. 从语法上看, 这两类消息只在起始行上不同: 请求使用请求行 (request-line), 响应使用状态行 (status-line); 另一个差异在于确定消息体长度的算法 (Section 6).
start-line = request-line / status-line
理论上, 客户端可以接收请求, 服务器也可以接收响应, 并通过不同的起始行格式区分二者. 实践中, 服务器实现只预期收到请求 (响应会被解释为未知或无效的请求方法), 客户端实现只预期收到响应.
HTTP 使用了一些类似于多用途 Internet 邮件扩展 (Multipurpose Internet Mail Extensions, MIME) [RFC2045] 的协议元素. HTTP 消息与 MIME 消息之间的差异参见 Appendix B.
2.2. 消息解析
解析 HTTP 消息的通常过程是: 将起始行读入一个结构, 随后按字段名称将每个头部字段行读入哈希表, 直到空行, 然后使用已解析的数据判断是否预期存在消息体. 如果已指示存在消息体, 则以流的形式读取它, 直到读取到与消息体长度相等的八位组数量, 或者连接被关闭.
接收方 MUST 将 HTTP 消息解析为八位组序列, 所用编码必须是 US-ASCII [USASCII] 的超集. 如果不考虑具体编码, 将 HTTP 消息解析为 Unicode 字符流, 会因字符串处理库对包含 LF (%x0A) 八位组的无效多字节字符序列处理方式不同而产生安全漏洞. 基于字符串的解析器只能在某个协议元素已经从消息中提取出来之后, 才能在该元素内部安全使用; 例如, 在消息解析已划分出各个字段行之后, 才能在头部字段行值内部使用.
虽然起始行和字段的行终止符是 CRLF 序列, 接收方 MAY 将单个 LF 识别为行终止符, 并忽略其前面的任何 CR.
发送方 MUST NOT 在内容以外的任何协议元素中生成裸 CR (未紧跟 LF 的 CR 字符). 接收到此类裸 CR 的接收方 MUST 将该元素视为无效, 或者在处理该元素或转发消息之前, 将每个裸 CR 替换为 SP.
较早的 HTTP/1.0 用户代理实现可能会在 POST 请求之后发送一个额外的 CRLF, 以绕过某些早期服务器应用无法读取未以行尾结束的消息体内容的问题. HTTP/1.1 用户代理 MUST NOT 在请求之前或之后添加额外的 CRLF. 如果希望用行尾结束请求消息体, 则用户代理 MUST 将终止用的 CRLF 八位组计入消息体长度.
为了增强鲁棒性, 预期接收并解析请求行的服务器 SHOULD 忽略请求行之前收到的至少一个空行 (CRLF).
发送方 MUST NOT 在起始行与第一个头部字段之间发送空白.
接收方如果收到位于起始行与第一个头部字段之间的空白, MUST 要么将该消息作为无效消息拒绝, 要么逐行消耗每个前导空白行且不对其做进一步处理 (即忽略整行, 以及之后任何同样以前导空白开始的行, 直到收到格式正确的头部字段或头部区段结束). 拒绝或移除无效的前导空白行是必要的, 以防止下游接收方误解这些行; 下游接收方可能容易受到请求走私 (Section 11.2) 或响应拆分 (Section 11.1) 攻击.
当一个只监听 HTTP 请求消息的服务器, 或正在处理一个从起始行看起来像 HTTP 请求消息的服务器, 收到一串不匹配 HTTP-message 语法的八位组 (上述鲁棒性例外除外) 时, 服务器 SHOULD 以 400 (Bad Request) 响应并关闭连接.
2.3. HTTP 版本
HTTP 使用 "<major>.<minor>" 编号方案表示协议版本. 本规范定义版本 "1.1". [HTTP] 的 Section 2.5 规定了 HTTP 版本号的语义.
HTTP/1.x 消息的版本由起始行中的 HTTP-version 字段表示. HTTP-version 区分大小写.
HTTP-version = HTTP-name "/" DIGIT "." DIGIT
HTTP-name = %s"HTTP"
当 HTTP/1.1 消息被发送给 HTTP/1.0 接收方 [HTTP/1.0] 或版本未知的接收方时, HTTP/1.1 消息的构造方式应使得在忽略所有较新特性时, 它能被解释为有效的 HTTP/1.0 消息. 本规范对某些新特性规定了接收方版本要求, 使符合规范的发送方在通过配置或收到消息确认接收方支持 HTTP/1.1 之前, 只使用兼容特性.
处理 HTTP 消息的中间件 (即除充当隧道者以外的所有中间件) MUST 在转发消息中发送自己的 HTTP-version, 除非它是为规避上游问题而有意降级. 换言之, 中间件不得盲目转发起始行, 而必须确保该消息中的协议版本与该中间件在接收和发送消息时均符合的版本匹配. 转发 HTTP 消息而不重写 HTTP-version 可能导致通信错误, 因为下游接收方会使用消息发送方的版本来判断后续与该发送方通信时哪些特性可以安全使用.
如果已知或怀疑客户端未正确实现 HTTP 规范, 且无法正确处理较新版本的响应, 服务器 MAY 对 HTTP/1.1 请求发送 HTTP/1.0 响应; 例如客户端无法正确解析版本号, 或已知某个中间件即使不符合给定协议次版本也会盲目转发 HTTP-version. 除非由特定客户端属性触发, 例如一个或多个请求头部字段 (如 User-Agent) 与已知有误的客户端发送值唯一匹配, 否则 SHOULD NOT 执行此类协议降级.