mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 20:24:05 -08:00
fix(core): Remove HTTP body for GET, HEAD, and OPTIONS requests (#3621)
Co-authored-by: Jonathan Bennetts <jonathan.bennetts@gmail.com> Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <aditya@netroy.in>
This commit is contained in:
parent
bcbff76055
commit
d85d0ecf45
|
@ -31,6 +31,7 @@ import { access as fsAccess, writeFile as fsWriteFile } from 'fs/promises';
|
|||
import { IncomingMessage, type IncomingHttpHeaders } from 'http';
|
||||
import { Agent, type AgentOptions } from 'https';
|
||||
import get from 'lodash/get';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import pick from 'lodash/pick';
|
||||
import { extension, lookup } from 'mime-types';
|
||||
import type {
|
||||
|
@ -962,9 +963,21 @@ function convertN8nRequestToAxios(n8nRequest: IHttpRequestOptions): AxiosRequest
|
|||
return axiosRequest;
|
||||
}
|
||||
|
||||
const NoBodyHttpMethods = ['GET', 'HEAD', 'OPTIONS'];
|
||||
|
||||
/** Remove empty request body on GET, HEAD, and OPTIONS requests */
|
||||
export const removeEmptyBody = (requestOptions: IHttpRequestOptions | IRequestOptions) => {
|
||||
const method = requestOptions.method || 'GET';
|
||||
if (NoBodyHttpMethods.includes(method) && isEmpty(requestOptions.body)) {
|
||||
delete requestOptions.body;
|
||||
}
|
||||
};
|
||||
|
||||
async function httpRequest(
|
||||
requestOptions: IHttpRequestOptions,
|
||||
): Promise<IN8nHttpFullResponse | IN8nHttpResponse> {
|
||||
removeEmptyBody(requestOptions);
|
||||
|
||||
let axiosRequest = convertN8nRequestToAxios(requestOptions);
|
||||
if (
|
||||
axiosRequest.data === undefined ||
|
||||
|
@ -972,6 +985,7 @@ async function httpRequest(
|
|||
) {
|
||||
delete axiosRequest.data;
|
||||
}
|
||||
|
||||
let result: AxiosResponse<any>;
|
||||
try {
|
||||
result = await axios(axiosRequest);
|
||||
|
@ -1276,6 +1290,8 @@ export async function requestOAuth2(
|
|||
oAuth2Options?: IOAuth2Options,
|
||||
isN8nRequest = false,
|
||||
) {
|
||||
removeEmptyBody(requestOptions);
|
||||
|
||||
const credentials = (await this.getCredentials(
|
||||
credentialsType,
|
||||
)) as unknown as OAuth2CredentialData;
|
||||
|
@ -1511,6 +1527,8 @@ export async function requestOAuth1(
|
|||
requestOptions: IHttpRequestOptions | IRequestOptions,
|
||||
isN8nRequest = false,
|
||||
) {
|
||||
removeEmptyBody(requestOptions);
|
||||
|
||||
const credentials = await this.getCredentials(credentialsType);
|
||||
|
||||
if (credentials === undefined) {
|
||||
|
@ -1584,9 +1602,12 @@ export async function httpRequestWithAuthentication(
|
|||
additionalData: IWorkflowExecuteAdditionalData,
|
||||
additionalCredentialOptions?: IAdditionalCredentialOptions,
|
||||
) {
|
||||
removeEmptyBody(requestOptions);
|
||||
|
||||
let credentialsDecrypted: ICredentialDataDecryptedObject | undefined;
|
||||
try {
|
||||
const parentTypes = additionalData.credentialsHelper.getParentTypes(credentialsType);
|
||||
|
||||
if (parentTypes.includes('oAuth1Api')) {
|
||||
return await requestOAuth1.call(this, credentialsType, requestOptions, true);
|
||||
}
|
||||
|
@ -1777,6 +1798,8 @@ export async function requestWithAuthentication(
|
|||
additionalCredentialOptions?: IAdditionalCredentialOptions,
|
||||
itemIndex?: number,
|
||||
) {
|
||||
removeEmptyBody(requestOptions);
|
||||
|
||||
let credentialsDecrypted: ICredentialDataDecryptedObject | undefined;
|
||||
|
||||
try {
|
||||
|
|
|
@ -4,6 +4,7 @@ import {
|
|||
parseIncomingMessage,
|
||||
parseRequestObject,
|
||||
proxyRequestToAxios,
|
||||
removeEmptyBody,
|
||||
setBinaryDataBuffer,
|
||||
} from '@/NodeExecuteFunctions';
|
||||
import { mkdtempSync, readFileSync } from 'fs';
|
||||
|
@ -12,7 +13,9 @@ import { mock } from 'jest-mock-extended';
|
|||
import type {
|
||||
IBinaryData,
|
||||
IHttpRequestMethods,
|
||||
IHttpRequestOptions,
|
||||
INode,
|
||||
IRequestOptions,
|
||||
ITaskDataConnections,
|
||||
IWorkflowExecuteAdditionalData,
|
||||
Workflow,
|
||||
|
@ -458,4 +461,42 @@ describe('NodeExecuteFunctions', () => {
|
|||
expect(output[0].a === input.a).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeEmptyBody', () => {
|
||||
test.each(['GET', 'HEAD', 'OPTIONS'] as IHttpRequestMethods[])(
|
||||
'Should remove empty body for %s',
|
||||
async (method) => {
|
||||
const requestOptions = {
|
||||
method,
|
||||
body: {},
|
||||
} as IHttpRequestOptions | IRequestOptions;
|
||||
removeEmptyBody(requestOptions);
|
||||
expect(requestOptions.body).toEqual(undefined);
|
||||
},
|
||||
);
|
||||
|
||||
test.each(['GET', 'HEAD', 'OPTIONS'] as IHttpRequestMethods[])(
|
||||
'Should not remove non-empty body for %s',
|
||||
async (method) => {
|
||||
const requestOptions = {
|
||||
method,
|
||||
body: { test: true },
|
||||
} as IHttpRequestOptions | IRequestOptions;
|
||||
removeEmptyBody(requestOptions);
|
||||
expect(requestOptions.body).toEqual({ test: true });
|
||||
},
|
||||
);
|
||||
|
||||
test.each(['POST', 'PUT', 'PATCH', 'DELETE'] as IHttpRequestMethods[])(
|
||||
'Should not remove empty body for %s',
|
||||
async (method) => {
|
||||
const requestOptions = {
|
||||
method,
|
||||
body: {},
|
||||
} as IHttpRequestOptions | IRequestOptions;
|
||||
removeEmptyBody(requestOptions);
|
||||
expect(requestOptions.body).toEqual({});
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue