JSON parser fails to check for closing array bracket ]
Closed this issue · 3 comments
The parser will allow an array to be closed with "}" or with no closing element at all.
It will also allow an extra closing "}" on the root object.
These conditions allow invalid JSON to be parsed as valid JSON.
The following unit test can be added to: JsonXMLStreamReaderTest to demonstrate:
// Tests for invalid JSON ///
@Test(expected=Exception.class)
public void testInvalidJson_RootArrayStartWithObjectClose() throws Exception {
String input = "{\"alice\":[\"bob\",\"bob\"}}";
XMLStreamReader reader = new JsonXMLInputFactory().createXMLStreamReader(new StringReader(input));
verify(reader, XMLStreamConstants.START_DOCUMENT, null, null);
reader.next();
verify(reader, XMLStreamConstants.PROCESSING_INSTRUCTION, null, null);
Assert.assertEquals(JsonXMLStreamConstants.MULTIPLE_PI_TARGET, reader.getPITarget());
Assert.assertEquals("alice", reader.getPIData());
reader.next();
verify(reader, XMLStreamConstants.START_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.CHARACTERS, null, "bob");
reader.next();
verify(reader, XMLStreamConstants.END_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.START_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.CHARACTERS, null, "bob");
reader.next();
verify(reader, XMLStreamConstants.END_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.END_DOCUMENT, null, null);
reader.close();
}
@Test(expected=Exception.class)
public void testInvalidJson_ArrayMissingCloseBracket() throws Exception {
String input = "{\"alice\":[\"bob\",\"bob\" }";
XMLStreamReader reader = new JsonXMLInputFactory().createXMLStreamReader(new StringReader(input));
verify(reader, XMLStreamConstants.START_DOCUMENT, null, null);
reader.next();
verify(reader, XMLStreamConstants.PROCESSING_INSTRUCTION, null, null);
Assert.assertEquals(JsonXMLStreamConstants.MULTIPLE_PI_TARGET, reader.getPITarget());
Assert.assertEquals("alice", reader.getPIData());
reader.next();
verify(reader, XMLStreamConstants.START_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.CHARACTERS, null, "bob");
reader.next();
verify(reader, XMLStreamConstants.END_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.START_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.CHARACTERS, null, "bob");
reader.next();
verify(reader, XMLStreamConstants.END_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.END_DOCUMENT, null, null);
reader.close();
}
// test currently passes
@Test(expected=Exception.class)
public void testInvalidJson_ObjectStartWithArrayClose() throws Exception {
String input = "{\"alice\":[\"bob\",\"bob\"]]";
XMLStreamReader reader = new JsonXMLInputFactory().createXMLStreamReader(new StringReader(input));
verify(reader, XMLStreamConstants.START_DOCUMENT, null, null);
reader.next();
verify(reader, XMLStreamConstants.PROCESSING_INSTRUCTION, null, null);
Assert.assertEquals(JsonXMLStreamConstants.MULTIPLE_PI_TARGET, reader.getPITarget());
Assert.assertEquals("alice", reader.getPIData());
reader.next();
verify(reader, XMLStreamConstants.START_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.CHARACTERS, null, "bob");
reader.next();
verify(reader, XMLStreamConstants.END_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.START_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.CHARACTERS, null, "bob");
reader.next();
verify(reader, XMLStreamConstants.END_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.END_DOCUMENT, null, null);
reader.close();
}
// test currently passes
@Test(expected=Exception.class)
public void testInvalidJson_ArrayClosedWith2Brackets() throws Exception {
String input = "{\"alice\":[\"bob\",\"bob\"]]}";
XMLStreamReader reader = new JsonXMLInputFactory().createXMLStreamReader(new StringReader(input));
verify(reader, XMLStreamConstants.START_DOCUMENT, null, null);
reader.next();
verify(reader, XMLStreamConstants.PROCESSING_INSTRUCTION, null, null);
Assert.assertEquals(JsonXMLStreamConstants.MULTIPLE_PI_TARGET, reader.getPITarget());
Assert.assertEquals("alice", reader.getPIData());
reader.next();
verify(reader, XMLStreamConstants.START_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.CHARACTERS, null, "bob");
reader.next();
verify(reader, XMLStreamConstants.END_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.START_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.CHARACTERS, null, "bob");
reader.next();
verify(reader, XMLStreamConstants.END_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.END_DOCUMENT, null, null);
reader.close();
}
@Test(expected=Exception.class)
public void testInvalidJson_ArrayStartWithObjectClose() throws Exception {
String input = "{\"alice\":{\"bob\":[\"charlie\",\"david\"}}}";
XMLStreamReader reader = new JsonXMLInputFactory().createXMLStreamReader(new StringReader(input));
verify(reader, XMLStreamConstants.START_DOCUMENT, null, null);
reader.next();
verify(reader, XMLStreamConstants.START_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.PROCESSING_INSTRUCTION, null, null);
Assert.assertEquals(JsonXMLStreamConstants.MULTIPLE_PI_TARGET, reader.getPITarget());
Assert.assertEquals("bob", reader.getPIData());
reader.next();
verify(reader, XMLStreamConstants.START_ELEMENT, "bob", null);
reader.next();
verify(reader, XMLStreamConstants.CHARACTERS, null, "charlie");
reader.next();
verify(reader, XMLStreamConstants.END_ELEMENT, "bob", null);
reader.next();
verify(reader, XMLStreamConstants.START_ELEMENT, "bob", null);
reader.next();
verify(reader, XMLStreamConstants.CHARACTERS, null, "david");
reader.next();
verify(reader, XMLStreamConstants.END_ELEMENT, "bob", null);
reader.next();
verify(reader, XMLStreamConstants.END_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.END_DOCUMENT, null, null);
reader.close();
}
// test currently passes
@Test(expected=Exception.class)
public void testInvalidJson_ObjectStartWithArrayClose_Nested() throws Exception {
//String input = "{\"alice\":{\"bob\":{\"charlie\",\"david\"]}}";
String input = "{\"alice\":{\"bob\":[\"charlie\",\"david\"]]}";
XMLStreamReader reader = new JsonXMLInputFactory().createXMLStreamReader(new StringReader(input));
verify(reader, XMLStreamConstants.START_DOCUMENT, null, null);
reader.next();
verify(reader, XMLStreamConstants.START_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.PROCESSING_INSTRUCTION, null, null);
Assert.assertEquals(JsonXMLStreamConstants.MULTIPLE_PI_TARGET, reader.getPITarget());
Assert.assertEquals("bob", reader.getPIData());
reader.next();
verify(reader, XMLStreamConstants.START_ELEMENT, "bob", null);
reader.next();
verify(reader, XMLStreamConstants.CHARACTERS, null, "charlie");
reader.next();
verify(reader, XMLStreamConstants.END_ELEMENT, "bob", null);
reader.next();
verify(reader, XMLStreamConstants.START_ELEMENT, "bob", null);
reader.next();
verify(reader, XMLStreamConstants.CHARACTERS, null, "david");
reader.next();
verify(reader, XMLStreamConstants.END_ELEMENT, "bob", null);
reader.next();
verify(reader, XMLStreamConstants.END_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.END_DOCUMENT, null, null);
reader.close();
}
@Test(expected=Exception.class)
public void testInvalidJson_ObjectStartArrayClose() throws Exception {
String input = "{\"alice\":\"bob\"]";
XMLStreamReader reader = new JsonXMLInputFactory().createXMLStreamReader(new StringReader(input));
verify(reader, XMLStreamConstants.START_DOCUMENT, null, null);
reader.next();
verify(reader, XMLStreamConstants.START_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.CHARACTERS, null, "bob");
reader.next();
verify(reader, XMLStreamConstants.END_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.END_DOCUMENT, null, null);
reader.close();
}
// throws AssertionError
@Test (expected=Exception.class)
public void testInvalidJson_ArrayStartObjectClose() throws Exception {
String input = "[\"edgar\",\"david\"}";
XMLStreamReader reader = new JsonXMLInputFactory().createXMLStreamReader(new StringReader(input));
verify(reader, XMLStreamConstants.PROCESSING_INSTRUCTION, null, null);
Assert.assertEquals(JsonXMLStreamConstants.MULTIPLE_PI_TARGET, reader.getPITarget());
Assert.assertNull(reader.getPIData());
reader.next();
verify(reader, XMLStreamConstants.CHARACTERS, null, "edgar");
reader.next();
verify(reader, XMLStreamConstants.CHARACTERS, null, "david");
Assert.assertFalse(reader.hasNext());
reader.close();
}
@Test(expected=Exception.class)
public void testInvalidJson_ArrayStartNoClose() throws Exception {
String input = "[\"edgar\",\"david\" ";
XMLStreamReader reader = new JsonXMLInputFactory().createXMLStreamReader(new StringReader(input));
verify(reader, XMLStreamConstants.PROCESSING_INSTRUCTION, null, null);
Assert.assertEquals(JsonXMLStreamConstants.MULTIPLE_PI_TARGET, reader.getPITarget());
Assert.assertNull(reader.getPIData());
reader.next();
verify(reader, XMLStreamConstants.CHARACTERS, null, "edgar");
reader.next();
verify(reader, XMLStreamConstants.CHARACTERS, null, "david");
Assert.assertFalse(reader.hasNext());
reader.close();
}
@Test(expected=Exception.class)
public void testInvalidJson_ExtraObjectClose() throws Exception {
String input = "{\"alice\":\"bob\"}}";
XMLStreamReader reader = new JsonXMLInputFactory().createXMLStreamReader(new StringReader(input));
verify(reader, XMLStreamConstants.START_DOCUMENT, null, null);
reader.next();
verify(reader, XMLStreamConstants.START_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.CHARACTERS, null, "bob");
reader.next();
verify(reader, XMLStreamConstants.END_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.END_DOCUMENT, null, null);
reader.close();
}
// The reader throws exception as expected.
// However, when this exception occurs after reader is added to writer, you get a RuntimeException (see JsonXMLStreamWriterTest)
@Test(expected=XMLStreamException.class)
public void testInvalidJson_RandomColon() throws Exception {
String input = "{\"alice\":{\"bob\":\"charlie\",\"david\":\"edgar\"}:}";
XMLStreamReader reader = new JsonXMLInputFactory().createXMLStreamReader(new StringReader(input));
verify(reader, XMLStreamConstants.START_DOCUMENT, null, null);
reader.next();
verify(reader, XMLStreamConstants.START_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.START_ELEMENT, "bob", null);
reader.next();
verify(reader, XMLStreamConstants.CHARACTERS, null, "charlie");
reader.next();
verify(reader, XMLStreamConstants.END_ELEMENT, "bob", null);
reader.next();
verify(reader, XMLStreamConstants.START_ELEMENT, "david", null);
reader.next();
verify(reader, XMLStreamConstants.CHARACTERS, null, "edgar");
reader.next();
verify(reader, XMLStreamConstants.END_ELEMENT, "david", null);
reader.next();
verify(reader, XMLStreamConstants.END_ELEMENT, "alice", null);
reader.next();
verify(reader, XMLStreamConstants.END_DOCUMENT, null, null);
reader.close();
}
Thanks for the great tests! I'll look into this asap.
You are welcome. Thanks for fixing these so quickly!
Dave
On Fri, Jul 6, 2012 at 6:18 AM, Christoph Beck <
reply@reply.github.com
wrote:
Thanks for the great tests! I'll look into this asap.
Reply to this email directly or view it on GitHub:
#7 (comment)
Fixed JsonStreamSourceImpl
. Added most of your tests to JsonStreamSourceImplTest
, but simplified them and made them check the exception message.