/// <reference types="node" />
import type * as net from 'net';
import { Readable } from 'stream';
import { Headers, CompletedRequest, CompletedBody, Explainable, RawHeaders } from "../../types";
import { MaybePromise, Replace } from '../../util/type-utils';
import { Serializable, ClientServerChannel, SerializedProxyConfig } from "../../serialization/serialization";
import { ProxyConfig } from '../proxy-config';
import { ForwardingOptions, PassThroughHandlerConnectionOptions, PassThroughLookupOptions } from '../passthrough-handling-definitions';
export interface RequestHandlerDefinition extends Explainable, Serializable {
    type: keyof typeof HandlerDefinitionLookup;
}
export declare type SerializedBuffer = {
    type: 'Buffer';
    data: number[];
};
/**
 * Can be returned from callbacks to override parts of a request.
 *
 * All fields are optional, and omitted values will default to the original
 * request value.
 */
export interface CallbackRequestResult {
    /**
     * A replacement HTTP method, capitalized.
     */
    method?: string;
    /**
     * The full URL to send the request to. If set, this will redirect
     * the request and automatically update the Host header accordingly,
     * unless you also provide a `headers` value that includes a Host
     * header, in which case that will take used as-is.
     */
    url?: string;
    /**
     * The replacement HTTP headers, as an object of string keys and either
     * single string or array of string values.
     */
    headers?: Headers;
    /**
     * A string or buffer, which replaces the request body if set. This will
     * be automatically content-encoded to match the Content-Encoding defined
     * in your request headers.
     *
     * If this is set, the Content-Length header will be automatically updated
     * accordingly to match, unless you also provide a `headers` value that
     * includes a Content-Length header, in which case that will take used
     * as-is.
     *
     * You should only return one body field: either `body`, `rawBody` or
     * `json`.
     */
    body?: string | Buffer | Uint8Array;
    /**
     * A buffer, which replaces the request body if set, which is sent exactly
     * as is, and is not automatically encoded.
     *
     * If this is set, the Content-Length header will be automatically updated
     * accordingly to match, unless you also provide a `headers` value that
     * includes a Content-Length header, in which case that will take used
     * as-is.
     *
     * You should only return one body field: either `body`, `rawBody` or
     * `json`.
     */
    rawBody?: Buffer | Uint8Array;
    /**
     * A JSON value, which will be stringified and send as a JSON-encoded
     * request body. This will be automatically content-encoded to match
     * the Content-Encoding defined in your request headers.
     *
     * If this is set, the Content-Length header will be automatically updated
     * accordingly to match, unless you also provide a `headers` value that
     * includes a Content-Length header, in which case that will take used
     * as-is.
     *
     * You should only return one body field: either `body`, `rawBody` or
     * `json`.
     */
    json?: any;
    /**
     * A response: either a response object defining the fields of a response
     * or the string 'close' to immediately close the connection.
     *
     * See {@link CallbackResponseMessageResult} for the possible fields that can
     * be set to define the response.
     *
     * If set, the request will not be forwarded at all, and this will be used
     * as the response to immediately return to the client (or for 'close', this
     * will immediately close the connection to the client).
     */
    response?: CallbackResponseResult;
}
export declare type CallbackResponseResult = CallbackResponseMessageResult | 'close' | 'reset';
/**
 * Can be returned from callbacks to define parts of a response, or
 * override parts when given an existing repsonse.
 *
 * All fields are optional, and omitted values will default to the original
 * response value or a default value.
 */
export interface CallbackResponseMessageResult {
    /**
     * The response status code as a number.
     *
     * Defaults to 200 if not set.
     */
    statusCode?: number;
    /**
     * Supported only for backward compatibility.
     *
     * @deprecated Use statusCode instead.
     */
    status?: number;
    /**
     * The response status message, as a string. This is ignored for
     * HTTP/2 responses.
     *
     * Defaults to the default status message for the status code if not set.
     */
    statusMessage?: string;
    /**
     * The replacement HTTP headers, as an object of string keys and either
     * single string or array of string values.
     *
     * Defaults to a minimum set of standard required headers if not set.
     */
    headers?: Headers;
    /**
     * A string or buffer, which replaces the response body if set. This will
     * be automatically encoded to match the Content-Encoding defined in your
     * response headers.
     *
     * If this is set, the Content-Length header will be automatically updated
     * accordingly to match, unless you also provide a `headers` value that
     * includes a Content-Length header, in which case that will take used
     * as-is.
     *
     * Defaults to empty.
     *
     * You should only return one body field: either `body`, `rawBody` or
     * `json`.
     */
    body?: string | Buffer | Uint8Array;
    /**
     * A buffer, which replaces the response body if set, which is sent exactly
     * as is, and is not automatically encoded.
     *
     * If this is set, the Content-Length header will be automatically updated
     * accordingly to match, unless you also provide a `headers` value that
     * includes a Content-Length header, in which case that will take used
     * as-is.
     *
     * You should only return one body field: either `body`, `rawBody` or
     * `json`.
     */
    rawBody?: Buffer | Uint8Array;
    /**
     * A JSON value, which will be stringified and send as a JSON-encoded
     * request body. This will be automatically content-encoded to match the
     * Content-Encoding defined in your response headers.
     *
     * If this is set, the Content-Length header will be automatically updated
     * accordingly to match, unless you also provide a `headers` value that
     * includes a Content-Length header, in which case that will take used
     * as-is.
     *
     * You should only return one body field: either `body`, `rawBody` or
     * `json`.
     */
    json?: any;
}
export declare class SimpleHandlerDefinition extends Serializable implements RequestHandlerDefinition {
    status: number;
    statusMessage?: string | undefined;
    data?: string | Uint8Array | Buffer | SerializedBuffer | undefined;
    headers?: Headers | undefined;
    readonly type = "simple";
    constructor(status: number, statusMessage?: string | undefined, data?: string | Uint8Array | Buffer | SerializedBuffer | undefined, headers?: Headers | undefined);
    explain(): string;
}
/**
 * @internal
 */
