Skip to content

Commit 033d010

Browse files
authored
Merge pull request #62 from gulugulubing/maxDepthInPolicy
add maxDepth check in defautlDeserializePolicy
2 parents 4a0ae85 + a9275fd commit 033d010

File tree

1 file changed

+75
-8
lines changed

1 file changed

+75
-8
lines changed

source/iopipe/json/serialize.d

Lines changed: 75 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,28 @@ import std.format;
3333

3434
struct DefaultDeserializationPolicy(bool caseInsensitive = false) {
3535
ReleasePolicy relPol = ReleasePolicy.afterMembers; // default policy
36+
int maxDepthAvailable = 64;
3637

3738
this(ReleasePolicy relPol) {
3839
this.relPol = relPol;
3940
}
4041

42+
this(int maxDepthAvailable) {
43+
this.maxDepthAvailable = maxDepthAvailable;
44+
}
45+
46+
this(ReleasePolicy relPol, int maxDepthAvailable) {
47+
this.relPol = relPol;
48+
this.maxDepthAvailable = maxDepthAvailable;
49+
}
50+
51+
auto onObjectBegin(JT, T)(ref JT tokenizer, ref T item) {
52+
if (--maxDepthAvailable < 0) {
53+
throw new JSONIopipeException("Maximum parse depth exceeded");
54+
}
55+
return .onObjectBegin(this, tokenizer, item);
56+
}
57+
4158
void onField(JT, T, C)(
4259
ref JT tokenizer,
4360
ref T item,
@@ -49,6 +66,11 @@ struct DefaultDeserializationPolicy(bool caseInsensitive = false) {
4966
tokenizer.releaseParsed();
5067
}
5168
}
69+
70+
void onObjectEnd(JT, T, C)(ref JT tokenizer, ref T item, ref C context) {
71+
.onObjectEnd(this, tokenizer, item, context);
72+
++maxDepthAvailable;
73+
}
5274
}
5375

5476

@@ -68,6 +90,59 @@ unittest
6890
assert(s.age == 30);
6991
}
7092

93+
unittest
94+
{
95+
// Test maxDepth on deserializing a struct with nested objects in extra members.
96+
97+
static struct T {
98+
string name;
99+
@extras JSONValue!string stuff;
100+
}
101+
102+
103+
auto jsonStr = `{
104+
"name": "valid",
105+
"a": "another string",
106+
"b": 2,
107+
"c": 8.5,
108+
"pet1": {
109+
"name": "Fido",
110+
"age": 5
111+
},
112+
"pet2": {
113+
"name": "Rex",
114+
"age": 3
115+
}
116+
}`;
117+
118+
auto policy1 = DefaultDeserializationPolicy!false(1); // Set max depth to 1
119+
import std.exception;
120+
// This should throw an exception because the depth exceeds 1
121+
assertThrown!JSONIopipeException(
122+
deserialize!T(jsonStr, policy1)
123+
);
124+
125+
// Now deserialize with a higher max depth
126+
auto policy2 = DefaultDeserializationPolicy!false(2); // Set max depth to 2
127+
auto t = deserialize!T(jsonStr, policy2);
128+
assert(t.name == "valid");
129+
assert(t.stuff.object["a"].type == JSONType.String);
130+
assert(t.stuff.object["a"].str == "another string");
131+
assert(t.stuff.object["b"].type == JSONType.Integer);
132+
assert(t.stuff.object["b"].integer == 2);
133+
assert(t.stuff.object["c"].type == JSONType.Floating);
134+
assert(t.stuff.object["c"].floating == 8.5);
135+
assert(t.stuff.object["pet1"].type == JSONType.Obj);
136+
assert(t.stuff.object["pet1"].object["name"].type == JSONType.String);
137+
assert(t.stuff.object["pet1"].object["name"].str == "Fido");
138+
assert(t.stuff.object["pet1"].object["age"].type == JSONType.Integer);
139+
assert(t.stuff.object["pet1"].object["age"].integer == 5);
140+
assert(t.stuff.object["pet2"].type == JSONType.Obj);
141+
assert(t.stuff.object["pet2"].object["name"].type == JSONType.String);
142+
assert(t.stuff.object["pet2"].object["name"].str == "Rex");
143+
assert(t.stuff.object["pet2"].object["age"].type == JSONType.Integer);
144+
assert(t.stuff.object["pet2"].object["age"].integer == 3);
145+
}
71146

72147
// shim for policies that do not specify a release policy
73148
private ReleasePolicy relPol(P)(ref P policy) => ReleasePolicy.afterMembers;
@@ -611,14 +686,6 @@ void deserializeImpl(P, T, JT)(ref P policy, ref JT tokenizer, ref T item) if (i
611686
}
612687
}
613688

614-
/*
615-
void deserializeImpl(P, T, JT)(ref P policy, ref JT tokenizer, ref T item) if (isInstanceOf!(JSONValue, T))
616-
{
617-
618-
item = tokenizer.parseJSON!(typeof(T.str))(policy.relPol);
619-
}
620-
*/
621-
622689
void deserializeImpl(P, T, JT)(ref P policy, ref JT tokenizer, ref T item) if (isInstanceOf!(JSONValue, T))
623690
{
624691
auto token = tokenizer.peekSignificant();

0 commit comments

Comments
 (0)