pact-foundation/pact-js

View on GitHub
src/dsl/verifier/proxy/proxy.ts

Summary

Maintainability
A
1 hr
Test Coverage
import express from 'express';
import HttpProxy from 'http-proxy';
import bodyParser from 'body-parser';
import * as http from 'http';

import { ProxyOptions } from './types';
import logger from '../../../common/logger';
import { createProxyStateHandler } from './stateHandler/stateHandler';
import { registerAfterHook, registerBeforeHook } from './hooks';
import { createRequestTracer, createResponseTracer } from './tracer';
import { createProxyMessageHandler } from './messages';
import { toServerOptions } from './proxyRequest';

// Listens for the server start event
export const waitForServerReady = (server: http.Server): Promise<http.Server> =>
  new Promise((resolve, reject) => {
    server.on('listening', () => resolve(server));
    server.on('error', () =>
      reject(new Error('Unable to start verification proxy server'))
    );
  });

// Get the Proxy we'll pass to the CLI for verification
export const createProxy = (
  config: ProxyOptions,
  stateSetupPath: string,
  messageTransportPath: string
): http.Server => {
  const app = express();
  const proxy = new HttpProxy();
  logger.trace(`Setting up state proxy with path: ${stateSetupPath}`);

  // NOTE: if you change any of these global middleware that consumes the body
  //       review the "proxyReq" event reader below
  app.use(
    bodyParser.json({
      type: [
        'application/json',
        'application/json; charset=utf-8',
        'application/json; charset=utf8',
      ],
    })
  );
  app.use(bodyParser.urlencoded({ extended: true }));
  app.use('/*', bodyParser.raw({ type: '*/*' }));
  registerBeforeHook(app, config, stateSetupPath);
  registerAfterHook(app, config, stateSetupPath);

  // Trace req/res logging
  if (config.logLevel === 'debug' || config.logLevel === 'trace') {
    logger.info('debug request/response logging enabled');
    app.use(createRequestTracer());
    app.use(createResponseTracer());
  }

  // Allow for request filtering
  if (config.requestFilter !== undefined) {
    app.use(config.requestFilter);
  }

  // Setup provider state handler
  app.post(stateSetupPath, createProxyStateHandler(config));

  // Register message handler and transport
  // TODO: ensure proxy does not interfere with this
  app.post(messageTransportPath, createProxyMessageHandler(config));

  // Proxy server will respond to Verifier process
  app.all('/*', (req, res) => {
    logger.debug(`Proxying ${req.method}: ${req.path}`);

    proxy.web(req, res, toServerOptions(config, req));
  });

  // TODO: node is now using ipv6 as a default. This should be customised
  return http
    .createServer(app)
    .listen(undefined, config.proxyHost || '127.0.0.1');
};