export interface SerializedCallbackHandlerData {
    type: string;
    name?: string;
    version?: number;
}
/**
 * @internal
 */
export interface CallbackRequestMessage {
    args: [
        Replace<CompletedRequest, {
            body: string;
        }> | CompletedRequest
    ];
}
export declare class CallbackHandlerDefinition extends Serializable implements RequestHandlerDefinition {
    callback: (request: CompletedRequest) => MaybePromise<CallbackResponseResult>;
    readonly type = "callback";
    constructor(callback: (request: CompletedRequest) => MaybePromise<CallbackResponseResult>);
    explain(): string;
    /**
     * @internal
     */
    serialize(channel: ClientServerChannel): SerializedCallbackHandlerData;
}
/**
 * @internal
 */
export interface SerializedStreamHandlerData {
    type: string;
    status: number;
    headers?: Headers;
}
export declare class StreamHandlerDefinition extends Serializable implements RequestHandlerDefinition {
    status: number;
    stream: Readable & {
        done?: true;
    };
    headers?: Headers | undefined;
    readonly type = "stream";
    constructor(status: number, stream: Readable & {
        done?: true;
    }, headers?: Headers | undefined);
    explain(): string;
    /**
     * @internal
     */
    serialize(channel: ClientServerChannel): SerializedStreamHandlerData;
}
export declare class FileHandlerDefinition extends Serializable implements RequestHandlerDefinition {
    status: number;
    statusMessage: string | undefined;
    filePath: string;
    headers?: Headers | undefined;
    readonly type = "file";
    constructor(status: number, statusMessage: string | undefined, filePath: string, headers?: Headers | undefined);
    explain(): string;
}
export interface PassThroughResponse {
    id: string;
    statusCode: number;
    statusMessage?: string;
    headers: Headers;
    rawHeaders: RawHeaders;
    body: CompletedBody;
}
export interface PassThroughHandlerOptions extends PassThroughHandlerConnectionOptions {
    /**
     * Whether to simulate connection errors back to the client.
     *
     * By default (in most cases - see below) when an upstream request fails
     * outright a 502 "Bad Gateway" response is sent to the downstream client,
     * explicitly indicating the failure and containing the error that caused
     * the issue in the response body.
     *
     * Only in the case of upstream connection reset errors is a connection reset
     * normally sent back downstream to existing clients (this behaviour exists
     * for backward compatibility, and will change to match other error behaviour
     * in a future version).
     *
     * When this option is set to `true`, low-level connection failures will
     * always trigger a downstream connection close/reset, rather than a 502
     * response.
     *
     * This includes DNS failures, TLS connection errors, TCP connection resets,
     * etc (but not HTTP non-200 responses, which are still proxied as normal).
     * This is less convenient for debugging in a testing environment or when
     * using a proxy intentionally, but can be more accurate when trying to
     * transparently proxy network traffic, errors and all.
     */
    simulateConnectionErrors?: boolean;
    /**
     * A set of data to automatically transform a request. This includes properties
     * to support many transformation common use cases.
     *
     * For advanced cases, a custom callback using beforeRequest can be used instead.
     * Using this field however where possible is typically simpler, more declarative,
     * and can be more performant. The two options are mutually exclusive: you cannot
     * use both transformRequest and a beforeRequest callback.
     *
     * Only one transformation for each target (method, headers & body) can be
     * specified. If more than one is specified then an error will be thrown when the
     * rule is registered.
     */
    transformRequest?: RequestTransform;
    /**
     * A set of data to automatically transform a response. This includes properties
     * to support many transformation common use cases.
     *
     * For advanced cases, a custom callback using beforeResponse can be used instead.
     * Using this field however where possible is typically simpler, more declarative,
     * and can be more performant. The two options are mutually exclusive: you cannot
     * use both transformResponse and a beforeResponse callback.
     *
     * Only one transformation for each target (status, headers & body) can be
     * specified. If more than one is specified then an error will be thrown when the
     * rule is registered.
     */
    transformResponse?: ResponseTransform;
    /**
     * A callback that will be passed the full request before it is passed through,
     * and which returns an object that defines how the the request content should
     * be transformed before it's passed to the upstream server.
     *
     * The callback can return an object to define how the request should be changed.
     * All fields on the object are optional, and returning undefined is equivalent
     * to returning an empty object (transforming nothing).
     *
     * See {@link CallbackRequestResult} for the possible fields that can be set.
     */
    beforeRequest?: (req: CompletedRequest) => MaybePromise<CallbackRequestResult | void> | void;
    /**
     * A callback that will be passed the full response before it is passed through,
     * and which returns a value that defines how the the response content should
     * be transformed before it's returned to the client.
     *
     * The callback can either return an object to define how the response should be
     * changed, or the string 'close' to immediately close the underlying connection.
     *
     * All fields on the object are optional, and returning undefined is equivalent
     * to returning an empty object (transforming nothing).
     *
     * See {@link CallbackResponseMessageResult} for the possible fields that can be set.
     */
    beforeResponse?: (res: PassThroughResponse) => MaybePromise<CallbackResponseResult | void> | void;
}
export interface RequestTransform {
    /**
     * A replacement HTTP method. Case insensitive.
     */
    replaceMethod?: string;
    /**
     * A headers object which will be merged with the real request headers to add or
     * replace values. Headers with undefined values will be removed.
     */
    updateHeaders?: Headers;
    /**
     * A headers object which will completely replace the real request headers.
     */
    replaceHeaders?: Headers;
    /**
     * A string or buffer that replaces the request body entirely.
     *
     * If this is specified, the upstream request will not wait for the original request
     * body, so this may make responses faster than they would be otherwise given large
     * request bodies or slow/streaming clients.
     */
    replaceBody?: string | Uint8Array | Buffer;
    /**
     * The path to a file, which will be used to replace the request body entirely. The
     * file will be re-read for each request, so the body will always reflect the latest
     * file contents.
     *
     * If this is specified, the upstream request will not wait for the original request
     * body, so this may make responses faster than they would be otherwise given large
     * request bodies or slow/streaming clients.
     */
    replaceBodyFromFile?: string;
    /**
     * A JSON object which will be merged with the real request body. Undefined values
     * will be removed. Any requests which are received with an invalid JSON body that
     * match this rule will fail.
     */
    updateJsonBody?: {
        [key: string]: any;
    };
    /**
     * Perform a series of string match & replace operations on the request body.
     *
     * This parameter should be an array of pairs, which will be applied to the body
     * decoded as a string like `body.replace(p1, p2)`, applied in the order provided.
     * The first parameter can be either a string or RegExp to match, and the second
     * must be a string to insert. The normal `str.replace` $ placeholders can be
     * used in the second argument, so that e.g. $1 will insert the 1st matched group.
     */
    matchReplaceBody?: Array<[string | RegExp, string]>;
}
export interface ResponseTransform {
    /**
     * A replacement response status code.
     */
    replaceStatus?: number;
    /**
     * A headers object which will be merged with the real response headers to add or
     * replace values. Headers with undefined values will be removed.
     */
    updateHeaders?: Headers;
    /**
     * A headers object which will completely replace the real response headers.
     */
    replaceHeaders?: Headers;
    /**
     * A string or buffer that replaces the response body entirely.
     *
     * If this is specified, the downstream response will not wait for the original response
     * body, so this may make responses arrive faster than they would be otherwise given large
     * response bodies or slow/streaming servers.
     */
    replaceBody?: string | Uint8Array | Buffer;
    /**
     * The path to a file, which will be used to replace the response body entirely. The
     * file will be re-read for each response, so the body will always reflect the latest
     * file contents.
     *
     * If this is specified, the downstream response will not wait for the original response
     * body, so this may make responses arrive faster than they would be otherwise given large
     * response bodies or slow/streaming servers.
     */
    replaceBodyFromFile?: string;
    /**
     * A JSON object which will be merged with the real response body. Undefined values
     * will be removed. Any responses which are received with an invalid JSON body that
     * match this rule will fail.
     */
    updateJsonBody?: {
        [key: string]: any;
    };
    /**
     * Perform a series of string match & replace operations on the response body.
     *
     * This parameter should be an array of pairs, which will be applied to the body
     * decoded as a string like `body.replace(p1, p2)`, applied in the order provided.
     * The first parameter can be either a string or RegExp to match, and the second
     * must be a string to insert. The normal `str.replace` $ placeholders can be
     * used in the second argument, so that e.g. $1 will insert the 1st matched group.
     */
    matchReplaceBody?: Array<[string | RegExp, string]>;
}
/**
 * @internal
 */
