salvia-0.1: src/Network/Protocol/Http/Parser.hs
module Network.Protocol.Http.Parser (
parseRequest
, parseResponse
) where
import Control.Applicative hiding (empty)
import Data.Char (ord)
import Data.List (intercalate)
import Data.Map (insert, empty)
import Misc.Misc (pMaybe)
import Network.Protocol.Http.Data
import Network.Protocol.Http.Status
import Network.Protocol.Uri (pUriReference)
import Text.ParserCombinators.Parsec hiding (many, optional, (<|>))
{- | Parse a string as an HTTP request message. -}
parseRequest :: String -> Either ParseError Message
parseRequest msg = parse pRequest "" msg
{- | Parse a string as an HTTP request message. -}
parseResponse :: String -> Either ParseError Message
parseResponse msg = parse pResponse "" msg
lf, ws, ls :: String
lf = "\r\n"
ws = " \t\r\n"
ls = " \t"
pLf :: GenParser Char st Char
pLf = (char '\r' <* pMaybe (char '\n')) <|> char '\n'
pVersion :: GenParser Char st Version
pVersion =
(\h l -> Version (ord h - ord '0') (ord l - ord '0'))
<$> (string "HTTP/" *> digit)
<*> (char '.' *> digit)
pHeaders :: GenParser Char st Headers
pHeaders = insert
<$> many1 (noneOf (':':ws)) <* string ":"
<*> (intercalate ws <$> (many $ many1 (oneOf ls) *> many1 (noneOf lf) <* pLf))
<*> option empty pHeaders
pMethod :: GenParser Char st Method
pMethod = choice $ map (\a -> a <$ (try $ string $ show a)) methods
pRequest :: GenParser Char st Message
pRequest = (\m u v h b -> Message (Request m u) v h b)
<$> (pMethod <* many1 (oneOf ls))
<*> (pUriReference <* many1 (oneOf ls))
<*> (pVersion <* pLf)
<*> (pHeaders <* pLf)
<*> (many anyToken)
pResponse :: GenParser Char st Message
pResponse = (\v s h b -> Message (Response (statusFromCode $ read s)) v h b)
<$> (pVersion <* many1 (oneOf ls))
<*> (many1 digit <* many1 (oneOf ls) <* many1 (noneOf lf) <* pLf)
<*> (pHeaders <* pLf)
<*> (many anyToken)