mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
feat(HTTP Request Tool Node): Relax binary data detection (#13048)
This commit is contained in:
parent
a7792684a6
commit
b67a003e0b
|
@ -237,6 +237,69 @@ describe('ToolHttpRequest', () => {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return the error when receiving text that contains a null character', async () => {
|
||||||
|
helpers.httpRequest.mockResolvedValue({
|
||||||
|
body: 'Hello\0World',
|
||||||
|
headers: {
|
||||||
|
'content-type': 'text/plain',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
executeFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
||||||
|
switch (paramName) {
|
||||||
|
case 'method':
|
||||||
|
return 'GET';
|
||||||
|
case 'url':
|
||||||
|
return 'https://httpbin.org/text/plain';
|
||||||
|
case 'options':
|
||||||
|
return {};
|
||||||
|
case 'placeholderDefinitions.values':
|
||||||
|
return [];
|
||||||
|
default:
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const { response } = await httpTool.supplyData.call(executeFunctions, 0);
|
||||||
|
const res = await (response as N8nTool).invoke({});
|
||||||
|
expect(helpers.httpRequest).toHaveBeenCalled();
|
||||||
|
// Check that the returned string is formatted as an error message.
|
||||||
|
expect(res).toContain('error');
|
||||||
|
expect(res).toContain('Binary data is not supported');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the error when receiving a JSON response containing a null character', async () => {
|
||||||
|
// Provide a raw JSON string with a literal null character.
|
||||||
|
helpers.httpRequest.mockResolvedValue({
|
||||||
|
body: '{"message":"hello\0world"}',
|
||||||
|
headers: {
|
||||||
|
'content-type': 'application/json',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
executeFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
||||||
|
switch (paramName) {
|
||||||
|
case 'method':
|
||||||
|
return 'GET';
|
||||||
|
case 'url':
|
||||||
|
return 'https://httpbin.org/json';
|
||||||
|
case 'options':
|
||||||
|
return {};
|
||||||
|
case 'placeholderDefinitions.values':
|
||||||
|
return [];
|
||||||
|
default:
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const { response } = await httpTool.supplyData.call(executeFunctions, 0);
|
||||||
|
const res = await (response as N8nTool).invoke({});
|
||||||
|
expect(helpers.httpRequest).toHaveBeenCalled();
|
||||||
|
// Check that the tool returns an error string rather than resolving to valid JSON.
|
||||||
|
expect(res).toContain('error');
|
||||||
|
expect(res).toContain('Binary data is not supported');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Optimize response', () => {
|
describe('Optimize response', () => {
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { JSDOM } from 'jsdom';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import set from 'lodash/set';
|
import set from 'lodash/set';
|
||||||
import unset from 'lodash/unset';
|
import unset from 'lodash/unset';
|
||||||
import * as mime from 'mime-types';
|
|
||||||
import { getOAuth2AdditionalParameters } from 'n8n-nodes-base/dist/nodes/HttpRequest/GenericFunctions';
|
import { getOAuth2AdditionalParameters } from 'n8n-nodes-base/dist/nodes/HttpRequest/GenericFunctions';
|
||||||
import type {
|
import type {
|
||||||
IDataObject,
|
IDataObject,
|
||||||
|
@ -146,6 +145,25 @@ const defaultOptimizer = <T>(response: T) => {
|
||||||
return String(response);
|
return String(response);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function isBinary(data: unknown) {
|
||||||
|
// Check if data is a Buffer
|
||||||
|
if (Buffer.isBuffer(data)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If data is a string, assume it's text unless it contains null characters.
|
||||||
|
if (typeof data === 'string') {
|
||||||
|
// If the string contains a null character, it's likely binary.
|
||||||
|
if (data.includes('\0')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For any other type, assume it's not binary.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const htmlOptimizer = (ctx: ISupplyDataFunctions, itemIndex: number, maxLength: number) => {
|
const htmlOptimizer = (ctx: ISupplyDataFunctions, itemIndex: number, maxLength: number) => {
|
||||||
const cssSelector = ctx.getNodeParameter('cssSelector', itemIndex, '') as string;
|
const cssSelector = ctx.getNodeParameter('cssSelector', itemIndex, '') as string;
|
||||||
const onlyContent = ctx.getNodeParameter('onlyContent', itemIndex, false) as boolean;
|
const onlyContent = ctx.getNodeParameter('onlyContent', itemIndex, false) as boolean;
|
||||||
|
@ -755,13 +773,8 @@ export const configureToolFunction = (
|
||||||
if (!response) {
|
if (!response) {
|
||||||
try {
|
try {
|
||||||
// Check if the response is binary data
|
// Check if the response is binary data
|
||||||
if (fullResponse?.headers?.['content-type']) {
|
if (fullResponse.body && isBinary(fullResponse.body)) {
|
||||||
const contentType = fullResponse.headers['content-type'] as string;
|
throw new NodeOperationError(ctx.getNode(), 'Binary data is not supported');
|
||||||
const mimeType = contentType.split(';')[0].trim();
|
|
||||||
|
|
||||||
if (mime.charset(mimeType) !== 'UTF-8') {
|
|
||||||
throw new NodeOperationError(ctx.getNode(), 'Binary data is not supported');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
response = optimizeResponse(fullResponse.body);
|
response = optimizeResponse(fullResponse.body);
|
||||||
|
|
Loading…
Reference in a new issue