on master help sign in
servant: allow whitespace before JSON
5413182Christian Marie
servant/src/Servant/API/ContentTypes.hs+23−22
@@ -66,30 +66,31 @@ module Servant.API.ContentTypes
66 ) where
66 ) where
67
67
68#if !MIN_VERSION_base(4,8,0)
68#if !MIN_VERSION_base(4,8,0)
69−import Control.Applicative ((<*))
69+import Control.Applicative ((*>), (<*))
70#endif
70#endif
71−import Control.Arrow (left)
71+import Control.Arrow (left)
72import Control.Monad
72import Control.Monad
73−import Data.Aeson (FromJSON, ToJSON, encode,
73+import Data.Aeson (FromJSON, ToJSON, encode,
74− parseJSON)
74+ parseJSON)
75−import Data.Aeson.Parser (value)
75+import Data.Aeson.Parser (value)
76−import Data.Aeson.Types (parseEither)
76+import Data.Aeson.Types (parseEither)
77import Data.Attoparsec.ByteString.Char8 (endOfInput, parseOnly,
77import Data.Attoparsec.ByteString.Char8 (endOfInput, parseOnly,
78 skipSpace, (<?>))
78 skipSpace, (<?>))
79−import qualified Data.ByteString as BS
79+import qualified Data.ByteString as BS
80−import Data.ByteString.Lazy (ByteString, fromStrict, toStrict)
80+import Data.ByteString.Lazy (ByteString, fromStrict,
81+ toStrict)
81−import qualified Data.ByteString.Lazy as B
82+import qualified Data.ByteString.Lazy as B
82import Data.Monoid
83import Data.Monoid
83−import Data.String.Conversions (cs)
84+import Data.String.Conversions (cs)
84−import qualified Data.Text as TextS
85+import qualified Data.Text as TextS
85−import qualified Data.Text.Encoding as TextS
86+import qualified Data.Text.Encoding as TextS
86−import qualified Data.Text.Lazy as TextL
87+import qualified Data.Text.Lazy as TextL
87−import qualified Data.Text.Lazy.Encoding as TextL
88+import qualified Data.Text.Lazy.Encoding as TextL
88import Data.Typeable
89import Data.Typeable
89−import GHC.Exts (Constraint)
90+import GHC.Exts (Constraint)
90−import qualified Network.HTTP.Media as M
91+import qualified Network.HTTP.Media as M
91−import Network.URI (escapeURIString, isUnreserved,
92+import Network.URI (escapeURIString,
92− unEscapeString)
93+ isUnreserved, unEscapeString)
93
94
94-- * Provided content types
95-- * Provided content types
95data JSON deriving Typeable
96data JSON deriving Typeable
@@ -304,10 +305,10 @@ eitherDecodeLenient :: FromJSON a => ByteString -> Either String a
304eitherDecodeLenient input =
305eitherDecodeLenient input =
305 parseOnly parser (cs input) >>= parseEither parseJSON
306 parseOnly parser (cs input) >>= parseEither parseJSON
306 where
307 where
307− parser =
308+ parser = skipSpace
308− Data.Aeson.Parser.value
309+ *> Data.Aeson.Parser.value
309− <* skipSpace
310+ <* skipSpace
310− <* (endOfInput <?> "trailing junk after valid JSON")
311+ <* (endOfInput <?> "trailing junk after valid JSON")
311
312
312-- | `eitherDecode`
313-- | `eitherDecode`
313instance FromJSON a => MimeUnrender JSON a where
314instance FromJSON a => MimeUnrender JSON a where
servant/test/Servant/API/ContentTypesSpec.hs+5−3
@@ -8,15 +8,15 @@ module Servant.API.ContentTypesSpec where
8
8
9#if !MIN_VERSION_base(4,8,0)
9#if !MIN_VERSION_base(4,8,0)
10import Control.Applicative
10import Control.Applicative
11+import Data.Monoid
11#endif
12#endif
12import Control.Arrow
13import Control.Arrow
13−import Data.Either
14import Data.Aeson
14import Data.Aeson
15import Data.Aeson.Parser (jstring)
15import Data.Aeson.Parser (jstring)
16import Data.Attoparsec.ByteString (parseOnly)
16import Data.Attoparsec.ByteString (parseOnly)
17+import Data.Either
17import Data.Function (on)
18import Data.Function (on)
18import Data.Proxy
19import Data.Proxy
19−
20import Data.ByteString.Char8 (ByteString, append, pack)
20import Data.ByteString.Char8 (ByteString, append, pack)
21import qualified Data.ByteString.Lazy as BSL
21import qualified Data.ByteString.Lazy as BSL
22import Data.List (maximumBy)
22import Data.List (maximumBy)
@@ -26,7 +26,6 @@ import Data.String.Conversions (cs)
26import qualified Data.Text as TextS
26import qualified Data.Text as TextS
27import qualified Data.Text.Lazy as TextL
27import qualified Data.Text.Lazy as TextL
28import GHC.Generics
28import GHC.Generics
29−import Data.Monoid
30import Network.URL (exportParams, importParams)
29import Network.URL (exportParams, importParams)
31import Test.Hspec
30import Test.Hspec
32import Test.QuickCheck
31import Test.QuickCheck
@@ -43,6 +42,9 @@ spec = describe "Servant.API.ContentTypes" $ do
43 it "handles whitespace at end of input" $ do
42 it "handles whitespace at end of input" $ do
44 mimeUnrender p "[1] " `shouldBe` Right [1 :: Int]
43 mimeUnrender p "[1] " `shouldBe` Right [1 :: Int]
45
44
45+ it "handles whitespace at beginning of input" $ do
46+ mimeUnrender p " [1] " `shouldBe` Right [1 :: Int]
47+
46 it "does not like junk at end of input" $ do
48 it "does not like junk at end of input" $ do
47 mimeUnrender p "[1] this probably shouldn't work"
49 mimeUnrender p "[1] this probably shouldn't work"
48 `shouldSatisfy` (isLeft :: Either a [Int] -> Bool)
50 `shouldSatisfy` (isLeft :: Either a [Int] -> Bool)