diff --git a/docs/interfaces/use_uwebsockets.extra.md b/docs/interfaces/use_uwebsockets.extra.md index 5cee25c1..8672aaa6 100644 --- a/docs/interfaces/use_uwebsockets.extra.md +++ b/docs/interfaces/use_uwebsockets.extra.md @@ -6,15 +6,38 @@ The extra that will be put in the `Context`. +## Hierarchy + +- [*UpgradeData*](use_uwebsockets.upgradedata.md) + + ↳ **Extra** + ## Table of contents ### Properties +- [persistedRequest](use_uwebsockets.extra.md#persistedrequest) - [request](use_uwebsockets.extra.md#request) - [socket](use_uwebsockets.extra.md#socket) ## Properties +### persistedRequest + +• `Readonly` **persistedRequest**: [*PersistedRequest*](use_uwebsockets.persistedrequest.md) + +The initial HTTP upgrade request before the actual +socket and connection is established. + +uWS's request is stack allocated and cannot be accessed +from outside of the internal upgrade; therefore, the persisted +request holds the relevant values extracted from the uWS's request +while it is accessible. + +Inherited from: [UpgradeData](use_uwebsockets.upgradedata.md).[persistedRequest](use_uwebsockets.upgradedata.md#persistedrequest) + +___ + ### request • `Readonly` **request**: HttpRequest @@ -22,10 +45,15 @@ The extra that will be put in the `Context`. The initial HTTP request before the actual socket and connection is established. +**`deprecated`** uWS.HttpRequest is stack allocated and cannot be accessed outside the internal `upgrade` callback. Consider using the `persistedRequest` instead. + +Inherited from: [UpgradeData](use_uwebsockets.upgradedata.md).[request](use_uwebsockets.upgradedata.md#request) + ___ ### socket -• `Readonly` **socket**: WebSocket +• `Readonly` **socket**: WebSocket & [*UpgradeData*](use_uwebsockets.upgradedata.md) -The actual socket connection between the server and the client. +The actual socket connection between the server and the client +with the upgrade data. diff --git a/docs/interfaces/use_uwebsockets.persistedrequest.md b/docs/interfaces/use_uwebsockets.persistedrequest.md new file mode 100644 index 00000000..6a896b3b --- /dev/null +++ b/docs/interfaces/use_uwebsockets.persistedrequest.md @@ -0,0 +1,48 @@ +[graphql-ws](../README.md) / [use/uWebSockets](../modules/use_uwebsockets.md) / PersistedRequest + +# Interface: PersistedRequest + +[use/uWebSockets](../modules/use_uwebsockets.md).PersistedRequest + +The initial HTTP upgrade request before the actual +socket and connection is established. + +uWS's request is stack allocated and cannot be accessed +from outside of the internal upgrade; therefore, the persisted +request holds relevant values extracted from the uWS's request +while it is accessible. + +## Table of contents + +### Properties + +- [headers](use_uwebsockets.persistedrequest.md#headers) +- [method](use_uwebsockets.persistedrequest.md#method) +- [query](use_uwebsockets.persistedrequest.md#query) +- [url](use_uwebsockets.persistedrequest.md#url) + +## Properties + +### headers + +• **headers**: *IncomingHttpHeaders* + +___ + +### method + +• **method**: *string* + +___ + +### query + +• **query**: *string* + +The raw query string (after the `?` sign) or empty string. + +___ + +### url + +• **url**: *string* diff --git a/docs/interfaces/use_uwebsockets.upgradedata.md b/docs/interfaces/use_uwebsockets.upgradedata.md new file mode 100644 index 00000000..e57c9032 --- /dev/null +++ b/docs/interfaces/use_uwebsockets.upgradedata.md @@ -0,0 +1,45 @@ +[graphql-ws](../README.md) / [use/uWebSockets](../modules/use_uwebsockets.md) / UpgradeData + +# Interface: UpgradeData + +[use/uWebSockets](../modules/use_uwebsockets.md).UpgradeData + +Data acquired during the HTTP upgrade callback from uWS. + +## Hierarchy + +- **UpgradeData** + + ↳ [*Extra*](use_uwebsockets.extra.md) + +## Table of contents + +### Properties + +- [persistedRequest](use_uwebsockets.upgradedata.md#persistedrequest) +- [request](use_uwebsockets.upgradedata.md#request) + +## Properties + +### persistedRequest + +• `Readonly` **persistedRequest**: [*PersistedRequest*](use_uwebsockets.persistedrequest.md) + +The initial HTTP upgrade request before the actual +socket and connection is established. + +uWS's request is stack allocated and cannot be accessed +from outside of the internal upgrade; therefore, the persisted +request holds the relevant values extracted from the uWS's request +while it is accessible. + +___ + +### request + +• `Readonly` **request**: HttpRequest + +The initial HTTP request before the actual +socket and connection is established. + +**`deprecated`** uWS.HttpRequest is stack allocated and cannot be accessed outside the internal `upgrade` callback. Consider using the `persistedRequest` instead. diff --git a/docs/modules/use_uwebsockets.md b/docs/modules/use_uwebsockets.md index a45bd96e..0e0ccc84 100644 --- a/docs/modules/use_uwebsockets.md +++ b/docs/modules/use_uwebsockets.md @@ -7,6 +7,8 @@ ### Interfaces - [Extra](../interfaces/use_uwebsockets.extra.md) +- [PersistedRequest](../interfaces/use_uwebsockets.persistedrequest.md) +- [UpgradeData](../interfaces/use_uwebsockets.upgradedata.md) ### Functions diff --git a/src/tests/use.ts b/src/tests/use.ts index 6ab76043..61874751 100644 --- a/src/tests/use.ts +++ b/src/tests/use.ts @@ -91,6 +91,18 @@ for (const { tServer, startTServer } of tServers) { expect((ctx.extra as UWSExtra).request.constructor.name).toEqual( 'uWS.HttpRequest', ); + expect((ctx.extra as UWSExtra).persistedRequest.method).toBe( + 'get', + ); + expect((ctx.extra as UWSExtra).persistedRequest.url).toBe( + '/simple', + ); + expect((ctx.extra as UWSExtra).persistedRequest.query).toBe( + 'te=st', + ); + expect( + (ctx.extra as UWSExtra).persistedRequest.headers, + ).toBeInstanceOf(Object); } else if (tServer === 'ws') { expect((ctx.extra as WSExtra).socket).toBeInstanceOf(ws); expect((ctx.extra as WSExtra).request).toBeInstanceOf( @@ -104,7 +116,7 @@ for (const { tServer, startTServer } of tServers) { }, }); - const client = await createTClient(server.url); + const client = await createTClient(server.url + '?te=st'); client.ws.send( stringifyMessage({ type: MessageType.ConnectionInit, diff --git a/src/use/uWebSockets.ts b/src/use/uWebSockets.ts index 54c67631..e6bad894 100644 --- a/src/use/uWebSockets.ts +++ b/src/use/uWebSockets.ts @@ -1,4 +1,5 @@ import type * as uWS from 'uWebSockets.js'; +import type http from 'http'; import { makeServer, ServerOptions } from '../server'; /** @@ -6,16 +7,56 @@ import { makeServer, ServerOptions } from '../server'; * * @category Server/uWebSockets */ -export interface Extra { +export interface Extra extends UpgradeData { /** - * The actual socket connection between the server and the client. + * The actual socket connection between the server and the client + * with the upgrade data. */ - readonly socket: uWS.WebSocket; + readonly socket: uWS.WebSocket & UpgradeData; +} + +/** + * Data acquired during the HTTP upgrade callback from uWS. + * + * @category Server/uWebSockets + */ +export interface UpgradeData { /** * The initial HTTP request before the actual * socket and connection is established. + * + * @deprecated uWS.HttpRequest is stack allocated and cannot be accessed outside the internal `upgrade` callback. Consider using the `persistedRequest` instead. */ readonly request: uWS.HttpRequest; + /** + * The initial HTTP upgrade request before the actual + * socket and connection is established. + * + * uWS's request is stack allocated and cannot be accessed + * from outside of the internal upgrade; therefore, the persisted + * request holds the relevant values extracted from the uWS's request + * while it is accessible. + */ + readonly persistedRequest: PersistedRequest; +} + +/** + * The initial HTTP upgrade request before the actual + * socket and connection is established. + * + * uWS's request is stack allocated and cannot be accessed + * from outside of the internal upgrade; therefore, the persisted + * request holds relevant values extracted from the uWS's request + * while it is accessible. + * + * @category Server/uWebSockets + */ +export interface PersistedRequest { + method: string; + url: string; + /** The raw query string (after the `?` sign) or empty string. */ + query: string; + headers: http.IncomingHttpHeaders; } interface Client { @@ -71,8 +112,21 @@ export function makeBehavior< behavior.upgrade?.(...args); const [res, req, context] = args; - res.upgrade( - { upgradeReq: req }, + const headers: http.IncomingHttpHeaders = {}; + req.forEach((key, value) => { + headers[key] = value; + }); + + res.upgrade( + { + request: req, + persistedRequest: { + method: req.getMethod(), + url: req.getUrl(), + query: req.getQuery(), + headers, + }, + }, req.getHeader('sec-websocket-key'), req.getHeader('sec-websocket-protocol'), req.getHeader('sec-websocket-extensions'), @@ -81,7 +135,8 @@ export function makeBehavior< }, open(...args) { behavior.open?.(...args); - const [socket] = args; + const socket = args[0] as uWS.WebSocket & UpgradeData; + const persistedRequest = socket.persistedRequest; // prepare client object const client: Client = { @@ -95,10 +150,9 @@ export function makeBehavior< }, }; - const request = socket.upgradeReq as uWS.HttpRequest; client.closed = server.opened( { - protocol: request.getHeader('sec-websocket-protocol'), + protocol: persistedRequest.headers['sec-websocket-protocol'] ?? '', send: async (message) => { // the socket might have been destroyed in the meantime if (!clients.has(socket)) return; @@ -115,7 +169,8 @@ export function makeBehavior< }, onMessage: (cb) => (client.handleMessage = cb), }, - { socket, request } as Extra & Partial, + { socket, request: socket.request, persistedRequest } as Extra & + Partial, ); if (keepAlive > 0 && isFinite(keepAlive)) {