HTTP 升级

Envoy 升级主要用于支持 WebSocket 和 CONNECT 在 HTTP 请求中的的升级,同时也支持其他的升级。 升级操作通过 HTTP 过滤链来传递 HTTP header 和升级的负载信息。 除此之外也可以使用或者不使用自定义过滤链来配置 upgrade_configs 如果指定了 upgrade_type 的值,那么升级的 HTTP header 信息、请求体、返回体、HTTP 负载数据默认都将通过 HTTP 过滤器链。 此外为了避免升级负载仅使用 HTTP 过滤器,可以为给定的升级类型设置自定义的过滤器,同时也只能使用路由 filters 将数据发往上游。

升级可以根据 每个路由 配置来启用还是禁用。 同时任意的路由启用/禁用都会自动覆盖 HttpConnectionManager 配置信息。 如下图所示,自定义过滤器链只能基于每个 HttpConnectionManager 进行配置。

启用 HCM 升级

启用路由升级

启用升级

T (Default)

T (Default)

T

T (Default)

F

F

F

T (Default)

T

F

F

F

注意!所有升级的统计信息是绑定在一起的,例如 WebSocket 或者其它的 HTTP 升级都是通过 downstream_cx_upgrades_totaldownstream_cx_upgrades_active 来统计信息的。

HTTP/2 上的 WebSocket

默认情况下,HTTP/2 对 WebSocket 的支持都是关闭的,但 Envoy 却支持 WebSocket 在 HTTP/2 流上进行隧道传输,以便在整个部署过程中可以使用统一的 HTTP/2 网络。 例如,可以这样进行部署:

[Client] —- HTTP/1.1 —- [Front Envoy] —- HTTP/2 —- [Sidecar Envoy —- H1 —- App]

在上面的示例中,客户端需要使用 WebSocket,同时我们也希望 WebSocket 可以直接到达上游业务服务器,那就意味着只穿过 HTTP/2 即可到达。

上述实例中的方法是通过扩展连接( RFC8441 )支持实现的,通过在第二层 Envoy 中设置 allow_connect 打开的。 在 WebSocket 请求被转换为 HTTP CONNECT 流时,其中包含protocol 头指示原始升级、遍历跳转 HTTP/2 、降级回 HTTP/1.1 WebSocket Upgrade。 相同的 Upgrade-CONNECT-Upgrade 转换将会在任意 HTTP/2 上跳转执行,即假设 HTTP/1.1 中请求方法为 GET 。 非 WebSocket 升级则允许任何有效的 HTTP 方法(例如 POST 请求),当前的升级/降级机制也会丢弃原有的请求方式,最终Envoy 会将请求转换为去往上游的 GET 方法。

注意!HTTP/2 升级会非常严格的要求 HTTP/1.1 的路径,因此不能使用代理用于 WebSocket 升级的请求和响应。

CONNECT 支持

默认情况下,Envoy 内部的 CONNECT 支持都是处于关闭状态的(Envoy 会返回403 状态码以响应 CONNECT 请求)。 因此,可以通过上述的选项来启用 CONNECT 支持,其中将设置特殊关键字为 “CONNECT”。

在 HTTP/2 中,CONNECT 请求可能会是一个路径,但是在 HTTP/1.1 中,CONNECT 请求通常是没有路径的,只能使用 connect_matcher 进行匹配。

注意!当对 CONNECT 请求执行非通配符域匹配时,CONNECT 的目标是匹配主机和端口才能成功,而不是匹配 Host 或者授权信息。

Envoy 可以使用两种方法来处理 CONNECT 请求,一种是代理 CONNECT 报文头,让上游终止 CONNECT 请求,就类似于其他的请求一样;或者终止 CONNECT 请求,将负载信息作为原始 TCP 信息转发。

而当 CONNECT 升级配置信息被配置时,默认情况下就是使用代理连接请求,并使用升级路径将其处理为任何其他请求。

如果需要终止,也可以通过设置 connect_config 来完成。 如果仅仅只是针对 CONNECT 请求,路由过滤器将会去掉请求头,并将请求发往上游。 在收到来自上游的 TCP 数据时,路由就会生成 HTTP 200 响应头信息,然后将上游返回的 TCP 数据作为 HTTP 响应体。

Note

如果配置不正确,这种 CONNECT 支持连接会造成严重的安全漏洞。例如如果上游的安全漏洞存在于负载中,那么上游就会转发未经初始化的头信息。请谨慎使用!

HTTP/2 上的TCP 隧道

Envoy 还支持将原始 TCP 请求转化为 HTTP/2 CONNECT 请求,这是通过提前预备的安全链路来代理多路传输的 TCP 请求,并且可以分摊 TLS 握手的成本。 例如设置代理 SMTP 的流程如下:

[SMTP Upstream] — raw SMTP — [L2 Envoy] — SMTP tunneled over HTTP/2 — [L1 Envoy] — raw SMTP — [Client]

如果运行 bazel-bin/source/exe/envoy-static –config-path configs/encapsulate_in_connect.yaml –base-id 1 and bazel-bin/source/exe/envoy-static –config-path configs/terminate_connect.yaml 则能在示例配置 文件 中找到对应的示例。 其中将要运行两个 Envoy ,第一个会监听 10000 端口 上的 TCP 流量,接着会将其封装为 HTTP/2 请求;另一个会监听 10001 端口上的 HTTP/2 请求,去掉请求的请求头,接着将原始 TCP 请求转到上游,在本示例中是 google.com。