1- module Data.URI.UserInfo where
1+ module Data.URI.UserInfo
2+ ( UserInfo (..)
3+ , parser
4+ , print
5+ )where
26
37import Prelude
48
59import Control.Alt ((<|>))
10+ import Data.Foldable (foldMap )
611import Data.Generic.Rep (class Generic )
712import Data.Generic.Rep.Show (genericShow )
813import Data.Newtype (class Newtype )
9- import Data.URI.Common (decodePCT , joinWith , parsePCTEncoded , parseSubDelims , parseUnreserved )
10- import Global (encodeURI )
14+ import Data.String as Str
15+ import Data.URI.Common (decodePCTComponent , joinWith , parsePCTEncoded , parseSubDelims , parseUnreserved )
16+ import Global (encodeURIComponent )
1117import Text.Parsing.StringParser (Parser )
1218import Text.Parsing.StringParser.Combinators (many1 )
1319import Text.Parsing.StringParser.String (string )
@@ -25,9 +31,46 @@ parser ∷ Parser UserInfo
2531parser = UserInfo <<< joinWith " " <$> many1 p
2632 where
2733 p = parseUnreserved
28- <|> parsePCTEncoded decodePCT
34+ <|> parsePCTEncoded decodePCTComponent
2935 <|> parseSubDelims
3036 <|> string " :"
3137
3238print ∷ UserInfo → String
33- print (UserInfo u) = encodeURI u
39+ print (UserInfo u) = encodeUserPassword u
40+
41+
42+ encodeUserPassword :: String -> String
43+ encodeUserPassword s = foldMap encodeChar $ Str .toCharArray s
44+
45+ shouldNotEscape :: Char -> Boolean
46+ shouldNotEscape c =
47+ {-
48+ https://tools.ietf.org/html/rfc3986#section-3.2.1
49+ userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
50+
51+ https://tools.ietf.org/html/rfc3986#section-2.1
52+ pct-encoded = "%" HEXDIG HEXDIG
53+
54+ https://tools.ietf.org/html/rfc3986#section-2.3
55+ unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
56+
57+ https://tools.ietf.org/html/rfc3986#section-2.1
58+ sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
59+ / "*" / "+" / "," / ";" / "="
60+ -}
61+ -- unreserved
62+ (' A' <= c && c <= ' Z' )
63+ || (' a' <= c && c <= ' z' )
64+ || (' 0' <= c && c <= ' 9' )
65+ || c == ' -' || c == ' _' || c == ' .' || c == ' ~'
66+ -- sub-delims
67+ || c == ' !' || c == ' $' || c == ' &' || c == ' \' '
68+ || c == ' (' || c == ' )' || c == ' *' || c == ' +'
69+ || c == ' ,' || c == ' ;' || c == ' ='
70+ -- userinfo
71+ || c == ' :'
72+
73+ encodeChar :: Char -> String
74+ encodeChar c =
75+ let cStr = Str .singleton c
76+ in if shouldNotEscape c then cStr else encodeURIComponent cStr
0 commit comments