diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts index 638f41b5d6..483a279a82 100644 --- a/packages/cli/src/Server.ts +++ b/packages/cli/src/Server.ts @@ -95,6 +95,7 @@ import { import { credentialsController } from '@/credentials/credentials.controller'; import { oauth2CredentialController } from '@/credentials/oauth2Credential.api'; import type { + BinaryDataRequest, CurlHelper, ExecutionRequest, NodeListSearchRequest, @@ -1305,19 +1306,24 @@ class Server extends AbstractServer { // Download binary this.app.get( `/${this.restEndpoint}/data/:path`, - async (req: express.Request, res: express.Response): Promise => { + async (req: BinaryDataRequest, res: express.Response): Promise => { // TODO UM: check if this needs permission check for UM const identifier = req.params.path; const binaryDataManager = BinaryDataManager.getInstance(); const binaryPath = binaryDataManager.getBinaryPath(identifier); - const { mimeType, fileName, fileSize } = await binaryDataManager.getBinaryMetadata( - identifier, - ); + let { mode, fileName, mimeType } = req.query; + if (!fileName || !mimeType) { + try { + const metadata = await binaryDataManager.getBinaryMetadata(identifier); + fileName = metadata.fileName; + mimeType = metadata.mimeType; + res.setHeader('Content-Length', metadata.fileSize); + } catch {} + } if (mimeType) res.setHeader('Content-Type', mimeType); - if (req.query.mode === 'download' && fileName) { + if (mode === 'download') { res.setHeader('Content-Disposition', `attachment; filename="${fileName}"`); } - res.setHeader('Content-Length', fileSize); res.sendFile(binaryPath); }, ); diff --git a/packages/cli/src/requests.d.ts b/packages/cli/src/requests.d.ts index b6b14a6919..08e3bbfda8 100644 --- a/packages/cli/src/requests.d.ts +++ b/packages/cli/src/requests.d.ts @@ -350,3 +350,14 @@ export declare namespace CurlHelper { export declare namespace LicenseRequest { type Activate = AuthenticatedRequest<{}, {}, { activationKey: string }, {}>; } + +export type BinaryDataRequest = AuthenticatedRequest< + { path: string }, + {}, + {}, + { + mode: 'view' | 'download'; + fileName?: string; + mimeType?: string; + } +>; diff --git a/packages/editor-ui/src/Interface.ts b/packages/editor-ui/src/Interface.ts index 21e5992dbc..0dea128204 100644 --- a/packages/editor-ui/src/Interface.ts +++ b/packages/editor-ui/src/Interface.ts @@ -237,7 +237,12 @@ export interface IRestApi { deleteExecutions(sendData: IExecutionDeleteFilter): Promise; retryExecution(id: string, loadWorkflow?: boolean): Promise; getTimezones(): Promise; - getBinaryUrl(dataPath: string, mode: 'view' | 'download'): string; + getBinaryUrl( + dataPath: string, + mode: 'view' | 'download', + fileName?: string, + mimeType?: string, + ): string; getExecutionEvents(id: string): Promise; } diff --git a/packages/editor-ui/src/components/BinaryDataDisplayEmbed.vue b/packages/editor-ui/src/components/BinaryDataDisplayEmbed.vue index a0ce6d7de1..04fbde24a6 100644 --- a/packages/editor-ui/src/components/BinaryDataDisplayEmbed.vue +++ b/packages/editor-ui/src/components/BinaryDataDisplayEmbed.vue @@ -45,18 +45,18 @@ export default mixins(restApi).extend({ }; }, async mounted() { - const id = this.binaryData?.id; - const isJSONData = this.binaryData.fileType === 'json'; + const { id, data, fileName, fileType, mimeType } = (this.binaryData || {}) as IBinaryData; + const isJSONData = fileType === 'json'; if (!id) { if (isJSONData) { - this.jsonData = jsonParse(atob(this.binaryData.data)); + this.jsonData = jsonParse(atob(data)); } else { - this.embedSource = 'data:' + this.binaryData.mimeType + ';base64,' + this.binaryData.data; + this.embedSource = 'data:' + mimeType + ';base64,' + data; } } else { try { - const binaryUrl = this.restApi().getBinaryUrl(id, 'view'); + const binaryUrl = this.restApi().getBinaryUrl(id, 'view', fileName, mimeType); if (isJSONData) { this.jsonData = await (await fetch(binaryUrl)).json(); } else { diff --git a/packages/editor-ui/src/components/RunData.vue b/packages/editor-ui/src/components/RunData.vue index ce8ead9b38..7ef714f3d0 100644 --- a/packages/editor-ui/src/components/RunData.vue +++ b/packages/editor-ui/src/components/RunData.vue @@ -1206,7 +1206,7 @@ export default mixins(externalHooks, genericHelpers, nodeHelpers, pinData).exten const { id, data, fileName, fileExtension, mimeType } = this.binaryData[index][key]; if (id) { - const url = this.restApi().getBinaryUrl(id, 'download'); + const url = this.restApi().getBinaryUrl(id, 'download', fileName, mimeType); saveAs(url, [fileName, fileExtension].join('.')); return; } else { diff --git a/packages/editor-ui/src/mixins/restApi.ts b/packages/editor-ui/src/mixins/restApi.ts index ab90327c21..0349722902 100644 --- a/packages/editor-ui/src/mixins/restApi.ts +++ b/packages/editor-ui/src/mixins/restApi.ts @@ -202,8 +202,15 @@ export const restApi = Vue.extend({ }, // Binary data - getBinaryUrl: (dataPath, mode): string => - self.rootStore.getRestApiContext.baseUrl + `/data/${dataPath}?mode=${mode}`, + getBinaryUrl: (dataPath, mode, fileName, mimeType): string => { + let restUrl = self.rootStore.getRestUrl; + if (restUrl.startsWith('/')) restUrl = window.location.origin + restUrl; + const url = new URL(`${restUrl}/data/${dataPath}`); + url.searchParams.append('mode', mode); + if (fileName) url.searchParams.append('fileName', fileName); + if (mimeType) url.searchParams.append('mimeType', mimeType); + return url.toString(); + }, // Returns all the available timezones getExecutionEvents: (id: string): Promise => {