fix(HTTP Request Node): Process text files (#16226)

This commit is contained in:
Dana
2025-06-13 16:05:15 +02:00
committed by GitHub
parent 88e3c90e71
commit 0d5ac1f822
7 changed files with 378 additions and 235 deletions

View File

@@ -10,6 +10,11 @@ describe('Test Binary Data Download', () => {
.get('/path/to/image.png')
.reply(200, Buffer.from('test'), { 'content-type': 'image/png' });
nock(baseUrl)
.persist()
.get('/path/to/text.txt')
.reply(200, Buffer.from('test'), { 'content-type': 'text/plain; charset=utf-8' });
nock(baseUrl)
.persist()
.get('/redirect-to-image')

View File

@@ -1,227 +1,264 @@
{
"name": "Download as Binary Data",
"nodes": [
{
"name": "When clicking \"Execute Workflow\"",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"parameters": {},
"position": [580, 300]
},
{
"name": "HTTP Request (v1)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 1,
"parameters": {
"url": "https://dummy.domain/path/to/image.png",
"responseFormat": "file"
},
"position": [1020, -100]
},
{
"name": "HTTP Request (v2)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 2,
"parameters": {
"url": "https://dummy.domain/path/to/image.png",
"responseFormat": "file",
"options": {}
},
"position": [1020, 80]
},
{
"name": "HTTP Request (v3)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"parameters": {
"url": "https://dummy.domain/path/to/image.png",
"options": {
"response": {
"response": {
"responseFormat": "file"
}
}
}
},
"position": [1020, 240]
},
{
"name": "HTTP Request (v4)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"parameters": {
"url": "https://dummy.domain/path/to/image.png",
"options": {
"response": {
"response": {
"responseFormat": "file"
}
}
}
},
"position": [1020, 400]
},
{
"name": "Follow Redirect",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"parameters": {
"url": "https://dummy.domain/redirect-to-image",
"options": {
"response": {
"response": {
"responseFormat": "file"
}
}
}
},
"position": [1020, 560]
},
{
"name": "Content Disposition",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"parameters": {
"url": "https://dummy.domain/custom-content-disposition",
"options": {
"response": {
"response": {
"responseFormat": "file"
}
}
}
},
"position": [1020, 720]
}
],
"pinData": {
"HTTP Request (v1)": [
{
"binary": {
"data": {
"data": "dGVzdA==",
"mimeType": "image/png",
"fileType": "image",
"fileExtension": "png",
"fileName": "image.png",
"fileSize": "4 B"
}
},
"json": {}
}
],
"HTTP Request (v2)": [
{
"binary": {
"data": {
"data": "dGVzdA==",
"mimeType": "image/png",
"fileType": "image",
"fileExtension": "png",
"fileName": "image.png",
"fileSize": "4 B"
}
},
"json": {}
}
],
"HTTP Request (v3)": [
{
"binary": {
"data": {
"data": "dGVzdA==",
"mimeType": "image/png",
"fileType": "image",
"fileExtension": "png",
"fileName": "image.png",
"fileSize": "4 B"
}
},
"json": {}
}
],
"HTTP Request (v4)": [
{
"binary": {
"data": {
"data": "dGVzdA==",
"mimeType": "image/png",
"fileType": "image",
"fileExtension": "png",
"fileName": "image.png",
"fileSize": "4 B"
}
},
"json": {}
}
],
"Follow Redirect": [
{
"binary": {
"data": {
"data": "dGVzdA==",
"mimeType": "image/png",
"fileType": "image",
"fileExtension": "png",
"fileName": "image.png",
"fileSize": "4 B"
}
},
"json": {}
}
],
"Content Disposition": [
{
"binary": {
"data": {
"data": "dGVzdGluZw==",
"mimeType": "image/jpeg",
"fileType": "image",
"fileExtension": "jpg",
"fileName": "testing.jpg",
"fileSize": "7 B"
}
},
"json": {}
}
]
},
"connections": {
"When clicking \"Execute Workflow\"": {
"main": [
[
{
"node": "HTTP Request (v1)",
"type": "main",
"index": 0
},
{
"node": "HTTP Request (v2)",
"type": "main",
"index": 0
},
{
"node": "HTTP Request (v3)",
"type": "main",
"index": 0
},
{
"node": "HTTP Request (v4)",
"type": "main",
"index": 0
},
{
"node": "Follow Redirect",
"type": "main",
"index": 0
},
{
"node": "Content Disposition",
"type": "main",
"index": 0
}
]
]
}
}
"name": "Download as Binary Data",
"nodes": [
{
"name": "When clicking \"Execute Workflow\"",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"parameters": {},
"position": [580, 300]
},
{
"name": "HTTP Request (v1)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 1,
"parameters": {
"url": "https://dummy.domain/path/to/image.png",
"responseFormat": "file"
},
"position": [1020, -100]
},
{
"name": "HTTP Request (v2)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 2,
"parameters": {
"url": "https://dummy.domain/path/to/image.png",
"responseFormat": "file",
"options": {}
},
"position": [1020, 80]
},
{
"name": "HTTP Request (v3)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"parameters": {
"url": "https://dummy.domain/path/to/image.png",
"options": {
"response": {
"response": {
"responseFormat": "file"
}
}
}
},
"position": [1020, 240]
},
{
"name": "HTTP Request (v4)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"parameters": {
"url": "https://dummy.domain/path/to/image.png",
"options": {
"response": {
"response": {
"responseFormat": "file"
}
}
}
},
"position": [1020, 400]
},
{
"name": "Follow Redirect",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"parameters": {
"url": "https://dummy.domain/redirect-to-image",
"options": {
"response": {
"response": {
"responseFormat": "file"
}
}
}
},
"position": [1020, 560]
},
{
"name": "Content Disposition",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"parameters": {
"url": "https://dummy.domain/custom-content-disposition",
"options": {
"response": {
"response": {
"responseFormat": "file"
}
}
}
},
"position": [1020, 720]
},
{
"parameters": {
"url": "https://dummy.domain/path/to/text.txt",
"options": {
"response": {
"response": {
"responseFormat": "file"
}
}
}
},
"name": "HTTP Request (v4)2",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [1680, 600],
"id": "665fef5c-6380-4bc0-be2a-430446b140ca"
}
],
"pinData": {
"HTTP Request (v1)": [
{
"binary": {
"data": {
"data": "dGVzdA==",
"mimeType": "image/png",
"fileType": "image",
"fileExtension": "png",
"fileName": "image.png",
"fileSize": "4 B"
}
},
"json": {}
}
],
"HTTP Request (v2)": [
{
"binary": {
"data": {
"data": "dGVzdA==",
"mimeType": "image/png",
"fileType": "image",
"fileExtension": "png",
"fileName": "image.png",
"fileSize": "4 B"
}
},
"json": {}
}
],
"HTTP Request (v3)": [
{
"binary": {
"data": {
"data": "dGVzdA==",
"mimeType": "image/png",
"fileType": "image",
"fileExtension": "png",
"fileName": "image.png",
"fileSize": "4 B"
}
},
"json": {}
}
],
"HTTP Request (v4)": [
{
"binary": {
"data": {
"data": "dGVzdA==",
"mimeType": "image/png",
"fileType": "image",
"fileExtension": "png",
"fileName": "image.png",
"fileSize": "4 B"
}
},
"json": {}
}
],
"Follow Redirect": [
{
"binary": {
"data": {
"data": "dGVzdA==",
"mimeType": "image/png",
"fileType": "image",
"fileExtension": "png",
"fileName": "image.png",
"fileSize": "4 B"
}
},
"json": {}
}
],
"Content Disposition": [
{
"binary": {
"data": {
"data": "dGVzdGluZw==",
"mimeType": "image/jpeg",
"fileType": "image",
"fileExtension": "jpg",
"fileName": "testing.jpg",
"fileSize": "7 B"
}
},
"json": {}
}
],
"HTTP Request (v4)2": [
{
"binary": {
"data": {
"data": "dGVzdA==",
"mimeType": "text/plain",
"fileType": "text",
"fileExtension": "txt",
"fileName": "text.txt",
"fileSize": "4 B"
}
},
"json": {}
}
]
},
"connections": {
"When clicking \"Execute Workflow\"": {
"main": [
[
{
"node": "HTTP Request (v1)",
"type": "main",
"index": 0
},
{
"node": "HTTP Request (v2)",
"type": "main",
"index": 0
},
{
"node": "HTTP Request (v3)",
"type": "main",
"index": 0
},
{
"node": "HTTP Request (v4)",
"type": "main",
"index": 0
},
{
"node": "Follow Redirect",
"type": "main",
"index": 0
},
{
"node": "Content Disposition",
"type": "main",
"index": 0
},
{
"node": "HTTP Request (v4)2",
"type": "main",
"index": 0
}
]
]
}
}
}

