3. 背景
在 HTTP/1.1 [HTTP/1.1] 及更高版本中, 单个连接可以用于多个请求. 在 HTTP/2 [HTTP/2] 和 HTTP/3 [HTTP/3] 中, 这些请求可以被多路复用, 因为每个请求都由其 stream ID 显式区分. 然而, 在 HTTP/1.1 中, 请求严格按顺序处理, 每个新请求通过前一个请求的结束被隐式区分.
HTTP/1.1 也是唯一允许客户端改变连接剩余部分所用协议的 HTTP 版本. 有两种机制可用于请求这种协议转换. 一种机制是 Upgrade 头字段 ([HTTP], Section 7.8). 当请求中包含此字段时, 它表示客户端希望将该连接用于 HTTP/1.1 之外的协议. 如果服务器接受协议变更, 则以 101 (Switching Protocols) 状态码响应 ([HTTP], Section 15.2.2).
另一种机制是 HTTP CONNECT 方法 ([HTTP] 的 Section 9.3.6). 该方法表示客户端希望建立到指定主机和端口的 TCP 连接. 如果接受, 服务器会以 2xx (Successful) 响应表示请求已被接受且 TCP 连接已建立. 从此时起, 该 TCP 连接充当 TCP 隧道, 而不是 HTTP/1.1 连接.
这两种机制也都允许服务器拒绝请求. 例如, [HTTP] 的 Section 7.8 说:
如果服务器希望继续在该连接上使用当前协议, 可以忽略收到的 Upgrade 头字段.
[HTTP] 的 Section 9.3.6 说:
服务器必须拒绝目标为空端口号或无效端口号的 CONNECT 请求, 通常通过以 400 (Bad Request) 状态码响应来实现.
被拒绝的 upgrade 很常见, 并且可能由多种原因导致, 例如:
-
服务器不支持客户端指明的任何 upgrade token (即客户端提出的新协议), 因此继续使用 HTTP/1.1.
-
服务器要求客户端在升级协议前进行认证, 因此以 401 (Authentication Required) 状态码响应, 并在 Authorization 响应头字段中提供质询 ([HTTP], Section 11.6.2).
-
资源已移动, 因此服务器以 3xx (Redirection) 状态码响应 ([HTTP], Section 3.4).
类似地, 服务器也经常拒绝 HTTP CONNECT 请求, 例如:
-
服务器不支持 HTTP CONNECT.
-
根据服务器策略, 指定目标不被允许.
-
目标无法解析, 不可达, 或不接受连接.
-
代理要求客户端在继续之前进行认证.
在拒绝请求后, 服务器将继续按照 HTTP/1.1 解释在该连接上收到的字节.
[HTTP] 的 Section 7.8 还指出:
在完全发送请求消息之前, 客户端不能在该连接上开始使用升级后的协议 (即客户端不能在消息中途改变它正在发送的协议).
换句话说, 请求消息完成是客户端开始使用新协议的必要条件. 然而, 需要澄清的是, 这不是充分条件, 因为服务器可能会拒绝该请求.
在某些情况下, 客户端可能会预测服务器很可能接受所请求的协议转换. 例如, 如果最近使用某个 upgrade token 的请求成功了, 客户端可能预期后续使用同一 upgrade token 的请求也会成功. 如果这一预期正确, 客户端通常可以通过立即 "optimistically" 发送新协议的首批字节来减少延迟, 而无需等待服务器响应. 本文档探讨这种 "optimistic" 行为的安全影响.