Created
February 9, 2026 22:10
-
-
Save DinoChiesa/d187c90774671e246a1edd251c2e67bb to your computer and use it in GitHub Desktop.
parse multipart/form-data in JavaScript, for Apigee X
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| function parseMultipartPart(part) { | |
| var lines = part.split(/\r\n|\n/); | |
| var name = null; | |
| var value = []; | |
| var state = 0; | |
| for (var i = 0; i < lines.length; i++) { | |
| var line = lines[i]; | |
| switch (state) { | |
| case 0 /* awaiting content-disposition */: | |
| { | |
| var lowerCaseLine = line.toLowerCase(); | |
| if (lowerCaseLine.startsWith("content-disposition:")) { | |
| var nameMatch = /name=\"([^\"]+)\"/.exec(line); | |
| if (nameMatch && nameMatch.length > 1) { | |
| name = nameMatch[1]; | |
| state = 1; | |
| } | |
| } | |
| } | |
| break; | |
| case 1 /* awaiting end of headers */: | |
| if (line.trim() === "") { | |
| // Empty line, part content starts after this | |
| state = 2; | |
| } | |
| break; | |
| case 2 /* Reading part content */: | |
| value.push(line); | |
| break; | |
| default: | |
| throw new Error("parse error"); | |
| } | |
| } | |
| var resultValue = value.join("\n"); | |
| if (resultValue.endsWith("\n")) { | |
| resultValue = resultValue.slice(0, -1); | |
| } | |
| return { | |
| name: name, | |
| value: resultValue, | |
| }; | |
| } | |
| function parseMultiPart(eachPart) { | |
| var ctype = context.getVariable("request.header.content-type"); | |
| // Example | |
| // Content-Type: multipart/form-data; boundary=---------------------------1837170403803086655542689190 | |
| var parts = ctype.split(";").map((p) => p.trim()); | |
| // print("examining part0: (" + parts[0] + ")"); | |
| if (parts[0] != "multipart/form-data") { | |
| throw new Error("Not a multipart/form-data message"); | |
| } | |
| var boundaryPart = parts.find((v) => v.startsWith("boundary=")); | |
| var boundary = | |
| boundaryPart && boundaryPart.split("=").map((p) => p.trim())[1]; | |
| var payload = context.getVariable("request.content"); | |
| parts = payload.split("--" + boundary).map((p) => p.trim()); | |
| if (parts && parts.length) { | |
| var L = parts.length; | |
| if (parts[L - 1] == "--") { | |
| // end of all parts marker | |
| var count = 0; | |
| parts.forEach((part, ix) => { | |
| if (part && part != "--") { | |
| var parsed = parseMultipartPart(part); | |
| eachPart(parsed, ix); | |
| count++; | |
| } | |
| }); | |
| context.setVariable("formpart.count", String(count)); | |
| } else { | |
| throw new Error("Could not find the final part delimiter"); | |
| } | |
| } else { | |
| context.setVariable("formpart.count", "0"); | |
| } | |
| } | |
| parseMultiPart((parsed, ix) => { | |
| context.setVariable("formpart." + ix + ".name", parsed.name); | |
| context.setVariable("formpart." + ix + ".value", parsed.value); | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment