Skip to content

Commit

Permalink
Fix #93
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Nov 15, 2019
1 parent 9e02240 commit fee31c2
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 25 deletions.
11 changes: 11 additions & 0 deletions release-notes/CREDITS
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,14 @@ Colm O hEigeartaigh (coheigea@github)

* Reported #85: OSGi dependency on relaxng should be `optional`
(6.0.2)

Michael Siegel (michaelsiegel@github)

* Reported, contributed fix for #88: Missing closing quote for attribute values during
Validating output mode
(6.0.3)

Ivo Studensky (istudens@github)

* Reported #93: Stax `maxAttributeSize` limit is only vaguely respected
(6.0.3)
2 changes: 2 additions & 0 deletions release-notes/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Project: woodstox

#88: Missing closing quote for attribute values during in Validating output mode
(reported, fixed by michaelsiegel@github)
#93: Stax `maxAttributeSize` limit is only vaguely respected
(reported by Ivo S)

6.0.2 (12-Oct-2019)

Expand Down
58 changes: 35 additions & 23 deletions src/main/java/com/ctc/wstx/sr/BasicStreamReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import com.ctc.wstx.exc.WstxException;
import com.ctc.wstx.io.*;
import com.ctc.wstx.util.DefaultXmlSymbolTable;
import com.ctc.wstx.util.ExceptionUtil;
import com.ctc.wstx.util.TextBuffer;
import com.ctc.wstx.util.TextBuilder;

