Apache httpd: Conditionally set response header based on other *response* header - apache

Is there a way to set a new response header conditionally, where the condition uses another response header? Specifically, the new response header should be set only if the response has a certain Content-Type.
I have looked into mod_headers in combination with mod_setenvif but it looks like conditions can only use request headers, not response headers.
Thanks, John

Apache 2.4 is the answer:
Set Cache-Control header when response content type is application/pdf
Header set Cache-Control "no-store,no-transform" "expr=%{resp:Content-Type} =~ m|application/pdf|"
Do NOT try with the IF directive. It is evaluated too early in the process. For example, the following will NOT work:
<If "%{resp:Content-Type} =~ m|application/pdf|">
Header set Cache-Control "no-store, no-transform"
</If>

Related

Apache mod_rewrite pass Headers

I am running my apache on http://localhost:8083 and i am calling an API hosted on local box i.e. http://localhost:8082
I want to map http://localhost:8083/test-call/abc/authorize call to actual service call i.e. http://localhost:8082/TestCall/abc/authorize.
I have rewrite engine as follows in httpd.conf file:
RewriteEngine on
RewriteRule "^/test-call/(.*)$" "http://localhost:8082/TestCall/$1"
I can see that the call is being mapped correctly from developer console of chrome i.e. http://localhost:8082/TestCall/abc/authorize and i have disabled CORS on my browser as i am testing the API call only.
I have added the following headers in my httpd.conf file:
Header set Access-Control-Allow-Origin "http://localhost:8083"
Header always set Access-Control-Allow-Headers "Authorization, X-Requested-With, Content-Type, content-type, x-requested-with, Accept, Access-Control-Allow-Origin, Cache-Control"
Header always set Cache-Control "no-cache, no-store, must-revalidate"
Header always set Access-Control-Allow-Methods "GET, POST, DELETE, HEAD, OPTIONS"
Header always set Access-Control-Expose-Headers "Content-Security-Policy, Location"
Header always set Access-Control-Max-Age "3600"
Header always set REMOTE_USER "abc.def#db.com"
It's a react application and the bundles are getting loaded correctly with the specified headers above and also the REMOTE_USER is getting added to the REPONSE_HEADERS but for the rewritten URL, the headers are not getting applied.
I want to pass the REMOTE_USER header in the API call after rewrite/redirect.
I have enabled mod_headers and mod_rewrite.
What am i missing?

apache httpd - header merge ignoring existing header

Using apache mod_proxy 2.5 I'm trying to merge or replace an existing access-control-allow-origin header with mod_headers in a proxypass location.
the answer returned from proxied backend already includes a access-control-allow-origin header which I'd like to merge or replace
Header always merge Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Methods "OPTIONS, GET"
Header always set Access-Control-Max-Age "1000"
Header always set Access-Control-Allow-Headers "x-requested-with, Content-Type, origin, authorization, accept, client-security-token, x-smp-appcid"
This results in a header duplicate which raises an error in all browser cause this header can only occur once.
same is for Header always set although this should replace the existing header.
I also tried to use if module to first check for the headers occurence and only set if unset. but it's somehow hard to look into response headers.
any help is appreciated
I got through the same problem by setting the Access-Control-Allow-Origin and Access-Control-Allow-Credentials headers only when its a preflight request
The second request ( POST, DELETE, PUT etc ) which is handled by the proxied backend ( which already sends the required headers ) is not a preflight request and hence the headers would not be set again by the Apache rules.
To check for preflight request, you could check whether the request contains:
REQUEST_METHOD == OPTIONS
Access-Control-Request-Method !-= ""
Origin != ""
Hope this helps.

Apache - Add Cache-Control header if not already added

