mswjs / interceptors

Low-level network interception library.
https://npm.im/@mswjs/interceptors
MIT License
537 stars 123 forks source link

Support IPv6 #451

Closed mikicho closed 4 months ago

mikicho commented 11 months ago

Maybe I'm missing something but:

const { ClientRequestInterceptor } = require('@mswjs/interceptors/ClientRequest')
const http = require('http')

const interceptor = new ClientRequestInterceptor({
  name: 'my-interceptor',
})
interceptor.apply();
interceptor.on('request', ({request}) => {
  request.respondWith(new Response('hey'))
});

http.get('http://[2607:f0d0:1002:51::4]:8080/', res => {
  res.on('data', () => {})
  res.on('end', () => {
    console.log(1) 
  })
})

Prints:

RequestError: connect ENETUNREACH 2607:f0d0:1002:51::4:8080 - Local (:::0)

Logs:

02:24:25:826 [http] constructing the interceptor...
02:24:25:843 [http:apply] applying the interceptor...
02:24:25:843 [http] retrieved global instance: undefined
02:24:25:843 [http:apply] no running instance found, setting up a new instance...
02:24:25:844 [http:setup] native "http" module patched!
02:24:25:844 [http:setup] native "https" module patched!
02:24:25:844 [http] set global instance! http
02:24:25:844 [http:on] adding "request" event listener:
02:24:25:845 [http normalizeClientRequestArgs] arguments ["http://[2607:f0d0:1002:51::4]:8080/",null]
02:24:25:845 [http normalizeClientRequestArgs] using default protocol: http:
02:24:25:845 [http normalizeClientRequestArgs] first argument is a location string: http://[2607:f0d0:1002:51::4]:8080/
02:24:25:845 [http normalizeClientRequestArgs] created a url: "http://[2607:f0d0:1002:51::4]:8080/"
02:24:25:846 [http normalizeClientRequestArgs] request options from url: {"method":"GET","protocol":"http:","hostname":"2607:f0d0:1002:51::4","host":"[2607:f0d0:1002:51::4]:8080","path":"/","port":8080}
02:24:25:846 [http normalizeClientRequestArgs] request options not provided, deriving from the url "http://[2607:f0d0:1002:51::4]:8080/"
02:24:25:846 [http normalizeClientRequestArgs] resolved request options: {"method":"GET","protocol":"http:","hostname":"2607:f0d0:1002:51::4","host":"[2607:f0d0:1002:51::4]:8080","path":"/","port":8080}
02:24:25:847 [http normalizeClientRequestArgs] resolved fallback agent: {"_events":{},"_eventsCount":2,"defaultPort":80,"protocol":"http:","options":{"noDelay":true,"path":null},"requests":{},"sockets":{},"freeSockets":{},"keepAliveMsecs":1000,"keepAlive":false,"maxSockets":null,"maxFreeSockets":256,"scheduling":"lifo","maxTotalSockets":null,"totalSocketCount":0}
02:24:25:847 [http normalizeClientRequestArgs] has no default agent, setting the default agent for "http:"
02:24:25:847 [http normalizeClientRequestArgs] successfully resolved url: http://[2607:f0d0:1002:51::4]:8080/
02:24:25:847 [http normalizeClientRequestArgs] successfully resolved options: {"method":"GET","protocol":"http:","hostname":"2607:f0d0:1002:51::4","host":"[2607:f0d0:1002:51::4]:8080","path":"/","port":8080,"agent":{"_events":{},"_eventsCount":2,"defaultPort":80,"protocol":"http:","options":{"noDelay":true,"path":null},"requests":{},"sockets":{},"freeSockets":{},"keepAliveMsecs":1000,"keepAlive":false,"maxSockets":null,"maxFreeSockets":256,"scheduling":"lifo","maxTotalSockets":null,"totalSocketCount":0},"_defaultAgent":{"_events":{},"_eventsCount":2,"defaultPort":80,"protocol":"http:","options":{"keepAlive":true,"scheduling":"lifo","timeout":5000,"noDelay":true,"path":null},"requests":{},"sockets":{},"freeSockets":{},"keepAliveMsecs":1000,"keepAlive":true,"maxSockets":null,"maxFreeSockets":256,"scheduling":"lifo","maxTotalSockets":null,"totalSocketCount":0}}
02:24:25:847 [http normalizeClientRequestArgs] successfully resolved callback: res => {
  res.on('data', () => {})
  res.on('end', () => {
    console.log(1)
  })
}
02:24:25:851 [http:request GET http://[2607:f0d0:1002:51::4]:8080/] constructing ClientRequest using options: {"url":"http://[2607:f0d0:1002:51::4]:8080/","requestOptions":{"method":"GET","protocol":"http:","hostname":"2607:f0d0:1002:51::4","host":"[2607:f0d0:1002:51::4]:8080","path":"/","port":8080,"agent":{"_events":{},"_eventsCount":2,"defaultPort":80,"protocol":"http:","options":{"noDelay":true,"path":null},"requests":{},"sockets":{"2607:f0d0:1002:51::4:8080:":[{"connecting":true,"_hadError":false,"_parent":null,"_host":null,"_closeAfterHandlingError":false,"_readableState":{"objectMode":false,"highWaterMark":16384,"buffer":{"head":null,"tail":null,"length":0},"length":0,"pipes":[],"flowing":null,"ended":false,"endEmitted":false,"reading":false,"constructed":true,"sync":true,"needReadable":false,"emittedReadable":false,"readableListening":false,"resumeScheduled":false,"errorEmitted":false,"emitClose":false,"autoDestroy":true,"destroyed":false,"errored":null,"closed":false,"closeEmitted":false,"defaultEncoding":"utf8","awaitDrainWriters":null,"multiAwaitDrain":false,"readingMore":false,"dataEmitted":false,"decoder":null,"encoding":null},"_events":{},"_eventsCount":6,"_writableState":{"objectMode":false,"highWaterMark":16384,"finalCalled":false,"needDrain":false,"ending":false,"ended":false,"finished":false,"destroyed":false,"decodeStrings":false,"defaultEncoding":"utf8","length":0,"writing":false,"corked":0,"sync":true,"bufferProcessing":false,"writecb":null,"writelen":0,"afterWriteTickInfo":null,"buffered":[],"bufferedIndex":0,"allBuffers":true,"allNoop":true,"pendingcb":0,"constructed":true,"prefinished":false,"errorEmitted":false,"emitClose":false,"autoDestroy":true,"errored":null,"closed":false,"closeEmitted":false},"allowHalfOpen":false,"_sockname":null,"_pendingData":null,"_pendingEncoding":"","server":null,"_server":null}]},"freeSockets":{},"keepAliveMsecs":1000,"keepAlive":false,"maxSockets":null,"maxFreeSockets":256,"scheduling":"lifo","maxTotalSockets":null,"totalSocketCount":1},"_defaultAgent":{"_events":{},"_eventsCount":2,"defaultPort":80,"protocol":"http:","options":{"keepAlive":true,"scheduling":"lifo","timeout":5000,"noDelay":true,"path":null},"requests":{},"sockets":{},"freeSockets":{},"keepAliveMsecs":1000,"keepAlive":true,"maxSockets":null,"maxFreeSockets":256,"scheduling":"lifo","maxTotalSockets":null,"totalSocketCount":0}}}
02:24:25:852 [http:request GET http://[2607:f0d0:1002:51::4]:8080/] end []
02:24:25:852 [utils getUrlByRequestOptions] arguments []
02:24:25:853 [utils getUrlByRequestOptions] normalized args [null,null,null]
02:24:25:853 [http:request GET http://[2607:f0d0:1002:51::4]:8080/] normalized arguments: {"chunk":null,"encoding":null,"callback":null}
02:24:25:867 [http:request GET http://[2607:f0d0:1002:51::4]:8080/] emitting the "request" event for 2 listener(s)...
02:24:25:871 [http:request GET http://[2607:f0d0:1002:51::4]:8080/] emit: socket
02:24:25:871 [http:request GET http://[2607:f0d0:1002:51::4]:8080/] emit: error
02:24:25:871 [http:request GET http://[2607:f0d0:1002:51::4]:8080/] error:
 {"errno":-101,"code":"ENETUNREACH","syscall":"connect","address":"2607:f0d0:1002:51::4","port":8080}
node:events:492
      throw er; // Unhandled 'error' event
      ^

Error: connect ENETUNREACH 2607:f0d0:1002:51::4:8080 - Local (:::0)
    at internalConnect (node:net:1090:16)
    at defaultTriggerAsyncIdScope (node:internal/async_hooks:464:18)
    at node:net:1315:9
    at process.processTicksAndRejections (node:internal/process/task_queues:77:11)
Emitted 'error' event on _NodeClientRequest instance at:
    at _NodeClientRequest.emit (/.../nock/node_modules/@mswjs/interceptors/lib/node/chunk-44QGFZIT.js:353:18)
    at Socket.socketErrorListener (node:_http_client:495:9)
    at Socket.emit (node:events:514:28)
    at emitErrorNT (node:internal/streams/destroy:151:8)
    at emitErrorCloseNT (node:internal/streams/destroy:116:3)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  errno: -101,
  code: 'ENETUNREACH',
  syscall: 'connect',
  address: '2607:f0d0:1002:51::4',
  port: 8080
}

Node.js v20.6.1
kettanaito commented 11 months ago

Can you please give it a quick try by adding the error code (ENETUNREACH) to the list of suppressed error codes here:

https://github.com/mswjs/interceptors/blob/2e98a714bc4364fb201313c1bcd326b3b2767a61/src/interceptors/ClientRequest/NodeClientRequest.ts#L35

I think that may solve the issue. We keep an internal list of socket errors to ignore to know that those are expecting, such as when trying to connect to an address that doesn't exist.

mikicho commented 11 months ago

Yes. It does solve it. Thanks! I focus on fixing nocks tests, so I'll open a PR later.

kettanaito commented 11 months ago

Released: v0.25.7 🎉

This has been released in v0.25.7!

Make sure to always update to the latest version (npm i @mswjs/interceptors@latest) to get the newest features and bug fixes.


Predictable release automation by @ossjs/release.

mikicho commented 10 months ago

@kettanaito Eventually we didn't fix this in https://github.com/mswjs/interceptors/pull/454. Can you please reopen this?

kettanaito commented 10 months ago

@mikicho, thanks for letting me know. Apologies, I've been busy with the MSW 2.0 release and everything around so I fell off our effort here. It is still something I want to achieve so please ping me anywhere I can help.

kettanaito commented 4 months ago

Released: v0.29.0 🎉

This has been released in v0.29.0!

Make sure to always update to the latest version (npm i @mswjs/interceptors@latest) to get the newest features and bug fixes.


Predictable release automation by @ossjs/release.