httpd duplicate Access-Control-Allow-Origin with "Header always set"
Asked Answered
H

2

2

I am trying to enable CORS on my server. It hosts both an Apache HTTPD and an Apache Tomee. HTTPD is configured as:

SetEnvIf Origin "^https://(.+\.)?my-domain.com$" allowed_origin=$0
Header always set Access-Control-Allow-Origin %{allowed_origin}e env=allowed_origin
Header set Access-Control-Allow-Credentials "true"
Header set Access-Control-Allow-Methods "GET, POST, OPTIONS, HEAD, PUT, DELETE, PATCH"
Header set Access-Control-Allow-Headers "accept,x-requested-method,origin,x-requested-with,x-request,cache-control,content-type"
Header set Access-Control-Max-Age "600"

and my Tomee web XML :

<filter>
  <filter-name>CorsFilter</filter-name>
  <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
  <init-param>
    <param-name>cors.allowed.headers</param-name>
    <param-value>Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Accept-Language,Keep-Alive</param-value>
  </init-param>
  <init-param>
    <param-name>cors.allowed.methods</param-name>
    <param-value>GET,POST,HEAD,OPTIONS,PUT,PATCH,DELETE</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>CorsFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

My problem is I get the Access-Control-Allow-Credentials header twice in the response to the preflight OPTIONS request :

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://my-origin.my-domain.com
Access-Control-Allow-Origin: https://my-origin.my-domain.com
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 600
Access-Control-Allow-Methods: GET, POST, OPTIONS, HEAD, PUT, DELETE, PATCH
Access-Control-Allow-Headers: accept,x-requested-method,origin,x-requested-with,x-request,cache-control,content-type,authorization

I don't understand why the usage of the set keyword in my HTTPD configuration does not remove the duplicate Access-Control-Allow-Origin. Moreover, if I remove the 'always' keyword it returns one Access-Control-Allow-Origin only...

Hebel answered 27/6, 2016 at 12:15 Comment(2)
I would do a tcp dump between httpd and see where the extra headers are getting addedKattiekatuscha
I'm having a similar problem, but removing the "always" keyword doesn't fix it, requests still include duplicate headers. Apache 2.4.25Leopoldeen
A
7

Experiencing a similar issue. Spent a lot of time in debugging.

It is a bug in Apache. A failure of the internal design and a failure to document it.

Header [table] set [cookie] [value] [...]

That's the command to manipulate headers. There are at least two cookie tables in apache.

  • onsuccess, default, used for 20X status codes.
  • always, used for errors, including redirects codes.

Judging by my experience in the wild, all cookies from all tables are appended to the response.

In your example, the cookie set by Tomcat is in the onsuccess table, the cookie sets in apache is in the always table. The response gets both cookies, hence the duplication.

It gets more messy than that. The tables have different meaning depending on what modules are in use. For instance, when using proxy or CGI, the relevant table for cookies is onsuccess if the upstream server delivers an error successfully, but always if an internal apache error occurs.

This behavior is not documented. That seems not intentional but a consequence of apache internals. In the current state, it is basically impossible to manipulate headers properly with Apache.

Aft answered 23/6, 2017 at 15:16 Comment(2)
bz.apache.org/bugzilla/show_bug.cgi?id=61860 discusses exactly this issue and contains a patch (already merged into trunk).Ber
Thank you so much.... Perfect answer. I found this problem and only this answer solve my problem.Laughlin
B
9

The accepted answer is correct. This is just a way of handling it that I've been using.

SetEnvIf Origin "^(.*(\.yoursite.com)[:0-9]*)$" cors=$1
# wash out these headers in the 'onsuccess' table if we get them from the backend
Header onsuccess unset Access-Control-Allow-Origin env=cors
Header onsuccess unset Access-Control-Allow-Credentials env=cors
Header onsuccess unset Access-Control-Allow-Methods env=cors
Header onsuccess unset Access-Control-Allow-Headers env=cors
# add them to the 'always' table
Header always set Access-Control-Allow-Origin %{cors}e env=cors
Header always set Access-Control-Allow-Credentials "true" env=cors
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, PUT, DELETE" env=cors
Header always set Access-Control-Allow-Headers "accept,x-requested-method,origin" env=cors
Buyse answered 17/5, 2018 at 19:25 Comment(0)
A
7

Experiencing a similar issue. Spent a lot of time in debugging.

It is a bug in Apache. A failure of the internal design and a failure to document it.

Header [table] set [cookie] [value] [...]

That's the command to manipulate headers. There are at least two cookie tables in apache.

  • onsuccess, default, used for 20X status codes.
  • always, used for errors, including redirects codes.

Judging by my experience in the wild, all cookies from all tables are appended to the response.

In your example, the cookie set by Tomcat is in the onsuccess table, the cookie sets in apache is in the always table. The response gets both cookies, hence the duplication.

It gets more messy than that. The tables have different meaning depending on what modules are in use. For instance, when using proxy or CGI, the relevant table for cookies is onsuccess if the upstream server delivers an error successfully, but always if an internal apache error occurs.

This behavior is not documented. That seems not intentional but a consequence of apache internals. In the current state, it is basically impossible to manipulate headers properly with Apache.

Aft answered 23/6, 2017 at 15:16 Comment(2)
bz.apache.org/bugzilla/show_bug.cgi?id=61860 discusses exactly this issue and contains a patch (already merged into trunk).Ber
Thank you so much.... Perfect answer. I found this problem and only this answer solve my problem.Laughlin

© 2022 - 2024 — McMap. All rights reserved.