@httptoolkit/httpolyglot 0.2.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/dist/index.d.ts +20 -0
- package/dist/index.js +153 -0
- package/dist/index.js.map +1 -0
- package/package.json +26 -4
- package/src/index.ts +180 -0
- package/lib/index.js +0 -87
- package/q +0 -22
- package/test/common.js +0 -43
- package/test/fixtures/server.crt +0 -22
- package/test/fixtures/server.key +0 -28
- package/test/test-early-disconnect.js +0 -21
- package/test/test-normal.js +0 -45
- package/test/test.js +0 -4
package/README.md
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# Httpolyglot [](https://github.com/httptoolkit/httpolyglot/actions) [](https://npmjs.com/package/@httptoolkit/httpolyglot)
|
|
2
|
+
|
|
3
|
+
> _Part of [HTTP Toolkit](https://httptoolkit.tech): powerful tools for building, testing & debugging HTTP(S)_
|
|
3
4
|
|
|
4
5
|
A module for serving http and https connections over the same port.
|
|
5
6
|
|
|
6
7
|
Forked from the original [`httpolyglot`](https://github.com/mscdex/httpolyglot) to fix various issues required for [HTTP Toolkit](https://httptoolkit.tech), including:
|
|
7
8
|
|
|
9
|
+
* Support for HTTP/2
|
|
8
10
|
* Fixing `tlsClientError`: https://github.com/mscdex/httpolyglot/pull/11.
|
|
9
11
|
* Exposing the lost bytes from https://github.com/mscdex/httpolyglot/issues/13 on the socket, as `__httpPeekedData`.
|
|
10
12
|
* Dropping support for old versions of Node (and thereby simplifying the code somewhat)
|
|
13
|
+
* Converting to TypeScript
|
|
11
14
|
|
|
12
15
|
Requirements
|
|
13
16
|
============
|
|
14
17
|
|
|
15
|
-
* [node.js](http://nodejs.org/) --
|
|
18
|
+
* [node.js](http://nodejs.org/) -- v12.0.0 or newer
|
|
16
19
|
|
|
17
20
|
|
|
18
21
|
Install
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import * as net from 'net';
|
|
3
|
+
import * as http from 'http';
|
|
4
|
+
import * as https from 'https';
|
|
5
|
+
declare module 'net' {
|
|
6
|
+
interface Socket {
|
|
7
|
+
__httpPeekedData?: Buffer;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export declare class Server extends net.Server {
|
|
11
|
+
private _httpServer;
|
|
12
|
+
private _http2Server;
|
|
13
|
+
private _tlsServer;
|
|
14
|
+
constructor(requestListener: http.RequestListener);
|
|
15
|
+
constructor(tlsConfig: https.ServerOptions, requestListener: http.RequestListener);
|
|
16
|
+
private connectionListener;
|
|
17
|
+
private http2Listener;
|
|
18
|
+
}
|
|
19
|
+
export declare function createServer(requestListener: http.RequestListener): Server;
|
|
20
|
+
export declare function createServer(tlsConfig: https.ServerOptions, requestListener: http.RequestListener): Server;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createServer = exports.Server = void 0;
|
|
4
|
+
const net = require("net");
|
|
5
|
+
const tls = require("tls");
|
|
6
|
+
const http = require("http");
|
|
7
|
+
const http2 = require("http2");
|
|
8
|
+
const events_1 = require("events");
|
|
9
|
+
function onError(err) { }
|
|
10
|
+
const TLS_HANDSHAKE_BYTE = 0x16; // SSLv3+ or TLS handshake
|
|
11
|
+
const HTTP2_PREFACE = 'PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n';
|
|
12
|
+
const HTTP2_PREFACE_BUFFER = Buffer.from(HTTP2_PREFACE);
|
|
13
|
+
const NODE_MAJOR_VERSION = parseInt(process.version.slice(1).split('.')[0], 10);
|
|
14
|
+
class Server extends net.Server {
|
|
15
|
+
constructor(configOrListener, listener) {
|
|
16
|
+
// We just act as a plain TCP server, accepting and examing
|
|
17
|
+
// each connection, then passing it to the right subserver.
|
|
18
|
+
super((socket) => this.connectionListener(socket));
|
|
19
|
+
let tlsConfig;
|
|
20
|
+
let requestListener;
|
|
21
|
+
if (typeof configOrListener === 'function') {
|
|
22
|
+
requestListener = configOrListener;
|
|
23
|
+
tlsConfig = undefined;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
tlsConfig = configOrListener;
|
|
27
|
+
requestListener = listener;
|
|
28
|
+
}
|
|
29
|
+
// We bind the request listener, so 'this' always refers to us, not each subserver.
|
|
30
|
+
// This means 'this' is consistent (and this.close() works).
|
|
31
|
+
const boundListener = requestListener.bind(this);
|
|
32
|
+
// Create subservers for each supported protocol:
|
|
33
|
+
this._httpServer = new http.Server(boundListener);
|
|
34
|
+
this._http2Server = http2.createServer({}, boundListener);
|
|
35
|
+
if (typeof tlsConfig === 'object') {
|
|
36
|
+
// If we have TLS config, create a TLS server, which will pass sockets to
|
|
37
|
+
// the relevant subserver once the TLS connection is set up.
|
|
38
|
+
this._tlsServer = new tls.Server(tlsConfig, (tlsSocket) => {
|
|
39
|
+
if (tlsSocket.alpnProtocol === false || tlsSocket.alpnProtocol === 'http/1.1') {
|
|
40
|
+
this._httpServer.emit('connection', tlsSocket);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
this._http2Server.emit('connection', tlsSocket);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
// Fake server that rejects all connections:
|
|
49
|
+
this._tlsServer = new events_1.EventEmitter();
|
|
50
|
+
this._tlsServer.on('connection', (socket) => socket.destroy());
|
|
51
|
+
}
|
|
52
|
+
const subServers = [this._httpServer, this._http2Server, this._tlsServer];
|
|
53
|
+
// Proxy all event listeners setup onto the subservers, so any
|
|
54
|
+
// subscriptions on this server are fed from all the subservers
|
|
55
|
+
this.on('newListener', function (eventName, listener) {
|
|
56
|
+
subServers.forEach(function (subServer) {
|
|
57
|
+
subServer.addListener(eventName, listener);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
this.on('removeListener', function (eventName, listener) {
|
|
61
|
+
subServers.forEach(function (subServer) {
|
|
62
|
+
subServer.removeListener(eventName, listener);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
connectionListener(socket) {
|
|
67
|
+
const data = socket.read(1);
|
|
68
|
+
if (data === null) {
|
|
69
|
+
socket.removeListener('error', onError);
|
|
70
|
+
socket.on('error', onError);
|
|
71
|
+
socket.once('readable', () => {
|
|
72
|
+
this.connectionListener(socket);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
socket.removeListener('error', onError);
|
|
77
|
+
// Put the peeked data back into the socket
|
|
78
|
+
const firstByte = data[0];
|
|
79
|
+
socket.unshift(data);
|
|
80
|
+
// Pass the socket to the correct subserver:
|
|
81
|
+
if (firstByte === TLS_HANDSHAKE_BYTE) {
|
|
82
|
+
// TLS sockets don't allow half open
|
|
83
|
+
socket.allowHalfOpen = false;
|
|
84
|
+
this._tlsServer.emit('connection', socket);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
if (firstByte === HTTP2_PREFACE_BUFFER[0]) {
|
|
88
|
+
// The connection _might_ be HTTP/2. To confirm, we need to keep
|
|
89
|
+
// reading until we get the whole stream:
|
|
90
|
+
this.http2Listener(socket);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
// The above unshift isn't always sufficient to invisibly replace the
|
|
94
|
+
// read data. The rawPacket property on errors in the clientError event
|
|
95
|
+
// for plain HTTP servers loses this data - this prop makes it available.
|
|
96
|
+
// Bit of a hacky fix, but sufficient to allow for manual workarounds.
|
|
97
|
+
socket.__httpPeekedData = data;
|
|
98
|
+
this._httpServer.emit('connection', socket);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
http2Listener(socket, pastData) {
|
|
104
|
+
const h1Server = this._httpServer;
|
|
105
|
+
const h2Server = this._http2Server;
|
|
106
|
+
const newData = socket.read() || Buffer.from([]);
|
|
107
|
+
const data = pastData ? Buffer.concat([pastData, newData]) : newData;
|
|
108
|
+
if (data.length >= HTTP2_PREFACE_BUFFER.length) {
|
|
109
|
+
socket.unshift(data);
|
|
110
|
+
if (data.slice(0, HTTP2_PREFACE_BUFFER.length).equals(HTTP2_PREFACE_BUFFER)) {
|
|
111
|
+
// We have a full match for the preface - it's definitely HTTP/2.
|
|
112
|
+
// For HTTP/2 we hit issues when passing non-socket streams (like H2 streams for proxying H2-over-H2).
|
|
113
|
+
if (NODE_MAJOR_VERSION <= 12) {
|
|
114
|
+
// For Node 12 and older, we need a (later deprecated) stream wrapper:
|
|
115
|
+
const StreamWrapper = require('_stream_wrap');
|
|
116
|
+
socket = new StreamWrapper(socket);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
// For newer node, we can fix this with a quick patch here:
|
|
120
|
+
const socketWithInternals = socket;
|
|
121
|
+
if (socketWithInternals._handle) {
|
|
122
|
+
socketWithInternals._handle.isStreamBase = false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
h2Server.emit('connection', socket);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
h1Server.emit('connection', socket);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
else if (!data.equals(HTTP2_PREFACE_BUFFER.slice(0, data.length))) {
|
|
134
|
+
socket.unshift(data);
|
|
135
|
+
// Haven't finished the preface length, but something doesn't match already
|
|
136
|
+
h1Server.emit('connection', socket);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
// Not enough data to know either way - try again, waiting for more:
|
|
140
|
+
socket.removeListener('error', onError);
|
|
141
|
+
socket.on('error', onError);
|
|
142
|
+
socket.once('readable', () => {
|
|
143
|
+
this.http2Listener.call(this, socket, data);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
exports.Server = Server;
|
|
148
|
+
function createServer(configOrListener, listener) {
|
|
149
|
+
return new Server(configOrListener, listener);
|
|
150
|
+
}
|
|
151
|
+
exports.createServer = createServer;
|
|
152
|
+
;
|
|
153
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,18 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@httptoolkit/httpolyglot",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"author": "Tim Perry <pimterry@gmail.com>",
|
|
5
5
|
"description": "Serve http and https connections over the same port with node.js",
|
|
6
|
-
"main": "./
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist/",
|
|
10
|
+
"src/"
|
|
11
|
+
],
|
|
7
12
|
"scripts": {
|
|
8
|
-
"
|
|
13
|
+
"prebuild": "rimraf dist/*",
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"prepack": "npm run build",
|
|
16
|
+
"pretest": "npm run build",
|
|
17
|
+
"test": "mocha -r ts-node/register 'test/**/*.spec.ts'"
|
|
9
18
|
},
|
|
10
19
|
"engines": {
|
|
11
|
-
"node": ">=
|
|
20
|
+
"node": ">=12.0.0"
|
|
12
21
|
},
|
|
13
22
|
"keywords": [
|
|
14
23
|
"http",
|
|
15
24
|
"https",
|
|
25
|
+
"http2",
|
|
16
26
|
"multiplex",
|
|
17
27
|
"polyglot"
|
|
18
28
|
],
|
|
@@ -25,5 +35,17 @@
|
|
|
25
35
|
"repository": {
|
|
26
36
|
"type": "git",
|
|
27
37
|
"url": "http://github.com/httptoolkit/httpolyglot.git"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@types/node": "^16.7.10"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/chai": "^4.2.21",
|
|
44
|
+
"@types/mocha": "^9.0.0",
|
|
45
|
+
"chai": "^4.3.4",
|
|
46
|
+
"mocha": "^9.1.1",
|
|
47
|
+
"rimraf": "^3.0.2",
|
|
48
|
+
"ts-node": "^10.2.1",
|
|
49
|
+
"typescript": "^4.4.2"
|
|
28
50
|
}
|
|
29
51
|
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import * as net from 'net';
|
|
2
|
+
import * as tls from 'tls';
|
|
3
|
+
import * as http from 'http';
|
|
4
|
+
import * as https from 'https';
|
|
5
|
+
import * as http2 from 'http2';
|
|
6
|
+
|
|
7
|
+
import { EventEmitter } from 'events';
|
|
8
|
+
|
|
9
|
+
declare module 'net' {
|
|
10
|
+
interface Socket {
|
|
11
|
+
__httpPeekedData?: Buffer;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function onError(err: any) {}
|
|
16
|
+
|
|
17
|
+
const TLS_HANDSHAKE_BYTE = 0x16; // SSLv3+ or TLS handshake
|
|
18
|
+
const HTTP2_PREFACE = 'PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n';
|
|
19
|
+
const HTTP2_PREFACE_BUFFER = Buffer.from(HTTP2_PREFACE);
|
|
20
|
+
|
|
21
|
+
const NODE_MAJOR_VERSION = parseInt(process.version.slice(1).split('.')[0], 10);
|
|
22
|
+
|
|
23
|
+
type Http2Listener = (request: http2.Http2ServerRequest, response: http2.Http2ServerResponse) => void;
|
|
24
|
+
|
|
25
|
+
export class Server extends net.Server {
|
|
26
|
+
|
|
27
|
+
private _httpServer: http.Server;
|
|
28
|
+
private _http2Server: http2.Http2Server;
|
|
29
|
+
private _tlsServer: EventEmitter;
|
|
30
|
+
|
|
31
|
+
constructor(requestListener: http.RequestListener);
|
|
32
|
+
constructor(tlsConfig: https.ServerOptions, requestListener: http.RequestListener);
|
|
33
|
+
constructor(configOrListener: https.ServerOptions | http.RequestListener, listener?: http.RequestListener) {
|
|
34
|
+
// We just act as a plain TCP server, accepting and examing
|
|
35
|
+
// each connection, then passing it to the right subserver.
|
|
36
|
+
super((socket) => this.connectionListener(socket));
|
|
37
|
+
|
|
38
|
+
let tlsConfig: https.ServerOptions | undefined;
|
|
39
|
+
let requestListener: http.RequestListener;
|
|
40
|
+
|
|
41
|
+
if (typeof configOrListener === 'function') {
|
|
42
|
+
requestListener = configOrListener;
|
|
43
|
+
tlsConfig = undefined;
|
|
44
|
+
} else {
|
|
45
|
+
tlsConfig = configOrListener;
|
|
46
|
+
requestListener = listener!;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// We bind the request listener, so 'this' always refers to us, not each subserver.
|
|
50
|
+
// This means 'this' is consistent (and this.close() works).
|
|
51
|
+
const boundListener = requestListener.bind(this);
|
|
52
|
+
|
|
53
|
+
// Create subservers for each supported protocol:
|
|
54
|
+
this._httpServer = new http.Server(boundListener);
|
|
55
|
+
this._http2Server = http2.createServer({}, boundListener as any as Http2Listener);
|
|
56
|
+
|
|
57
|
+
if (typeof tlsConfig === 'object') {
|
|
58
|
+
// If we have TLS config, create a TLS server, which will pass sockets to
|
|
59
|
+
// the relevant subserver once the TLS connection is set up.
|
|
60
|
+
this._tlsServer = new tls.Server(tlsConfig, (tlsSocket) => {
|
|
61
|
+
if (tlsSocket.alpnProtocol === false || tlsSocket.alpnProtocol === 'http/1.1') {
|
|
62
|
+
this._httpServer.emit('connection', tlsSocket);
|
|
63
|
+
} else {
|
|
64
|
+
this._http2Server.emit('connection', tlsSocket);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
} else {
|
|
68
|
+
// Fake server that rejects all connections:
|
|
69
|
+
this._tlsServer = new EventEmitter();
|
|
70
|
+
this._tlsServer.on('connection', (socket) => socket.destroy());
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const subServers = [this._httpServer, this._http2Server, this._tlsServer];
|
|
74
|
+
|
|
75
|
+
// Proxy all event listeners setup onto the subservers, so any
|
|
76
|
+
// subscriptions on this server are fed from all the subservers
|
|
77
|
+
this.on('newListener', function (eventName, listener) {
|
|
78
|
+
subServers.forEach(function (subServer) {
|
|
79
|
+
subServer.addListener(eventName, listener);
|
|
80
|
+
})
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
this.on('removeListener', function (eventName, listener) {
|
|
84
|
+
subServers.forEach(function (subServer) {
|
|
85
|
+
subServer.removeListener(eventName, listener);
|
|
86
|
+
})
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private connectionListener(socket: net.Socket) {
|
|
91
|
+
const data = socket.read(1);
|
|
92
|
+
|
|
93
|
+
if (data === null) {
|
|
94
|
+
socket.removeListener('error', onError);
|
|
95
|
+
socket.on('error', onError);
|
|
96
|
+
|
|
97
|
+
socket.once('readable', () => {
|
|
98
|
+
this.connectionListener(socket);
|
|
99
|
+
});
|
|
100
|
+
} else {
|
|
101
|
+
socket.removeListener('error', onError);
|
|
102
|
+
|
|
103
|
+
// Put the peeked data back into the socket
|
|
104
|
+
const firstByte = data[0];
|
|
105
|
+
socket.unshift(data);
|
|
106
|
+
|
|
107
|
+
// Pass the socket to the correct subserver:
|
|
108
|
+
if (firstByte === TLS_HANDSHAKE_BYTE) {
|
|
109
|
+
// TLS sockets don't allow half open
|
|
110
|
+
socket.allowHalfOpen = false;
|
|
111
|
+
this._tlsServer.emit('connection', socket);
|
|
112
|
+
} else {
|
|
113
|
+
if (firstByte === HTTP2_PREFACE_BUFFER[0]) {
|
|
114
|
+
// The connection _might_ be HTTP/2. To confirm, we need to keep
|
|
115
|
+
// reading until we get the whole stream:
|
|
116
|
+
this.http2Listener(socket);
|
|
117
|
+
} else {
|
|
118
|
+
// The above unshift isn't always sufficient to invisibly replace the
|
|
119
|
+
// read data. The rawPacket property on errors in the clientError event
|
|
120
|
+
// for plain HTTP servers loses this data - this prop makes it available.
|
|
121
|
+
// Bit of a hacky fix, but sufficient to allow for manual workarounds.
|
|
122
|
+
socket.__httpPeekedData = data;
|
|
123
|
+
this._httpServer.emit('connection', socket);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
private http2Listener(socket: net.Socket, pastData?: Buffer) {
|
|
130
|
+
const h1Server = this._httpServer;
|
|
131
|
+
const h2Server = this._http2Server;
|
|
132
|
+
|
|
133
|
+
const newData: Buffer = socket.read() || Buffer.from([]);
|
|
134
|
+
const data = pastData ? Buffer.concat([pastData, newData]) : newData;
|
|
135
|
+
|
|
136
|
+
if (data.length >= HTTP2_PREFACE_BUFFER.length) {
|
|
137
|
+
socket.unshift(data);
|
|
138
|
+
if (data.slice(0, HTTP2_PREFACE_BUFFER.length).equals(HTTP2_PREFACE_BUFFER)) {
|
|
139
|
+
// We have a full match for the preface - it's definitely HTTP/2.
|
|
140
|
+
|
|
141
|
+
// For HTTP/2 we hit issues when passing non-socket streams (like H2 streams for proxying H2-over-H2).
|
|
142
|
+
if (NODE_MAJOR_VERSION <= 12) {
|
|
143
|
+
// For Node 12 and older, we need a (later deprecated) stream wrapper:
|
|
144
|
+
const StreamWrapper = require('_stream_wrap');
|
|
145
|
+
socket = new StreamWrapper(socket);
|
|
146
|
+
} else {
|
|
147
|
+
// For newer node, we can fix this with a quick patch here:
|
|
148
|
+
const socketWithInternals = socket as { _handle?: { isStreamBase?: boolean } };
|
|
149
|
+
if (socketWithInternals._handle) {
|
|
150
|
+
socketWithInternals._handle.isStreamBase = false;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
h2Server.emit('connection', socket);
|
|
155
|
+
return;
|
|
156
|
+
} else {
|
|
157
|
+
h1Server.emit('connection', socket);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
} else if (!data.equals(HTTP2_PREFACE_BUFFER.slice(0, data.length))) {
|
|
161
|
+
socket.unshift(data);
|
|
162
|
+
// Haven't finished the preface length, but something doesn't match already
|
|
163
|
+
h1Server.emit('connection', socket);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Not enough data to know either way - try again, waiting for more:
|
|
168
|
+
socket.removeListener('error', onError);
|
|
169
|
+
socket.on('error', onError);
|
|
170
|
+
socket.once('readable', () => {
|
|
171
|
+
this.http2Listener.call(this, socket, data);
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function createServer(requestListener: http.RequestListener): Server;
|
|
177
|
+
export function createServer(tlsConfig: https.ServerOptions, requestListener: http.RequestListener): Server;
|
|
178
|
+
export function createServer(configOrListener: https.ServerOptions | http.RequestListener, listener?: http.RequestListener) {
|
|
179
|
+
return new Server(configOrListener as any, listener as any);
|
|
180
|
+
};
|
package/lib/index.js
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
const http = require('http');
|
|
2
|
-
const https = require('https');
|
|
3
|
-
const inherits = require('util').inherits;
|
|
4
|
-
const httpSocketHandler = http._connectionListener;
|
|
5
|
-
|
|
6
|
-
function Server(tlsconfig, requestListener) {
|
|
7
|
-
if (!(this instanceof Server)) return new Server(tlsconfig, requestListener);
|
|
8
|
-
|
|
9
|
-
if (typeof tlsconfig === 'function') {
|
|
10
|
-
requestListener = tlsconfig;
|
|
11
|
-
tlsconfig = undefined;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
if (typeof tlsconfig === 'object') {
|
|
15
|
-
this.removeAllListeners('connection');
|
|
16
|
-
|
|
17
|
-
https.Server.call(this, tlsconfig, requestListener);
|
|
18
|
-
|
|
19
|
-
// capture https socket handler, it's not exported like http's socket
|
|
20
|
-
// handler
|
|
21
|
-
const connev = this._events.connection;
|
|
22
|
-
if (typeof connev === 'function') {
|
|
23
|
-
this._tlsHandler = connev;
|
|
24
|
-
} else {
|
|
25
|
-
this._tlsHandler = connev[connev.length - 1];
|
|
26
|
-
}
|
|
27
|
-
this.removeListener('connection', this._tlsHandler);
|
|
28
|
-
|
|
29
|
-
this._connListener = connectionListener;
|
|
30
|
-
this.on('connection', connectionListener);
|
|
31
|
-
|
|
32
|
-
// copy from http.Server
|
|
33
|
-
this.timeout = 2 * 60 * 1000;
|
|
34
|
-
this.allowHalfOpen = true;
|
|
35
|
-
this.httpAllowHalfOpen = false;
|
|
36
|
-
} else {
|
|
37
|
-
http.Server.call(this, requestListener);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
inherits(Server, https.Server);
|
|
41
|
-
|
|
42
|
-
Server.prototype.setTimeout = function (msecs, callback) {
|
|
43
|
-
this.timeout = msecs;
|
|
44
|
-
if (callback) this.on('timeout', callback);
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
Server.prototype.__httpSocketHandler = httpSocketHandler;
|
|
48
|
-
|
|
49
|
-
function onError(err) {}
|
|
50
|
-
|
|
51
|
-
const connectionListener = function (socket) {
|
|
52
|
-
const data = socket.read(1);
|
|
53
|
-
|
|
54
|
-
if (data === null) {
|
|
55
|
-
socket.removeListener('error', onError);
|
|
56
|
-
socket.on('error', onError);
|
|
57
|
-
|
|
58
|
-
socket.once('readable', () => {
|
|
59
|
-
this._connListener(socket);
|
|
60
|
-
});
|
|
61
|
-
} else {
|
|
62
|
-
socket.removeListener('error', onError);
|
|
63
|
-
|
|
64
|
-
const firstByte = data[0];
|
|
65
|
-
socket.unshift(data);
|
|
66
|
-
if (firstByte < 32 || firstByte >= 127) {
|
|
67
|
-
// tls/ssl
|
|
68
|
-
// TLS sockets don't allow half open
|
|
69
|
-
socket.allowHalfOpen = false;
|
|
70
|
-
this._tlsHandler(socket);
|
|
71
|
-
} else {
|
|
72
|
-
// The above unshift isn't always sufficient to invisibly replace the
|
|
73
|
-
// read data. The rawPacket property on errors in the clientError event
|
|
74
|
-
// specifically is missing this data - this prop makes it available.
|
|
75
|
-
// Bit of a hacky fix, but sufficient to allow for manual workarounds.
|
|
76
|
-
socket.__httpPeekedData = data;
|
|
77
|
-
|
|
78
|
-
this.__httpSocketHandler(socket);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
exports.Server = Server;
|
|
84
|
-
|
|
85
|
-
exports.createServer = function (tlsconfig, requestListener) {
|
|
86
|
-
return new Server(tlsconfig, requestListener);
|
|
87
|
-
};
|
package/q
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
*[33m-[m[33m.[m [33m1d3593f[m[33m ([m[1;35mrefs/stash[m[33m)[m WIP on master: 2ddda12 Update docs & details to fork the package for httptoolkit use
|
|
2
|
-
[31m|[m[32m\[m [33m\[m
|
|
3
|
-
[31m|[m [32m|[m * [33mcd20755[m untracked files on master: 2ddda12 Update docs & details to fork the package for httptoolkit use
|
|
4
|
-
[31m|[m * [33m0caa43e[m index on master: 2ddda12 Update docs & details to fork the package for httptoolkit use
|
|
5
|
-
[31m|[m[31m/[m
|
|
6
|
-
* [33m2ddda12[m[33m ([m[1;36mHEAD -> [m[1;32mmaster[m[33m)[m Update docs & details to fork the package for httptoolkit use
|
|
7
|
-
* [33mac0a75f[m Expose peeked HTTP data as __httpPeekedData
|
|
8
|
-
* [33m247cd34[m Drop support for Node < 8, and simplify
|
|
9
|
-
* [33mf2652ea[m[33m ([m[1;31morigin/no-half-open-tls[m[33m, [m[1;32mno-half-open-tls[m[33m)[m Don't allow half-open TLS connections
|
|
10
|
-
* [33m1c6c4af[m[33m ([m[1;33mtag: v0.1.2[m[33m)[m bump version
|
|
11
|
-
* [33m475e6f4[m lib: ignore pre-detection errors
|
|
12
|
-
* [33mef54b90[m readme: add section about how the module works
|
|
13
|
-
* [33mf78eb12[m[33m ([m[1;33mtag: v0.1.1[m[33m)[m bump version
|
|
14
|
-
* [33mf98b92a[m fix for node 0.11+ again
|
|
15
|
-
* [33m1af5506[m[33m ([m[1;33mtag: v0.1.0[m[33m)[m bump version
|
|
16
|
-
* [33m1f20a4a[m fix node v0.11+ compatibility
|
|
17
|
-
* [33mbc43948[m[33m ([m[1;33mtag: v0.0.2[m[33m)[m bump version
|
|
18
|
-
* [33m2b06da2[m avoid .call()
|
|
19
|
-
* [33ma6f4e7e[m be more strict about byte check
|
|
20
|
-
* [33m2c33984[m readme: add http->https redirect example
|
|
21
|
-
* [33m153cbdf[m[33m ([m[1;33mtag: v0.0.1[m[33m)[m bump version
|
|
22
|
-
* [33mb62bc44[m Initial commit
|
package/test/common.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
exports.mustCall = mustCall;
|
|
2
|
-
function mustCall(fn, expected) {
|
|
3
|
-
if (typeof expected !== 'number')
|
|
4
|
-
expected = 1;
|
|
5
|
-
|
|
6
|
-
var context = {
|
|
7
|
-
expected: expected,
|
|
8
|
-
actual: 0,
|
|
9
|
-
stack: (new Error()).stack,
|
|
10
|
-
name: fn.name || '<anonymous>'
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
// add the exit listener only once to avoid listener leak warnings
|
|
14
|
-
if (mustCall.checks.length === 0)
|
|
15
|
-
process.on('exit', mustCall.runChecks);
|
|
16
|
-
|
|
17
|
-
mustCall.checks.push(context);
|
|
18
|
-
|
|
19
|
-
return function() {
|
|
20
|
-
context.actual++;
|
|
21
|
-
return fn.apply(this, arguments);
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
mustCall.checks = [];
|
|
25
|
-
mustCall.runChecks = function(exitCode) {
|
|
26
|
-
if (exitCode !== 0)
|
|
27
|
-
return;
|
|
28
|
-
|
|
29
|
-
var failed = mustCall.checks.filter(function(context) {
|
|
30
|
-
return context.actual !== context.expected;
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
failed.forEach(function(context) {
|
|
34
|
-
console.log('Mismatched %s function calls. Expected %d, actual %d.',
|
|
35
|
-
context.name,
|
|
36
|
-
context.expected,
|
|
37
|
-
context.actual);
|
|
38
|
-
console.log(context.stack.split('\n').slice(2).join('\n'));
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
if (failed.length)
|
|
42
|
-
process.exit(1);
|
|
43
|
-
};
|
package/test/fixtures/server.crt
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
-----BEGIN CERTIFICATE-----
|
|
2
|
-
MIIDjzCCAnegAwIBAgIJANiEfJkuqhEaMA0GCSqGSIb3DQEBCwUAMF4xCzAJBgNV
|
|
3
|
-
BAYTAlVTMQ0wCwYDVQQIDARPaGlvMQ8wDQYDVQQHDAZEYXl0b24xEjAQBgNVBAoM
|
|
4
|
-
CUZvbywgSW5jLjEbMBkGA1UEAwwSbXlob3N0LmxvY2FsZG9tYWluMB4XDTE2MTEy
|
|
5
|
-
NjE3MTUxNFoXDTE2MTIyNjE3MTUxNFowXjELMAkGA1UEBhMCVVMxDTALBgNVBAgM
|
|
6
|
-
BE9oaW8xDzANBgNVBAcMBkRheXRvbjESMBAGA1UECgwJRm9vLCBJbmMuMRswGQYD
|
|
7
|
-
VQQDDBJteWhvc3QubG9jYWxkb21haW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
|
|
8
|
-
ggEKAoIBAQDi8OEKkQogjasE908B/yBHqYFtbYfYJJpq3qsxV7oWWLuygEvVTM/O
|
|
9
|
-
edAt0CrXppgh1VxKIbyxkQtf+2TyoUlWxUK/9iYzXolTMQ82X+WeeClPdemoNIYV
|
|
10
|
-
wCKrZObJ1TtBM8v2mL8NfQZumr9NahOfK6pWWuLosKtXviJuzAVKQCm3r0scbzi/
|
|
11
|
-
avSP63LfY/ua7m29PZI4wflLAghAUbNAaefp9UAxgYQigXuIj+lMDhIdfuGEndS+
|
|
12
|
-
xkcW/tqeRr42r4xh1C7lb/FagFqMXA5+wDMn1Tj0JBzQLZMR4Ea2vj24BXuPuA8P
|
|
13
|
-
Kq6wvbpZ4B3k+3jrWNL2i3mPUFFXriP3AgMBAAGjUDBOMB0GA1UdDgQWBBSuHVhn
|
|
14
|
-
CAGxnAE81k3uq1oC+TIRsTAfBgNVHSMEGDAWgBSuHVhnCAGxnAE81k3uq1oC+TIR
|
|
15
|
-
sTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCTk27sW0x9CRPC9ZQs
|
|
16
|
-
FuhhcJQb7KXxhUikctkQC101+xZHE0VZeBLgkHCr8Q1tRzqJuvQO6Q5CRB8b5DIX
|
|
17
|
-
ZHOEtzjNnm8yoMDCWVb/4G8repGacpHDkZv3jZguHxpTYVJlwvdDCr0SGqfpcF4e
|
|
18
|
-
5MY8DgfsmXo2hqKp/FozTA1MKs3esuxdrZBxhvoQpRsvX0mxfiBNoTWVu2BgjeqP
|
|
19
|
-
11vSPK1z2YCxHkt1SvwrpycfGV8x7qNvEIn+zzxPitYJHro0w0WX8aelT7Xtj2mD
|
|
20
|
-
pkLsYhM1dHZkIc+uXVSv+EUUkfLJ1FDJ5D+yyKifyYtBVEOvrDpfUFNKy+bZRYsy
|
|
21
|
-
Lcdy
|
|
22
|
-
-----END CERTIFICATE-----
|
package/test/fixtures/server.key
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
-----BEGIN PRIVATE KEY-----
|
|
2
|
-
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDi8OEKkQogjasE
|
|
3
|
-
908B/yBHqYFtbYfYJJpq3qsxV7oWWLuygEvVTM/OedAt0CrXppgh1VxKIbyxkQtf
|
|
4
|
-
+2TyoUlWxUK/9iYzXolTMQ82X+WeeClPdemoNIYVwCKrZObJ1TtBM8v2mL8NfQZu
|
|
5
|
-
mr9NahOfK6pWWuLosKtXviJuzAVKQCm3r0scbzi/avSP63LfY/ua7m29PZI4wflL
|
|
6
|
-
AghAUbNAaefp9UAxgYQigXuIj+lMDhIdfuGEndS+xkcW/tqeRr42r4xh1C7lb/Fa
|
|
7
|
-
gFqMXA5+wDMn1Tj0JBzQLZMR4Ea2vj24BXuPuA8PKq6wvbpZ4B3k+3jrWNL2i3mP
|
|
8
|
-
UFFXriP3AgMBAAECggEARjVFOdKjMm0Bkpi8DZ8TKnhrPSJcm2a/iv52Md61CELN
|
|
9
|
-
VqzQSR3pUDRpTjMPfgXhHN54HcsQKFL6FOieU13IZZrDSsXpDY1aqK0NysGiNQNx
|
|
10
|
-
rE6LSelt7f6x+xpNN/XKziIrIJAi0xZxzff75QRDK8QDf5HAj0JQz+VXm7VskYpw
|
|
11
|
-
90YdekO5S/7V8UlLDDQFcKVdsmiPoDogPz6C2CnzD/yVzduJhmoM9PqccRyA/WVD
|
|
12
|
-
YHejPs+LGhM5SLQaMmMWXX5oQ21Gc/t1xvrHokiqcBpxz1djT8I4amRg7D+3bsNG
|
|
13
|
-
d/cRLTKLj1joxJl2VQi+cXT45P5VF5inLwXvraJomQKBgQD0F9FcwhbINjtHFSsr
|
|
14
|
-
gexUjwynvAZyNkI+rROku37wBtT4EwMkRgq9FN6aHZZ8wi6kxRVH7KbmGKXmPkIw
|
|
15
|
-
H/t2lHsae7GZ207H9LZa+VLfDMYCSXa40SvGRBrSPOrTOMCc3HgmP0s/00xfALzs
|
|
16
|
-
T4IHJbOYwhzArZhwC6YLn9byFQKBgQDuAt6QxiJneUM/1JW5P7TEzGLi9bwUmSKH
|
|
17
|
-
EkLbsDKRmqH1EvEoQaG9js9FBLBKaSRYRnub3FbRb7Ckk1MpQY67rOb8L2ypp7uy
|
|
18
|
-
+Bv2Cmbm4mD+/Aapw5Is/6UqNCqTChjI58437eEtZx7X4cYBLwiaKPvPUWI6L2wJ
|
|
19
|
-
4nMsr3fc2wKBgQCpaqqelfvYBIQKJzAqZ2fPnOXsub1DolNCS0CaEqTdFfDVKeUB
|
|
20
|
-
VTf42rZSA31CpEhZhozpueBxTeQ/tTCdVGVlfVMgI4A2SJgagsfaxrf1Jll8lt63
|
|
21
|
-
Ej8uwnBXQX6/EeHmPcOK0F17ND4Kpml6HwkhytInkXsBZLur8PnTkaJPrQKBgQCN
|
|
22
|
-
kF9YtMBZ0yJQoNy85ktakkZuv8IybjK/K/lgOZiaSeLypWWSkBbnbD2Ty4ofeBIJ
|
|
23
|
-
/0IeHhv1Tf0+pfHcpAWFUv3AGWUEM6PMew4GdYFm6lbO0pAUASK8aQGP7J81/ddo
|
|
24
|
-
B5f8ZBx+qMsLlFn08kiniKDdWoaWHQahinL+rQ8Z6QKBgQDN1SpQnFHYy3uugmN0
|
|
25
|
-
KZjDjVs9gBo0lhNVE/HUbf91TiY/ITpjUCHmv+N3VxKyCII4O7+jjFhzK+5NKLV2
|
|
26
|
-
WsYLN9ttR/2FQ4JnTUocXple3DxmaA7rCRZj8ZQ/jrGwbEj5nLyOIDblWgaaADMB
|
|
27
|
-
W2YC7grwofz3HqqSUCHySDHvUA==
|
|
28
|
-
-----END PRIVATE KEY-----
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
var fs = require('fs');
|
|
2
|
-
var exec = require('child_process').exec;
|
|
3
|
-
var assert = require('assert');
|
|
4
|
-
|
|
5
|
-
var common = require(__dirname + '/common');
|
|
6
|
-
var httpolyglot = require(__dirname + '/../lib/index');
|
|
7
|
-
|
|
8
|
-
var srv = httpolyglot.createServer({
|
|
9
|
-
key: fs.readFileSync(__dirname + '/fixtures/server.key'),
|
|
10
|
-
cert: fs.readFileSync(__dirname + '/fixtures/server.crt')
|
|
11
|
-
}, function(req, res) {
|
|
12
|
-
assert(false, 'Request handler should not be called');
|
|
13
|
-
});
|
|
14
|
-
srv.listen(0, '127.0.0.1', common.mustCall(function() {
|
|
15
|
-
var port = this.address().port;
|
|
16
|
-
|
|
17
|
-
exec('nmap 127.0.0.1 -p' + port,
|
|
18
|
-
common.mustCall(function(err, stdout, stderr) {
|
|
19
|
-
srv.close();
|
|
20
|
-
}));
|
|
21
|
-
}));
|
package/test/test-normal.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
var fs = require('fs');
|
|
2
|
-
var http = require('http');
|
|
3
|
-
var https = require('https');
|
|
4
|
-
var assert = require('assert');
|
|
5
|
-
|
|
6
|
-
var common = require(__dirname + '/common');
|
|
7
|
-
var httpolyglot = require(__dirname + '/../lib/index');
|
|
8
|
-
|
|
9
|
-
var srv = httpolyglot.createServer({
|
|
10
|
-
key: fs.readFileSync(__dirname + '/fixtures/server.key'),
|
|
11
|
-
cert: fs.readFileSync(__dirname + '/fixtures/server.crt')
|
|
12
|
-
}, common.mustCall(function(req, res) {
|
|
13
|
-
this.count || (this.count = 0);
|
|
14
|
-
res.end(req.socket.encrypted ? 'https' : 'http');
|
|
15
|
-
if (++this.count === 2)
|
|
16
|
-
this.close();
|
|
17
|
-
}, 2));
|
|
18
|
-
srv.listen(0, '127.0.0.1', common.mustCall(function() {
|
|
19
|
-
var port = this.address().port;
|
|
20
|
-
|
|
21
|
-
http.get({
|
|
22
|
-
host: '127.0.0.1',
|
|
23
|
-
port: port
|
|
24
|
-
}, common.mustCall(function(res) {
|
|
25
|
-
var body = '';
|
|
26
|
-
res.on('data', function(data) {
|
|
27
|
-
body += data;
|
|
28
|
-
}).on('end', common.mustCall(function() {
|
|
29
|
-
assert.strictEqual(body, 'http');
|
|
30
|
-
}));
|
|
31
|
-
}));
|
|
32
|
-
|
|
33
|
-
https.get({
|
|
34
|
-
host: '127.0.0.1',
|
|
35
|
-
port: port,
|
|
36
|
-
rejectUnauthorized: false
|
|
37
|
-
}, common.mustCall(function(res) {
|
|
38
|
-
var body = '';
|
|
39
|
-
res.on('data', function(data) {
|
|
40
|
-
body += data;
|
|
41
|
-
}).on('end', common.mustCall(function() {
|
|
42
|
-
assert.strictEqual(body, 'https');
|
|
43
|
-
}));
|
|
44
|
-
}));
|
|
45
|
-
}));
|
package/test/test.js
DELETED