Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(uWebSockets): Add persistedRequest to context extra and deprecate uWS's stack allocated request #196

Merged
merged 5 commits into from
Jun 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions docs/interfaces/use_uwebsockets.extra.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,54 @@

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

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.
48 changes: 48 additions & 0 deletions docs/interfaces/use_uwebsockets.persistedrequest.md
Original file line number Diff line number Diff line change
@@ -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*
45 changes: 45 additions & 0 deletions docs/interfaces/use_uwebsockets.upgradedata.md
Original file line number Diff line number Diff line change
@@ -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.
2 changes: 2 additions & 0 deletions docs/modules/use_uwebsockets.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
### Interfaces

- [Extra](../interfaces/use_uwebsockets.extra.md)
- [PersistedRequest](../interfaces/use_uwebsockets.persistedrequest.md)
- [UpgradeData](../interfaces/use_uwebsockets.upgradedata.md)

### Functions

Expand Down
14 changes: 13 additions & 1 deletion src/tests/use.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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<MessageType.ConnectionInit>({
type: MessageType.ConnectionInit,
Expand Down
73 changes: 64 additions & 9 deletions src/use/uWebSockets.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,62 @@
import type * as uWS from 'uWebSockets.js';
import type http from 'http';
import { makeServer, ServerOptions } from '../server';

/**
* The extra that will be put in the `Context`.
*
* @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 {
Expand Down Expand Up @@ -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<UpgradeData>(
{
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'),
Expand All @@ -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 = {
Expand All @@ -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;
Expand All @@ -115,7 +169,8 @@ export function makeBehavior<
},
onMessage: (cb) => (client.handleMessage = cb),
},
{ socket, request } as Extra & Partial<E>,
{ socket, request: socket.request, persistedRequest } as Extra &
Partial<E>,
);

if (keepAlive > 0 && isFinite(keepAlive)) {
Expand Down