From 00e017c2743b075be57a9d9d5eeecfbfb09045df Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Wed, 9 Oct 2024 02:33:53 -0700 Subject: [PATCH] stash this --- packages/bun-uws/src/HttpContext.h | 3 +- packages/bun-uws/src/HttpContextData.h | 5 + packages/bun-uws/src/HttpResponse.h | 11 ++ packages/bun-uws/src/HttpResponseData.h | 3 + src/bun.js/bindings/NodeHTTP.cpp | 135 ++++++++++++++++++ src/bun.js/bindings/NodeHTTP.h | 5 +- src/bun.js/bindings/ZigGlobalObject.cpp | 6 +- src/bun.js/bindings/ZigGlobalObject.h | 2 + .../bindings/webcore/DOMClientIsoSubspaces.h | 1 + src/bun.js/bindings/webcore/DOMIsoSubspaces.h | 3 +- 10 files changed, 169 insertions(+), 5 deletions(-) diff --git a/packages/bun-uws/src/HttpContext.h b/packages/bun-uws/src/HttpContext.h index 338683f816..efee5c3176 100644 --- a/packages/bun-uws/src/HttpContext.h +++ b/packages/bun-uws/src/HttpContext.h @@ -127,8 +127,9 @@ private: /* Signal broken HTTP request only if we have a pending request */ if (httpResponseData->onAborted) { httpResponseData->onAborted((HttpResponse *)s, httpResponseData->userData); + } else if (httpResponseData->socketData && httpContextData->onSocketClosed) { + httpContextData->onSocketClosed(httpResponseData->socketData, SSL, s); } - /* Destruct socket ext */ httpResponseData->~HttpResponseData(); diff --git a/packages/bun-uws/src/HttpContextData.h b/packages/bun-uws/src/HttpContextData.h index 502941de87..53f1b91065 100644 --- a/packages/bun-uws/src/HttpContextData.h +++ b/packages/bun-uws/src/HttpContextData.h @@ -27,6 +27,7 @@ namespace uWS { template struct HttpResponse; struct HttpRequest; + template struct alignas(16) HttpContextData { template friend struct HttpContext; @@ -34,6 +35,7 @@ struct alignas(16) HttpContextData { template friend struct TemplatedApp; private: std::vector *, int)>> filterHandlers; + using OnSocketClosedCallback = void (*)(void* userData, int is_ssl, struct us_socket_t *rawSocket); MoveOnlyFunction missingServerNameHandler; @@ -51,6 +53,9 @@ private: bool isParsingHttp = false; bool rejectUnauthorized = false; + /* Used to simulate Node.js socket events. */ + OnSocketClosedCallback onSocketClosed = nullptr; + // TODO: SNI void clearRoutes() { this->router = HttpRouter{}; diff --git a/packages/bun-uws/src/HttpResponse.h b/packages/bun-uws/src/HttpResponse.h index 5c5f56cd85..9f93dd67b3 100644 --- a/packages/bun-uws/src/HttpResponse.h +++ b/packages/bun-uws/src/HttpResponse.h @@ -647,6 +647,17 @@ public: data->received_bytes_per_timeout = 0; } + void* getSocketData() { + HttpResponseData *httpResponseData = getHttpResponseData(); + + return httpResponseData->socketData; + } + + void setSocketData(void* socketData) { + HttpResponseData *httpResponseData = getHttpResponseData(); + + httpResponseData->socketData = socketData; + } void setWriteOffset(uint64_t offset) { HttpResponseData *httpResponseData = getHttpResponseData(); diff --git a/packages/bun-uws/src/HttpResponseData.h b/packages/bun-uws/src/HttpResponseData.h index 3b07b7257b..d118534a2d 100644 --- a/packages/bun-uws/src/HttpResponseData.h +++ b/packages/bun-uws/src/HttpResponseData.h @@ -85,6 +85,7 @@ struct HttpResponseData : AsyncSocketData, HttpParser { /* Shared context pointer */ void* userData = nullptr; + void* socketData = nullptr; /* Per socket event handlers */ OnWritableCallback onWritable = nullptr; @@ -109,3 +110,5 @@ struct HttpResponseData : AsyncSocketData, HttpParser { } #endif // UWS_HTTPRESPONSEDATA_H + +static_assert(sizeof(uWS::HttpResponseData) == 128, "HttpResponseData size is incorrect"); \ No newline at end of file diff --git a/src/bun.js/bindings/NodeHTTP.cpp b/src/bun.js/bindings/NodeHTTP.cpp index e7709185b2..ea44662172 100644 --- a/src/bun.js/bindings/NodeHTTP.cpp +++ b/src/bun.js/bindings/NodeHTTP.cpp @@ -21,6 +21,141 @@ namespace Bun { using namespace JSC; using namespace WebCore; +// Create a static hash table of values containing an onclose DOMAttributeGetterSetter and a close function +static const struct HashTableValue JSNodeHTTPServerSocketPrototypeTableValues[] = { + { "onclose"_s, static_cast(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, getterOnClose, setterOnClose } }, + { "close"_s, static_cast(PropertyAttribute::Function | PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::NativeFunctionType, functionNodeHTTPServerSocket_close, 0 } }, +}; + +class JSNodeHTTPServerSocketPrototype final : public JSC::JSNonFinalObject { +public: + using Base = JSC::JSNonFinalObject; + + static JSNodeHTTPServerSocketPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) + { + JSNodeHTTPServerSocketPrototype* prototype = new (NotNull, allocateCell(vm)) JSNodeHTTPServerSocketPrototype(vm, structure); + prototype->finishCreation(vm, globalObject); + return prototype; + } + + DECLARE_INFO; + + static constexpr bool needsDestruction = false; + static constexpr unsigned StructureFlags = Base::StructureFlags | HasStaticPropertyTable; + + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSNodeHTTPServerSocketPrototype, Base); + return &vm.plainObjectSpace(); + } + +private: + JSNodeHTTPServerSocketPrototype(VM& vm, Structure* structure) + : Base(vm, structure) + { + } + + void finishCreation(VM& vm, JSGlobalObject* globalObject) + { + Base::finishCreation(vm); + ASSERT(inherits(info())); + } +}; + +class JSNodeHTTPServerSocket : public JSC::JSDestructibleObject { + using Base = JSC::JSDestructibleObject; + +public: + static JSNodeHTTPServerSocket* create(JSC::VM& vm, JSC::Structure* structure, us_socket_t* socket, bool is_ssl) + { + return new (JSC::allocateCell(vm)) JSNodeHTTPServerSocket(vm, structure, socket, is_ssl); + } + + static JSNodeHTTPServerSocket* create(JSC::VM& vm, Zig::GlobalObject* globalObject, us_socket_t* socket, bool is_ssl) + { + auto* structure = globalObject->m_JSNodeHTTPServerSocketStructure.getInitializedOnMainThread(globalObject); + return create(vm, structure, socket, is_ssl); + } + + static void destroy(JSC::JSCell* cell) + { + static_cast(cell)->JSNodeHTTPServerSocket::~JSNodeHTTPServerSocket(); + } + + template + static void clearSocketData(us_socket_t* socket) + { + auto* httpResponseData = (uWS::HttpResponseData*)us_socket_ext(SSL, socket); + if (httpResponseData->socketData) { + httpResponseData->socketData = nullptr; + } + } + + ~JSNodeHTTPServerSocket() + { + if (socket) { + if (is_ssl) { + clearSocketData(socket); + } else { + clearSocketData(socket); + } + } + } + + JSNodeHTTPServerSocket(JSC::VM& vm, JSC::Structure* structure, us_socket_t* socket, bool is_ssl) + : JSC::JSDestructibleObject(vm, structure) + , socket(socket) + , is_ssl(is_ssl) + { + } + + mutable WriteBarrier functionToCallOnClose; + mutable WriteBarrier currentResponseObject; + unsigned is_ssl : 1; + us_socket_t* socket; + + DECLARE_INFO; + DECLARE_VISIT_CHILDREN; + + template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + if constexpr (mode == JSC::SubspaceAccess::Concurrently) + return nullptr; + + return WebCore::subspaceForImpl( + vm, + [](auto& spaces) { return spaces.m_clientSubspaceForJSNodeHTTPServerSocket.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForJSNodeHTTPServerSocket = std::forward(space); }, + [](auto& spaces) { return spaces.m_subspaceForJSNodeHTTPServerSocket.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForJSNodeHTTPServerSocket = std::forward(space); }); + } + + void onClose() + { + this->socket = nullptr; + } + + static JSC_HOST_CALL_ATTRIBUTES JSC::EncodedJSValue onClose(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame) + { + auto* thisObject = jsDynamicCast(callFrame->thisValue()); + if (!thisObject) { + return JSValue::encode(JSC::jsUndefined()); + } + + thisObject->onClose(); + return JSValue::encode(JSC::jsUndefined()); + } + + static Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject) + { + JSC::JSObject* prototype = JSC::constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure()); + prototype->structure()->setMayBePrototype(true); + + return JSC::Structure::create(vm, globalObject, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); + } +}; + BUN_DECLARE_HOST_FUNCTION(jsFunctionRequestOrResponseHasBodyValue); BUN_DECLARE_HOST_FUNCTION(jsFunctionGetCompleteRequestOrResponseBodyValueAsArrayBuffer); extern "C" uWS::HttpRequest* Request__getUWSRequest(void*); diff --git a/src/bun.js/bindings/NodeHTTP.h b/src/bun.js/bindings/NodeHTTP.h index e79a2b21d1..b682d826b2 100644 --- a/src/bun.js/bindings/NodeHTTP.h +++ b/src/bun.js/bindings/NodeHTTP.h @@ -1,11 +1,12 @@ #include "config.h" namespace Bun { - + JSC_DECLARE_HOST_FUNCTION(jsHTTPAssignHeaders); JSC_DECLARE_HOST_FUNCTION(jsHTTPGetHeader); JSC_DECLARE_HOST_FUNCTION(jsHTTPSetHeader); +JSC::Structure* createNodeHTTPServerSocketStructure(JSC::VM& vm); JSC::JSValue createNodeHTTPInternalBinding(Zig::GlobalObject*); -} \ No newline at end of file +} diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index f8466406ea..2039774239 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -2687,7 +2687,10 @@ void GlobalObject::finishCreation(VM& vm) m_commonStrings.initialize(); Bun::addNodeModuleConstructorProperties(vm, this); - + m_JSNodeHTTPServerSocketStructure.initLater( + [](const Initializer& init) { + init.set(Bun::createNodeHTTPServerSocketStructure(init.vm)); + }); m_JSDOMFileConstructor.initLater( [](const Initializer& init) { JSObject* fileConstructor = Bun::createJSDOMFileConstructor(init.vm, init.owner); @@ -3632,6 +3635,7 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) thisObject->m_JSBufferClassStructure.visit(visitor); thisObject->m_JSBufferListClassStructure.visit(visitor); thisObject->m_JSBufferSubclassStructure.visit(visitor); + thisObject->m_JSNodeHTTPServerSocketStructure.visit(visitor); thisObject->m_JSCryptoKey.visit(visitor); thisObject->m_JSDOMFileConstructor.visit(visitor); thisObject->m_JSFFIFunctionStructure.visit(visitor); diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index b80d29315b..3ad3b852aa 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -587,6 +587,8 @@ public: LazyProperty m_performanceObject; LazyProperty m_processObject; + LazyProperty m_JSNodeHTTPServerSocketStructure; + bool hasOverridenModuleResolveFilenameFunction = false; private: diff --git a/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h b/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h index 3ba6b4c6e2..d4f177c1cc 100644 --- a/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h +++ b/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h @@ -56,6 +56,7 @@ public: std::unique_ptr m_clientSubspaceForHandleScopeBuffer; std::unique_ptr m_clientSubspaceForFunctionTemplate; std::unique_ptr m_clientSubspaceForV8Function; + std::unique_ptr m_clientSubspaceForJSNodeHTTPServerSocket; #include "ZigGeneratedClasses+DOMClientIsoSubspaces.h" /* --- bun --- */ diff --git a/src/bun.js/bindings/webcore/DOMIsoSubspaces.h b/src/bun.js/bindings/webcore/DOMIsoSubspaces.h index e86f18bfd5..cee6e4a3fc 100644 --- a/src/bun.js/bindings/webcore/DOMIsoSubspaces.h +++ b/src/bun.js/bindings/webcore/DOMIsoSubspaces.h @@ -56,6 +56,7 @@ public: std::unique_ptr m_subspaceForHandleScopeBuffer; std::unique_ptr m_subspaceForFunctionTemplate; std::unique_ptr m_subspaceForV8Function; + std::unique_ptr m_subspaceForJSNodeHTTPServerSocket; #include "ZigGeneratedClasses+DOMIsoSubspaces.h" /*-- BUN --*/ @@ -898,7 +899,7 @@ public: // std::unique_ptr m_subspaceForXPathNSResolver; // std::unique_ptr m_subspaceForXPathResult; // std::unique_ptr m_subspaceForXSLTProcessor; - + std::unique_ptr m_subspaceForBakeGlobalScope; std::unique_ptr m_subspaceForAbortController;