Bug 69233 - ResponseFieldSize for ProxyPassMatch directives?
Summary: ResponseFieldSize for ProxyPassMatch directives?
Status: NEW
Alias: None
Product: Apache httpd-2
Classification: Unclassified
Component: mod_proxy (show other bugs)
Version: 2.4.59
Hardware: PC All
: P2 normal (vote)
Target Milestone: ---
Assignee: Apache HTTPD Bugs Mailing List
URL:
Keywords: FixedInTrunk
Depends on:
Blocks:
 
Reported: 2024-07-30 18:00 UTC by David
Modified: 2024-08-21 13:52 UTC (History)
0 users



Attachments
Don't enforce min_match for ProxyPassMatch (5.43 KB, patch)
2024-07-31 14:34 UTC, Yann Ylavic
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description David 2024-07-30 18:00:02 UTC
We have an Apache Http Server 2.4.59 running that's started generating errors when one of the response servers from a backend system we don't control exceeds the default 8192 bytes. This was not the case in previous versions of HTTPD as exceeding that limit did not cause an error.


Unfortunately, it seems that ResponseFieldSize in our ProxyPassMatch definitions with this format: 

ProxyPassMatch "^/([^/]+)/?(.+)?$" https://$1-myhost/$2 responsefieldsize=20 keepalive=On disablereuse=On
 

is being ignored.  I can configure responsefieldsize correctly for ProxyPass directives but it does not seem to work for ProxyPass. 

Are we doing anything incorrectly? It seems from the docs it should work as per my example, so not sure if this is a bug or something that needs clarification in docs. It would also be great if you could document any way to configure this responsefieldsize globally.
Comment 1 David 2024-07-30 18:01:10 UTC
Sorry, I meant "one of the response headers"
Comment 2 Yann Ylavic 2024-07-30 22:32:23 UTC
If this ProxyPassMatch is "elected" I don't see why the configured responsefieldsize wouldn't apply. Could it be that another ProxyPass[Match] also matches and takes precedence, or a RewriteRule [P] or anything falling back to the default/implicit proxy worker with the default settings?

With "LogLevel trace2" you should have a log line like "found worker <name> for <url>", which <name> do you see?
Comment 3 Rainer Jung 2024-07-30 22:50:48 UTC
More in the direction of Yann's thoughts: I think multiple ProxyPass(Match) can share the same target worker including its configuration. You might even find messages in the error log about sharing workers during startup (but I forgot the log level, maybe info).

So check in addition to looking for RewriteRules which do proxying, also check for other ProxyPass(Match), which do not necessarily match your request, but use the same target host, scheme and port as the rule which doesn't work correctly for you.
Comment 4 David 2024-07-31 11:02:33 UTC
Hi!

 Actually it is a very simple config where we only have two virtual hosts with a single ProxyPassMatch directive each, both with the responsefieldsize config value, and another proxypassmatch rule that will not match those or does not use the same target, but we've also added responsefieldsize to that one.

There are no RewriteRules or similar... is there any debugging info I can use to print the value of ResponseFieldSize when it's loaded? 

What I did to verify this (since responsefieldsize did not seem to work) was to create a new "localhost" virtual host configuring the responsefieldsize to 20 in a ProxyPass directive,  and that caused failures for any backend services I tried. Changing ProxyPass to ProxyPassMatch , requests go through without failures.


This is my virtualhost:

<VirtualHost *:*>
    ServerName http://localhost:1080

        CustomLog "|/usr/sbin/rotatelogs -l -f /var/log/httpd/localaccess.%Y%m%d0000 86400" combined env=!forwarded
        CustomLog "|/usr/sbin/rotatelogs -l -f /var/log/httpd/localaccess.%Y%m%d0000 86400" proxy env=forwarded
        ErrorLog "|/usr/sbin/rotatelogs -l -f /var/log/httpd/localerrors.%Y%m%d0000 86400"

       #ProxyPassMatch "^/([^/]+)/?(.+)?$"  https://$1-HOSTNAME/$2  responsefieldsize=20 keepalive=On disablereuse=On
       ProxyPass "/prefix/" "https://HOSTNAME/" responsefieldsize=20  keepalive=On disablereuse=On
</VirtualHost>


With the ProxyPass directive enabled,  I get this error for the backend I am testing (It sends a CSP over 20 chars): 

Wed Jul 31 06:38:46.833680 2024] [proxy_http:warn] [pid 33291:tid 33313] (28)No space left on device: [client ::1:34578] AH10124: header size is over the limit allowed by ResponseFieldSize (20 bytes). Bad response header: 'Date: Wed[...] 31 Jul 2'


If I comment the ProxyPass directive and uncomment the ProxyPassMatch one, I do get a successful response from the backend, which shows headers over 20 characters. No error logs about  responsefieldsize at all.


The only other "ProxyPass" directive I have in my config is: 

ProxyPass /healthcheck.html !

and a ProxyPassMatch for a different target which also has responsefieldsize=20

way to configure a default responsefieldsize that will apply to any hosts?
Comment 5 David 2024-07-31 11:27:16 UTC
Hi,

 I've looked into this further and I can see that the problem  seems to be that Apache expects a line with a 'perfect match' with the target in the ProxyPass* directives ?

Let me elaborate. If I add this config:

