| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 565b04a commit 9fba5e1
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -244,6 +244,17 @@ added: | |||
| 244 | 244 | ||
| 245 | 245 | * Type {number} | |
| 246 | 246 | ||
| 247 | + ### `SocketAddress.parse(input)` | ||
| 248 | + | ||
| 249 | + <!-- YAML | ||
| 250 | + added: REPLACEME | ||
| 251 | + --> | ||
| 252 | + | ||
| 253 | + * `input` {string} An input string containing an IP address and optional port, | ||
| 254 | + e.g. `123.1.2.3:1234` or `[1::1]:1234`. | ||
| 255 | + * Returns: {net.SocketAddress} Returns a `SocketAddress` if parsing was successful. | ||
| 256 | + Otherwise returns `undefined`. | ||
| 257 | + | ||
| 247 | 258 | ## Class: `net.Server` | |
| 248 | 259 | ||
| 249 | 260 | <!-- YAML | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -37,6 +37,8 @@ const { | |||
| 37 | 37 | kDeserialize, | |
| 38 | 38 | } = require('internal/worker/js_transferable'); | |
| 39 | 39 | ||
| 40 | + const { URL } = require('internal/url'); | ||
| 41 | + | ||
| 40 | 42 | const kHandle = Symbol('kHandle'); | |
| 41 | 43 | const kDetail = Symbol('kDetail'); | |
| 42 | 44 | ||
@@ -74,7 +76,7 @@ class SocketAddress { | |||
| 74 | 76 | validatePort(port, 'options.port'); | |
| 75 | 77 | validateUint32(flowlabel, 'options.flowlabel', false); | |
| 76 | 78 | ||
| 77 | - this[kHandle] = new _SocketAddress(address, port, type, flowlabel); | ||
| 79 | + this[kHandle] = new _SocketAddress(address, port | 0, type, flowlabel | 0); | ||
| 78 | 80 | this[kDetail] = this[kHandle].detail({ | |
| 79 | 81 | address: undefined, | |
| 80 | 82 | port: undefined, | |
@@ -138,6 +140,36 @@ class SocketAddress { | |||
| 138 | 140 | flowlabel: this.flowlabel, | |
| 139 | 141 | }; | |
| 140 | 142 | } | |
| 143 | + | ||
| 144 | + /** | ||
| 145 | + * Parse an "${ip}:${port}" formatted string into a SocketAddress. | ||
| 146 | + * Returns undefined if the input cannot be successfully parsed. | ||
| 147 | + * @param {string} input | ||
| 148 | + * @returns {SocketAddress|undefined} | ||
| 149 | + */ | ||
| 150 | + static parse(input) { | ||
| 151 | + validateString(input, 'input'); | ||
| 152 | + // While URL.parse is not expected to throw, there are several | ||
| 153 | + // other pieces here that do... the destucturing, the SocketAddress | ||
| 154 | + // constructor, etc. So we wrap this in a try/catch to be safe. | ||
| 155 | + try { | ||
| 156 | + const { | ||
| 157 | + hostname: address, | ||
| 158 | + port, | ||
| 159 | + } = URL.parse(`http://${input}`); | ||
| 160 | + if (address.startsWith('[') && address.endsWith(']')) { | ||
| 161 | + return new SocketAddress({ | ||
| 162 | + address: address.slice(1, -1), | ||
| 163 | + port: port | 0, | ||
| 164 | + family: 'ipv6', | ||
| 165 | + }); | ||
| 166 | + } | ||
| 167 | + return new SocketAddress({ address, port: port | 0 }); | ||
| 168 | + } catch { | ||
| 169 | + // Ignore errors here. Return undefined if the input cannot | ||
| 170 | + // be successfully parsed or is not a proper socket address. | ||
| 171 | + } | ||
| 172 | + } | ||
| 141 | 173 | } | |
| 142 | 174 | ||
| 143 | 175 | class InternalSocketAddress { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -17,121 +17,160 @@ const { | |||
| 17 | 17 | const { internalBinding } = require('internal/test/binding'); | |
| 18 | 18 | const { | |
| 19 | 19 | SocketAddress: _SocketAddress, | |
| 20 | - AF_INET | ||
| 20 | + AF_INET, | ||
| 21 | 21 | } = internalBinding('block_list'); | |
| 22 | 22 | ||
| 23 | - { | ||
| 24 | - const sa = new SocketAddress(); | ||
| 25 | - strictEqual(sa.address, '127.0.0.1'); | ||
| 26 | - strictEqual(sa.port, 0); | ||
| 27 | - strictEqual(sa.family, 'ipv4'); | ||
| 28 | - strictEqual(sa.flowlabel, 0); | ||
| 23 | + const { describe, it } = require('node:test'); | ||
| 29 | 24 | ||
| 30 | - const mc = new MessageChannel(); | ||
| 31 | - mc.port1.onmessage = common.mustCall(({ data }) => { | ||
| 32 | - ok(SocketAddress.isSocketAddress(data)); | ||
| 25 | + describe('net.SocketAddress...', () => { | ||
| 33 | 26 | ||
| 34 | - strictEqual(data.address, '127.0.0.1'); | ||
| 35 | - strictEqual(data.port, 0); | ||
| 36 | - strictEqual(data.family, 'ipv4'); | ||
| 37 | - strictEqual(data.flowlabel, 0); | ||
| 27 | + it('is cloneable', () => { | ||
| 28 | + const sa = new SocketAddress(); | ||
| 29 | + strictEqual(sa.address, '127.0.0.1'); | ||
| 30 | + strictEqual(sa.port, 0); | ||
| 31 | + strictEqual(sa.family, 'ipv4'); | ||
| 32 | + strictEqual(sa.flowlabel, 0); | ||
| 38 | 33 | ||
| 39 | - mc.port1.close(); | ||
| 34 | + const mc = new MessageChannel(); | ||
| 35 | + mc.port1.onmessage = common.mustCall(({ data }) => { | ||
| 36 | + ok(SocketAddress.isSocketAddress(data)); | ||
| 37 | + | ||
| 38 | + strictEqual(data.address, '127.0.0.1'); | ||
| 39 | + strictEqual(data.port, 0); | ||
| 40 | + strictEqual(data.family, 'ipv4'); | ||
| 41 | + strictEqual(data.flowlabel, 0); | ||
| 42 | + | ||
| 43 | + mc.port1.close(); | ||
| 44 | + }); | ||
| 45 | + mc.port2.postMessage(sa); | ||
| 40 | 46 | }); | |
| 41 | - mc.port2.postMessage(sa); | ||
| 42 | - } | ||
| 43 | - | ||
| 44 | - { | ||
| 45 | - const sa = new SocketAddress({}); | ||
| 46 | - strictEqual(sa.address, '127.0.0.1'); | ||
| 47 | - strictEqual(sa.port, 0); | ||
| 48 | - strictEqual(sa.family, 'ipv4'); | ||
| 49 | - strictEqual(sa.flowlabel, 0); | ||
| 50 | - } | ||
| 51 | - | ||
| 52 | - { | ||
| 53 | - const sa = new SocketAddress({ | ||
| 54 | - address: '123.123.123.123', | ||
| 47 | + | ||
| 48 | + it('has reasonable defaults', () => { | ||
| 49 | + const sa = new SocketAddress({}); | ||
| 50 | + strictEqual(sa.address, '127.0.0.1'); | ||
| 51 | + strictEqual(sa.port, 0); | ||
| 52 | + strictEqual(sa.family, 'ipv4'); | ||
| 53 | + strictEqual(sa.flowlabel, 0); | ||
| 55 | 54 | }); | |
| 56 | - strictEqual(sa.address, '123.123.123.123'); | ||
| 57 | - strictEqual(sa.port, 0); | ||
| 58 | - strictEqual(sa.family, 'ipv4'); | ||
| 59 | - strictEqual(sa.flowlabel, 0); | ||
| 60 | - } | ||
| 61 | - | ||
| 62 | - { | ||
| 63 | - const sa = new SocketAddress({ | ||
| 64 | - address: '123.123.123.123', | ||
| 65 | - port: 80 | ||
| 55 | + | ||
| 56 | + it('interprets simple ipv4 correctly', () => { | ||
| 57 | + const sa = new SocketAddress({ | ||
| 58 | + address: '123.123.123.123', | ||
| 59 | + }); | ||
| 60 | + strictEqual(sa.address, '123.123.123.123'); | ||
| 61 | + strictEqual(sa.port, 0); | ||
| 62 | + strictEqual(sa.family, 'ipv4'); | ||
| 63 | + strictEqual(sa.flowlabel, 0); | ||
| 66 | 64 | }); | |
| 67 | - strictEqual(sa.address, '123.123.123.123'); | ||
| 68 | - strictEqual(sa.port, 80); | ||
| 69 | - strictEqual(sa.family, 'ipv4'); | ||
| 70 | - strictEqual(sa.flowlabel, 0); | ||
| 71 | - } | ||
| 72 | - | ||
| 73 | - { | ||
| 74 | - const sa = new SocketAddress({ | ||
| 75 | - family: 'ipv6' | ||
| 65 | + | ||
| 66 | + it('sets the port correctly', () => { | ||
| 67 | + const sa = new SocketAddress({ | ||
| 68 | + address: '123.123.123.123', | ||
| 69 | + port: 80 | ||
| 70 | + }); | ||
| 71 | + strictEqual(sa.address, '123.123.123.123'); | ||
| 72 | + strictEqual(sa.port, 80); | ||
| 73 | + strictEqual(sa.family, 'ipv4'); | ||
| 74 | + strictEqual(sa.flowlabel, 0); | ||
| 76 | 75 | }); | |
| 77 | - strictEqual(sa.address, '::'); | ||
| 78 | - strictEqual(sa.port, 0); | ||
| 79 | - strictEqual(sa.family, 'ipv6'); | ||
| 80 | - strictEqual(sa.flowlabel, 0); | ||
| 81 | - } | ||
| 82 | - | ||
| 83 | - { | ||
| 84 | - const sa = new SocketAddress({ | ||
| 85 | - family: 'ipv6', | ||
| 86 | - flowlabel: 1, | ||
| 76 | + | ||
| 77 | + it('interprets simple ipv6 correctly', () => { | ||
| 78 | + const sa = new SocketAddress({ | ||
| 79 | + family: 'ipv6' | ||
| 80 | + }); | ||
| 81 | + strictEqual(sa.address, '::'); | ||
| 82 | + strictEqual(sa.port, 0); | ||
| 83 | + strictEqual(sa.family, 'ipv6'); | ||
| 84 | + strictEqual(sa.flowlabel, 0); | ||
| 87 | 85 | }); | |
| 88 | - strictEqual(sa.address, '::'); | ||
| 89 | - strictEqual(sa.port, 0); | ||
| 90 | - strictEqual(sa.family, 'ipv6'); | ||
| 91 | - strictEqual(sa.flowlabel, 1); | ||
| 92 | - } | ||
| 93 | - | ||
| 94 | - [1, false, 'hello'].forEach((i) => { | ||
| 95 | - throws(() => new SocketAddress(i), { | ||
| 96 | - code: 'ERR_INVALID_ARG_TYPE' | ||
| 86 | + | ||
| 87 | + it('uses the flowlabel correctly', () => { | ||
| 88 | + const sa = new SocketAddress({ | ||
| 89 | + family: 'ipv6', | ||
| 90 | + flowlabel: 1, | ||
| 91 | + }); | ||
| 92 | + strictEqual(sa.address, '::'); | ||
| 93 | + strictEqual(sa.port, 0); | ||
| 94 | + strictEqual(sa.family, 'ipv6'); | ||
| 95 | + strictEqual(sa.flowlabel, 1); | ||
| 97 | 96 | }); | |
| 98 | - }); | ||
| 99 | 97 | ||
| 100 | - [1, false, {}, [], 'test'].forEach((family) => { | ||
| 101 | - throws(() => new SocketAddress({ family }), { | ||
| 102 | - code: 'ERR_INVALID_ARG_VALUE' | ||
| 98 | + it('validates input correctly', () => { | ||
| 99 | + [1, false, 'hello'].forEach((i) => { | ||
| 100 | + throws(() => new SocketAddress(i), { | ||
| 101 | + code: 'ERR_INVALID_ARG_TYPE' | ||
| 102 | + }); | ||
| 103 | + }); | ||
| 104 | + | ||
| 105 | + [1, false, {}, [], 'test'].forEach((family) => { | ||
| 106 | + throws(() => new SocketAddress({ family }), { | ||
| 107 | + code: 'ERR_INVALID_ARG_VALUE' | ||
| 108 | + }); | ||
| 109 | + }); | ||
| 110 | + | ||
| 111 | + [1, false, {}, []].forEach((address) => { | ||
| 112 | + throws(() => new SocketAddress({ address }), { | ||
| 113 | + code: 'ERR_INVALID_ARG_TYPE' | ||
| 114 | + }); | ||
| 115 | + }); | ||
| 116 | + | ||
| 117 | + [-1, false, {}, []].forEach((port) => { | ||
| 118 | + throws(() => new SocketAddress({ port }), { | ||
| 119 | + code: 'ERR_SOCKET_BAD_PORT' | ||
| 120 | + }); | ||
| 121 | + }); | ||
| 122 | + | ||
| 123 | + throws(() => new SocketAddress({ flowlabel: -1 }), { | ||
| 124 | + code: 'ERR_OUT_OF_RANGE' | ||
| 125 | + }); | ||
| 103 | 126 | }); | |
| 104 | - }); | ||
| 105 | 127 | ||
| 106 | - [1, false, {}, []].forEach((address) => { | ||
| 107 | - throws(() => new SocketAddress({ address }), { | ||
| 108 | - code: 'ERR_INVALID_ARG_TYPE' | ||
| 128 | + it('InternalSocketAddress correctly inherits from SocketAddress', () => { | ||
| 129 | + // Test that the internal helper class InternalSocketAddress correctly | ||
| 130 | + // inherits from SocketAddress and that it does not throw when its properties | ||
| 131 | + // are accessed. | ||
| 132 | + | ||
| 133 | + const address = '127.0.0.1'; | ||
| 134 | + const port = 8080; | ||
| 135 | + const flowlabel = 0; | ||
| 136 | + const handle = new _SocketAddress(address, port, AF_INET, flowlabel); | ||
| 137 | + const addr = new InternalSocketAddress(handle); | ||
| 138 | + ok(addr instanceof SocketAddress); | ||
| 139 | + strictEqual(addr.address, address); | ||
| 140 | + strictEqual(addr.port, port); | ||
| 141 | + strictEqual(addr.family, 'ipv4'); | ||
| 142 | + strictEqual(addr.flowlabel, flowlabel); | ||
| 109 | 143 | }); | |
| 110 | - }); | ||
| 111 | 144 | ||
| 112 | - [-1, false, {}, []].forEach((port) => { | ||
| 113 | - throws(() => new SocketAddress({ port }), { | ||
| 114 | - code: 'ERR_SOCKET_BAD_PORT' | ||
| 145 | + it('SocketAddress.parse() works as expected', () => { | ||
| 146 | + const good = [ | ||
| 147 | + { input: '1.2.3.4', address: '1.2.3.4', port: 0, family: 'ipv4' }, | ||
| 148 | + { input: '192.168.257:1', address: '192.168.1.1', port: 1, family: 'ipv4' }, | ||
| 149 | + { input: '256', address: '0.0.1.0', port: 0, family: 'ipv4' }, | ||
| 150 | + { input: '999999999:12', address: '59.154.201.255', port: 12, family: 'ipv4' }, | ||
| 151 | + { input: '0xffffffff', address: '255.255.255.255', port: 0, family: 'ipv4' }, | ||
| 152 | + { input: '0x.0x.0', address: '0.0.0.0', port: 0, family: 'ipv4' }, | ||
| 153 | + { input: '[1:0::]', address: '1::', port: 0, family: 'ipv6' }, | ||
| 154 | + { input: '[1::8]:123', address: '1::8', port: 123, family: 'ipv6' }, | ||
| 155 | + ]; | ||
| 156 | + | ||
| 157 | + good.forEach((i) => { | ||
| 158 | + const addr = SocketAddress.parse(i.input); | ||
| 159 | + strictEqual(addr.address, i.address); | ||
| 160 | + strictEqual(addr.port, i.port); | ||
| 161 | + strictEqual(addr.family, i.family); | ||
| 162 | + }); | ||
| 163 | + | ||
| 164 | + const bad = [ | ||
| 165 | + 'not an ip', | ||
| 166 | + 'abc.123', | ||
| 167 | + '259.1.1.1', | ||
| 168 | + '12:12:12', | ||
| 169 | + ]; | ||
| 170 | + | ||
| 171 | + bad.forEach((i) => { | ||
| 172 | + strictEqual(SocketAddress.parse(i), undefined); | ||
| 173 | + }); | ||
| 115 | 174 | }); | |
| 116 | - }); | ||
| 117 | 175 | ||
| 118 | - throws(() => new SocketAddress({ flowlabel: -1 }), { | ||
| 119 | - code: 'ERR_OUT_OF_RANGE' | ||
| 120 | 176 | }); | |
| 121 | - | ||
| 122 | - { | ||
| 123 | - // Test that the internal helper class InternalSocketAddress correctly | ||
| 124 | - // inherits from SocketAddress and that it does not throw when its properties | ||
| 125 | - // are accessed. | ||
| 126 | - | ||
| 127 | - const address = '127.0.0.1'; | ||
| 128 | - const port = 8080; | ||
| 129 | - const flowlabel = 0; | ||
| 130 | - const handle = new _SocketAddress(address, port, AF_INET, flowlabel); | ||
| 131 | - const addr = new InternalSocketAddress(handle); | ||
| 132 | - ok(addr instanceof SocketAddress); | ||
| 133 | - strictEqual(addr.address, address); | ||
| 134 | - strictEqual(addr.port, port); | ||
| 135 | - strictEqual(addr.family, 'ipv4'); | ||
| 136 | - strictEqual(addr.flowlabel, flowlabel); | ||
| 137 | - } | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments