route-adapter: write a body limit as the predecessor's buffering middleware

The adapter skips what its one file shape cannot say. A body limit is the exception: the predecessor
has a buffering middleware and served its own registry name with exactly it, so this is written
rather than skipped, named after the router so the two halves cannot drift.

A limit that is not a whole positive number of bytes takes the route with it. Written without the
limit, the predecessor would carry what the module said not to carry and this module would report
success. Silence stays silence — no middleware, the predecessor's default.
This commit is contained in:
jochen
2026-09-26 16:01:23 +02:00
parent 3d73c9f54e
commit b2e39eb2cd
3 changed files with 105 additions and 3 deletions
+42 -2
View File
@@ -22,7 +22,9 @@ async function predecessor(already: Record<string, string> = {}): Promise<Settin
}
/** The contributions file the mesh writes, in the shape the mesh's own proxy also reads. */
function contributed(...given: { from: string; node?: string; at?: string; name: string; port: number }[]) {
function contributed(
...given: { from: string; node?: string; at?: string; name: string; port: number; limit?: unknown }[]
) {
return {
contributions: 1,
requirement: "route",
@@ -30,7 +32,7 @@ function contributed(...given: { from: string; node?: string; at?: string; name:
from: g.from,
node: g.node ?? "control-node",
at: g.at ?? "",
values: { name: g.name, port: g.port },
values: { name: g.name, port: g.port, ...(g.limit === undefined ? {} : { "max-request-body": g.limit }) },
})),
};
}
@@ -232,3 +234,41 @@ test("it refuses when the predecessor's directory is not there, and says why", a
const settings = { ...defaults, dynamic: join(await mkdtemp(join(tmpdir(), "route-adapter-")), "absent") };
await assert.rejects(reconcile([], settings), /is not there.*`dynamic` setting.*mounts it/s);
});
// **A registry is why a route needs to say this.** Image layers arrive as single requests of
// gigabytes, and the predecessor served its own registry name with a `buffering` middleware for
// exactly that reason. The contribution carries the limit as `max-request-body`, the adapter writes
// the middleware the predecessor already understands, named after the router so the two halves
// cannot drift — and writes nothing of the kind for a route that did not ask.
test("a body limit is written as the predecessor's buffering middleware", async () => {
const settings = await predecessor();
const changed = await pass(settings, contributed(
{ from: "registry", name: "images.example", port: 5001, limit: 21474836480 },
{ from: "forge", name: "git.example", port: 2999 },
));
assert.deepEqual(changed.written, ["mesh-git.example.yml", "mesh-images.example.yml"]);
const written = await readFile(join(settings.dynamic, "mesh-images.example.yml"), "utf8");
assert.match(written, /^ {6}middlewares: \[mesh-images-example-body\]$/m);
assert.match(written, /^ {2}middlewares:\n {4}mesh-images-example-body:\n {6}buffering:\n {8}maxRequestBodyBytes: 21474836480$/m);
// The route that asked for nothing carries no middleware — the predecessor's default stands.
const plain = await readFile(join(settings.dynamic, "mesh-git.example.yml"), "utf8");
assert.doesNotMatch(plain, /middlewares|buffering/);
});
// A limit it cannot honour is a route it does not write. Written without it, the predecessor would
// carry exactly what the module said not to carry, and this module would report success.
test("a body limit that is not a whole number of bytes is skipped and named", () => {
for (const limit of ["20g", 0, -1, 1.5, true, null]) {
const { routes, skipped } = routesFrom(
contributed({ from: "registry", name: "images.example", port: 5001, limit }), defaults.machine);
assert.deepEqual(routes, [], `a limit of ${JSON.stringify(limit)} was served`);
assert.equal(skipped.length, 1);
assert.match(skipped[0]!, /max-request-body/);
}
// And a limit the mesh's own proxy would accept is carried through, as a number.
const { routes } = routesFrom(
contributed({ from: "registry", name: "images.example", port: 5001, limit: 1024 }), defaults.machine);
assert.equal(routes[0]?.maxRequestBody, 1024);
});