Apache RewriteRule丢弃SetInputFilter DEFLATE配置指令

时间:2017-07-06 14:22:46

标签: php apache .htaccess mod-rewrite mod-deflate

我有以下(简化)文件夹/文件结构:

/.htaccess
/test.php
/api/web/index.php

apache config中的以下指令:

<IfModule mod_deflate.c>
    <IfModule mod_filter.c>
        SetInputFilter DEFLATE
   </IfModule>
</IfModule>

我发送一个带有gzipped正文的POST请求,其中包含相应的标题:

POST /test.php HTTP/1.1
Host: 192.168.1.248
Authorization: Bearer ed717c077e4bf81201196011adb457731b24e19d
Content-Type: application/json
Content-Encoding: gzip

我有 .htaccess 文件的以下配置:

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^api/(.*) api/web/index.php/$1 [NC,L]

问题是,如果我发布到/test.php,一切都按预期工作,正文缩小,我可以恰到好处地访问解压缩的内容。

但是,如果我发布到重定向的内容(/api//api/v1/project),则index.php脚本无法解析主体。

我认为它必须与忽略RewriteRule指令的SetInputFilter指令相关,但是,我该如何避免这种情况呢?

我试图直接在.htaccess中添加SetInputFilter指令而不解决问题(可能它不在正确的位置?)。

你知道我怎么解决这个问题?

1 个答案:

答案 0 :(得分:2)

确实存在问题。我要做的更深入研究的第一件事是记录有关模块(rewritefilterdeflate)的踪迹。

mod_rewrite日志没问题,那里没有可疑之处。为确保一切正常,我查看了其source code的最新版本。再一次,关于编码/解码(也没有HTTP请求/响应头,更一般地)没有任何可疑之处。

因此,我开始认为问题可能来自filterdeflate模块,即使它也可能来自其他地方。为了确认/确认我的想法,我查看了这些模块日志。很快,我能够看到两个测试用例之间的区别:是否包含mod_rewrite

不涉及mod_rewrite

mod_deflate.c(1421): [client 127.0.0.1:53000] AH01393: Zlib: Inflated 35 to 41 : URL /test.php
mod_filter.c(188): [client 127.0.0.1:53000] Content-Type condition for 'deflate' matched

我以此为参考来比较下面的下一个案例

涉及到mod_rewrite

mod_filter.c(188): [client 127.0.0.1:53002] Content-Type condition for 'deflate' matched

有趣。实际上,看来mod_deflate是问题所在。我怀疑它的行动是在适当的时候 之后。这就是为什么在这种情况下,您看不到它的原因。

解决方案

到目前为止,太好了。所以呢 ?好吧,使用关键字mod_deflate too late快速搜索Apache的已知错误列表给了what I was searching for一个偶然的机会。这张名为mod_deflate adjusts the headers "too late"的票证载有以下内容:

  

使用mod_deflate进行充气时,它必须调整请求   标头(例如,它需要删除“ Content-Length”标头和   调整“ Content-Encoding”标头)。

     

当前,mod_deflate在请求正文为   读。但这为时已晚。例如,如果内容生成器模块   在读取请求正文之前,需要先查看请求标头,   内容生成器模块“看到”旧的(未修改的)标题。

     

mod_deflate应该在早期调整标头,例如   在修正挂钩(ap_hook_fixups)中。

尤里卡!这正是我们面临的问题。现在,好消息是有一个补丁可以解决此问题。坏消息:尚未对其进行审核/接受/合并。

您可以选择

  1. 应用此修补程序并重新编译服务器。它应该起作用,因为一切都有意义。 但是,要小心 ...这可能会引入其他错误/漏洞(即使经过审核/接受,有时也是如此)
  2. 请耐心等待将其包含在可用版本中(考虑到票证日期,可能需要很长时间)。届时,将自定义deflate与php一起使用。

更新

只需尝试应用补丁并重新编译mod_deflate。看起来它在正确的轨道上:它吞噬了Content-Encoding标头。无论如何,Content-Length仍然存在。结果:尚未解压缩。因此,仍有一些事情要做和适应,但是问题肯定在那个领域。

更新2(正在运行)

最后,我设法使其起作用。这是我应用于Apache(httpd version 2.4.34)的补丁:

diff --git a/modules/filters/mod_deflate.c b/modules/filters/mod_deflate.c
index 1428460..cc8c0cb 100644
--- a/modules/filters/mod_deflate.c
+++ b/modules/filters/mod_deflate.c
@@ -1099,10 +1099,10 @@ static apr_status_t deflate_in_filter(ap_filter_t *f,

         if (!ctx) {
             /* only work on main request/no subrequests */
-            if (!ap_is_initial_req(r)) {
+            /*if (!ap_is_initial_req(r)) {
                 ap_remove_input_filter(f);
                 return ap_get_brigade(f->next, bb, mode, block, readbytes);
-            }
+            }*/

             /* We can't operate on Content-Ranges */
             if (apr_table_get(r->headers_in, "Content-Range") != NULL) {

实际上,我也做了mod_deflate处理子请求。我不确定它不会破坏其他模块,但可以用于您的用例(更多是概念证明)。无论如何,我在上述机票上提出了我的补丁。这是结果的屏幕截图:

enter image description here