<VirtualHost *:*>
    ServerName http://localhost:1080

        CustomLog "|/usr/sbin/rotatelogs -l -f /var/log/httpd/localaccess.%Y%m%d0000 86400" combined env=!forwarded
        CustomLog "|/usr/sbin/rotatelogs -l -f /var/log/httpd/localaccess.%Y%m%d0000 86400" proxy env=forwarded
        ErrorLog "|/usr/sbin/rotatelogs -l -f /var/log/httpd/localerrors.%Y%m%d0000 86400"

    ProxyPassMatch "^/([^/]+)/?(.+)?$"  https://$1-myhostname.com/$2 responsefieldsize=20 keepalive=On disablereuse=On

    ProxyPass "/application/test/" "https://application-myhostname.com/" responsefieldsize=20  keepalive=On disablereuse=On


</VirtualHost>

And I try to curl http://localhost:8180/application/healthcheck  , then I correctly get an error saying my responsefieldsize is 20  (this is matching the ProxyPassMatch directive and not ProxyPass as I don't have /application/test/ in the path - I can also see a match with the proxy handler i in the tracelogs ) . However, the moment I comment the ProxyPass directive or change this "ProxyPass" directive to not match https://application-myhostname.com/  I don't get an error complaining about the  responsefieldsize.

An example, with the config above, when I call both /application/assets and /application/healthcheck, I get an error about the responsefieldsize. However, if I change the ProxyPass directive to this:

ProxyPass "/application/test/" "https://application-myhostname.com/healthcheck" responsefieldsize=20  keepalive=On disablereuse=On


I get the error when calling /application/healthcheck (responsefieldsize is correctly read from ProxyPass directive) , but I don't get an error (responseFieldSize is the default instead of 20) when I call /application/assets .  If I change the target url to   https://application-myhostname.com/assets , it is the opposite: calls to /application/healthcheck use the default responsefieldsize but calls to /application/assets work as desired.


I've also tried creating a ProxyPassMatch directive where the target hostname is "https://application-myhostname.com/$2"  (with no ProxyPass at all, just this ProxyPassMatch) , and in that case responsefieldsize is also correctly read from the ProxyPassMatch  rule.


In our case, we cannot preconfigure all the target hostnames (which are unknown) but rather need to write the hostname based on the request path, using a ProxyPassMatch directive. How can we configur ethe responsefieldsize in this case?
Comment 6 David 2024-07-31 11:42:57 UTC
To simplify my report:


This rule works as expected, configuring responsefieldsize for requests to /application/:


ProxyPassMatch "^/([^/]+)/?(.+)?$"  https://application-HOSTNAME/$2  responsefieldsize=20 keepalive=On disablereuse=On


This one , where the target hostname is composed with regex, does not work as expected, and responsefieldsize is not  respected (although directive itself  matches the request and calls are forwarded to the expected backend):
 
ProxyPassMatch "^/([^/]+)/?(.+)?$"  https://$1-HOSTNAME/$2  responsefieldsize=20 keepalive=On disablereuse=On


I hope that's clear. Hopefully there's a workaround  for this like a way to configure responsefieldsize for any targets?
Comment 7 Eric Covener 2024-07-31 11:45:57 UTC
Without a host I guess these will use the "default reverse proxy worker".

I wonder if it is possible to use 
<Proxy "proxy:reverse"> 
  ProxySet responsefieldsize=32768
</Proxy> 

to configure the default worker?  Maybe it's easy for you to try in your env?
Comment 8 Eric Covener 2024-07-31 11:46:36 UTC
It may be "*" rather than proxy:reverse
Comment 9 David 2024-07-31 13:21:44 UTC
Hi Eric,

 Thanks a lot for the quick reply.  I've tried to implement this suggested configuration change, but it seems that the server will not start if I add either:
<Proxy "proxy:reverse"> 
  ProxySet responsefieldsize=32768
</Proxy>

or 

<Proxy "*"> 
  ProxySet responsefieldsize=32768
</Proxy>

 
I haven't been able to find any error details?
Comment 10 David 2024-07-31 14:06:01 UTC
Ah sorry,


I always get this error:

ProxySet URL must be absolute!: proxy:reverse

ProxySet URL must be absolute!: *
Comment 11 Yann Ylavic 2024-07-31 14:34:43 UTC
Created attachment 39831 [details]
Don't enforce min_match for ProxyPassMatch

This works for me, could you try it?
Comment 12 Yann Ylavic 2024-08-01 11:55:08 UTC
Checked in trunk r1919617.

Please try this patch for 2.4.x: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/469.diff
Comment 13 David 2024-08-01 12:38:36 UTC
Hi Yann,

 Thanks a lot for the quick fix!  We'll try to have this tested ... What's the expected change in behaviour exactly?  Is it that the key/val parameters in the ProxyPassMatch directive will be used? 

For instance: 
ProxyPassMatch "^/([^/]+)/?(.+)?$" https://$1-myhost/$2 responsefieldsize=20 keepalive=On 

Will use "responseFieldSize=20" , "keepalive=on" whenever the ProxyPassMatch rule is applied?
Comment 14 Yann Ylavic 2024-08-01 12:57:07 UTC
Yes exactly, the proxy worker "https://$1-myhost/$2" defined with this ProxyPassMatch is used/selected hence its parameters apply.

Without this patch the request falls back to the default reverse proxy worker mentionned by Eric, which is not configurable, so the defaults apply.
Comment 15 David 2024-08-21 13:52:35 UTC
Hi Yann ,


Sorry but I was allocated to something else and I never had the chance to test this in the 2.4.x branch.   Maybe someone else can have it tested? I'm going to be away for a while but my organization will still require this.