In Apache, how can I set a Response Header only if it is not already set by the CGI application?
I need a way to automatically add the Cache-Control header to static content on my website, but I want the CGI application to be able to specify its own Cache-Control header too.
SetEnvIf will not work for this purpose because it only matches Request Headers.
Is there some way to conditionally / optionally set a header if it is not already set?
1) Configure Apache to append the value of empty string ("") to the Cache-Control header to ensure the header is always included in the response.
2) Configure Apache to set the Cache-Control header only if it's still set to empty string.
<FilesMatch "\.(css|ico|flv|gif|jpeg|jpg|js|pdf|png|swf)$">
Header append Cache-Control ""
Header edit Cache-Control "^[, ]*$" "max-age=1800, public"
</FilesMatch>

handle multiple domains with Access-Control-Allow-Origin header in Apache

I want to configure apache for cross-domain access header. I have tried multiple combination as suggested on number of threads on the forum. But its not working for me.
The ways, I have tried:
1) Specify domain on different line as below with Header set :
Header set Access-Control-Allow-Origin "example1.com"
Header set Access-Control-Allow-Origin "example2.com"
Header set Access-Control-Allow-Origin: "example3.com"
With this setup its picking only last one and ignore rest of all.
2) Specify domain on different line as below with Header add :
Header add Access-Control-Allow-Origin "example1.com"
Header add Access-Control-Allow-Origin "example2.com"
Header add Access-Control-Allow-Origin: "example3.com"
With this its showing all three domains in header, but fonts are not getting picked up on Firefox.
3.) Tried Using SetEnvIf, but again its not working :
SetEnvIf Origin "http(s)?://(www\.)?(mydomain.com|mydomain2.com)$" AccessControlAllowOrigin=$0$1
Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
Finally working with "*", but I don't want to use this.
Please help with this.
For 3 domains, in your .htaccess:
<IfModule mod_headers.c>
SetEnvIf Origin "http(s)?://(www\.)?(domain1.org|domain2.com|domain3.net)$" AccessControlAllowOrigin=$0$1
Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
Header set Access-Control-Allow-Credentials true
</IfModule>
I've tried this and it works for me. Let me know if it doesn't for you.
Unless I'm misunderstanding the manual, it should be:
Header always append Access-Control-Allow-Origin: "example1.com"
Header always append Access-Control-Allow-Origin: "example2.com"
Header always append Access-Control-Allow-Origin: "example3.com"
The manual states that the set and add actions behave in the following way:
set: "The response header is set, replacing any previous header with this name"
add: "...This can result in two (or more) headers having the same name. This can lead to unforeseen consequences..."
To restrict access to certain URIs checkout these docs:
CrossOriginRequestSecurity
Server-Side Access Control#Apache_examples
One helpful trick is to use an Apache rewrite, environment variable, and headers to apply Access-Control-Allow-* to certain URIs. This is useful, for example, to constrain cross-origin requests to GET /api(.*).json requests without credentials:
RewriteRule ^/api(.*)\.json$ /api$1.json [CORS=True]
Header set Access-Control-Allow-Origin "*" env=CORS
Header set Access-Control-Allow-Methods "GET" env=CORS
Header set Access-Control-Allow-Credentials "false" env=CORS
Also, in general, according to W3 Wiki - CORS Enabled#For_Apache
To expose the header, you can add the following line inside Directory, Location, and Files sections, or within an .htaccess file.
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
</IfModule>
AND, you can use add rather than set, but be aware that add can add the header multiple times, so it's generally safer to use set.
Try this one, it works for me.
Apply in .htaccess:
SetEnvIf Origin "^http(s)?://(.+\.)?(domain\.org|domain2\.com)$" origin_is=$0
Header always set Access-Control-Allow-Origin %{origin_is}e env=origin_is
Will be work 100%, Apply in .htaccess:
# Enable cross domain access control
SetEnvIf Origin "^http(s)?://(.+\.)?(domain1\.com|domain2\.org|domain3\.net)$" REQUEST_ORIGIN=$0
Header always set Access-Control-Allow-Origin %{REQUEST_ORIGIN}e env=REQUEST_ORIGIN
Header always set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
Header always set Access-Control-Allow-Headers "x-test-header, Origin, X-Requested-With, Content-Type, Accept"
# Force to request 200 for options
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule .* / [R=200,L]
For Apache 2.4, I have used SET command for the Apache web server to set Header dynamically.
<IfModule mod_deflate.c>
# CORS
SetEnvIfNoCase Origin "http(s)?://(\w+\.)?(example.com|localhost)(:[0-9]+)?$" AccessControlAllowOrigin=$0
Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
Header set Access-Control-Allow-Credentials true
</IfModule>
ADD command didn't work for me.
I am using this in my .htaccess file for allowing access to multiple domains
<ifModule mod_headers.c>
SetEnvIf Origin "http(s)?://(localhost:25120|domain.com|domain2.com)$" AccessControlAllowOrigin=$0
Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
Header always set Access-Control-Allow-Methods: "GET,POST,OPTIONS,DELETE,PUT"
</ifModule>
For Multiple domains, in your .htaccess:
<IfModule mod_headers.c>
SetEnvIf Origin "http(s)?://(www\.)?(domain.com|domain.online|domain.in|domain.net|domain.site|domain.website|domain.space)$" AccessControlAllowOrigin=$0
Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
Header set Access-Control-Allow-Credentials true
</IfModule>
it 100% works for me
This works for me in Classic ASP:
If Request.ServerVariables("HTTP_ORIGIN") = "http://domain1.com" Then
Response.AddHeader "Access-Control-Allow-Origin","http://domain1.com"
ElseIf Request.ServerVariables("HTTP_ORIGIN") = "http://domain2.com" Then
Response.AddHeader "Access-Control-Allow-Origin","http://domain2.com"
'and so on
End If

