minimalistic-server 0.0.2 → 0.0.4
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/index.mjs +102 -10
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -1160,6 +1160,7 @@ export class FileResponse extends Response {
|
|
|
1160
1160
|
#dataPromise = null;
|
|
1161
1161
|
|
|
1162
1162
|
#maxChunkSize = 16 * 1024 * 1024;
|
|
1163
|
+
#fragmentRequestMap = new WeakMap();
|
|
1163
1164
|
|
|
1164
1165
|
constructor(filePath, code = 200, contentType = null, cookies = null) {
|
|
1165
1166
|
super();
|
|
@@ -1169,18 +1170,39 @@ export class FileResponse extends Response {
|
|
|
1169
1170
|
this.setCookies(cookies);
|
|
1170
1171
|
}
|
|
1171
1172
|
|
|
1172
|
-
async getCode() {
|
|
1173
|
+
async getCode(headers = null) {
|
|
1174
|
+
const requestedFragment = await this.#getFragmentRequest(headers);
|
|
1173
1175
|
const data = await this.#retreiveData();
|
|
1176
|
+
|
|
1177
|
+
if (requestedFragment) {
|
|
1178
|
+
return 206;
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1174
1181
|
return data.code;
|
|
1175
1182
|
}
|
|
1176
1183
|
|
|
1177
|
-
async getHeaders() {
|
|
1184
|
+
async getHeaders(headers = null) {
|
|
1185
|
+
const requestedFragment = await this.#getFragmentRequest(headers);
|
|
1178
1186
|
const data = await this.#retreiveData();
|
|
1187
|
+
|
|
1188
|
+
if (requestedFragment) {
|
|
1189
|
+
return {
|
|
1190
|
+
'Content-Range': `bytes ${requestedFragment.offset}-${requestedFragment.offset + requestedFragment.size - 1}/${data.size}`,
|
|
1191
|
+
...data.headers,
|
|
1192
|
+
};
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1179
1195
|
return data.headers;
|
|
1180
1196
|
}
|
|
1181
1197
|
|
|
1182
|
-
async getBody() {
|
|
1198
|
+
async getBody(headers = null) {
|
|
1199
|
+
const requestedFragment = await this.#getFragmentRequest(headers);
|
|
1183
1200
|
const data = await this.#retreiveData();
|
|
1201
|
+
|
|
1202
|
+
if (requestedFragment) {
|
|
1203
|
+
return () => data.body(requestedFragment);
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1184
1206
|
return data.body;
|
|
1185
1207
|
}
|
|
1186
1208
|
|
|
@@ -1190,9 +1212,69 @@ export class FileResponse extends Response {
|
|
|
1190
1212
|
|
|
1191
1213
|
setFilePath(filePath) {
|
|
1192
1214
|
this.#filePath = filePath;
|
|
1215
|
+
this.#dataPromise = null;
|
|
1193
1216
|
}
|
|
1194
1217
|
|
|
1195
|
-
async
|
|
1218
|
+
async #getFragmentRequest(headers) {
|
|
1219
|
+
let result = this.#fragmentRequestMap.get(headers);
|
|
1220
|
+
|
|
1221
|
+
if (result === undefined && headers?.['range']) {
|
|
1222
|
+
if (headers['range'].includes(',')) {
|
|
1223
|
+
this.#fragmentRequestMap.set(headers, null);
|
|
1224
|
+
return null;
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
const numbers = headers['range']
|
|
1228
|
+
.trim()
|
|
1229
|
+
.replace('bytes=', '')
|
|
1230
|
+
.split(/\b\s*-\s*/gm)
|
|
1231
|
+
.map(x => {
|
|
1232
|
+
x = +x;
|
|
1233
|
+
|
|
1234
|
+
if (isNaN(x) || x < Number.MIN_SAFE_INTEGER || x > Number.MAX_SAFE_INTEGER) {
|
|
1235
|
+
return null;
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
return Math.floor(x);
|
|
1239
|
+
});
|
|
1240
|
+
|
|
1241
|
+
const data = await this.#retreiveData();
|
|
1242
|
+
|
|
1243
|
+
if (data.code < 200 || data.code > 299 || typeof data.body !== 'function') {
|
|
1244
|
+
this.#fragmentRequestMap.set(headers, null);
|
|
1245
|
+
return null;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
let offset = numbers[0] ?? 0;
|
|
1249
|
+
|
|
1250
|
+
if (offset < 0) {
|
|
1251
|
+
offset = data.size + offset;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
if (offset >= data.size) {
|
|
1255
|
+
offset = data.size - 1;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
let size = (numbers[1] ?? (data.size - 1)) - offset + 1;
|
|
1259
|
+
|
|
1260
|
+
if (size < 0) {
|
|
1261
|
+
size = 0;
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
size = Math.min(size, data.size - offset);
|
|
1265
|
+
|
|
1266
|
+
result = {
|
|
1267
|
+
offset,
|
|
1268
|
+
size,
|
|
1269
|
+
};
|
|
1270
|
+
|
|
1271
|
+
this.#fragmentRequestMap.set(headers, result);
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
return result ?? null;
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
async * #getBodyStream(fragmentRequest) {
|
|
1196
1278
|
const data = await this.#retreiveData();
|
|
1197
1279
|
|
|
1198
1280
|
if (typeof data.body !== 'function') {
|
|
@@ -1203,12 +1285,19 @@ export class FileResponse extends Response {
|
|
|
1203
1285
|
let filehandle;
|
|
1204
1286
|
|
|
1205
1287
|
try {
|
|
1288
|
+
const requestedPosition = fragmentRequest?.offset ?? 0;
|
|
1289
|
+
const requestedSize = fragmentRequest?.size ?? data.size;
|
|
1290
|
+
|
|
1206
1291
|
filehandle = await fs.open(this.#filePath, 'r');
|
|
1207
1292
|
|
|
1208
|
-
|
|
1209
|
-
|
|
1293
|
+
if (requestedPosition > 0) {
|
|
1294
|
+
await filehandle.read(Buffer.alloc(0), 0, 0, requestedPosition);
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
for (let offset = 0; offset < requestedSize; offset += this.#maxChunkSize) {
|
|
1298
|
+
const size = Math.min(this.#maxChunkSize, requestedSize - offset);
|
|
1210
1299
|
const chunk = await filehandle.read(Buffer.alloc(size), 0, size);
|
|
1211
|
-
yield chunk;
|
|
1300
|
+
yield chunk.buffer;
|
|
1212
1301
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
1213
1302
|
}
|
|
1214
1303
|
} finally {
|
|
@@ -1224,7 +1313,7 @@ export class FileResponse extends Response {
|
|
|
1224
1313
|
try {
|
|
1225
1314
|
filehandle = await fs.open(this.#filePath, 'r');
|
|
1226
1315
|
const size = (await filehandle.stat()).size;
|
|
1227
|
-
const body = size > this.#maxChunkSize ? (
|
|
1316
|
+
const body = size > this.#maxChunkSize ? (fragmentRequest => this.#getBodyStream(fragmentRequest)) : await filehandle.readFile();
|
|
1228
1317
|
|
|
1229
1318
|
resolve({
|
|
1230
1319
|
code: this.#code,
|
|
@@ -1530,12 +1619,15 @@ async function handleRequest(req, routes, staticFileDirectory) {
|
|
|
1530
1619
|
message: 'Invalid data'
|
|
1531
1620
|
}, 400);
|
|
1532
1621
|
|
|
1622
|
+
let requestHeaders;
|
|
1623
|
+
|
|
1533
1624
|
try {
|
|
1534
1625
|
const request = new Request(req);
|
|
1535
1626
|
|
|
1536
1627
|
const method = request.getMethod();
|
|
1537
1628
|
const path = request.getPath();
|
|
1538
1629
|
const pathParams = {};
|
|
1630
|
+
requestHeaders = request.getHeaders();
|
|
1539
1631
|
|
|
1540
1632
|
let routeHandler = routes;
|
|
1541
1633
|
let handleOptions = false;
|
|
@@ -1584,7 +1676,7 @@ async function handleRequest(req, routes, staticFileDirectory) {
|
|
|
1584
1676
|
|
|
1585
1677
|
if (method === 'OPTIONS' && typeof routeHandler?.[`/${method}/`] !== 'function') {
|
|
1586
1678
|
handleOptions = true;
|
|
1587
|
-
routeHandler = routeHandler?.[`/${
|
|
1679
|
+
routeHandler = routeHandler?.[`/${requestHeaders?.['access-control-request-method']}/`.toUpperCase()];
|
|
1588
1680
|
} else {
|
|
1589
1681
|
routeHandler = routeHandler?.[`/${method}/`];
|
|
1590
1682
|
}
|
|
@@ -1613,7 +1705,7 @@ async function handleRequest(req, routes, staticFileDirectory) {
|
|
|
1613
1705
|
}
|
|
1614
1706
|
|
|
1615
1707
|
try {
|
|
1616
|
-
return [await response.getCode(), await response.getHeaders(), await response.getBody()];
|
|
1708
|
+
return [await response.getCode(requestHeaders), await response.getHeaders(requestHeaders), await response.getBody(requestHeaders)];
|
|
1617
1709
|
} catch (error) {
|
|
1618
1710
|
console.error(error);
|
|
1619
1711
|
|