diff --git a/packages/cultmesh-ts/src/content.ts b/packages/cultmesh-ts/src/content.ts index 3191a285..a0f3f06d 100644 --- a/packages/cultmesh-ts/src/content.ts +++ b/packages/cultmesh-ts/src/content.ts @@ -2,7 +2,7 @@ import { constants } from "node:fs"; import { open } from "node:fs/promises"; import type { IncomingMessage, ServerResponse } from "node:http"; import { join } from "node:path"; -import { DEFAULT_CHUNK_SIZE_BYTES, EMPTY_SHA256, chunkRecordKey, parseSha256Hex, sha256Hex } from "cultnet-ts/content"; +import { DEFAULT_CHUNK_SIZE_BYTES, EMPTY_SHA256, chunkRecordKey, isNullOrWhiteSpaceCSharp, parseSha256Hex, sha256Hex } from "cultnet-ts/content"; /** What the provider reads of a request. The path and the headers are never read: the route is the query alone. */ export interface ContentChunkRequest { method: string; url: string; } @@ -63,7 +63,7 @@ export function createContentChunkHandler(store: ContentChunkStore, options: Con const [hash, ...otherHashes] = query.getAll("chunkHash"); const [key = "", ...otherKeys] = query.getAll("recordKey"); hex = parseSha256Hex(hash ?? ""); - if (otherHashes.length || otherKeys.length || (key.trim() !== "" && key !== chunkRecordKey(hex))) return refusal(400); + if (otherHashes.length || otherKeys.length || (!isNullOrWhiteSpaceCSharp(key) && key !== chunkRecordKey(hex))) return refusal(400); } catch { return refusal(400); } if (hex === EMPTY_SHA256) return chunkAnswer(new Uint8Array()); let bytes: Uint8Array | undefined; diff --git a/packages/cultnet-ts/src/content.ts b/packages/cultnet-ts/src/content.ts index 8474c396..323a59e9 100644 --- a/packages/cultnet-ts/src/content.ts +++ b/packages/cultnet-ts/src/content.ts @@ -12,6 +12,9 @@ import { checkPayloadDepth } from "@gamecult/cultcache-ts/document"; import { isNullOrWhiteSpaceCSharp, trimCSharp } from "./cultmesh-authority"; import { wellFormed } from "./utf8-bound"; +/** C#'s `string.IsNullOrWhiteSpace`, the one blank rule every consumer of the content shapes shares. */ +export { isNullOrWhiteSpaceCSharp }; + export const CULTMESH_CDN_MANIFEST_SCHEMA = "gamecult.mesh.cdn_artifact_manifest.v1"; export const DEFAULT_CHUNK_SIZE_BYTES = 4 * 1024 * 1024; export const EMPTY_SHA256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";