From c3bd8fe437f422e1314a1a2ecd45c1d8f16facaa Mon Sep 17 00:00:00 2001 From: Mathias Date: Tue, 28 Oct 2014 12:23:29 +0100 Subject: Fix OOE when parsing unterminated JSON strings, fixes #122 --- src/main/scala/spray/json/JsonParser.scala | 10 ++++++---- src/test/scala/spray/json/JsonParserSpec.scala | 6 ++++++ src/test/scala/spray/json/RoundTripSpecs.scala | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main/scala/spray/json/JsonParser.scala b/src/main/scala/spray/json/JsonParser.scala index 8e7a83e..ea48842 100644 --- a/src/main/scala/spray/json/JsonParser.scala +++ b/src/main/scala/spray/json/JsonParser.scala @@ -132,11 +132,13 @@ class JsonParser(input: ParserInput) { } private def `char`() = - cursorChar match { - case '"' => false + // simple bloom-filter that quick-matches the most frequent case of characters that are ok to append + // (it doesn't match control chars, EOI, '"', '?', '\', 'b' and certain higher, non-ASCII chars) + if (((1L << cursorChar) & ((31 - cursorChar) >> 31) & 0x7ffffffbefffffffL) != 0L) appendSB(cursorChar) + else cursorChar match { + case '"' | EOI => false case '\\' => advance(); `escaped`() - case c if cursorChar >= ' ' => appendSB(cursorChar) - case _ => false + case c => (c >= ' ') && appendSB(c) } private def `escaped`() = { diff --git a/src/test/scala/spray/json/JsonParserSpec.scala b/src/test/scala/spray/json/JsonParserSpec.scala index 4968eee..7d527b1 100644 --- a/src/test/scala/spray/json/JsonParserSpec.scala +++ b/src/test/scala/spray/json/JsonParserSpec.scala @@ -89,6 +89,12 @@ class JsonParserSpec extends Specification { |[null, 1.23, { key":true } ] | ^ |""".stripMargin + + errorMessage("""{"a}""") === + """Unexpected end-of-input at input index 4 (line 1, position 5), expected '"': + |{"a} + | ^ + |""".stripMargin } } } \ No newline at end of file diff --git a/src/test/scala/spray/json/RoundTripSpecs.scala b/src/test/scala/spray/json/RoundTripSpecs.scala index 7609a53..c4f7764 100644 --- a/src/test/scala/spray/json/RoundTripSpecs.scala +++ b/src/test/scala/spray/json/RoundTripSpecs.scala @@ -8,7 +8,7 @@ object JsValueGenerators { import Gen._ import Arbitrary.arbitrary - val parseableString: Gen[String] = arbitrary[String] + val parseableString: Gen[String] = Gen.someOf(('\u0020' to '\u007E').toVector).map(_.mkString) val genString: Gen[JsString] = parseableString.map(JsString(_)) val genBoolean: Gen[JsBoolean] = oneOf(JsFalse, JsTrue) val genLongNumber: Gen[JsNumber] = arbitrary[Long].map(JsNumber(_)) -- cgit v1.2.3