@@ -32,8 +32,6 @@ function get_allowed_origin(origin, allowed_origins)
3232 allowed_origins [index ] = value :gsub (" %s+" , " " )
3333 end
3434
35- core .Debug (" CORS - Origin: " .. origin )
36-
3735 if contains (allowed_origins , " *" ) then
3836 return " *"
3937 elseif contains (allowed_origins , origin :match (" //([^/]+)" )) then
@@ -44,16 +42,29 @@ function get_allowed_origin(origin, allowed_origins)
4442 return nil
4543end
4644
45+ -- Adds headers for CORS preflight request and then attaches them to the response
46+ -- after it comes back from the server. This works with versions of HAProxy prior to 2.2.
47+ -- The downside is that the OPTIONS request must be sent to the backend server first and can't
48+ -- be intercepted and returned immediately.
49+ -- txn: The current transaction object that gives access to response properties
50+ -- allowed_methods: Comma-delimited list of allowed HTTP methods. (e.g. GET,POST,PUT,DELETE)
51+ function preflight_request_ver1 (txn , allowed_methods )
52+ core .Debug (" CORS: preflight request received" )
53+ txn .http :res_add_header (" Access-Control-Allow-Methods" , allowed_methods )
54+ txn .http :res_add_header (" Access-Control-Max-Age" , 600 )
55+ core .Debug (" CORS: attaching allowed methods to response" )
56+ end
57+
4758-- Add headers for CORS preflight request and then returns a 204 response.
59+ -- The 'reply' function used here is available in HAProxy 2.2+. It allows HAProxy to return
60+ -- a reply without contacting the server.
4861-- txn: The current transaction object that gives access to response properties
49- -- method: The HTTP method
5062-- origin: The value from the 'origin' request header
5163-- allowed_methods: Comma-delimited list of allowed HTTP methods. (e.g. GET,POST,PUT,DELETE)
5264-- allowed_origins: Comma-delimited list of allowed origins. (e.g. localhost,localhost:8080,test.com)
53- function preflight_request (txn , method , origin , allowed_methods , allowed_origins )
54- core .Debug (" CORS: preflight request OPTIONS " )
65+ function preflight_request_ver2 (txn , origin , allowed_methods , allowed_origins )
66+ core .Debug (" CORS: preflight request received " )
5567
56- -- NOTE: The 'reply' function is available in HAProxy 2.2+
5768 local reply = txn :reply ()
5869 reply :set_status (204 , " No Content" )
5970 reply :add_header (" Content-Type" , " text/html" )
@@ -69,12 +80,13 @@ function preflight_request(txn, method, origin, allowed_methods, allowed_origins
6980 reply :add_header (" Access-Control-Allow-Origin" , allowed_origin )
7081 end
7182
72- core .Debug (" CORS: Returning reply to CORS preflight request" )
83+ core .Debug (" CORS: Returning reply to preflight request" )
7384 txn :done (reply )
7485end
7586
7687-- When invoked during a request, captures the origin header if present and stores it in a private variable.
77- -- If the request is OPTIONS, returns a preflight request reply.
88+ -- If the request is OPTIONS and it is a supported version of HAProxy, returns a preflight request reply.
89+ -- Otherwise, the preflight request header is added to the response after it has returned from the server.
7890-- txn: The current transaction object that gives access to response properties
7991-- allowed_methods: Comma-delimited list of allowed HTTP methods. (e.g. GET,POST,PUT,DELETE)
8092-- allowed_origins: Comma-delimited list of allowed origins. (e.g. localhost,localhost:8080,test.com)
@@ -95,9 +107,10 @@ function cors_request(txn, allowed_methods, allowed_origins)
95107 txn :set_priv (transaction_data )
96108
97109 local method = txn .sf :method ()
110+ transaction_data [" method" ] = method
98111
99- if method == " OPTIONS" then
100- preflight_request (txn , method , origin , allowed_methods , allowed_origins )
112+ if method == " OPTIONS" and txn . reply ~= nil then
113+ preflight_request_ver2 (txn , origin , allowed_methods , allowed_origins )
101114 end
102115end
103116
@@ -107,6 +120,8 @@ function cors_response(txn)
107120 local transaction_data = txn :get_priv ()
108121 local origin = transaction_data [" origin" ]
109122 local allowed_origins = transaction_data [" allowed_origins" ]
123+ local allowed_methods = transaction_data [" allowed_methods" ]
124+ local method = transaction_data [" method" ]
110125
111126 -- Always vary on the Origin
112127 txn .http :res_add_header (" Vary" , " Accept-Encoding,Origin" )
@@ -121,6 +136,10 @@ function cors_response(txn)
121136 if allowed_origin == nil then
122137 core .Debug (" CORS: " .. origin .. " not allowed" )
123138 else
139+ if method == " OPTIONS" and txn .reply == nil then
140+ preflight_request_ver1 (txn , allowed_methods )
141+ end
142+
124143 core .Debug (" CORS: " .. origin .. " allowed" )
125144 txn .http :res_add_header (" Access-Control-Allow-Origin" , allowed_origin )
126145 end
0 commit comments