Adding CORS response headers
Hey all,
There are a number of other older (2013-era) threads about CORS headers, and I want to ask a specific question which has not been asked there:
Can I add a response header using HTTP::header insert within an HTTP_REQUEST?
In at least one CORS-related thread (https://devcentral.f5.com/questions/cors-irule-query), this is shown happening. However, in another thread (https://devcentral.f5.com/questions/access-control-allow-origin-on-f5) the answer includes code in the HTTP_REQUEST to set a variable and then in the HTTP_RESPONSE, a check is made on that variable and if it is set, the HTTP::header insert is used.
Basically, I want to include all my CORS-related code in one place. Currently, I am doing basic CORS (adding the ACAO header for GET/POST requests from my domain where the Origin request header is present) using my CDN (Akamai) and I have this iRule for CORS preflight responses:
when HTTP_REQUEST {
if { ( [HTTP::method] equals "OPTIONS" ) and
( [HTTP::host] contains "mysite.com"] ) and
( [HTTP::header] exists "Access-Control-Request-Method") } {
HTTP::respond 200 Access-Control-Allow-Origin "[HTTP::header Origin]" \
Access-Control-Allow-Methods "POST, GET, OPTIONS" \
Access-Control-Allow-Headers "[HTTP::header Access-Control-Request-Headers]" \
Access-Control-Max-Age "86400"
return
}
}
However, for simplification, I want to put all the CORS stuff (basic and preflight) in the iRule. So my question is, will this work:
when HTTP_REQUEST {
CORS preflight OPTIONS requests
if { ( [HTTP::method] equals "OPTIONS" ) and
( [HTTP::host] contains "mysite.com"] ) and
( [HTTP::header] exists "Access-Control-Request-Method") } {
HTTP::respond 200 Access-Control-Allow-Origin "[HTTP::header Origin]" \
Access-Control-Allow-Methods "POST, GET, OPTIONS" \
Access-Control-Allow-Headers "[HTTP::header Access-Control-Request-Headers]" \
Access-Control-Max-Age "86400"
return
}
CORS GET/POST requests
if { ( [HTTP::method] equals "GET" or [HTTP::method] equals "POST") and
( [HTTP::host] contains "mysite.com"] ) and
( [HTTP::header] exists "Origin") } {
HTTP::header insert Access-Control-Allow-Origin "[HTTP::header Origin]"
}
}
or do I need this:
when HTTP_REQUEST {
CORS preflight OPTIONS requests
if { ( [HTTP::method] equals "OPTIONS" ) and
( [HTTP::host] contains "mysite.com"] ) and
( [HTTP::header] exists "Access-Control-Request-Method") } {
HTTP::respond 200 Access-Control-Allow-Origin "[HTTP::header Origin]" \
Access-Control-Allow-Methods "POST, GET, OPTIONS" \
Access-Control-Allow-Headers "[HTTP::header Access-Control-Request-Headers]" \
Access-Control-Max-Age "86400"
return
}
CORS GET/POST requests
if { ( [HTTP::host] contains "mysite.com"] ) and
( [HTTP::header] exists "Origin") } {
set cors_origin [HTTP::header Origin]
}
}
when HTTP_RESPONSE {
CORS GET/POST response - check variable set in request
if { [info exists cors_origin] } {
HTTP::header insert Access-Control-Allow-Origin $cors_origin
}
}
Does this make sense, or am I getting too complex?
To anyone who comes in afterwards and wants to find a 'final' solution, here's what we ended up with (which functions perfectly, at least for us):
when HTTP_REQUEST priority 200 { unset cors_origin -nocomplain if { [HTTP::header Origin] ends_with ".example.com" } { if { ( [HTTP::method] equals "OPTIONS" ) and ( [HTTP::header exists "Access-Control-Request-Method"] ) } { CORS preflight request - return response immediately HTTP::respond 200 "Access-Control-Allow-Origin" [HTTP::header "Origin"] \ "Access-Control-Allow-Methods" "POST, GET, OPTIONS" \ "Access-Control-Allow-Headers" [HTTP::header "Access-Control-Request-Headers"] \ "Access-Control-Max-Age" "86400" } else { CORS GET/POST requests - set cors_origin variable set cors_origin [HTTP::header "Origin"] } } ... ... ... other irules ... ... ... } when HTTP_RESPONSE { CORS GET/POST response - check cors_origin variable set in request if { [info exists cors_origin] } { HTTP::header insert "Access-Control-Allow-Origin" $cors_origin HTTP::header insert "Access-Control-Allow-Credentials" "true" HTTP::header insert "Vary" "Origin" } }
If you have any comments about this, please do so. And, of course, feel free to use it yourself.