jetty引发的两个bug
给存储实现了s3协议已经一段时间, 最近同事测试反馈偶尔会出现上传对象失败
上传对象, 如果key带%,就会失败
现象
上传文件时, 如果指定对象key带%,就会失败,直接返回400 Bad Message.
分析
我看了服务器后台日志,发现上传请求,还没有开始处理就返回了. 应该是jetty层就已经解码出了问题.
打开jetty debug日志, 发现 org.eclipse.jetty.http.BadMessageException: 400: Ambiguous URI empty segment
看了一下githhub issue, 原来是jetty遵守rfc要求, 默认的UriCompliance过于严格.
Error 400 – Ambiguous URI Empty Segment · Issue #11298 · jetty/jetty.project
解决方案
创建 ServletWebServerFactory时,自定义jetty配置, 指定使用 UriCompliance.LEGACY.
使用juicesync 从minio往我们存储s3迁移时,有个别对象迁移失败.
现象
同事使用juicesync从minio往s3gw 迁移数据时,发现有个别对象出现迁移失败, 原因是aws sign v4签名认证错误.
分析
s3gw 实现了aws signature v4, 并且是根据官网说明实现的.
打开juicesync 的aws-sdk-go debug日志
下载juicefs 和 juicesync , 修改juicesync 的go.mod指向本地版本的juicefs
[wjh@node1 juicesync]$ cat go.mod |grep replace
replace github.com/juicedata/juicefs v1.2.2 => ../juicefs
修改’juicefs/pkg/object/s3.go’ awsConfig, 设置debug日志,重新编译juicesync
awsConfig := &aws.Config{
Region: ®ion,
DisableSSL: aws.Bool(!ssl),
HTTPClient: httpClient,
LogLevel: aws.LogLevel(aws.LogDebugWithSigning), //打开aws-sdk-go debug日志
}
出错地方
对比客户端和服务端签名时,拼接的字符串, 发现
- 客户端计算的Canonical Headers 中是 ‘Content-Type::text/xml; charset=utf-8’
- 服务端端计算的Canonical Headers 中是 ‘Content-Type::text/xml; charset=UTF-8’
编码的地方大小写不一样.
问题是出现在客户端呢? 还是服务端呢?
客户端发送的请求出来的 conten-type中utf-8是小写的. 那么问题应该是发生在服务器端.
服务器端是通过spring-boot + jetty 提供http服务的.
使用arthas watch,发现 org.eclipse.jetty.ee10.servlet.FilterHolder.doFilter时 请求的 conten-type中utf-8已经是大写的.
- 查看网上资料也没有说, spring会修改过请求头.
-
反而看到网上说,jetty会缓存一些请求头, 减少解析请求开销. 并且jetty是遵守rfc 标准的, rfc 标准对conten-type中utf-8不区分大小写.
https://github.com/jetty/jetty.project/blob/jetty-12.0.x/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java 看到有CACHE实现
https://github.com/jetty/jetty.project/blob/6986b18ecb2d6d4ed7288cd92d9a0c1eb8a29d28/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java#L480 可以设置HeaderCacheCaseSensitive
最后通过自定义配置jetty, setHeaderCacheCaseSensitive(true), 签名错误的问题终于解决了.
总结
这两个问题,严格来说不算哪一方的bug, 就是双方的标准有冲突, 这里主要目的是实现对象存储功能, 因此调整jetty配置适应aws s3协议.