"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createReuseportFd = exports.Request = void 0;
const os_1 = require("os");
/**
 * We define our own request class, to ensure that it has integrity against leaks in a secure environment
 * and for better conformance to WHATWG standards.
 */
class Request {
    #body;
    #peerCertificate;
    _nodeRequest;
    _nodeResponse;
    method;
    url;
    headers;
    isWebSocket;
    user; // User object can be attached during authentication
    response;
    __harperRequestUpgraded;
    constructor(nodeRequest, nodeResponse) {
        this.method = nodeRequest.method;
        const url = nodeRequest.url;
        this._nodeRequest = nodeRequest;
        this._nodeResponse = nodeResponse;
        this.url = url;
        this.headers = new Headers(nodeRequest.headers);
        this.__harperRequestUpgraded = false;
    }
    get absoluteURL() {
        return this.protocol + '://' + this.host + this.url;
    }
    get pathname() {
        const queryStart = this.url.indexOf('?');
        if (queryStart > -1)
            return this.url.slice(0, queryStart);
        return this.url;
    }
    set pathname(pathname) {
        const queryStart = this.url.indexOf('?');
        if (queryStart > -1)
            this.url = pathname + this.url.slice(queryStart);
        else
            this.url = pathname;
    }
    get protocol() {
        return this._nodeRequest.socket.encrypted ? 'https' : 'http';
    }
    get ip() {
        return this._nodeRequest.socket.remoteAddress;
    }
    get authorized() {
        return this._nodeRequest.socket.authorized;
    }
    get peerCertificate() {
        // Cache the certificate to avoid repeated parsing overhead
        // getPeerCertificate() calls translatePeerCertificate which parses
        // the raw certificate data each time (via handle.getPeerCertificate() -> SSL_get_peer_certificate)
        // This issue persists in Node.js v24 - https://github.com/nodejs/node/blob/v24.x/lib/_tls_wrap.js#L1117
        if (this.#peerCertificate === undefined) {
            // Pass true to include the full certificate chain with issuerCertificate properties
            // This is required for OCSP verification which needs both the peer cert and its issuer
            this.#peerCertificate = this._nodeRequest.socket.getPeerCertificate?.(true) || null;
        }
        return this.#peerCertificate;
    }
    get mtlsConfig() {
        return this._nodeRequest.socket.server.mtlsConfig;
    }
    get body() {
        return this.#body || (this.#body = new RequestBody(this._nodeRequest));
    }
    get host() {
        return this._nodeRequest.authority || this._nodeRequest.headers.host;
    }
    get hostname() {
        return this._nodeRequest.headers.host;
    }
    get httpVersion() {
        return this._nodeRequest.httpVersion;
    }
    get isAborted() {
        // TODO: implement this
        return false;
    }
    // Expose node request for cases that need direct access (e.g., replication)
    get nodeRequest() {
        return this._nodeRequest;
    }
    sendEarlyHints(link, headers = {}) {
        headers.link = link;
        this._nodeResponse.writeEarlyHints(headers);
    }
}
exports.Request = Request;
class RequestBody {
    #nodeRequest;
    constructor(nodeRequest) {
        this.#nodeRequest = nodeRequest;
    }
    on(event, listener) {
        this.#nodeRequest.on(event, listener);
        return this;
    }
    pipe(destination, options) {
        return this.#nodeRequest.pipe(destination, options);
    }
}
class Headers {
    asObject;
    constructor(asObject) {
        this.asObject = asObject;
    }
    set(name, value) {
        this.asObject[name.toLowerCase()] = value;
    }
    get(name) {
        return this.asObject[name.toLowerCase()];
    }
    has(name) {
        return Object.prototype.hasOwnProperty.call(this.asObject, name.toLowerCase());
    }
    [Symbol.iterator]() {
        return Object.entries(this.asObject)[Symbol.iterator]();
    }
    keys() {
        return Object.keys(this.asObject);
    }
    values() {
        return Object.values(this.asObject);
    }
    delete(name) {
        delete this.asObject[name.toLowerCase()];
    }
    forEach(callback) {
        for (const [key, value] of this) {
            callback(value, key, this);
        }
    }
}
if ((0, os_1.platform)() != 'win32')
    exports.createReuseportFd = require('node-unix-socket').createReuseportFd;
//# sourceMappingURL=Request.js.map