【问题标题】:PRI method in http2 implementation causing issuehttp2实现中的PRI方法导致问题
【发布时间】:2018-10-30 05:59:40
【问题描述】:

我正在尝试使用 HTTP/2 扩展服务器,该服务器已经支持 HTTP/1.1TLS v1.2。我在 Go 中编写它,在那里我定义了这样的 tls 配置 -

tlsConfig := &tls.Config{
                    Certificates: []tls.Certificate{cert},
                    ServerName:   "mysrvr",
                    NextProtos:   []string{"h2", "http/1.1", "http/1.0"},
                    Time:         time.Now,
                    Rand:         rand.Reader,
            }

很明显,我使用“h2”字符串来设置 ALPN 握手。

现在当我通过 curl 发出请求时,我收到了这个请求 -

$ curl -v https://127.0.0.1:8000 -k --http2

当我解析请求时,它显示一个 PRI 方法首先发送而不是 GET -

HTTP/2.0
PRI

我从https://www.rfc-editor.org/rfc/rfc7540#page-78 获得了一些关于 PRI 方法的想法,其中说如下 -

This method is never used by an actual client.
This method will appear to be used when an HTTP/1.1 server or
intermediary attempts to parse an HTTP/2 connection preface. 

我现在的问题是为什么发送 PRI 请求,而服务器显然支持 HTTP/2?我是否需要根据 HTTP/2 规范解析它并使用空的 SETTINGS 帧进行响应,还是应该由 Go http2 运行时处理它?

我正在使用 http.ReadRequest 解析客户端请求,但即使我忽略 PRI 请求(如建议如下)。

【问题讨论】:

  • 当标准库包含一个已经支持 HTTP/2 的 HTTP 服务器时,为什么还要编写自己的 HTTP 服务器?重新发明轮子通常是个坏主意。
  • 我的用例有点不同。另外,我想通过这个实验更多地了解 Go 和 http2。

标签: http go http2


【解决方案1】:

HTTP/2 客户端应该发送的第一条消息就是这个 PRI 消息。来自HTTP/2 specification

在 HTTP/2 中,每个端点都需要发送一个连接前言作为对正在使用的协议的最终确认,并为 HTTP/2 连接建立初始设置。客户端和服务器各自发送不同的连接前言。

客户端连接前言以 24 个八位字节的序列开头,十六进制表示为:

0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a

即连接前言以字符串 PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n) 开头。此序列必须后跟一个 SETTINGS 帧(第 6.5 节),该帧可以为空。

...

注意:选择客户端连接前言,以便大部分 HTTP/1.1 或 HTTP/1.0 服务器和中介不会尝试处理更多帧。

这条消息的重点是它是一个假的类似 HTTP/1 的消息,因此任何不支持 HTTP/2 的服务器都应该以错误响应。

任何 HTTP/2 服务器都应该期待这个消息被发送,然后应该忽略它,然后继续说 HTTP/2。

事实上,如果这个消息没有被发送,那么服务器应该把它当作一个错误而不是继续:

客户端和服务器必须将无效的连接前言视为 PROTOCOL_ERROR 类型的连接错误(第 5.4.1 节)。在这种情况下,可以省略 GOAWAY 帧(第 6.8 节),因为无效的前言表明对等方未使用 HTTP/2。

【讨论】:

  • 所以问题仍然是我应该如何“忽略”它?我假设如果我再次从 tcp 连接读取,我应该得到 GET 请求。顺便说一句,我正在使用 Go 的 http.ReadRequest 来解析 http 请求并直接写入 TCP 连接。
  • 老实说,我不太了解 Go,但我想它应该透明地处理这个问题,并且如果你有支持 HTTP/2 的 Go,它就不会提供给你。您使用的是 Go 1.6 或更高版本吗?
  • 我使用的是 Go 1.10.2。令我困惑的是,当 ALPN 握手将协议设置为“h2”时,为什么 http2 请求甚至需要 PRI。
  • 因为 ALPN 是 TLS 的东西,技术上与 HTTP 无关。在 HTTP 层,它不知道选择了哪种 ALPN 方法(h2 或 http/1.1)——当然 Web 服务器会知道并且可以使用该知识来适当地处理请求。另一方面,虽然这对于 HTTP/2 协商的 h2 方法在技术上可能不需要,但它适用于所有其他 h2c 方法,我猜他们认为保持一致会更好。此外,还可以在边缘服务器上卸载 TLS 并将解密的消息发送到 h2c Web 服务器,因此需要它。
  • 我可以和一致性推理相处。在调试更多时,我发现我可以在连接前言之后直接从tcp连接读取一个blob(原始req),但是http.ReadRequest阻塞而不会抛出任何读取错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-04
  • 2019-11-21
  • 1970-01-01
  • 2017-06-22
  • 2020-07-23
  • 2010-10-30
相关资源
最近更新 更多