@radatek/microserver 3.0.2 → 3.0.3
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/microserver.d.ts +5 -9
- package/microserver.js +68 -89
- package/package.json +1 -1
package/microserver.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MicroServer
|
|
3
|
-
* @version 3.0.
|
|
3
|
+
* @version 3.0.3
|
|
4
4
|
* @package @radatek/microserver
|
|
5
5
|
* @copyright Darius Kisonas 2022
|
|
6
6
|
* @license MIT
|
|
@@ -32,9 +32,6 @@ export declare class WebSocketError extends Error {
|
|
|
32
32
|
statusCode: number;
|
|
33
33
|
constructor(text?: string, code?: number);
|
|
34
34
|
}
|
|
35
|
-
type DeferPromise<T = void> = Promise<T> & {
|
|
36
|
-
resolve: (res?: T | Error) => void;
|
|
37
|
-
};
|
|
38
35
|
/** Middleware */
|
|
39
36
|
export interface Middleware {
|
|
40
37
|
(req: ServerRequest, res: ServerResponse, next: Function): any;
|
|
@@ -50,7 +47,7 @@ export declare abstract class Plugin {
|
|
|
50
47
|
constructor();
|
|
51
48
|
}
|
|
52
49
|
interface PluginClass {
|
|
53
|
-
new (options
|
|
50
|
+
new (options: any, server: MicroServer): Plugin;
|
|
54
51
|
}
|
|
55
52
|
export type ServerRequestBody<T = any> = T extends Model<infer U extends ModelSchema> ? ModelDocument<U> : Record<string, any>;
|
|
56
53
|
/** Extended http.IncomingMessage */
|
|
@@ -89,12 +86,12 @@ export declare class ServerRequest<T = any> extends http.IncomingMessage {
|
|
|
89
86
|
rawBody: Buffer[];
|
|
90
87
|
/** Request raw body size */
|
|
91
88
|
rawBodySize: number;
|
|
92
|
-
_body?: ServerRequestBody<T>;
|
|
93
|
-
_isReady: DeferPromise | undefined;
|
|
94
89
|
private constructor();
|
|
95
|
-
static extend(req: http.IncomingMessage, server: MicroServer): ServerRequest;
|
|
90
|
+
static extend(req: http.IncomingMessage, res: http.ServerResponse, server: MicroServer): ServerRequest;
|
|
96
91
|
get isReady(): boolean;
|
|
97
92
|
waitReady(): Promise<void>;
|
|
93
|
+
setReady(err?: Error): void;
|
|
94
|
+
setBody(body: ServerRequestBody<T>): void;
|
|
98
95
|
/** Update request url */
|
|
99
96
|
updateUrl(url: string): this;
|
|
100
97
|
/** Rewrite request url */
|
|
@@ -351,7 +348,6 @@ export declare class WebSocketPlugin extends Plugin {
|
|
|
351
348
|
constructor(options?: any, server?: MicroServer);
|
|
352
349
|
addUpgradeHandler(srv: http.Server): void;
|
|
353
350
|
upgradeHandler(server: MicroServer, req: ServerRequest, socket: net.Socket, head: any): void;
|
|
354
|
-
static create(req: ServerRequest, options?: WebSocketOptions): WebSocket;
|
|
355
351
|
}
|
|
356
352
|
/** Trust proxy plugin, adds `req.ip` and `req.localip` */
|
|
357
353
|
export declare class TrustProxyPlugin extends Plugin {
|
package/microserver.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MicroServer
|
|
3
|
-
* @version 3.0.
|
|
3
|
+
* @version 3.0.3
|
|
4
4
|
* @package @radatek/microserver
|
|
5
5
|
* @copyright Darius Kisonas 2022
|
|
6
6
|
* @license MIT
|
|
@@ -118,11 +118,11 @@ export class ServerRequest extends http.IncomingMessage {
|
|
|
118
118
|
rawBodySize;
|
|
119
119
|
_body;
|
|
120
120
|
_isReady;
|
|
121
|
-
constructor(server) {
|
|
121
|
+
constructor(res, server) {
|
|
122
122
|
super(new net.Socket());
|
|
123
|
-
ServerRequest.extend(this, server);
|
|
123
|
+
ServerRequest.extend(this, res, server);
|
|
124
124
|
}
|
|
125
|
-
static extend(req, server) {
|
|
125
|
+
static extend(req, res, server) {
|
|
126
126
|
const reqNew = Object.setPrototypeOf(req, ServerRequest.prototype);
|
|
127
127
|
let ip = req.socket.remoteAddress || '::1';
|
|
128
128
|
if (ip.startsWith('::ffff:'))
|
|
@@ -141,6 +141,15 @@ export class ServerRequest extends http.IncomingMessage {
|
|
|
141
141
|
rawBody: [],
|
|
142
142
|
rawBodySize: 0
|
|
143
143
|
});
|
|
144
|
+
if (req.readable && !req.complete) {
|
|
145
|
+
reqNew._isReady = deferPromise((err) => {
|
|
146
|
+
reqNew._isReady = undefined;
|
|
147
|
+
if (err && res && !res.headersSent) {
|
|
148
|
+
res.statusCode = 'statusCode' in err ? err.statusCode : 400;
|
|
149
|
+
res.end(http.STATUS_CODES[res.statusCode] || 'Error');
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
144
153
|
reqNew.updateUrl(req.url || '/');
|
|
145
154
|
return reqNew;
|
|
146
155
|
}
|
|
@@ -154,6 +163,12 @@ export class ServerRequest extends http.IncomingMessage {
|
|
|
154
163
|
if (res && res instanceof Error)
|
|
155
164
|
throw res;
|
|
156
165
|
}
|
|
166
|
+
setReady(err) {
|
|
167
|
+
this._isReady?.resolve(err);
|
|
168
|
+
}
|
|
169
|
+
setBody(body) {
|
|
170
|
+
this._body = body;
|
|
171
|
+
}
|
|
157
172
|
/** Update request url */
|
|
158
173
|
updateUrl(url) {
|
|
159
174
|
this.url = url;
|
|
@@ -193,7 +208,8 @@ export class ServerResponse extends http.ServerResponse {
|
|
|
193
208
|
isJson;
|
|
194
209
|
headersOnly;
|
|
195
210
|
constructor(server) {
|
|
196
|
-
super(
|
|
211
|
+
super(new http.IncomingMessage(new net.Socket()));
|
|
212
|
+
ServerRequest.extend(this.req, this, server);
|
|
197
213
|
ServerResponse.extend(this);
|
|
198
214
|
}
|
|
199
215
|
static extend(res) {
|
|
@@ -572,17 +588,8 @@ export class MicroServer extends EventEmitter {
|
|
|
572
588
|
}
|
|
573
589
|
/** Default server handler */
|
|
574
590
|
handler(req, res) {
|
|
575
|
-
ServerRequest.extend(req, this);
|
|
591
|
+
ServerRequest.extend(req, res, this);
|
|
576
592
|
ServerResponse.extend(res);
|
|
577
|
-
if (req.readable) {
|
|
578
|
-
req._isReady = deferPromise((err) => {
|
|
579
|
-
req._isReady = undefined;
|
|
580
|
-
if (err) {
|
|
581
|
-
if (!res.headersSent)
|
|
582
|
-
res.error('statusCode' in err ? err.statusCode : 400);
|
|
583
|
-
}
|
|
584
|
-
});
|
|
585
|
-
}
|
|
586
593
|
this._router.walk(this._stack, req, res, () => res.error(404));
|
|
587
594
|
//this.handlerRouter(req, res, () => this.handlerLast(req, res))
|
|
588
595
|
}
|
|
@@ -991,20 +998,9 @@ export class BodyPlugin extends Plugin {
|
|
|
991
998
|
handler(req, res, next) {
|
|
992
999
|
if (req.complete || req.method === 'GET') {
|
|
993
1000
|
if (!req.body)
|
|
994
|
-
req.
|
|
1001
|
+
req.setBody({});
|
|
995
1002
|
return next();
|
|
996
1003
|
}
|
|
997
|
-
req._isReady = deferPromise((err) => {
|
|
998
|
-
req._isReady = undefined;
|
|
999
|
-
if (err) {
|
|
1000
|
-
if (!req.complete)
|
|
1001
|
-
req.pause();
|
|
1002
|
-
if (!res.headersSent)
|
|
1003
|
-
res.error('statusCode' in err ? err.statusCode : 400);
|
|
1004
|
-
}
|
|
1005
|
-
else if (req.complete)
|
|
1006
|
-
res.removeHeader('Connection');
|
|
1007
|
-
});
|
|
1008
1004
|
const contentType = req.headers['content-type'] || '';
|
|
1009
1005
|
if (contentType.startsWith('multipart/form-data')) {
|
|
1010
1006
|
req.pause();
|
|
@@ -1012,44 +1008,35 @@ export class BodyPlugin extends Plugin {
|
|
|
1012
1008
|
return next();
|
|
1013
1009
|
}
|
|
1014
1010
|
if (parseInt(req.headers['content-length'] || '-1') > this._maxBodySize) {
|
|
1015
|
-
return req.
|
|
1011
|
+
return req.setReady(new ResponseError("too big", 413));
|
|
1016
1012
|
}
|
|
1017
1013
|
req.once('error', () => { })
|
|
1018
1014
|
.on('data', chunk => {
|
|
1019
1015
|
req.rawBodySize += chunk.length;
|
|
1020
1016
|
if (req.rawBodySize >= this._maxBodySize)
|
|
1021
|
-
req.
|
|
1017
|
+
req.setReady(new ResponseError("too big", 413));
|
|
1022
1018
|
else
|
|
1023
1019
|
req.rawBody.push(chunk);
|
|
1024
1020
|
})
|
|
1025
1021
|
.once('end', () => {
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
}
|
|
1045
|
-
else
|
|
1046
|
-
req._body = {};
|
|
1047
|
-
}
|
|
1048
|
-
return req._body;
|
|
1049
|
-
},
|
|
1050
|
-
configurable: true,
|
|
1051
|
-
enumerable: true
|
|
1052
|
-
});
|
|
1022
|
+
let charset = contentType.match(/charset=(\S+)/)?.[1];
|
|
1023
|
+
if (charset !== 'utf8' && charset !== 'latin1' && charset !== 'ascii')
|
|
1024
|
+
charset = 'utf8';
|
|
1025
|
+
const bodyString = Buffer.concat(req.rawBody).toString(charset);
|
|
1026
|
+
if (contentType.startsWith('application/x-www-form-urlencoded')) {
|
|
1027
|
+
req.setBody(querystring.parse(bodyString));
|
|
1028
|
+
}
|
|
1029
|
+
else if (bodyString.startsWith('{') || bodyString.startsWith('[')) {
|
|
1030
|
+
try {
|
|
1031
|
+
req.setBody(JSON.parse(bodyString));
|
|
1032
|
+
}
|
|
1033
|
+
catch {
|
|
1034
|
+
return res.jsonError(405);
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
else
|
|
1038
|
+
req.setBody({});
|
|
1039
|
+
req.setReady();
|
|
1053
1040
|
return next();
|
|
1054
1041
|
});
|
|
1055
1042
|
}
|
|
@@ -1070,19 +1057,6 @@ export class UploadPlugin extends Plugin {
|
|
|
1070
1057
|
const contentType = req.headers['content-type'] || '';
|
|
1071
1058
|
if (!contentType.startsWith('multipart/form-data'))
|
|
1072
1059
|
return next();
|
|
1073
|
-
if (!req._isReady) {
|
|
1074
|
-
req._isReady = deferPromise((err) => {
|
|
1075
|
-
req._isReady = undefined;
|
|
1076
|
-
if (err) {
|
|
1077
|
-
req.pause();
|
|
1078
|
-
if (!res.headersSent)
|
|
1079
|
-
res.setHeader('Connection', 'close');
|
|
1080
|
-
res.error('statusCode' in err ? err.statusCode : 400);
|
|
1081
|
-
}
|
|
1082
|
-
else
|
|
1083
|
-
res.removeHeader('Connection');
|
|
1084
|
-
});
|
|
1085
|
-
}
|
|
1086
1060
|
req.pause();
|
|
1087
1061
|
res.setHeader('Connection', 'close');
|
|
1088
1062
|
if (!this._uploadDir)
|
|
@@ -1152,7 +1126,7 @@ export class UploadPlugin extends Plugin {
|
|
|
1152
1126
|
fileStream = undefined;
|
|
1153
1127
|
if (buffer[nextBoundaryIndexEnd] === 45) {
|
|
1154
1128
|
res.removeHeader('Connection');
|
|
1155
|
-
req.
|
|
1129
|
+
req.setReady();
|
|
1156
1130
|
}
|
|
1157
1131
|
buffer = buffer.subarray(nextBoundaryIndex);
|
|
1158
1132
|
}
|
|
@@ -1170,7 +1144,7 @@ export class UploadPlugin extends Plugin {
|
|
|
1170
1144
|
};
|
|
1171
1145
|
const _removeTempFiles = () => {
|
|
1172
1146
|
if (!req.isReady)
|
|
1173
|
-
req.
|
|
1147
|
+
req.setReady(new Error('Upload error'));
|
|
1174
1148
|
if (fileStream) {
|
|
1175
1149
|
fileStream.close();
|
|
1176
1150
|
fileStream = undefined;
|
|
@@ -1181,12 +1155,12 @@ export class UploadPlugin extends Plugin {
|
|
|
1181
1155
|
delete f.filePath;
|
|
1182
1156
|
});
|
|
1183
1157
|
files.splice(0);
|
|
1184
|
-
req.
|
|
1158
|
+
req.setReady();
|
|
1185
1159
|
};
|
|
1186
1160
|
next();
|
|
1187
|
-
req.once('error', () => req.
|
|
1161
|
+
req.once('error', () => req.setReady(new Error('Upload error')))
|
|
1188
1162
|
.on('data', chunk => chunkParse(chunk))
|
|
1189
|
-
.once('end', () => req.
|
|
1163
|
+
.once('end', () => req.setReady(new Error('Upload error')));
|
|
1190
1164
|
res.once('finish', () => _removeTempFiles());
|
|
1191
1165
|
res.once('error', () => _removeTempFiles());
|
|
1192
1166
|
res.once('close', () => _removeTempFiles());
|
|
@@ -1230,9 +1204,12 @@ export class WebSocket extends EventEmitter {
|
|
|
1230
1204
|
this._options.deflate = true;
|
|
1231
1205
|
}
|
|
1232
1206
|
this.ready = true;
|
|
1233
|
-
this._upgrade(key, headers)
|
|
1207
|
+
this._upgrade(key, headers, () => {
|
|
1208
|
+
req.setReady();
|
|
1209
|
+
this.emit('open');
|
|
1210
|
+
});
|
|
1234
1211
|
}
|
|
1235
|
-
_upgrade(key, headers = []) {
|
|
1212
|
+
_upgrade(key, headers = [], cb) {
|
|
1236
1213
|
const digest = crypto.createHash('sha1')
|
|
1237
1214
|
.update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
|
|
1238
1215
|
.digest('base64');
|
|
@@ -1245,7 +1222,7 @@ export class WebSocket extends EventEmitter {
|
|
|
1245
1222
|
'',
|
|
1246
1223
|
''
|
|
1247
1224
|
];
|
|
1248
|
-
this._socket.write(headers.join('\r\n'));
|
|
1225
|
+
this._socket.write(headers.join('\r\n'), cb);
|
|
1249
1226
|
this._socket.on('error', this._errorHandler.bind(this));
|
|
1250
1227
|
this._socket.on('data', this._dataHandler.bind(this));
|
|
1251
1228
|
this._socket.on('close', () => this.emit('close'));
|
|
@@ -1511,7 +1488,6 @@ export class WebSocketPlugin extends Plugin {
|
|
|
1511
1488
|
srv.on('upgrade', this._handler);
|
|
1512
1489
|
}
|
|
1513
1490
|
upgradeHandler(server, req, socket, head) {
|
|
1514
|
-
ServerRequest.extend(req, server);
|
|
1515
1491
|
const host = req.headers.host || '';
|
|
1516
1492
|
const vhostPlugin = server.getPlugin('vhost');
|
|
1517
1493
|
const vserver = vhostPlugin?.vhosts?.[host] || server;
|
|
@@ -1524,7 +1500,7 @@ export class WebSocketPlugin extends Plugin {
|
|
|
1524
1500
|
statusCode: 200,
|
|
1525
1501
|
socket,
|
|
1526
1502
|
server,
|
|
1527
|
-
|
|
1503
|
+
end(data) {
|
|
1528
1504
|
if (res.headersSent)
|
|
1529
1505
|
throw new Error('Headers already sent');
|
|
1530
1506
|
let code = res.statusCode || 403;
|
|
@@ -1538,7 +1514,7 @@ export class WebSocketPlugin extends Plugin {
|
|
|
1538
1514
|
const headers = [
|
|
1539
1515
|
`HTTP/1.1 ${code} ${http.STATUS_CODES[code]}`,
|
|
1540
1516
|
'Connection: close',
|
|
1541
|
-
'Content-Type: text/
|
|
1517
|
+
'Content-Type: text/plain',
|
|
1542
1518
|
`Content-Length: ${Buffer.byteLength(data)}`,
|
|
1543
1519
|
'',
|
|
1544
1520
|
data
|
|
@@ -1547,22 +1523,25 @@ export class WebSocketPlugin extends Plugin {
|
|
|
1547
1523
|
},
|
|
1548
1524
|
error(code) {
|
|
1549
1525
|
res.statusCode = code || 403;
|
|
1550
|
-
res.
|
|
1551
|
-
},
|
|
1552
|
-
end(data) {
|
|
1553
|
-
res.write(data);
|
|
1526
|
+
res.end();
|
|
1554
1527
|
},
|
|
1555
1528
|
send(data) {
|
|
1556
|
-
res.
|
|
1529
|
+
res.end(data);
|
|
1557
1530
|
},
|
|
1558
1531
|
getHeader() { },
|
|
1559
1532
|
setHeader() { }
|
|
1560
1533
|
};
|
|
1534
|
+
ServerRequest.extend(req, res, server);
|
|
1535
|
+
let _ws;
|
|
1536
|
+
Object.defineProperty(req, 'websocket', {
|
|
1537
|
+
get: () => {
|
|
1538
|
+
if (!_ws)
|
|
1539
|
+
_ws = new WebSocket(req, server.config.websocket);
|
|
1540
|
+
return _ws;
|
|
1541
|
+
},
|
|
1542
|
+
enumerable: true
|
|
1543
|
+
});
|
|
1561
1544
|
vserver.handler(req, res);
|
|
1562
|
-
//vserver.handlerRouter(req, res as unknown as ServerResponse, () => res.error(404))
|
|
1563
|
-
}
|
|
1564
|
-
static create(req, options) {
|
|
1565
|
-
return new WebSocket(req, options);
|
|
1566
1545
|
}
|
|
1567
1546
|
}
|
|
1568
1547
|
// #endregion WebSocket
|