{-# LANGUAGE TemplateHaskell, TypeOperators #-} module Network.Protocol.Uri.Data where import Prelude hiding ((.), id) import Control.Category import Data.Record.Label import Data.Maybe import Network.Protocol.Uri.Encode type Scheme = String type RegName = String type Port = Int type Query = String type Fragment = String type Hash = String type UserInfo = String type PathSegment = String data IPv4 = IPv4 Int Int Int Int deriving (Eq, Ord) data Domain = Domain { __parts :: [String] } deriving (Eq, Ord) data Host = Hostname { __domain :: Domain } | RegName { __regname :: RegName } | IP { __ipv4 :: IPv4 } -- | IPv6 { __ipv6 :: IPv6 } deriving (Eq, Ord) data Authority = Authority { __userinfo :: UserInfo , __host :: Host , __port :: Maybe Port } deriving (Eq, Ord) data Path = Path { __segments :: [PathSegment] } deriving (Eq, Ord) data Uri = Uri { _relative :: Bool , _scheme :: Scheme , _authority :: Authority , __path :: Path , __query :: Query , __fragment :: Fragment } deriving (Eq, Ord) $(mkLabels [''Domain, ''Path, ''Host, ''Authority, ''Uri]) _parts :: Domain :-> [String] _domain :: Host :-> Domain _ipv4 :: Host :-> IPv4 _regname :: Host :-> String _host :: Authority :-> Host _port :: Authority :-> Maybe Port _userinfo :: Authority :-> UserInfo _segments :: Path :-> [PathSegment] _path :: Uri :-> Path -- | Access raw (URI-encoded) query. _query :: Uri :-> Query -- | Access authority part of the URI. authority :: Uri :-> Authority -- | Access domain part of the URI, returns `Nothing' when the host is a -- regname or IP-address. domain :: Uri :-> Maybe Domain domain = (f <-> Hostname . fromJust) `iso` (_host . authority) where f (Hostname d) = Just d f _ = Nothing -- | Access regname part of the URI, returns `Nothing' when the host is a -- domain or IP-address. regname :: Uri :-> Maybe RegName regname = (f <-> RegName . fromJust) `iso` (_host . authority) where f (RegName r) = Just r f _ = Nothing -- | Access IPv4-address part of the URI, returns `Nothing' when the host is a -- domain or regname. ipv4 :: Uri :-> Maybe IPv4 ipv4 = (f <-> IP . fromJust) `iso` (_host . authority) where f (IP i) = Just i f _ = Nothing -- | Access raw (URI-encoded) fragment. _fragment :: Uri :-> Fragment -- | Access the port number part of the URI when available. port :: Uri :-> Maybe Port port = _port . authority -- | Access the query part of the URI, the part that follows the ?. The query -- will be properly decoded when reading and encoded when writing. query :: Uri :-> Query query = encoded `iso` _query -- | Access the fragment part of the URI, the part that follows the #. The -- fragment will be properly decoded when reading and encoded when writing. fragment :: Uri :-> Fragment fragment = encoded `iso` _fragment -- | Is a URI relative? relative :: Uri :-> Bool -- | Access the scheme part of the URI. A scheme is probably the protocol -- indicator like /http/, /ftp/, etc. scheme :: Uri :-> Scheme -- | Access the path part of the URI as a list of path segments. The segments -- will still be URI-encoded. segments :: Uri :-> [PathSegment] segments = _segments . _path -- | Access the userinfo part of the URI. The userinfo contains an optional -- username and password or some other credentials. userinfo :: Uri :-> String userinfo = _userinfo . authority -- | Constructors for making empty URI. mkUri :: Uri mkUri = Uri False mkScheme mkAuthority mkPath mkQuery mkFragment -- | Constructors for making empty `Scheme`. mkScheme :: Scheme mkScheme = "" -- | Constructors for making empty `Path`. mkPath :: Path mkPath = Path [] -- | Constructors for making empty `Authority`. mkAuthority :: Authority mkAuthority = Authority "" mkHost mkPort -- | Constructors for making empty `Query`. mkQuery :: Query mkQuery = "" -- | Constructors for making empty `Fragment`. mkFragment :: Fragment mkFragment = "" -- | Constructors for making empty `UserInfo`. mkUserinfo :: UserInfo mkUserinfo = "" -- | Constructors for making empty `Host`. mkHost :: Host mkHost = Hostname (Domain []) -- | Constructors for making empty `Port`. mkPort :: Maybe Port mkPort = Nothing