{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_HADDOCK not-home #-}
module Servant.API.ContentTypes
(
JSON
, PlainText
, FormUrlEncoded
, OctetStream
, Accept(..)
, MimeRender(..)
, MimeUnrender(..)
, NoContent(..)
, AcceptHeader(..)
, AllCTRender(..)
, AllCTUnrender(..)
, AllMime(..)
, AllMimeRender(..)
, AllMimeUnrender(..)
, eitherDecodeLenient
, canHandleAcceptH
) where
import Control.Arrow
(left)
import Control.Monad.Compat
import Control.DeepSeq
(NFData)
import Data.Aeson
(FromJSON (..), ToJSON (..), encode, eitherDecode)
import Data.Bifunctor
(bimap)
import qualified Data.ByteString as BS
import Data.ByteString.Lazy
(ByteString, fromStrict, toStrict)
import qualified Data.List.NonEmpty as NE
import Data.Maybe
(isJust)
import Data.String.Conversions
(cs)
import qualified Data.Text as TextS
import qualified Data.Text.Encoding as TextS
import qualified Data.Text.Lazy as TextL
import qualified Data.Text.Lazy.Encoding as TextL
import Data.Typeable
import GHC.Generics
(Generic)
import qualified GHC.TypeLits as TL
import qualified Network.HTTP.Media as M
import Prelude ()
import Prelude.Compat
import Web.FormUrlEncoded
(FromForm, ToForm, urlDecodeAsForm, urlEncodeAsForm)
data JSON deriving Typeable
data PlainText deriving Typeable
data FormUrlEncoded deriving Typeable
data OctetStream deriving Typeable
class Accept ctype where
contentType :: Proxy ctype -> M.MediaType
contentType = forall a. NonEmpty a -> a
NE.head forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {k} (ctype :: k).
Accept ctype =>
Proxy ctype -> NonEmpty MediaType
contentTypes
contentTypes :: Proxy ctype -> NE.NonEmpty M.MediaType
contentTypes = (forall a. a -> [a] -> NonEmpty a
NE.:| []) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {k} (ctype :: k). Accept ctype => Proxy ctype -> MediaType
contentType
{-# MINIMAL contentType | contentTypes #-}
instance Accept JSON where
contentTypes :: Proxy JSON -> NonEmpty MediaType
contentTypes Proxy JSON
_ =
ByteString
"application" ByteString -> ByteString -> MediaType
M.// ByteString
"json" MediaType -> (ByteString, ByteString) -> MediaType
M./: (ByteString
"charset", ByteString
"utf-8") forall a. a -> [a] -> NonEmpty a
NE.:|
[ ByteString
"application" ByteString -> ByteString -> MediaType
M.// ByteString
"json" ]
instance Accept FormUrlEncoded where
contentType :: Proxy FormUrlEncoded -> MediaType
contentType Proxy FormUrlEncoded
_ = ByteString
"application" ByteString -> ByteString -> MediaType
M.// ByteString
"x-www-form-urlencoded"
instance Accept PlainText where
contentType :: Proxy PlainText -> MediaType
contentType Proxy PlainText
_ = ByteString
"text" ByteString -> ByteString -> MediaType
M.// ByteString
"plain" MediaType -> (ByteString, ByteString) -> MediaType
M./: (ByteString
"charset", ByteString
"utf-8")
instance Accept OctetStream where
contentType :: Proxy OctetStream -> MediaType
contentType Proxy OctetStream
_ = ByteString
"application" ByteString -> ByteString -> MediaType
M.// ByteString
"octet-stream"
newtype = BS.ByteString
deriving (AcceptHeader -> AcceptHeader -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AcceptHeader -> AcceptHeader -> Bool
$c/= :: AcceptHeader -> AcceptHeader -> Bool
== :: AcceptHeader -> AcceptHeader -> Bool
$c== :: AcceptHeader -> AcceptHeader -> Bool
Eq, Int -> AcceptHeader -> ShowS
[AcceptHeader] -> ShowS
AcceptHeader -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [AcceptHeader] -> ShowS
$cshowList :: [AcceptHeader] -> ShowS
show :: AcceptHeader -> String
$cshow :: AcceptHeader -> String
showsPrec :: Int -> AcceptHeader -> ShowS
$cshowsPrec :: Int -> AcceptHeader -> ShowS
Show, ReadPrec [AcceptHeader]
ReadPrec AcceptHeader
Int -> ReadS AcceptHeader
ReadS [AcceptHeader]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [AcceptHeader]
$creadListPrec :: ReadPrec [AcceptHeader]
readPrec :: ReadPrec AcceptHeader
$creadPrec :: ReadPrec AcceptHeader
readList :: ReadS [AcceptHeader]
$creadList :: ReadS [AcceptHeader]
readsPrec :: Int -> ReadS AcceptHeader
$creadsPrec :: Int -> ReadS AcceptHeader
Read, Typeable, forall x. Rep AcceptHeader x -> AcceptHeader
forall x. AcceptHeader -> Rep AcceptHeader x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep AcceptHeader x -> AcceptHeader
$cfrom :: forall x. AcceptHeader -> Rep AcceptHeader x
Generic)
class Accept ctype => MimeRender ctype a where
mimeRender :: Proxy ctype -> a -> ByteString
class (AllMime list) => AllCTRender (list :: [*]) a where
handleAcceptH :: Proxy list -> AcceptHeader -> a -> Maybe (ByteString, ByteString)
instance {-# OVERLAPPABLE #-}
(Accept ct, AllMime cts, AllMimeRender (ct ': cts) a) => AllCTRender (ct ': cts) a where
handleAcceptH :: Proxy (ct : cts)
-> AcceptHeader -> a -> Maybe (ByteString, ByteString)
handleAcceptH Proxy (ct : cts)
_ (AcceptHeader ByteString
accept) a
val = forall b. [(MediaType, b)] -> ByteString -> Maybe b
M.mapAcceptMedia [(MediaType, (ByteString, ByteString))]
lkup ByteString
accept
where pctyps :: Proxy (ct : cts)
pctyps = forall {k} (t :: k). Proxy t
Proxy :: Proxy (ct ': cts)
amrs :: [(MediaType, ByteString)]
amrs = forall (list :: [*]) a.
AllMimeRender list a =>
Proxy list -> a -> [(MediaType, ByteString)]
allMimeRender Proxy (ct : cts)
pctyps a
val
lkup :: [(MediaType, (ByteString, ByteString))]
lkup = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\(MediaType
a,ByteString
b) -> (MediaType
a, (ByteString -> ByteString
fromStrict forall a b. (a -> b) -> a -> b
$ forall h. RenderHeader h => h -> ByteString
M.renderHeader MediaType
a, ByteString
b))) [(MediaType, ByteString)]
amrs
instance TL.TypeError ('TL.Text "No instance for (), use NoContent instead.")
=> AllCTRender '[] () where
handleAcceptH :: Proxy '[] -> AcceptHeader -> () -> Maybe (ByteString, ByteString)
handleAcceptH Proxy '[]
_ AcceptHeader
_ ()
_ = forall a. HasCallStack => String -> a
error String
"unreachable"
class Accept ctype => MimeUnrender ctype a where
mimeUnrender :: Proxy ctype -> ByteString -> Either String a
mimeUnrender Proxy ctype
p = forall {k} (ctype :: k) a.
MimeUnrender ctype a =>
Proxy ctype -> MediaType -> ByteString -> Either String a
mimeUnrenderWithType Proxy ctype
p (forall {k} (ctype :: k). Accept ctype => Proxy ctype -> MediaType
contentType Proxy ctype
p)
mimeUnrenderWithType :: Proxy ctype -> M.MediaType -> ByteString -> Either String a
mimeUnrenderWithType Proxy ctype
p MediaType
_ = forall {k} (ctype :: k) a.
MimeUnrender ctype a =>
Proxy ctype -> ByteString -> Either String a
mimeUnrender Proxy ctype
p
{-# MINIMAL mimeUnrender | mimeUnrenderWithType #-}
class AllCTUnrender (list :: [*]) a where
canHandleCTypeH
:: Proxy list
-> ByteString
-> Maybe (ByteString -> Either String a)
handleCTypeH :: Proxy list
-> ByteString
-> ByteString
-> Maybe (Either String a)
handleCTypeH Proxy list
p ByteString
ctypeH ByteString
body = (forall a b. (a -> b) -> a -> b
$ ByteString
body) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` forall (list :: [*]) a.
AllCTUnrender list a =>
Proxy list -> ByteString -> Maybe (ByteString -> Either String a)
canHandleCTypeH Proxy list
p ByteString
ctypeH
instance ( AllMimeUnrender ctyps a ) => AllCTUnrender ctyps a where
canHandleCTypeH :: Proxy ctyps -> ByteString -> Maybe (ByteString -> Either String a)
canHandleCTypeH Proxy ctyps
p ByteString
ctypeH =
forall b. [(MediaType, b)] -> ByteString -> Maybe b
M.mapContentMedia (forall (list :: [*]) a.
AllMimeUnrender list a =>
Proxy list -> [(MediaType, ByteString -> Either String a)]
allMimeUnrender Proxy ctyps
p) (forall a b. ConvertibleStrings a b => a -> b
cs ByteString
ctypeH)
class AllMime (list :: [*]) where
allMime :: Proxy list -> [M.MediaType]
instance AllMime '[] where
allMime :: Proxy '[] -> [MediaType]
allMime Proxy '[]
_ = []
instance (Accept ctyp, AllMime ctyps) => AllMime (ctyp ': ctyps) where
allMime :: Proxy (ctyp : ctyps) -> [MediaType]
allMime Proxy (ctyp : ctyps)
_ = forall a. NonEmpty a -> [a]
NE.toList (forall {k} (ctype :: k).
Accept ctype =>
Proxy ctype -> NonEmpty MediaType
contentTypes Proxy ctyp
pctyp) forall a. [a] -> [a] -> [a]
++ forall (list :: [*]). AllMime list => Proxy list -> [MediaType]
allMime Proxy ctyps
pctyps
where
pctyp :: Proxy ctyp
pctyp = forall {k} (t :: k). Proxy t
Proxy :: Proxy ctyp
pctyps :: Proxy ctyps
pctyps = forall {k} (t :: k). Proxy t
Proxy :: Proxy ctyps
canHandleAcceptH :: AllMime list => Proxy list -> AcceptHeader -> Bool
canHandleAcceptH :: forall (list :: [*]).
AllMime list =>
Proxy list -> AcceptHeader -> Bool
canHandleAcceptH Proxy list
p (AcceptHeader ByteString
h ) = forall a. Maybe a -> Bool
isJust forall a b. (a -> b) -> a -> b
$ forall a. Accept a => [a] -> ByteString -> Maybe a
M.matchAccept (forall (list :: [*]). AllMime list => Proxy list -> [MediaType]
allMime Proxy list
p) ByteString
h
class (AllMime list) => AllMimeRender (list :: [*]) a where
allMimeRender :: Proxy list
-> a
-> [(M.MediaType, ByteString)]
instance {-# OVERLAPPABLE #-} ( MimeRender ctyp a ) => AllMimeRender '[ctyp] a where
allMimeRender :: Proxy '[ctyp] -> a -> [(MediaType, ByteString)]
allMimeRender Proxy '[ctyp]
_ a
a = forall a b. (a -> b) -> [a] -> [b]
map (, ByteString
bs) forall a b. (a -> b) -> a -> b
$ forall a. NonEmpty a -> [a]
NE.toList forall a b. (a -> b) -> a -> b
$ forall {k} (ctype :: k).
Accept ctype =>
Proxy ctype -> NonEmpty MediaType
contentTypes Proxy ctyp
pctyp
where
bs :: ByteString
bs = forall {k} (ctype :: k) a.
MimeRender ctype a =>
Proxy ctype -> a -> ByteString
mimeRender Proxy ctyp
pctyp a
a
pctyp :: Proxy ctyp
pctyp = forall {k} (t :: k). Proxy t
Proxy :: Proxy ctyp
instance {-# OVERLAPPABLE #-}
( MimeRender ctyp a
, AllMimeRender (ctyp' ': ctyps) a
) => AllMimeRender (ctyp ': ctyp' ': ctyps) a where
allMimeRender :: Proxy (ctyp : ctyp' : ctyps) -> a -> [(MediaType, ByteString)]
allMimeRender Proxy (ctyp : ctyp' : ctyps)
_ a
a =
forall a b. (a -> b) -> [a] -> [b]
map (, ByteString
bs) (forall a. NonEmpty a -> [a]
NE.toList forall a b. (a -> b) -> a -> b
$ forall {k} (ctype :: k).
Accept ctype =>
Proxy ctype -> NonEmpty MediaType
contentTypes Proxy ctyp
pctyp)
forall a. [a] -> [a] -> [a]
++ forall (list :: [*]) a.
AllMimeRender list a =>
Proxy list -> a -> [(MediaType, ByteString)]
allMimeRender Proxy (ctyp' : ctyps)
pctyps a
a
where
bs :: ByteString
bs = forall {k} (ctype :: k) a.
MimeRender ctype a =>
Proxy ctype -> a -> ByteString
mimeRender Proxy ctyp
pctyp a
a
pctyp :: Proxy ctyp
pctyp = forall {k} (t :: k). Proxy t
Proxy :: Proxy ctyp
pctyps :: Proxy (ctyp' : ctyps)
pctyps = forall {k} (t :: k). Proxy t
Proxy :: Proxy (ctyp' ': ctyps)
instance {-# OVERLAPPING #-} ( Accept ctyp ) => AllMimeRender '[ctyp] NoContent where
allMimeRender :: Proxy '[ctyp] -> NoContent -> [(MediaType, ByteString)]
allMimeRender Proxy '[ctyp]
_ NoContent
NoContent = forall a b. (a -> b) -> [a] -> [b]
map (, ByteString
"") forall a b. (a -> b) -> a -> b
$ forall a. NonEmpty a -> [a]
NE.toList forall a b. (a -> b) -> a -> b
$ forall {k} (ctype :: k).
Accept ctype =>
Proxy ctype -> NonEmpty MediaType
contentTypes Proxy ctyp
pctyp
where
pctyp :: Proxy ctyp
pctyp = forall {k} (t :: k). Proxy t
Proxy :: Proxy ctyp
instance {-# OVERLAPPING #-}
( AllMime (ctyp ': ctyp' ': ctyps)
) => AllMimeRender (ctyp ': ctyp' ': ctyps) NoContent where
allMimeRender :: Proxy (ctyp : ctyp' : ctyps)
-> NoContent -> [(MediaType, ByteString)]
allMimeRender Proxy (ctyp : ctyp' : ctyps)
p NoContent
_ = forall a b. [a] -> [b] -> [(a, b)]
zip (forall (list :: [*]). AllMime list => Proxy list -> [MediaType]
allMime Proxy (ctyp : ctyp' : ctyps)
p) (forall a. a -> [a]
repeat ByteString
"")
class (AllMime list) => AllMimeUnrender (list :: [*]) a where
allMimeUnrender :: Proxy list
-> [(M.MediaType, ByteString -> Either String a)]
instance AllMimeUnrender '[] a where
allMimeUnrender :: Proxy '[] -> [(MediaType, ByteString -> Either String a)]
allMimeUnrender Proxy '[]
_ = []
instance ( MimeUnrender ctyp a
, AllMimeUnrender ctyps a
) => AllMimeUnrender (ctyp ': ctyps) a where
allMimeUnrender :: Proxy (ctyp : ctyps)
-> [(MediaType, ByteString -> Either String a)]
allMimeUnrender Proxy (ctyp : ctyps)
_ =
forall a b. (a -> b) -> [a] -> [b]
map MediaType -> (MediaType, ByteString -> Either String a)
mk (forall a. NonEmpty a -> [a]
NE.toList forall a b. (a -> b) -> a -> b
$ forall {k} (ctype :: k).
Accept ctype =>
Proxy ctype -> NonEmpty MediaType
contentTypes Proxy ctyp
pctyp)
forall a. [a] -> [a] -> [a]
++ forall (list :: [*]) a.
AllMimeUnrender list a =>
Proxy list -> [(MediaType, ByteString -> Either String a)]
allMimeUnrender Proxy ctyps
pctyps
where
mk :: MediaType -> (MediaType, ByteString -> Either String a)
mk MediaType
ct = (MediaType
ct, forall {k} (ctype :: k) a.
MimeUnrender ctype a =>
Proxy ctype -> MediaType -> ByteString -> Either String a
mimeUnrenderWithType Proxy ctyp
pctyp MediaType
ct)
pctyp :: Proxy ctyp
pctyp = forall {k} (t :: k). Proxy t
Proxy :: Proxy ctyp
pctyps :: Proxy ctyps
pctyps = forall {k} (t :: k). Proxy t
Proxy :: Proxy ctyps
instance {-# OVERLAPPABLE #-}
ToJSON a => MimeRender JSON a where
mimeRender :: Proxy JSON -> a -> ByteString
mimeRender Proxy JSON
_ = forall a. ToJSON a => a -> ByteString
encode
instance {-# OVERLAPPABLE #-}
ToForm a => MimeRender FormUrlEncoded a where
mimeRender :: Proxy FormUrlEncoded -> a -> ByteString
mimeRender Proxy FormUrlEncoded
_ = forall a. ToForm a => a -> ByteString
urlEncodeAsForm
instance MimeRender PlainText TextL.Text where
mimeRender :: Proxy PlainText -> Text -> ByteString
mimeRender Proxy PlainText
_ = Text -> ByteString
TextL.encodeUtf8
instance MimeRender PlainText TextS.Text where
mimeRender :: Proxy PlainText -> Text -> ByteString
mimeRender Proxy PlainText
_ = ByteString -> ByteString
fromStrict forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
TextS.encodeUtf8
instance MimeRender PlainText String where
mimeRender :: Proxy PlainText -> String -> ByteString
mimeRender Proxy PlainText
_ = Text -> ByteString
TextL.encodeUtf8 forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
TextL.pack
instance MimeRender OctetStream ByteString where
mimeRender :: Proxy OctetStream -> ByteString -> ByteString
mimeRender Proxy OctetStream
_ = forall a. a -> a
id
instance MimeRender OctetStream BS.ByteString where
mimeRender :: Proxy OctetStream -> ByteString -> ByteString
mimeRender Proxy OctetStream
_ = ByteString -> ByteString
fromStrict
data NoContent = NoContent
deriving (Int -> NoContent -> ShowS
[NoContent] -> ShowS
NoContent -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [NoContent] -> ShowS
$cshowList :: [NoContent] -> ShowS
show :: NoContent -> String
$cshow :: NoContent -> String
showsPrec :: Int -> NoContent -> ShowS
$cshowsPrec :: Int -> NoContent -> ShowS
Show, NoContent -> NoContent -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: NoContent -> NoContent -> Bool
$c/= :: NoContent -> NoContent -> Bool
== :: NoContent -> NoContent -> Bool
$c== :: NoContent -> NoContent -> Bool
Eq, ReadPrec [NoContent]
ReadPrec NoContent
Int -> ReadS NoContent
ReadS [NoContent]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [NoContent]
$creadListPrec :: ReadPrec [NoContent]
readPrec :: ReadPrec NoContent
$creadPrec :: ReadPrec NoContent
readList :: ReadS [NoContent]
$creadList :: ReadS [NoContent]
readsPrec :: Int -> ReadS NoContent
$creadsPrec :: Int -> ReadS NoContent
Read, forall x. Rep NoContent x -> NoContent
forall x. NoContent -> Rep NoContent x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep NoContent x -> NoContent
$cfrom :: forall x. NoContent -> Rep NoContent x
Generic)
instance NFData NoContent
eitherDecodeLenient :: FromJSON a => ByteString -> Either String a
eitherDecodeLenient :: forall a. FromJSON a => ByteString -> Either String a
eitherDecodeLenient = forall a. FromJSON a => ByteString -> Either String a
eitherDecode
{-# DEPRECATED eitherDecodeLenient "use eitherDecode instead" #-}
instance FromJSON a => MimeUnrender JSON a where
mimeUnrender :: Proxy JSON -> ByteString -> Either String a
mimeUnrender Proxy JSON
_ = forall a. FromJSON a => ByteString -> Either String a
eitherDecode
instance FromForm a => MimeUnrender FormUrlEncoded a where
mimeUnrender :: Proxy FormUrlEncoded -> ByteString -> Either String a
mimeUnrender Proxy FormUrlEncoded
_ = forall (a :: * -> * -> *) b c d.
ArrowChoice a =>
a b c -> a (Either b d) (Either c d)
left Text -> String
TextS.unpack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FromForm a => ByteString -> Either Text a
urlDecodeAsForm
instance MimeUnrender PlainText TextL.Text where
mimeUnrender :: Proxy PlainText -> ByteString -> Either String Text
mimeUnrender Proxy PlainText
_ = forall (a :: * -> * -> *) b c d.
ArrowChoice a =>
a b c -> a (Either b d) (Either c d)
left forall a. Show a => a -> String
show forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either UnicodeException Text
TextL.decodeUtf8'
instance MimeUnrender PlainText TextS.Text where
mimeUnrender :: Proxy PlainText -> ByteString -> Either String Text
mimeUnrender Proxy PlainText
_ = forall (a :: * -> * -> *) b c d.
ArrowChoice a =>
a b c -> a (Either b d) (Either c d)
left forall a. Show a => a -> String
show forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either UnicodeException Text
TextS.decodeUtf8' forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
toStrict
instance MimeUnrender PlainText String where
mimeUnrender :: Proxy PlainText -> ByteString -> Either String String
mimeUnrender Proxy PlainText
_ = forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap forall a. Show a => a -> String
show Text -> String
TextL.unpack forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either UnicodeException Text
TextL.decodeUtf8'
instance MimeUnrender OctetStream ByteString where
mimeUnrender :: Proxy OctetStream -> ByteString -> Either String ByteString
mimeUnrender Proxy OctetStream
_ = forall a b. b -> Either a b
Right forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> a
id
instance MimeUnrender OctetStream BS.ByteString where
mimeUnrender :: Proxy OctetStream -> ByteString -> Either String ByteString
mimeUnrender Proxy OctetStream
_ = forall a b. b -> Either a b
Right forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
toStrict