Expand Down Expand Up @@ -1964,8 +1965,11 @@ private final void parseAttrValue(char openingQuote, TextBuilder tb)
{
char[] outBuf = tb.getCharBuffer();
int outPtr = tb.getCharSize();
int outLen = outBuf.length;
WstxInputSource currScope = mInput;
// important! Underlying buffer may be shared, does not necessarily start from 0
final int startingOffset = outPtr;
final int maxAttrSize = mConfig.getMaxAttributeSize();
int outLimit = Math.min(startingOffset+maxAttrSize, outBuf.length);
final WstxInputSource currScope = mInput;

while (true) {
char c = (mInputPtr < mInputEnd) ? mInputBuffer[mInputPtr++]
Expand All @@ -1976,14 +1980,11 @@ private final void parseAttrValue(char openingQuote, TextBuilder tb)
if (c == '\n') {
markLF();
} else if (c == '\r') {
/* 04-Mar-2006, TSa: Linefeed normalization only
* done if enabled -- specifically, 2-char lfs
* from int. entities are not coalesced. Now...
* whether to try to count them as one or not...
* easier not to; esp. since we may not be able to
* distinguish char entity originated ones from
* real ones.
*/
// 04-Mar-2006, TSa: Linefeed normalization only done if enabled -
// specifically, 2-char lfs from int. entities are not coalesced.
// Now... whether to try to count them as one or not... easier not to;
// esp. since we may not be able to distinguish char entity originated ones
// from real ones.
if (mNormalizeLFs) {
c = getNextChar(SUFFIX_IN_ATTR_VALUE);
if (c != '\n') { // nope, not 2-char lf (Mac?)
Expand All @@ -1997,11 +1998,9 @@ private final void parseAttrValue(char openingQuote, TextBuilder tb)
// Whatever it was, it'll be 'normal' space now.
c = CHAR_SPACE;
} else if (c == openingQuote) {
/* 06-Aug-2004, TSa: Can get these via entities; only "real"
* end quotes in same scope count. Note, too, that since
* this will only be done at root level, there's no need
* to check for "runaway" values; they'll hit EOF
*/
// 06-Aug-2004, TSa: Can get these via entities; only "real" end quotes in same
// scope count. Note, too, that since this will only be done at root level,
// there's no need to check for "runaway" values; they'll hit EOF
if (mInput == currScope) {
break;
}
Expand All @@ -2022,9 +2021,9 @@ private final void parseAttrValue(char openingQuote, TextBuilder tb)
c = (char) ch;
} else {
ch -= 0x10000;
if (outPtr >= outLen) {
outBuf = tb.bufferFull(1);
outLen = outBuf.length;
if (outPtr >= outLimit) {
outBuf = _checkAttributeLimit(tb, outBuf, outPtr, outPtr - startingOffset, maxAttrSize);
outLimit = Math.min(startingOffset+maxAttrSize, outBuf.length);
}
outBuf[outPtr++] = (char) ((ch >> 10) + 0xD800);
c = (char) ((ch & 0x3FF) + 0xDC00);
Expand All @@ -2035,18 +2034,31 @@ private final void parseAttrValue(char openingQuote, TextBuilder tb)
}

// Ok, let's just add char in, whatever it was
if (outPtr >= outLen) {
verifyLimit("Maximum attribute size", mConfig.getMaxAttributeSize(), tb.getCharSize());
outBuf = tb.bufferFull(1);
outLen = outBuf.length;
if (outPtr >= outLimit) {
outBuf = _checkAttributeLimit(tb, outBuf, outPtr, outPtr - startingOffset, maxAttrSize);
outLimit = Math.min(startingOffset+maxAttrSize, outBuf.length);
}
outBuf[outPtr++] = c;
}

// Fine; let's tell TextBuild we're done:
tb.setBufferSize(outPtr);
}


private final char[] _checkAttributeLimit(TextBuilder tb,
char[] outBuf, int outPtr, int currAttrSize, int maxAttrSize)
throws XMLStreamException
{
// Add +1 since we are at point where we are to append (at least) one more character
verifyLimit("Maximum attribute size", maxAttrSize , currAttrSize+1);
// just sanity check
if (outPtr < outBuf.length) {
ExceptionUtil.throwInternal("Expected either attr limit ("+maxAttrSize
+") >= currAttrSize ("+currAttrSize+") OR >= outBuf.length ("+outBuf.length+")");
}
return tb.bufferFull(1);
}

/*
///////////////////////////////////////////////////////////////////////
// Internal methods, parsing prolog (before root) and epilog
Expand Down
7 changes: 5 additions & 2 deletions src/test/java/stax2/typed/WriterTestBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ public abstract class WriterTestBase
extends BaseStax2Test
{
final static int[] ARRAY_TEST_LENGTHS = new int[] {
3, 8, 25, 120, 16, 99, 253, 1099, 2866, 37242
// 15-Nov-2019, tatu: careful wrt [woodstox-core#93] so as not to exceed
// maximum attribute value lengths!
3, 8, 25, 120, 16, 99, 253, 1099, 2866, 7777, 23242
};

/*
Expand Down Expand Up @@ -514,7 +516,8 @@ private void doTestDoubleArrays(boolean testAttr)
}
String contents;
if (testAttr) {
contents = getAttributeContent(writeDoubleArrayAttrDoc("root", "attr", data));
final byte[] xml = writeDoubleArrayAttrDoc("root", "attr", data);
contents = getAttributeContent(xml);
} else {
contents = getElementContent(writeDoubleArrayElemDoc("root", data));
}
Expand Down
25 changes: 25 additions & 0 deletions src/test/java/wstxtest/stream/TestAttributeLimits.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,31 @@ public void close() throws IOException { }
reader.close();
}

// [woodstox-core#93]: should use stricter verification of max attr length
public void testShorterAttribute() throws Exception
{
XMLInputFactory factory = getNewInputFactory();
factory.setProperty(WstxInputProperties.P_MAX_ATTRIBUTE_SIZE, 4);

// First: ok document
XMLStreamReader r = factory.createXMLStreamReader(new StringReader(
"<root attr='1234' other='ab' x='yz&amp;0' />"));
assertTokenType(START_ELEMENT, r.next());
assertEquals(3, r.getAttributeCount());
assertTokenType(END_ELEMENT, r.next());
r.close();

// then not so much
r = factory.createXMLStreamReader(new StringReader(
"<root attr='1234' other='abcde' />"));
try {
r.next();
fail("Should not pass");
} catch (XMLStreamException ex) {
verifyException(ex, "Maximum attribute size limit (4)");
}
}

public void testLongAttribute() throws Exception {
final int max = 500;
Reader reader = new Reader() {
Expand Down

0 comments on commit fee31c2

Please sign in to comment.