From 71025c8bcc68929cea2260d92de03e20a3c898d2 Mon Sep 17 00:00:00 2001 From: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> Date: Fri, 17 Jun 2022 20:29:56 -0700 Subject: Fix most of the errors --- .../jsc/bindings/ScriptExecutionContext.cpp | 30 +++--- .../jsc/bindings/ScriptExecutionContext.h | 10 +- src/javascript/jsc/bindings/webcore/WebSocket.cpp | 119 +++++++++------------ src/javascript/jsc/bindings/webcore/WebSocket.h | 20 ++-- .../jsc/bindings/webcore/WebSocketStream.cpp | 29 ++--- .../jsc/bindings/webcore/WebSocketStream.h | 28 +++-- 6 files changed, 117 insertions(+), 119 deletions(-) (limited to 'src/javascript/jsc') diff --git a/src/javascript/jsc/bindings/ScriptExecutionContext.cpp b/src/javascript/jsc/bindings/ScriptExecutionContext.cpp index 4a3b07132..17bc266dc 100644 --- a/src/javascript/jsc/bindings/ScriptExecutionContext.cpp +++ b/src/javascript/jsc/bindings/ScriptExecutionContext.cpp @@ -1,23 +1,24 @@ #include "ScriptExecutionContext.h" -#include -#include +#include +#include "WebSocketStream.h" extern "C" void Bun__startLoop(us_loop_t* loop); namespace WebCore { template -us_socket_context_t* webSocketContext() +us_socket_context_t* ScriptExecutionContext::webSocketContext() { if constexpr (isSSL) { if (!m_ssl_client_websockets_ctx) { us_loop_t* loop = (us_loop_t*)uWS::Loop::get(); us_socket_context_options_t opts; - memset(&opts, 0, sizeof(us_socket_context_t)); - this->m_ssl_client_websockets_ctx = us_create_socket_context(1, loop, sizeof(*ScriptExecutionContext), opts); - *us_socket_context_ext(m_ssl_client_websockets_ctx) = this; - WebSocketStream::registerHTTPContext(this, m_ssl_client_websockets_ctx, loop); + memset(&opts, 0, sizeof(us_socket_context_options_t)); + this->m_ssl_client_websockets_ctx = us_create_socket_context(1, loop, sizeof(size_t), opts); + void** ptr = reinterpret_cast(us_socket_context_ext(1, m_ssl_client_websockets_ctx)); + *ptr = this; + registerHTTPContextForWebSocket(this, m_ssl_client_websockets_ctx); } return m_ssl_client_websockets_ctx; @@ -25,10 +26,11 @@ us_socket_context_t* webSocketContext() if (!m_client_websockets_ctx) { us_loop_t* loop = (us_loop_t*)uWS::Loop::get(); us_socket_context_options_t opts; - memset(&opts, 0, sizeof(us_socket_context_t)); - this->m_client_websockets_ctx = us_create_socket_context(0, loop, sizeof(*ScriptExecutionContext), opts); - *us_socket_context_ext(m_client_websockets_ctx) = this; - SecureWebSocketStream::registerHTTPContext(this, m_client_websockets_ctx, loop); + memset(&opts, 0, sizeof(us_socket_context_options_t)); + this->m_client_websockets_ctx = us_create_socket_context(0, loop, sizeof(size_t), opts); + void** ptr = reinterpret_cast(us_socket_context_ext(0, m_client_websockets_ctx)); + *ptr = this; + registerHTTPContextForWebSocket(this, m_client_websockets_ctx); } return m_client_websockets_ctx; @@ -36,13 +38,13 @@ us_socket_context_t* webSocketContext() } template -uWS::WebSocketContext* +uWS::WebSocketContext* ScriptExecutionContext::connnectedWebSocketContext() { if constexpr (isSSL) { if (!m_connected_ssl_client_websockets_ctx) { // should be the parent RELEASE_ASSERT(m_ssl_client_websockets_ctx); - m_connected_client_websockets_ctx = SecureWebSocketStream::registerClientContext(this, webSocketContext(), loop); + m_connected_client_websockets_ctx = registerWebSocketClientContext(this, webSocketContext()); } return m_connected_ssl_client_websockets_ctx; @@ -50,7 +52,7 @@ uWS::WebSocketContext* if (!m_connected_client_websockets_ctx) { // should be the parent RELEASE_ASSERT(m_client_websockets_ctx); - m_connected_client_websockets_ctx = WebSocketStream::registerClientContext(this, webSocketContext(), loop); + m_connected_client_websockets_ctx = registerWebSocketClientContext(this, webSocketContext()); } return m_connected_client_websockets_ctx; diff --git a/src/javascript/jsc/bindings/ScriptExecutionContext.h b/src/javascript/jsc/bindings/ScriptExecutionContext.h index 8f4e2edfd..f966cf5f6 100644 --- a/src/javascript/jsc/bindings/ScriptExecutionContext.h +++ b/src/javascript/jsc/bindings/ScriptExecutionContext.h @@ -10,7 +10,11 @@ #include #include "CachedScript.h" #include "wtf/URL.h" -#include + +namespace uWS { +template +struct WebSocketContext; +} struct us_socket_t; struct us_socket_context_t; @@ -106,7 +110,7 @@ private: us_socket_context_t* m_ssl_client_websockets_ctx = nullptr; us_socket_context_t* m_client_websockets_ctx = nullptr; - uWS::WebSocketContext* m_ssl_client_websockets_ctx = nullptr; - uWS::WebSocketContext* m_client_websockets_ctx = nullptr; + uWS::WebSocketContext* m_connected_ssl_client_websockets_ctx = nullptr; + uWS::WebSocketContext* m_connected_client_websockets_ctx = nullptr; }; } \ No newline at end of file diff --git a/src/javascript/jsc/bindings/webcore/WebSocket.cpp b/src/javascript/jsc/bindings/webcore/WebSocket.cpp index 3e82af805..dff4500be 100644 --- a/src/javascript/jsc/bindings/webcore/WebSocket.cpp +++ b/src/javascript/jsc/bindings/webcore/WebSocket.cpp @@ -69,6 +69,8 @@ #include #include +#include + // #if USE(WEB_THREAD) // #include "WebCoreThreadRun.h" // #endif @@ -78,6 +80,20 @@ using ThreadableWebSocketChannel = WebSocketStream; using WebSocketChannelClient = WebSocketStream; WTF_MAKE_ISO_ALLOCATED_IMPL(WebSocket); +static size_t getFramingOverhead(size_t payloadSize) +{ + static const size_t hybiBaseFramingOverhead = 2; // Every frame has at least two-byte header. + static const size_t hybiMaskingKeyLength = 4; // Every frame from client must have masking key. + static const size_t minimumPayloadSizeWithTwoByteExtendedPayloadLength = 126; + static const size_t minimumPayloadSizeWithEightByteExtendedPayloadLength = 0x10000; + size_t overhead = hybiBaseFramingOverhead + hybiMaskingKeyLength; + if (payloadSize >= minimumPayloadSizeWithEightByteExtendedPayloadLength) + overhead += 8; + else if (payloadSize >= minimumPayloadSizeWithTwoByteExtendedPayloadLength) + overhead += 2; + return overhead; +} + const size_t maxReasonSizeInBytes = 123; static inline bool isValidProtocolCharacter(UChar character) @@ -145,8 +161,6 @@ WebSocket::WebSocket(ScriptExecutionContext& context) : ContextDestructionObserver(&context) , m_subprotocol(emptyString()) , m_extensions(emptyString()) - , m_handshake(url, ) - { } @@ -164,19 +178,19 @@ WebSocket::~WebSocket() switch (m_connectedWebSocketKind) { case ConnectedWebSocketKind::Client: { - this->m_connectedWebSocket.client->end(code); + this->m_connectedWebSocket.client->end(None); break; } case ConnectedWebSocketKind::ClientSSL: { - this->m_connectedWebSocket.clientSSL->end(code); + this->m_connectedWebSocket.clientSSL->end(None); break; } case ConnectedWebSocketKind::Server: { - this->m_connectedWebSocket.server->end(code); + this->m_connectedWebSocket.server->end(None); break; } case ConnectedWebSocketKind::ServerSSL: { - this->m_connectedWebSocket.serverSSL->end(code); + this->m_connectedWebSocket.serverSSL->end(None); break; } default: { @@ -195,10 +209,10 @@ ExceptionOr> WebSocket::create(ScriptExecutionContext& context, c if (url.isNull()) return Exception { SyntaxError }; - auto socket = adoptRef(*new WebSocket(context, url)); + auto socket = adoptRef(*new WebSocket(context)); // socket->suspendIfNeeded(); - auto result = socket->connect(url.string(), protocols); + auto result = socket->connect(url, protocols); // auto result = socket->connect(url, protocols); if (result.hasException()) @@ -351,16 +365,20 @@ ExceptionOr WebSocket::connect(const String& url, const Vector& pr auto resource = resourceName(m_url); ZigString path = Zig::toZigString(resource); ZigString clientProtocolString = Zig::toZigString(protocolString); - uint16_t port = m_url.port(); + uint16_t port = is_secure ? 443 : 80; + if (auto userPort = m_url.port()) { + port = userPort.value(); + } + m_isSecure = is_secure; if (is_secure) { - us_socket_context_t* ctx = scriptExecutionContext->webSocketContext(); + us_socket_context_t* ctx = scriptExecutionContext()->webSocketContext(); RELEASE_ASSERT(ctx); - this->m_upgradeClient = Bun_SecureWebSocketUpgradeClient__connect(scriptExecutionContext->jsGlobalObject(), ctx, this, &host, port, &path, &clientProtocolString); + this->m_upgradeClient = Bun_SecureWebSocketUpgradeClient__connect(scriptExecutionContext()->jsGlobalObject(), ctx, this, &host, port, &path, &clientProtocolString); } else { - us_socket_context_t* ctx = scriptExecutionContext->webSocketContext(); + us_socket_context_t* ctx = scriptExecutionContext()->webSocketContext(); RELEASE_ASSERT(ctx); - this->m_upgradeClient = Bun_WebSocketUpgradeClient__connect(scriptExecutionContext->jsGlobalObject(), ctx, this, &host, port, &path, &clientProtocolString); + this->m_upgradeClient = Bun_WebSocketUpgradeClient__connect(scriptExecutionContext()->jsGlobalObject(), ctx, this, &host, port, &path, &clientProtocolString); } if (this->m_upgradeClient == nullptr) { @@ -439,8 +457,8 @@ ExceptionOr WebSocket::send(ArrayBufferView& arrayBufferView) } ASSERT(m_channel); - auto buffer = arrayBufferView.unsharedBuffer(); - char* baseAddress = reinterpret_cast(buffer.baseAddress()) + arrayBufferView.byteOffset(); + auto buffer = arrayBufferView.unsharedBuffer().get(); + char* baseAddress = reinterpret_cast(buffer->data()) + arrayBufferView.byteOffset(); size_t length = arrayBufferView.byteLength(); if (length > 0) this->sendWebSocketData(baseAddress, length); @@ -468,10 +486,10 @@ ExceptionOr WebSocket::send(ArrayBufferView& arrayBufferView) template void WebSocket::sendWebSocketData(const char* baseAddress, size_t length) { - uWS::OpCode opCode = uWS::OpCode::Text; + uWS::OpCode opCode = uWS::OpCode::TEXT; if constexpr (isBinary) - opCode = uWS::OpCode::Binary; + opCode = uWS::OpCode::BINARY; switch (m_connectedWebSocketKind) { case ConnectedWebSocketKind::Client: { @@ -732,26 +750,7 @@ void WebSocket::didReceiveBinaryData(Vector&& binaryData) // }); } -void WebSocket::didReceiveMessageError(String&& reason) -{ - LOG(Network, "WebSocket %p didReceiveErrorMessage()", this); - // queueTaskKeepingObjectAlive(*this, TaskSource::WebSocket, [this, reason = WTFMove(reason)] { - if (m_state == CLOSED) - return; - m_state = CLOSED; - ASSERT(scriptExecutionContext()); - - // if (UNLIKELY(InspectorInstrumentation::hasFrontends())) { - // if (auto* inspector = m_channel->channelInspector()) - // inspector->didReceiveWebSocketFrameError(reason); - // } - - // FIXME: As per https://html.spec.whatwg.org/multipage/web-sockets.html#feedback-from-the-protocol:concept-websocket-closed, we should synchronously fire a close event. - dispatchErrorEventIfNeeded(); - // }); -} - -void WebSocket::didReceiveMessageError(String& reason) +void WebSocket::didReceiveMessageError(WTF::StringImpl::StaticStringImpl* reason) { LOG(Network, "WebSocket %p didReceiveErrorMessage()", this); // queueTaskKeepingObjectAlive(*this, TaskSource::WebSocket, [this, reason = WTFMove(reason)] { @@ -766,7 +765,7 @@ void WebSocket::didReceiveMessageError(String& reason) // } // FIXME: As per https://html.spec.whatwg.org/multipage/web-sockets.html#feedback-from-the-protocol:concept-websocket-closed, we should synchronously fire a close event. - dispatchEvent(CloseEvent::create(false, 0, reason)); + dispatchEvent(CloseEvent::create(false, 0, WTF::String(reason))); // }); } @@ -819,25 +818,11 @@ void WebSocket::didClose(unsigned unhandledBufferedAmount, ClosingHandshakeCompl // }); } -void WebSocket::didUpgradeURL() -{ - ASSERT(m_url.protocolIs("ws")); - m_url.setProtocol("wss"); -} - -size_t WebSocket::getFramingOverhead(size_t payloadSize) -{ - static const size_t hybiBaseFramingOverhead = 2; // Every frame has at least two-byte header. - static const size_t hybiMaskingKeyLength = 4; // Every frame from client must have masking key. - static const size_t minimumPayloadSizeWithTwoByteExtendedPayloadLength = 126; - static const size_t minimumPayloadSizeWithEightByteExtendedPayloadLength = 0x10000; - size_t overhead = hybiBaseFramingOverhead + hybiMaskingKeyLength; - if (payloadSize >= minimumPayloadSizeWithEightByteExtendedPayloadLength) - overhead += 8; - else if (payloadSize >= minimumPayloadSizeWithTwoByteExtendedPayloadLength) - overhead += 2; - return overhead; -} +// void WebSocket::didUpgradeURL() +// { +// ASSERT(m_url.protocolIs("ws")); +// m_url.setProtocol("wss"); +// } void WebSocket::dispatchErrorEventIfNeeded() { @@ -850,24 +835,24 @@ void WebSocket::dispatchErrorEventIfNeeded() void WebSocket::didConnect(us_socket_t* socket, char* bufferedData, size_t bufferedDataSize) { - m_state = CONNECTED; + m_state = OPEN; this->m_upgradeClient = nullptr; if (m_isSecure) { /* Adopting a socket invalidates it, do not rely on it directly to carry any data */ uWS::WebSocket* webSocket = (uWS::WebSocket*)us_socket_context_adopt_socket(1, - (us_socket_context_t*)this->scriptExecutionContext()->connnectedWebSocketContext(), socket, sizeof(uWS::WebSocketData) + sizeof(WebSocket*)); + (us_socket_context_t*)this->scriptExecutionContext()->connnectedWebSocketContext(), socket, sizeof(uWS::WebSocketData) + sizeof(WebSocket*)); - webSocket->init(0, uWS::CompressOptions::disabled, uWS::Backpressure()); - *webSocket->getExt() = this; + webSocket->init(0, uWS::CompressOptions::DISABLED, uWS::BackPressure()); + *webSocket->getUserData() = this; this->m_connectedWebSocket.clientSSL = webSocket; this->m_connectedWebSocketKind = ConnectedWebSocketKind::ClientSSL; } else { /* Adopting a socket invalidates it, do not rely on it directly to carry any data */ uWS::WebSocket* webSocket = (uWS::WebSocket*)us_socket_context_adopt_socket(1, - (us_socket_context_t*)this->scriptExecutionContext()->connnectedWebSocketContext(), socket, sizeof(uWS::WebSocketData) + sizeof(WebSocket*)); + (us_socket_context_t*)this->scriptExecutionContext()->connnectedWebSocketContext(), socket, sizeof(uWS::WebSocketData) + sizeof(WebSocket*)); - webSocket->init(0, uWS::CompressOptions::disabled, uWS::Backpressure()); - *webSocket->getExt() = this; + webSocket->init(0, uWS::CompressOptions::DISABLED, uWS::BackPressure()); + *webSocket->getUserData() = this; this->m_connectedWebSocket.client = webSocket; this->m_connectedWebSocketKind = ConnectedWebSocketKind::Client; } @@ -996,11 +981,11 @@ void WebSocket::didFailToConnect(int32_t code) } } // namespace WebCore -extern "C" WebSocket__didConnect(WebCore::WebSocket* webSocket, us_socket_t* socket, char* bufferedData, size_t len) +extern "C" void WebSocket__didConnect(WebCore::WebSocket* webSocket, us_socket_t* socket, char* bufferedData, size_t len) { webSocket->didConnect(socket, bufferedData, len); } -extern "C" WebSocket__didFailToConnect(WebCore::WebSocket* webSocket, int32_t errorCode) +extern "C" void WebSocket__didFailToConnect(WebCore::WebSocket* webSocket, int32_t errorCode) { - webSocket->didFailToConnect(socket, errorCode); + webSocket->didFailToConnect(errorCode); } \ No newline at end of file diff --git a/src/javascript/jsc/bindings/webcore/WebSocket.h b/src/javascript/jsc/bindings/webcore/WebSocket.h index 73a6d8ca0..b75bc346c 100644 --- a/src/javascript/jsc/bindings/webcore/WebSocket.h +++ b/src/javascript/jsc/bindings/webcore/WebSocket.h @@ -70,7 +70,8 @@ public: CONNECTING = 0, OPEN = 1, CLOSING = 2, - CLOSED = 3 + CLOSED = 3, + }; ExceptionOr connect(const String& url); @@ -100,12 +101,16 @@ public: using RefCounted::deref; using RefCounted::ref; + void didConnect(); + void didClose(unsigned unhandledBufferedAmount, ClosingHandshakeCompletionStatus, unsigned short code, const String& reason); + void didConnect(us_socket_t* socket, char* bufferedData, size_t bufferedDataSize); + void didFailToConnect(int32_t code); private: typedef union AnyWebSocket { uWS::WebSocket* client; - uWS::WebSocket* clientSSL; - uWS::WebSocket* server; + uWS::WebSocket* clientSSL; + uWS::WebSocket* server; uWS::WebSocket* serverSSL; } AnyWebSocket; enum ConnectedWebSocketKind { @@ -117,6 +122,7 @@ private: }; explicit WebSocket(ScriptExecutionContext&); + explicit WebSocket(ScriptExecutionContext&, const String& url); void dispatchErrorEventIfNeeded(); @@ -131,16 +137,14 @@ private: void refEventTarget() final { ref(); } void derefEventTarget() final { deref(); } - void didConnect(); void didReceiveMessage(String&& message); void didReceiveData(const char* data, size_t length); void didReceiveBinaryData(Vector&&); - void didReceiveMessageError(String&& reason); + void didReceiveMessageError(WTF::StringImpl::StaticStringImpl* reason); void didUpdateBufferedAmount(unsigned bufferedAmount); void didStartClosingHandshake(); - void didClose(unsigned unhandledBufferedAmount, ClosingHandshakeCompletionStatus, unsigned short code, const String& reason); - void didConnect(us_socket_t* socket, char* bufferedData, size_t bufferedDataSize); - void didFailToConnect(int32_t code); + + template void sendWebSocketData(const char* data, size_t length); void failAsynchronously(); diff --git a/src/javascript/jsc/bindings/webcore/WebSocketStream.cpp b/src/javascript/jsc/bindings/webcore/WebSocketStream.cpp index 8e059edae..9aa480bbe 100644 --- a/src/javascript/jsc/bindings/webcore/WebSocketStream.cpp +++ b/src/javascript/jsc/bindings/webcore/WebSocketStream.cpp @@ -1,27 +1,14 @@ +#include "root.h" + #include "WebSocketStream.h" +#include "ScriptExecutionContext.h" +#include #include namespace WebCore { template -WebSocketStreamBase* WebSocketStreamBase::adoptSocket(us_socket_t* socket, ScriptExecutionContext* scriptCtx) -{ - using UserData = WebCore::WebSocket; - - /* Adopting a socket invalidates it, do not rely on it directly to carry any data */ - uWS::WebSocket* webSocket = (uWS::WebSocket*)us_socket_context_adopt_socket(SSL, - (us_socket_context_t*)webSocketContext, (us_socket_t*)this, sizeof(WebSocketData) + sizeof(UserData)); - - /* For whatever reason we were corked, update cork to the new socket */ - if (wasCorked) { - webSocket->AsyncSocket::corkUnchecked(); - } - - /* Initialize websocket with any moved backpressure intact */ - webSocket->init(perMessageDeflate, compressOptions, std::move(backpressure)); -} - -void WebSocketStreamBase::registerHTTPContext(ScriptExecutionContext* script, us_socket_context_t* ctx, us_loop_t* loop) +void registerHTTPContextForWebSocket(ScriptExecutionContext* script, us_socket_context_t* ctx, us_loop_t* loop) { if constexpr (!isServer) { if constexpr (SSL) { @@ -35,11 +22,13 @@ void WebSocketStreamBase::registerHTTPContext(ScriptExecutionContext* script, us } template -uWS::WebSocketContext* WebSocketStreamBase::registerClientContext(ScriptExecutionContext*, us_socket_context_t* parent) +uWS::WebSocketContext* registerWebSocketClientContext(ScriptExecutionContext* script, us_socket_context_t* parent) { uWS::Loop* loop = uWS::Loop::get(); - uWS::WebSocketContext* ctx = uWS::WebSocketContext::create(loop, parent, nullptr); + uWS::WebSocketContext* ctx = uWS::WebSocketContext::create(loop, parent, nullptr); auto* opts = ctx->getExt(); + ScriptExecutionContext** scriptCtx = ctx->getUserData(); + *scriptCtx = script; /* Maximum message size we can receive */ static unsigned int maxPayloadLength = 128 * 1024 * 1024; diff --git a/src/javascript/jsc/bindings/webcore/WebSocketStream.h b/src/javascript/jsc/bindings/webcore/WebSocketStream.h index a80c94a85..b6a2595a3 100644 --- a/src/javascript/jsc/bindings/webcore/WebSocketStream.h +++ b/src/javascript/jsc/bindings/webcore/WebSocketStream.h @@ -36,7 +36,14 @@ #include "wtf/URL.h" #include "wtf/Vector.h" #include "wtf/Function.h" -#include + +namespace uWS { +template +class WebSocket; + +template +class WebSocketContext; +} struct us_socket_context_t; struct us_socket_t; @@ -44,18 +51,23 @@ struct us_loop_t; namespace WebCore { +class ScriptExecutionContext; + enum ClosingHandshakeCompletionStatus { ClosingHandshakeIncomplete, ClosingHandshakeComplete }; +class WebSocket; + // This class expects the stream to already be connected & ready to go template class WebSocketStreamBase final { public: - using WebSocketImpl = uWS::WebSocket; + using WebSocketStreamPtr = WebCore::WebSocket*; + using WebSocketImpl = uWS::WebSocket; using WebSocketStreamImpl = WebSocketStreamBase; - using WebSocketContext = uWS::WebSocketContext; + using WebSocketContext = uWS::WebSocketContext; ~WebSocketStreamBase(); void didConnect(); @@ -65,10 +77,6 @@ public: void didUpdateBufferedAmount(unsigned bufferedAmount); void didStartClosingHandshake(); - static WebSocketStreamImpl* adoptSocket(us_socket_t* socket, ScriptExecutionContext* scriptCtx); - static void registerHTTPContext(ScriptExecutionContext*, us_socket_context_t*); - - static WebSocketContext* registerClientContext(ScriptExecutionContext*, us_socket_context_t* parent); void sendData(const uint8_t* data, size_t length, Function); void close(); // Disconnect after all data in buffer are sent. void disconnect(); @@ -103,6 +111,12 @@ public: } }; +template +void registerHTTPContextForWebSocket(ScriptExecutionContext*, us_socket_context_t*); + +template +uWS::WebSocketContext* registerWebSocketClientContext(ScriptExecutionContext*, us_socket_context_t* parent); + using WebSocketStream = WebSocketStreamBase; using SecureWebSocketStream = WebSocketStreamBase; using ServerWebSocketStream = WebSocketStreamBase; -- cgit v1.2.3