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 = (ByteString -> Maybe [Quality a]
forall a. Accept a => ByteString -> Maybe [Quality a]
parseQuality (ByteString -> Maybe [Quality a])
-> ([Quality a] -> Maybe a) -> ByteString -> Maybe a
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=>) (([Quality a] -> Maybe a) -> ByteString -> Maybe a)
-> ([a] -> [Quality a] -> Maybe a) -> [a] -> ByteString -> Maybe a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> [Quality a] -> Maybe a
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 = (ByteString -> Maybe [Quality a]
forall a. Accept a => ByteString -> Maybe [Quality a]
parseQuality (ByteString -> Maybe [Quality a])
-> ([Quality a] -> Maybe b) -> ByteString -> Maybe b
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=>) (([Quality a] -> Maybe b) -> ByteString -> Maybe b)
-> ([(a, b)] -> [Quality a] -> Maybe b)
-> [(a, b)]
-> ByteString
-> Maybe b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(a, b)] -> [Quality a] -> Maybe b
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 = [(MediaType, b)] -> ByteString -> Maybe b
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 = [(Charset, b)] -> ByteString -> Maybe b
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 = [(Encoding, b)] -> ByteString -> Maybe b
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 = [(Language, b)] -> ByteString -> Maybe b
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 = [(ByteString, b)] -> ByteString -> Maybe b
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 = (a -> a) -> [a] -> ByteString -> Maybe a
forall b a. Accept b => (a -> b) -> [a] -> ByteString -> Maybe a
findMatch a -> a
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 = ((a, b) -> b) -> Maybe (a, b) -> Maybe b
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (a, b) -> b
forall a b. (a, b) -> b
snd (Maybe (a, b) -> Maybe b)
-> (ByteString -> Maybe (a, b)) -> ByteString -> Maybe b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((a, b) -> a) -> [(a, b)] -> ByteString -> Maybe (a, b)
forall b a. Accept b => (a -> b) -> [a] -> ByteString -> Maybe a
findMatch (a, b) -> a
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 = [(MediaType, b)] -> ByteString -> Maybe b
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 = [(Charset, b)] -> ByteString -> Maybe b
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 = [(Encoding, b)] -> ByteString -> Maybe b
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 = [(Language, b)] -> ByteString -> Maybe b
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 = Proxy a -> ByteString -> Maybe [Quality a]
forall a. Accept a => Proxy a -> ByteString -> Maybe [Quality a]
parseQuality' Proxy a
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 = (([ByteString] -> Maybe [Quality a])
-> (ByteString -> [ByteString]) -> ByteString -> Maybe [Quality a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> ByteString) -> [ByteString] -> [ByteString]
forall a b. (a -> b) -> [a] -> [b]
map ByteString -> ByteString
trimBS ([ByteString] -> [ByteString])
-> (ByteString -> [ByteString]) -> ByteString -> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> ByteString -> [ByteString]
BS.split Char
',') (([ByteString] -> Maybe [Quality a])
-> ByteString -> Maybe [Quality a])
-> ((ByteString -> Maybe (Quality a))
-> [ByteString] -> Maybe [Quality a])
-> (ByteString -> Maybe (Quality a))
-> ByteString
-> Maybe [Quality a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> Maybe (Quality a))
-> [ByteString] -> Maybe [Quality a]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM ((ByteString -> Maybe (Quality a))
-> ByteString -> Maybe [Quality a])
-> (ByteString -> Maybe (Quality a))
-> ByteString
-> Maybe [Quality a]
forall a b. (a -> b) -> a -> b
$ \ByteString
s ->
let (ByteString
accept, Maybe ByteString
q) = (ByteString, Maybe ByteString)
-> Maybe (ByteString, Maybe ByteString)
-> (ByteString, Maybe ByteString)
forall a. a -> Maybe a -> a
fromMaybe (ByteString
s, Maybe ByteString
forall a. Maybe a
Nothing) (Maybe (ByteString, Maybe ByteString)
-> (ByteString, Maybe ByteString))
-> Maybe (ByteString, Maybe ByteString)
-> (ByteString, Maybe ByteString)
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 Maybe (a -> Quality a)
-> (ByteString -> Maybe (a -> Quality a))
-> Maybe ByteString
-> Maybe (a -> Quality a)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe ((a -> Quality a) -> Maybe (a -> Quality a)
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a -> Quality a
forall a. a -> Quality a
maxQuality) ((Word16 -> a -> Quality a)
-> Maybe Word16 -> Maybe (a -> Quality a)
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((a -> Word16 -> Quality a) -> Word16 -> a -> Quality a
forall a b c. (a -> b -> c) -> b -> a -> c
flip a -> Word16 -> Quality a
forall a. a -> Word16 -> Quality a
Quality) (Maybe Word16 -> Maybe (a -> Quality a))
-> (ByteString -> Maybe Word16)
-> ByteString
-> Maybe (a -> Quality a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Maybe Word16
readQ) Maybe ByteString
q
Maybe (a -> Quality a) -> Maybe a -> Maybe (Quality a)
forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> ByteString -> Maybe a
forall a. Accept a => ByteString -> Maybe a
parseAccept ByteString
accept
where
ext :: Bool
ext = Proxy a -> Bool
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 (ByteString -> ByteString)
-> (ByteString, ByteString) -> (ByteString, ByteString)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Char -> Bool) -> ByteString -> (ByteString, ByteString)
BS.breakEnd (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
';') ByteString
s
in if ByteString -> Bool
BS.null ByteString
a
then Maybe (ByteString, Maybe ByteString)
forall a. Maybe a
Nothing
else
(ByteString, Maybe ByteString)
-> Maybe (ByteString, Maybe ByteString)
forall a. a -> Maybe a
Just
( HasCallStack => ByteString -> ByteString
ByteString -> ByteString
BS.init ByteString
a,
if ByteString -> ByteString -> Bool
BS.isPrefixOf ByteString
"q=" ByteString
b then ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (Int -> ByteString -> ByteString
BS.drop Int
2 ByteString
b) else Maybe ByteString
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
Maybe (ByteString, Maybe ByteString)
-> (ByteString -> Maybe (ByteString, Maybe ByteString))
-> Maybe ByteString
-> Maybe (ByteString, Maybe ByteString)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (ByteString -> Maybe (ByteString, Maybe ByteString)
findQ ByteString
a) (Maybe (ByteString, Maybe ByteString)
-> ByteString -> Maybe (ByteString, Maybe ByteString)
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 = (a -> a) -> [a] -> [Quality a] -> Maybe a
forall a b. Accept a => (b -> a) -> [b] -> [Quality a] -> Maybe b
findQuality a -> a
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 = ((a, b) -> b) -> Maybe (a, b) -> Maybe b
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (a, b) -> b
forall a b. (a, b) -> b
snd (Maybe (a, b) -> Maybe b)
-> ([Quality a] -> Maybe (a, b)) -> [Quality a] -> Maybe b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((a, b) -> a) -> [(a, b)] -> [Quality a] -> Maybe (a, b)
forall a b. Accept a => (b -> a) -> [b] -> [Quality a] -> Maybe b
findQuality (a, b) -> a
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 <- ByteString -> Maybe b
forall a. Accept a => ByteString -> Maybe a
parseAccept ByteString
bs
(a -> Bool) -> [a] -> Maybe a
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find (b -> b -> Bool
forall a. Accept a => a -> a -> Bool
matches b
ctype (b -> Bool) -> (a -> b) -> a -> Bool
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
Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ Bool -> Bool
not ([b] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [b]
options)
Quality b
q <- (Maybe (Quality b) -> Maybe (Quality b) -> Ordering)
-> [Maybe (Quality b)] -> Maybe (Quality b)
forall (t :: * -> *) a.
Foldable t =>
(a -> a -> Ordering) -> t a -> a
maximumBy (Maybe QualityOrder -> Maybe QualityOrder -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Maybe QualityOrder -> Maybe QualityOrder -> Ordering)
-> (Maybe (Quality b) -> Maybe QualityOrder)
-> Maybe (Quality b)
-> Maybe (Quality b)
-> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` (Quality b -> QualityOrder)
-> Maybe (Quality b) -> Maybe QualityOrder
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Quality b -> QualityOrder
forall a. Quality a -> QualityOrder
qualityOrder) [Maybe (Quality b)]
optionsq
Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ Quality b -> Bool
forall a. Quality a -> Bool
isAcceptable Quality b
q
b -> Maybe b
forall a. a -> Maybe a
forall (m :: * -> *) a. Monad m => a -> m a
return (b -> Maybe b) -> b -> Maybe b
forall a b. (a -> b) -> a -> b
$ Quality b -> b
forall a. Quality a -> a
qualityData Quality b
q
where
optionsq :: [Maybe (Quality b)]
optionsq = [Maybe (Quality b)] -> [Maybe (Quality b)]
forall a. [a] -> [a]
reverse ([Maybe (Quality b)] -> [Maybe (Quality b)])
-> [Maybe (Quality b)] -> [Maybe (Quality b)]
forall a b. (a -> b) -> a -> b
$ (b -> Maybe (Quality b)) -> [b] -> [Maybe (Quality b)]
forall a b. (a -> b) -> [a] -> [b]
map b -> Maybe (Quality b)
addQuality [b]
options
addQuality :: b -> Maybe (Quality b)
addQuality b
opt = b -> Quality a -> Quality b
forall {a} {a}. a -> Quality a -> Quality a
withQValue b
opt (Quality a -> Quality b) -> Maybe (Quality a) -> Maybe (Quality b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Maybe (Quality a) -> Quality a -> Maybe (Quality a))
-> Maybe (Quality a) -> [Quality a] -> Maybe (Quality a)
forall b a. (b -> a -> b) -> b -> [a] -> 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) Maybe (Quality a)
forall a. Maybe a
Nothing [Quality a]
acceptq
withQValue :: a -> Quality a -> Quality a
withQValue a
opt Quality a
q = Quality a
q {qualityData = 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 a -> a -> Bool
forall a. Accept a => a -> a -> Bool
`matches` Quality a -> a
forall a. Quality a -> a
qualityData Quality a
q = Quality a -> Quality a -> Quality a
forall a. Accept a => Quality a -> Quality a -> Quality a
mostSpecific Quality a
q (Quality a -> Quality a) -> Maybe (Quality a) -> Maybe (Quality a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe (Quality a)
cur Maybe (Quality a) -> Maybe (Quality a) -> Maybe (Quality a)
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Quality a -> Maybe (Quality a)
forall a. a -> Maybe a
Just Quality a
q
| Bool
otherwise = Maybe (Quality a)
cur