code: function performRequest(uri, transactionReq, options, callback) {
    if (typeof options === 'function') { [options, callback] = [{}, options]; }
    const logger = options.logger || defaultLogger;
    const request = options.request || defaultRequest;
  
    const httpOptions = Object.assign({}, options.http || {});
    httpOptions.proxy = false;
    httpOptions.followRedirect = false;
    httpOptions.encoding = null;
    httpOptions.method = transactionReq.method;
    httpOptions.uri = uri;
  
    try {
      httpOptions.body = getBodyAsBuffer(transactionReq.body, transactionReq.bodyEncoding);
      httpOptions.headers = normalizeContentLengthHeader(transactionReq.headers, httpOptions.body);
  
      const protocol = httpOptions.uri.split(':')[0].toUpperCase();
      logger.debug(`Performing ${protocol} request to the server under test: `
        + `${httpOptions.method} ${httpOptions.uri}`);
  
      request(httpOptions, (error, response, responseBody) => {
        logger.debug(`Handling ${protocol} response from the server under test`);
        if (error) {
          callback(error);
        } else {
          callback(null, createTransactionResponse(response, responseBody));
        }
      });
    } catch (error) {
      process.nextTick(() => callback(error));
    }
  }
docs: Performs the HTTP request as described in the 'transaction.request' object
  
  In future we should introduce a 'real' request object as well so user has
  access to the modifications made on the way.
  
  @param {string} uri
  @param {Object} transactionReq
  @param {Object} [options]
  @param {Object} [options.logger] Custom logger
  @param {Object} [options.request] Custom 'request' library implementation
  @param {Object} [options.http] Custom default 'request' library options
  @param {Function} callback