module Text.Domain.Parser
( domainParser
)
where
import Control.Applicative
import Control.Monad (guard)
import Data.Attoparsec.ByteString.Char8
import qualified Data.ByteString.Char8 as BS
import Data.ByteString (ByteString)
domainParser :: Parser ByteString
domainParser = do
domain <- fst <$> match (label `sepBy1` char '.' >> optional (char '.'))
let trimmed =
case BS.last domain of
'.' -> BS.init domain
_ -> domain
guard (BS.length trimmed <= 253)
return trimmed
label :: Parser ByteString
label = do
lbl <- fst <$> match (alphaNum >> skipWhile isAlphaNumHyphen)
guard (BS.length lbl <= 63 && BS.last lbl /= '-')
return lbl
alphaNum :: Parser Char
alphaNum = satisfy isAlphaNum
where isAlphaNum x = isDigit x || isAlpha_ascii x
isAlphaNumHyphen :: Char -> Bool
isAlphaNumHyphen x = isDigit x || isAlpha_ascii x || x == '-'