From 3e6234e6019c5f3ae4280fac079ecc9cb0effc07 Mon Sep 17 00:00:00 2001 From: Saad Jutt Date: Sun, 20 Feb 2022 05:40:03 +0500 Subject: [PATCH] fix: return buffer in case of file response --- api/public/swagger.yaml | 12 ++++++-- api/src/controllers/code.ts | 4 ++- api/src/controllers/internal/Execution.ts | 35 ++++++++++++++-------- api/src/controllers/stp.ts | 15 ++++++---- api/src/utils/extractHeaders.ts | 6 ++-- api/src/utils/specs/extractHeaders.spec.ts | 12 ++++++++ 6 files changed, 59 insertions(+), 25 deletions(-) diff --git a/api/public/swagger.yaml b/api/public/swagger.yaml index b4f9ebd..ccb2f70 100644 --- a/api/public/swagger.yaml +++ b/api/public/swagger.yaml @@ -539,7 +539,9 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ExecuteReturnJsonResponse' + anyOf: + - {$ref: '#/components/schemas/ExecuteReturnJsonResponse'} + - {type: string, format: byte} description: 'Execute SAS code.' summary: 'Run SAS Code and returns log' tags: @@ -1054,7 +1056,9 @@ paths: content: application/json: schema: - type: string + anyOf: + - {type: string} + - {type: string, format: byte} description: "Trigger a SAS program using it's location in the _program parameter.\nEnable debugging using the _debug parameter.\nAdditional URL parameters are turned into SAS macro variables.\nAny files provided are placed into the session and\ncorresponding _WEBIN_XXX variables are created." summary: 'Execute Stored Program, return raw content' tags: @@ -1078,7 +1082,9 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ExecuteReturnJsonResponse' + anyOf: + - {$ref: '#/components/schemas/ExecuteReturnJsonResponse'} + - {type: string, format: byte} examples: 'Example 1': value: {status: success, _webout: 'webout content', log: [], httpHeaders: {Content-type: application/zip, Cache-Control: 'public, max-age=1000'}} diff --git a/api/src/controllers/code.ts b/api/src/controllers/code.ts index c5c8e65..b2a3c49 100644 --- a/api/src/controllers/code.ts +++ b/api/src/controllers/code.ts @@ -25,7 +25,7 @@ export class CodeController { public async executeSASCode( @Request() request: express.Request, @Body() body: ExecuteSASCodePayload - ): Promise { + ): Promise { return executeSASCode(request, body) } } @@ -41,6 +41,8 @@ const executeSASCode = async (req: any, { code }: ExecuteSASCodePayload) => { true )) as ExecuteReturnJson + if (webout instanceof Buffer) return webout + return { status: 'success', _webout: webout, diff --git a/api/src/controllers/internal/Execution.ts b/api/src/controllers/internal/Execution.ts index f452912..04e5084 100644 --- a/api/src/controllers/internal/Execution.ts +++ b/api/src/controllers/internal/Execution.ts @@ -1,7 +1,13 @@ import path from 'path' import fs from 'fs' import { getSessionController } from './' -import { readFile, fileExists, createFile, moveFile } from '@sasjs/utils' +import { + readFile, + fileExists, + createFile, + moveFile, + readFileBinary +} from '@sasjs/utils' import { PreProgramVars, TreeNode } from '../../types' import { extractHeaders, @@ -16,12 +22,12 @@ export interface ExecutionVars { export interface ExecuteReturnRaw { httpHeaders: HTTPHeaders - result: string + result: string | Buffer } export interface ExecuteReturnJson { httpHeaders: HTTPHeaders - webout: string + webout: string | Buffer log?: string } @@ -138,15 +144,17 @@ ${program}` } const log = (await fileExists(logPath)) ? await readFile(logPath) : '' - const webout = (await fileExists(weboutPath)) - ? await readFile(weboutPath) - : '' const headersContent = (await fileExists(headersPath)) ? await readFile(headersPath) : '' - const httpHeaders: HTTPHeaders = headersContent - ? extractHeaders(headersContent) - : {} + const httpHeaders: HTTPHeaders = extractHeaders(headersContent) + const fileResponse: boolean = httpHeaders.hasOwnProperty('Content-Type') + + const webout = (await fileExists(weboutPath)) + ? fileResponse + ? await readFileBinary(weboutPath) + : await readFile(weboutPath) + : '' const debugValue = typeof vars._debug === 'string' ? parseInt(vars._debug) : vars._debug @@ -165,10 +173,11 @@ ${program}` return { httpHeaders, - result: - (debugValue && debugValue >= 131) || session.crashed - ? `${webout}

