module Network.HTTP.Media
(
MediaType,
(//),
(/:),
mainType,
subType,
parameters,
(/?),
(/.),
Charset,
Encoding,
Language,
toParts,
matchAccept,
mapAccept,
mapAcceptMedia,
mapAcceptCharset,
mapAcceptEncoding,
mapAcceptLanguage,
mapAcceptBytes,
matchContent,
mapContent,
mapContentMedia,
mapContentCharset,
mapContentEncoding,
mapContentLanguage,
Quality (qualityData),
quality,
QualityOrder,
qualityOrder,
isAcceptable,
maxQuality,
minQuality,
parseQuality,
matchQuality,
mapQuality,
Accept (..),
RenderHeader (..),
)
where
import Control.Applicative ((<|>))
import Control.Monad (guard, (>=>))
import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as BS
import Data.Foldable (find, foldl', maximumBy)
import Data.Function (on)
import Data.Maybe (fromMaybe)
import Data.Proxy (Proxy (Proxy))
import Network.HTTP.Media.Accept as Accept
import Network.HTTP.Media.Charset as Charset
import Network.HTTP.Media.Encoding as Encoding
import Network.HTTP.Media.Language as Language
import Network.HTTP.Media.MediaType as MediaType
import Network.HTTP.Media.Quality
import Network.HTTP.Media.RenderHeader
import Network.HTTP.Media.Utils (trimBS)
matchAccept ::
(Accept a) =>
[a] ->
ByteString ->
Maybe a
matchAccept :: forall a. Accept a => [a] -> ByteString -> Maybe a
matchAccept = (forall a. Accept a => ByteString -> Maybe [Quality a]
parseQuality forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=>) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Accept a => [a] -> [Quality a] -> Maybe a
matchQuality
mapAccept ::
(Accept a) =>
[(a, b)] ->
ByteString ->
Maybe b
mapAccept :: forall a b. Accept a => [(a, b)] -> ByteString -> Maybe b
mapAccept = (forall a. Accept a => ByteString -> Maybe [Quality a]
parseQuality forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=>) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. Accept a => [(a, b)] -> [Quality a] -> Maybe b
mapQuality
mapAcceptMedia ::
[(MediaType, b)] ->
ByteString ->
Maybe b
mapAcceptMedia :: forall b. [(MediaType, b)] -> ByteString -> Maybe b
mapAcceptMedia = forall a b. Accept a => [(a, b)] -> ByteString -> Maybe b
mapAccept
mapAcceptCharset ::
[(Charset, b)] ->
ByteString ->
Maybe b
mapAcceptCharset :: forall b. [(Charset, b)] -> ByteString -> Maybe b
mapAcceptCharset = forall a b. Accept a => [(a, b)] -> ByteString -> Maybe b
mapAccept
mapAcceptEncoding ::
[(Encoding, b)] ->
ByteString ->
Maybe b
mapAcceptEncoding :: forall b. [(Encoding, b)] -> ByteString -> Maybe b
mapAcceptEncoding = forall a b. Accept a => [(a, b)] -> ByteString -> Maybe b
mapAccept
mapAcceptLanguage ::
[(Language, b)] ->
ByteString ->
Maybe b
mapAcceptLanguage :: forall b. [(Language, b)] -> ByteString -> Maybe b
mapAcceptLanguage = forall a b. Accept a => [(a, b)] -> ByteString -> Maybe b
mapAccept
mapAcceptBytes ::
[(ByteString, b)] ->
ByteString ->
Maybe b
mapAcceptBytes :: forall b. [(ByteString, b)] -> ByteString -> Maybe b
mapAcceptBytes = forall a b. Accept a => [(a, b)] -> ByteString -> Maybe b
mapAccept
matchContent ::
(Accept a) =>
[a] ->
ByteString ->
Maybe a
matchContent :: forall a. Accept a => [a] -> ByteString -> Maybe a
matchContent = forall b a. Accept b => (a -> b) -> [a] -> ByteString -> Maybe a
findMatch forall a. a -> a
id
mapContent ::
(Accept a) =>
[(a, b)] ->
ByteString ->
Maybe b
mapContent :: forall a b. Accept a => [(a, b)] -> ByteString -> Maybe b
mapContent [(a, b)]
options = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (a, b) -> b
snd forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall b a. Accept b => (a -> b) -> [a] -> ByteString -> Maybe a
findMatch forall a b. (a, b) -> a
fst [(a, b)]
options
mapContentMedia ::
[(MediaType, b)] ->
ByteString ->
Maybe b
mapContentMedia :: forall b. [(MediaType, b)] -> ByteString -> Maybe b
mapContentMedia = forall a b. Accept a => [(a, b)] -> ByteString -> Maybe b
mapContent
mapContentCharset ::
[(Charset, b)] ->
ByteString ->
Maybe b
mapContentCharset :: forall b. [(Charset, b)] -> ByteString -> Maybe b
mapContentCharset = forall a b. Accept a => [(a, b)] -> ByteString -> Maybe b
mapContent
mapContentEncoding ::
[(Encoding, b)] ->
ByteString ->
Maybe b
mapContentEncoding :: forall b. [(Encoding, b)] -> ByteString -> Maybe b
mapContentEncoding = forall a b. Accept a => [(a, b)] -> ByteString -> Maybe b
mapContent
mapContentLanguage ::
[(Language, b)] ->
ByteString ->
Maybe b
mapContentLanguage :: forall b. [(Language, b)] -> ByteString -> Maybe b
mapContentLanguage = forall a b. Accept a => [(a, b)] -> ByteString -> Maybe b
mapContent
parseQuality :: (Accept a) => ByteString -> Maybe [Quality a]
parseQuality :: forall a. Accept a => ByteString -> Maybe [Quality a]
parseQuality = forall a. Accept a => Proxy a -> ByteString -> Maybe [Quality a]
parseQuality' forall {k} (t :: k). Proxy t
Proxy
parseQuality' :: (Accept a) => Proxy a -> ByteString -> Maybe [Quality a]
parseQuality' :: forall a. Accept a => Proxy a -> ByteString -> Maybe [Quality a]
parseQuality' Proxy a
p = (forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map ByteString -> ByteString
trimBS forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> ByteString -> [ByteString]
BS.split Char
',') forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM forall a b. (a -> b) -> a -> b
$ \ByteString
s ->
let (ByteString
accept, Maybe ByteString
q) = forall a. a -> Maybe a -> a
fromMaybe (ByteString
s, forall a. Maybe a
Nothing) forall a b. (a -> b) -> a -> b
$ if Bool
ext then ByteString -> Maybe (ByteString, Maybe ByteString)
findQ ByteString
s else ByteString -> Maybe (ByteString, Maybe ByteString)
getQ ByteString
s
in forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a. a -> Quality a
maxQuality) (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a. a -> Word16 -> Quality a
Quality) forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Maybe Word16
readQ) Maybe ByteString
q
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall a. Accept a => ByteString -> Maybe a
parseAccept ByteString
accept
where
ext :: Bool
ext = forall a. Accept a => Proxy a -> Bool
hasExtensionParameters Proxy a
p
getQ :: ByteString -> Maybe (ByteString, Maybe ByteString)
getQ ByteString
s =
let (ByteString
a, ByteString
b) = ByteString -> ByteString
trimBS forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Char -> Bool) -> ByteString -> (ByteString, ByteString)
BS.breakEnd (forall a. Eq a => a -> a -> Bool
== Char
';') ByteString
s
in if ByteString -> Bool
BS.null ByteString
a
then forall a. Maybe a
Nothing
else
forall a. a -> Maybe a
Just
( HasCallStack => ByteString -> ByteString
BS.init ByteString
a,
if ByteString -> ByteString -> Bool
BS.isPrefixOf ByteString
"q=" ByteString
b then forall a. a -> Maybe a
Just (Int -> ByteString -> ByteString
BS.drop Int
2 ByteString
b) else forall a. Maybe a
Nothing
)
findQ :: ByteString -> Maybe (ByteString, Maybe ByteString)
findQ ByteString
s = do
let q :: Maybe (ByteString, Maybe ByteString)
q = ByteString -> Maybe (ByteString, Maybe ByteString)
getQ ByteString
s
(ByteString
a, Maybe ByteString
m) <- Maybe (ByteString, Maybe ByteString)
q
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (ByteString -> Maybe (ByteString, Maybe ByteString)
findQ ByteString
a) (forall a b. a -> b -> a
const Maybe (ByteString, Maybe ByteString)
q) Maybe ByteString
m
matchQuality ::
(Accept a) =>
[a] ->
[Quality a] ->
Maybe a
matchQuality :: forall a. Accept a => [a] -> [Quality a] -> Maybe a
matchQuality = forall a b. Accept a => (b -> a) -> [b] -> [Quality a] -> Maybe b
findQuality forall a. a -> a
id
mapQuality ::
(Accept a) =>
[(a, b)] ->
[Quality a] ->
Maybe b
mapQuality :: forall a b. Accept a => [(a, b)] -> [Quality a] -> Maybe b
mapQuality [(a, b)]
options = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (a, b) -> b
snd forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. Accept a => (b -> a) -> [b] -> [Quality a] -> Maybe b
findQuality forall a b. (a, b) -> a
fst [(a, b)]
options
findMatch :: (Accept b) => (a -> b) -> [a] -> ByteString -> Maybe a
findMatch :: forall b a. Accept b => (a -> b) -> [a] -> ByteString -> Maybe a
findMatch a -> b
f [a]
options ByteString
bs = do
b
ctype <- forall a. Accept a => ByteString -> Maybe a
parseAccept ByteString
bs
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find (forall a. Accept a => a -> a -> Bool
matches b
ctype forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> b
f) [a]
options
findQuality :: (Accept a) => (b -> a) -> [b] -> [Quality a] -> Maybe b
findQuality :: forall a b. Accept a => (b -> a) -> [b] -> [Quality a] -> Maybe b
findQuality b -> a
f [b]
options [Quality a]
acceptq = do
forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ Bool -> Bool
not (forall (t :: * -> *) a. Foldable t => t a -> Bool
null [b]
options)
Quality b
q <- forall (t :: * -> *) a.
Foldable t =>
(a -> a -> Ordering) -> t a -> a
maximumBy (forall a. Ord a => a -> a -> Ordering
compare forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. Quality a -> QualityOrder
qualityOrder) [Maybe (Quality b)]
optionsq
forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ forall a. Quality a -> Bool
isAcceptable Quality b
q
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a. Quality a -> a
qualityData Quality b
q
where
optionsq :: [Maybe (Quality b)]
optionsq = forall a. [a] -> [a]
reverse forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map b -> Maybe (Quality b)
addQuality [b]
options
addQuality :: b -> Maybe (Quality b)
addQuality b
opt = forall {a} {a}. a -> Quality a -> Quality a
withQValue b
opt forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (b -> Maybe (Quality a) -> Quality a -> Maybe (Quality a)
mfold b
opt) forall a. Maybe a
Nothing [Quality a]
acceptq
withQValue :: a -> Quality a -> Quality a
withQValue a
opt Quality a
q = Quality a
q {qualityData :: a
qualityData = a
opt}
mfold :: b -> Maybe (Quality a) -> Quality a -> Maybe (Quality a)
mfold b
opt Maybe (Quality a)
cur Quality a
q
| b -> a
f b
opt forall a. Accept a => a -> a -> Bool
`matches` forall a. Quality a -> a
qualityData Quality a
q = forall a. Accept a => Quality a -> Quality a -> Quality a
mostSpecific Quality a
q forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe (Quality a)
cur forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> forall a. a -> Maybe a
Just Quality a
q
| Bool
otherwise = Maybe (Quality a)
cur