WIP: http2 transport

This commit is contained in:
Micooz 2018-05-06 18:34:41 +08:00
parent be9dd7adcc
commit a706f42f7d
5 changed files with 63 additions and 15 deletions

@ -122,11 +122,13 @@ export class Config {
this.server_host = hostname;
this.server_port = +port;
// preload tls_cert or tls_key
if (this.transport === 'tls') {
logger.info(`[config] loading ${server.tls_cert}`);
this.tls_cert = loadFileSync(server.tls_cert);
if (this.is_server) {
// preload tls_cert and tls_key
if (this.transport === 'tls' || this.transport === 'h2') {
if (server.tls_cert) {
logger.info(`[config] loading ${server.tls_cert}`);
this.tls_cert = loadFileSync(server.tls_cert);
}
if (this.is_server && server.tls_key) {
logger.info(`[config] loading ${server.tls_key}`);
this.tls_key = loadFileSync(server.tls_key);
}
@ -336,14 +338,14 @@ export class Config {
const protocol = _protocol.slice(0, -1);
const available_server_protocols = [
'tcp', 'ws', 'tls'
'tcp', 'ws', 'tls', 'h2'
];
if (!available_server_protocols.includes(protocol)) {
throw Error(`service.protocol must be: ${available_server_protocols.join(', ')}`);
}
// tls_cert, tls_key
if (protocol === 'tls') {
if (protocol === 'tls' || protocol === 'h2') {
if (typeof server.tls_cert !== 'string' || server.tls_cert === '') {
throw Error('"tls_cert" must be provided');
}

@ -2,6 +2,7 @@ import _sodium from 'libsodium-wrappers';
import dgram from 'dgram';
import net from 'net';
import { URL } from 'url';
import http2 from 'http2';
import tls from 'tls';
import ws from 'ws';
import LRU from 'lru-cache';
@ -225,6 +226,12 @@ export class Hub {
server.listen(address, () => onListening(server));
break;
}
case 'h2': {
server = http2.createSecureServer({ key: tls_key, cert: tls_cert });
server.on('stream', (stream) => this._onConnection(stream));
server.listen(address, () => onListening(server));
break;
}
default:
return reject(Error(`unsupported protocol: "${local_protocol}"`));
}
@ -308,19 +315,16 @@ export class Hub {
this._upSpeedTester.feed(size);
};
_onConnection = (socket, proxyRequest = null) => {
logger.verbose(`[hub] [${socket.remoteAddress}:${socket.remotePort}] connected`);
_onConnection = (conn, proxyRequest = null) => {
const sourceAddress = this._getSourceAddress(conn);
const updateConnStatus = (event, extra) => this._updateConnStatus(event, sourceAddress, extra);
const sourceAddress = { host: socket.remoteAddress, port: socket.remotePort };
const updateConnStatus = (event, extra) => {
this._updateConnStatus(event, sourceAddress, extra);
};
logger.verbose(`[hub] [${sourceAddress.host}:${sourceAddress.port}] connected`);
updateConnStatus('new');
const context = {
socket,
socket: conn,
proxyRequest,
remoteInfo: sourceAddress,
};
@ -366,6 +370,18 @@ export class Hub {
this._tcpRelays.set(relay.id, relay);
};
_getSourceAddress(conn) {
let sourceHost, sourcePort;
if (conn.session) {
sourceHost = conn.session.socket.remoteAddress;
sourcePort = conn.session.socket.remotePort;
} else {
sourceHost = conn.remoteAddress;
sourcePort = conn.remotePort;
}
return { host: sourceHost, port: sourcePort };
}
_getMuxRelayOnClient(context, cid) {
// get a mux relay
let muxRelay = this._selectMuxRelay();

@ -8,6 +8,7 @@ import {
TcpInbound, TcpOutbound,
UdpInbound, UdpOutbound,
TlsInbound, TlsOutbound,
Http2Inbound, Http2Outbound,
WsInbound, WsOutbound,
MuxInbound, MuxOutbound,
} from '../transports';
@ -131,6 +132,7 @@ export class Relay extends EventEmitter {
'tcp': [TcpInbound, TcpOutbound],
'udp': [UdpInbound, UdpOutbound],
'tls': [TlsInbound, TlsOutbound],
'h2': [Http2Inbound, Http2Outbound],
'ws': [WsInbound, WsOutbound],
'mux': [MuxInbound, MuxOutbound],
};

27
src/transports/h2.js Normal file

@ -0,0 +1,27 @@
import http2 from 'http2';
import { TcpInbound, TcpOutbound } from './tcp';
import { logger } from '../utils';
const { HTTP2_HEADER_PATH } = http2.constants;
export class Http2Inbound extends TcpInbound {
get name() {
return 'h2:inbound';
}
}
export class Http2Outbound extends TcpOutbound {
get name() {
return 'h2:outbound';
}
async _connect({ host, port }) {
logger.info(`[h2:outbound] [${this.remote}] connecting to h2://${host}:${port}`);
const session = http2.connect(`https://${host}:${port}`, { ca: [this._config.tls_cert] });
return session.request({ [HTTP2_HEADER_PATH]: '/' });
}
}

@ -1,5 +1,6 @@
export * from './tcp';
export * from './udp';
export * from './tls';
export * from './h2';
export * from './ws';
export * from './mux';