From 80e6f1840d7190f65edc0f106e61f24bb728a369 Mon Sep 17 00:00:00 2001 From: Matteo Cristino <102997993+matteo-cristino@users.noreply.github.com> Date: Thu, 24 Oct 2024 13:35:28 +0200 Subject: [PATCH] fix: correct order of in which response status and headers are written (#381) * fix: add missing const declaration * chore: cleanup some unused vars and add types * fix: correct order of in which response status and headers are written * test: use of http_headers and success_code metadata together --- src/index.ts | 8 ++--- src/routeUtils.ts | 32 +++++++++---------- .../set_http_headers_response.metadata.json | 5 +++ .../set_http_headers_response.schema.json | 8 +++++ .../meta/set_http_headers_response.zen | 9 ++++++ tests/workflow.stepci.yml | 9 ++++++ 6 files changed, 51 insertions(+), 20 deletions(-) create mode 100644 tests/fixtures/meta/set_http_headers_response.metadata.json create mode 100644 tests/fixtures/meta/set_http_headers_response.schema.json create mode 100644 tests/fixtures/meta/set_http_headers_response.zen diff --git a/src/index.ts b/src/index.ts index 931367a..2f3d1b6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -237,8 +237,8 @@ Dir.ready(async () => { const endpoint = Dir.endpoint(path); if (!endpoint) return; const pathArray = path.split('.'); - ext = pathArray.pop() as string; - secondExt = pathArray.pop() as string; + const ext = pathArray.pop() as string; + const secondExt = pathArray.pop() as string; let event: Events; if ( FILE_EXTENSIONS.contract.includes(ext) || @@ -259,8 +259,8 @@ Dir.ready(async () => { Dir.onDelete(async (path: string) => { const pathArray = path.split('.'); - ext = pathArray.pop() as string; - secondExt = pathArray.pop() as string; + const ext = pathArray.pop() as string; + const secondExt = pathArray.pop() as string; let endpoint: Endpoints | undefined; let event: Events; if ( diff --git a/src/routeUtils.ts b/src/routeUtils.ts index 1061066..f766aef 100644 --- a/src/routeUtils.ts +++ b/src/routeUtils.ts @@ -5,7 +5,7 @@ import fs from 'fs'; import _ from 'lodash'; import { IMeta, Logger, type ILogObj } from 'tslog'; -import { App, HttpResponse, TemplatedApp } from 'uWebSockets.js'; +import { App, HttpRequest, HttpResponse, TemplatedApp } from 'uWebSockets.js'; import { execute as slangroomChainExecute } from '@dyne/slangroom-chain'; import { reportZenroomError } from './error.js'; @@ -111,7 +111,7 @@ export const runPrecondition = async (preconditionPath: string, data: Record Record> = { 'application/json': (data: string) => JSON.parse(data), 'application/x-www-form-urlencoded': (data: string) => { const res: Record = {}; @@ -128,10 +128,8 @@ const parseDataFunctions = { const checkAndGetHeaders = ( res: HttpResponse, req: HttpRequest, - LOG: Logger, action: Events, path: string, - metadata: JSONSchema, notAllowed: boolean ): Headers | undefined => { if (action === 'delete') { @@ -144,8 +142,8 @@ const checkAndGetHeaders = ( } const headers: Headers = {}; headers.request = {}; - req.forEach((k, v) => { - headers.request[k] = v; + req.forEach((k: string, v: string) => { + headers.request![k] = v; }); return headers; }; @@ -199,8 +197,8 @@ const execZencodeAndReply = async ( if ('chain' in endpoint) { const dataFormatted = data ? JSON.stringify(data) : undefined; const parsedChain = eval(endpoint.chain)(); - const res = await slangroomChainExecute(parsedChain, dataFormatted); - jsonResult = JSON.parse(res); + const slangRes = await slangroomChainExecute(parsedChain, dataFormatted); + jsonResult = JSON.parse(slangRes); } else { const s = SlangroomManager.getInstance(); ({ result: jsonResult } = await s.execute(endpoint.contract, { keys, data, conf })); @@ -225,16 +223,17 @@ const execZencodeAndReply = async ( } const slangroomResult = JSON.stringify(jsonResult); res.cork(() => { + res + .writeStatus(metadata.successCode) + .writeHeader('Content-Type', metadata.successContentType) + .writeHeader('Access-Control-Allow-Origin', '*') + if (metadata.httpHeaders && headers.response !== undefined) { for (const [k, v] of Object.entries(headers.response)) { res.writeHeader(k, v); } } - res - .writeStatus(metadata.successCode) - .writeHeader('Content-Type', metadata.successContentType) - .writeHeader('Access-Control-Allow-Origin', '*') - .end(slangroomResult); + res.end(slangroomResult); return; }); } catch (e) { @@ -258,7 +257,7 @@ const generatePost = ( ) => { const { path, metadata } = endpoint; app.post(path, (res, req) => { - const headers = checkAndGetHeaders(res, req, LOG, action, path, metadata, metadata.disablePost); + const headers = checkAndGetHeaders(res, req, action, path, metadata.disablePost); if (!headers) return; if (headers.request?.['content-type'] !== metadata.contentType) { unsupportedMediaType(res, new Error(`Unsupported media type on ${path}`)); @@ -277,7 +276,8 @@ const generatePost = ( if (isLast) { let data; try { - const parseFun = parseDataFunctions[metadata.contentType]; + const parseFun: (data: string) => Record | undefined = + parseDataFunctions[metadata.contentType]; if (!parseFun) { unsupportedMediaType(res, new Error(`Unsupported media type ${metadata.contentType}`)); } @@ -314,7 +314,7 @@ const generateGet = ( ) => { const { path, metadata } = endpoint; app.get(path, async (res, req) => { - const headers = checkAndGetHeaders(res, req, LOG, action, path, metadata, metadata.disableGet); + const headers = checkAndGetHeaders(res, req, action, path, metadata.disableGet); if (!headers) return; /** * Code may break on `slangroom.execute` diff --git a/tests/fixtures/meta/set_http_headers_response.metadata.json b/tests/fixtures/meta/set_http_headers_response.metadata.json new file mode 100644 index 0000000..d6c82a3 --- /dev/null +++ b/tests/fixtures/meta/set_http_headers_response.metadata.json @@ -0,0 +1,5 @@ +{ + "success_code": "302", + "error_code": "500", + "http_headers": true +} \ No newline at end of file diff --git a/tests/fixtures/meta/set_http_headers_response.schema.json b/tests/fixtures/meta/set_http_headers_response.schema.json new file mode 100644 index 0000000..05f2d71 --- /dev/null +++ b/tests/fixtures/meta/set_http_headers_response.schema.json @@ -0,0 +1,8 @@ +{ + "type:": "object", + "properties": { + "http_headers": { + "type": "object" + } + } +} \ No newline at end of file diff --git a/tests/fixtures/meta/set_http_headers_response.zen b/tests/fixtures/meta/set_http_headers_response.zen new file mode 100644 index 0000000..66d3e6a --- /dev/null +++ b/tests/fixtures/meta/set_http_headers_response.zen @@ -0,0 +1,9 @@ +Given I have a 'string dictionary' named 'http_headers' + +When I set 'location' to 'https://example.com/cb?code=aaaa' as 'string' +When I create the 'string dictionary' named 'response' + +When I move 'location' in 'response' +When I move 'response' in 'http headers' + +Then print the 'http_headers' \ No newline at end of file diff --git a/tests/workflow.stepci.yml b/tests/workflow.stepci.yml index f993f2f..964144f 100644 --- a/tests/workflow.stepci.yml +++ b/tests/workflow.stepci.yml @@ -70,6 +70,15 @@ tests: http_headers: response: Cache-Control: no-store + - name: set http_headers response + http: + url: http://${{env.host}}/meta/set_http_headers_response + method: GET + followRedirects: false + check: + headers: + Location: https://example.com/cb?code=aaaa + status: 302 hello: steps: