Skip to content

fix(node/net): return string family in server.address()#31465

Merged
Tango992 merged 2 commits intodenoland:mainfrom
nrako:fix/node-net-server-address-family
Dec 6, 2025
Merged

fix(node/net): return string family in server.address()#31465
Tango992 merged 2 commits intodenoland:mainfrom
nrako:fix/node-net-server-address-family

Conversation

@nrako
Copy link
Copy Markdown
Contributor

@nrako nrako commented Nov 30, 2025

Summary

Aligns Deno's Node.js compatibility layer (node:net, node:http, node:https,
node:http2, node:dns) with Node.js v18.4.0+ behavior by returning the family
property as a string ("IPv4" or "IPv6") rather than a number in server.address()
and socket address methods.

Node.js briefly changed family from string to number in v18.0.0 (nodejs/node#41431),
but reverted in v18.4.0 (nodejs/node#43054) due to ecosystem breakage
(nodejs/node#43014).

This fix ensures compatibility with npm packages that rely on the string format, which
has been the stable API since Node.js v18.4.0.

Changes

  • Modified ext/node/polyfills/http.ts to add family property to address() return
  • Modified ext/node/polyfills/internal_binding/tcp_wrap.ts to return string family
    instead of number in getsockname(), getpeername(), and #connect()
  • Modified ext/node/polyfills/net.ts to fix socket.remoteFamily getter (no longer
    needs conversion since family is now a string)
  • Modified ext/node/polyfills/dns.ts and
    ext/node/polyfills/internal/dns/promises.ts to accept string family values ("IPv4",
    "IPv6") in lookup(), matching Node.js behavior
  • Added tests in tests/unit_node/http_test.ts, tests/unit_node/http2_test.ts,
    tests/unit_node/https_test.ts, tests/unit_node/dns_test.ts, and
    tests/unit_node/net_test.ts

Node.js Compatibility Note

For non-IP addresses (when isIP() returns 0), the family property is undefined.
This matches Node.js C++ behavior in AddressToJS where family
is only set for AF_INET ("IPv4") and AF_INET6 ("IPv6"), and left undefined
otherwise.

Refs

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Nov 30, 2025

Walkthrough

Adds export getIPFamily(ip) and uses it to represent IP family as string literals ("IPv4"/"IPv6") in TCP internals and AddressInfo.family in ext/node/polyfills/internal_binding/tcp_wrap.ts. ServerImpl.address() now returns { port, address, family } in ext/node/polyfills/http.ts. Socket.remoteFamily getter in ext/node/polyfills/net.ts was changed to return the raw numeric family. DNS lookup handling in ext/node/polyfills/dns.ts and ext/node/polyfills/internal/dns/promises.ts accepts string family values and maps them to numeric 4/6. New tests for http, http2, https, dns, and net validate family behavior.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: returning string family in server.address() for Node.js compatibility.
Description check ✅ Passed The description thoroughly explains the changeset, including context (Node.js version history), affected modules, and the rationale for the changes.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6911007 and 7a54710.

📒 Files selected for processing (2)
  • ext/node/polyfills/http.ts (2 hunks)
  • ext/node/polyfills/internal/net.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • ext/node/polyfills/internal/net.ts
  • ext/node/polyfills/http.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: test debug linux-aarch64
  • GitHub Check: test debug linux-x86_64
  • GitHub Check: test release linux-x86_64
  • GitHub Check: test debug windows-x86_64
  • GitHub Check: test debug macos-aarch64
  • GitHub Check: test debug macos-x86_64
  • GitHub Check: test release macos-aarch64
  • GitHub Check: lint debug windows-x86_64
  • GitHub Check: build libs
  • GitHub Check: lint debug linux-x86_64
  • GitHub Check: lint debug macos-x86_64

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@nrako nrako marked this pull request as ready for review November 30, 2025 18:16
@nrako nrako force-pushed the fix/node-net-server-address-family branch 3 times, most recently from 6ba8a42 to b7c45b3 Compare November 30, 2025 19:36
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
ext/node/polyfills/http.ts (1)

2236-2241: Verify edge case: isIP could return 0.

If isIP(addr) returns 0 (not a valid IP), line 2241 defaults to "IPv4", which would be incorrect. While unlikely given that #addr.hostname is set to validated IPs in listen(), consider defensive handling:

const ipVersion = isIP(addr);
if (ipVersion === 0) {
  // Handle invalid IP - throw error or log warning
}
return {
  port: this.#addr.port,
  address: addr,
  family: ipVersion === 6 ? "IPv6" : "IPv4",
};
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6ba8a42 and b7c45b3.

📒 Files selected for processing (8)
  • ext/node/polyfills/dns.ts (1 hunks)
  • ext/node/polyfills/http.ts (2 hunks)
  • ext/node/polyfills/internal/dns/promises.ts (1 hunks)
  • ext/node/polyfills/internal_binding/tcp_wrap.ts (5 hunks)
  • ext/node/polyfills/net.ts (1 hunks)
  • tests/unit_node/http2_test.ts (1 hunks)
  • tests/unit_node/http_test.ts (1 hunks)
  • tests/unit_node/https_test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/unit_node/http_test.ts
  • ext/node/polyfills/internal_binding/tcp_wrap.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js}: For JavaScript runtime debugging, enable V8 inspector with --inspect-brk flag and connect Chrome DevTools to chrome://inspect
Use console.log() for debug prints in JavaScript runtime code

Files:

  • ext/node/polyfills/internal/dns/promises.ts
  • ext/node/polyfills/net.ts
  • ext/node/polyfills/dns.ts
  • tests/unit_node/https_test.ts
  • tests/unit_node/http2_test.ts
  • ext/node/polyfills/http.ts
🧬 Code graph analysis (3)
ext/node/polyfills/internal/dns/promises.ts (1)
ext/node/polyfills/internal/validators.mjs (1)
  • validateOneOf (219-232)
ext/node/polyfills/dns.ts (1)
ext/node/polyfills/internal/validators.mjs (1)
  • validateOneOf (219-232)
ext/node/polyfills/http.ts (2)
ext/http/lib.rs (1)
  • addr (1734-1734)
ext/node/polyfills/net.ts (1)
  • isIP (2756-2756)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: test release macos-aarch64
  • GitHub Check: test debug windows-x86_64
  • GitHub Check: test debug linux-aarch64
  • GitHub Check: test debug linux-x86_64
  • GitHub Check: test debug macos-aarch64
  • GitHub Check: test release linux-x86_64
  • GitHub Check: test debug macos-x86_64
  • GitHub Check: lint debug linux-x86_64
  • GitHub Check: lint debug windows-x86_64
  • GitHub Check: build libs
  • GitHub Check: lint debug macos-x86_64
🔇 Additional comments (6)
ext/node/polyfills/dns.ts (1)

237-249: LGTM - String family handling implemented correctly.

The switch statement properly maps string family values to their numeric equivalents while maintaining backward compatibility with numeric inputs. The fallback to validateOneOf ensures invalid values are caught.

tests/unit_node/http2_test.ts (1)

466-502: LGTM - Comprehensive test coverage for both IPv4 and IPv6.

The test properly verifies that server.address() includes the family property as a string for both IP versions, aligning with Node.js v18.4.0+ behavior.

tests/unit_node/https_test.ts (1)

7-52: LGTM - HTTPS family property test mirrors HTTP/2 pattern.

Consistent test implementation for HTTPS servers with proper TLS setup and verification of the string family property for both IPv4 and IPv6.

ext/node/polyfills/internal/dns/promises.ts (1)

197-209: LGTM - Consistent with dns.ts implementation.

String family handling is correctly implemented, maintaining consistency between the callback and promise-based DNS APIs.

ext/node/polyfills/http.ts (1)

71-71: LGTM - isIP import added for family determination.

ext/node/polyfills/net.ts (1)

1534-1534: Verify that _getpeername().family returns a string.

The test at tests/unit_node/http2_test.ts:383 expects remoteFamily to be the string "IPv4", but the AI summary for this change indicates the type shifts to number | undefined. Confirm the actual return type of _getpeername().family from the tcp_wrap.ts implementation—if it returns numeric values, the test will fail; if it returns strings, this comment is incorrect.

@nrako nrako force-pushed the fix/node-net-server-address-family branch from b7c45b3 to fd3260a Compare November 30, 2025 20:15
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
tests/unit_node/dns_test.ts (1)

4-7: Good coverage for string family -> numeric result mapping

The added alias for lookupPromise and the new test asserting lookup("localhost", { family: "IPv4" }) yields family === 4 align with the new DNS option behavior. This is a sensible, focused regression test; extending with an "IPv6" case would be nice-to-have but not required.

Also applies to: 93-96

ext/node/polyfills/http.ts (1)

71-71: ServerImpl.address() now exposes family and matches expected IP literals

Importing isIP and using it in address() to derive "IPv4" vs "IPv6" from this.#addr.hostname makes the HTTP/HTTPS server addresses consistent with net.Server.address() and the new tests. Given listen() normalizes host to concrete IP literals, this should reliably return the correct family string.

Also applies to: 2235-2242

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b7c45b3 and fd3260a.

📒 Files selected for processing (10)
  • ext/node/polyfills/dns.ts (1 hunks)
  • ext/node/polyfills/http.ts (2 hunks)
  • ext/node/polyfills/internal/dns/promises.ts (1 hunks)
  • ext/node/polyfills/internal_binding/tcp_wrap.ts (5 hunks)
  • ext/node/polyfills/net.ts (1 hunks)
  • tests/unit_node/dns_test.ts (2 hunks)
  • tests/unit_node/http2_test.ts (1 hunks)
  • tests/unit_node/http_test.ts (1 hunks)
  • tests/unit_node/https_test.ts (1 hunks)
  • tests/unit_node/net_test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • ext/node/polyfills/dns.ts
  • tests/unit_node/http2_test.ts
  • ext/node/polyfills/internal/dns/promises.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js}: For JavaScript runtime debugging, enable V8 inspector with --inspect-brk flag and connect Chrome DevTools to chrome://inspect
Use console.log() for debug prints in JavaScript runtime code

Files:

  • tests/unit_node/net_test.ts
  • ext/node/polyfills/http.ts
  • tests/unit_node/https_test.ts
  • ext/node/polyfills/net.ts
  • tests/unit_node/dns_test.ts
  • ext/node/polyfills/internal_binding/tcp_wrap.ts
  • tests/unit_node/http_test.ts
🧬 Code graph analysis (1)
ext/node/polyfills/http.ts (1)
ext/node/polyfills/net.ts (1)
  • isIP (2756-2756)
🔇 Additional comments (5)
ext/node/polyfills/net.ts (1)

1532-1535: remoteFamily now correctly surfaces string family from underlying handle

remoteFamily simply returning this._getpeername().family lets it pick up the "IPv4"/"IPv6" string set in the TCP handle, matching the rest of this PR’s family handling. No issues spotted here.

tests/unit_node/net_test.ts (1)

307-319: remoteFamily regression test is appropriate and minimal

This test asserts socket.remoteFamily is "IPv4" for a simple loopback connection, matching the updated implementation. The lifecycle (end socket, close server, await deferred) is clean and should be stable.

tests/unit_node/https_test.ts (1)

4-52: HTTPS Server.address() test correctly validates family for IPv4/IPv6

The new test for HTTPS servers verifies server.address() returns an AddressInfo with the expected address, "IPv4"/"IPv6" family, and numeric port for both 127.0.0.1 and ::1. The setup/teardown per block is straightforward and mirrors the HTTP tests.

tests/unit_node/http_test.ts (1)

2228-2262: HTTP Server.address() family test aligns with new behavior

This test sensibly checks that server.address() returns an object with address, "IPv4"/"IPv6" family, and numeric port for explicit IPv4 and IPv6 listens. It matches the updated polyfill’s contract and should catch regressions.

ext/node/polyfills/internal_binding/tcp_wrap.ts (1)

60-62: TCP address/peer family now consistently uses "IPv4"/"IPv6" strings

Switching AddressInfo.family and the internal #remoteFamily to strings and populating them via isIP() in the constructor, getsockname(), and #connect() makes the low-level TCP handle align with the higher-level expectations of net.Server.address() and net.Socket.remoteFamily. Resetting #remoteFamily in _onClose() keeps the cached state coherent. This looks correct and consistent with the rest of the PR.

Also applies to: 98-98, 146-148, 283-285, 380-382, 489-491

@nrako nrako force-pushed the fix/node-net-server-address-family branch from fd3260a to 7fe7995 Compare November 30, 2025 20:51
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
ext/node/polyfills/http.ts (1)

234-244: Consider extracting the IP version to family string mapping.

The logic ipVersion === 6 ? "IPv6" : ipVersion === 4 ? "IPv4" : undefined is duplicated in tcp_wrap.ts (lines 147-151, 288-292, 389-393). Consider extracting this to a helper function in internal/net.ts.

// In ext/node/polyfills/internal/net.ts
export function getIPFamily(address: string): string | undefined {
  const ipVersion = isIP(address);
  return ipVersion === 6 ? "IPv6" : ipVersion === 4 ? "IPv4" : undefined;
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b7c45b3 and 7fe7995.

📒 Files selected for processing (10)
  • ext/node/polyfills/dns.ts (1 hunks)
  • ext/node/polyfills/http.ts (2 hunks)
  • ext/node/polyfills/internal/dns/promises.ts (1 hunks)
  • ext/node/polyfills/internal_binding/tcp_wrap.ts (5 hunks)
  • ext/node/polyfills/net.ts (1 hunks)
  • tests/unit_node/dns_test.ts (2 hunks)
  • tests/unit_node/http2_test.ts (1 hunks)
  • tests/unit_node/http_test.ts (1 hunks)
  • tests/unit_node/https_test.ts (1 hunks)
  • tests/unit_node/net_test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • ext/node/polyfills/dns.ts
  • tests/unit_node/http2_test.ts
  • ext/node/polyfills/net.ts
  • tests/unit_node/http_test.ts
  • ext/node/polyfills/internal/dns/promises.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js}: For JavaScript runtime debugging, enable V8 inspector with --inspect-brk flag and connect Chrome DevTools to chrome://inspect
Use console.log() for debug prints in JavaScript runtime code

Files:

  • tests/unit_node/https_test.ts
  • tests/unit_node/net_test.ts
  • ext/node/polyfills/http.ts
  • ext/node/polyfills/internal_binding/tcp_wrap.ts
  • tests/unit_node/dns_test.ts
🧬 Code graph analysis (3)
tests/unit_node/net_test.ts (1)
ext/net/01_net.js (4)
  • port (593-593)
  • port (643-643)
  • port (660-660)
  • port (697-697)
ext/node/polyfills/http.ts (2)
ext/http/lib.rs (1)
  • addr (1734-1734)
ext/node/polyfills/net.ts (1)
  • isIP (2756-2756)
ext/node/polyfills/internal_binding/tcp_wrap.ts (1)
ext/node/polyfills/http.ts (1)
  • address (2234-2245)

@bartlomieju bartlomieju requested a review from Tango992 December 1, 2025 23:04
Copy link
Copy Markdown
Contributor

@Tango992 Tango992 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Just a minor review

Comment thread ext/node/polyfills/internal_binding/tcp_wrap.ts Outdated
Aligns Deno's Node.js compatibility layer with Node.js v18.4.0+ behavior
by returning the `family` property as a string ("IPv4" or "IPv6") rather
than a number in `server.address()` and socket address methods.

Node.js briefly changed `family` from string to number in v18.0.0
(nodejs/node#41431), but reverted in v18.4.0 (nodejs/node#43054) due to
ecosystem breakage (nodejs/node#43014).

Changes:
- `http.Server.address()`, `https.Server.address()`, `http2.Server.address()`
  now include `family` property as string
- `net.Server.address()` returns string `family` via tcp_wrap.ts
- `socket.remoteFamily` returns string instead of number
- `dns.lookup()` accepts both numeric (0, 4, 6) and string ("IPv4", "IPv6")
  family values, matching Node.js behavior

Family value derivation follows Node.js C++ implementation:
- isIP() === 4 → "IPv4"
- isIP() === 6 → "IPv6"
- isIP() === 0 → undefined (defensive, matches Node.js behavior for
  non-IP addresses, though not practically reachable via TCP server APIs)

Refs:
- nodejs/node#43054
- nodejs/node@70b516e

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@nrako nrako force-pushed the fix/node-net-server-address-family branch from 7fe7995 to 6911007 Compare December 4, 2025 20:51
@nrako nrako requested a review from Tango992 December 4, 2025 23:26
Copy link
Copy Markdown
Contributor

@Tango992 Tango992 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@nrako
Copy link
Copy Markdown
Contributor Author

nrako commented Dec 5, 2025

Thanks for the review. Let me know if I should fix up the last commit, or anything else. I look forward to seeing this fix released— I've encountered this issue while trying to use the latest version of Playwright in a Deno web project.

@Tango992 Tango992 merged commit bc9d356 into denoland:main Dec 6, 2025
20 checks passed
@Tango992
Copy link
Copy Markdown
Contributor

Tango992 commented Dec 6, 2025

Thanks, no action is needed from your side. In the meantime can do deno upgrade --canary if you'd like to try the fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants