Skip to content

Commit 6c8055f

Browse files
authored
feat: Add configurable request body size limit option (#380)
* feat: Add configurable request body size limit option
1 parent 9a7da28 commit 6c8055f

File tree

5 files changed

+106
-1
lines changed

5 files changed

+106
-1
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,14 @@ with the CLI.
158158
npx faas-js-runtime ./index.js
159159
```
160160

161+
### --bodyLimit
162+
Sets the maximum allowed payload size for incoming requests. Default is '1mb'.
163+
164+
Example:
165+
```console
166+
faas-js-runtime function.js --bodyLimit 2mb
167+
```
168+
161169
## Debugging Locally
162170

163171
During local development, it is often necessary to set breakpoints in your code for debugging. Since functions are just javascript files, using any current debugging(VS Code, Chrome Dev Tools) method will work. The linked blog post shows how to setup and use VS Code for development debugging.

bin/cli.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ program
1313
.option('--log-level <log-level>', 'change the log level of the function', defaults.LOG_LEVEL)
1414
.option('--port <port>', 'change the port the runtime listens on', defaults.PORT)
1515
.option('--include-raw', 'include the raw body in the request context', defaults.INCLUDE_RAW)
16+
.option('--bodyLimit <bodyLimit>)', 'maximum size of the request payload in bytes', defaults.BODY_LIMIT)
1617
.arguments('<file>')
1718
.action(runServer);
1819

@@ -26,6 +27,7 @@ async function runServer(file) {
2627
logLevel: process.env.FUNC_LOG_LEVEL || programOpts['logLevel'] || defaults.LOG_LEVEL,
2728
port: process.env.FUNC_PORT || programOpts.port || defaults.PORT,
2829
includeRaw: process.env.FUNC_INCLUDE_RAW ? true : programOpts.includeRaw || defaults.INCLUDE_RAW,
30+
bodyLimit: process.env.FUNC_BODY_LIMIT || programOpts.bodyLimit || defaults.BODY_LIMIT
2931
};
3032

3133
const filePath = extractFullPath(file);

index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export declare const defaults: {
2121
LOG_LEVEL: LogLevel,
2222
PORT: number,
2323
INCLUDE_RAW: boolean,
24+
BODY_LIMIT: number,
2425
};
2526

2627
// re-export

index.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ const PORT = 8080;
2121
// Don't Include Raw body by default
2222
const INCLUDE_RAW = false;
2323

24+
// Default maximum request payload size (1MB in bytes)
25+
const BODY_LIMIT = 1048576;
26+
2427
/**
2528
* Starts the provided Function. If the function is a module, it will be
2629
* inspected for init, shutdown, cors, liveness, and readiness functions and those
@@ -113,6 +116,7 @@ function initializeServer(config) {
113116
}),
114117
},
115118
},
119+
bodyLimit: Number(config.bodyLimit),
116120
});
117121

118122
if (config.includeRaw) {
@@ -191,13 +195,15 @@ function initializeServer(config) {
191195
* @param {String} options.config Path to a func.yaml file
192196
* @param {String} options.logLevel Log level - one of 'fatal', 'error', 'warn', 'info', 'debug', 'trace', 'silent'
193197
* @param {number} options.port Port to listen on
198+
* @param {number} [options.bodyLimit=1048576] - Maximum request payload size in bytes
194199
* @returns {Config} Configuration object
195200
*/
196201
function loadConfig(options) {
197202
const opts = { ...options, ...readFuncYaml(options.config) };
198203
opts.logLevel = opts.logLevel || LOG_LEVEL;
199204
opts.port = opts.port || PORT;
200205
opts.includeRaw = opts.includeRaw || INCLUDE_RAW;
206+
opts.bodyLimit = opts.bodyLimit || BODY_LIMIT;
201207
return opts;
202208
}
203209

@@ -235,5 +241,5 @@ function readFuncYaml(fileOrDirPath) {
235241

236242
module.exports = exports = {
237243
start,
238-
defaults: { LOG_LEVEL, PORT, INCLUDE_RAW },
244+
defaults: { LOG_LEVEL, PORT, INCLUDE_RAW, BODY_LIMIT },
239245
};

test/test-http-body.js

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,91 @@ test('Provides HTTP POST empty body as empty string parameter and rawBody', t =>
135135
});
136136
}, errHandler(t));
137137
});
138+
139+
test('Rejects HTTP POST exceeding bodyLimit', t => {
140+
const largeBody = 'x'.repeat(1048576 + 1);
141+
t.plan(2);
142+
start((_, receivedBody) => receivedBody, { bodyLimit: 1048576 })
143+
.then(server => {
144+
request(server)
145+
.post('/')
146+
.send(largeBody)
147+
.set({ 'Content-Type': 'text/plain' })
148+
.expect(413)
149+
.end((err, res) => {
150+
t.error(err, 'No error');
151+
t.equal(res.status, 413, 'Should reject payload larger than limit');
152+
t.end();
153+
server.close();
154+
});
155+
}, errHandler(t));
156+
});
157+
158+
test('Accepts HTTP POST within bodyLimit', t => {
159+
const body = 'x'.repeat(1048576);
160+
t.plan(2);
161+
start((_, receivedBody) => {
162+
t.equal(receivedBody, body);
163+
return receivedBody;
164+
}, { bodyLimit: 1048576 })
165+
.then(server => {
166+
request(server)
167+
.post('/')
168+
.send(body)
169+
.set({ 'Content-Type': 'text/plain' })
170+
.expect('Content-Type', /plain/)
171+
.expect(200)
172+
.end((err, _) => {
173+
t.error(err, 'No error');
174+
t.end();
175+
server.close();
176+
});
177+
}, errHandler(t));
178+
});
179+
180+
test('Rejects payload exceeding environment variable bodyLimit', t => {
181+
const bodyLimit = 1048576;
182+
const largeBody = 'x'.repeat(bodyLimit + 1);
183+
process.env.FUNC_BODY_LIMIT = bodyLimit;
184+
t.plan(2);
185+
start((_, receivedBody) => receivedBody)
186+
.then(server => {
187+
request(server)
188+
.post('/')
189+
.send(largeBody)
190+
.set({ 'Content-Type': 'text/plain' })
191+
.expect(413)
192+
.end((err, res) => {
193+
t.error(err, 'No error');
194+
t.equal(res.status, 413, 'Should reject payload larger than env var limit');
195+
delete process.env.FUNC_BODY_LIMIT;
196+
t.end();
197+
server.close();
198+
});
199+
}, errHandler(t));
200+
});
201+
202+
test('Accepts payload within environment variable bodyLimit', t => {
203+
const bodyLimit = 524288;
204+
const body = 'x'.repeat(bodyLimit);
205+
process.env.FUNC_BODY_LIMIT = bodyLimit;
206+
t.plan(2);
207+
start((_, receivedBody) => {
208+
t.equal(receivedBody, body);
209+
return receivedBody;
210+
})
211+
.then(server => {
212+
request(server)
213+
.post('/')
214+
.send(body)
215+
.set({ 'Content-Type': 'text/plain' })
216+
.expect('Content-Type', /plain/)
217+
.expect(200)
218+
.end((err, _) => {
219+
t.error(err, 'No error');
220+
delete process.env.FUNC_BODY_LIMIT;
221+
t.end();
222+
server.close();
223+
});
224+
}, errHandler(t));
225+
});

0 commit comments

Comments
 (0)