"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WsHandlerDefinitionLookup = exports.TimeoutHandlerDefinition = exports.ResetConnectionHandlerDefinition = exports.CloseConnectionHandlerDefinition = exports.RejectWebSocketHandlerDefinition = exports.ListenWebSocketHandlerDefinition = exports.EchoWebSocketHandlerDefinition = exports.PassThroughWebSocketHandlerDefinition = void 0;
const _ = require("lodash");
const url = require("url");
const common_tags_1 = require("common-tags");
const serialization_1 = require("../../serialization/serialization");
const request_handler_definitions_1 = require("../requests/request-handler-definitions");
Object.defineProperty(exports, "CloseConnectionHandlerDefinition", { enumerable: true, get: function () { return request_handler_definitions_1.CloseConnectionHandlerDefinition; } });
Object.defineProperty(exports, "ResetConnectionHandlerDefinition", { enumerable: true, get: function () { return request_handler_definitions_1.ResetConnectionHandlerDefinition; } });
Object.defineProperty(exports, "TimeoutHandlerDefinition", { enumerable: true, get: function () { return request_handler_definitions_1.TimeoutHandlerDefinition; } });
class PassThroughWebSocketHandlerDefinition extends serialization_1.Serializable {
    constructor(options = {}) {
        super();
        this.type = 'ws-passthrough';
        this.ignoreHostHttpsErrors = [];
        this.extraCACertificates = [];
        // If a location is provided, and it's not a bare hostname, it must be parseable
        const { forwarding } = options;
        if (forwarding && forwarding.targetHost.includes('/')) {
            const { protocol, hostname, port, path } = url.parse(forwarding.targetHost);
            if (path && path.trim() !== "/") {
                const suggestion = url.format({ protocol, hostname, port }) ||
                    forwarding.targetHost.slice(0, forwarding.targetHost.indexOf('/'));
                throw new Error((0, common_tags_1.stripIndent) `
                    URLs for forwarding cannot include a path, but "${forwarding.targetHost}" does. ${''}Did you mean ${suggestion}?
                `);
            }
        }
        this.forwarding = options.forwarding;
        this.ignoreHostHttpsErrors = options.ignoreHostHttpsErrors || [];
        if (!Array.isArray(this.ignoreHostHttpsErrors) && typeof this.ignoreHostHttpsErrors !== 'boolean') {
            throw new Error("ignoreHostHttpsErrors must be an array or a boolean");
        }
        this.lookupOptions = options.lookupOptions;
        this.proxyConfig = options.proxyConfig;
        this.extraCACertificates =
            options.additionalTrustedCAs ||
                options.trustAdditionalCAs ||
                [];
        this.clientCertificateHostMap = options.clientCertificateHostMap || {};
    }
    explain() {
        return this.forwarding
            ? `forward the websocket to ${this.forwarding.targetHost}`
            : 'pass the request through to the target host';
    }
    /**
     * @internal
     */
    serialize(channel) {
        return {
            type: this.type,
            forwarding: this.forwarding,
            lookupOptions: this.lookupOptions,
            proxyConfig: (0, serialization_1.serializeProxyConfig)(this.proxyConfig, channel),
            ignoreHostCertificateErrors: this.ignoreHostHttpsErrors,
            extraCACertificates: this.extraCACertificates.map((certObject) => {
                // We use toString to make sure that buffers always end up as
                // as UTF-8 string, to avoid serialization issues. Strings are an
                // easy safe format here, since it's really all just plain-text PEM
                // under the hood.
                if ('cert' in certObject) {
                    return { cert: certObject.cert.toString('utf8') };
                }
                else {
                    return certObject;
                }
            }),
            clientCertificateHostMap: _.mapValues(this.clientCertificateHostMap, ({ pfx, passphrase }) => ({ pfx: (0, serialization_1.serializeBuffer)(pfx), passphrase }))
        };
    }
}
exports.PassThroughWebSocketHandlerDefinition = PassThroughWebSocketHandlerDefinition;
class EchoWebSocketHandlerDefinition extends serialization_1.Serializable {
    constructor() {
        super(...arguments);
        this.type = 'ws-echo';
    }
    explain() {
        return "echo all websocket messages";
    }
}
exports.EchoWebSocketHandlerDefinition = EchoWebSocketHandlerDefinition;
class ListenWebSocketHandlerDefinition extends serialization_1.Serializable {
    constructor() {
        super(...arguments);
        this.type = 'ws-listen';
    }
    explain() {
        return "silently accept websocket messages without responding";
    }
}
exports.ListenWebSocketHandlerDefinition = ListenWebSocketHandlerDefinition;
class RejectWebSocketHandlerDefinition extends serialization_1.Serializable {
    constructor(statusCode, statusMessage = 'WebSocket rejected', headers = {}, body = '') {
        super();
        this.statusCode = statusCode;
        this.statusMessage = statusMessage;
        this.headers = headers;
        this.body = body;
        this.type = 'ws-reject';
    }
    explain() {
        return `explicitly reject the websocket upgrade with status ${this.statusCode}`;
    }
}
exports.RejectWebSocketHandlerDefinition = RejectWebSocketHandlerDefinition;
exports.WsHandlerDefinitionLookup = {
    'ws-passthrough': PassThroughWebSocketHandlerDefinition,
    'ws-echo': EchoWebSocketHandlerDefinition,
    'ws-listen': ListenWebSocketHandlerDefinition,
    'ws-reject': RejectWebSocketHandlerDefinition,
    'close-connection': request_handler_definitions_1.CloseConnectionHandlerDefinition,
    'reset-connection': request_handler_definitions_1.ResetConnectionHandlerDefinition,
    'timeout': request_handler_definitions_1.TimeoutHandlerDefinition
};
//# sourceMappingURL=websocket-handler-definitions.js.map