Skip to content

Commit

Permalink
Slightly more complete undici polyfill (#15360)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jarred-Sumner authored Nov 23, 2024
1 parent 1a1cf0a commit 514a47c
Show file tree
Hide file tree
Showing 3 changed files with 303 additions and 56 deletions.
18 changes: 17 additions & 1 deletion src/bun.js/bindings/Undici.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
#include "JavaScriptCore/AggregateError.h"
#include "JavaScriptCore/JSFunction.h"
#include "JSDOMFile.h"
#include "JSWebSocket.h"
#include "JSCloseEvent.h"
#include "JSErrorEvent.h"
#include "JSMessageEvent.h"

namespace Bun {

Expand All @@ -27,7 +31,7 @@ JSC::JSValue createUndiciInternalBinding(Zig::GlobalObject* globalObject)
{
auto& vm = globalObject->vm();

auto* obj = constructEmptyObject(globalObject);
auto* obj = constructEmptyObject(globalObject, globalObject->objectPrototype(), 11);
obj->putDirectIndex(
globalObject, 0,
globalObject->JSResponseConstructor());
Expand All @@ -52,6 +56,18 @@ JSC::JSValue createUndiciInternalBinding(Zig::GlobalObject* globalObject)
obj->putDirectIndex(
globalObject, 7,
JSURLSearchParams::getConstructor(vm, globalObject));
obj->putDirectIndex(
globalObject, 8,
JSWebSocket::getConstructor(vm, globalObject));
obj->putDirectIndex(
globalObject, 9,
JSCloseEvent::getConstructor(vm, globalObject));
obj->putDirectIndex(
globalObject, 10,
JSErrorEvent::getConstructor(vm, globalObject));
obj->putDirectIndex(
globalObject, 11,
JSMessageEvent::getConstructor(vm, globalObject));

return obj;
}
Expand Down
283 changes: 230 additions & 53 deletions src/js/thirdparty/undici.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,23 @@ const File = bindings[4];
const URL = bindings[5];
const AbortSignal = bindings[6];
const URLSearchParams = bindings[7];
const WebSocket = bindings[8];
const CloseEvent = bindings[9];
const ErrorEvent = bindings[10];
const MessageEvent = bindings[11];

class FileReader extends EventTarget {
constructor() {
throw new Error("Not implemented yet!");
super();
}

static EMPTY = 0;
static LOADING = 1;
static DONE = 2;
}

function notImplemented() {
throw new Error("Not implemented in bun");
throw new Error("This function is not yet implemented in Bun");
}

/**
Expand Down Expand Up @@ -230,102 +238,271 @@ async function request(
}

function stream() {
throw new Error("Not implemented in bun");
notImplemented();
}
function pipeline() {
throw new Error("Not implemented in bun");
notImplemented();
}
function connect() {
throw new Error("Not implemented in bun");
notImplemented();
}
function upgrade() {
throw new Error("Not implemented in bun");
notImplemented();
}

class MockClient {
constructor() {}
}
class MockPool {
constructor() {}
}
class MockAgent {
constructor() {}
}

function mockErrors() {}

class Dispatcher extends EventEmitter {}
class Agent extends Dispatcher {}
class Pool extends Dispatcher {
request() {}
}
class BalancedPool extends Dispatcher {}
class Client extends Dispatcher {
request() {}
}

class DispatcherBase extends EventEmitter {}

class ProxyAgent extends DispatcherBase {
constructor() {
throw new Error("Not implemented in bun");
super();
}
}
class MockPool {

class EnvHttpProxyAgent extends DispatcherBase {
constructor() {
throw new Error("Not implemented in bun");
super();
}
}
class MockAgent {

class RetryAgent extends Dispatcher {
constructor() {
throw new Error("Not implemented in bun");
super();
}
}

function mockErrors() {
throw new Error("Not implemented in bun");
class RetryHandler {
constructor() {}
}

function Undici() {
throw new Error("Not implemented in bun");
class DecoratorHandler {
constructor() {}
}

class Dispatcher extends EventEmitter {}
class Agent extends Dispatcher {}
class Pool extends Dispatcher {
request() {
throw new Error("Not implemented in bun");
}
class RedirectHandler {
constructor() {}
}
class BalancedPool extends Dispatcher {}
class Client extends Dispatcher {
request() {
throw new Error("Not implemented in bun");

function createRedirectInterceptor() {
return new RedirectHandler();
}

const interceptors = {
redirect: () => {},
retry: () => {},
dump: () => {},
};

// Error classes
class UndiciError extends Error {}
class AbortError extends UndiciError {}
class HTTPParserError extends Error {}
class HeadersTimeoutError extends UndiciError {}
class HeadersOverflowError extends UndiciError {}
class BodyTimeoutError extends UndiciError {}
class RequestContentLengthMismatchError extends UndiciError {}
class ConnectTimeoutError extends UndiciError {}
class ResponseStatusCodeError extends UndiciError {}
class InvalidArgumentError extends UndiciError {}
class InvalidReturnValueError extends UndiciError {}
class RequestAbortedError extends AbortError {}
class ClientDestroyedError extends UndiciError {}
class ClientClosedError extends UndiciError {}
class InformationalError extends UndiciError {}
class SocketError extends UndiciError {}
class NotSupportedError extends UndiciError {}
class ResponseContentLengthMismatchError extends UndiciError {}
class BalancedPoolMissingUpstreamError extends UndiciError {}
class ResponseExceededMaxSizeError extends UndiciError {}
class RequestRetryError extends UndiciError {}
class SecureProxyConnectionError extends UndiciError {}
class MockNotMatchedError extends UndiciError {}

const errors = {
AbortError,
HTTPParserError,
UndiciError,
HeadersTimeoutError,
HeadersOverflowError,
BodyTimeoutError,
RequestContentLengthMismatchError,
ConnectTimeoutError,
ResponseStatusCodeError,
InvalidArgumentError,
InvalidReturnValueError,
RequestAbortedError,
ClientDestroyedError,
ClientClosedError,
InformationalError,
SocketError,
NotSupportedError,
ResponseContentLengthMismatchError,
BalancedPoolMissingUpstreamError,
ResponseExceededMaxSizeError,
RequestRetryError,
SecureProxyConnectionError,
};

const util = {
parseHeaders: () => {
notImplemented();
},
headerNameToString: () => {
notImplemented();
},
};

class EventSource extends EventTarget {
static CONNECTING = 0;
static OPEN = 1;
static CLOSED = 2;

constructor() {
super();
}
}

Undici.Dispatcher = Dispatcher;
Undici.Pool = Pool;
Undici.BalancedPool = BalancedPool;
Undici.Client = Client;
Undici.Agent = Agent;

Undici.buildConnector =
Undici.errors =
Undici.setGlobalDispatcher =
Undici.getGlobalDispatcher =
Undici.request =
Undici.stream =
Undici.pipeline =
Undici.connect =
Undici.upgrade =
Undici.MockClient =
Undici.MockPool =
Undici.MockAgent =
Undici.mockErrors =
notImplemented;

Undici.fetch = fetch;

export default {
// Add missing cookie functions
function deleteCookie() {
notImplemented();
}

function getCookies() {
notImplemented();
}

function getSetCookies() {
notImplemented();
}

function setCookie() {
notImplemented();
}

// Add missing MIME type functions
function parseMIMEType() {
notImplemented();
}

function serializeAMimeType() {
notImplemented();
}

let globalDispatcher;

// Add missing dispatcher functions
function setGlobalDispatcher(dispatcher) {
globalDispatcher = dispatcher;
}

function getGlobalDispatcher() {
return (globalDispatcher ??= new Dispatcher());
}

// Add missing origin functions
function setGlobalOrigin() {}

function getGlobalOrigin() {}

// Create empty CacheStorage
const caches = {};

/**
* Builds a connector function for making network connections
* @param {Object} [options] Configuration options for the connector
* @param {boolean} [options.rejectUnauthorized] Whether to reject unauthorized SSL/TLS connections
* @param {number} [options.connectTimeout] Connection timeout in milliseconds
* @param {number} [options.maxCachedSessions] Maximum number of cached TLS sessions
* @param {boolean} [options.allowH2] Whether to allow HTTP/2 connections
* @returns {function} A connector function
*/
function buildConnector(options = {}) {
const { rejectUnauthorized = true, connectTimeout, maxCachedSessions = 100, allowH2 = false } = options;

/**
* @param {Object} options
* @param {string} options.hostname
* @param {number} options.port
* @param {string} [options.servername]
* @param {AbortSignal} [options.signal]
*/
return function connect({ hostname, port, servername, signal }) {
notImplemented();
};
}

// Update the exports to match the exact structure
const moduleExports = {
Agent,
BalancedPool,
buildConnector,
caches,
Client,
CloseEvent,
connect,
createRedirectInterceptor,
DecoratorHandler,
deleteCookie,
Dispatcher,
EnvHttpProxyAgent,
ErrorEvent,
errors,
EventSource,
fetch,
File,
FileReader,
FormData,
getCookies,
getGlobalDispatcher,
getGlobalOrigin,
getSetCookies,
Headers,
interceptors,
MessageEvent,
MockAgent,
MockClient,
mockErrors,
MockPool,
parseMIMEType,
pipeline,
Pool,
request,
ProxyAgent,
RedirectHandler,
Request,
request,
Response,
RetryAgent,
RetryHandler,
serializeAMimeType,
setCookie,
setGlobalDispatcher,
setGlobalOrigin,
stream,
Undici,
upgrade,
URL,
URLSearchParams,
util,
WebSocket,
};

moduleExports.default = moduleExports;
export default moduleExports;
Loading

0 comments on commit 514a47c

Please sign in to comment.