View File

@@ -0,0 +1,29 @@
import type { IBinaryData, IRequestOptions } from 'n8n-workflow';
import { setFilename } from '../../V3/utils/binaryData';
describe('setFilename', () => {
it('returns filename from URI if fileName is missing and URI ends with fileExtension', () => {
const preparedBinaryData = { fileExtension: 'png' } as IBinaryData;
const requestOptions = { uri: 'https://example.com/image.png' } as IRequestOptions;
expect(setFilename(preparedBinaryData, requestOptions, undefined)).toBe('image.png');
});
it('returns constructed filename if fileName is missing and URI does not end with fileExtension', () => {
const preparedBinaryData = { fileExtension: 'jpg' } as IBinaryData;
const requestOptions = { uri: 'https://example.com/image.png' } as IRequestOptions;
expect(setFilename(preparedBinaryData, requestOptions, 'response')).toBe('response.jpg');
});
it('returns constructed filename with default "data" if responseFileName is undefined', () => {
const preparedBinaryData = { fileExtension: 'txt' } as IBinaryData;
const requestOptions = { uri: 'https://example.com/file' } as IRequestOptions;
expect(setFilename(preparedBinaryData, requestOptions, undefined)).toBe('data.txt');
});
it('returns fileName if it exists', () => {
const preparedBinaryData = { fileName: 'myfile.pdf', fileExtension: 'pdf' } as IBinaryData;
const requestOptions = { uri: 'https://example.com/file.pdf' } as IRequestOptions;
expect(setFilename(preparedBinaryData, requestOptions, 'response')).toBe('myfile.pdf');
});
});

View File

@@ -0,0 +1,33 @@
import { mimeTypeFromResponse } from '../../V3/utils/parse';
describe('mimeTypeFromResponse', () => {
it('should return undefined if input is undefined', () => {
expect(mimeTypeFromResponse(undefined)).toBeUndefined();
});
it('should return the mime type for a simple type', () => {
expect(mimeTypeFromResponse('image/png')).toBe('image/png');
});
it('should strip charset from content type', () => {
expect(mimeTypeFromResponse('text/html; charset=utf-8')).toBe('text/html');
});
it('should strip charset from content type', () => {
expect(mimeTypeFromResponse('text/plain; charset=utf-8')).toBe('text/plain');
});
it('should strip boundary from multipart content type', () => {
expect(mimeTypeFromResponse('multipart/form-data; boundary=ExampleBoundaryString')).toBe(
'multipart/form-data',
);
});
it('should handle content type with extra spaces', () => {
expect(mimeTypeFromResponse('application/json ; charset=utf-8')).toBe('application/json');
});
it('should handle content type with space before semicolon', () => {
expect(mimeTypeFromResponse('application/xml ;charset=utf-8')).toBe('application/xml');
});
});