Skip to content

Commit ee57cea

Browse files
authored
Merge pull request #190 from lifeomic/EOCI-745-prevent-recursion
[EOCI-745] prevent recursive range error on redirects
2 parents 249e8b4 + 93cb037 commit ee57cea

File tree

2 files changed

+36
-8
lines changed

2 files changed

+36
-8
lines changed

src/alpha.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
import pick from 'lodash/pick';
21
import merge from 'lodash/merge';
2+
import pick from 'lodash/pick';
33

4+
import { Handler } from 'aws-lambda';
45
import axios, { Axios, AxiosAdapter, AxiosHeaders, AxiosResponse } from 'axios';
56
import cloneDeep from 'lodash/cloneDeep';
67
import { AlphaOptions, AlphaResponse, HandlerRequest } from './types';
7-
import { Handler } from 'aws-lambda';
88

9+
import { InvocationRequest } from '@aws-sdk/client-lambda';
910
import { adapters } from './adapters';
10-
import { interceptors } from './interceptors';
1111
import { RequestError } from './adapters/helpers/requestError';
12+
import { interceptors } from './interceptors';
1213
import { resolve } from './resolve';
13-
import { InvocationRequest } from '@aws-sdk/client-lambda';
1414

1515
const ALPHA_CONFIG = ['adapter', 'lambda', 'Lambda', 'retry', '__retryCount'];
1616

@@ -72,15 +72,26 @@ export class Alpha extends Axios {
7272

7373
const castResp = response as any as AxiosResponse;
7474

75-
if (castResp.status === 301 || castResp.status === 302) {
75+
const redirectUrl = castResp.headers.location as string;
76+
77+
if (
78+
(castResp.status === 301 || castResp.status === 302) &&
79+
redirectUrl
80+
) {
7681
if (maxRedirects === 0) {
7782
const request = castResp.request as InvocationRequest | HandlerRequest;
7883
throw new RequestError('Exceeded maximum number of redirects.', castResp.config, request, castResp);
7984
}
8085

8186
const redirect = cloneDeep(config);
8287
redirect.maxRedirects = maxRedirects - 1;
83-
redirect.url = resolve(castResp.headers.location as string, castResp.config.url);
88+
redirect.url = resolve(redirectUrl, castResp.config.url);
89+
90+
// Prevent recursive loops
91+
if (redirect.url === config.url) {
92+
return response as R;
93+
}
94+
8495
return this.request(redirect);
8596
}
8697

test/redirects.test.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { Alpha } from '../src';
2-
import nock from 'nock';
31
import { InvokeCommand, Lambda } from '@aws-sdk/client-lambda';
42
import { mockClient } from 'aws-sdk-client-mock';
3+
import nock from 'nock';
4+
import { Alpha } from '../src';
55
import { createResponse, prepResponse } from './utils';
66

77
const mockLambda = mockClient(Lambda);
@@ -171,3 +171,20 @@ test('Redirects can be explicitly limited', async () => {
171171
expect(error.response.headers.location).toBe('/two');
172172
expect(server.isDone()).toBe(true);
173173
});
174+
175+
test('A Lambda should not follow a redirect back to itself', async () => {
176+
createResponse(mockLambda, {
177+
StatusCode: 200,
178+
Payload: {
179+
headers: { location: 'lambda://test' },
180+
statusCode: 302,
181+
},
182+
});
183+
184+
const response = await ctx.alpha.get('lambda://test');
185+
186+
// The desired behavior is to receive the 302 response, not to recursively follow it.
187+
expect(response.status).toBe(302);
188+
// Ensure we only called the lambda once.
189+
expect(mockLambda.commandCalls(InvokeCommand)).toHaveLength(1);
190+
});

0 commit comments

Comments
 (0)