UNPKG

5.39 kBJavaScriptView Raw
1import { combine } from "./context.js";
2import { accepts } from './content-negotiation.js';
3import { payloadTooLarge } from '@worker-tools/response-creators';
4export const JSON = 'application/json';
5export const FORM = 'application/x-www-form-urlencoded';
6export const FORM_DATA = 'multipart/form-data';
7export const TEXT_HTML = 'text/html';
8export const TEXT_PLAIN = 'text/plain';
9/** Standard MIME type for binary data */
10export const BINARY = 'application/octet-stream';
11/** Non-standard MIME type for binary data. Sometimes used, so included anyway. */
12export const X_BINARY = 'application/x-binary';
13const defaultBody = [
14 FORM,
15 FORM_DATA,
16 JSON,
17 BINARY,
18 X_BINARY,
19 TEXT_HTML,
20 TEXT_PLAIN,
21];
22// Not possible to provide a fallback rn: https://github.com/microsoft/TypeScript/issues/48073
23const _isString = (x) => !(x[1] instanceof File);
24const _isFile = (x) => x[1] instanceof File;
25const isBodyTextContext = (nx) => { var _a; return (_a = nx.accepted) === null || _a === void 0 ? void 0 : _a.startsWith('text/'); };
26const isBodyVendorJSONContext = (nx) => { var _a; return ((_a = nx.accepted) === null || _a === void 0 ? void 0 : _a.startsWith('application/')) && nx.accepted.endsWith('+json'); };
27// const isBodyVendorBinaryContext = <J = any>(nx: BodyContext<J>): nx is BodyVendorBinaryContext =>
28// nx.accepted?.startsWith('application/vnd.')
29const MB = 1024 ** 2;
30async function checkSize(req, maxSize) {
31 let size = 0;
32 await req.clone().body.pipeTo(new WritableStream({
33 write(chunk, ctrl) {
34 size += chunk.byteLength;
35 if (size > maxSize) {
36 ctrl.error(new Error('Payload too large'));
37 }
38 }
39 }));
40 return size <= maxSize;
41}
42export const bodyParser = (opts = {}) => async (ax) => {
43 var _a;
44 const x = await ax;
45 const nx = x;
46 const ok = await checkSize(x.request, (_a = opts.maxSize) !== null && _a !== void 0 ? _a : 1 * MB);
47 if (!ok)
48 throw payloadTooLarge();
49 switch (nx.accepted) {
50 case JSON: {
51 nx.body = nx.json = await x.request.json();
52 return nx;
53 }
54 case FORM: {
55 nx.body = nx.form = new URLSearchParams(await x.request.text());
56 // FIXME: Multiple values per key??
57 // nx.form = Object.fromEntries(form);
58 return nx;
59 }
60 case FORM_DATA: {
61 nx.body = nx.formData = await x.request.formData();
62 // FIXME: Multiple values per key??
63 // const tuples = [...formData];
64 // nx.form = Object.fromEntries(tuples.filter(isString));
65 // nx.files = Object.fromEntries(tuples.filter(isFile));
66 return nx;
67 }
68 case BINARY:
69 case X_BINARY: {
70 nx.body = nx.arrayBuffer = await x.request.arrayBuffer();
71 nx.blob = new Blob([nx.arrayBuffer]); // TODO: does this copy??
72 return nx;
73 }
74 default: {
75 if (isBodyTextContext(nx)) {
76 nx.body = nx.text = await x.request.text();
77 }
78 else if (isBodyVendorJSONContext(nx)) {
79 nx.body = nx.json = await x.request.json();
80 return nx;
81 // } else if (isBodyVendorBinaryContext(nx)) {
82 // nx.body = nx.buffer = await x.request.arrayBuffer();
83 // nx.blob = new Blob([nx.buffer]) // TODO: does this copy??
84 // return nx;
85 }
86 else {
87 // Anything else gets the binary treatment (outside of scope of type system)
88 nx.body = nx.buffer = await x.request.arrayBuffer();
89 nx.blob = new Blob([nx.buffer]);
90 return nx;
91 }
92 return nx;
93 }
94 }
95};
96export const defaultBodyParser = (options) => combine(accepts(defaultBody), bodyParser(options));
97// type ErrorOf<T> = T extends { error?: infer E } ? E : never
98// (async () => {
99// const ctx: Context = { request: new Request('/'), effects: [], waitUntil: (_f: any) => {}, handled: Promise.resolve(null as any) }
100// const z = provides([])(accepts([])(ctx))
101// const x = await parseBody()(accepts(['text/x-foo', 'application/vnd.github.v3+json', FORM, FORM_DATA])(ctx))
102// if (x.accepted === 'application/vnd.github.v3+json') {
103// x.body
104// } else if (x.accepted === 'text/x-foo') {
105// x.body
106// } else if (x.accepted === 'application/x-www-form-urlencoded') {
107// x.body
108// }
109// const y = await bodyParser()(ctx)
110// if (y.accepted === 'application/x-www-form-urlencoded') {
111// y.bodyParams
112// y.body
113// }
114// if (y.accepted === 'multipart/form-data') {
115// y.formData
116// y.body
117// }
118// if (y.accepted === 'application/foobar+json') {
119// y.json
120// y.body
121// }
122// // if (x.accepted === 'application/x-www-form-urlencoded') {
123// // x.body
124// // x.bodyParams
125// // x.form
126// // }
127// // else if (x.accepted === 'multipart/form-data') {
128// // x.formData
129// // x.form
130// // x.files
131// // } else if (x.accepted === 'application/octet-stream' || x.accepted === 'application/x-binary') {
132// // x.buffer
133// // x.blob
134// // } else if (x.accepted === 'application/vnd.github.v3+json') {
135// // } else if (x.accepted === 'text/foo') {
136// // x.text
137// // }
138// })
139//# sourceMappingURL=body-parser.js.map
\No newline at end of file