mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
Implement --max-http-header-size (#13577)
This commit is contained in:
@@ -39,6 +39,8 @@
|
||||
#include "ProxyParser.h"
|
||||
#include "QueryParser.h"
|
||||
|
||||
extern "C" size_t BUN_DEFAULT_MAX_HTTP_HEADER_SIZE;
|
||||
|
||||
namespace uWS
|
||||
{
|
||||
|
||||
@@ -207,7 +209,7 @@ namespace uWS
|
||||
/* This guy really has only 30 bits since we reserve two highest bits to chunked encoding parsing state */
|
||||
uint64_t remainingStreamingBytes = 0;
|
||||
|
||||
const size_t MAX_FALLBACK_SIZE = 1024 * 8;
|
||||
const size_t MAX_FALLBACK_SIZE = BUN_DEFAULT_MAX_HTTP_HEADER_SIZE;
|
||||
|
||||
/* Returns UINT_MAX on error. Maximum 999999999 is allowed. */
|
||||
static uint64_t toUnsignedInteger(std::string_view str) {
|
||||
|
||||
@@ -37,3 +37,24 @@ pub fn getBunServerAllClosedPromise(globalThis: *JSC.JSGlobalObject, callframe:
|
||||
|
||||
return globalThis.throwInvalidArgumentTypeValue("server", "bun.Server", value);
|
||||
}
|
||||
|
||||
pub fn getMaxHTTPHeaderSize(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(JSC.conv) JSC.JSValue {
|
||||
_ = globalThis; // autofix
|
||||
_ = callframe; // autofix
|
||||
return JSC.JSValue.jsNumber(bun.http.max_http_header_size);
|
||||
}
|
||||
|
||||
pub fn setMaxHTTPHeaderSize(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(JSC.conv) JSC.JSValue {
|
||||
const arguments = callframe.arguments(1).slice();
|
||||
if (arguments.len < 1) {
|
||||
globalThis.throwNotEnoughArguments("setMaxHTTPHeaderSize", 1, arguments.len);
|
||||
return .zero;
|
||||
}
|
||||
const value = arguments[0];
|
||||
const num = value.coerceToInt64(globalThis);
|
||||
if (num <= 0) {
|
||||
return globalThis.throwInvalidArgumentTypeValue("maxHeaderSize", "non-negative integer", value);
|
||||
}
|
||||
bun.http.max_http_header_size = @intCast(num);
|
||||
return JSC.JSValue.jsNumber(bun.http.max_http_header_size);
|
||||
}
|
||||
|
||||
13
src/cli.zig
13
src/cli.zig
@@ -209,6 +209,7 @@ pub const Arguments = struct {
|
||||
clap.parseParam("-u, --origin <STR>") catch unreachable,
|
||||
clap.parseParam("--conditions <STR>... Pass custom conditions to resolve") catch unreachable,
|
||||
clap.parseParam("--fetch-preconnect <STR>... Preconnect to a URL while code is loading") catch unreachable,
|
||||
clap.parseParam("--max-http-header-size <INT> Set the maximum size of HTTP headers in bytes. Default is 16KiB") catch unreachable,
|
||||
};
|
||||
|
||||
const auto_or_run_params = [_]ParamType{
|
||||
@@ -612,6 +613,18 @@ pub const Arguments = struct {
|
||||
}
|
||||
}
|
||||
|
||||
if (args.option("--max-http-header-size")) |size_str| {
|
||||
const size = std.fmt.parseInt(usize, size_str, 10) catch {
|
||||
Output.errGeneric("Invalid value for --max-http-header-size: \"{s}\". Must be a positive integer\n", .{size_str});
|
||||
Global.exit(1);
|
||||
};
|
||||
if (size == 0) {
|
||||
bun.http.max_http_header_size = 1024 * 1024 * 1024;
|
||||
} else {
|
||||
bun.http.max_http_header_size = size;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.debug.offline_mode_setting = if (args.flag("--prefer-offline"))
|
||||
Bunfig.OfflineMode.offline
|
||||
else if (args.flag("--prefer-latest"))
|
||||
|
||||
@@ -53,6 +53,11 @@ var async_http_id: std.atomic.Value(u32) = std.atomic.Value(u32).init(0);
|
||||
const MAX_REDIRECT_URL_LENGTH = 128 * 1024;
|
||||
var custom_ssl_context_map = std.AutoArrayHashMap(*SSLConfig, *NewHTTPContext(true)).init(bun.default_allocator);
|
||||
|
||||
pub var max_http_header_size: usize = 16 * 1024;
|
||||
comptime {
|
||||
@export(max_http_header_size, .{ .name = "BUN_DEFAULT_MAX_HTTP_HEADER_SIZE" });
|
||||
}
|
||||
|
||||
const print_every = 0;
|
||||
var print_every_i: usize = 0;
|
||||
|
||||
|
||||
@@ -2250,6 +2250,9 @@ function emitAbortNextTick(self) {
|
||||
self.emit("abort");
|
||||
}
|
||||
|
||||
const setMaxHTTPHeaderSize = $newZigFunction("node_http_binding.zig", "setMaxHTTPHeaderSize", 1);
|
||||
const getMaxHTTPHeaderSize = $newZigFunction("node_http_binding.zig", "getMaxHTTPHeaderSize", 0);
|
||||
|
||||
var globalAgent = new Agent();
|
||||
export default {
|
||||
Agent,
|
||||
@@ -2261,7 +2264,12 @@ export default {
|
||||
IncomingMessage,
|
||||
request,
|
||||
get,
|
||||
maxHeaderSize: 16384,
|
||||
get maxHeaderSize() {
|
||||
return getMaxHTTPHeaderSize();
|
||||
},
|
||||
set maxHeaderSize(value) {
|
||||
setMaxHTTPHeaderSize(value);
|
||||
},
|
||||
validateHeaderName,
|
||||
validateHeaderValue,
|
||||
setMaxIdleHTTPParsers(max) {
|
||||
|
||||
33
test/js/node/http/max-header-size-fixture.ts
generated
Normal file
33
test/js/node/http/max-header-size-fixture.ts
generated
Normal file
@@ -0,0 +1,33 @@
|
||||
import http from "node:http";
|
||||
|
||||
if (http.maxHeaderSize !== parseInt(process.env.BUN_HTTP_MAX_HEADER_SIZE, 10)) {
|
||||
throw new Error("BUN_HTTP_MAX_HEADER_SIZE is not set to the correct value");
|
||||
}
|
||||
|
||||
using server = Bun.serve({
|
||||
port: 0,
|
||||
fetch(req) {
|
||||
return new Response(JSON.stringify(req.headers, null, 2));
|
||||
},
|
||||
});
|
||||
|
||||
await fetch(`${server.url}/`, {
|
||||
headers: {
|
||||
"Huge": Buffer.alloc(Math.max(http.maxHeaderSize, 256) - 256, "abc").toString(),
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
await fetch(`${server.url}/`, {
|
||||
headers: {
|
||||
"Huge": Buffer.alloc(http.maxHeaderSize + 1024, "abc").toString(),
|
||||
},
|
||||
});
|
||||
throw new Error("bad");
|
||||
} catch (e) {
|
||||
if (e.message.includes("bad")) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
}
|
||||
83
test/js/node/http/node-http-maxHeaderSize.test.ts
Normal file
83
test/js/node/http/node-http-maxHeaderSize.test.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import http from "node:http";
|
||||
import path from "path";
|
||||
import { test, expect } from "bun:test";
|
||||
import { bunEnv } from "harness";
|
||||
|
||||
test("maxHeaderSize", async () => {
|
||||
const originalMaxHeaderSize = http.maxHeaderSize;
|
||||
expect(http.maxHeaderSize).toBe(16 * 1024);
|
||||
// @ts-expect-error its a liar
|
||||
http.maxHeaderSize = 1024;
|
||||
expect(http.maxHeaderSize).toBe(1024);
|
||||
{
|
||||
using server = Bun.serve({
|
||||
port: 0,
|
||||
|
||||
fetch(req) {
|
||||
return new Response(JSON.stringify(req.headers, null, 2));
|
||||
},
|
||||
});
|
||||
|
||||
expect(
|
||||
async () =>
|
||||
await fetch(`${server.url}/`, {
|
||||
headers: {
|
||||
"Huge": Buffer.alloc(8 * 1024, "abc").toString(),
|
||||
},
|
||||
}),
|
||||
).toThrow();
|
||||
expect(
|
||||
async () =>
|
||||
await fetch(`${server.url}/`, {
|
||||
headers: {
|
||||
"Huge": Buffer.alloc(512, "abc").toString(),
|
||||
},
|
||||
}),
|
||||
).not.toThrow();
|
||||
}
|
||||
http.maxHeaderSize = 16 * 1024;
|
||||
{
|
||||
using server = Bun.serve({
|
||||
port: 0,
|
||||
|
||||
fetch(req) {
|
||||
return new Response(JSON.stringify(req.headers, null, 2));
|
||||
},
|
||||
});
|
||||
|
||||
expect(
|
||||
async () =>
|
||||
await fetch(`${server.url}/`, {
|
||||
headers: {
|
||||
"Huge": Buffer.alloc(15 * 1024, "abc").toString(),
|
||||
},
|
||||
}),
|
||||
).not.toThrow();
|
||||
expect(
|
||||
async () =>
|
||||
await fetch(`${server.url}/`, {
|
||||
headers: {
|
||||
"Huge": Buffer.alloc(17 * 1024, "abc").toString(),
|
||||
},
|
||||
}),
|
||||
).toThrow();
|
||||
}
|
||||
|
||||
http.maxHeaderSize = originalMaxHeaderSize;
|
||||
});
|
||||
|
||||
test("--max-http-header-size=1024", async () => {
|
||||
const size = 1024;
|
||||
bunEnv.BUN_HTTP_MAX_HEADER_SIZE = size;
|
||||
expect(["--max-http-header-size=" + size, path.join(import.meta.dir, "max-header-size-fixture.ts")]).toRun();
|
||||
});
|
||||
|
||||
test("--max-http-header-size=NaN", async () => {
|
||||
expect(["--max-http-header-size=" + "NaN", path.join(import.meta.dir, "max-header-size-fixture.ts")]).not.toRun();
|
||||
});
|
||||
|
||||
test("--max-http-header-size=16*1024", async () => {
|
||||
const size = 16 * 1024;
|
||||
bunEnv.BUN_HTTP_MAX_HEADER_SIZE = size;
|
||||
expect(["--max-http-header-size=" + size, path.join(import.meta.dir, "max-header-size-fixture.ts")]).toRun();
|
||||
});
|
||||
Reference in New Issue
Block a user