git.iko.soy/typeable/http-api-data
on master help sign in
Merge pull request #86 from fizruk/fix-set-cookie

Try to fix SetCooke instances

commit283c7474cbbeb3e586387312dc077b51641a5350 authorOleg Grenrus <oleg.grenrus@iki.fi> dateFri 5 Oct 2018, 14:26 (8 years ago) parentaf01cff34ab187
4 files changed+56−67
CHANGELOG.md+9−1 http-api-data.cabal+2−1 src/Web/Internal/HttpApiData.hs+19−6 test/Web/Internal/HttpApiDataSpec.hs+26−59
CHANGELOG.md+9−1
@@ -1,10 +1,18 @@
1+0.3.10
2+---
3+
4+* Fix 'SetCookie' instances
5+ (see [#86](https://github.com/fizruk/http-api-data/pull/86))
6+* Add support for `Fixed`
7+ (see [#78](https://github.com/fizruk/http-api-data/pull/87))
8+
190.3.9
210---
311
412* GHC-8.6 support
513* Remove dependency on `uri-bytestring` and use functions from `http-types` instead
614 (see [#75](https://github.com/fizruk/http-api-data/pull/78))
7−* Add support for `Cookie`
15+* Add support for `SetCookie`
816 (see [#74](https://github.com/fizruk/http-api-data/pull/74))
917
10180.3.8.1
http-api-data.cabal+2−1
@@ -1,6 +1,6 @@
11cabal-version: >= 1.10
22name: http-api-data
3−version: 0.3.9
3+version: 0.3.10
44
55synopsis: Converting to/from HTTP API data like URL pieces, headers and query parameters.
66category: Web
@@ -99,6 +99,7 @@ test-suite spec
9999 , time
100100 , bytestring
101101 , uuid-types
102+ , cookie
102103
103104 build-depends: HUnit >= 1.6.0.0 && <1.7
104105 , hspec >= 2.5.5 && <2.6
src/Web/Internal/HttpApiData.hs+19−6
@@ -24,6 +24,7 @@ import Control.Monad ((<=<))
2424
2525import Data.ByteString (ByteString)
2626import qualified Data.ByteString as BS
27+import qualified Data.ByteString.Lazy as LBS
2728import Data.Monoid
2829
2930import qualified Data.Fixed as F
@@ -32,7 +33,8 @@ import Data.Word
3233
3334import Data.Text (Text)
3435import qualified Data.Text as T
35−import Data.Text.Encoding (decodeUtf8', encodeUtf8)
36+import Data.Text.Encoding (decodeUtf8With, decodeUtf8', encodeUtf8)
37+import Data.Text.Encoding.Error (lenientDecode)
3638import qualified Data.Text.Lazy as L
3739import Data.Text.Read (Reader, decimal, rational,
3840 signed)
@@ -539,13 +541,19 @@ instance (ToHttpApiData a, ToHttpApiData b) => ToHttpApiData (Either a b) where
539541 toUrlPiece (Left x) = "left " <> toUrlPiece x
540542 toUrlPiece (Right x) = "right " <> toUrlPiece x
541543
542−-- |
544+-- | /Note:/ this instance works correctly for alphanumeric name and value
545+--
543546-- >>> let Right c = parseUrlPiece "SESSID=r2t5uvjq435r4q7ib3vtdjq120" :: Either Text SetCookie
544547-- >>> toUrlPiece c
545−-- "\"SESSID=r2t5uvjq435r4q7ib3vtdjq120\""
548+-- "SESSID=r2t5uvjq435r4q7ib3vtdjq120"
549+--
550+-- >>> toHeader c
551+-- "SESSID=r2t5uvjq435r4q7ib3vtdjq120"
552+--
546553instance ToHttpApiData SetCookie where
547− toUrlPiece = showt . BS.toLazyByteString . renderSetCookie
548− toEncodedUrlPiece = renderSetCookie
554+ toUrlPiece = decodeUtf8With lenientDecode . toHeader
555+ toHeader = LBS.toStrict . BS.toLazyByteString . renderSetCookie
556+ -- toEncodedUrlPiece = renderSetCookie -- doesn't do things.
549557
550558-- |
551559-- >>> parseUrlPiece "_" :: Either Text ()
@@ -601,6 +609,9 @@ instance FromHttpApiData String where parseUrlPiece = Right . T.unpack
601609instance FromHttpApiData Text where parseUrlPiece = Right
602610instance FromHttpApiData L.Text where parseUrlPiece = Right . L.fromStrict
603611
612+instance F.HasResolution a => FromHttpApiData (F.Fixed a) where
613+ parseUrlPiece = runReader rational
614+
604615-- |
605616-- >>> toGregorian <$> parseUrlPiece "2016-12-01"
606617-- Right (2016,12,1)
@@ -681,12 +692,14 @@ instance FromHttpApiData a => FromHttpApiData (LenientData a) where
681692 parseHeader = Right . LenientData . parseHeader
682693 parseQueryParam = Right . LenientData . parseQueryParam
683694
684−-- |
695+-- | /Note:/ this instance works correctly for alphanumeric name and value
696+--
685697-- >>> parseUrlPiece "SESSID=r2t5uvjq435r4q7ib3vtdjq120" :: Either Text SetCookie
686698-- Right (SetCookie {setCookieName = "SESSID", setCookieValue = "r2t5uvjq435r4q7ib3vtdjq120", setCookiePath = Nothing, setCookieExpires = Nothing, setCookieMaxAge = Nothing, setCookieDomain = Nothing, setCookieHttpOnly = False, setCookieSecure = False, setCookieSameSite = Nothing})
687699instance FromHttpApiData SetCookie where
688700 parseUrlPiece = parseHeader . encodeUtf8
689701 parseHeader = Right . parseSetCookie
702+
690703-------------------------------------------------------------------------------
691704-- Attoparsec helpers
692705-------------------------------------------------------------------------------
test/Web/Internal/HttpApiDataSpec.hs+26−59
@@ -5,14 +5,17 @@ module Web.Internal.HttpApiDataSpec (spec) where
55import Control.Applicative
66import qualified Data.Fixed as F
77import Data.Int
8+import Data.Char
89import Data.Word
910import Data.Time
1011import qualified Data.Text as T
12+import qualified Data.Text.Encoding as TE
1113import qualified Data.Text.Lazy as L
1214import qualified Data.ByteString as BS
1315import Data.ByteString.Builder (toLazyByteString)
1416import Data.Version
1517import qualified Data.UUID.Types as UUID
18+import Web.Cookie (SetCookie, defaultSetCookie, setCookieName, setCookieValue)
1619
1720import Data.Proxy
1821
@@ -40,30 +43,24 @@ import Web.Internal.TestInstances
4043encodedUrlPieceProp :: ToHttpApiData a => a -> Property
4144encodedUrlPieceProp x = toLazyByteString (toEncodedUrlPiece (toUrlPiece x)) === toLazyByteString (toEncodedUrlPiece x)
4245
43−
46+-- | Check 'ToHttpApiData' and 'FromHttpApiData' compatibility
4447checkUrlPiece :: forall a. (Eq a, ToHttpApiData a, FromHttpApiData a, Show a, Arbitrary a) => Proxy a -> String -> Spec
45−checkUrlPiece _ name = prop name (toUrlPiece <=> parseUrlPiece :: a -> Property)
48+checkUrlPiece _ = checkUrlPiece' (arbitrary :: Gen a)
4649
47−-- | Check with given generator
4850checkUrlPiece' :: forall a. (Eq a, ToHttpApiData a, FromHttpApiData a, Show a) => Gen a -> String -> Spec
49−checkUrlPiece' gen name = prop name $ forAll gen (toUrlPiece <=> parseUrlPiece)
51+checkUrlPiece' gen name = describe name $ do
52+ prop "toUrlPiece <=> parseUrlPiece" $ forAll gen (toUrlPiece <=> parseUrlPiece :: a -> Property)
53+ prop "toQueryParam <=> parseQueryParam" $ forAll gen (toQueryParam <=> parseQueryParam :: a -> Property)
54+ prop "toHeader <=> parseHeader" $ forAll gen (toHeader <=> parseHeader :: a -> Property)
55+ prop "toEncodedUrlPiece encodes correctly" $ forAll gen encodedUrlPieceProp
5056
5157-- | Check case insensitivity for @parseUrlPiece@.
5258checkUrlPieceI :: forall a. (Eq a, ToHttpApiData a, FromHttpApiData a, Arbitrary a) => Proxy a -> String -> Spec
5359checkUrlPieceI _ = checkUrlPiece (Proxy :: Proxy (RandomCase a))
5460
55−-- | Check that 'toEncodedUrlPiece' is equivallent to default implementation.
56−checkEncodedUrlPiece :: forall a. (Show a, ToHttpApiData a, Arbitrary a) => Proxy a -> String -> Spec
57−checkEncodedUrlPiece _ = checkEncodedUrlPiece' (arbitrary :: Gen a)
58−
59−-- | Check that 'toEncodedUrlPiece' is equivallent to default implementation.
60−-- Use a given generator.
61−checkEncodedUrlPiece' :: forall a. (Show a, ToHttpApiData a) => Gen a -> String -> Spec
62−checkEncodedUrlPiece' gen name = prop name $ forAll gen encodedUrlPieceProp
63−
6461spec :: Spec
6562spec = do
66− describe "toUrlPiece <=> parseUrlPiece" $ do
63+ describe "Instances" $ do
6764 checkUrlPiece (Proxy :: Proxy ()) "()"
6865 checkUrlPiece (Proxy :: Proxy Char) "Char"
6966 checkUrlPieceI (Proxy :: Proxy Bool) "Bool"
@@ -90,6 +87,15 @@ spec = do
9087 checkUrlPiece' nominalDiffTimeGen "NominalDiffTime"
9188 checkUrlPiece (Proxy :: Proxy Version) "Version"
9289 checkUrlPiece' uuidGen "UUID"
90+ checkUrlPiece' setCookieGen "Cookie"
91+
92+ checkUrlPiece (Proxy :: Proxy F.Uni) "Uni"
93+ checkUrlPiece (Proxy :: Proxy F.Deci) "Deci"
94+ checkUrlPiece (Proxy :: Proxy F.Centi) "Centi"
95+ checkUrlPiece (Proxy :: Proxy F.Milli) "Milli"
96+ checkUrlPiece (Proxy :: Proxy F.Micro) "Micro"
97+ checkUrlPiece (Proxy :: Proxy F.Nano) "Nano"
98+ checkUrlPiece (Proxy :: Proxy F.Pico) "Pico"
9399
94100 checkUrlPiece (Proxy :: Proxy (Maybe String)) "Maybe String"
95101 checkUrlPieceI (Proxy :: Proxy (Maybe Integer)) "Maybe Integer"
@@ -100,51 +106,6 @@ spec = do
100106 checkUrlPiece (Proxy :: Proxy Natural) "Natural"
101107#endif
102108
103− describe "toEncodedUrlPiece encodes correctly" $ do
104− checkEncodedUrlPiece (Proxy :: Proxy ()) "()"
105− checkEncodedUrlPiece (Proxy :: Proxy Char) "Char"
106− checkEncodedUrlPiece (Proxy :: Proxy Bool) "Bool"
107− checkEncodedUrlPiece (Proxy :: Proxy Ordering) "Ordering"
108− checkEncodedUrlPiece (Proxy :: Proxy Int) "Int"
109− checkEncodedUrlPiece (Proxy :: Proxy Int8) "Int8"
110− checkEncodedUrlPiece (Proxy :: Proxy Int16) "Int16"
111− checkEncodedUrlPiece (Proxy :: Proxy Int32) "Int32"
112− checkEncodedUrlPiece (Proxy :: Proxy Int64) "Int64"
113− checkEncodedUrlPiece (Proxy :: Proxy Integer) "Integer"
114− checkEncodedUrlPiece (Proxy :: Proxy Word) "Word"
115− checkEncodedUrlPiece (Proxy :: Proxy Word8) "Word8"
116− checkEncodedUrlPiece (Proxy :: Proxy Word16) "Word16"
117− checkEncodedUrlPiece (Proxy :: Proxy Word32) "Word32"
118− checkEncodedUrlPiece (Proxy :: Proxy Word64) "Word64"
119− checkEncodedUrlPiece (Proxy :: Proxy String) "String"
120− checkEncodedUrlPiece (Proxy :: Proxy T.Text) "Text.Strict"
121− checkEncodedUrlPiece (Proxy :: Proxy L.Text) "Text.Lazy"
122− checkEncodedUrlPiece (Proxy :: Proxy Day) "Day"
123− checkEncodedUrlPiece' timeOfDayGen "TimeOfDay"
124− checkEncodedUrlPiece' localTimeGen "LocalTime"
125− checkEncodedUrlPiece' zonedTimeGen "ZonedTime"
126− checkEncodedUrlPiece' utcTimeGen "UTCTime"
127− checkEncodedUrlPiece' nominalDiffTimeGen "NominalDiffTime"
128− checkEncodedUrlPiece (Proxy :: Proxy Version) "Version"
129− checkEncodedUrlPiece' uuidGen "UUID"
130−
131− checkEncodedUrlPiece (Proxy :: Proxy (Maybe String)) "Maybe String"
132− checkEncodedUrlPiece (Proxy :: Proxy (Maybe Integer)) "Maybe Integer"
133− checkEncodedUrlPiece (Proxy :: Proxy (Either Integer T.Text)) "Either Integer Text"
134− checkEncodedUrlPiece (Proxy :: Proxy (Either Version Day)) "Either Version Day"
135−
136−#if MIN_VERSION_base(4,8,0)
137− checkEncodedUrlPiece (Proxy :: Proxy Natural) "Natural"
138−#endif
139−
140− checkEncodedUrlPiece (Proxy :: Proxy F.Uni) "Uni"
141− checkEncodedUrlPiece (Proxy :: Proxy F.Deci) "Deci"
142− checkEncodedUrlPiece (Proxy :: Proxy F.Centi) "Centi"
143− checkEncodedUrlPiece (Proxy :: Proxy F.Milli) "Milli"
144− checkEncodedUrlPiece (Proxy :: Proxy F.Micro) "Micro"
145− checkEncodedUrlPiece (Proxy :: Proxy F.Nano) "Nano"
146− checkEncodedUrlPiece (Proxy :: Proxy F.Pico) "Pico"
147−
148109 it "bad integers are rejected" $ do
149110 parseUrlPieceMaybe (T.pack "123hello") `shouldBe` (Nothing :: Maybe Int)
150111
@@ -179,3 +140,9 @@ utcTimeGen = UTCTime <$> arbitrary <*> fmap fromInteger (choose (0, 86400))
179140
180141nominalDiffTimeGen :: Gen NominalDiffTime
181142nominalDiffTimeGen = fromInteger <$> arbitrary
143+
144+setCookieGen :: Gen SetCookie
145+setCookieGen = do
146+ n <- TE.encodeUtf8 . T.pack . filter isAlphaNum <$> arbitrary
147+ v <- TE.encodeUtf8 . T.pack . filter isAlphaNum <$> arbitrary
148+ return $ defaultSetCookie { setCookieName = n, setCookieValue = v }