Added auth and request storage
This commit is contained in:
@@ -11,6 +11,7 @@ import { ApplicationError, normalizePublicError } from '../../errors/index.ts';
|
||||
import { HTTP_STATUS_CODE_BAD_REQUEST, HTTP_STATUS_CODE_NO_CONTENT } from '../../constants.ts';
|
||||
import { HonoSSEStream } from '../stream/hono-sse-stream.ts';
|
||||
import { HttpRequestStream } from '../stream/http-request-stream.ts';
|
||||
import { normalizeRequestHeaders } from './request-headers.ts';
|
||||
|
||||
/** Hono context key where decoded Extended JSON bodies are stored. */
|
||||
const PARSED_BODY_KEY = 'parsedBody';
|
||||
@@ -110,6 +111,7 @@ export class HttpTransportRouter implements TransportRouter {
|
||||
|
||||
return {
|
||||
path: context.req.path,
|
||||
headers: normalizeRequestHeaders(context.req.header()),
|
||||
...(body === undefined ? {} : { body }),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import type { RequestHeaders } from '../../routes/types.ts';
|
||||
import { ApplicationError } from '../../errors/index.ts';
|
||||
import { HTTP_STATUS_CODE_BAD_REQUEST } from '../../constants.ts';
|
||||
|
||||
/** RFC 9110 field-name token grammar. */
|
||||
const HEADER_NAME_PATTERN = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
||||
|
||||
/**
|
||||
* Validate and normalize request headers at a transport boundary.
|
||||
*
|
||||
* Lowercase names give HTTP and WebSocket routes identical lookup semantics.
|
||||
* Case-insensitive duplicates are rejected instead of selecting an ambiguous
|
||||
* authentication value. Header values may not contain line breaks.
|
||||
*/
|
||||
export const normalizeRequestHeaders = (headers: Readonly<Record<string, string>>): RequestHeaders => {
|
||||
const normalizedEntries: Array<[string, string]> = [];
|
||||
const names = new Set<string>();
|
||||
|
||||
for (const [ name, value ] of Object.entries(headers)) {
|
||||
if (!HEADER_NAME_PATTERN.test(name)) {
|
||||
throw new ApplicationError(HTTP_STATUS_CODE_BAD_REQUEST, 'Invalid request header name');
|
||||
}
|
||||
|
||||
if (value.includes('\r') || value.includes('\n')) {
|
||||
throw new ApplicationError(HTTP_STATUS_CODE_BAD_REQUEST, 'Invalid request header value');
|
||||
}
|
||||
|
||||
const normalizedName = name.toLowerCase();
|
||||
if (names.has(normalizedName)) {
|
||||
throw new ApplicationError(HTTP_STATUS_CODE_BAD_REQUEST, 'Duplicate request header name');
|
||||
}
|
||||
|
||||
names.add(normalizedName);
|
||||
normalizedEntries.push([ normalizedName, value ]);
|
||||
}
|
||||
|
||||
return Object.freeze(Object.fromEntries(normalizedEntries));
|
||||
};
|
||||
@@ -13,6 +13,7 @@ import type { AppEnv, UpgradeTransportRouter } from './transport-router.ts';
|
||||
import { ApplicationError, normalizePublicError } from '../../errors/index.ts';
|
||||
import { HTTP_STATUS_CODE_BAD_REQUEST } from '../../constants.ts';
|
||||
import { WSStream } from '../stream/ws-stream.ts';
|
||||
import { normalizeRequestHeaders } from './request-headers.ts';
|
||||
|
||||
/** Default WebSocket upgrade path for application messages. */
|
||||
const WS_ROUTE = '/ws';
|
||||
@@ -24,6 +25,7 @@ const wsRequestSchema = z
|
||||
.optional(),
|
||||
path: z.string().min(1),
|
||||
body: z.unknown().optional(),
|
||||
headers: z.record(z.string(), z.string()).optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
@@ -208,6 +210,7 @@ export class WsTransportRouter implements UpgradeTransportRouter {
|
||||
path: envelope.path,
|
||||
...(envelope.id === undefined ? {} : { requestId: envelope.id }),
|
||||
...(envelope.body === undefined ? {} : { body: envelope.body }),
|
||||
...(envelope.headers === undefined ? {} : { headers: normalizeRequestHeaders(envelope.headers) }),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user