Skip to content

Commit 9e8f86b

Browse files
authored
Append querystring to redirects (#304)
1 parent cbc8870 commit 9e8f86b

File tree

6 files changed

+1025
-1193
lines changed

6 files changed

+1025
-1193
lines changed

packages/proxy/src/handler.ts

+33-16
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
import { STATUS_CODES } from 'http';
2+
23
import {
34
CloudFrontHeaders,
45
CloudFrontResultResponse,
56
CloudFrontRequestEvent,
67
CloudFrontRequest,
78
} from 'aws-lambda';
89

10+
import { appendQuerystring } from './util/append-querystring';
911
import { fetchProxyConfig } from './util/fetch-proxy-config';
1012
import { generateCloudFrontHeaders } from './util/generate-cloudfront-headers';
11-
import { ProxyConfig, RouteResult } from './types';
12-
import { Proxy } from './proxy';
1313
import {
1414
createCustomOriginFromApiGateway,
1515
createCustomOriginFromUrl,
1616
serveRequestFromCustomOrigin,
1717
serveRequestFromS3Origin,
1818
} from './util/custom-origin';
19+
import { Proxy } from './proxy';
20+
import { ProxyConfig, RouteResult } from './types';
1921

2022
let proxyConfig: ProxyConfig;
2123
let proxy: Proxy;
@@ -31,23 +33,38 @@ function isRedirect(
3133
routeResult.status >= 300 &&
3234
routeResult.status <= 309
3335
) {
34-
if ('Location' in routeResult.headers) {
35-
let headers: CloudFrontHeaders = {};
36-
37-
// If the redirect is permanent, cache the result
38-
if (routeResult.status === 301 || routeResult.status === 308) {
39-
headers['cache-control'] = [
36+
const redirectTarget = routeResult.headers['Location'];
37+
if (redirectTarget) {
38+
// Append the original querystring to the redirect
39+
const redirectTargetWithQuerystring = routeResult.uri_args
40+
? appendQuerystring(redirectTarget, routeResult.uri_args)
41+
: redirectTarget;
42+
43+
// Override the Location header value with the appended querystring
44+
routeResult.headers['Location'] = redirectTargetWithQuerystring;
45+
46+
// Redirects are not cached, see discussion for details:
47+
// https://github.com/milliHQ/terraform-aws-next-js/issues/296
48+
const initialHeaders: CloudFrontHeaders = {
49+
'cache-control': [
4050
{
4151
key: 'Cache-Control',
42-
value: 'public,max-age=31536000,immutable',
52+
value: 'public, max-age=0, must-revalidate',
53+
},
54+
],
55+
'content-type': [
56+
{
57+
key: 'Content-Type',
58+
value: 'text/plain',
4359
},
44-
];
45-
}
60+
],
61+
};
4662

4763
return {
4864
status: routeResult.status.toString(),
4965
statusDescription: STATUS_CODES[routeResult.status],
50-
headers: generateCloudFrontHeaders(headers, routeResult.headers),
66+
headers: generateCloudFrontHeaders(initialHeaders, routeResult.headers),
67+
body: `Redirecting to ${redirectTargetWithQuerystring} (${routeResult.status})`,
5168
};
5269
}
5370
}
@@ -77,7 +94,6 @@ async function main(
7794
][0].value;
7895
const apiEndpoint = request.origin!.s3!.customHeaders['x-env-api-endpoint'][0]
7996
.value;
80-
let headers: Record<string, string> = {};
8197

8298
try {
8399
if (!proxyConfig) {
@@ -107,9 +123,10 @@ async function main(
107123

108124
// Append query string if we have one
109125
// @see: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-event-structure.html
110-
const requestPath = `${request.uri}${
111-
request.querystring !== '' ? `?${request.querystring}` : ''
112-
}`;
126+
const requestPath =
127+
request.querystring !== ''
128+
? `${request.uri}?${request.querystring}`
129+
: request.uri;
113130
const proxyResult = proxy.route(requestPath);
114131

115132
// Check for redirect
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { URL, URLSearchParams } from 'url';
2+
3+
import isURL from './is-url';
4+
5+
/**
6+
* Append a querystring to a relative or absolute URL.
7+
* Already existing searchParams are not overridden by the new searchParams.
8+
*
9+
* @param url The relative or absolute URL
10+
* @param searchParams The searchParams that should be merged with the input URL
11+
*/
12+
function appendQuerystring(url: string, searchParams: URLSearchParams): string {
13+
const urlObj = new URL(url, 'https://n');
14+
const combinedSearchParams = new URLSearchParams({
15+
...Object.fromEntries(searchParams),
16+
...Object.fromEntries(urlObj.searchParams),
17+
}).toString();
18+
19+
if (combinedSearchParams == '') {
20+
return url;
21+
}
22+
23+
if (isURL(url)) {
24+
urlObj.search = '';
25+
return `${urlObj.toString()}?${combinedSearchParams}`;
26+
}
27+
28+
return `${urlObj.pathname}?${combinedSearchParams}`;
29+
}
30+
31+
export { appendQuerystring };

0 commit comments

Comments
 (0)