diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java index 4390060c4bc..3a83b1803bc 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java @@ -227,7 +227,7 @@ class ParserState { /** * @param theResourceType - * May be null + * May be null */ static ParserState getPreResourceInstance(Class theResourceType, FhirContext theContext, boolean theJsonMode, IParserErrorHandler theErrorHandler) throws DataFormatException { @@ -796,6 +796,10 @@ class ParserState { myPreResourceState = thePreResourceState; } + /** + * @param theValue + * The attribute value + */ public void attributeValue(String theName, String theValue) throws DataFormatException { myErrorHandler.unknownAttribute(null, theName); } @@ -804,6 +808,15 @@ class ParserState { // ignore by default } + protected void logAndSwallowUnexpectedElement(String theLocalPart) { + myErrorHandler.unknownElement(null, theLocalPart); + push(new SwallowChildrenWholeState(getPreResourceState())); + } + + /** + * @param theNamespaceUri + * The XML namespace (if XML) or null + */ public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException { myErrorHandler.unknownElement(null, theLocalPart); } @@ -860,7 +873,7 @@ class ParserState { /** * @param theData - * The string value + * The string value */ public void string(String theData) { // ignore by default @@ -872,7 +885,7 @@ class ParserState { /** * @param theNextEvent - * The XML event + * The XML event */ public void xmlEvent(XMLEvent theNextEvent) { // ignore @@ -1143,13 +1156,13 @@ class ParserState { } else if ("url".equals(theLocalPart)) { push(new PrimitiveState(getPreResourceState(), myEntry.getLinkSearch())); } else { - ourLog.warn("Unexpected element in Bundle.entry.search: " + theLocalPart); - push(new SwallowChildrenWholeState(getPreResourceState())); + logAndSwallowUnexpectedElement(theLocalPart); } } } + private class BundleLinkState extends BaseState { private BundleEntry myEntry; @@ -1553,13 +1566,13 @@ class ParserState { push(new SwallowChildrenWholeState(getPreResourceState())); return; } - + if ((child.getMax() == 0 || child.getMax() == 1) && !myParsedNonRepeatableNames.add(theChildName)) { myErrorHandler.unexpectedRepeatingElement(null, theChildName); push(new SwallowChildrenWholeState(getPreResourceState())); return; } - + BaseRuntimeElementDefinition target = child.getChildByName(theChildName); if (target == null) { // This is a bug with the structures and shouldn't happen.. @@ -2328,11 +2341,14 @@ class ParserState { } else if ("resource".equals(theLocalPart)) { mySubState = ResourceReferenceSubState.REFERENCE; break; + } else { + logAndSwallowUnexpectedElement(theLocalPart); + break; } - //$FALL-THROUGH$ case DISPLAY: case REFERENCE: - throw new DataFormatException("Unexpected element: " + theLocalPart); + logAndSwallowUnexpectedElement(theLocalPart); + break; } } diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java index d5534f76135..bdf716812dc 100644 --- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java @@ -108,39 +108,14 @@ public class XmlParserTest { String str = ourCtx.newXmlParser().encodeResourceToString(patient); ourLog.info(str); - assertThat( - str, - Matchers.stringContainsInOrder("")); + assertThat(str, Matchers.stringContainsInOrder( + "")); MyPatient parse = ourCtx.newXmlParser().parseResource(MyPatient.class, str); assertEquals("PatientName", parse.getNameFirstRep().getFamilyAsSingleString()); assertEquals("OrgName", ((MyOrganization) parse.getSomeOrganization().getResource()).getName().getValue()); } - - @Test - public void testParseAndEncodeHugeValue() { - int len = 1000000; - byte[] bytes = new byte[len]; - for (int i = 0; i < len; i++) { - bytes[i] = (byte) (Math.random() * Byte.MAX_VALUE); - } - - AttachmentDt att = new AttachmentDt(); - att.setData(bytes); - - Observation obs = new Observation(); - obs.setValue(att); - - String str = ourCtx.newXmlParser().encodeResourceToString(obs); - assertThat(str.length(), Matchers.greaterThan(len)); - - obs = ourCtx.newXmlParser().parseResource(Observation.class, str); - att = (AttachmentDt) obs.getValue(); - assertArrayEquals(bytes, att.getData().getValue()); - } - - /** * Test for #82 - Not yet enabled because the test won't pass */ @@ -157,9 +132,8 @@ public class XmlParserTest { String str = ourCtx.newXmlParser().encodeResourceToString(patient); ourLog.info(str); - assertThat( - str, - Matchers.stringContainsInOrder("")); + assertThat(str, Matchers.stringContainsInOrder( + "")); MyPatient parse = ourCtx.newXmlParser().parseResource(MyPatient.class, str); assertEquals("PatientName", parse.getNameFirstRep().getFamilyAsSingleString()); @@ -251,13 +225,11 @@ public class XmlParserTest { String enc = ourCtx.newXmlParser().encodeResourceToString(patient); assertThat(enc, containsString("")); assertThat(enc, containsString("")); - assertThat( - enc, - containsString("")); + assertThat(enc, containsString( + "")); assertThat(enc, containsString("")); - assertThat( - enc, - containsString("")); + assertThat(enc, containsString( + "")); /* * Now parse this back @@ -306,9 +278,9 @@ public class XmlParserTest { comp.addSection().getContent().setResource(new AllergyIntolerance().addIdentifier("foo", "bar")); comp.addSection().getContent().setResource(new AllergyIntolerance().addIdentifier("foo", "bar")); comp.addSection().getContent().setResource(new AllergyIntolerance().addIdentifier("foo", "bar")); - + IParser parser = ourCtx.newJsonParser().setPrettyPrint(true); - + String string = parser.encodeResourceToString(comp); ourLog.info(string); @@ -331,9 +303,9 @@ public class XmlParserTest { comp.addSection().getContent().setResource(new AllergyIntolerance().addIdentifier("foo", "bar")); comp.addSection().getContent().setResource(new AllergyIntolerance().addIdentifier("foo", "bar")); comp.addSection().getContent().setResource(new AllergyIntolerance().addIdentifier("foo", "bar")); - + IParser parser = ourCtx.newXmlParser().setPrettyPrint(true); - + String string = parser.encodeResourceToString(comp); ourLog.info(string); @@ -500,28 +472,6 @@ public class XmlParserTest { } - - @Test - public void testEncodeContainedWithSelfReference() { - IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true); - - // Create an organization, note that the organization does not have an ID - Organization org = new Organization(); - org.getName().setValue("Contained Test Organization"); - org.setPartOf(new ResourceReferenceDt(org)); - - // Create a patient - Patient patient = new Patient(); - patient.getManagingOrganization().setResource(org); - - String encoded = xmlParser.encodeResourceToString(patient); - ourLog.info(encoded); - assertThat(encoded, containsString("")); - assertThat(encoded, containsString("")); - } - - - @Test public void testEncodeContained() { IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true); @@ -673,6 +623,25 @@ public class XmlParserTest { } + @Test + public void testEncodeContainedWithSelfReference() { + IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true); + + // Create an organization, note that the organization does not have an ID + Organization org = new Organization(); + org.getName().setValue("Contained Test Organization"); + org.setPartOf(new ResourceReferenceDt(org)); + + // Create a patient + Patient patient = new Patient(); + patient.getManagingOrganization().setResource(org); + + String encoded = xmlParser.encodeResourceToString(patient); + ourLog.info(encoded); + assertThat(encoded, containsString("")); + assertThat(encoded, containsString("")); + } + @Test public void testEncodeDeclaredExtensionWithAddressContent() { IParser parser = ourCtx.newXmlParser(); @@ -1265,9 +1234,8 @@ public class XmlParserTest { String enc = ourCtx.newXmlParser().encodeResourceToString(patient); assertThat(enc, containsString("")); - assertThat( - enc, - containsString("")); + assertThat(enc, containsString( + "")); assertThat(enc, containsString("")); } @@ -1360,6 +1328,28 @@ public class XmlParserTest { } + @Test + public void testParseAndEncodeHugeValue() { + int len = 1000000; + byte[] bytes = new byte[len]; + for (int i = 0; i < len; i++) { + bytes[i] = (byte) (Math.random() * Byte.MAX_VALUE); + } + + AttachmentDt att = new AttachmentDt(); + att.setData(bytes); + + Observation obs = new Observation(); + obs.setValue(att); + + String str = ourCtx.newXmlParser().encodeResourceToString(obs); + assertThat(str.length(), Matchers.greaterThan(len)); + + obs = ourCtx.newXmlParser().parseResource(Observation.class, str); + att = (AttachmentDt) obs.getValue(); + assertArrayEquals(bytes, att.getData().getValue()); + } + /** * See #131 */ @@ -1685,6 +1675,20 @@ public class XmlParserTest { } + @Test + public void testParseErrorHandlerDuplicateElement() { + String input = ""; + try { + ourCtx.newXmlParser().setParserErrorHandler(new StrictErrorHandler()).parseResource(Patient.class, input); + fail(); + } catch (DataFormatException e) { + assertThat(e.getMessage(), containsString("Multiple repetitions")); + } + + Patient p = ourCtx.newXmlParser().setParserErrorHandler(new LenientErrorHandler()).parseResource(Patient.class, input); + assertEquals("true", p.getActive().getValueAsString()); + } + @Test public void testParseErrorHandlerNoError() { String input = ""; @@ -1719,20 +1723,6 @@ public class XmlParserTest { assertEquals(p.getName().get(0).getFamily().get(0).getValue(), "AAA"); } - @Test - public void testParseErrorHandlerDuplicateElement() { - String input = ""; - try { - ourCtx.newXmlParser().setParserErrorHandler(new StrictErrorHandler()).parseResource(Patient.class, input); - fail(); - } catch (DataFormatException e) { - assertThat(e.getMessage(), containsString("Multiple repetitions")); - } - - Patient p = ourCtx.newXmlParser().setParserErrorHandler(new LenientErrorHandler()).parseResource(Patient.class, input); - assertEquals("true", p.getActive().getValueAsString()); - } - @Test public void testParseFeedWithListResource() throws ConfigurationException, DataFormatException, IOException { @@ -1781,18 +1771,35 @@ public class XmlParserTest { } + @Test + public void testParseReferenceWithUnexpectedChild() { + //@formatter:off + String input = + "" + + " " + + " " + + " " + + " " + + ""; + //@formatter:on + + Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, input); + String output = ourCtx.newXmlParser().encodeResourceToString(parsed); + + assertEquals("", output); + } + /** * #175 */ -// @Test + // @Test public void testParseTextWithUnknownEntity() { - String msg = "" - + "
Trade ™
"; + String msg = "" + "
Trade ™
"; Patient pt = ourCtx.newXmlParser().parseResource(Patient.class, msg); ourLog.info(pt.getText().getDiv().getValueAsString()); assertThat(pt.getText().getDiv().getValueAsString(), containsString("Trade ™")); - + String enc = ourCtx.newXmlParser().encodeResourceToString(pt); ourLog.info(enc); assertThat(enc, containsString("Trade ™")); diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 76a8f470965..cb6bcede139 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -72,6 +72,10 @@ a trailing comma or an escaped backslash. Thanks to GitHub user @SherryH for all of her help in diagnosing this issue! + + Avoid crash when parsing if an invalid child element is found in + a resource reference. +