Support for URL encoding and decoding.
Proper URL encoding.
Proper URL decoding.
module Encoding.URL exposing (encode, decode)
{-| Support for URL encoding and decoding.
# Standard URL Encoding
@docs encode, decode
-}
import Encoding.Integral
import Combine exposing (andThen)
import Combine.Char
import String
import Char
{-| Proper URL encoding.
-}
encode : String -> String
encode input =
crashOnFailParser_ "URL encoding should never fail" combinatorEncodeURL_ input
{-| Proper URL decoding.
-}
decode : String -> String
decode input =
crashOnFailParser_ "URL decoding should never fail" combinatorDecodeURL_ input
crashOnFailParser_ msg f input =
case Combine.parse f input of
Ok ( _, _, output ) ->
output
Err ( _, _, errs ) ->
String.join "" [ msg, ": ", errs |> String.join ", " ]
|> Debug.crash
encodeHexes_ =
Combine.regex "[^\\w ]+"
|> andThen
(\s ->
String.foldr
(\c ls ->
Char.toCode c
|> Encoding.Integral.encodeHexPadded 2
|> (++) "%"
|> flip (::) ls
)
[]
s
|> String.join ""
|> Combine.succeed
)
decodeHex_ =
Combine.Char.char '%'
|> andThen
(\_ ->
Combine.count 2 (Combine.Char.oneOf Encoding.Integral.hexChars)
|> andThen (List.map String.fromChar >> String.join "" >> Combine.succeed)
|> andThen
(Encoding.Integral.decodeHex
>> Maybe.map (Char.fromCode >> String.fromChar >> Combine.succeed)
>> Maybe.withDefault (Combine.fail "Failed to decode code in URL!")
)
)
combinatorEncodeURL_ =
Combine.many
(Combine.choice
[ Combine.Char.newline |> andThen (always "\x0D\n" >> Combine.succeed)
, encodeHexes_
, Combine.Char.space |> andThen (always "%20" >> Combine.succeed)
, Combine.Char.anyChar |> andThen (String.fromChar >> Combine.succeed)
]
)
|> andThen (String.join "" >> Combine.succeed)
combinatorDecodeURL_ =
Combine.many
(Combine.choice
[ Combine.string "%20" |> andThen (always " " >> Combine.succeed)
, decodeHex_
, Combine.string "\x0D\n" |> andThen (always "\n" >> Combine.succeed)
, Combine.Char.anyChar |> andThen (String.fromChar >> Combine.succeed)
]
)
|> andThen (String.join "" >> Combine.succeed)