|
Packit |
acf257 |
-----------------------------------------------------------------------------
|
|
Packit |
acf257 |
-- |
|
|
Packit |
acf257 |
-- Module : Network.HTTP.Cookie
|
|
Packit |
acf257 |
-- Copyright : See LICENSE file
|
|
Packit |
acf257 |
-- License : BSD
|
|
Packit |
acf257 |
--
|
|
Packit |
acf257 |
-- Maintainer : Ganesh Sittampalam <ganesh@earth.li>
|
|
Packit |
acf257 |
-- Stability : experimental
|
|
Packit |
acf257 |
-- Portability : non-portable (not tested)
|
|
Packit |
acf257 |
--
|
|
Packit |
acf257 |
-- This module provides the data types and functions for working with HTTP cookies.
|
|
Packit |
acf257 |
-- Right now, it contains mostly functionality needed by 'Network.Browser'.
|
|
Packit |
acf257 |
--
|
|
Packit |
acf257 |
-----------------------------------------------------------------------------
|
|
Packit |
acf257 |
module Network.HTTP.Cookie
|
|
Packit |
acf257 |
( Cookie(..)
|
|
Packit |
acf257 |
, cookieMatch -- :: (String,String) -> Cookie -> Bool
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
-- functions for translating cookies and headers.
|
|
Packit |
acf257 |
, cookiesToHeader -- :: [Cookie] -> Header
|
|
Packit |
acf257 |
, processCookieHeaders -- :: String -> [Header] -> ([String], [Cookie])
|
|
Packit |
acf257 |
) where
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
import Network.HTTP.Headers
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
import Data.Char
|
|
Packit |
acf257 |
import Data.List
|
|
Packit |
acf257 |
import Data.Maybe
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
import Text.ParserCombinators.Parsec
|
|
Packit |
acf257 |
( Parser, char, many, many1, satisfy, parse, option, try
|
|
Packit |
acf257 |
, (<|>), sepBy1
|
|
Packit |
acf257 |
)
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
------------------------------------------------------------------
|
|
Packit |
acf257 |
----------------------- Cookie Stuff -----------------------------
|
|
Packit |
acf257 |
------------------------------------------------------------------
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
-- | @Cookie@ is the Haskell representation of HTTP cookie values.
|
|
Packit |
acf257 |
-- See its relevant specs for authoritative details.
|
|
Packit |
acf257 |
data Cookie
|
|
Packit |
acf257 |
= MkCookie
|
|
Packit |
acf257 |
{ ckDomain :: String
|
|
Packit |
acf257 |
, ckName :: String
|
|
Packit |
acf257 |
, ckValue :: String
|
|
Packit |
acf257 |
, ckPath :: Maybe String
|
|
Packit |
acf257 |
, ckComment :: Maybe String
|
|
Packit |
acf257 |
, ckVersion :: Maybe String
|
|
Packit |
acf257 |
}
|
|
Packit |
acf257 |
deriving(Show,Read)
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
instance Eq Cookie where
|
|
Packit |
acf257 |
a == b = ckDomain a == ckDomain b
|
|
Packit |
acf257 |
&& ckName a == ckName b
|
|
Packit |
acf257 |
&& ckPath a == ckPath b
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
-- | @cookieToHeaders ck@ serialises @Cookie@s to an HTTP request header.
|
|
Packit |
acf257 |
cookiesToHeader :: [Cookie] -> Header
|
|
Packit |
acf257 |
cookiesToHeader cs = Header HdrCookie (mkCookieHeaderValue cs)
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
-- | Turn a list of cookies into a key=value pair list, separated by
|
|
Packit |
acf257 |
-- semicolons.
|
|
Packit |
acf257 |
mkCookieHeaderValue :: [Cookie] -> String
|
|
Packit |
acf257 |
mkCookieHeaderValue = intercalate "; " . map mkCookieHeaderValue1
|
|
Packit |
acf257 |
where
|
|
Packit |
acf257 |
mkCookieHeaderValue1 c = ckName c ++ "=" ++ ckValue c
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
-- | @cookieMatch (domain,path) ck@ performs the standard cookie
|
|
Packit |
acf257 |
-- match wrt the given domain and path.
|
|
Packit |
acf257 |
cookieMatch :: (String, String) -> Cookie -> Bool
|
|
Packit |
acf257 |
cookieMatch (dom,path) ck =
|
|
Packit |
acf257 |
ckDomain ck `isSuffixOf` dom &&
|
|
Packit |
acf257 |
case ckPath ck of
|
|
Packit |
acf257 |
Nothing -> True
|
|
Packit |
acf257 |
Just p -> p `isPrefixOf` path
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
-- | @processCookieHeaders dom hdrs@
|
|
Packit |
acf257 |
processCookieHeaders :: String -> [Header] -> ([String], [Cookie])
|
|
Packit |
acf257 |
processCookieHeaders dom hdrs = foldr (headerToCookies dom) ([],[]) hdrs
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
-- | @headerToCookies dom hdr acc@
|
|
Packit |
acf257 |
headerToCookies :: String -> Header -> ([String], [Cookie]) -> ([String], [Cookie])
|
|
Packit |
acf257 |
headerToCookies dom (Header HdrSetCookie val) (accErr, accCookie) =
|
|
Packit |
acf257 |
case parse cookies "" val of
|
|
Packit |
acf257 |
Left{} -> (val:accErr, accCookie)
|
|
Packit |
acf257 |
Right x -> (accErr, x ++ accCookie)
|
|
Packit |
acf257 |
where
|
|
Packit |
acf257 |
cookies :: Parser [Cookie]
|
|
Packit |
acf257 |
cookies = sepBy1 cookie (char ',')
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
cookie :: Parser Cookie
|
|
Packit |
acf257 |
cookie =
|
|
Packit |
acf257 |
do name <- word
|
|
Packit |
acf257 |
_ <- spaces_l
|
|
Packit |
acf257 |
_ <- char '='
|
|
Packit |
acf257 |
_ <- spaces_l
|
|
Packit |
acf257 |
val1 <- cvalue
|
|
Packit |
acf257 |
args <- cdetail
|
|
Packit |
acf257 |
return $ mkCookie name val1 args
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
cvalue :: Parser String
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
spaces_l = many (satisfy isSpace)
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
cvalue = quotedstring <|> many1 (satisfy $ not . (==';')) <|> return ""
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
-- all keys in the result list MUST be in lower case
|
|
Packit |
acf257 |
cdetail :: Parser [(String,String)]
|
|
Packit |
acf257 |
cdetail = many $
|
|
Packit |
acf257 |
try (do _ <- spaces_l
|
|
Packit |
acf257 |
_ <- char ';'
|
|
Packit |
acf257 |
_ <- spaces_l
|
|
Packit |
acf257 |
s1 <- word
|
|
Packit |
acf257 |
_ <- spaces_l
|
|
Packit |
acf257 |
s2 <- option "" (char '=' >> spaces_l >> cvalue)
|
|
Packit |
acf257 |
return (map toLower s1,s2)
|
|
Packit |
acf257 |
)
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
mkCookie :: String -> String -> [(String,String)] -> Cookie
|
|
Packit |
acf257 |
mkCookie nm cval more =
|
|
Packit |
acf257 |
MkCookie { ckName = nm
|
|
Packit |
acf257 |
, ckValue = cval
|
|
Packit |
acf257 |
, ckDomain = map toLower (fromMaybe dom (lookup "domain" more))
|
|
Packit |
acf257 |
, ckPath = lookup "path" more
|
|
Packit |
acf257 |
, ckVersion = lookup "version" more
|
|
Packit |
acf257 |
, ckComment = lookup "comment" more
|
|
Packit |
acf257 |
}
|
|
Packit |
acf257 |
headerToCookies _ _ acc = acc
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
word, quotedstring :: Parser String
|
|
Packit |
acf257 |
quotedstring =
|
|
Packit |
acf257 |
do _ <- char '"' -- "
|
|
Packit |
acf257 |
str <- many (satisfy $ not . (=='"'))
|
|
Packit |
acf257 |
_ <- char '"'
|
|
Packit |
acf257 |
return str
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
word = many1 (satisfy (\x -> isAlphaNum x || x=='_' || x=='.' || x=='-' || x==':'))
|