Skip to content

Commit f151081

Browse files
authored
Standardize POST canonicalization query strings with pywb (#68)
* Make non-GET query canonicalization consistent with new spec This is part of bringing consistency between pywb and warcio.js with regard to how query parameters are constructed from request bodies for non-GET requests. The more complicated test is duplicated in pywb to help ensure that the results are consistent across our toolsets/packages.
1 parent 7fa516a commit f151081

File tree

2 files changed

+50
-6
lines changed

2 files changed

+50
-6
lines changed

src/lib/utils.ts

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,13 +157,41 @@ export function jsonToQueryParams(json: string | any, ignoreInvalid = true) {
157157
return key + "." + ++dupes[key] + "_";
158158
};
159159

160-
try {
161-
JSON.stringify(json, (k, v) => {
162-
if (!["object", "function"].includes(typeof v)) {
163-
q.set(getKey(k), v);
160+
const parser = (jsonObj: object, key="") => {
161+
let queryValue = "";
162+
163+
// if object, attempt to recurse through key/value pairs
164+
if (typeof(jsonObj) === "object" && !(jsonObj instanceof Array)) {
165+
try {
166+
for (const [key, value] of Object.entries(jsonObj)) {
167+
parser(value, key);
168+
}
169+
} catch (e) {
170+
// special case for null
171+
if (jsonObj === null) {
172+
queryValue = "null";
173+
}
174+
}
175+
}
176+
177+
// if array, recurse through values, re-using key
178+
else if (jsonObj instanceof Array) {
179+
for (let i=0; i < jsonObj.length; i++) {
180+
parser(jsonObj[i], key);
164181
}
165-
return v;
166-
});
182+
}
183+
184+
if (["string", "number", "boolean"].includes(typeof(jsonObj))) {
185+
queryValue = jsonObj.toString();
186+
}
187+
188+
if (queryValue) {
189+
q.set(getKey(key), queryValue);
190+
}
191+
};
192+
193+
try {
194+
parser(json);
167195
} catch (e) {
168196
if (!ignoreInvalid) {
169197
throw e;

test/testUtils.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,22 @@ describe("utils", () => {
3434
).toBe("abc=def&data=bar&bar=2&a=3&a.2_=4&bar.2_=123&a.3_=5");
3535
});
3636

37+
test("another json with more complicated data", () => {
38+
expect(
39+
toQuery({
40+
"type": "event",
41+
"id": 44.0,
42+
"float": 35.7,
43+
"values": [true, false, null],
44+
"source": {
45+
"type": "component",
46+
"id": "a+b&c= d",
47+
"values": [3, 4]
48+
}
49+
})
50+
).toBe("type=event&id=44&float=35.7&values=true&values.2_=false&values.3_=null&type.2_=component&id.2_=a%2Bb%26c%3D+d&values.4_=3&values.5_=4");
51+
});
52+
3753
test("post-to-get empty", () => {
3854
const request = {
3955
postData: "",

0 commit comments

Comments
 (0)