mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-09-03 06:18:22 +00:00
70 lines
2.3 KiB
TypeScript
70 lines
2.3 KiB
TypeScript
/** Bounded raw HTTP body intake for GitHub signature verification. */
|
|
|
|
import type { IncomingMessage } from 'node:http'
|
|
|
|
/** HTTP refusal whose message is safe to return without request data. */
|
|
export class WebhookHttpError extends Error {
|
|
override readonly name = 'WebhookHttpError'
|
|
|
|
constructor(
|
|
readonly status: 400 | 401 | 405 | 413 | 415 | 503,
|
|
message: string,
|
|
) {
|
|
super(message)
|
|
}
|
|
}
|
|
|
|
/** Parse a decimal Content-Length or reject an ambiguous header. */
|
|
function contentLength(request: IncomingMessage): number | undefined {
|
|
const value = request.headers['content-length']
|
|
if (value === undefined) return undefined
|
|
if (!/^(0|[1-9]\d*)$/.test(value)) {
|
|
throw new WebhookHttpError(400, 'invalid Content-Length')
|
|
}
|
|
const length = Number(value)
|
|
if (!Number.isSafeInteger(length)) throw new WebhookHttpError(413, 'request body is too large')
|
|
return length
|
|
}
|
|
|
|
/**
|
|
* Read one request body as exact, bounded UTF-8 text.
|
|
* @param request - incoming request before any parser consumes it.
|
|
* @param maxBodyBytes - positive byte ceiling.
|
|
* @returns the decoded body after EOF.
|
|
* @throws {WebhookHttpError} for invalid length, excessive bytes, invalid UTF-8, or an aborted stream.
|
|
*/
|
|
export async function readBoundedUtf8Body(
|
|
request: IncomingMessage,
|
|
maxBodyBytes: number,
|
|
): Promise<string> {
|
|
const declared = contentLength(request)
|
|
if (declared !== undefined && declared > maxBodyBytes) {
|
|
request.resume()
|
|
throw new WebhookHttpError(413, 'request body is too large')
|
|
}
|
|
|
|
const chunks: Buffer[] = []
|
|
let size = 0
|
|
try {
|
|
for await (const raw of request) {
|
|
const chunk = Buffer.isBuffer(raw) ? raw : Buffer.from(raw as string)
|
|
size += chunk.byteLength
|
|
if (size > maxBodyBytes) {
|
|
request.resume()
|
|
throw new WebhookHttpError(413, 'request body is too large')
|
|
}
|
|
chunks.push(chunk)
|
|
}
|
|
} catch (error: unknown) {
|
|
if (error instanceof WebhookHttpError) throw error
|
|
throw new WebhookHttpError(400, 'request body was aborted')
|
|
}
|
|
if (!request.complete) throw new WebhookHttpError(400, 'request body was aborted')
|
|
try {
|
|
return new TextDecoder('utf-8', { fatal: true }).decode(Buffer.concat(chunks, size))
|
|
} catch {
|
|
// TextDecoder is the only statement in the try; GitHub JSON must be valid UTF-8.
|
|
throw new WebhookHttpError(400, 'request body is not valid UTF-8')
|
|
}
|
|
}
|