logo
Apache Lounge
Webmasters

 

About Forum Index Downloads Search Register Log in RSS X


Keep Server Online

If you find the Apache Lounge, the downloads and overall help useful, please express your satisfaction with a donation.

or

Bitcoin

A donation makes a contribution towards the costs, the time and effort that's going in this site and building.

Thank You! Steffen

Your donations will help to keep this site alive and well, and continuing building binaries. Apache Lounge is not sponsored.
Post new topic   Forum Index -> Apache View previous topic :: View next topic
Reply to topic   Topic: How To Modify HTTP Response In A Proxy Environment
Author
apishdad



Joined: 01 Jul 2019
Posts: 43
Location: Canada, Toronto

PostPosted: Fri 05 Feb '21 23:25    Post subject: How To Modify HTTP Response In A Proxy Environment Reply with quote

I wanted to know what is the best way to replace the <HEAD> tag of a HTTP Response when you have your Apache setup as a load balancer Reverse Proxy Server.

I have few application servers that are running JBOSS and apache is setup to load balance the traffic that comes to these servers.

I need to inject a script tag:
<script> etc..</script>
inside the <HEAD> element of the HTML that gets sent back to the apache server.

I have used the "substitute" command of mod_substitute, but it seems not to work. It works if my Apache is not acting as a Reverse Proxy server and load balancer.

Was wondering whether I am missing any "ProxySet" commands for the proxy server.

Any ideas on what to do?
Back to top
mraddi



Joined: 27 Jun 2016
Posts: 149
Location: Schömberg, Baden-Württemberg, Germany

PostPosted: Sat 06 Feb '21 8:04    Post subject: Reply with quote

Hello,

I've google and found this post https://stackoverflow.com/questions/32603182/apache-httpd-substitute-wont-work which says that one person hat to add
Code:
AddOutputFilterByType INFLATE;SUBSTITUTE;DEFLATE text/html

instead of the
Code:
AddOutputFilterByType SUBSTITUTE text/html

as stated in Apache's documentation at https://httpd.apache.org/docs/2.4/mod/mod_substitute.html

Tip: If performance is important I would prefer NginX over Apache as a Loadbalancer.
Back to top
apishdad



Joined: 01 Jul 2019
Posts: 43
Location: Canada, Toronto

PostPosted: Sat 06 Feb '21 21:58    Post subject: Reply with quote

Thanks mraddi
I have tried many things, and I also tried your code. When apache compiles it says :

Unknown Filter Provided INFLATE

As long as the backend server is another server such as IIS or Apache then the ProxyPass and ProxyPassReverse works, but my issue is that the back end server is JBOSS and whatever I do it seems that the JBOSS server wipes it out and puts its own stuff there.

I might look at another method that doesn't involve Apache, because I am loosing my hair on this on the number of items I have tried Smile
Back to top
apishdad



Joined: 01 Jul 2019
Posts: 43
Location: Canada, Toronto

PostPosted: Sat 06 Feb '21 22:23    Post subject: Reply with quote

Its funny that when i put

loglevel substitute:trace8

I do see the substitution takes place in the error logs, but I cant see it when I do a view source.
Back to top
tangent
Moderator


Joined: 16 Aug 2020
Posts: 312
Location: UK

PostPosted: Sun 07 Feb '21 0:41    Post subject: Reply with quote

I saw your post earlier today, but haven't had time to prepare a more detailed reply.

As mraddi suggests, the problem relates to the proxied response from JBoss being compressed, which messes up mod_substitute being able to filter the response body. I've had exactly the same problem in the past.

His recommendation filter wise, is to inflate the proxied response, perform the substitution, and then compress the result before sending it to the client.

My solution, to save the inflate performance overhead (since my JBoss servers were on a local network), was to simply remove the Accept-Encoding request header, so that JBoss sent an uncompressed response which Apache could then filter. Put the following in your proxy location block or global configuration (if acceptable).

Code:
RequestHeader unset Accept-Encoding

The greater challenge, should you accept it, is to then conditionally compress the response once mod_substitute has done its work. e.g.

1) use mod_rewrite to set an environment variable, recording the fact the client request includes an Accept-Encoding header
2) Remove the Accept-Encoding request header before the request is sent to the proxied back-end servers.
3) Use mod_substitute to filter the response body.
4) Conditionally run the deflate filter (with force-gzip set).

Note the deflate filter won't run if the Accept-Encoding request header is missing; hence the need to use the force-gzip variable (check the module source if you really want to see what really happens).

Also, rather than use AddOutputFilterByType directive, I used the later "filter chain" options to create a smart filter - see https://httpd.apache.org/docs/2.4/mod/mod_filter.html The FilterProvider directive is more flexible since you can use an ap_expr expression to dynamically control the execution, based on the content type as much as the presence of the original Accept-Encoding request header.

I'll see if I can dig out some previous configuration settings and post examples.
Back to top
tangent
Moderator


Joined: 16 Aug 2020
Posts: 312
Location: UK

PostPosted: Sun 07 Feb '21 13:28    Post subject: Reply with quote

The following are code snippets you should be able to weave into your configuration.

