support browser cors request
CI / scan_ruby (push) Successful in 18s
CI / scan_js (push) Successful in 12s
CI / lint (push) Successful in 21s
CI / test (push) Successful in 47s

This commit is contained in:
2026-02-05 23:59:11 +01:00
parent 83320d4c9a
commit e15835bda9
+47 -10
View File
@@ -9,14 +9,16 @@ module Middleware
def call(env) def call(env)
if allow_cors_for?(env) if allow_cors_for?(env)
return preflight_response(env["HTTP_ORIGIN"]) if env["REQUEST_METHOD"] == "OPTIONS" if env["REQUEST_METHOD"] == "OPTIONS"
return preflight_response(env["HTTP_ORIGIN"], allowed_request_headers(env))
end
end end
status, headers, body = @app.call(env) status, headers, body = @app.call(env)
if allow_cors_for?(env) if allow_cors_for?(env)
apply_cors_headers(headers, env["HTTP_ORIGIN"]) apply_cors_headers(headers, env["HTTP_ORIGIN"])
end end
[status, headers, body] [ status, headers, body ]
end end
private private
@@ -25,25 +27,60 @@ module Middleware
origin = env["HTTP_ORIGIN"].to_s origin = env["HTTP_ORIGIN"].to_s
return false if origin.empty? return false if origin.empty?
if env["REQUEST_METHOD"] == "OPTIONS"
return preflight_includes_app_id_header?(env)
end
app_id = env[APP_ID_HEADER].to_s app_id = env[APP_ID_HEADER].to_s
return false if app_id.empty? return false if app_id.empty?
app_id == ALLOWED_APP_ID app_id == ALLOWED_APP_ID
end end
def preflight_response(origin) def preflight_includes_app_id_header?(env)
headers = {} access_control_headers = env["HTTP_ACCESS_CONTROL_REQUEST_HEADERS"].to_s
apply_cors_headers(headers, origin) return false if access_control_headers.empty?
headers["Access-Control-Max-Age"] = "86400"
[204, headers, []] access_control_headers
.split(",")
.map { |header_name| header_name.strip.downcase }
.include?("x-sanasto-app")
end end
def apply_cors_headers(headers, origin) def allowed_request_headers(env)
access_control_headers = env["HTTP_ACCESS_CONTROL_REQUEST_HEADERS"].to_s
return default_allowed_headers if access_control_headers.empty?
sanitized = access_control_headers
.split(",")
.map { |header_name| header_name.strip }
.reject(&:empty?)
.join(", ")
sanitized.empty? ? default_allowed_headers : sanitized
end
def preflight_response(origin, allowed_headers)
headers = {}
apply_cors_headers(headers, origin, allowed_headers)
headers["Access-Control-Max-Age"] = "86400"
headers["Vary"] = [
headers["Vary"],
"Access-Control-Request-Headers",
"Access-Control-Request-Method"
].compact.join(", ")
[ 204, headers, [] ]
end
def apply_cors_headers(headers, origin, allowed_headers = default_allowed_headers)
headers["Access-Control-Allow-Origin"] = origin headers["Access-Control-Allow-Origin"] = origin
headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, PATCH, DELETE, OPTIONS" headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, PATCH, DELETE, OPTIONS"
headers["Access-Control-Allow-Headers"] = headers["Access-Control-Allow-Headers"] = allowed_headers
headers["Vary"] = [ headers["Vary"], "Origin, X-Sanasto-App" ].compact.join(", ")
end
def default_allowed_headers
"Origin, Content-Type, Accept, Authorization, X-Sanasto-App" "Origin, Content-Type, Accept, Authorization, X-Sanasto-App"
headers["Vary"] = [headers["Vary"], "Origin, X-Sanasto-App"].compact.join(", ")
end end
end end
end end