module Network.HTTP.Encoding (
decode
,encode
,withDecodedBody
,withDecodedBodyM
,decodeBody
,encodeBody
,HasBody(..)
,EncodingError
,DecodingResult(..)) where
import Network.HTTP.Encoding.Content
import Network.HTTP.Encoding.Character
import Network.HTTP.Encoding.Error
import Network.HTTP
import Data.ByteString.Lazy
import Codec.Text.IConv
import Control.Applicative
import Data.ByteString.Lazy.UTF8 (fromString, toString)
targetEncoding = "UTF-8"
class HasBody a where
getBody :: a b -> b
setBody :: c -> a b -> a c
instance HasBody Request where
getBody = rqBody
setBody body rq = rq {rqBody = body}
instance HasBody Response where
getBody = rspBody
setBody body rsp = rsp {rspBody = body}
data DecodingResult = DecodingResult {decodedBody :: String
,originalEncoding :: EncodingName
}
decodeBody :: (HasHeaders (r ByteString), HasBody r)
=> r ByteString
-> Either EncodingError DecodingResult
decodeBody r =
let headers = getHeaders r
body = getBody r
contentEnc = getContentEncoding headers
decodeBody2 :: String -> Either EncodingError DecodingResult
decodeBody2 enc =
do dbody <- decompress contentEnc body
x <- either (Right) (Left . IConvError)
(convertStrictly enc targetEncoding dbody)
return $ DecodingResult {decodedBody = toString x
,originalEncoding = enc}
in case snd $ getContentTypeAndCharacterEncoding headers of
Nothing -> decodeBody2 "utf-8"
Just charEnc -> decodeBody2 charEnc
flipEither :: Either a b -> Either b a
flipEither (Left x) = Right x
flipEither (Right x) = Left x
decode :: (HasHeaders (m ByteString), HasHeaders (m String), HasBody m)
=> m ByteString
-> Either EncodingError (String, m String)
decode r = do res <- decodeBody r
let hdrs = updateContentEncoding IdentityCompression (getHeaders r)
hdrs2= setCharacterEncoding (originalEncoding res) hdrs
return (originalEncoding res
,flip setHeaders hdrs $ setBody (decodedBody res) r)
encodeBody :: EncodingName
-> ContentEncoding
-> String
-> Either EncodingError ByteString
encodeBody source_enc ce str =
do body <- either Right
(Left . IConvError)
(convertStrictly targetEncoding source_enc (fromString str))
compress ce body
encode :: (HasHeaders (m String), HasBody m)
=> EncodingName -> m String -> Either EncodingError (m ByteString)
encode ch_enc r =
let headers = getHeaders r
body = getBody r
in let ce = getContentEncoding headers in
do ebody <- encodeBody ch_enc ce body
return $ setBody ebody r
either2Maybe (Left x) = Just x
either2Maybe (Right _) = Nothing
withDecodedBody :: (HasHeaders (r String), HasHeaders (r ByteString), HasBody r)
=> (String -> String)
-> r ByteString
-> Either EncodingError (r ByteString)
withDecodedBody f r =
do (enc, dr) <- decode r
let mdr = setBody (f $ getBody dr) dr
encode enc mdr
withDecodedBodyM :: (Monad m, HasHeaders (r String), HasHeaders (r ByteString),
HasBody r)
=> (String -> m String)
-> r ByteString
-> m (Either EncodingError (r ByteString))
withDecodedBodyM f r =
case decode r of
Left err -> return $ Left err
Right (enc, dr) -> f (getBody dr) >>= \mbody ->
case encode enc $ setBody mbody dr of
Left err -> return $ Left err
Right mr -> return $ Right mr