-- | `DomainParser` is a simple parser for domain names as described in RFC 1035. module DomainParser where import Prelude (bind, discard, pure, show, ($), (<>), (>)) import Control.Alt ((<|>)) import Control.Lazy (defer) import Data.Array.NonEmpty as NonEmpty import Data.Either (Either(..)) import Data.Maybe (Maybe(..)) import Data.String as S -- length import Data.String.CodeUnits as CU -- import Data.String.Regex as R -- import Data.String.Regex.Flags as RF import Data.Tuple (Tuple(..)) import Parsing.Combinators.Array (many1) import Parsing.Combinators as PC import Parsing (Parser, fail, runParser) import Parsing.String.Basic (alphaNum, letter) import Parsing.String (char, string, eof) -- | From RFC 1035: ::= | " " -- | -- | Accepting an optional '.' at the end of the subdomain doesn't conform -- | to the (prefered) syntax of a domain as described in RFC 1035. -- | However, this last '.' character should be acceptable in most applications. -- | In some cases, a fully qualified domain name (FQDN) such as `example.com.` -- | has to be differenciated from a "relative" name (www). domain :: Parser String String domain = PC.try (string " ") <|> sub_eof sub_eof :: Parser String String sub_eof = do sub <- subdomain maybe_final_point <- PC.optionMaybe (char '.') eof let parsed_domain = did_we_parsed_the_final_point maybe_final_point sub if S.length parsed_domain > 255 then fail $ "domain length is > 255 bytes (" <> show (S.length parsed_domain) <> ")" else pure parsed_domain where did_we_parsed_the_final_point Nothing sub = sub did_we_parsed_the_final_point (Just _) sub = sub <> "." -- From RFC 1035: ::=