BootProbes: add a websocket probe

This self-test isn't perfect because we're running it from the backend
instead of the frontend. Conceivably the backend might have trouble
resolving its own url. Eventually we should move this test or
something like it to something that executes in the frontend.
Jordi Gutiérrez Hermoso 2 weeks ago
parent 89fb9c3fa0
commit 0c9bed9de5

@ -169,6 +169,16 @@ It is good practice not to run Grist as the root user.
'reachable': {
info: `
The main page of Grist should be available.
`
},
'websockets': {
info: `
Websocket connections need HTTP 1.1 and the ability to pass a few
extra headers in order to work. Sometimes a reverse proxy can
interfere with these requirements. See <a
href="https://support.getgrist.com/self-managed/#how-do-i-run-grist-on-a-server">this
documentation</a> for more explanation.
`
},
};

@ -6,7 +6,8 @@ export type BootProbeIds =
'reachable' |
'host-header' |
'sandboxing' |
'system-user'
'system-user' |
'websockets'
;
export interface BootProbeResult {

@ -4,6 +4,7 @@ import { removeTrailingSlash } from 'app/common/gutil';
import { expressWrap, jsonErrorHandler } from 'app/server/lib/expressWrap';
import { GristServer } from 'app/server/lib/GristServer';
import * as express from 'express';
import WS from 'ws';
import fetch from 'node-fetch';
/**
@ -58,6 +59,7 @@ export class BootProbes {
this._probes.push(_bootProbe);
this._probes.push(_hostHeaderProbe);
this._probes.push(_sandboxingProbe);
this._probes.push(_webSocketsProbe);
this._probeById = new Map(this._probes.map(p => [p.id, p]));
}
}
@ -104,6 +106,37 @@ const _homeUrlReachableProbe: Probe = {
}
};
const _webSocketsProbe: Probe = {
id: 'websockets',
name: 'Can we open a websocket with the server',
apply: async (server, req) => {
return new Promise((resolve) => {
const url = new URL(server.getHomeUrl(req));
url.protocol = (url.protocol === 'https:') ? 'wss:' : 'ws:';
const ws = new WS.WebSocket(url.href);
const details: Record<string, any> = {
url,
};
ws.on('open', () => {
ws.send('Just nod if you can hear me.');
resolve({
success: true,
details,
});
ws.close();
});
ws.on('error', (ev) => {
details.error = ev.message;
resolve({
success: false,
details,
});
ws.close();
});
});
}
};
const _statusCheckProbe: Probe = {
id: 'health-check',
name: 'Is an internal health check passing',

Loading…
Cancel
Save