Skip to content

Commit

Permalink
Merge pull request #41266 from warunalakshitha/xml-parser-fix-5.x
Browse files Browse the repository at this point in the history
[2201.5.x] Fix XML parser truncating large texts
  • Loading branch information
warunalakshitha authored Aug 22, 2023
2 parents c8053c5 + ef740b5 commit 2be0f24
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,16 @@ private void handleXMLStreamException(Exception e) {
}

public BXml parse() {
boolean readNext = false;
int next;
try {
while (xmlStreamReader.hasNext()) {
int next = xmlStreamReader.next();
if (readNext) {
readNext = false;
next = xmlStreamReader.getEventType();
} else {
next = xmlStreamReader.next();
}
switch (next) {
case START_ELEMENT:
readElement(xmlStreamReader);
Expand All @@ -120,6 +127,7 @@ public BXml parse() {
case CDATA:
case CHARACTERS:
readText(xmlStreamReader);
readNext = true;
break;
case END_DOCUMENT:
return buildDocument();
Expand Down Expand Up @@ -147,8 +155,13 @@ private void readPI(XMLStreamReader xmlStreamReader) {
siblingDeque.peek().add(xmlItem);
}

private void readText(XMLStreamReader xmlStreamReader) {
siblingDeque.peek().add(new XmlText(xmlStreamReader.getText()));
private void readText(XMLStreamReader xmlStreamReader) throws XMLStreamException {
StringBuilder textBuilder = new StringBuilder();
while (xmlStreamReader.getEventType() == CHARACTERS) {
textBuilder.append(xmlStreamReader.getText());
xmlStreamReader.next();
}
siblingDeque.peek().add(new XmlText(textBuilder.toString()));
}

private void readComment(XMLStreamReader xmlStreamReader) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,15 @@
import io.ballerina.runtime.api.values.BObject;
import io.ballerina.runtime.api.values.BString;
import io.ballerina.runtime.api.values.BTypedesc;
import io.ballerina.runtime.api.values.BXml;
import io.ballerina.runtime.internal.TypeChecker;
import io.ballerina.runtime.internal.types.BArrayType;
import io.ballerina.runtime.internal.types.BFunctionType;
import io.ballerina.runtime.internal.types.BRecordType;
import io.ballerina.runtime.internal.types.BTupleType;
import org.jetbrains.annotations.Nullable;

import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
Expand Down Expand Up @@ -461,4 +463,26 @@ public static Boolean checkInlineRecordAnnotations(BTypedesc typedesc, BTypedesc
BString annotKey = StringUtils.fromString("testorg/types.typeref:1:String");
return TypeChecker.checkIsType(((BMap) annotation).get(annotKey), constraint.getDescribingType());
}

public static BXml getXMLValueFromString1() {
return ValueCreator.createXmlValue("<book>The Lost World</book>");
}

public static BXml getXMLValueFromString2() {
return ValueCreator.createXmlValue("<reservationID>12345678901234567890123456789012345678901234567890" +
"12345678901234567890123456789012345678901234567890aaaaaa</reservationID>");
}

public static BXml getXMLValueFromInputStream1() {
return ValueCreator.createXmlValue(new ByteArrayInputStream("<book>The Lost World</book>".getBytes()));
}

public static BXml getXMLValueFromInputStream2() {
String xmlString = "<Reservation>\n" +
"<reservationID>1234567890123456789012345678901234567890123456789012345678901234567890" +
"12345678901234567890123456789exceeding100chars</reservationID>\n" +
" <confirmationID>RPFABE</confirmationID>\n" +
"</Reservation>";
return ValueCreator.createXmlValue(new ByteArrayInputStream(xmlString.getBytes()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import values.records;
import values.objects;
import values.maps;
import values.arrays;
import values.xml_values;
import values.enums;
import ballerina/lang.test as test;

Expand Down Expand Up @@ -67,4 +68,5 @@ public function main() {
records:validateAPI();
enums:validateAPI();
arrays:validateAPI();
xml_values:validateAPI();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved.
//
// WSO2 LLC. licenses this file to you under the Apache License,
// Version 2.0 (the "License"); you may not use this file except
// in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

import ballerina/test;
import ballerina/jballerina.java;

public function validateAPI() {
xml xmlVal = getXMLValueFromString1();
test:assertEquals(xmlVal.toString(), "<book>The Lost World</book>");
test:assertEquals(xmlVal.data(), "The Lost World");

xmlVal = getXMLValueFromString2();
test:assertEquals(xmlVal.toString(), "<reservationID>12345678901234567890123456789012345678901234567890" +
"12345678901234567890123456789012345678901234567890aaaaaa</reservationID>");
test:assertEquals(xmlVal.data(), "1234567890123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890aaaaaa");

xmlVal = getXMLValueFromInputStream1();
test:assertEquals(xmlVal.toString(), "<book>The Lost World</book>");
test:assertEquals(xmlVal.data(), "The Lost World");

xmlVal = getXMLValueFromInputStream2();

test:assertEquals(xmlVal.children().length(), 5);
test:assertEquals(xmlVal.children()[0].toString(), "\n");

test:assertTrue(xmlVal.children()[1] is xml:Element);
xml:Element child1 = <xml:Element>xmlVal.children()[1];
test:assertEquals(child1.toString(), "<reservationID>123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456789exceeding100chars</reservationID>");
test:assertEquals(child1.getName(), "reservationID");
test:assertEquals(child1.children().length(), 1);
test:assertTrue(child1.children()[0] is xml:Text);

xml:Text text = <xml:Text>child1.children()[0];
string xmlString = "12345678901234567890123456789012345678901234567890123456789012345678901234567890" +
"1234567890123456789exceeding100chars";
test:assertEquals(text.data(), xmlString);

test:assertEquals(xmlVal.children()[2].toString(), "\n ");

test:assertTrue(xmlVal.children()[3] is xml:Element);
xml:Element child2 = <xml:Element>xmlVal.children()[3];
test:assertEquals(child2.getName(), "confirmationID");
test:assertEquals(child2.children().length(), 1);
test:assertTrue(child2.children()[0] is xml:Text);
test:assertEquals(child2.children()[0].data(), "RPFABE");

test:assertEquals(xmlVal.children()[4].toString(), "\n");
}

function getXMLValueFromString1() returns xml = @java:Method {
'class: "org.ballerinalang.nativeimpl.jvm.runtime.api.tests.Values"
} external;

function getXMLValueFromString2() returns xml = @java:Method {
'class: "org.ballerinalang.nativeimpl.jvm.runtime.api.tests.Values"
} external;

function getXMLValueFromInputStream1() returns xml = @java:Method {
'class: "org.ballerinalang.nativeimpl.jvm.runtime.api.tests.Values"
} external;

function getXMLValueFromInputStream2() returns xml = @java:Method {
'class: "org.ballerinalang.nativeimpl.jvm.runtime.api.tests.Values"
} external;

0 comments on commit 2be0f24

Please sign in to comment.