Skip to content

Commit

Permalink
feat(uWebSockets): Add persistedRequest to context extra and deprec…
Browse files Browse the repository at this point in the history
…ate uWS's stack allocated `request` (enisdenjo#196)

Co-authored-by: enisdenjo <badurinadenis@gmail.com>
  • Loading branch information
maxpain and enisdenjo authored Jun 3, 2021
1 parent 2933997 commit 736e6ed
Show file tree
Hide file tree
Showing 6 changed files with 202 additions and 12 deletions.
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

0 comments on commit 736e6ed

Please sign in to comment.