How do you set the Access-Control-Allow-Origin header for the HTTP basic authentication response in Apache?

I want to use XHR to log in to a site that uses HTTP basic authentication. The following piece does this.
http = new XMLHttpRequest();
http.open("get", "http://...", false, username, password);
http.send("");
The problem is that this does not work from a domain that is different from the one where the authentication is. The solution is simple enough: set the Access-Control-Allow-Origin header to *. So I changed my Apache configuration to this:
<Location />
Header set Access-Control-Allow-Origin "*"
AuthType Basic
AuthName "trac"
AuthUserFile /home/admin/development/pass.htpasswd
Require valid-user
</Location>
Responses from that page look like:
HTTP/1.1 401 Authorization Required
Connection: Keep-Alive
Content-Encoding: gzip
Content-Length: 345
Content-Type: text/html; charset=iso-8859-1
Date: Sun, 11 Sep 2011 01:17:55 GMT
Keep-Alive: timeout=15, max=100
Vary: Accept-Encoding
WWW-Authenticate: Basic realm="trac"
The responses do not have the Access-Control-Allow-Origin header. This seems strange.
When I use the same Header directive for the inside pages, the header is set.
Why was the header not set?
How do you set the Access-Control-Allow-Origin header for the HTTP basic authentication response in Apache?
The answer is:
Header always set Access-Control-Allow-Origin "*"
instead of
Header set Access-Control-Allow-Origin "*"
And the reason is in the documentation of Header directive:
Header [condition] set|append|merge|add|unset|echo|edit header [value] [replacement] [early|env=[!]variable]
The optional condition argument determines which internal table of responses headers this directive will operate against. Other components of the server may have stored their response headers in either the table that corresponds to onsuccess or the table that corresponds to always. "Always" in this context refers to whether headers you add will be sent during both a successful and unsucessful response, but if your action is a function of an existing header, you will have to read on for further complications.
The default value of onsuccess may need to be changed to always under the circumstances similar to those listed below. Note also that repeating this directive with both conditions makes sense in some scenarios because always is not a superset of onsuccess with respect to existing headers:
You're adding a header to a non-success (non-2xx) response, such as a redirect, in which case only the table corresponding to always is used in the ultimate response.
You're modifying or removing a header generated by a CGI script, in which case the CGI scripts are in the table corresponding to always and not in the default table.
You're modifying or removing a header generated by some piece of the server but that header is not being found by the default onsuccess condition.
In your case you send a 401 response instead of a classical 200 response, and the Header is only set on 200 responses if you do not use the always keyword.