Skip to content

Commit 5f39279

Browse files
committed
fix: koa tests - sanitizeHeaders
Signed-off-by: seven <zilisheng1996@gmail.com>
1 parent 9d2afb8 commit 5f39279

File tree

4 files changed

+71
-15
lines changed

4 files changed

+71
-15
lines changed

src/context.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,30 @@ import { debug } from './common';
1010
// return event.requestContext.identity.sourceIp;
1111
// };
1212

13+
const requestBody = (event: Event) => {
14+
if (event.body === undefined || event.body === null) {
15+
return undefined;
16+
}
17+
const type = typeof event.body;
18+
19+
if (Buffer.isBuffer(event.body)) {
20+
return event.body;
21+
} else if (type === 'string') {
22+
return Buffer.from(event.body as string, event.isBase64Encoded ? 'base64' : 'utf8');
23+
} else if (type === 'object') {
24+
return Buffer.from(JSON.stringify(event.body));
25+
}
26+
27+
throw new Error(`Unexpected event.body type: ${typeof event.body}`);
28+
};
29+
1330
export const constructFrameworkContext = (event: Event, context: Context) => {
1431
debug(`constructFrameworkContext: ${JSON.stringify({ event, context })}`);
1532
const request = new ServerlessRequest({
1633
method: event.httpMethod,
1734
headers: event.headers,
1835
path: event.path,
19-
body:
20-
event.body !== undefined && event.body !== null
21-
? Buffer.from(event.body, event.isBase64Encoded ? 'base64' : 'utf8')
22-
: undefined,
36+
body: requestBody(event),
2337
remoteAddress: '',
2438
url: url.format({
2539
pathname: event.path,

src/serverlessResponse.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { IncomingHttpHeaders, ServerResponse } from 'http';
2-
import { IncomingMessage } from 'node:http';
3-
import ServerlessRequest from './serverlessRequest';
42
import { Socket } from 'node:net';
53
import { debug } from './common';
4+
import ServerlessRequest from './serverlessRequest';
65

76
const headerEnd = '\r\n\r\n';
87

@@ -37,12 +36,8 @@ export default class ServerlessResponse extends ServerResponse {
3736
[BODY]: Buffer[];
3837
[HEADERS]: IncomingHttpHeaders;
3938

40-
static from(res: IncomingMessage): ServerlessResponse {
41-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
42-
// @ts-expect-error
39+
static from(res: ServerlessRequest): ServerlessResponse {
4340
const response = new ServerlessResponse(res);
44-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
45-
// @ts-expect-error
4641
const { statusCode = 0, headers, body } = res;
4742
response.statusCode = statusCode;
4843
response[HEADERS] = headers;

src/transport.ts

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import { Writable } from 'stream';
2+
import { IncomingHttpHeaders } from 'http';
23
import ServerlessRequest from './serverlessRequest';
34
import ServerlessResponse from './serverlessResponse';
45

6+
type MultiValueHeaders = {
7+
[key: string]: string[];
8+
};
59
export const waitForStreamComplete = (stream: Writable): Promise<Writable> => {
610
if (stream.writableFinished || stream.writableEnded) {
711
return Promise.resolve(stream);
@@ -34,17 +38,58 @@ export const waitForStreamComplete = (stream: Writable): Promise<Writable> => {
3438
});
3539
};
3640

41+
const sanitizeHeaders = (headers: IncomingHttpHeaders) => {
42+
return Object.keys(headers).reduce(
43+
(memo, key) => {
44+
const value = headers[key];
45+
46+
if (Array.isArray(value)) {
47+
memo.multiValueHeaders[key] = value;
48+
if (key.toLowerCase() !== 'set-cookie') {
49+
memo.headers[key] = value.join(', ');
50+
}
51+
} else {
52+
memo.headers[key] = value == null ? '' : value.toString();
53+
}
54+
55+
return memo;
56+
},
57+
{
58+
headers: {} as IncomingHttpHeaders,
59+
multiValueHeaders: {} as MultiValueHeaders,
60+
},
61+
);
62+
};
63+
3764
export const buildResponse = ({
3865
request,
3966
response,
4067
}: {
4168
request: ServerlessRequest;
4269
response: ServerlessResponse;
4370
}) => {
71+
const { headers, multiValueHeaders } = sanitizeHeaders(ServerlessResponse.headers(response));
72+
73+
let body = ServerlessResponse.body(response).toString(
74+
request.isBase64Encoded ? 'base64' : 'utf8',
75+
);
76+
if (headers['transfer-encoding'] === 'chunked' || response.chunkedEncoding) {
77+
const raw = ServerlessResponse.body(response).toString().split('\r\n');
78+
const parsed = [];
79+
for (let i = 0; i < raw.length; i += 2) {
80+
const size = parseInt(raw[i], 16);
81+
const value = raw[i + 1];
82+
if (value) {
83+
parsed.push(value.substring(0, size));
84+
}
85+
}
86+
body = parsed.join('');
87+
}
4488
return {
4589
statusCode: response.statusCode,
46-
body: ServerlessResponse.body(response).toString(request.isBase64Encoded ? 'base64' : 'utf8'),
47-
headers: response.headers,
90+
body,
91+
headers,
92+
multiValueHeaders,
4893
isBase64Encoded: request.isBase64Encoded,
4994
};
5095
};

tests/index-koa.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ describe('koa', () => {
5555
ctx.status = 200;
5656
ctx.body = ctx.request.body.hello;
5757
});
58+
app.use(router.routes());
5859

5960
const response = await serverlessAdapter(app)(
6061
{
@@ -76,6 +77,7 @@ describe('koa', () => {
7677
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
7778
ctx.body = ctx.request.body.hello;
7879
});
80+
app.use(router.routes());
7981

8082
const response = await serverlessAdapter(app)(
8183
{
@@ -89,7 +91,7 @@ describe('koa', () => {
8991
defaultContext,
9092
);
9193

92-
expect(response.statusCode).toEqual(200);
94+
expect(response.statusCode).toEqual(204);
9395
expect(response.body).toBeDefined();
9496
});
9597

@@ -98,12 +100,12 @@ describe('koa', () => {
98100
ctx.status = 200;
99101
ctx.body = ctx.request.query.foo;
100102
});
103+
app.use(router.routes());
101104

102105
const response = await serverlessAdapter(app)(
103106
{
104107
...defaultEvent,
105108
httpMethod: 'GET',
106-
path: '/',
107109
queryParameters: {
108110
foo: 'bar',
109111
},

0 commit comments

Comments
 (0)