diff --git a/charts/fsm/components/scripts.tar.gz b/charts/fsm/components/scripts.tar.gz index 8e5e9a8e..ecf40e73 100644 Binary files a/charts/fsm/components/scripts.tar.gz and b/charts/fsm/components/scripts.tar.gz differ diff --git a/charts/fsm/components/scripts/gateways/filters/http/ExternalRateLimit.js b/charts/fsm/components/scripts/gateways/filters/http/ExternalRateLimit.js new file mode 100644 index 00000000..2cfdf378 --- /dev/null +++ b/charts/fsm/components/scripts/gateways/filters/http/ExternalRateLimit.js @@ -0,0 +1,47 @@ +export default function (config) { + var host = config.externalRateLimit.throttleHost + var passHeaders = config.externalRateLimit.passHeaders + + var $throttleResponse + var $throttleResolve + + var errorResponse = new Message({ status: 503 }, 'Throttle service down') + + return pipeline($=>$ + .fork().to($=>$ + .replaceData() + .replaceMessageStart( + req => { + if (passHeaders instanceof Array && passHeaders.length > 0) { + var head = req.head + var headers = head.headers + var selectedHeaders = Object.fromEntries( + passHeaders.map(k => [k, headers?.[k]]) + ) + return new MessageStart({ + method: head.method, + path: head.path, + headers: selectedHeaders, + }) + } else { + return req + } + } + ) + .muxHTTP(() => 1, { version: 2 }).to($=>$ + .connect(host) + ) + .handleMessage( + res => { + $throttleResponse = res?.head ? res : errorResponse + $throttleResolve(true) + } + ) + ) + .wait(() => new Promise(r => { $throttleResolve = r })) + .pipe(() => $throttleResponse.head.status === 200 ? 'pass' : 'reject', { + 'pass': $=>$.pipeNext(), + 'reject': $=>$.replaceData().replaceMessage(() => $throttleResponse) + }) + ) +} diff --git a/charts/fsm/components/scripts/gateways/filters/http/RateLimit.js b/charts/fsm/components/scripts/gateways/filters/http/RateLimit.js index af085b68..087e16a7 100644 --- a/charts/fsm/components/scripts/gateways/filters/http/RateLimit.js +++ b/charts/fsm/components/scripts/gateways/filters/http/RateLimit.js @@ -4,6 +4,7 @@ export default function (config) { var interval = Number.parseFloat(config.rateLimit.interval) var burst = Number.parseInt(config.rateLimit.burst) var backlog = Number.parseInt(config.rateLimit.backlog) + var blocking = config.rateLimit.blocking === 'true' var response = new Message( { @@ -36,7 +37,7 @@ export default function (config) { } }, { 'pass': ($=>$ - .throttleMessageRate(rateQuota) + .throttleMessageRate(rateQuota, { blockInput: blocking }) .pipeNext() .handleMessageStart(() => { if (backlog) { diff --git a/charts/fsm/components/scripts/gateways/filters/http/RequestTermination.js b/charts/fsm/components/scripts/gateways/filters/http/RequestTermination.js new file mode 100644 index 00000000..7e63cde6 --- /dev/null +++ b/charts/fsm/components/scripts/gateways/filters/http/RequestTermination.js @@ -0,0 +1,14 @@ +export default function (config) { + var abortMessage = new Message( + { + status: config.requestTermination.response?.status || 503, + headers: config.requestTermination.response?.headers, + }, + config.requestTermination.response?.body || 'Service unavailable' + ) + + return pipeline($=>$ + .replaceData() + .replaceMessage(abortMessage) + ) +}