-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathform-data.js
More file actions
96 lines (84 loc) · 3.94 KB
/
form-data.js
File metadata and controls
96 lines (84 loc) · 3.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
import { FORM_MULTIPART, FORM_URL_ENCODED, OCTET_STREAM } from '@shgysk8zer0/consts/mimes.js';
const PATTERN = /^(\r\n)?(?:Content-Disposition:\s?form-data;\s?name="(?<name>[^"]*)";?)(?:\s?filename="(?<filename>[^"]*)")?;?(?:\r\nContent-Type:\s?(?<contentType>[^\r\n]+))?;?(\r\n){2}(?<data>[^])?(\r\n)?$/i;
/**
* Parse a multipart/form-data body and extract form fields and files.
*
* @deprecated This function is potentially vulnerable to ReDoS attacks and is not necessary in node >= 20
* @see https://github.com/shgysk8zer0/node-http/issues/2
* @param {string} body - The raw string of the multipart/form-data body.
* @param {string} contentType - The Content-Type header specifying the boundary.
* @returns {FormData} - A FormData object containing the parsed data.
* @throws {TypeError} - If the body or contentType is not a string.
* @throws {Error} - If the contentType is not valid for multipart/form-data.
*/
export function parseMultipartFormData(body, contentType) {
console.warn('parseMultipartFormData() is deprecated and will be removed in version 2.0.0');
if (typeof body !== 'string') {
throw new TypeError('body must be a string.');
} else if (typeof contentType !== 'string') {
throw new TypeError('contentType must be a string.');
} else if (! contentType.startsWith(FORM_MULTIPART)) {
throw new Error(`Invalid Content-Type, expected ${FORM_MULTIPART}`);
}
const boundary = contentType.split(';')[1].trim().split('=')[1];
const formData = new FormData();
for (const part of body.split(`--${boundary}`)) {
// End of body will be `--${boundary}--`, so final part will be "--" with newlines.
if (part.trim().length > 2) {
const { name, filename, contentType, data = '' } = PATTERN.exec(part)?.groups ?? {};
if (typeof filename === 'string') {
formData.append(name, new File([data], filename, { type: contentType ?? OCTET_STREAM }));
} else {
formData.append(name, data);
}
}
}
return formData;
}
/**
* Parse a URL-encoded form data body and convert it into FormData.
*
* @deprecated Node >= 20 offers native form data handling via `await new Request().formData()`
* @param {string} body - The raw string of the URL-encoded form data body.
* @param {string} contentType - The Content-Type header specifying the encoding.
* @returns {FormData} - A FormData object containing the parsed data.
* @throws {TypeError} - If the body or contentType is not a string.
* @throws {Error} - If the contentType is not valid for URL-encoded form data.
*/
export function parseUrlEncodedFormData(body, contentType) {
if (typeof body !== 'string') {
throw new TypeError('body must be a string.');
} else if (typeof contentType !== 'string') {
throw new TypeError('contentType must be a string.');
} else if (! contentType.startsWith(FORM_URL_ENCODED)) {
throw new Error(`Invalid Content-Type, expected ${FORM_URL_ENCODED}`);
}
const params = new URLSearchParams(body);
const formData = new FormData();
for (const [key, value] of params) {
formData.append(key, value);
}
return formData;
}
/**
* Parse the raw body data based on the content type and return it as FormData.
*
* @param {string} body - The raw body data to be parsed.
* @param {string} contentType - The Content-Type header specifying the encoding.
* @returns {FormData} - A FormData object containing the parsed data.
* @throws {TypeError} - If the body or contentType is not a string.
* @throws {Error} - If the contentType is not supported or invalid.
*/
export function parseFormData(body, contentType) {
if (typeof contentType !== 'string') {
throw new TypeError('contentType must be a string.');
} else if (typeof body !== 'string') {
throw new TypeError('body must be a string.');
} else if (contentType.startsWith(FORM_MULTIPART)) {
return parseMultipartFormData(body, contentType);
} else if (contentType === FORM_URL_ENCODED) {
return parseUrlEncodedFormData(body, contentType);
} else {
throw new Error(`Unsupported contentType: ${contentType}`);
}
}