@milaboratories/pframes-rs-serv 1.1.18 → 1.1.19
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/dist/export.cjs +16 -17
- package/dist/export.cjs.map +1 -1
- package/dist/export.d.ts +6 -2
- package/dist/export.d.ts.map +1 -1
- package/dist/export.js +16 -15
- package/dist/export.js.map +1 -1
- package/dist/fs-store.cjs +83 -87
- package/dist/fs-store.cjs.map +1 -1
- package/dist/fs-store.d.ts +14 -10
- package/dist/fs-store.d.ts.map +1 -1
- package/dist/fs-store.js +83 -85
- package/dist/fs-store.js.map +1 -1
- package/dist/handler.cjs +132 -157
- package/dist/handler.cjs.map +1 -1
- package/dist/handler.d.ts +8 -4
- package/dist/handler.d.ts.map +1 -1
- package/dist/handler.js +132 -155
- package/dist/handler.js.map +1 -1
- package/dist/index.cjs +13 -18
- package/dist/index.d.ts +6 -6
- package/dist/index.js +6 -6
- package/dist/parquet-server.cjs +95 -101
- package/dist/parquet-server.cjs.map +1 -1
- package/dist/parquet-server.d.ts +16 -12
- package/dist/parquet-server.d.ts.map +1 -1
- package/dist/parquet-server.js +95 -98
- package/dist/parquet-server.js.map +1 -1
- package/dist/serve.cjs +98 -94
- package/dist/serve.cjs.map +1 -1
- package/dist/serve.d.ts +11 -2
- package/dist/serve.d.ts.map +1 -1
- package/dist/serve.js +98 -92
- package/dist/serve.js.map +1 -1
- package/dist/utils/etag.cjs +5 -7
- package/dist/utils/etag.cjs.map +1 -1
- package/dist/utils/etag.js +5 -5
- package/dist/utils/etag.js.map +1 -1
- package/dist/utils/filename.cjs +9 -11
- package/dist/utils/filename.cjs.map +1 -1
- package/dist/utils/filename.js +9 -9
- package/dist/utils/filename.js.map +1 -1
- package/dist/utils/headers.cjs +28 -21
- package/dist/utils/headers.cjs.map +1 -1
- package/dist/utils/headers.js +28 -19
- package/dist/utils/headers.js.map +1 -1
- package/dist/utils/method.cjs +7 -7
- package/dist/utils/method.cjs.map +1 -1
- package/dist/utils/method.js +7 -5
- package/dist/utils/method.js.map +1 -1
- package/dist/utils/options.cjs +111 -134
- package/dist/utils/options.cjs.map +1 -1
- package/dist/utils/options.js +111 -132
- package/dist/utils/options.js.map +1 -1
- package/dist/utils/range.cjs +26 -31
- package/dist/utils/range.cjs.map +1 -1
- package/dist/utils/range.js +26 -29
- package/dist/utils/range.js.map +1 -1
- package/dist/utils/status.cjs +17 -17
- package/dist/utils/status.cjs.map +1 -1
- package/dist/utils/status.js +17 -15
- package/dist/utils/status.js.map +1 -1
- package/package.json +4 -4
- package/src/parquet-server.ts +16 -2
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/utils/etag.d.ts +0 -15
- package/dist/utils/etag.d.ts.map +0 -1
- package/dist/utils/filename.d.ts +0 -4
- package/dist/utils/filename.d.ts.map +0 -1
- package/dist/utils/headers.d.ts +0 -31
- package/dist/utils/headers.d.ts.map +0 -1
- package/dist/utils/index.d.ts +0 -8
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/method.d.ts +0 -6
- package/dist/utils/method.d.ts.map +0 -1
- package/dist/utils/options.d.ts +0 -64
- package/dist/utils/options.d.ts.map +0 -1
- package/dist/utils/range.d.ts +0 -4
- package/dist/utils/range.d.ts.map +0 -1
- package/dist/utils/status.d.ts +0 -17
- package/dist/utils/status.d.ts.map +0 -1
package/dist/handler.cjs
CHANGED
|
@@ -1,171 +1,146 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
var plModelCommon = require('@milaboratories/pl-model-common');
|
|
13
|
-
|
|
1
|
+
const require_filename = require("./utils/filename.cjs");
|
|
2
|
+
const require_etag = require("./utils/etag.cjs");
|
|
3
|
+
const require_headers = require("./utils/headers.cjs");
|
|
4
|
+
const require_options = require("./utils/options.cjs");
|
|
5
|
+
const require_range = require("./utils/range.cjs");
|
|
6
|
+
const require_method = require("./utils/method.cjs");
|
|
7
|
+
const require_status = require("./utils/status.cjs");
|
|
8
|
+
let node_stream_promises = require("node:stream/promises");
|
|
9
|
+
let node_crypto = require("node:crypto");
|
|
10
|
+
let _milaboratories_pl_model_common = require("@milaboratories/pl-model-common");
|
|
11
|
+
//#region src/handler.ts
|
|
14
12
|
/** Main request handler for parquet files */
|
|
15
13
|
function handleRequest(request, response, store) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
else {
|
|
105
|
-
// RFC 9110 section 15.3.1: OK response
|
|
106
|
-
response.setHeader(headers.HeaderName.ContentLength, result.size);
|
|
107
|
-
response.writeHead(status.StatusCode.Ok);
|
|
108
|
-
}
|
|
109
|
-
// RFC 9110 section 9.3.2: HEAD method must not return message body
|
|
110
|
-
if (method.isHead(method$1)) {
|
|
111
|
-
return void response.end();
|
|
112
|
-
}
|
|
113
|
-
try {
|
|
114
|
-
return await promises.pipeline(result.data, response, { signal });
|
|
115
|
-
}
|
|
116
|
-
catch (error) {
|
|
117
|
-
if (!plModelCommon.isAbortError(error))
|
|
118
|
-
throw error;
|
|
119
|
-
}
|
|
120
|
-
},
|
|
121
|
-
});
|
|
14
|
+
response.sendDate = true;
|
|
15
|
+
response.strictContentLength = true;
|
|
16
|
+
response.setHeader(require_headers.HeaderName.ContentLength, 0);
|
|
17
|
+
response.setHeader(require_headers.HeaderName.CacheControl, require_headers.HeaderValue.CacheControl);
|
|
18
|
+
const method = request.method;
|
|
19
|
+
if (!require_method.isGetOrHead(method)) {
|
|
20
|
+
response.setHeader(require_headers.HeaderName.Allow, require_headers.HeaderValue.Allow);
|
|
21
|
+
response.writeHead(require_status.StatusCode.MethodNotAllowed).end();
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const filename = require_filename.getFilenameFromUrl(request);
|
|
25
|
+
if (filename === null) {
|
|
26
|
+
response.writeHead(require_status.StatusCode.Gone).end();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
response.setHeader(require_headers.HeaderName.AcceptRanges, require_headers.HeaderValue.AcceptRanges);
|
|
30
|
+
response.setHeader(require_headers.HeaderName.ContentType, require_headers.HeaderValue.ContentType);
|
|
31
|
+
const etag = require_etag.createETag(filename);
|
|
32
|
+
const mtime = /* @__PURE__ */ new Date(0);
|
|
33
|
+
response.setHeader(require_headers.HeaderName.CacheControl, require_headers.HeaderValue.CacheControl);
|
|
34
|
+
response.setHeader(require_headers.HeaderName.ETag, etag);
|
|
35
|
+
response.setHeader(require_headers.HeaderName.LastModified, mtime.toUTCString());
|
|
36
|
+
const options = new require_options.Options(request);
|
|
37
|
+
if (options.preconditionFailed(etag, mtime)) {
|
|
38
|
+
response.writeHead(require_status.StatusCode.PreconditionFailed).end();
|
|
39
|
+
return;
|
|
40
|
+
} else if (options.notModified(etag, mtime)) {
|
|
41
|
+
response.writeHead(require_status.StatusCode.NotModified).end();
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const range = require_range.parseRange(request);
|
|
45
|
+
if (range === null) {
|
|
46
|
+
response.writeHead(require_status.StatusCode.BadRequest).end();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const abortController = new AbortController();
|
|
50
|
+
request.on("close", () => abortController.abort());
|
|
51
|
+
const signal = abortController.signal;
|
|
52
|
+
store.request(filename, {
|
|
53
|
+
method,
|
|
54
|
+
range,
|
|
55
|
+
signal,
|
|
56
|
+
callback: async (result) => {
|
|
57
|
+
if (request.destroyed) if (response.destroyed) return;
|
|
58
|
+
else if (response.headersSent) {
|
|
59
|
+
response.end();
|
|
60
|
+
return;
|
|
61
|
+
} else {
|
|
62
|
+
response.setHeader(require_headers.HeaderName.Connection, require_headers.HeaderValue.Connection);
|
|
63
|
+
response.writeHead(require_status.StatusCode.RequestTimeout).end();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
switch (result.type) {
|
|
67
|
+
case "InternalError":
|
|
68
|
+
response.writeHead(require_status.StatusCode.InternalServerError).end();
|
|
69
|
+
return;
|
|
70
|
+
case "NotFound":
|
|
71
|
+
response.writeHead(require_status.StatusCode.NotFound).end();
|
|
72
|
+
return;
|
|
73
|
+
case "RangeNotSatisfiable":
|
|
74
|
+
response.setHeader(require_headers.HeaderName.ContentRange, `bytes */${result.size}`);
|
|
75
|
+
response.writeHead(require_status.StatusCode.RangeNotSatisfiable).end();
|
|
76
|
+
return;
|
|
77
|
+
case "Ok": break;
|
|
78
|
+
}
|
|
79
|
+
if (require_method.isGet(method) && !result.data) {
|
|
80
|
+
response.writeHead(require_status.StatusCode.GatewayTimeout).end();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (range) {
|
|
84
|
+
response.setHeader(require_headers.HeaderName.ContentLength, result.range.end - result.range.start + 1);
|
|
85
|
+
response.setHeader(require_headers.HeaderName.ContentRange, `bytes ${result.range.start}-${result.range.end}/${result.size}`);
|
|
86
|
+
response.writeHead(require_status.StatusCode.PartialContent);
|
|
87
|
+
} else {
|
|
88
|
+
response.setHeader(require_headers.HeaderName.ContentLength, result.size);
|
|
89
|
+
response.writeHead(require_status.StatusCode.Ok);
|
|
90
|
+
}
|
|
91
|
+
if (require_method.isHead(method)) {
|
|
92
|
+
response.end();
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
return await (0, node_stream_promises.pipeline)(result.data, response, { signal });
|
|
97
|
+
} catch (error) {
|
|
98
|
+
if (!(0, _milaboratories_pl_model_common.isAbortError)(error)) throw error;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
});
|
|
122
102
|
}
|
|
123
103
|
/**
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
104
|
+
* Create a request handler for serving files from an object store
|
|
105
|
+
* compatible with HTTP/1.1 as defined in RFC 9110 and RFC 9111:
|
|
106
|
+
* - <https://datatracker.ietf.org/doc/html/rfc9110>
|
|
107
|
+
* - <https://datatracker.ietf.org/doc/html/rfc9111>
|
|
108
|
+
*
|
|
109
|
+
* Accepts only paths of the form `/<filename>.parquet`, returns 410 Gone otherwise
|
|
110
|
+
* Assumes that files are immutable (and sets cache headers accordingly)
|
|
111
|
+
*/
|
|
132
112
|
function createRequestHandler(options) {
|
|
133
|
-
|
|
134
|
-
|
|
113
|
+
const { store } = options;
|
|
114
|
+
return (request, response) => handleRequest(request, response, store);
|
|
135
115
|
}
|
|
136
116
|
/** Request authorization middleware */
|
|
137
117
|
function authorizeRequest(request, response, handler, authHeader) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
if (receivedBuffer.byteLength !== expectedBuffer.byteLength ||
|
|
157
|
-
!node_crypto.timingSafeEqual(receivedBuffer, expectedBuffer)) {
|
|
158
|
-
response.setHeader(headers.HeaderName.WWWAuthenticate, headers.HeaderValue.WWWAuthenticate);
|
|
159
|
-
return void response.writeHead(status.StatusCode.Unauthorized).end();
|
|
160
|
-
}
|
|
161
|
-
return handler(request, response);
|
|
118
|
+
response.sendDate = true;
|
|
119
|
+
response.strictContentLength = true;
|
|
120
|
+
response.setHeader(require_headers.HeaderName.ContentLength, 0);
|
|
121
|
+
const actualHeader = request.headers[require_headers.HeaderName.Authorization];
|
|
122
|
+
if (!actualHeader || actualHeader.length !== authHeader.length) {
|
|
123
|
+
response.setHeader(require_headers.HeaderName.WWWAuthenticate, require_headers.HeaderValue.WWWAuthenticate);
|
|
124
|
+
response.writeHead(require_status.StatusCode.Unauthorized).end();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const encoder = new TextEncoder();
|
|
128
|
+
const receivedBuffer = encoder.encode(actualHeader);
|
|
129
|
+
const expectedBuffer = encoder.encode(authHeader);
|
|
130
|
+
if (receivedBuffer.byteLength !== expectedBuffer.byteLength || !(0, node_crypto.timingSafeEqual)(receivedBuffer, expectedBuffer)) {
|
|
131
|
+
response.setHeader(require_headers.HeaderName.WWWAuthenticate, require_headers.HeaderValue.WWWAuthenticate);
|
|
132
|
+
response.writeHead(require_status.StatusCode.Unauthorized).end();
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
return handler(request, response);
|
|
162
136
|
}
|
|
163
137
|
/** Apply Bearer token authorization to @param handler */
|
|
164
138
|
function authorizeRequestHandler(handler, authToken) {
|
|
165
|
-
|
|
166
|
-
|
|
139
|
+
const authHeader = `Bearer ${authToken}`;
|
|
140
|
+
return (request, response) => authorizeRequest(request, response, handler, authHeader);
|
|
167
141
|
}
|
|
168
|
-
|
|
142
|
+
//#endregion
|
|
169
143
|
exports.authorizeRequestHandler = authorizeRequestHandler;
|
|
170
144
|
exports.createRequestHandler = createRequestHandler;
|
|
171
|
-
|
|
145
|
+
|
|
146
|
+
//# sourceMappingURL=handler.cjs.map
|
package/dist/handler.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.cjs","sources":["../src/handler.ts"],"sourcesContent":["import type { IncomingMessage, RequestListener, ServerResponse } from \"node:http\";\nimport { pipeline } from \"node:stream/promises\";\nimport { timingSafeEqual } from \"node:crypto\";\nimport type { PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\nimport {\n createETag,\n getFilenameFromUrl,\n parseRange,\n isGetOrHead,\n isGet,\n isHead,\n Options,\n StatusCode,\n HeaderName,\n HeaderValue,\n} from \"./utils\";\nimport { isAbortError } from \"@milaboratories/pl-model-common\";\n\n/** Main request handler for parquet files */\nfunction handleRequest(\n request: IncomingMessage,\n response: ServerResponse,\n store: PFrameInternal.ObjectStore,\n): void {\n // RFC 9110 section 6.6.1: Date header should be present in all responses\n response.sendDate = true;\n // RFC 9110 section 8.6: Content-Length 0 as default for error responses\n response.strictContentLength = true;\n response.setHeader(HeaderName.ContentLength, 0);\n // Note: setting Content-Length disables Node.js default Transfer-Encoding: chunked\n\n // RFC 9111 section 5.2: Cache-Control header with public allows to cache authenticated responses\n response.setHeader(HeaderName.CacheControl, HeaderValue.CacheControl);\n\n // RFC 9110 section 15.5.6: Method not allowed\n const method = request.method;\n if (!isGetOrHead(method)) {\n response.setHeader(HeaderName.Allow, HeaderValue.Allow);\n return void response.writeHead(StatusCode.MethodNotAllowed).end();\n }\n\n const filename = getFilenameFromUrl(request);\n if (filename === null) {\n return void response.writeHead(StatusCode.Gone).end();\n }\n\n // From now on we are sure that the response would be a Parquet file\n response.setHeader(HeaderName.AcceptRanges, HeaderValue.AcceptRanges);\n response.setHeader(HeaderName.ContentType, HeaderValue.ContentType);\n\n // RFC 9110 section 8.8.3: ETag header is used for cache versioning\n const etag = createETag(filename);\n // RFC 9110 section 8.8.2: Last-Modified header field for cache validation\n const mtime = new Date(0); // Using fake fixed date since files are immutable\n // RFC 9111 section 5.2: Cache-Control header with public allows to cache authenticated responses\n response.setHeader(HeaderName.CacheControl, HeaderValue.CacheControl);\n response.setHeader(HeaderName.ETag, etag);\n response.setHeader(HeaderName.LastModified, mtime.toUTCString());\n\n const options = new Options(request);\n // RFC 9110 section 13.1.1: If-Match precondition evaluation\n // RFC 9110 section 13.1.4: If-Unmodified-Since precondition evaluation\n if (options.preconditionFailed(etag, mtime)) {\n return void response.writeHead(StatusCode.PreconditionFailed).end();\n }\n // RFC 9110 section 13.1.2: If-None-Match precondition evaluation\n // RFC 9110 section 13.1.3: If-Modified-Since precondition evaluation\n else if (options.notModified(etag, mtime)) {\n return void response.writeHead(StatusCode.NotModified).end();\n }\n\n const range = parseRange(request);\n if (range === null) {\n return void response.writeHead(StatusCode.BadRequest).end();\n }\n\n const abortController = new AbortController();\n request.on(\"close\", () => abortController.abort());\n const signal = abortController.signal;\n\n store.request(filename, {\n method,\n range,\n signal,\n // pipeline automatically destroys the streams if they were not gracefully closed\n callback: async (result) => {\n if (request.destroyed) {\n // request has timed out, close the connection\n if (response.destroyed) {\n return;\n } else if (response.headersSent) {\n return void response.end();\n } else {\n response.setHeader(HeaderName.Connection, HeaderValue.Connection);\n return void response.writeHead(StatusCode.RequestTimeout).end();\n }\n }\n\n switch (result.type) {\n case \"InternalError\":\n // object store encountered network error, retry by client can help\n return void response.writeHead(StatusCode.InternalServerError).end();\n case \"NotFound\":\n // RFC 9110 section 15.4.5: Not found\n return void response.writeHead(StatusCode.NotFound).end();\n case \"RangeNotSatisfiable\":\n // RFC 9110 section 15.5.17: Range not satisfiable\n response.setHeader(HeaderName.ContentRange, `bytes */${result.size}`);\n return void response.writeHead(StatusCode.RangeNotSatisfiable).end();\n case \"Ok\":\n break;\n }\n\n if (isGet(method) && !result.data) {\n // object store implementation is incorrect, retry by client cannot help\n return void response.writeHead(StatusCode.GatewayTimeout).end();\n }\n\n if (range) {\n // RFC 9110 section 14.4: Partial content response\n response.setHeader(HeaderName.ContentLength, result.range.end - result.range.start + 1);\n response.setHeader(\n HeaderName.ContentRange,\n `bytes ${result.range.start}-${result.range.end}/${result.size}`,\n );\n response.writeHead(StatusCode.PartialContent);\n } else {\n // RFC 9110 section 15.3.1: OK response\n response.setHeader(HeaderName.ContentLength, result.size);\n response.writeHead(StatusCode.Ok);\n }\n\n // RFC 9110 section 9.3.2: HEAD method must not return message body\n if (isHead(method)) {\n return void response.end();\n }\n\n try {\n return await pipeline(result.data!, response, { signal });\n } catch (error: unknown) {\n if (!isAbortError(error)) throw error;\n }\n },\n });\n}\n\n/**\n * Create a request handler for serving files from an object store\n * compatible with HTTP/1.1 as defined in RFC 9110 and RFC 9111:\n * - <https://datatracker.ietf.org/doc/html/rfc9110>\n * - <https://datatracker.ietf.org/doc/html/rfc9111>\n *\n * Accepts only paths of the form `/<filename>.parquet`, returns 410 Gone otherwise\n * Assumes that files are immutable (and sets cache headers accordingly)\n */\nexport function createRequestHandler(\n options: PFrameInternal.RequestHandlerOptions,\n): RequestListener {\n const { store } = options;\n return (request, response) => handleRequest(request, response, store);\n}\n\n/** Request authorization middleware */\nfunction authorizeRequest(\n request: IncomingMessage,\n response: ServerResponse,\n handler: RequestListener,\n authHeader: string,\n): void {\n // RFC 9110 section 6.6.1: Date header should be present in all responses\n response.sendDate = true;\n // RFC 9110 section 8.6: Content-Length 0 as default for error responses\n response.strictContentLength = true;\n response.setHeader(HeaderName.ContentLength, 0);\n // Note: setting Content-Length disables Node.js default Transfer-Encoding: chunked\n\n const actualHeader = request.headers[HeaderName.Authorization];\n\n // Early length check to avoid unnecessary processing\n if (!actualHeader || actualHeader.length !== authHeader.length) {\n // RFC 9110 section 11.6.1: WWW-Authenticate header field\n response.setHeader(HeaderName.WWWAuthenticate, HeaderValue.WWWAuthenticate);\n return void response.writeHead(StatusCode.Unauthorized).end();\n }\n\n // Use timing-safe comparison to prevent timing attacks\n // <https://developers.cloudflare.com/workers/examples/protect-against-timing-attacks/>\n const encoder = new TextEncoder();\n const receivedBuffer = encoder.encode(actualHeader);\n const expectedBuffer = encoder.encode(authHeader);\n\n if (\n receivedBuffer.byteLength !== expectedBuffer.byteLength ||\n !timingSafeEqual(receivedBuffer, expectedBuffer)\n ) {\n response.setHeader(HeaderName.WWWAuthenticate, HeaderValue.WWWAuthenticate);\n return void response.writeHead(StatusCode.Unauthorized).end();\n }\n\n return handler(request, response);\n}\n\n/** Apply Bearer token authorization to @param handler */\nexport function authorizeRequestHandler(\n handler: RequestListener,\n authToken: PFrameInternal.HttpAuthorizationToken,\n): RequestListener {\n const authHeader = `Bearer ${authToken}`;\n return (request, response) => authorizeRequest(request, response, handler, authHeader);\n}\n"],"names":["HeaderName","HeaderValue","method","isGetOrHead","StatusCode","filename","getFilenameFromUrl","etag","createETag","options","Options","range","parseRange","isGet","isHead","pipeline","isAbortError","timingSafeEqual"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"handler.cjs","names":["HeaderName","HeaderValue","isGetOrHead","StatusCode","getFilenameFromUrl","createETag","Options","parseRange","isGet","isHead"],"sources":["../src/handler.ts"],"sourcesContent":["import type { IncomingMessage, RequestListener, ServerResponse } from \"node:http\";\nimport { pipeline } from \"node:stream/promises\";\nimport { timingSafeEqual } from \"node:crypto\";\nimport type { PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\nimport {\n createETag,\n getFilenameFromUrl,\n parseRange,\n isGetOrHead,\n isGet,\n isHead,\n Options,\n StatusCode,\n HeaderName,\n HeaderValue,\n} from \"./utils\";\nimport { isAbortError } from \"@milaboratories/pl-model-common\";\n\n/** Main request handler for parquet files */\nfunction handleRequest(\n request: IncomingMessage,\n response: ServerResponse,\n store: PFrameInternal.ObjectStore,\n): void {\n // RFC 9110 section 6.6.1: Date header should be present in all responses\n response.sendDate = true;\n // RFC 9110 section 8.6: Content-Length 0 as default for error responses\n response.strictContentLength = true;\n response.setHeader(HeaderName.ContentLength, 0);\n // Note: setting Content-Length disables Node.js default Transfer-Encoding: chunked\n\n // RFC 9111 section 5.2: Cache-Control header with public allows to cache authenticated responses\n response.setHeader(HeaderName.CacheControl, HeaderValue.CacheControl);\n\n // RFC 9110 section 15.5.6: Method not allowed\n const method = request.method;\n if (!isGetOrHead(method)) {\n response.setHeader(HeaderName.Allow, HeaderValue.Allow);\n return void response.writeHead(StatusCode.MethodNotAllowed).end();\n }\n\n const filename = getFilenameFromUrl(request);\n if (filename === null) {\n return void response.writeHead(StatusCode.Gone).end();\n }\n\n // From now on we are sure that the response would be a Parquet file\n response.setHeader(HeaderName.AcceptRanges, HeaderValue.AcceptRanges);\n response.setHeader(HeaderName.ContentType, HeaderValue.ContentType);\n\n // RFC 9110 section 8.8.3: ETag header is used for cache versioning\n const etag = createETag(filename);\n // RFC 9110 section 8.8.2: Last-Modified header field for cache validation\n const mtime = new Date(0); // Using fake fixed date since files are immutable\n // RFC 9111 section 5.2: Cache-Control header with public allows to cache authenticated responses\n response.setHeader(HeaderName.CacheControl, HeaderValue.CacheControl);\n response.setHeader(HeaderName.ETag, etag);\n response.setHeader(HeaderName.LastModified, mtime.toUTCString());\n\n const options = new Options(request);\n // RFC 9110 section 13.1.1: If-Match precondition evaluation\n // RFC 9110 section 13.1.4: If-Unmodified-Since precondition evaluation\n if (options.preconditionFailed(etag, mtime)) {\n return void response.writeHead(StatusCode.PreconditionFailed).end();\n }\n // RFC 9110 section 13.1.2: If-None-Match precondition evaluation\n // RFC 9110 section 13.1.3: If-Modified-Since precondition evaluation\n else if (options.notModified(etag, mtime)) {\n return void response.writeHead(StatusCode.NotModified).end();\n }\n\n const range = parseRange(request);\n if (range === null) {\n return void response.writeHead(StatusCode.BadRequest).end();\n }\n\n const abortController = new AbortController();\n request.on(\"close\", () => abortController.abort());\n const signal = abortController.signal;\n\n store.request(filename, {\n method,\n range,\n signal,\n // pipeline automatically destroys the streams if they were not gracefully closed\n callback: async (result) => {\n if (request.destroyed) {\n // request has timed out, close the connection\n if (response.destroyed) {\n return;\n } else if (response.headersSent) {\n return void response.end();\n } else {\n response.setHeader(HeaderName.Connection, HeaderValue.Connection);\n return void response.writeHead(StatusCode.RequestTimeout).end();\n }\n }\n\n switch (result.type) {\n case \"InternalError\":\n // object store encountered network error, retry by client can help\n return void response.writeHead(StatusCode.InternalServerError).end();\n case \"NotFound\":\n // RFC 9110 section 15.4.5: Not found\n return void response.writeHead(StatusCode.NotFound).end();\n case \"RangeNotSatisfiable\":\n // RFC 9110 section 15.5.17: Range not satisfiable\n response.setHeader(HeaderName.ContentRange, `bytes */${result.size}`);\n return void response.writeHead(StatusCode.RangeNotSatisfiable).end();\n case \"Ok\":\n break;\n }\n\n if (isGet(method) && !result.data) {\n // object store implementation is incorrect, retry by client cannot help\n return void response.writeHead(StatusCode.GatewayTimeout).end();\n }\n\n if (range) {\n // RFC 9110 section 14.4: Partial content response\n response.setHeader(HeaderName.ContentLength, result.range.end - result.range.start + 1);\n response.setHeader(\n HeaderName.ContentRange,\n `bytes ${result.range.start}-${result.range.end}/${result.size}`,\n );\n response.writeHead(StatusCode.PartialContent);\n } else {\n // RFC 9110 section 15.3.1: OK response\n response.setHeader(HeaderName.ContentLength, result.size);\n response.writeHead(StatusCode.Ok);\n }\n\n // RFC 9110 section 9.3.2: HEAD method must not return message body\n if (isHead(method)) {\n return void response.end();\n }\n\n try {\n return await pipeline(result.data!, response, { signal });\n } catch (error: unknown) {\n if (!isAbortError(error)) throw error;\n }\n },\n });\n}\n\n/**\n * Create a request handler for serving files from an object store\n * compatible with HTTP/1.1 as defined in RFC 9110 and RFC 9111:\n * - <https://datatracker.ietf.org/doc/html/rfc9110>\n * - <https://datatracker.ietf.org/doc/html/rfc9111>\n *\n * Accepts only paths of the form `/<filename>.parquet`, returns 410 Gone otherwise\n * Assumes that files are immutable (and sets cache headers accordingly)\n */\nexport function createRequestHandler(\n options: PFrameInternal.RequestHandlerOptions,\n): RequestListener {\n const { store } = options;\n return (request, response) => handleRequest(request, response, store);\n}\n\n/** Request authorization middleware */\nfunction authorizeRequest(\n request: IncomingMessage,\n response: ServerResponse,\n handler: RequestListener,\n authHeader: string,\n): void {\n // RFC 9110 section 6.6.1: Date header should be present in all responses\n response.sendDate = true;\n // RFC 9110 section 8.6: Content-Length 0 as default for error responses\n response.strictContentLength = true;\n response.setHeader(HeaderName.ContentLength, 0);\n // Note: setting Content-Length disables Node.js default Transfer-Encoding: chunked\n\n const actualHeader = request.headers[HeaderName.Authorization];\n\n // Early length check to avoid unnecessary processing\n if (!actualHeader || actualHeader.length !== authHeader.length) {\n // RFC 9110 section 11.6.1: WWW-Authenticate header field\n response.setHeader(HeaderName.WWWAuthenticate, HeaderValue.WWWAuthenticate);\n return void response.writeHead(StatusCode.Unauthorized).end();\n }\n\n // Use timing-safe comparison to prevent timing attacks\n // <https://developers.cloudflare.com/workers/examples/protect-against-timing-attacks/>\n const encoder = new TextEncoder();\n const receivedBuffer = encoder.encode(actualHeader);\n const expectedBuffer = encoder.encode(authHeader);\n\n if (\n receivedBuffer.byteLength !== expectedBuffer.byteLength ||\n !timingSafeEqual(receivedBuffer, expectedBuffer)\n ) {\n response.setHeader(HeaderName.WWWAuthenticate, HeaderValue.WWWAuthenticate);\n return void response.writeHead(StatusCode.Unauthorized).end();\n }\n\n return handler(request, response);\n}\n\n/** Apply Bearer token authorization to @param handler */\nexport function authorizeRequestHandler(\n handler: RequestListener,\n authToken: PFrameInternal.HttpAuthorizationToken,\n): RequestListener {\n const authHeader = `Bearer ${authToken}`;\n return (request, response) => authorizeRequest(request, response, handler, authHeader);\n}\n"],"mappings":"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"}
|
package/dist/handler.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { PFrameInternal } from "@milaboratories/pl-model-middle-layer";
|
|
2
|
+
import { RequestListener } from "node:http";
|
|
3
|
+
|
|
4
|
+
//#region src/handler.d.ts
|
|
3
5
|
/**
|
|
4
6
|
* Create a request handler for serving files from an object store
|
|
5
7
|
* compatible with HTTP/1.1 as defined in RFC 9110 and RFC 9111:
|
|
@@ -9,7 +11,9 @@ import type { PFrameInternal } from "@milaboratories/pl-model-middle-layer";
|
|
|
9
11
|
* Accepts only paths of the form `/<filename>.parquet`, returns 410 Gone otherwise
|
|
10
12
|
* Assumes that files are immutable (and sets cache headers accordingly)
|
|
11
13
|
*/
|
|
12
|
-
|
|
14
|
+
declare function createRequestHandler(options: PFrameInternal.RequestHandlerOptions): RequestListener;
|
|
13
15
|
/** Apply Bearer token authorization to @param handler */
|
|
14
|
-
|
|
16
|
+
declare function authorizeRequestHandler(handler: RequestListener, authToken: PFrameInternal.HttpAuthorizationToken): RequestListener;
|
|
17
|
+
//#endregion
|
|
18
|
+
export { authorizeRequestHandler, createRequestHandler };
|
|
15
19
|
//# sourceMappingURL=handler.d.ts.map
|
package/dist/handler.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","
|
|
1
|
+
{"version":3,"file":"handler.d.ts","names":[],"sources":["../src/handler.ts"],"mappings":";;;;;;AA2JA;;;;;;;iBAAgB,oBAAA,CACd,OAAA,EAAS,cAAA,CAAe,qBAAA,GACvB,eAAA;;iBA8Ca,uBAAA,CACd,OAAA,EAAS,eAAA,EACT,SAAA,EAAW,cAAA,CAAe,sBAAA,GACzB,eAAA"}
|