Tomcat 9:头行不符合RFC 7230

3

我有一个应用程序在Tomcat 8.5.38上运行良好。现在我决定升级到Tomcat 9.0.27,但GET请求和RFC 7230,超文本传输协议(HTTP/1.1):消息语法和路由出现问题。

请求如下:

/api/vehicle/power_off?vehicleId=1428714&dtStart=2019-10-21 08:00:00&dtEnd=2019-10-21 08:30:00

它在任何浏览器(IE,Opera,Chrome,FF)和另一客户端(1C ERP系统)上都能够完美地工作。

升级后,从浏览器访问仍然可以完美地工作,但是从1C访问时出现错误。Tomcat显示以下错误:

28-Oct-2019 17:29:26.201 INFO [http-nio-8080-exec-3] org.apache.coyote.http11.Http11Processor.service Error parsing HTTP request header
 Note: further occurrences of HTTP request parsing errors will be logged at DEBUG level.
    java.lang.IllegalArgumentException: The HTTP header line [get /api/vehicle/power_off?deviceId=1428714&dtStart=2019-10-21%2008:00:00&dtEnd=2019-10-21%2008:30:00 HTTP/1.1: ] does not conform to RFC 7230 and has been ignored.
        at org.apache.coyote.http11.Http11InputBuffer.skipLine(Http11InputBuffer.java:962)
        at org.apache.coyote.http11.Http11InputBuffer.parseHeader(Http11InputBuffer.java:825)
        at org.apache.coyote.http11.Http11InputBuffer.parseHeaders(Http11InputBuffer.java:564)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:309)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1587)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:748)

我在我的开发机(MacOS + Tomcat 9.0.24)和生产服务器(Ubuntu 16.04 + Tomcat 9.0.27)上都遇到了同样的错误。

导致这个错误的原因是日期时间参数中的冒号。当我从查询字符串中删除冒号(只留下“2019-10-21 080000”)时,请求按预期工作(出现“无法解析日期时间”的错误)。另外,当我手动将冒号更改为“%3A”时,请求也可以正常返回结果。

然后我在Tomcat Connector中添加了relaxedQueryChars参数来允许冒号(尽管冒号是被允许的符号):

relaxedQueryChars=':[]|{}^\`"<>'

它仍然失败。

在Tomcat 8和9版本之间,我的请求能够在8中正常工作,但在9中却不行。在Tomcat中是否有任何我可以做的事情来使该请求成功?更改客户端请求很困难...

2个回答

3
“我的请求在Tomcat 8中可以工作,但在9中不能,这两个版本有什么区别?”
我认为问题在于Tomcat 9.x收紧了URL中未编码的内容应该允许的范围,所以从技术角度来看,Tomcat 9.x没有问题;问题出在早期的Tomcat版本和浏览器没有严格遵循规范。尽管如此,我无法确定是否有任何特定的修复措施导致了您的问题,也没有在 发布说明 中找到任何信息。
“我向Tomcat Connector添加了relaxedQueryChars参数,使用冒号(虽然冒号是允许的符号)……但它仍然失败。”
根据 Tomcat 9.0文档 中的描述,relaxedQueryChars 参数应该被设置为一个字符串,其中包含允许在查询字符串中未经转义的字符。
HTTP/1.1规范要求在URI查询字符串中使用某些字符时进行%nn编码。不幸的是,包括所有主流浏览器在内的许多用户代理程序都不符合此规范,并以未编码的形式使用这些字符。为了防止Tomcat拒绝此类请求,可以使用此属性指定要允许的其他字符。如果未指定,则不允许任何其他字符。值可以是以下任意组合的字符:" < > [ \ ] ^ ` { | } . 值中存在的任何其他字符将被忽略。

请注意最后两个句子。冒号字符没有被提到,因此"将被忽略"。

有什么我可以在Tomcat中做的来使这个请求工作吗?

我认为没有,但真正的问题是您没有对参数中的冒号进行编码,而且您已经提到了这解决了问题。请参见此SO答案,特别是最后一句话:

There are reserved characters, that have a reserved meanings, those are delimiters — :/?#[]@ — and subdelimiters — !$&'()*+,;=

There is also a set of characters called unreserved characters — alphanumerics and -._~ — which are not to be encoded.

That means, that anything that doesn't belong to unreserved characters set is supposed to be %-encoded, when they do not have special meaning (e.g. when passed as a part of GET parameter).

冒号是一个具有特殊含义的保留字符,因此必须在参数中进行编码。

注:


感谢澄清。虽然我仍然不明白为什么浏览器可以正常工作——我已经使用Wireshark检查了请求,它们是相同的。无论如何,我决定要求客户对其请求进行编码,这将保证其正常工作。 - zhoriq

0
在我的情况下,我通过手动添加新的 cookie 到 Curl 请求来增加请求头大小。在这样做时,使用了 ENTER 键而不是空格。退格并使用空格代替解决了我的问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接