UNPKG

mockttp-mvs

Version:

Mock HTTP server for testing HTTP clients and stubbing webservices

319 lines (318 loc) 10.4 kB
/// <reference types="node" /> import stream = require('stream'); import http = require('http'); import { EventEmitter } from 'events'; import { InterceptedWebSocket } from './rules/websockets/websocket-handlers'; export declare const DEFAULT_ADMIN_SERVER_PORT = 45454; export declare enum Method { GET = 0, POST = 1, PUT = 2, DELETE = 3, PATCH = 4, HEAD = 5, OPTIONS = 6 } export declare enum RulePriority { FALLBACK = 0, DEFAULT = 1 } export interface Headers { host?: string; 'content-length'?: string; 'content-type'?: string; 'user-agent'?: string; cookie?: string; ':method'?: string; ':scheme'?: string; ':authority'?: string; ':path'?: string; [key: string]: undefined | string | string[]; } export declare type RawHeaders = Array<[key: string, value: string]>; export interface Request { id: string; matchedRuleId?: string; protocol: string; httpVersion?: string; method: string; url: string; path: string; remoteIpAddress?: string; remotePort?: number; hostname?: string; headers: Headers; rawHeaders: RawHeaders; timingEvents: TimingEvents; tags: string[]; } export interface TlsConnectionEvent { hostname?: string; remoteIpAddress: string; remotePort: number; tags: string[]; timingEvents: TlsTimingEvents; tlsMetadata: TlsSocketMetadata; } export interface TlsSocketMetadata { sniHostname?: string; connectHostname?: string; connectPort?: string; clientAlpn?: string[]; ja3Fingerprint?: string; } export interface TlsPassthroughEvent extends TlsConnectionEvent { id: string; upstreamPort: number; } export interface TlsHandshakeFailure extends TlsConnectionEvent { failureCause: 'closed' | 'reset' | 'cert-rejected' | 'no-shared-cipher' | 'handshake-timeout' | 'unknown'; timingEvents: TlsFailureTimingEvents; } export interface TlsTimingEvents { /** * When the socket initially connected, in MS since the unix * epoch. */ startTime: number; /** * When the socket initially connected, equivalent to startTime. * * High-precision floating-point monotonically increasing timestamps. * Comparable and precise, but not related to specific current time. */ connectTimestamp: number; /** * When Mockttp's handshake for this connection was completed (if there * was one). This is not set for passed through connections. */ handshakeTimestamp?: number; /** * When the outer tunnel (e.g. a preceeding CONNECT request) was created, * if there was one. */ tunnelTimestamp?: number; /** * When the connection was closed, if it has been closed. */ disconnectTimestamp?: number; } export interface TlsFailureTimingEvents extends TlsTimingEvents { /** * When the TLS connection failed. This may be due to a failed handshake * (in which case `handshakeTimestamp` will be undefined) or due to a * subsequent error which means the TLS connection was not usable (like * an immediate closure due to an async certificate rejection). */ failureTimestamp: number; } export interface OngoingRequest extends Request, EventEmitter { body: OngoingBody; } export interface OngoingBody { asStream: () => stream.Readable; asBuffer: () => Promise<Buffer>; asDecodedBuffer: () => Promise<Buffer>; asText: () => Promise<string>; asJson: () => Promise<object>; asFormData: () => Promise<{ [key: string]: string | string[] | undefined; }>; } export interface CompletedBody { /** * The raw bytes of the response. If a content encoding was used, this is * the raw encoded data. */ buffer: Buffer; /** * The decoded bytes of the response. If no encoding was used, this is the * same as `.buffer`. The response is decoded and returned asynchronously * as a Promise. */ getDecodedBuffer(): Promise<Buffer | undefined>; /** * The contents of the response, decoded and parsed as a UTF-8 string. * The response is decoded and returned asynchronously as a Promise. */ getText(): Promise<string | undefined>; /** * The contents of the response, decoded, parsed as UTF-8 string, and * then parsed a JSON. The response is decoded and returned asynchronously * as a Promise. */ getJson(): Promise<object | undefined>; /** * The contents of the response, decoded, parsed as UTF-8 string, and * then parsed form-encoded data. The response is decoded and returned * asynchronously as a Promise. */ getFormData(): Promise<{ [key: string]: string | string[] | undefined; } | undefined>; } export declare type InitiatedRequest = Request; export interface AbortedRequest extends InitiatedRequest { error?: { name?: string; code?: string; message?: string; stack?: string; }; } export interface CompletedRequest extends Request { body: CompletedBody; } export interface TimingEvents { startTime: number; startTimestamp: number; bodyReceivedTimestamp?: number; headersSentTimestamp?: number; responseSentTimestamp?: number; wsAcceptedTimestamp?: number; wsClosedTimestamp?: number; abortedTimestamp?: number; } export interface OngoingResponse extends http.ServerResponse { id: string; getHeaders(): Headers; getRawHeaders(): RawHeaders; body: OngoingBody; timingEvents: TimingEvents; tags: string[]; } export interface CompletedResponse { id: string; statusCode: number; statusMessage: string; headers: Headers; rawHeaders: RawHeaders; body: CompletedBody; timingEvents: TimingEvents; tags: string[]; } export interface WebSocketMessage { /** * The id of this websocket stream. This will match the id of the request, * the initial connection response, and any other WebSocket events for the * same connection stream. */ streamId: string; /** * Whether the message was sent by Mockttp, or received from a Mockttp client. */ direction: 'sent' | 'received'; /** * The contents of the message as a raw buffer. This is already decompressed, * if the WebSocket uses compression. */ content: { data: Uint8Array; }; /** * Whether this is a string message or a raw binary data message. */ isBinary: boolean; /** * A high-precision floating-point monotonically increasing timestamp. * Comparable and precise, but not related to specific current time. * * To link this to the current time, compare it to `timingEvents.startTime`. */ eventTimestamp: number; timingEvents: TimingEvents; tags: string[]; ws: InterceptedWebSocket; } export interface WebSocketClose { /** * The id of this websocket stream. This will match the id of the request, * the initial connection response, and any other WebSocket events for the * same connection stream. */ streamId: string; /** * The close code of the shutdown. This is the close code that was received * from the remote client (either initiated remotely, or echoing our own sent * close frame). * * This may be undefined only if a close frame was received but did not contain * any close code. If no close frame was received before the connection was * lost (i.e. the connection was not cleanly closed) this event will not * fire at all, and an 'abort' event will fire instead. */ closeCode: number | undefined; /** * The close reason of the shutdown. */ closeReason: string; timingEvents: TimingEvents; tags: string[]; } /** * A client error event describes a request (or our best guess at parsing it), * that wasn't correctly completed, and the error response it received, or * 'aborted' if the connection was disconnected before we could respond. */ export interface ClientError { errorCode?: string; request: { id: string; timingEvents: TimingEvents; tags: string[]; protocol?: string; httpVersion?: string; method?: string; url?: string; path?: string; headers: Headers; rawHeaders: RawHeaders; remoteIpAddress?: string; remotePort?: number; }; response: CompletedResponse | 'aborted'; } /** * A mocked endpoint provides methods to see the current state of * a mock rule. */ export interface MockedEndpoint { id: string; /** * Get the requests that this endpoint has seen so far. * * This method returns a promise, which resolves with the requests seen * up until now, once all ongoing requests have terminated. The returned * lists are immutable, so won't change if more requests arrive in future. * Call `getSeenRequests` again later to get an updated list. * * Requests are included here once the response is completed, even if the request * itself failed, the responses failed or exceptions are thrown elsewhere. To * watch for errors or detailed response info, look at the various server.on(event) * methods. */ getSeenRequests(): Promise<CompletedRequest[]>; /** * Reports whether this endpoint is still pending: if it either hasn't seen the * specified number of requests (if one was specified e.g. with .twice()) * or if it hasn't seen at least one request, by default. * * This method returns a promise, which resolves with the result once all * ongoing requests have terminated. */ isPending(): Promise<boolean>; } export interface MockedEndpointData { id: string; explanation?: string; seenRequests: CompletedRequest[]; isPending: boolean; } export interface Explainable { explain(): string; } export interface ProxyEnvConfig { HTTP_PROXY: string; HTTPS_PROXY: string; } export declare type defaultMaxListeners = typeof EventEmitter.defaultMaxListeners;