Edit the various FilterProvider entries to match your requirements, depending on which content types you want to filter, noting the FilterChain directive in the location block. Also, you might need to set the SubstituteMaxLineLength directive, depending on the size of JBoss content line you're trying to filter.

Note here I've replaced any original Accept-Encoding request header with the value 'identity', which means no compression or modification is required.

Code:
# Load additional modules.
#
LoadModule deflate_module modules/mod_deflate.so
LoadModule filter_module modules/mod_filter.so
LoadModule rewrite_module modules/mod_rewrite.so

# Configuration for substitute filter.
#
FilterDeclare Replace
FilterProvider Replace Substitute "%{CONTENT_TYPE} =~ m#^application/(javascript|json|xml)#i"
FilterProvider Replace Substitute "%{CONTENT_TYPE} =~ m#^text/(css|html|javascript|plain|xml)#i"

# Configuration for deflate (gzip) filter.
#
FilterDeclare Compress
FilterProvider Compress Deflate "%{CONTENT_TYPE} =~ m%^application/(javascript||xml)%i && reqenv('force-gzip') == 'true'"
FilterProvider Compress Deflate "%{CONTENT_TYPE} =~ m%^text/(css|html|javascript|php|plain|xml)%i && reqenv('force-gzip') == 'true'"
FilterProtocol Compress change=yes;byteranges=no

# Enable rewrite engine.
#
RewriteEngine On

# Check for Accept-Encoding request header, and if found set force-gzip variable.
#
RewriteCond %{HTTP:Accept-Encoding} '(deflate|gzip)' [NC,NV]
RewriteRule .* - [E=force-gzip:true,NE]

# Define secure site virtual host.
#
<VirtualHost *:443>
    # Inherit mod_rewrite logic.
    #
    RewriteEngine On
    RewriteOptions InheritBefore

    #   Enable SSL for this virtual host.
    #
    SSLEngine on

    # Proxy selected requests to JBoss.
    #
    <LocationMatch ^/(.*)$>
        # Insert filter chain for this site location.
        #
        FilterChain Replace Compress

        # Replace original Accept-Encoding header with identity request.
        #
        RequestHeader unset Accept-Encoding
        RequestHeader set Accept-Encoding identity

        ProxyPassMatch http(s)://my-jboss-server/$1
        ProxyPassReverse http(s)://my-jboss-server/$1

        # Use the substitute module, to edit the response body.
        # Hence the need for the content to be uncompressed.
        #
        Substitute "s@before@after@inq"

    </LocationMatch>

</VirtualHost>
Back to top
apishdad



Joined: 01 Jul 2019
Posts: 43
Location: Canada, Toronto

PostPosted: Mon 08 Feb '21 10:09    Post subject: Reply with quote

Tangent
Thank you very much for your help. That worked. The trick was the encoding as you mentioned. Thank you for the time you took to find the code.

I like to thank Mraddi as well for his help, he definitely had me trying many things and gave a whole perspective to the situation that I never thought before.
Back to top
gunderwood



Joined: 02 Mar 2022
Posts: 11
Location: US, Greenville, SC

PostPosted: Mon 07 Mar '22 16:11    Post subject: Reply with quote

Hi,

I am trying to add the substitute filter you have in this configuration to my vhost.conf file. When I place the following code apache is indicating an error. The error is "Bad Substitute format, must be an s/// pattern.

RewriteEngine On
# Configuration for substitute filter.
#
AddOutputFilterByType SUBSTITUTE text/html
Substitute "%{CONTENT_TYPE} =~ m#^application/(javascript|json|xml)#i"

Thanks in advance!
Back to top
tangent
Moderator


Joined: 16 Aug 2020
Posts: 312
Location: UK

PostPosted: Mon 07 Mar '22 19:21    Post subject: Reply with quote

Your Substitute statement is indeed invalid.

I notice you've used AddOutputFilterByType rather than the FilterProvider structure in the example above. It's the latter that accepts the %{CONTENT_TYPE} match directive, to conditionally determine which content types the filter runs for. For a given content type, you can't make the filter run conditionally using AddOutputFilterByType.

Which ever variant you choose to run the filter, the Substitute statement should be somthing of the form:
Code:
Substitute "s@before@after@inq"

I tend to use an "@" symbol as the delimiter here, since "/" will most likely appear in content URLs in the response body, and it's often these URLs that need editing.

If you do crack this proxy content problem, please can you update the other post so we don't have two sets of discussion running.
Back to top
gunderwood



Joined: 02 Mar 2022
Posts: 11
Location: US, Greenville, SC

PostPosted: Tue 08 Mar '22 15:05    Post subject: Reply with quote

Hi tangent,

I posted in this thread as I copied the code snippet from the above configuration file. I am sorry as I really am over my head on this topic. Looking at the code in this thread how would I implement the same substitute statement in my vhost.conf file?
Back to top
James Blond
Moderator


Joined: 19 Jan 2006
Posts: 7294
Location: Germany, Next to Hamburg

PostPosted: Mon 14 Mar '22 15:31    Post subject: Reply with quote

Did you read the manual yet?

https://httpd.apache.org/docs/2.4/mod/mod_substitute.html
Back to top


Reply to topic   Topic: How To Modify HTTP Response In A Proxy Environment View previous topic :: View next topic
Post new topic   Forum Index -> Apache