Apache RewriteRule 丢弃 SetInputFilter DEFLATE 配置指令

Sup*_*Rey 5 php apache .htaccess mod-rewrite mod-deflate

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

/.htaccess
/test.php
/api/web/index.php
Run Code Online (Sandbox Code Playgroud)

以及 apache 配置中的以下指令:

<IfModule mod_deflate.c>
    <IfModule mod_filter.c>
        SetInputFilter DEFLATE
   </IfModule>
</IfModule>
Run Code Online (Sandbox Code Playgroud)

我正在发送一个带有 gzipped 正文的 POST 请求,其中包含适当的标头:

POST /test.php HTTP/1.1
Host: 192.168.1.248
Authorization: Bearer ed717c077e4bf81201196011adb457731b24e19d
Content-Type: application/json
Content-Encoding: gzip
Run Code Online (Sandbox Code Playgroud)

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

RewriteEngine On

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

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

但是,如果我发布到重定向(/api//api/v1/project)的内容,则index.php脚本不会解压缩正文。

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

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

你知道我该如何解决这个问题吗?

Jus*_*man 5

确实,有问题。为了进行更深入的调查,我所做的第一件事是记录相关模块的痕迹(rewritefilterdeflate)。

mod_rewrite 日志正常,没有任何可疑之处。为了确保一切都正常,我查看了其源代码的最新版本。再说一遍,关于编码/解码(更一般地说,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
Run Code Online (Sandbox Code Playgroud)

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

涉及mod_rewrite

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

有趣的。事实上,这看起来就是mod_deflate问题所在。我怀疑它的行动是适当的时机。这就是为什么在本例中您看不到它实际运行的原因。

解决方案

到目前为止,一切都很好。所以呢 ?好吧,用关键字快速搜索 Apache 的已知错误列表mod_deflate too late,偶然地找到了我要搜索的内容。这张名为mod_deflate 的票据“太晚”调整了标头,声明如下:

当mod_deflate用于inflate时,它必须调整请求头(例如需要删除“Content-Length”头并调整“Content-Encoding”头)。

目前 mod_deflate 在读取请求正文时调整标头。但这已经太晚了。例如,如果内容生成器模块需要在读取请求主体之前查看请求标头,则内容生成器模块“看到”旧的(未修改的)标头。

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

尤里卡!这正是我们面临的问题。现在,好消息是有一个补丁可以解决这个问题。坏消息:它尚未被审查/接受/合并到可用版本中。

你有选择

  1. 应用此补丁并重新编译您的服务器。它应该有效,因为一切都是有道理的。但是,要小心......这可能会引入其他错误/漏洞(有时会出现这种情况,即使经过审查/接受)
  2. 等待它包含在可用版本中(考虑到门票日期,可能需要很长时间)。到那时,将您的自定义 deflate 与 php 一起使用。

更新

只是尝试应用补丁并重新编译mod_deflate。看起来它走在正确的轨道上:它吃掉了Content-Encoding头。无论如何,Content-Length还是有的。结果:尚未解压。所以,仍然有一些事情要做和适应,但问题肯定出在那个方面。

更新2(工作中)

我终于成功了。httpd version 2.4.34这是我应用到 Apache ( )的补丁:

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) {
Run Code Online (Sandbox Code Playgroud)

实际上,我mod_deflate也处理了子请求。我不确定它不会破坏其他一些模块,但它适用于您的用例(它更多的是概念证明)。不管怎样,我在上面提到的票上提出了我的补丁。这是结果的屏幕截图:

在此输入图像描述