Skip to content

Commit e41e1ba

Browse files
Improvements to json parsing (thanks Bradley Peabody)
It now remembers if a string was quoted with single or double quotes and deals with both scenarios properly. Some cases of bad json could go into an infinite loop, which now throw an exception. Unwanted backslashes (something like \$ for example) now return the literal character instead of throwing it away.
1 parent 16ff394 commit e41e1ba

File tree

3 files changed

+137
-3
lines changed

3 files changed

+137
-3
lines changed

src/com/rabbitmq/tools/json/JSONReader.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,9 @@ private Object read() {
8888
skipWhiteSpace();
8989

9090
if (c == '"' || c == '\'') {
91+
char sep = c;
9192
next();
92-
ret = string();
93+
ret = string(sep);
9394
} else if (c == '[') {
9495
next();
9596
ret = array();
@@ -119,6 +120,10 @@ private Object read() {
119120
} else if (Character.isDigit(c) || c == '-') {
120121
ret = number();
121122
}
123+
else {
124+
// in this case we want to throw, not valid JSON
125+
throw new IllegalStateException("Found invalid token while parsing JSON (around character "+(it.getIndex()-it.getBeginIndex())+"): " + ret);
126+
}
122127

123128
// System.out.println("token: " + ret); // enable this line to see the token stream
124129
token = ret;
@@ -179,9 +184,12 @@ private Object number() {
179184
}
180185
}
181186

182-
private Object string() {
187+
/**
188+
* Read a string with a specific delimiter (either ' or ")
189+
*/
190+
private Object string(char sep) {
183191
buf.setLength(0);
184-
while (c != '"' && c != '\'') {
192+
while (c != sep) {
185193
if (c == '\\') {
186194
next();
187195
if (c == 'u') {
@@ -191,6 +199,12 @@ private Object string() {
191199
if (value != null) {
192200
add(((Character) value).charValue());
193201
}
202+
// if escaping is invalid, if we're going to ignore the error,
203+
// it makes more sense to put in the literal character instead
204+
// of just skipping it, so we do that
205+
else {
206+
add();
207+
}
194208
}
195209
} else {
196210
add();

test/src/com/rabbitmq/client/test/ClientTests.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public static TestSuite suite() {
3838
suite.addTestSuite(com.rabbitmq.utility.IntAllocatorTests.class);
3939
suite.addTestSuite(AMQBuilderApiTest.class);
4040
suite.addTestSuite(AmqpUriTest.class);
41+
suite.addTestSuite(JSONReadWriteTest.class);
4142
return suite;
4243
}
4344
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// The contents of this file are subject to the Mozilla Public License
2+
// Version 1.1 (the "License"); you may not use this file except in
3+
// compliance with the License. You may obtain a copy of the License
4+
// at http://www.mozilla.org/MPL/
5+
//
6+
// Software distributed under the License is distributed on an "AS IS"
7+
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
8+
// the License for the specific language governing rights and
9+
// limitations under the License.
10+
//
11+
// The Original Code is RabbitMQ.
12+
//
13+
// The Initial Developer of the Original Code is VMware, Inc.
14+
// Copyright (c) 2007-2013 VMware, Inc. All rights reserved.
15+
//
16+
17+
18+
package com.rabbitmq.client.test;
19+
20+
import java.io.BufferedReader;
21+
import java.io.IOException;
22+
import java.io.InputStream;
23+
import java.io.InputStreamReader;
24+
25+
import com.rabbitmq.tools.json.JSONWriter;
26+
import com.rabbitmq.tools.json.JSONReader;
27+
28+
import junit.framework.TestCase;
29+
30+
public class JSONReadWriteTest extends TestCase {
31+
32+
public void testReadWriteSimple() throws Exception {
33+
34+
Object myRet;
35+
String myJson;
36+
37+
// simple string
38+
myRet = new JSONReader().read(myJson = new JSONWriter().write("blah"));
39+
assertEquals("blah", myRet);
40+
41+
// simple int
42+
myRet = new JSONReader().read(myJson = new JSONWriter().write(1));
43+
assertEquals(1, myRet);
44+
45+
// string with double quotes
46+
myRet = new JSONReader().read(myJson = new JSONWriter().write("t1-blah\"blah"));
47+
assertEquals("t1-blah\"blah", myRet);
48+
// string with single quotes
49+
myRet = new JSONReader().read(myJson = new JSONWriter().write("t2-blah'blah"));
50+
assertEquals("t2-blah'blah", myRet);
51+
// string with two double quotes
52+
myRet = new JSONReader().read(myJson = new JSONWriter().write("t3-blah\"n\"blah"));
53+
assertEquals("t3-blah\"n\"blah", myRet);
54+
// string with two single quotes
55+
myRet = new JSONReader().read(myJson = new JSONWriter().write("t4-blah'n'blah"));
56+
assertEquals("t4-blah'n'blah", myRet);
57+
// string with a single and a double quote
58+
myRet = new JSONReader().read(myJson = new JSONWriter().write("t4-blah'n\"blah"));
59+
assertEquals("t4-blah'n\"blah", myRet);
60+
61+
// UTF-8 character
62+
myRet = new JSONReader().read(myJson = new JSONWriter().write("smile \u9786"));
63+
// System.out.println("JSON: "+myJson);
64+
// System.out.println("JSON: "+myRet);
65+
assertEquals("smile \u9786", myRet);
66+
67+
// null byte
68+
myRet = new JSONReader().read(myJson = new JSONWriter().write("smile \u0000"));
69+
// System.out.println("JSON: "+myJson);
70+
// System.out.println("JSON: "+myRet);
71+
assertEquals("smile \u0000", myRet);
72+
73+
}
74+
75+
public void testMoreComplicated() throws Exception {
76+
77+
String v, s;
78+
Object t;
79+
80+
s = "[\"foo\",{\"bar\":[\"baz\",null,1.0,2]}]";
81+
v = new JSONWriter().write(new JSONReader().read(s));
82+
assertEquals(s, v);
83+
84+
s = "[\"foo\",{\"bar\":[\"b\\\"az\",null,1.0,2]}]";
85+
t = new JSONReader().read(s);
86+
v = new JSONWriter().write(t);
87+
assertEquals(s, v);
88+
89+
s = "[\"foo\",{\"bar\":[\"b'az\",null,1.0,2]}]";
90+
v = new JSONWriter().write(new JSONReader().read(s));
91+
assertEquals(s, v);
92+
93+
s = "[\"foo\",{\"bar\":[\"b'a'z\",null,1.0,2]}]";
94+
v = new JSONWriter().write(new JSONReader().read(s));
95+
assertEquals(s, v);
96+
97+
s = "[\"foo\",{\"bar\":[\"b\\\"a\\\"z\",null,1.0,2]}]";
98+
v = new JSONWriter().write(new JSONReader().read(s));
99+
assertEquals(s, v);
100+
101+
}
102+
103+
public void testBadJSON() throws Exception {
104+
105+
try {
106+
new JSONReader().read("[\"foo\",{\"bar\":[\"b\"az\",null,1.0,2]}]");
107+
fail("Should not have parsed");
108+
}
109+
catch (IllegalStateException e) {}
110+
111+
try {
112+
new JSONReader().read("[\"foo\",{\"bar\":[\"b\"a\"z\",null,1.0,2]}]");
113+
fail("Should not have parsed");
114+
}
115+
catch (IllegalStateException e) {}
116+
117+
}
118+
119+
}

0 commit comments

Comments
 (0)