Apache RewriteRule discards SetInputFilter DEFLATE config directive
Asked Answered
A

1

6

I have the following (simplified) folder/file structure:

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

And the following directive in apache config:

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

I am sending a POST request with a gzipped body with the appropiated headers:

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

And I have the following config for the .htaccess file:

RewriteEngine On

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

The issue is, if I post to /test.php, everything works as expected, the body is deflated and I can access decompressed contents just right.

However if I post to something that gets redirected (/api/ or /api/v1/project) the index.php script does not get the body decompressed.

I think it must be related to the RewriteRule directive ignoring the SetInputFilter directive, but, how can I avoid this situation?

I tried to add the SetInputFilter directive directly in the .htaccess without solving the issue (may be it was not in the right place?).

Do you know how can I solve this?

Aeonian answered 6/7, 2017 at 14:22 Comment(8)
Have you checked to make sure you have set AllowOverride All in your virtual host config?Etruria
@HalfCrazed AllowOverride All is active. And I think it is working properly because the redirection I defined in the .htaccess is working but ignoring the SetInputFilter directive that it is in the apache.conf file.Aeonian
I'm experiencing this issue as well. May I know whether anyone has come up with a solution?Hassock
@FrederickZhang I posted the issue on Apache mailing list (mail-archives.apache.org/mod_mbox/httpd-users/201707.mbox/…) and forums (apachelounge.com/viewtopic.php?t=7686) without any success. I opted to deflate the body myself but I am still confident a solution from Apache will come sometime in the future :)Aeonian
What is /api/web/ ? A known CMS or something of your own ? Indeed, POST data is passed along with the request when rewriting and it should be the same for decompressed contents, I guess. Also, did you check your server logs ? You may find some interesting things thereBurdette
@JustinIurman I don't think that's something related. You can have a basic setup which contains only an index.php and a .htaccess to rewrite all requests to index.php to reproduce this issue.Hassock
@JustinIurman I prepared a test suite but I could not attach the link to download them as I was too newbie in StackOverflow. Now I can, dropbox.com/s/mfduw81flnvy1ik/test-suite.zip?dl=0Aeonian
Found a solution (see Update 2 (working) section in my answer)Burdette
B
5

Indeed, there is a problem. The first thing I did to investigate deeper was to log traces of concerned modules (rewrite, filter and deflate).

mod_rewrite logs were OK, nothing suspicious there. To make sure everything was really OK, I looked at the very last version of its source code. And again, nothing suspicious regarding encoding/decoding (nor http request/response headers, more generally).

So I started thinking the problem may come from either filter or deflate module, even if it may also come from somewhere else. To confirm/infirm what I thought, I looked at those modules logs. Quickly, I was able to see a difference between the two test cases: with or without mod_rewrite involved.

mod_rewrite not involved

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

I took this one as a reference to compare the next case below

mod_rewrite involved

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

Interesting. Actually, it looked like mod_deflate was the problem. I suspected its action was after the right moment. That's the reason why you don't see it in action, here, in this case.

Solution

So far, so good. So... what ? Well, a quick search on the known bugs list of Apache, with keywords mod_deflate too late, gave me by chance what I was searching for. This ticket called mod_deflate adjusts the headers "too late", states the following:

When mod_deflate is used to inflate, it must adjust the request headers (e.g. it needs to remove the "Content-Length" header and adjust the "Content-Encoding" header).

Currently mod_deflate adjusts the headers when the request body is read. But this is too late. For example, if a content generator module needs to look at the request headers before reading the request body, the content generator module "sees" the old (unmodified) headers.

mod_deflate should adjust the headers in an early stage, for example in a fixup hook (ap_hook_fixups).

Eureka ! This is exactly the problem we're facing. Now, good news is there is a patch to overcome this issue. Bad news: it is not yet reviewed/accepted/merged in available versions.

You have the choice:

  1. Apply this patch and recompile your server. It should work because the all thing makes sense. But, be careful... this may introduce other bugs/holes (that's sometimes the case, even when reviewed/accepted)
  2. Wait for it to be included in available versions (maybe a long time, considering the ticket date). By then, use your custom deflate with php.

Update

Just tried to apply the patch and recompile mod_deflate. Looks like it's on the right track: it eats Content-Encoding header. Anyway, Content-Length is still there. Result: no yet decompressed. So, there is still something to do and adapt, but the problem is definitely in that area.

Update 2 (working)

I managed to make it work, finally. Here is the patch I applied to 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) {

Actually, I made mod_deflate handle sub-requests too. I'm not sure it's not gonna break some other modules, but it works for your use case (it's more a proof of concept). Anyway, I proposed my patch on the ticket mentioned above. Here is a screenshot of the result:

enter image description here

Burdette answered 1/8, 2018 at 15:16 Comment(4)
Wow, excellent answer! It's sad tho that such an ancient issue hasn't got fixed in Apache. I guess mod_deflate was mainly designed for WebDAV and didn't get thoroughly tested in different scenarios as few clients actually support request payload compression. I reckon it's better for me to conquer the issue directly in my code like OP at least for now.Hassock
Yes, it's sad. Welcome to the open-source world ! But it has also many advantages so let's be happy. For your solution, indeed it's more prudent to wait for an official change in apache releases. I restarted the thread (ticket) by submitting my patch, let's see if something moves. I hope it'll get back to life soon.Burdette
@JustinIurman wow, good job, you have just hit the nail in the head.Aeonian
Thanks guys, I'm glad I brought both of you an explanation on this very old problem. Unanswered questions and unsolved issues are painful.Burdette

© 2022 - 2024 — McMap. All rights reserved.