module Network.HTTP.Media.MediaType.Internal
( MediaType (..)
, Parameters
) where
import qualified Data.ByteString.Char8 as BS
import qualified Data.CaseInsensitive as CI
import qualified Data.Map as Map
import Control.Monad (foldM, guard)
import Data.ByteString (ByteString)
import Data.CaseInsensitive (CI, original)
import Data.Map (Map)
import Data.Maybe (fromMaybe)
import Data.Monoid ((<>))
import Data.String (IsString (..))
import Network.HTTP.Media.Accept (Accept (..))
import Network.HTTP.Media.RenderHeader (RenderHeader (..))
import Network.HTTP.Media.Utils (breakChar, trimBS)
data MediaType = MediaType
{ mainType :: CI ByteString
, subType :: CI ByteString
, parameters :: Parameters
} deriving (Eq, Ord)
instance Show MediaType where
show = BS.unpack . renderHeader
instance IsString MediaType where
fromString str = flip fromMaybe (parseAccept $ BS.pack str) $
error $ "Invalid media type literal " ++ str
instance Accept MediaType where
parseAccept bs = do
(s, ps) <- uncons (map trimBS (BS.split ';' bs))
(a, b) <- breakChar '/' s
guard $ not (BS.null a || BS.null b) && (a /= "*" || b == "*")
ps' <- foldM insert Map.empty ps
return $ MediaType (CI.mk a) (CI.mk b) ps'
where
uncons [] = Nothing
uncons (a : b) = Just (a, b)
both f (a, b) = (f a, f b)
insert ps =
fmap (flip (uncurry Map.insert) ps . both CI.mk) . breakChar '='
matches a b
| mainType b == "*" = params
| subType b == "*" = mainType a == mainType b && params
| otherwise = main && sub && params
where
main = mainType a == mainType b
sub = subType a == subType b
params = Map.null (parameters b) || parameters a == parameters b
moreSpecificThan a b = (a `matches` b &&) $
mainType a == "*" && anyB && params ||
subType a == "*" && (anyB || subB && params) ||
anyB || subB || params
where
anyB = mainType b == "*"
subB = subType b == "*"
params = not (Map.null $ parameters a) && Map.null (parameters b)
hasExtensionParameters _ = True
instance RenderHeader MediaType where
renderHeader (MediaType a b p) =
Map.foldrWithKey f (original a <> "/" <> original b) p
where
f k v = (<> ";" <> original k <> "=" <> original v)
type Parameters = Map (CI ByteString) (CI ByteString)