moll / node-mitm

Intercept and mock outgoing Node.js network TCP connections and HTTP requests for testing. Intercepts and gives you a Net.Socket, Http.IncomingMessage and Http.ServerResponse to test and respond with. Super useful when testing code that hits remote servers.
Other
637 stars 48 forks source link

Error: "req.handle.writev" is not a function, while intercept json POST, node v10 #50

Closed someoneinatree closed 5 years ago

someoneinatree commented 5 years ago

I'm trying to use mitm to intercept a json post made by the request library, but on the latest node, I am getting a http_client error. I can tell mitm is somehow involved because if I comment out the Mitm initialization then that error disappears.

Error:

[...]
     Uncaught TypeError: req.handle.writev is not a function
      at writevGeneric (internal/stream_base_commons.js:59:24)
      at Socket._writeGeneric (net.js:759:5)
      at Socket._writev (net.js:768:8)
      at doWrite (_stream_writable.js:408:12)
      at clearBuffer (_stream_writable.js:517:5)
      at Socket.Writable.uncork (_stream_writable.js:314:7)
      at ClientRequest._flushOutput (_http_outgoing.js:804:10)
      at ClientRequest._flush (_http_outgoing.js:779:16)
      at ClientRequest._deferToConnect (_http_client.js:258:47)
      at callSocketMethod (_http_client.js:701:7)
      at ClientRequest.onSocket (_http_client.js:706:7)
      at tickOnSocket (_http_client.js:645:7)
      at onSocketNT (_http_client.js:684:5)
      at process._tickCallback (internal/process/next_tick.js:63:19)
[...]

Not 100% sure this is mitm issue, seen it referenced in node core (https://github.com/nodejs/node/issues/21665). But after reading the issue conversation, I'm still not clear if this is something to be fixed their end or is a change to internals that we ("mitm") made assumptions about. Something to do with sockets or streams. Reproduction and error codes attached.

minimal test.js file to reproduce:

const Mitm = require('mitm')
const request = require('request')

const handler = (req, res) => new Promise((resolve, reject) => {
  // const opts = { url: 'http://example.com/', json: { test: 'data' }, method: 'POST' } // also fails
  const opts = { url: 'http://example.com/', form: { hey: 'a' }, method: 'POST' }
  request(opts, (err, res2) => {
    if (err) reject(err)
    resolve(res2)
  })
})

let mitm = null

describe('handler', () => {
  before(() => {
    mitm = Mitm() // commenting this line removes "req.handle.writev" error
  })

  after(() => {
    mitm.disable()
  })

  it('sends its own callback, when present in sessionData', () => {
    let requestCount = 0
    mitm.on('request', (req, res) => {
      requestCount += 1
      // req.socket.bypass()
    })
    const fakeRequest = {}
    const fakeResponse = {}
    const handlerReturnValue = handler(fakeRequest, fakeResponse)
    // lines below don't execute, handler fails
    if (!(handlerReturnValue instanceof Promise)) throw 'not a promise'
    return handlerReturnValue.then(() => {
      if (requestCount !== 1) throw Error('need one request')
    })
  })
})

run with: mocha test.js

papandreou commented 5 years ago

There are some other problems with mitm and node 10: https://github.com/assetgraph/assetgraph/pull/873

someoneinatree commented 5 years ago

For now I have used nock because it supported the things I was doing and appears to work on node 10 (or at least without the above issue in my usecase...) but intrigued to the cause of this. I don't know the node core well enough to fix but any pointers to more info would be great.

moll commented 5 years ago

Hey again! Should be fixed, but waiting on more confirmation in https://github.com/moll/node-mitm/issues/48. I'll close this issue in favor of that. ;)