bdy 1.8.3-dev → 1.8.4-dev

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.
Files changed (112) hide show
  1. package/distTs/bin/cli.js +5 -0
  2. package/distTs/src/agent/linux.js +119 -0
  3. package/distTs/src/agent/manager.js +395 -0
  4. package/distTs/src/agent/osx.js +139 -0
  5. package/distTs/src/agent/socket/tunnel.js +212 -0
  6. package/distTs/src/agent/socket.js +220 -0
  7. package/distTs/src/agent/system.js +177 -0
  8. package/distTs/src/agent/wait.js +23 -0
  9. package/distTs/src/agent/windows.js +159 -0
  10. package/distTs/src/agent.js +237 -0
  11. package/distTs/src/api/agent.js +84 -0
  12. package/distTs/src/api/buddy.js +117 -0
  13. package/distTs/src/api/socket.js +133 -0
  14. package/distTs/src/cfg.js +238 -0
  15. package/distTs/src/command/agent/install.js +106 -0
  16. package/distTs/src/command/agent/restart.js +27 -0
  17. package/distTs/src/command/agent/run.js +19 -0
  18. package/distTs/src/command/agent/start.js +28 -0
  19. package/distTs/src/command/agent/status.js +35 -0
  20. package/distTs/src/command/agent/stop.js +28 -0
  21. package/distTs/src/command/agent/tunnel/http.js +44 -0
  22. package/distTs/src/command/agent/tunnel/list.js +27 -0
  23. package/distTs/src/command/agent/tunnel/remove.js +28 -0
  24. package/distTs/src/command/agent/tunnel/start.js +34 -0
  25. package/distTs/src/command/agent/tunnel/status.js +31 -0
  26. package/distTs/src/command/agent/tunnel/tcp.js +43 -0
  27. package/distTs/src/command/agent/tunnel/tls.js +43 -0
  28. package/distTs/src/command/agent/tunnel.js +23 -0
  29. package/distTs/src/command/agent/uninstall.js +38 -0
  30. package/distTs/src/command/agent/update.js +38 -0
  31. package/distTs/src/command/agent/version.js +21 -0
  32. package/distTs/src/command/agent.js +29 -0
  33. package/distTs/src/command/config/add/http.js +25 -0
  34. package/distTs/src/command/config/add/tcp.js +25 -0
  35. package/distTs/src/command/config/add/tls.js +25 -0
  36. package/distTs/src/command/config/add.js +15 -0
  37. package/distTs/src/command/config/get/region.js +15 -0
  38. package/distTs/src/command/config/get/timeout.js +15 -0
  39. package/distTs/src/command/config/get/token.js +15 -0
  40. package/distTs/src/command/config/get/tunnel.js +19 -0
  41. package/distTs/src/command/config/get/tunnels.js +15 -0
  42. package/distTs/src/command/config/get/whitelist.js +15 -0
  43. package/distTs/src/command/config/get.js +21 -0
  44. package/distTs/src/command/config/remove/tunnel.js +19 -0
  45. package/distTs/src/command/config/remove.js +11 -0
  46. package/distTs/src/command/config/set/region.js +17 -0
  47. package/distTs/src/command/config/set/timeout.js +17 -0
  48. package/distTs/src/command/config/set/token.js +16 -0
  49. package/distTs/src/command/config/set/whitelist.js +17 -0
  50. package/distTs/src/command/config/set.js +17 -0
  51. package/distTs/src/command/config.js +17 -0
  52. package/distTs/src/command/http.js +30 -0
  53. package/distTs/src/command/pre.js +49 -0
  54. package/distTs/src/command/start.js +28 -0
  55. package/distTs/src/command/tcp.js +30 -0
  56. package/distTs/src/command/tls.js +30 -0
  57. package/distTs/src/command/version.js +13 -0
  58. package/distTs/src/command/vt/close.js +28 -0
  59. package/distTs/src/command/vt/exec.js +79 -0
  60. package/distTs/src/command/vt/storybook.js +90 -0
  61. package/distTs/src/command/vt.js +15 -0
  62. package/distTs/src/format.js +172 -0
  63. package/distTs/src/index.js +40 -0
  64. package/distTs/src/input.js +286 -0
  65. package/distTs/src/logger.js +93 -0
  66. package/distTs/src/output/interactive/tunnel.js +860 -0
  67. package/distTs/src/output/noninteractive/agent/tunnels.js +43 -0
  68. package/distTs/src/output/noninteractive/config/tunnel.js +67 -0
  69. package/distTs/src/output/noninteractive/config/tunnels.js +18 -0
  70. package/distTs/src/output/noninteractive/tunnel.js +59 -0
  71. package/distTs/src/output.js +138 -0
  72. package/distTs/src/server/cert.js +52 -0
  73. package/distTs/src/server/http1.js +74 -0
  74. package/distTs/src/server/http2.js +74 -0
  75. package/distTs/src/server/sftp.js +487 -0
  76. package/distTs/src/server/ssh.js +112 -0
  77. package/distTs/src/server/tls.js +41 -0
  78. package/distTs/src/ssh/client.js +191 -0
  79. package/distTs/src/texts.js +345 -0
  80. package/distTs/src/tunnel/agent.js +100 -0
  81. package/distTs/src/tunnel/compression.js +41 -0
  82. package/distTs/src/tunnel/dns.js +54 -0
  83. package/distTs/src/tunnel/html.js +30 -0
  84. package/distTs/src/tunnel/http/log.js +196 -0
  85. package/distTs/src/tunnel/http/serve.js +132 -0
  86. package/distTs/src/tunnel/http/stream.js +45 -0
  87. package/distTs/src/tunnel/http.js +405 -0
  88. package/distTs/src/tunnel/identification.js +96 -0
  89. package/distTs/src/tunnel/latency.js +71 -0
  90. package/distTs/src/tunnel/tcp.js +92 -0
  91. package/distTs/src/tunnel.js +647 -0
  92. package/distTs/src/types/ciInfo.js +10 -0
  93. package/distTs/src/types/options.js +2 -0
  94. package/distTs/src/types/plugin.js +2 -0
  95. package/distTs/src/types/queue.js +2 -0
  96. package/distTs/src/types/requests.js +2 -0
  97. package/distTs/src/types/resources.js +2 -0
  98. package/distTs/src/types/snapshots.js +2 -0
  99. package/distTs/src/types/storybook.js +2 -0
  100. package/distTs/src/utils.js +437 -0
  101. package/distTs/src/visualTest/browser.js +32 -0
  102. package/distTs/src/visualTest/ci.js +206 -0
  103. package/distTs/src/visualTest/context.js +44 -0
  104. package/distTs/src/visualTest/exec.js +51 -0
  105. package/distTs/src/visualTest/queue.js +43 -0
  106. package/distTs/src/visualTest/requests.js +197 -0
  107. package/distTs/src/visualTest/resources.js +195 -0
  108. package/distTs/src/visualTest/server.js +33 -0
  109. package/distTs/src/visualTest/snapshots.js +109 -0
  110. package/distTs/src/visualTest/utils/parseDom.js +238 -0
  111. package/distTs/src/visualTest/validation.js +18 -0
  112. package/package.json +1 -1
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const zlib_1 = __importDefault(require("zlib"));
7
+ const mime_db_1 = __importDefault(require("mime-db"));
8
+ const accept_negotiator_1 = require("@fastify/accept-negotiator");
9
+ const stream_1 = __importDefault(require("stream"));
10
+ const utils_1 = require("../utils");
11
+ class TunnelCompression {
12
+ static detect(canCompress, reqHeaders, resHeaders) {
13
+ if (!canCompress || resHeaders['content-encoding'])
14
+ return utils_1.TUNNEL_COMPRESSION_METHOD_IDENTITY; // already compressed
15
+ const contentType = resHeaders['content-type'] || 'application/json';
16
+ const mimeData = mime_db_1.default[contentType.split(';', 1)[0].trim().toLowerCase()];
17
+ if (!mimeData || !mimeData.compressible)
18
+ return utils_1.TUNNEL_COMPRESSION_METHOD_IDENTITY;
19
+ const encoding = (0, accept_negotiator_1.negotiate)(reqHeaders['accept-encoding'] || '', [
20
+ utils_1.TUNNEL_COMPRESSION_METHOD_BR,
21
+ utils_1.TUNNEL_COMPRESSION_METHOD_GZIP,
22
+ utils_1.TUNNEL_COMPRESSION_METHOD_DEFLATE,
23
+ ]);
24
+ if (!encoding)
25
+ return utils_1.TUNNEL_COMPRESSION_METHOD_IDENTITY;
26
+ return encoding;
27
+ }
28
+ static compress(method) {
29
+ let outStream;
30
+ if (method === utils_1.TUNNEL_COMPRESSION_METHOD_BR)
31
+ outStream = zlib_1.default.createBrotliCompress();
32
+ else if (method === utils_1.TUNNEL_COMPRESSION_METHOD_GZIP)
33
+ outStream = zlib_1.default.createGzip();
34
+ else if (method === utils_1.TUNNEL_COMPRESSION_METHOD_DEFLATE)
35
+ outStream = zlib_1.default.createDeflate();
36
+ else
37
+ outStream = new stream_1.default.PassThrough();
38
+ return outStream;
39
+ }
40
+ }
41
+ exports.default = TunnelCompression;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const dns_1 = require("dns");
4
+ class TunnelDns {
5
+ constructor(sshIp, domain, subdomain, region, sshId) {
6
+ this.region = region;
7
+ this.sshId = sshId;
8
+ this.sshIp = sshIp;
9
+ this.domain = domain;
10
+ this.subdomain = subdomain;
11
+ this.valid = false;
12
+ this.checking = true;
13
+ this.ts = null;
14
+ }
15
+ check() {
16
+ const r = new dns_1.Resolver();
17
+ // todo custom domain
18
+ const hostname = `${this.subdomain}.${this.region.toLowerCase()}-${this.sshId}.${this.domain}`;
19
+ r.resolveCname(hostname, (err, a1) => {
20
+ if (err || !a1 || a1.length !== 1) {
21
+ this.valid = false;
22
+ this.checking = false;
23
+ }
24
+ else {
25
+ r.resolve4(a1[0], (err, a2) => {
26
+ if (err || !a2 || a2.length !== 1) {
27
+ this.valid = false;
28
+ this.checking = false;
29
+ }
30
+ else {
31
+ this.valid = a2[0] === this.sshIp;
32
+ this.checking = false;
33
+ }
34
+ });
35
+ }
36
+ });
37
+ }
38
+ startChecking() {
39
+ this.stopChecking();
40
+ setTimeout(() => {
41
+ this.check();
42
+ }, 1000);
43
+ this.ts = setInterval(() => {
44
+ this.check();
45
+ }, 15000);
46
+ }
47
+ stopChecking() {
48
+ if (this.ts) {
49
+ clearInterval(this.ts);
50
+ this.ts = null;
51
+ }
52
+ }
53
+ }
54
+ exports.default = TunnelDns;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const fs_1 = require("fs");
4
+ const node_sea_1 = require("node:sea");
5
+ const path_1 = require("path");
6
+ class TunnelHtml {
7
+ static get404() {
8
+ if (!this.html404) {
9
+ if ((0, node_sea_1.isSea)()) {
10
+ this.html404 = (0, node_sea_1.getAsset)('404.html', 'utf8');
11
+ }
12
+ else {
13
+ this.html404 = (0, fs_1.readFileSync)((0, path_1.resolve)(__dirname, 'html/404.html'), 'utf8');
14
+ }
15
+ }
16
+ return this.html404;
17
+ }
18
+ static get503(validTarget) {
19
+ if (!this.html503) {
20
+ if ((0, node_sea_1.isSea)()) {
21
+ this.html503 = (0, node_sea_1.getAsset)('503.html', 'utf8');
22
+ }
23
+ else {
24
+ this.html503 = (0, fs_1.readFileSync)((0, path_1.resolve)(__dirname, 'html/503.html'), 'utf8');
25
+ }
26
+ }
27
+ return this.html503.replace('$SERVICE', validTarget);
28
+ }
29
+ }
30
+ exports.default = TunnelHtml;
@@ -0,0 +1,196 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const events_1 = __importDefault(require("events"));
7
+ const uuid_1 = require("uuid");
8
+ const stream_js_1 = __importDefault(require("./stream.js"));
9
+ const isbinaryfile_1 = require("isbinaryfile");
10
+ const utils_1 = require("../../utils");
11
+ class TunnelHttpLogRequest extends events_1.default {
12
+ constructor(method, headers, url, httpVersion) {
13
+ super();
14
+ this.method = method;
15
+ this.headers = headers;
16
+ this.url = url;
17
+ this.httpVersion = httpVersion;
18
+ this.status = 'NEW';
19
+ this.start = process.hrtime();
20
+ this.finished = false;
21
+ this.id = (0, uuid_1.v4)();
22
+ this.requestBody = new stream_js_1.default(utils_1.TUNNEL_HTTP_LOG_MAX_BODY);
23
+ this.requestBody.once('close', () => {
24
+ this.emit(utils_1.EVENT_TUNNEL_HTTP_NEW_REQUEST_END);
25
+ });
26
+ this.responseBody = new stream_js_1.default(utils_1.TUNNEL_HTTP_LOG_MAX_BODY);
27
+ this.responseBody.once('close', () => {
28
+ this.emit(utils_1.EVENT_TUNNEL_HTTP_NEW_RESPONSE_END);
29
+ });
30
+ }
31
+ response(statusCode, headers) {
32
+ this.status = statusCode;
33
+ this.responseHeaders = headers;
34
+ const end = process.hrtime(this.start);
35
+ this.time = Math.round(end[0] * 1000 + end[1] / 1000000);
36
+ this.finished = true;
37
+ }
38
+ toSocket() {
39
+ let requestBody = null;
40
+ let requestBodyLength = 0;
41
+ let requestBodyTooLarge = false;
42
+ let requestBodyBinary = false;
43
+ let responseBody = null;
44
+ let responseBodyLength = 0;
45
+ let responseBodyTooLarge = false;
46
+ let responseBodyBinary = false;
47
+ if (this.requestBody.realLength > 0) {
48
+ requestBodyLength = this.requestBody.realLength;
49
+ requestBodyTooLarge =
50
+ requestBodyLength >= utils_1.TUNNEL_MAX_REQUEST_SIZE_TO_SYNC;
51
+ requestBodyBinary = (0, isbinaryfile_1.isBinaryFileSync)(this.requestBody.data);
52
+ if (!requestBodyTooLarge && !requestBodyBinary) {
53
+ requestBody = this.requestBody.data.toString('base64');
54
+ }
55
+ }
56
+ if (this.responseBody.realLength > 0) {
57
+ responseBodyLength = this.responseBody.realLength;
58
+ responseBodyTooLarge =
59
+ requestBodyLength >= utils_1.TUNNEL_MAX_REQUEST_SIZE_TO_SYNC;
60
+ responseBodyBinary = (0, isbinaryfile_1.isBinaryFileSync)(this.responseBody.data);
61
+ if (!responseBodyTooLarge && !responseBodyBinary) {
62
+ responseBody = this.responseBody.data.toString('base64');
63
+ }
64
+ }
65
+ return {
66
+ method: this.method,
67
+ headers: this.headers,
68
+ url: this.url,
69
+ httpVersion: this.httpVersion,
70
+ status: this.status,
71
+ finished: this.finished,
72
+ id: this.id,
73
+ responseHeaders: this.responseHeaders,
74
+ time: this.time,
75
+ requestBody,
76
+ requestBodyTooLarge,
77
+ requestBodyBinary,
78
+ requestBodyLength,
79
+ responseBody,
80
+ responseBodyTooLarge,
81
+ responseBodyBinary,
82
+ responseBodyLength,
83
+ };
84
+ }
85
+ }
86
+ class TunnelHttpLog extends events_1.default {
87
+ constructor(log, circuitBreakerThreshold) {
88
+ super();
89
+ this.log = log;
90
+ this.requests = [];
91
+ this.rateLimit = {};
92
+ this.circuitBreaker = {
93
+ active: circuitBreakerThreshold !== null,
94
+ threshold: circuitBreakerThreshold,
95
+ open: false,
96
+ test: false,
97
+ total: 0,
98
+ failed: 0,
99
+ };
100
+ this.tsRateLimit = setInterval(() => {
101
+ this.rateLimit = {};
102
+ }, utils_1.TUNNEL_HTTP_RATE_WINDOW);
103
+ if (this.circuitBreaker.active) {
104
+ this.tsCb = setInterval(() => {
105
+ const t = this.circuitBreaker.total;
106
+ const f = this.circuitBreaker.failed;
107
+ const r = !t ? 0 : f / t;
108
+ this.circuitBreaker.test = false;
109
+ if (!this.circuitBreaker.open) {
110
+ if (f > 0 &&
111
+ t >= utils_1.TUNNEL_HTTP_CB_MIN_REQUESTS &&
112
+ r > this.circuitBreaker.threshold) {
113
+ this.circuitBreaker.open = true;
114
+ }
115
+ }
116
+ else {
117
+ this.circuitBreaker.open = false;
118
+ this.circuitBreaker.test = true;
119
+ }
120
+ this.circuitBreaker.total = 0;
121
+ this.circuitBreaker.failed = 0;
122
+ }, utils_1.TUNNEL_HTTP_CB_WINDOW);
123
+ }
124
+ }
125
+ stop() {
126
+ if (this.tsRateLimit) {
127
+ clearInterval(this.tsRateLimit);
128
+ this.tsRateLimit = null;
129
+ }
130
+ if (this.tsCb) {
131
+ clearInterval(this.tsCb);
132
+ this.tsCb = null;
133
+ }
134
+ }
135
+ getIp(req) {
136
+ let ip;
137
+ if (req.httpVersion === '2.0') {
138
+ ip = req.socket.stream ? req.socket.stream.remoteAddress : '::1';
139
+ }
140
+ else {
141
+ ip = req.socket.remoteAddress;
142
+ }
143
+ return ip;
144
+ }
145
+ increaseRateLimit(req) {
146
+ const ip = this.getIp(req);
147
+ if (!this.rateLimit[ip])
148
+ this.rateLimit[ip] = 0;
149
+ this.rateLimit[ip] += 1;
150
+ }
151
+ isRateLimited(req) {
152
+ const ip = this.getIp(req);
153
+ if (!this.rateLimit[ip])
154
+ return false;
155
+ return this.rateLimit[ip] >= utils_1.TUNNEL_HTTP_RATE_LIMIT;
156
+ }
157
+ isCircuitBreakerOpen() {
158
+ return this.circuitBreaker.active && this.circuitBreaker.open;
159
+ }
160
+ newRequest(method, headers, url, httpVersion, originalReq) {
161
+ this.increaseRateLimit(originalReq);
162
+ if (this.log) {
163
+ const r = new TunnelHttpLogRequest(method, headers, url, httpVersion);
164
+ this.requests.unshift(r);
165
+ if (this.requests.length > utils_1.TUNNEL_HTTP_LOG_MAX_REQUESTS)
166
+ this.requests.pop();
167
+ this.emit(utils_1.EVENT_TUNNEL_HTTP_NEW_REQUEST, r);
168
+ return r;
169
+ }
170
+ }
171
+ increaseCircuitBreaker(statusCode) {
172
+ if (this.circuitBreaker.active && !this.circuitBreaker.open) {
173
+ this.circuitBreaker.total += 1;
174
+ if (statusCode >= 500)
175
+ this.circuitBreaker.failed += 1;
176
+ if (this.circuitBreaker.test) {
177
+ const t = this.circuitBreaker.total;
178
+ const f = this.circuitBreaker.failed;
179
+ const rate = !t ? 0 : f / t;
180
+ if (f > 0 &&
181
+ t >= utils_1.TUNNEL_HTTP_CB_MIN_REQUESTS &&
182
+ rate > this.circuitBreaker.threshold) {
183
+ this.circuitBreaker.open = true;
184
+ }
185
+ }
186
+ }
187
+ }
188
+ newResponse(req, statusCode, headers, logRequest) {
189
+ this.increaseCircuitBreaker(statusCode);
190
+ if (logRequest && this.log) {
191
+ logRequest.response(statusCode, headers);
192
+ this.emit(utils_1.EVENT_TUNNEL_HTTP_NEW_RESPONSE, logRequest);
193
+ }
194
+ }
195
+ }
196
+ exports.default = TunnelHttpLog;
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const events_1 = __importDefault(require("events"));
7
+ const path_1 = __importDefault(require("path"));
8
+ const path_is_inside_1 = __importDefault(require("path-is-inside"));
9
+ const range_parser_1 = __importDefault(require("range-parser"));
10
+ const fs_1 = __importDefault(require("fs"));
11
+ const promises_1 = __importDefault(require("fs/promises"));
12
+ const content_disposition_1 = __importDefault(require("content-disposition"));
13
+ const mime_types_1 = __importDefault(require("mime-types"));
14
+ const stream_1 = __importDefault(require("stream"));
15
+ class TunnelHttpServe extends events_1.default {
16
+ constructor(serve) {
17
+ super();
18
+ this.serve = path_1.default.resolve(serve);
19
+ }
20
+ triggerError(err) {
21
+ this.emit('error', err);
22
+ this.emit('close');
23
+ }
24
+ trigger404() {
25
+ const s = new stream_1.default.Readable();
26
+ s.push('Not found');
27
+ s.push(null);
28
+ this.emit('response', 404, {
29
+ 'content-type': 'text/plain',
30
+ }, s);
31
+ this.emit('close');
32
+ }
33
+ triggerResponse(statusCode, headers, stream) {
34
+ this.emit('response', statusCode, headers, stream);
35
+ this.emit('close');
36
+ }
37
+ async process(req) {
38
+ if (!['GET', 'HEAD'].includes(req.method)) {
39
+ this.trigger404();
40
+ return;
41
+ }
42
+ let relativePath;
43
+ try {
44
+ relativePath = decodeURIComponent(new URL(req.url, 'https://localhost').pathname);
45
+ }
46
+ catch (err) {
47
+ this.triggerError(err);
48
+ return;
49
+ }
50
+ let absolutePath = path_1.default.join(this.serve, relativePath);
51
+ if (!(0, path_is_inside_1.default)(absolutePath, this.serve)) {
52
+ this.trigger404();
53
+ return;
54
+ }
55
+ let stats;
56
+ try {
57
+ stats = await promises_1.default.lstat(absolutePath);
58
+ }
59
+ catch {
60
+ this.trigger404();
61
+ return;
62
+ }
63
+ if (stats.isDirectory()) {
64
+ absolutePath = path_1.default.join(absolutePath, 'index.html');
65
+ try {
66
+ stats = await promises_1.default.lstat(absolutePath);
67
+ }
68
+ catch {
69
+ this.trigger404();
70
+ return;
71
+ }
72
+ }
73
+ if (!stats.isFile()) {
74
+ this.trigger404();
75
+ return;
76
+ }
77
+ const streamOpts = {};
78
+ const headers = {};
79
+ let statusCode = 200;
80
+ if (req.headers.range && stats.size) {
81
+ const range = (0, range_parser_1.default)(stats.size, req.headers.range);
82
+ if (typeof range === 'object' && range.type === 'bytes') {
83
+ const { start, end } = range[0];
84
+ statusCode = 206;
85
+ streamOpts.start = start;
86
+ streamOpts.end = end;
87
+ }
88
+ else {
89
+ statusCode = 416;
90
+ headers['content-range'] = `bytes */${stats.size}`;
91
+ }
92
+ }
93
+ const { base } = path_1.default.parse(absolutePath);
94
+ headers['content-length'] = stats.size;
95
+ headers['content-disposition'] = (0, content_disposition_1.default)(base, {
96
+ type: 'inline',
97
+ });
98
+ headers['accept-ranges'] = 'bytes';
99
+ headers['last-modified'] = stats.mtime.toUTCString();
100
+ const contentType = mime_types_1.default.contentType(base);
101
+ if (contentType) {
102
+ headers['content-type'] = contentType;
103
+ }
104
+ if (streamOpts.start !== undefined && streamOpts.end !== undefined) {
105
+ headers['content-range'] =
106
+ `bytes ${streamOpts.start}-${streamOpts.end}/${stats.size}`;
107
+ headers['content-length'] = streamOpts.end - streamOpts.start + 1;
108
+ }
109
+ if (!req.headers.range && req.headers['if-modified-since']) {
110
+ const ims = Math.floor(Date.parse(req.headers['if-modified-since']) / 1000);
111
+ const mt = Math.floor(stats.mtime.getTime() / 1000);
112
+ if (mt <= ims) {
113
+ this.triggerResponse(304, headers);
114
+ return;
115
+ }
116
+ }
117
+ if (req.method === 'HEAD') {
118
+ this.triggerResponse(statusCode, headers);
119
+ return;
120
+ }
121
+ let stream;
122
+ try {
123
+ stream = fs_1.default.createReadStream(absolutePath, streamOpts);
124
+ }
125
+ catch (err) {
126
+ this.triggerError(err);
127
+ return;
128
+ }
129
+ this.triggerResponse(statusCode, headers, stream);
130
+ }
131
+ }
132
+ exports.default = TunnelHttpServe;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const stream_1 = require("stream");
4
+ class TunnelHttpStream extends stream_1.Transform {
5
+ constructor(maxSize) {
6
+ super();
7
+ this.maxSize = maxSize;
8
+ this.data = Buffer.alloc(0);
9
+ this.realLength = 0;
10
+ this.tooLarge = false;
11
+ this.backPressure = [];
12
+ }
13
+ _transform(chunk, encoding, callback) {
14
+ if (!this.tooLarge) {
15
+ if (this.data.length + chunk.length > this.maxSize) {
16
+ this.tooLarge = true;
17
+ this.data = Buffer.alloc(0);
18
+ }
19
+ else {
20
+ this.data = Buffer.concat([this.data, chunk]);
21
+ }
22
+ }
23
+ this.realLength += chunk.length;
24
+ this.backPressure.push(chunk);
25
+ this._pushBackPressure();
26
+ callback();
27
+ }
28
+ _pushBackPressure() {
29
+ while (this.backPressure.length > 0) {
30
+ const chunk = this.backPressure.shift();
31
+ if (!this.push(chunk)) {
32
+ this.removeAllListeners('drain');
33
+ this.once('drain', () => {
34
+ this._pushBackPressure();
35
+ });
36
+ break;
37
+ }
38
+ }
39
+ }
40
+ pipeToNothing(done) {
41
+ this.once('end', done);
42
+ this.resume();
43
+ }
44
+ }
45
+ exports.default = TunnelHttpStream;