constructor({ req, options, interceptors }) {
    this.req = req
    this.options = {
      // We may be changing the options object and we don't want those changes
      // affecting the user so we use a clone of the object.
      ...options,
      // We use lower-case header field names throughout Nock.
      headers: common.headersFieldNamesToLowerCase(
        options.headers || {},
        false,
      ),
    }
    this.interceptors = interceptors

    this.socket = new Socket(options)

    // support setting `timeout` using request `options`
    // https://nodejs.org/docs/latest-v12.x/api/http.html#http_http_request_url_options_callback
    // any timeout in the request options override any timeout in the agent options.
    // per https://github.com/nodejs/node/pull/21204
    const timeout =
      options.timeout ||
      (options.agent && options.agent.options && options.agent.options.timeout)

    if (timeout) {
      this.socket.setTimeout(timeout)
    }

    this.response = new IncomingMessage(this.socket)
    this.requestBodyBuffers = []
    this.playbackStarted = false

    // For parity with Node, it's important the socket event is emitted before we begin playback.
    // This flag is set when playback is triggered if we haven't yet gotten the
    // socket event to indicate that playback should start as soon as it comes in.
    this.readyToStartPlaybackOnSocketEvent = false

    this.attachToReq()

    // Emit a fake socket event on the next tick to mimic what would happen on a real request.
    // Some clients listen for a 'socket' event to be emitted before calling end(),
    // which causes Nock to hang.
    process.nextTick(() => this.connectSocket())
  }
Given a group of interceptors, appropriately route an outgoing request.
Identify which interceptor ought to respond, if any, then delegate to
`playbackInterceptor()` to consume the request itself.