export interface SerializedPassThroughData {
    type: 'passthrough';
    forwardToLocation?: string;
    forwarding?: ForwardingOptions;
    proxyConfig?: SerializedProxyConfig;
    ignoreHostCertificateErrors?: string[] | boolean;
    extraCACertificates?: Array<{
        cert: string;
    } | {
        certPath: string;
    }>;
    clientCertificateHostMap?: {
        [host: string]: {
            pfx: string;
            passphrase?: string;
        };
    };
    lookupOptions?: PassThroughLookupOptions;
    simulateConnectionErrors?: boolean;
    transformRequest?: Replace<RequestTransform, {
        'replaceBody'?: string;
        'updateHeaders'?: string;
        'updateJsonBody'?: string;
        'matchReplaceBody'?: Array<[
            string | {
                regexSource: string;
                flags: string;
            },
            string
        ]>;
    }>;
    transformResponse?: Replace<ResponseTransform, {
        'replaceBody'?: string;
        'updateHeaders'?: string;
        'updateJsonBody'?: string;
        'matchReplaceBody'?: Array<[
            string | {
                regexSource: string;
                flags: string;
            },
            string
        ]>;
    }>;
    hasBeforeRequestCallback?: boolean;
    hasBeforeResponseCallback?: boolean;
}
/**
 * @internal
 */
