@@ -20,35 +20,93 @@ function contains(items, test_str)
2020 return false
2121end
2222
23- -- When invoked during a request, captures the Origin header if present
24- -- and stores it in a private variable.
25- function cors_request (txn )
23+ -- If the given origin is found within the allowed_origins string, it is returned. Otherwise, nil is returned.
24+ -- origin: The value from the 'origin' request header
25+ -- allowed_methods: Comma-delimited list of allowed HTTP methods. (e.g. GET,POST,PUT,DELETE)
26+ function get_allowed_origin (origin , allowed_origins )
27+ if origin ~= nil then
28+ local allowed_origins = core .tokenize (allowed_origins , " ," )
29+
30+ -- Strip whitespace
31+ for index , value in ipairs (allowed_origins ) do
32+ allowed_origins [index ] = value :gsub (" %s+" , " " )
33+ end
34+
35+ core .Debug (" CORS - Origin: " .. origin )
36+
37+ if contains (allowed_origins , " *" ) then
38+ return " *"
39+ elseif contains (allowed_origins , origin :match (" //([^/]+)" )) then
40+ return origin
41+ end
42+ end
43+
44+ return nil
45+ end
46+
47+ -- Add headers for CORS preflight request and then returns a 204 response.
48+ -- txn: The current transaction object that gives access to response properties
49+ -- method: The HTTP method
50+ -- origin: The value from the 'origin' request header
51+ -- allowed_methods: Comma-delimited list of allowed HTTP methods. (e.g. GET,POST,PUT,DELETE)
52+ -- 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" )
55+
56+ -- NOTE: The 'reply' function is available in HAProxy 2.2+
57+ local reply = txn :reply ()
58+ reply :set_status (204 , " No Content" )
59+ reply :add_header (" Content-Type" , " text/html" )
60+ reply :add_header (" Access-Control-Allow-Methods" , allowed_methods )
61+ reply :add_header (" Access-Control-Max-Age" , 600 )
62+
63+ local allowed_origin = get_allowed_origin (origin , allowed_origins )
64+
65+ if allowed_origin == nil then
66+ core .Debug (" CORS: " .. origin .. " not allowed" )
67+ else
68+ core .Debug (" CORS: " .. origin .. " allowed" )
69+ reply :add_header (" Access-Control-Allow-Origin" , allowed_origin )
70+ end
71+
72+ core .Debug (" CORS: Returning reply to CORS preflight request" )
73+ txn :done (reply )
74+ end
75+
76+ -- 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.
78+ -- txn: The current transaction object that gives access to response properties
79+ -- allowed_methods: Comma-delimited list of allowed HTTP methods. (e.g. GET,POST,PUT,DELETE)
80+ -- allowed_origins: Comma-delimited list of allowed origins. (e.g. localhost,localhost:8080,test.com)
81+ function cors_request (txn , allowed_methods , allowed_origins )
2682 local headers = txn .http :req_get_headers ()
27- local origin = headers [" origin" ]
83+ local origin = headers [" origin" ][0 ]
84+
85+ local transaction_data = {}
2886
2987 if origin ~= nil then
3088 core .Debug (" CORS: Got 'Origin' header: " .. headers [" origin" ][0 ])
31- txn : set_priv ( headers [" origin" ][ 0 ])
89+ transaction_data [" origin" ] = origin
3290 end
33- end
3491
35- -- Add headers for CORS preflight request
36- function preflight_request (txn , method , allowed_methods )
92+ transaction_data [" allowed_methods" ] = allowed_methods
93+ transaction_data [" allowed_origins" ] = allowed_origins
94+
95+ txn :set_priv (transaction_data )
96+
97+ local method = txn .sf :method ()
98+
3799 if method == " OPTIONS" then
38- core .Debug (" CORS: preflight request OPTIONS" )
39- txn .http :res_add_header (" Access-Control-Allow-Methods" , allowed_methods )
40- txn .http :res_add_header (" Access-Control-Max-Age" , 600 )
100+ preflight_request (txn , method , origin , allowed_methods , allowed_origins )
41101 end
42102end
43103
44- -- When invoked during a response, sets CORS headers so that the browser
45- -- can read the response from permitted domains.
104+ -- When invoked during a response, sets CORS headers so that the browser can read the response from permitted domains.
46105-- txn: The current transaction object that gives access to response properties.
47- -- allowed_methods: Comma-delimited list of allowed HTTP methods. (e.g. GET,POST,PUT,DELETE)
48- -- allowed_origins: Comma-delimited list of allowed origins. (e.g. localhost,localhost:8080,test.com)
49- function cors_response (txn , allowed_methods , allowed_origins )
50- local method = txn .sf :method ()
51- local origin = txn :get_priv ()
106+ function cors_response (txn )
107+ local transaction_data = txn :get_priv ()
108+ local origin = transaction_data [" origin" ]
109+ local allowed_origins = transaction_data [" allowed_origins" ]
52110
53111 -- Always vary on the Origin
54112 txn .http :res_add_header (" Vary" , " Accept-Encoding,Origin" )
@@ -58,26 +116,16 @@ function cors_response(txn, allowed_methods, allowed_origins)
58116 return
59117 end
60118
61- local allowed_origins = core .tokenize (allowed_origins , " ," )
62-
63- -- Strip whitespace
64- for index , value in ipairs (allowed_origins ) do
65- allowed_origins [index ] = value :gsub (" %s+" , " " )
66- end
119+ local allowed_origin = get_allowed_origin (origin , allowed_origins )
67120
68- if contains (allowed_origins , " *" ) then
69- core .Debug (" CORS: " .. " * allowed" )
70- txn .http :res_add_header (" Access-Control-Allow-Origin" , " *" )
71- preflight_request (txn , method , allowed_methods )
72- elseif contains (allowed_origins , origin :match (" //([^/]+)" )) then
73- core .Debug (" CORS: " .. origin .. " allowed" )
74- txn .http :res_add_header (" Access-Control-Allow-Origin" , origin )
75- preflight_request (txn , method , allowed_methods )
76- else
121+ if allowed_origin == nil then
77122 core .Debug (" CORS: " .. origin .. " not allowed" )
123+ else
124+ core .Debug (" CORS: " .. origin .. " allowed" )
125+ txn .http :res_add_header (" Access-Control-Allow-Origin" , allowed_origin )
78126 end
79127end
80128
81129-- Register the actions with HAProxy
82- core .register_action (" cors" , {" http-req" }, cors_request , 0 )
83- core .register_action (" cors" , {" http-res" }, cors_response , 2 )
130+ core .register_action (" cors" , {" http-req" }, cors_request , 2 )
131+ core .register_action (" cors" , {" http-res" }, cors_response , 0 )
0 commit comments