interceptors icon indicating copy to clipboard operation
interceptors copied to clipboard

fix: properly handle Unix socket paths in interceptors

Open vinialbano opened this issue 7 months ago • 7 comments

Fix Unix socket path handling in MSW Interceptors

Problem

The MSW Interceptors library had an issue with TCP requests bound to Unix sockets. When making requests to Unix socket paths (via the socketPath option), the interceptor was incorrectly trying to establish a TCP connection to localhost:80 rather than using the provided socket path. This prevented proper interception and mocking of requests to Unix sockets.

This issue is particularly important for:

  • Applications using Docker API (which often communicates through /var/run/docker.sock)
  • TestContainers and other containerization tools that leverage Unix sockets
  • Database connections that use Unix sockets (e.g., MySQL, PostgreSQL)
  • Custom IPC mechanisms based on Unix sockets

Solution

The solution involves a comprehensive approach to properly handle Unix socket paths throughout the request interceptor chain:

  1. Modified URL creation for Unix sockets:

    • Updated getUrlByRequestOptions.ts to create URLs with a special hostname "unix-socket-placeholder" for Unix socket requests
    • This prevents the library from attempting TCP connections to localhost
  2. Enhanced socket connection handling:

    • Updated MockHttpSocket.ts to directly create socket connections using net.createConnection({ path: socketPath }) when a socket path is specified
    • This bypasses the hostname/port mechanism for Unix socket connections
  3. Improved agent configuration:

    • Modified MockAgent and MockHttpsAgent classes to properly handle and preserve the socketPath property
    • Added support in baseUrlFromConnectionOptions.ts to use the same special hostname for consistency
  4. Code organization improvements:

    • Refactored ClientRequest/index.ts to extract duplicate agent creation code into a helper method
    • Ensured the socketPath property is properly preserved throughout the request handling chain
  5. Comprehensive test coverage:

    • Added regression tests verifying Unix socket connections work correctly
    • Added unit tests for normalizeClientRequestArgs.ts to verify socketPath preservation
    • Added tests for getUrlByRequestOptions.ts to verify special hostname URL creation

Testing

The fix has been thoroughly tested with:

  • Direct Unix socket connections to local test servers
  • GET and POST requests with various headers and body content
  • Error handling for non-existent sockets
  • Integration with the full interception pipeline

All tests are now passing, confirming that Unix socket connections are properly handled.

Related Issues

This fix addresses issues encountered when working with applications that leverage Unix sockets for communication, particularly in containerized environments or when interacting with system services.

  • https://github.com/mswjs/msw/issues/1600
  • https://github.com/nock/nock/issues/2839

vinialbano avatar May 06 '25 17:05 vinialbano

Hi @kettanaito, were you able to take a look at this by any chance? Or @msutkowski, @marcosvega91, @timdeschryver

vinialbano avatar May 20 '25 21:05 vinialbano

I'm wondering what the expected behavior is from this lib POV. Should we intercept them or automatically pass through?

mikicho avatar Jun 07 '25 09:06 mikicho

I'm wondering what the expected behavior is from this lib POV. Should we intercept them or automatically pass through?

That's a great question @mikicho. Could this introduce any vulnerabilities if requests were intercepted? I see no harm in passing them through. I recognize some use cases for intercepting them, but they should probably be rarely explored, and I'm not sure if any security issues might arise.

vinialbano avatar Jun 07 '25 16:06 vinialbano

Sorry, I didn't have the time to look into this. Will do my best to review this this month.

kettanaito avatar Jun 08 '25 16:06 kettanaito

@mikicho, correct me if I'm wrong, but socketPath seems like another way to construct a request. As a result, it performs a regular request that must be intercepted and allowed to be mocked like any other request.

kettanaito avatar Jun 08 '25 16:06 kettanaito

@kettanaito I'm not familiar with this either. From what I understand, it is a Unix way to communicate between processes. From a quick look, it seems like Node translates/overrides it to path, but I may be missing something.

mikicho avatar Jun 08 '25 16:06 mikicho

@kettanaito @vinialbano I think the root cause is that we create a custom agent and then override the path property, which determines the type of the request (pipe/tcp), with null. It should be the socket path in order to create a pipe connection. When I disable it or send agent: false in the options, it works like a charm:

const request = http.get({
  socketPath,
  path: '/test-get',
  agent: false, // Disable the default agent
})

@kettanaito I believe this logic is outdated and no longer applicable to the socket-level interceptor we are currently using. After running a quick check, I noticed that all the tests still passed when I commented out these lines. We may want to remove it.

mikicho avatar Jun 09 '25 22:06 mikicho

@mikicho, I think you are right regarding the default agent. Nice find!

kettanaito avatar Jul 17 '25 13:07 kettanaito

Do we need any additional changes to support Unix socket paths after #731?

kettanaito avatar Jul 17 '25 13:07 kettanaito

Update

I've moved the tests introduced in this pull request to #751, where they are passing without any additional changes. It looks like #731 has indeed fixed this issue.

Interestingly enough, we already had Unix socket tests at test/modules/http/compliance/http-unix-socket.test.ts and they were always passing. I wonder if this issue addresses something that the suggested tests does not cover. cc @vinialbano

kettanaito avatar Oct 19 '25 10:10 kettanaito

Since the tests are passing, I'm consider this issue non-reproducible. If it still happens, please open a pull request with a failing test to confirm that. Thanks!

kettanaito avatar Oct 19 '25 10:10 kettanaito

Released: v0.40.0 🎉

This has been released in v0.40.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.

kettanaito avatar Oct 19 '25 10:10 kettanaito