Migrate from socket.io
Reviewed By: passy Differential Revision: D34787674 fbshipit-source-id: 63d7c166ea29d14c96f0646a045e3f6fa93472e2
This commit is contained in:
committed by
Facebook GitHub Bot
parent
6ec3771824
commit
f85def32fb
@@ -11,8 +11,9 @@ import express, {Express} from 'express';
|
||||
import http from 'http';
|
||||
import path from 'path';
|
||||
import fs from 'fs-extra';
|
||||
import socketio from 'socket.io';
|
||||
import {VerifyClientCallbackSync, WebSocketServer} from 'ws';
|
||||
import {WEBSOCKET_MAX_MESSAGE_SIZE} from 'flipper-server-core';
|
||||
import {parse} from 'url';
|
||||
|
||||
type Config = {
|
||||
port: number;
|
||||
@@ -23,7 +24,7 @@ type Config = {
|
||||
export async function startBaseServer(config: Config): Promise<{
|
||||
app: Express;
|
||||
server: http.Server;
|
||||
socket: socketio.Server;
|
||||
socket: WebSocketServer;
|
||||
}> {
|
||||
const {app, server} = await startAssetServer(config);
|
||||
const socket = addWebsocket(server, config);
|
||||
@@ -67,36 +68,60 @@ function addWebsocket(server: http.Server, config: Config) {
|
||||
const localhostIPV6NoBrackets = `::1:${config.port}`;
|
||||
|
||||
const possibleHosts = [localhostIPV4, localhostIPV6, localhostIPV6NoBrackets];
|
||||
const possibleOrigins = possibleHosts.map((host) => `http://${host}`);
|
||||
|
||||
const io = new socketio.Server(server, {
|
||||
maxHttpBufferSize: WEBSOCKET_MAX_MESSAGE_SIZE,
|
||||
allowRequest(req, callback) {
|
||||
const noOriginHeader = req.headers.origin === undefined;
|
||||
if (
|
||||
noOriginHeader &&
|
||||
req.headers.host &&
|
||||
possibleHosts.includes(req.headers.host)
|
||||
) {
|
||||
// no origin header? Either the request is not cross-origin,
|
||||
// or the request is not originating from a browser, so should be OK to pass through
|
||||
callback(null, true);
|
||||
} else {
|
||||
// for now we don't allow cross origin request, so that an arbitrary website cannot try to
|
||||
// connect a socket to localhost:serverport, and try to use the all powerful Flipper APIs to read
|
||||
// for example files.
|
||||
// Potentially in the future we do want to allow this, e.g. if we want to connect to a local flipper-server
|
||||
// directly from intern. But before that, we should either authenticate the request somehow,
|
||||
// and discuss security impact and for example scope the files that can be read by Flipper.
|
||||
console.warn(
|
||||
`Refused sockect connection from cross domain request, origin: ${
|
||||
req.headers.origin
|
||||
}, host: ${req.headers.host}. Expected: ${possibleHosts.join(
|
||||
' or ',
|
||||
)}`,
|
||||
);
|
||||
callback(null, false);
|
||||
}
|
||||
},
|
||||
const verifyClient: VerifyClientCallbackSync = ({origin, req}) => {
|
||||
const noOriginHeader = origin === undefined;
|
||||
if (
|
||||
(noOriginHeader || possibleOrigins.includes(origin)) &&
|
||||
req.headers.host &&
|
||||
possibleHosts.includes(req.headers.host)
|
||||
) {
|
||||
// no origin header? The request is not originating from a browser, so should be OK to pass through
|
||||
// If origin matches our own address, it means we are serving the page
|
||||
return true;
|
||||
} else {
|
||||
// for now we don't allow cross origin request, so that an arbitrary website cannot try to
|
||||
// connect a socket to localhost:serverport, and try to use the all powerful Flipper APIs to read
|
||||
// for example files.
|
||||
// Potentially in the future we do want to allow this, e.g. if we want to connect to a local flipper-server
|
||||
// directly from intern. But before that, we should either authenticate the request somehow,
|
||||
// and discuss security impact and for example scope the files that can be read by Flipper.
|
||||
console.warn(
|
||||
`Refused socket connection from cross domain request, origin: ${origin}, host: ${
|
||||
req.headers.host
|
||||
}. Expected origins: ${possibleOrigins.join(
|
||||
' or ',
|
||||
)}. Expected hosts: ${possibleHosts.join(' or ')}`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const wss = new WebSocketServer({
|
||||
noServer: true,
|
||||
maxPayload: WEBSOCKET_MAX_MESSAGE_SIZE,
|
||||
verifyClient,
|
||||
});
|
||||
return io;
|
||||
|
||||
server.on('upgrade', function upgrade(request, socket, head) {
|
||||
const {pathname} = parse(request.url);
|
||||
|
||||
// Handled by Metro
|
||||
if (pathname === '/hot') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pathname === '/') {
|
||||
wss.handleUpgrade(request, socket, head, function done(ws) {
|
||||
wss.emit('connection', ws, request);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
console.error('addWebsocket.upgrade -> unknown pathname', pathname);
|
||||
socket.destroy();
|
||||
});
|
||||
|
||||
return wss;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user