SAS Log

${log}
` - : webout + result: fileResponse + ? webout + : (debugValue && debugValue >= 131) || session.crashed + ? `${webout}

SAS Log

${log}
` + : webout } } diff --git a/api/src/controllers/stp.ts b/api/src/controllers/stp.ts index f5fff74..b5390ca 100644 --- a/api/src/controllers/stp.ts +++ b/api/src/controllers/stp.ts @@ -59,7 +59,7 @@ export class STPController { public async executeReturnRaw( @Request() request: express.Request, @Query() _program: string - ): Promise { + ): Promise { return executeReturnRaw(request, _program) } @@ -87,7 +87,7 @@ export class STPController { @Request() request: express.Request, @Body() body?: ExecuteReturnJsonPayload, @Query() _program?: string - ): Promise { + ): Promise { const program = _program ?? body?._program return executeReturnJson(request, program!) } @@ -96,7 +96,7 @@ export class STPController { const executeReturnRaw = async ( req: express.Request, _program: string -): Promise => { +): Promise => { const query = req.query as ExecutionVars const sasCodePath = path @@ -113,7 +113,10 @@ const executeReturnRaw = async ( req.res?.set(httpHeaders) - return result as string + // if (result instanceof Buffer) + // req.res?.writeHead(200, httpHeaders) + + return result } catch (err: any) { throw { code: 400, @@ -127,7 +130,7 @@ const executeReturnRaw = async ( const executeReturnJson = async ( req: any, _program: string -): Promise => { +): Promise => { const sasCodePath = path .join(getTmpFilesFolderPath(), _program) @@ -145,6 +148,8 @@ const executeReturnJson = async ( true )) as ExecuteReturnJson + if (webout instanceof Buffer) return webout + return { status: 'success', _webout: webout, diff --git a/api/src/utils/extractHeaders.ts b/api/src/utils/extractHeaders.ts index e3812f0..bba76c0 100644 --- a/api/src/utils/extractHeaders.ts +++ b/api/src/utils/extractHeaders.ts @@ -4,14 +4,14 @@ export interface HTTPHeaders { [key: string]: string } -export const extractHeaders = (content: string): HTTPHeaders => { +export const extractHeaders = (content?: string): HTTPHeaders => { const headersObj: HTTPHeaders = {} const headersArr = content - .split('\n') + ?.split('\n') .map((line) => line.trim()) .filter((line) => !!line) - headersArr.forEach((headerStr) => { + headersArr?.forEach((headerStr) => { const [key, value] = headerStr.split(':').map((data) => data.trim()) if (value && headerUtils.validateHeader(key, value)) { diff --git a/api/src/utils/specs/extractHeaders.spec.ts b/api/src/utils/specs/extractHeaders.spec.ts index 4e6e467..4d5f5d0 100644 --- a/api/src/utils/specs/extractHeaders.spec.ts +++ b/api/src/utils/specs/extractHeaders.spec.ts @@ -37,4 +37,16 @@ describe('extractHeaders', () => { expect(headers).toEqual({}) }) + + it('should return http headers if empty', () => { + const headers = extractHeaders('') + + expect(headers).toEqual({}) + }) + + it('should return http headers if not provided', () => { + const headers = extractHeaders() + + expect(headers).toEqual({}) + }) })