aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js/net.exports.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/bun.js/net.exports.js')
-rw-r--r--src/bun.js/net.exports.js795
1 files changed, 0 insertions, 795 deletions
diff --git a/src/bun.js/net.exports.js b/src/bun.js/net.exports.js
deleted file mode 100644
index 3d15eed2b..000000000
--- a/src/bun.js/net.exports.js
+++ /dev/null
@@ -1,795 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// IPv4 Segment
-const v4Seg = "(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])";
-const v4Str = `(${v4Seg}[.]){3}${v4Seg}`;
-const IPv4Reg = new RegExp(`^${v4Str}$`);
-
-// IPv6 Segment
-const v6Seg = "(?:[0-9a-fA-F]{1,4})";
-const IPv6Reg = new RegExp(
- "^(" +
- `(?:${v6Seg}:){7}(?:${v6Seg}|:)|` +
- `(?:${v6Seg}:){6}(?:${v4Str}|:${v6Seg}|:)|` +
- `(?:${v6Seg}:){5}(?::${v4Str}|(:${v6Seg}){1,2}|:)|` +
- `(?:${v6Seg}:){4}(?:(:${v6Seg}){0,1}:${v4Str}|(:${v6Seg}){1,3}|:)|` +
- `(?:${v6Seg}:){3}(?:(:${v6Seg}){0,2}:${v4Str}|(:${v6Seg}){1,4}|:)|` +
- `(?:${v6Seg}:){2}(?:(:${v6Seg}){0,3}:${v4Str}|(:${v6Seg}){1,5}|:)|` +
- `(?:${v6Seg}:){1}(?:(:${v6Seg}){0,4}:${v4Str}|(:${v6Seg}){1,6}|:)|` +
- `(?::((?::${v6Seg}){0,5}:${v4Str}|(?::${v6Seg}){1,7}|:))` +
- ")(%[0-9a-zA-Z-.:]{1,})?$",
-);
-
-function isIPv4(s) {
- return IPv4Reg.test(s);
-}
-
-function isIPv6(s) {
- return IPv6Reg.test(s);
-}
-
-function isIP(s) {
- if (isIPv4(s)) return 4;
- if (isIPv6(s)) return 6;
- return 0;
-}
-
-const { Bun, createFIFO, Object } = import.meta.primordials;
-const { connect: bunConnect } = Bun;
-const { Duplex } = import.meta.require("node:stream");
-const { EventEmitter } = import.meta.require("node:events");
-var { setTimeout } = globalThis;
-
-const bunTlsSymbol = Symbol.for("::buntls::");
-const bunSocketServerHandlers = Symbol.for("::bunsocket_serverhandlers::");
-const bunSocketServerConnections = Symbol.for("::bunnetserverconnections::");
-const bunSocketServerOptions = Symbol.for("::bunnetserveroptions::");
-
-var SocketClass;
-const Socket = (function (InternalSocket) {
- SocketClass = InternalSocket;
- Object.defineProperty(SocketClass.prototype, Symbol.toStringTag, {
- value: "Socket",
- enumerable: false,
- });
-
- return Object.defineProperty(
- function Socket(options) {
- return new InternalSocket(options);
- },
- Symbol.hasInstance,
- {
- value(instance) {
- return instance instanceof InternalSocket;
- },
- },
- );
-})(
- class Socket extends Duplex {
- static #Handlers = {
- close: Socket.#Close,
- connectError(socket, error) {
- const self = socket.data;
-
- self.emit("error", error);
- },
- data({ data: self }, buffer) {
- self.bytesRead += buffer.length;
- const queue = self.#readQueue;
-
- if (queue.isEmpty()) {
- if (self.push(buffer)) return;
- }
- queue.push(buffer);
- },
- drain: Socket.#Drain,
- end: Socket.#Close,
- error(socket, error) {
- const self = socket.data;
- const callback = self.#writeCallback;
- if (callback) {
- self.#writeCallback = null;
- callback(error);
- }
- self.emit("error", error);
- },
- open(socket) {
- const self = socket.data;
- socket.timeout(self.timeout);
- socket.ref();
- self.#socket = socket;
- self.connecting = false;
- self.emit("connect", self);
- Socket.#Drain(socket);
- },
- handshake(socket, success, verifyError) {
- const { data: self } = socket;
- self._securePending = false;
- self.secureConnecting = false;
- self._secureEstablished = !!success;
-
- // Needs getPeerCertificate support (not implemented yet)
- // if (!verifyError && !this.isSessionReused()) {
- // const hostname = options.servername ||
- // options.host ||
- // (options.socket && options.socket._host) ||
- // 'localhost';
- // const cert = this.getPeerCertificate(true);
- // verifyError = options.checkServerIdentity(hostname, cert);
- // }
-
- if (self._requestCert || self._rejectUnauthorized) {
- if (verifyError) {
- self.authorized = false;
- self.authorizationError = verifyError.code || verifyError.message;
- if (self._rejectUnauthorized) {
- self.destroy(verifyError);
- return;
- }
- }
- } else {
- self.authorized = true;
- }
- self.emit("secureConnect", verifyError);
- },
- timeout(socket) {
- const self = socket.data;
- self.emit("timeout", self);
- },
- binaryType: "buffer",
- };
-
- static #Close(socket) {
- const self = socket.data;
- if (self.#closed) return;
- self.#closed = true;
- //socket cannot be used after close
- self.#socket = null;
- const queue = self.#readQueue;
- if (queue.isEmpty()) {
- if (self.push(null)) return;
- }
- queue.push(null);
- }
-
- static #Drain(socket) {
- const self = socket.data;
-
- const callback = self.#writeCallback;
- if (callback) {
- const chunk = self.#writeChunk;
- const written = socket.write(chunk);
-
- self.bytesWritten += written;
- if (written < chunk.length) {
- self.#writeChunk = chunk.slice(written);
- } else {
- self.#writeCallback = null;
- self.#writeChunk = null;
- callback(null);
- }
- }
- }
-
- static [bunSocketServerHandlers] = {
- data: Socket.#Handlers.data,
- close(socket) {
- Socket.#Handlers.close(socket);
- this.data[bunSocketServerConnections]--;
- },
- end(socket) {
- Socket.#Handlers.end(socket);
- this.data[bunSocketServerConnections]--;
- },
- open(socket) {
- const self = this.data;
- const options = self[bunSocketServerOptions];
- const { pauseOnConnect, connectionListener, InternalSocketClass, requestCert, rejectUnauthorized } = options;
- const _socket = new InternalSocketClass({});
- _socket.isServer = true;
- _socket._requestCert = requestCert;
- _socket._rejectUnauthorized = rejectUnauthorized;
-
- _socket.#attach(this.localPort, socket);
- if (self.maxConnections && self[bunSocketServerConnections] >= self.maxConnections) {
- const data = {
- localAddress: _socket.localAddress,
- localPort: _socket.localPort,
- localFamily: _socket.localFamily,
- remoteAddress: _socket.remoteAddress,
- remotePort: _socket.remotePort,
- remoteFamily: _socket.remoteFamily || "IPv4",
- };
-
- socket.end();
-
- self.emit("drop", data);
- return;
- }
- // the duplex implementation start paused, so we resume when pauseOnConnect is falsy
- if (!pauseOnConnect) {
- _socket.resume();
- }
-
- self[bunSocketServerConnections]++;
-
- if (typeof connectionListener == "function") {
- if (InternalSocketClass.name === "TLSSocket") {
- // add secureConnection event handler
- self.once("secureConnection", () => connectionListener(_socket));
- } else {
- connectionListener(_socket);
- }
- }
-
- self.emit("connection", _socket);
- },
- handshake({ data: self }, success, verifyError) {
- self._securePending = false;
- self.secureConnecting = false;
- self._secureEstablished = !!success;
- // Needs getPeerCertificate support (not implemented yet)
- // if (!verifyError && !this.isSessionReused()) {
- // const hostname = options.servername ||
- // options.host ||
- // (options.socket && options.socket._host) ||
- // 'localhost';
- // const cert = this.getPeerCertificate(true);
- // verifyError = options.checkServerIdentity(hostname, cert);
- // }
-
- if (self._requestCert || self._rejectUnauthorized) {
- if (verifyError) {
- self.authorized = false;
- self.authorizationError = verifyError.code || verifyError.message;
- if (self._rejectUnauthorized) {
- self.destroy(verifyError);
- return;
- }
- }
- } else {
- self.authorized = true;
- }
- self.emit("secureConnect", verifyError);
- },
- error(socket, error) {
- Socket.#Handlers.error(socket, error);
- this.data.emit("error", error);
- },
- timeout: Socket.#Handlers.timeout,
- connectError: Socket.#Handlers.connectError,
- drain: Socket.#Handlers.drain,
- binaryType: "buffer",
- };
-
- bytesRead = 0;
- bytesWritten = 0;
- #closed = false;
- connecting = false;
- localAddress = "127.0.0.1";
- #readQueue = createFIFO();
- remotePort;
- #socket;
- timeout = 0;
- #writeCallback;
- #writeChunk;
- #pendingRead;
-
- isServer = false;
-
- constructor(options) {
- const { signal, write, read, allowHalfOpen = false, ...opts } = options || {};
- super({
- ...opts,
- allowHalfOpen,
- readable: true,
- writable: true,
- });
- this.#pendingRead = undefined;
- signal?.once("abort", () => this.destroy());
- this.once("connect", () => this.emit("ready"));
- }
-
- address() {
- return {
- address: this.localAddress,
- family: this.localFamily,
- port: this.localPort,
- };
- }
-
- get bufferSize() {
- return this.writableLength;
- }
-
- #attach(port, socket) {
- this.remotePort = port;
- socket.data = this;
- socket.timeout(this.timeout);
- socket.ref();
- this.#socket = socket;
- this.connecting = false;
- this.emit("connect", this);
- Socket.#Drain(socket);
- }
-
- connect(port, host, connectListener) {
- var path;
- if (typeof port === "string") {
- path = port;
- port = undefined;
-
- if (typeof host === "function") {
- connectListener = host;
- host = undefined;
- }
- } else if (typeof host == "function") {
- if (typeof port === "string") {
- path = port;
- port = undefined;
- }
-
- connectListener = host;
- host = undefined;
- }
- if (typeof port == "object") {
- var {
- port,
- host,
- path,
- // TODOs
- localAddress,
- localPort,
- family,
- hints,
- lookup,
- noDelay,
- keepAlive,
- keepAliveInitialDelay,
- requestCert,
- rejectUnauthorized,
- pauseOnConnect,
- servername,
- } = port;
- this.servername = servername;
- }
-
- if (!pauseOnConnect) {
- this.resume();
- }
- this.connecting = true;
- this.remotePort = port;
-
- const bunTLS = this[bunTlsSymbol];
- var tls = undefined;
-
- if (typeof bunTLS === "function") {
- tls = bunTLS.call(this, port, host, true);
- // Client always request Cert
- this._requestCert = true;
- this._rejectUnauthorized = rejectUnauthorized;
-
- if (tls) {
- // TLS can true/false or options
- if (typeof tls !== "object") {
- tls = {
- rejectUnauthorized: rejectUnauthorized,
- requestCert: true,
- };
- } else {
- tls.rejectUnauthorized = rejectUnauthorized;
- tls.requestCert = true;
- }
- }
-
- this.authorized = false;
- this.secureConnecting = true;
- this._secureEstablished = false;
- this._securePending = true;
- if (connectListener) this.on("secureConnect", connectListener);
- } else if (connectListener) this.on("connect", connectListener);
- bunConnect(
- path
- ? {
- data: this,
- unix: path,
- socket: Socket.#Handlers,
- tls,
- }
- : {
- data: this,
- hostname: host || "localhost",
- port: port,
- socket: Socket.#Handlers,
- tls,
- },
- );
- return this;
- }
-
- _destroy(err, callback) {
- this.#socket?.end();
- callback(err);
- }
-
- _final(callback) {
- this.#socket?.end();
- callback();
- }
-
- get localAddress() {
- return "127.0.0.1";
- }
-
- get localFamily() {
- return "IPv4";
- }
-
- get localPort() {
- return this.#socket?.localPort;
- }
-
- get pending() {
- return this.connecting;
- }
-
- _read(size) {
- const queue = this.#readQueue;
- let chunk;
- while ((chunk = queue.peek())) {
- if (!this.push(chunk)) return;
- queue.shift();
- }
- }
-
- get readyState() {
- if (this.connecting) return "opening";
- if (this.readable) {
- return this.writable ? "open" : "readOnly";
- } else {
- return this.writable ? "writeOnly" : "closed";
- }
- }
-
- ref() {
- this.#socket?.ref();
- }
-
- get remoteAddress() {
- return this.#socket?.remoteAddress;
- }
-
- get remoteFamily() {
- return "IPv4";
- }
-
- resetAndDestroy() {
- this.#socket?.end();
- }
-
- setKeepAlive(enable = false, initialDelay = 0) {
- // TODO
- return this;
- }
-
- setNoDelay(noDelay = true) {
- // TODO
- return this;
- }
-
- setTimeout(timeout, callback) {
- this.#socket?.timeout(timeout);
- this.timeout = timeout;
- if (callback) this.once("timeout", callback);
- return this;
- }
-
- unref() {
- this.#socket?.unref();
- }
-
- _write(chunk, encoding, callback) {
- if (typeof chunk == "string" && encoding !== "utf8") chunk = Buffer.from(chunk, encoding);
- var written = this.#socket?.write(chunk);
- if (written == chunk.length) {
- callback();
- } else if (this.#writeCallback) {
- callback(new Error("overlapping _write()"));
- } else {
- if (written > 0) {
- if (typeof chunk == "string") {
- chunk = chunk.slice(written);
- } else {
- chunk = chunk.subarray(written);
- }
- }
-
- this.#writeCallback = callback;
- this.#writeChunk = chunk;
- }
- }
- },
-);
-
-function createConnection(port, host, connectListener) {
- if (typeof port === "object") {
- // port is option pass Socket options and let connect handle connection options
- return new Socket(port).connect(port, host, connectListener);
- }
- // port is path or host, let connect handle this
- return new Socket().connect(port, host, connectListener);
-}
-
-const connect = createConnection;
-
-class Server extends EventEmitter {
- #server;
- #listening = false;
- [bunSocketServerConnections] = 0;
- [bunSocketServerOptions];
- maxConnections = 0;
-
- constructor(options, connectionListener) {
- super();
-
- if (typeof options === "function") {
- connectionListener = options;
- options = {};
- } else if (options == null || typeof options === "object") {
- options = { ...options };
- } else {
- throw new Error("bun-net-polyfill: invalid arguments");
- }
-
- const { maxConnections } = options;
- this.maxConnections = Number.isSafeInteger(maxConnections) && maxConnections > 0 ? maxConnections : 0;
-
- options.connectionListener = connectionListener;
- this[bunSocketServerOptions] = options;
- }
-
- ref() {
- this.#server?.ref();
- return this;
- }
-
- unref() {
- this.#server?.unref();
- return this;
- }
-
- close(callback) {
- if (this.#server) {
- this.#server.stop(true);
- this.#server = null;
- this.#listening = false;
- this[bunSocketServerConnections] = 0;
- this.emit("close");
- if (typeof callback === "function") {
- callback();
- }
-
- return this;
- }
-
- if (typeof callback === "function") {
- const error = new Error("Server is not running");
- error.code = "ERR_SERVER_NOT_RUNNING";
- callback(error);
- }
- return this;
- }
-
- address() {
- const server = this.#server;
- if (server) {
- const unix = server.unix;
- if (unix) {
- return unix;
- }
-
- //TODO: fix adress when host is passed
- let address = server.hostname;
- const type = isIP(address);
- const port = server.port;
- if (typeof port === "number") {
- return {
- port,
- address,
- family: type ? `IPv${type}` : undefined,
- };
- }
- if (type) {
- return {
- address,
- family: type ? `IPv${type}` : undefined,
- };
- }
-
- return address;
- }
- return null;
- }
-
- getConnections(callback) {
- if (typeof callback === "function") {
- //in Bun case we will never error on getConnections
- //node only errors if in the middle of the couting the server got disconnected, what never happens in Bun
- //if disconnected will only pass null as well and 0 connected
- callback(null, this.#server ? this[bunSocketServerConnections] : 0);
- }
- return this;
- }
-
- listen(port, hostname, onListen) {
- let backlog;
- let path;
- let exclusive = false;
- //port is actually path
- if (typeof port === "string") {
- if (Number.isSafeInteger(hostname)) {
- if (hostname > 0) {
- //hostname is backlog
- backlog = hostname;
- }
- } else if (typeof hostname === "function") {
- //hostname is callback
- onListen = hostname;
- }
-
- path = port;
- hostname = undefined;
- port = undefined;
- } else {
- if (typeof hostname === "function") {
- onListen = hostname;
- hostname = undefined;
- }
-
- if (typeof port === "function") {
- onListen = port;
- port = 0;
- } else if (typeof port === "object") {
- const options = port;
- options.signal?.addEventListener("abort", () => this.close());
-
- hostname = options.host;
- exclusive = options.exclusive === true;
- const path = options.path;
- port = options.port;
-
- if (!Number.isSafeInteger(port) || port < 0) {
- if (path) {
- hostname = path;
- port = undefined;
- } else {
- let message = 'The argument \'options\' must have the property "port" or "path"';
- try {
- message = `${message}. Received ${JSON.stringify(options)}`;
- } catch {}
-
- const error = new TypeError(message);
- error.code = "ERR_INVALID_ARG_VALUE";
- throw error;
- }
- } else if (!Number.isSafeInteger(port) || port < 0) {
- port = 0;
- }
-
- // port <number>
- // host <string>
- // path <string> Will be ignored if port is specified. See Identifying paths for IPC connections.
- // backlog <number> Common parameter of server.listen() functions.
- // exclusive <boolean> Default: false
- // readableAll <boolean> For IPC servers makes the pipe readable for all users. Default: false.
- // writableAll <boolean> For IPC servers makes the pipe writable for all users. Default: false.
- // ipv6Only <boolean> For TCP servers, setting ipv6Only to true will disable dual-stack support, i.e., binding to host :: won't make 0.0.0.0 be bound. Default: false.
- // signal <AbortSignal> An AbortSignal that may be used to close a listening server.
-
- if (typeof port.callback === "function") onListen = port?.callback;
- } else if (!Number.isSafeInteger(port) || port < 0) {
- port = 0;
- }
- hostname = hostname || "::";
- }
-
- try {
- var tls = undefined;
- var TLSSocketClass = undefined;
- const bunTLS = this[bunTlsSymbol];
- if (typeof bunTLS === "function") {
- [tls, TLSSocketClass] = bunTLS.call(this, port, hostname, false);
- }
-
- this[bunSocketServerOptions].InternalSocketClass = TLSSocketClass || SocketClass;
-
- this.#server = Bun.listen(
- path
- ? {
- exclusive,
- unix: path,
- tls,
- socket: SocketClass[bunSocketServerHandlers],
- }
- : {
- exclusive,
- port,
- hostname,
- tls,
- socket: SocketClass[bunSocketServerHandlers],
- },
- );
-
- //make this instance available on handlers
- this.#server.data = this;
-
- this.#listening = true;
-
- // We must schedule the emitListeningNextTick() only after the next run of
- // the event loop's IO queue. Otherwise, the server may not actually be listening
- // when the 'listening' event is emitted.
- //
- // That leads to all sorts of confusion.
- //
- // process.nextTick() is not sufficient because it will run before the IO queue.
- setTimeout(emitListeningNextTick, 1, this, onListen);
- } catch (err) {
- this.#listening = false;
- setTimeout(emitErrorNextTick, 1, this, err);
- }
- return this;
- }
-}
-
-function emitErrorNextTick(self, error) {
- self.emit("error", error);
-}
-
-function emitListeningNextTick(self, onListen) {
- if (typeof onListen === "function") {
- try {
- onListen();
- } catch (err) {
- self.emit("error", err);
- }
- }
- self.emit("listening");
-}
-
-function createServer(options, connectionListener) {
- return new Server(options, connectionListener);
-}
-
-export default {
- createServer,
- Server,
- createConnection,
- connect,
- isIP,
- isIPv4,
- isIPv6,
- Socket,
- [Symbol.for("CommonJS")]: 0,
- [Symbol.for("::bunternal::")]: SocketClass,
-};
-
-export { createServer, Server, createConnection, connect, isIP, isIPv4, isIPv6, Socket };