Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/http/core/response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1262,59 +1262,64 @@
*
* @param body - Response body (string, Buffer, object, array, or undefined)
*/
send(body?: string | Buffer | Record<string, unknown> | unknown[]): void {
if (this.aborted) {
return; // Silently ignore if connection aborted
}

if (this.finished) {
return;
}

if (this.sending) {
throw new Error('Response already being sent');
}

// Serialize body outside atomic so compression can inspect/modify headers
let finalBody: string | Buffer | undefined;

if (body === null || body === undefined) {
finalBody = undefined;
} else if (typeof body === 'string' || Buffer.isBuffer(body)) {
finalBody = body;
} else if (typeof body === 'object') {
if (!this._headersSent && !this.hasHeader('content-type')) {
this.setHeader('content-type', 'application/json; charset=utf-8');
}
finalBody = JSON.stringify(body);
} else {
finalBody = String(body);
}

// RFC 9110 §9.3.2: HEAD responses must have identical headers to GET but no body.
if (this.req?.method === 'HEAD') {
finalBody = undefined;
}

this.sending = true;

// Apply compression if configured and body is present
if (this.compressionHandler && this.req && finalBody) {
const bodyBuffer = Buffer.isBuffer(finalBody) ? finalBody : Buffer.from(finalBody);
this.compressionHandler
.compressBuffer(this.req, this, bodyBuffer)
.then((compressed) => this._sendInternal(compressed))
.catch(() => {
this.sending = false;
if (this.finished || this.aborted || this._headersSent) {
return;
}
// Drop headers the compression handler may have set so the
// plaintext fallback isn't tagged with a Content-Encoding
this.removeHeader('content-encoding');
this.removeHeader('content-length');
this.status(500);
this._sendInternal('Internal Server Error');
});
} else {
this._sendInternal(finalBody);
}
}

Check notice on line 1322 in src/http/core/response.ts

View check run for this annotation

codefactor.io / CodeFactor

src/http/core/response.ts#L1265-L1322

Complex Method

/**
* Internal method to perform the actual uWS send after optional compression
Expand Down
13 changes: 13 additions & 0 deletions src/http/routing/route-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,19 @@ export class RouteRegistry {
metadata,
});

// Auto-register HEAD route for GET routes (RFC 9110 §9.3.2)
if (normalizedMethod === 'GET') {
this.routes.set(`HEAD:${path}`, {
method: 'HEAD',
path,
uwsPath,
pattern,
paramNames,
isComplex,
handler,
metadata,
});
}
// Get the uWS method function
const uwsMethodFn = this.uwsApp[uwsMethod as keyof uWS.TemplatedApp] as any;

Expand Down