export interface BeforePassthroughRequestRequest {
    args: [Replace<CompletedRequest, {
        body: string;
    }>];
}
/**
 * @internal
 */
export interface BeforePassthroughResponseRequest {
    args: [Replace<PassThroughResponse, {
        body: string;
    }>];
}
/**
 * Used in merging as a marker for values to omit, because lodash ignores undefineds.
 * @internal
 */
export declare const SERIALIZED_OMIT = "__mockttp__transform__omit__";
export declare class PassThroughHandlerDefinition extends Serializable implements RequestHandlerDefinition {
    readonly type = "passthrough";
    readonly forwarding?: ForwardingOptions;
    readonly ignoreHostHttpsErrors: string[] | boolean;
    readonly clientCertificateHostMap: {
        [host: string]: {
            pfx: Buffer;
            passphrase?: string;
        };
    };
    readonly extraCACertificates: Array<{
        cert: string | Buffer;
    } | {
        certPath: string;
    }>;
    readonly transformRequest?: RequestTransform;
    readonly transformResponse?: ResponseTransform;
    readonly beforeRequest?: (req: CompletedRequest) => MaybePromise<CallbackRequestResult | void> | void;
    readonly beforeResponse?: (res: PassThroughResponse) => MaybePromise<CallbackResponseResult | void> | void;
    readonly proxyConfig?: ProxyConfig;
    readonly lookupOptions?: PassThroughLookupOptions;
    readonly simulateConnectionErrors: boolean;
    protected outgoingSockets: Set<net.Socket>;
    constructor(options?: PassThroughHandlerOptions);
    explain(): string;
    /**
     * @internal
     */
    serialize(channel: ClientServerChannel): SerializedPassThroughData;
}
export declare class CloseConnectionHandlerDefinition extends Serializable implements RequestHandlerDefinition {
    readonly type = "close-connection";
    explain(): string;
}
export declare class ResetConnectionHandlerDefinition extends Serializable implements RequestHandlerDefinition {
    readonly type = "reset-connection";
    explain(): string;
}
export declare class TimeoutHandlerDefinition extends Serializable implements RequestHandlerDefinition {
    readonly type = "timeout";
    explain(): string;
}
export declare class JsonRpcResponseHandlerDefinition extends Serializable implements RequestHandlerDefinition {
    readonly result: {
        result: any;
        error?: undefined;
    } | {
        error: any;
        result?: undefined;
    };
    readonly type = "json-rpc-response";
    constructor(result: {
        result: any;
        error?: undefined;
    } | {
        error: any;
        result?: undefined;
    });
    explain(): string;
}
export declare const HandlerDefinitionLookup: {
    simple: typeof SimpleHandlerDefinition;
    callback: typeof CallbackHandlerDefinition;
    stream: typeof StreamHandlerDefinition;
    file: typeof FileHandlerDefinition;
    passthrough: typeof PassThroughHandlerDefinition;
    'close-connection': typeof CloseConnectionHandlerDefinition;
    'reset-connection': typeof ResetConnectionHandlerDefinition;
    timeout: typeof TimeoutHandlerDefinition;
    'json-rpc-response': typeof JsonRpcResponseHandlerDefinition;
};
//# sourceMappingURL=request-handler-definitions.d.ts.map