[java-support] 08/21: Tests for parsing bad inputs.
Scott Cantor
cantor.2 at osu.edu
Thu Jun 2 14:38:55 UTC 2022
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch dev/JSPT-111
in repository java-support.
View the commit online:
http://git.shibboleth.net/view/?p=java-support.git;a=commit;h=157646c5946b31a3eb8c4c7a1db930aecd518fce
commit 157646c5946b31a3eb8c4c7a1db930aecd518fce
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu May 20 16:16:00 2021 -0400
Tests for parsing bad inputs.
---
.../shibboleth/utilities/java/support/ddf/DDF.java | 83 ++++++++----
.../utilities/java/support/ddf/DDFTest.java | 146 +++++++++++++++++++--
2 files changed, 190 insertions(+), 39 deletions(-)
diff --git a/src/main/java/net/shibboleth/utilities/java/support/ddf/DDF.java b/src/main/java/net/shibboleth/utilities/java/support/ddf/DDF.java
index c84f6be..53764c1 100644
--- a/src/main/java/net/shibboleth/utilities/java/support/ddf/DDF.java
+++ b/src/main/java/net/shibboleth/utilities/java/support/ddf/DDF.java
@@ -1275,28 +1275,29 @@ public class DDF implements Iterable<DDF> {
} catch (final IllegalArgumentException e) {
throw new IOException("Invalid DDF type");
}
-
- // Required last byte read will vary by type.
- if (type == DDFType.DDF_EMPTY || type == DDFType.DDF_POINTER) {
- if (ch != 0x0A) {
- throw new IOException("Empty/pointer record not terminated by linefeed");
- }
- // Nothing else to do, it's already empty.
- return obj;
- }
-
- // All others should be followed by a space.
- if (ch != 0x20) {
- throw new IOException("Type field not followed by space character");
- }
// Process typical value types.
final StringBuilder valueBuilder = new StringBuilder();
switch (type) {
+ case DDF_EMPTY:
+ case DDF_POINTER:
+ if (ch != 0x0A) {
+ throw new IOException("Empty/pointer record not terminated by linefeed");
+ }
+ // Nothing else to do, it's already empty.
+ return obj;
+
case DDF_STRING:
case DDF_STRING_UNSAFE:
- case DDF_INT:
- case DDF_FLOAT:
+ if (ch == 0x0A) {
+ if (type == DDFType.DDF_STRING) {
+ return obj.string(null);
+ }
+ return obj.unsafe_string(null);
+ } else if (ch != 0x20) {
+ throw new IOException("Type field not followed by space character");
+ }
+
while ((ch = is.read()) != -1 && !Character.isWhitespace(ch)) {
if (ch >= 0 && ch <= 127) {
// The int is a code point from 0..255, but our grammar constrains this to 0..127 so
@@ -1314,23 +1315,50 @@ public class DDF implements Iterable<DDF> {
try {
if (type == DDFType.DDF_STRING) {
// String values are handled as UTF-8.
- obj.string(URLDecoder.decode(valueBuilder.toString(), "UTF-8"));
- } else if (type == DDFType.DDF_STRING_UNSAFE) {
- // Unsafe string values are processed as ISO-8859-1.
- // They may be anything, but it will guarantee a single byte encoding.
- obj.unsafe_string(URLDecoder.decode(valueBuilder.toString(), "ISO-8859-1"));
- } else if (type == DDFType.DDF_INT) {
- obj.integer(valueBuilder.toString());
- } else if (type == DDFType.DDF_FLOAT) {
- obj.floating(valueBuilder.toString());
+ return obj.string(URLDecoder.decode(valueBuilder.toString(), "UTF-8"));
}
+
+ // Unsafe string values are processed as ISO-8859-1.
+ // They may be anything, but it will guarantee a single byte encoding.
+ return obj.unsafe_string(URLDecoder.decode(valueBuilder.toString(), "ISO-8859-1"));
+
} catch (final IllegalArgumentException e) {
throw new IOException(e);
}
- return obj;
+
+ case DDF_INT:
+ case DDF_FLOAT:
+ if (ch != 0x20) {
+ throw new IOException("Type field not followed by space character");
+ }
+
+ while ((ch = is.read()) != -1 && !Character.isWhitespace(ch)) {
+ if (ch >= 0 && ch <= 127) {
+ // The int is a code point from 0..255, but our grammar constrains this to 0..127 so
+ // this is a safe append, to promote the ASCII into Unicode.
+ valueBuilder.appendCodePoint(ch);
+ } else {
+ throw new IOException("Invalid code point outside US-ASCII range");
+ }
+ }
+
+ if (ch != 0x0A) {
+ throw new IOException("Numeric value not followed by linefeed");
+ } else if (valueBuilder.length() == 0) {
+ throw new IOException("Numeric value missing");
+ }
+
+ if (type == DDFType.DDF_INT) {
+ return obj.integer(valueBuilder.toString());
+ }
+ return obj.floating(valueBuilder.toString());
case DDF_STRUCT:
case DDF_LIST:
+ if (ch != 0x20) {
+ throw new IOException("Type field not followed by space character");
+ }
+
while ((ch = is.read()) != -1 && Character.isDigit(ch)) {
// This is safe because the byte contract of the stream disallows
// any non-ASCII digit from satisfying the isDigit check.
@@ -1339,6 +1367,8 @@ public class DDF implements Iterable<DDF> {
if (ch != 0x0A) {
throw new IOException("Record count not followed by linefeed");
+ } else if (valueBuilder.length() == 0) {
+ throw new IOException("Record count missing");
}
int count;
@@ -1358,7 +1388,6 @@ public class DDF implements Iterable<DDF> {
obj.add(deserialize(is));
}
return obj;
-
default:
throw new IOException("Unexpected record type");
diff --git a/src/test/java/net/shibboleth/utilities/java/support/ddf/DDFTest.java b/src/test/java/net/shibboleth/utilities/java/support/ddf/DDFTest.java
index 1889c58..9845a30 100644
--- a/src/test/java/net/shibboleth/utilities/java/support/ddf/DDFTest.java
+++ b/src/test/java/net/shibboleth/utilities/java/support/ddf/DDFTest.java
@@ -249,6 +249,19 @@ public class DDFTest {
}
}
+ /**
+ * Convert test file contents to a byte array.
+ *
+ * @param name file name
+ *
+ * @return byte array
+ *
+ * @throws IOException on error
+ */
+ private byte[] testFile(@Nonnull final String name) throws IOException {
+ return getClass().getResourceAsStream(name).readAllBytes();
+ }
+
@Test
public void testDeserialize() throws IOException {
try (final InputStream is = getClass().getResourceAsStream("empty-noname.ddf")) {
@@ -313,18 +326,127 @@ public class DDFTest {
}
}
-
- /**
- * Convert test file contents to a byte array.
- *
- * @param name file name
- *
- * @return byte array
- *
- * @throws IOException on error
- */
- private byte[] testFile(@Nonnull final String name) throws IOException {
- return getClass().getResourceAsStream(name).readAllBytes();
+ @Test
+ public void testBadInputs() {
+ try (final InputStream is = new ByteArrayInputStream(new String().getBytes("UTF-8"))) {
+ DDF.deserialize(is);
+ fail("Should have thrown IOException");
+ } catch (final IOException e) {
+
+ }
+
+ try (final InputStream is = new ByteArrayInputStream(new String("\n").getBytes("UTF-8"))) {
+ DDF.deserialize(is);
+ fail("Should have thrown IOException");
+ } catch (final IOException e) {
+
+ }
+
+ try (final InputStream is = new ByteArrayInputStream(new String(" ").getBytes("UTF-8"))) {
+ DDF.deserialize(is);
+ fail("Should have thrown IOException");
+ } catch (final IOException e) {
+
+ }
+
+ try (final InputStream is = new ByteArrayInputStream(new String(".\n").getBytes("UTF-8"))) {
+ DDF.deserialize(is);
+ fail("Should have thrown IOException");
+ } catch (final IOException e) {
+
+ }
+
+ try (final InputStream is = new ByteArrayInputStream(new String(". \n").getBytes("UTF-8"))) {
+ DDF.deserialize(is);
+ fail("Should have thrown IOException");
+ } catch (final IOException e) {
+
+ }
+
+ try (final InputStream is = new ByteArrayInputStream(new String(". -2").getBytes("UTF-8"))) {
+ DDF.deserialize(is);
+ fail("Should have thrown IOException");
+ } catch (final IOException e) {
+
+ }
+
+ try (final InputStream is = new ByteArrayInputStream(new String(". 0 \n").getBytes("UTF-8"))) {
+ DDF.deserialize(is);
+ fail("Should have thrown IOException");
+ } catch (final IOException e) {
+
+ }
+
+ try (final InputStream is = new ByteArrayInputStream(new String(". 1 foo \n").getBytes("UTF-8"))) {
+ DDF.deserialize(is);
+ fail("Should have thrown IOException");
+ } catch (final IOException e) {
+
+ }
+
+ try (final InputStream is = new ByteArrayInputStream(new String(". 2\n").getBytes("UTF-8"))) {
+ DDF.deserialize(is);
+ fail("Should have thrown IOException");
+ } catch (final IOException e) {
+
+ }
+
+ try (final InputStream is = new ByteArrayInputStream(new String(". 2 \n").getBytes("UTF-8"))) {
+ DDF.deserialize(is);
+ fail("Should have thrown IOException");
+ } catch (final IOException e) {
+
+ }
+
+ try (final InputStream is = new ByteArrayInputStream(new String(". 3\n").getBytes("UTF-8"))) {
+ DDF.deserialize(is);
+ fail("Should have thrown IOException");
+ } catch (final IOException e) {
+
+ }
+
+ try (final InputStream is = new ByteArrayInputStream(new String(". 3 \n").getBytes("UTF-8"))) {
+ DDF.deserialize(is);
+ fail("Should have thrown IOException");
+ } catch (final IOException e) {
+
+ }
+
+ try (final InputStream is = new ByteArrayInputStream(new String(". 4 \n").getBytes("UTF-8"))) {
+ DDF.deserialize(is);
+ fail("Should have thrown IOException");
+ } catch (final IOException e) {
+
+ }
+
+ try (final InputStream is = new ByteArrayInputStream(new String(". 4\n").getBytes("UTF-8"))) {
+ DDF.deserialize(is);
+ fail("Should have thrown IOException");
+ } catch (final IOException e) {
+
+ }
+
+ try (final InputStream is = new ByteArrayInputStream(new String(". 4 2\n. 1 foo\n").getBytes("UTF-8"))) {
+ DDF.deserialize(is);
+ fail("Should have thrown IOException");
+ } catch (final IOException e) {
+
+ }
+
+ try (final InputStream is = new ByteArrayInputStream(new String(". 5 foo\n").getBytes("UTF-8"))) {
+ DDF.deserialize(is);
+ fail("Should have thrown IOException");
+ } catch (final IOException e) {
+
+ }
+
+ try (final InputStream is = new ByteArrayInputStream(new String(". 5 1\n").getBytes("UTF-8"))) {
+ DDF.deserialize(is);
+ fail("Should have thrown IOException");
+ } catch (final IOException e) {
+
+ }
+
}
}
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list