mirror of
https://github.com/status-im/eth-rpc-proxy.git
synced 2026-08-31 11:41:08 +00:00
143 lines
4.3 KiB
Lua
143 lines
4.3 KiB
Lua
local _M = {}
|
|
|
|
-- HTTP status codes that should trigger retry
|
|
_M.RETRY_STATUS = {
|
|
[401] = true, [402] = true, [403] = true, [429] = true,
|
|
[500] = true, [501] = true, [502] = true, [503] = true, [504] = true, [505] = true
|
|
}
|
|
|
|
-- JSON-RPC error codes that should trigger retry
|
|
_M.RETRY_EVM = {
|
|
[32005] = true, -- Request timeout
|
|
[33000] = true, -- Rate limit exceeded
|
|
[33300] = true, -- Network error
|
|
[33400] = true -- Provider error
|
|
}
|
|
|
|
-- Headers that should not be proxied to client (hop-by-hop and CORS)
|
|
_M.HEADER_BLOCKLIST = {
|
|
-- Connection-related headers (hop-by-hop)
|
|
["connection"] = true,
|
|
["transfer-encoding"] = true,
|
|
["keep-alive"] = true,
|
|
["upgrade"] = true,
|
|
["proxy-authenticate"] = true,
|
|
["proxy-authorization"] = true,
|
|
["te"] = true,
|
|
["trailer"] = true,
|
|
|
|
-- CORS headers (we control these ourselves)
|
|
["access-control-allow-origin"] = true,
|
|
["access-control-allow-credentials"] = true,
|
|
["access-control-allow-methods"] = true,
|
|
["access-control-allow-headers"] = true,
|
|
["access-control-expose-headers"] = true,
|
|
["access-control-max-age"] = true,
|
|
}
|
|
|
|
-- Check if we should retry with next provider
|
|
function _M.should_retry(res, decoded)
|
|
if not res then return true end
|
|
if _M.RETRY_STATUS[res.status] then return true end
|
|
if decoded and decoded.error and _M.RETRY_EVM[decoded.error.code] then return true end
|
|
return false
|
|
end
|
|
|
|
-- Filter providers by provider_type if specified
|
|
function _M.filter_providers(providers, provider_type)
|
|
if not providers or type(providers) ~= "table" then
|
|
return {}, false
|
|
end
|
|
|
|
local providers_to_try = {}
|
|
local tried_specific_provider = false
|
|
|
|
if provider_type and provider_type ~= "" then
|
|
for _, provider in ipairs(providers) do
|
|
if provider.type == provider_type then
|
|
table.insert(providers_to_try, provider)
|
|
end
|
|
end
|
|
tried_specific_provider = true
|
|
else
|
|
providers_to_try = providers
|
|
end
|
|
|
|
return providers_to_try, tried_specific_provider
|
|
end
|
|
|
|
-- Parse and validate URL path parameters
|
|
function _M.parse_url_path(uri)
|
|
if not uri or type(uri) ~= "string" then
|
|
return nil, nil, nil, "Invalid URI"
|
|
end
|
|
|
|
local chain, network, provider_type = uri:match("^/([^/]+)/([^/]+)/?([^/]*)$")
|
|
if not chain or not network then
|
|
return nil, nil, nil, "Invalid URL format - must be /chain/network or /chain/network/provider_type"
|
|
end
|
|
|
|
-- Convert empty provider_type to nil for consistency
|
|
if provider_type == "" then
|
|
provider_type = nil
|
|
end
|
|
|
|
return chain, network, provider_type, nil
|
|
end
|
|
|
|
-- Setup authentication for provider request
|
|
function _M.setup_auth(provider, base_url, base_headers)
|
|
if not provider or type(provider) ~= "table" then
|
|
return base_url or "", base_headers or {}
|
|
end
|
|
|
|
local request_url = provider.url or base_url or ""
|
|
local request_headers = {}
|
|
|
|
-- Copy base headers
|
|
if base_headers then
|
|
for k, v in pairs(base_headers) do
|
|
request_headers[k] = v
|
|
end
|
|
end
|
|
|
|
if provider.authType == "token-auth" and provider.authToken then
|
|
if request_url:sub(-1) == "/" then
|
|
request_url = request_url .. provider.authToken
|
|
else
|
|
request_url = request_url .. "/" .. provider.authToken
|
|
end
|
|
elseif provider.authType == "basic-auth" and provider.authLogin and provider.authPassword then
|
|
local auth_str = ngx.encode_base64(provider.authLogin .. ":" .. provider.authPassword)
|
|
request_headers["Authorization"] = "Basic " .. auth_str
|
|
end
|
|
|
|
return request_url, request_headers
|
|
end
|
|
|
|
-- Filter response headers based on blocklist
|
|
function _M.filter_response_headers(headers)
|
|
if not headers or type(headers) ~= "table" then
|
|
return {}
|
|
end
|
|
|
|
local filtered_headers = {}
|
|
for key, value in pairs(headers) do
|
|
local lower_key = string.lower(key)
|
|
if not _M.HEADER_BLOCKLIST[lower_key] then
|
|
filtered_headers[key] = value
|
|
end
|
|
end
|
|
|
|
return filtered_headers
|
|
end
|
|
|
|
-- Create chain:network key for provider lookup
|
|
function _M.get_chain_network_key(chain, network)
|
|
if not chain or not network then
|
|
return nil
|
|
end
|
|
return chain .. ":" .. network
|
|
end
|
|
|
|
return _M |