Skip to content

Commit 304fd12

Browse files
committed
Reject input with non-whitespace leftovers
1 parent a87c94d commit 304fd12

3 files changed

Lines changed: 27 additions & 8 deletions

File tree

json-syntax.cabal

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ library
3131
, array-builder >=0.1 && <0.2
3232
, array-chunks >=0.1.1 && <0.2
3333
, base >=4.12 && <5
34-
, bytesmith >=0.3 && <0.4
34+
, bytesmith >=0.3.2 && <0.4
3535
, byteslice >=0.1.3 && <0.3
3636
, scientific-notation >=0.1.1 && <0.2
3737
, text-short >=0.1.3 && <0.2
@@ -51,6 +51,7 @@ test-suite test
5151
ghc-options: -Wall -O2
5252
build-depends:
5353
, aeson
54+
, array-chunks
5455
, base >=4.12.0.0 && <5
5556
, byteslice >=0.1.3
5657
, bytestring

src/Json.hs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{-# language BangPatterns #-}
22
{-# language BinaryLiterals #-}
3+
{-# language BlockArguments #-}
34
{-# language DerivingStrategies #-}
45
{-# language DeriveAnyClass #-}
56
{-# language LambdaCase #-}
@@ -87,6 +88,7 @@ data SyntaxException
8788
| InvalidLeader
8889
| InvalidNumber
8990
| LeadingZero
91+
| UnexpectedLeftovers
9092
deriving stock (Eq,Show)
9193
deriving anyclass (Exception)
9294

@@ -114,14 +116,15 @@ isSpace w =
114116

115117
-- | Decode a JSON syntax tree from a byte sequence.
116118
decode :: Bytes -> Either SyntaxException Value
117-
decode !bs = case P.parseBytes (P.skipWhile isSpace *> (Latin.any EmptyInput >>= parser)) bs of
118-
P.Failure err -> Left err
119-
-- Since parser only completes once the end of the input
120-
-- has been reached, we do not need to check the length here.
121-
P.Success (P.Slice _ _ cs) -> Right cs
119+
decode = P.parseBytesEither do
120+
P.skipWhile isSpace
121+
result <- Latin.any EmptyInput >>= parser
122+
P.skipWhile isSpace
123+
P.endOfInput UnexpectedLeftovers
124+
pure result
122125

123126
-- Precondition: skip over all space before calling this.
124-
-- It will not skip space for you.
127+
-- It will not skip leading space for you. It does
125128
parser :: Char -> Parser SyntaxException s Value
126129
parser = \case
127130
'{' -> objectTrailedByBrace

test/Main.hs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import Twitter100 (encodedTwitter100,byteStringTwitter100)
1212

1313
import qualified Data.Aeson as AE
1414
import qualified Data.Bytes as Bytes
15+
import qualified Data.Chunks as Chunks
1516
import qualified Data.HashMap.Strict as HM
1617
import qualified Data.Number.Scientific as SCI
1718
import qualified Data.Text.Short as TS
@@ -40,10 +41,24 @@ tests = testGroup "Tests"
4041
Right (J.Object (Exts.fromList [Exts.fromList [J.Member "foo" J.True, J.Member "bar" J.False]]))
4142
@=?
4243
J.decode (Bytes.fromAsciiString "{\"foo\" : true, \"bar\": false }")
43-
, THU.testCase "D" $
44+
, THU.testCase "E" $
4445
Right (J.String "Smile: 😂")
4546
@=?
4647
J.decode (shortTextToBytes "\"Smile: 😂\"")
48+
, THU.testCase "F" $
49+
Right (J.Array (Exts.fromList [Exts.fromList [ J.Object mempty, J.Object mempty, J.Null ]]))
50+
@=?
51+
J.decode (shortTextToBytes " [ {} , { } , null ] ")
52+
, THU.testCase "G" $ case J.decode (shortTextToBytes " [ 55e2 , 1 ] ") of
53+
Right (J.Array xs) -> case Exts.toList (Chunks.concat xs) of
54+
[J.Number a, J.Number b] -> do
55+
SCI.toWord32 a @=? Just 5500
56+
SCI.toWord32 b @=? Just 1
57+
_ -> fail "no good y"
58+
_ -> fail "no good x"
59+
, THU.testCase "H" $ case J.decode (shortTextToBytes " [] x") of
60+
Left _ -> pure ()
61+
Right _ -> fail "this was not supposed parse"
4762
, THU.testCase "Twitter100" $
4863
case J.decode (Bytes.fromByteArray encodedTwitter100) of
4964
Left _ -> fail "nope"

0 commit comments

Comments
 (0)