一次 HTTP/2 通信失败的问题分析

背景

某业务上线 HTTP/2 以后,通过 curl 访问某接口一直失败。

cc212b5de73333d2db5efdc5a7c7eb21.png

开发人员怀疑可能是运维的 HTTP/2 配置不当导致访问失败,但是同样是配置 HTTP/2 的其它域名却是正常的,于是来一起看了一下这个问题。

排查

排查第一步:遇事不决先抓包,在没有任何先决信息的情况下,先抓包,看看传输了一些啥。因为 HTTP/2 要求通过 HTTPS 通信,所以这里抓包,还需要用到 wireshark 抓取 HTTPS 包的一些技巧。至于这么做,我在之前的 B 站分享有讲过,大家如果感兴趣可以看看。地址在这里:Wireshark 抓取 HTTPS 流量的 N 种方法「 https://www.bilibili.com/video/BV1ur4y1Y7NB 」

抓取 HTTPS 的包

简单来说,就是通过导出 premaster-secret 来帮助 wireshark 解密数据。wireshark ssl keylog 格式长啥样,具体的定义在 https://github.com/boundary/wireshark/blob/master/epan/dissectors/packet-ssl-utils.c#L4183

9ac554686ee22e7561671c25612ae22f.png
wireshark ssl keylog 格式

curl 要做的就是把 key 打印到文件里,这部分的源码在:https://github.com/curl/ lib/vtls/keylog.c ,如下图所示。

5899b33d89a930d4d85a5c3b67403621.png
curl 源码

对于 curl 而言,我们只需要指定一个环境变量就可以了,抓取的包我们就可以解密出来了。

export SSLKEYLOGFILE=/Users/arthur/keylog.txt

wireshark 解密出来的结果如下。

6ace9a73686c4909394bd3aee3b9face.png
wireshark 解密结果

看起来就是 HTTP2 服务端的问题发了一个错误的包导致客户端回了 rst 帧。

接下来继续看 HTTP/2 服务端回复了什么。通过查看包,果然发现了一些有意思的。

17aa08824583b077b5818ede1b3da684.png
wireshark 包结果

expires 头部后面多了一个空格,其它的 header 都没有。怀疑是这个导致的,同时发现通过增加一个 Cache-Control 请求头,返回结果里 expires 头部就没有返回了,请求就成功了,因此更加确认是这个问题。

curl -H 'Cache-Control: max-age=0'  -v  https://license.bytello.com/licenseAdmin/test

返回结果如图

6c2b63ca092ee2cde77b1af85987096e.png

通过跟业务确认,确实如此,expires 后面多了一个空格,去掉以后马上访问正常了。

59bcfd3a0910cb8ef5dd96b8dd84f0c5.png
Expires 头

在 HTTP/1.1 时代,curl 是合法的,没有问题,在 HTTP/2 中,这里就有问题了。

当然这依然不能直接证明就是这个原因,除非 curl 亲自告诉我。

进一步分析

为什么有空格会出现问题呢?当然要从 curl 的底层去分析,curl 的 HTTP/2 底层是用 nghttp 这个库来实现的,nghttp 本来也可以通过命令行直接发起请求。

使用 nghttp 访问一下,印证了我们的想法。

6975994d06fce3adeb34c2c4439396f0.png
nghttp 访问结果

探究源码

nghttp 是一个开源项目,可以很方面的把源码 clone 下来编译本地调试,发现他在处理 header 的时候会判定 header 是否合法

90eed69823e0d9e2c6166ec617edefe2.png 7b47dc97f01f9b332436d05f42ef9284.png

合法非法的 ASCII 字符在这里定义

d22c4ef56cf26e465c917f2e5f6cd0a8.png

可以看到空格,也就是下图中的 SPC,ASCII 码值是:32(0x20),对应的 VALID 为 0,表示空格是非法的 header 字符。

通过 GDB 同步确认这一点

2ae57a2fc12babcec0de744ac704f65c.png
GDB 调试

至此,我们就知道了为什么 curl 在处理带有空格头部时的问题,chrome、safari 也有类似的问题,大家感兴趣可以看看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值