块末尾的意外内容 - 是什么构建了损坏的流?



我正在访问一个返回大约 900k XML 的端点。 时不时地(在今天的测试中不到 1/5000(我得到一个 MalformChunkCodingException

这是从一个相当古老的网络应用程序(~10 年(发生的,它建立在 Spring 3 上。 我改用RestTemplate而不是直接使用httpclient,但这并没有解决它。 今天在httpclient上启用了线级日志记录运行了几个小时后,我设法捕获了一个。

Caused by: org.apache.http.MalformedChunkCodingException: Unexpected content at the end of chunk
at org.apache.http.impl.io.ChunkedInputStream.getChunkSize(ChunkedInputStream.java:259)
at org.apache.http.impl.io.ChunkedInputStream.nextChunk(ChunkedInputStream.java:227)
at org.apache.http.impl.io.ChunkedInputStream.read(ChunkedInputStream.java:186)
at org.apache.http.conn.EofSensorInputStream.read(EofSensorInputStream.java:137)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.Reader.read(Reader.java:140)
at org.springframework.util.StreamUtils.copyToString(StreamUtils.java:74)
at org.springframework.http.converter.StringHttpMessageConverter.readInternal(StringHttpMessageConverter.java:85)
at org.springframework.http.converter.StringHttpMessageConverter.readInternal(StringHttpMessageConverter.java:40)
at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:153)
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:103)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:724)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:709)

通常日志似乎是这样的:

DEBUG org.apache.http.wire - << "words words words"
DEBUG org.apache.http.wire - << "[r][n]"
DEBUG org.apache.http.wire - << "FAF[r][n]"
DEBUG org.apache.http.wire - << "words words words up to FAF bytes" 
DEBUG org.apache.http.wire - << "[r][n]"
DEBUG org.apache.http.wire - << "BAA[r][n]"
DEBUG org.apache.http.wire - << "words words words up to BAA bytes"

但是在出错的那个中,我有这个:

DEBUG org.apache.http.wire - << "words words words"
DEBUG org.apache.http.wire - << "[r][n]"
DEBUG org.apache.http.wire - << "B50[r][n]"
DEBUG org.apache.http.wire - << "words words words up to B50 bytes"
DEBUG org.apache.http.wire - << "3FC0[r][n]"

它缺少 B50 块末尾的 [\r][]。

因此,假设我可以信任org.apache.http.wire调试,那么我的应用程序正在接收这样的流,并且它的格式不正确。 它们之间的 haproxy 是否有可能破坏流?

幸运的是,或者不是,对话的另一端也是我的应用程序之一,在 Spring 4.2.4 的 tomcat 中运行。

我从哪里开始寻找谁在构建该无效响应? 春天? 雄猫?

看起来我可以禁用分块,但只是我在构建响应时计算我的内容长度,我不太热衷于这样做,因为那样我将不得不手动序列化我的响应,而不是让 Spring 这样做。

正如你所说,该应用程序已经很旧了。您可能需要更新所有库版本,希望该问题已在某处检测到并修复。

但是找到坏演员会有所帮助,因为你只需要修复那个。

根据我自己在HTTP工具中测试不良语法支持的经验,我很确定Haproxy是您列出的元素中更强大的元素。但这并不排除那里的问题。

发送和接收端点之间的每个 HTTP 参与者都可以更改 HTTP 正文(重新设计块大小(,因此您需要捕获所有参与者(spring、tomcat、haproxy、任何其他代理和/或反向代理、负载均衡器、SSL 终止符(的输入和输出以检测坏块。我将从消息发射器(XML 端点(开始。我会使用 wireshark/pcap/httpdump,它真正捕获了 TCP 和 HTTP 流量。但是,您可能需要找到一种方法来快速丢弃捕获,直到达到故障点,因为 1/5000 意味着您有很大的风险捕获大量数据。

我花了一个月的大部分时间对此进行测试。 虽然我缺乏100%确定的答案,但我发现:

使用 haproxy 版本 1.7.x 运行时,我无法触发错误。

使用 haproxy 版本 2.0.x 运行时,我偶尔会触发错误。

它可能与此相关,也可能与此无关:

https://github.com/haproxy/haproxy/issues/171

最新更新