@@ -33,11 +33,28 @@ import std.format;
3333
3434struct 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
73148private 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-
622689void 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