{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
module Network.HTTP.Types.URI (
Query,
QueryItem,
renderQuery,
renderQueryBuilder,
parseQuery,
parseQueryReplacePlus,
QueryText,
queryTextToQuery,
queryToQueryText,
renderQueryText,
parseQueryText,
SimpleQuery,
SimpleQueryItem,
simpleQueryToQuery,
renderSimpleQuery,
parseSimpleQuery,
PartialEscapeQuery,
PartialEscapeQueryItem,
EscapeItem (..),
renderQueryPartialEscape,
renderQueryBuilderPartialEscape,
extractPath,
encodePath,
decodePath,
encodePathSegments,
encodePathSegmentsRelative,
decodePathSegments,
urlEncode,
urlEncodeBuilder,
urlDecode,
)
where
import Control.Arrow (second, (***))
import Data.Bits (shiftL, (.|.))
import qualified Data.ByteString as B
import qualified Data.ByteString.Builder as B
import qualified Data.ByteString.Lazy as BL
import Data.Char (ord)
import Data.List (intersperse)
import Data.Maybe (fromMaybe)
#if __GLASGOW_HASKELL__ < 710
import Data.Monoid
#endif
import Data.Text (Text)
import Data.Text.Encoding (decodeUtf8With, encodeUtf8)
import Data.Text.Encoding.Error (lenientDecode)
import Data.Word (Word8)
type QueryItem = (B.ByteString, Maybe B.ByteString)
type Query = [QueryItem]
type QueryText = [(Text, Maybe Text)]
queryTextToQuery :: QueryText -> Query
queryTextToQuery :: QueryText -> Query
queryTextToQuery = forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a -> b) -> a -> b
$ Text -> ByteString
encodeUtf8 forall (a :: * -> * -> *) b c b' c'.
Arrow a =>
a b c -> a b' c' -> a (b, b') (c, c')
*** forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Text -> ByteString
encodeUtf8
renderQueryText :: Bool -> QueryText -> B.Builder
renderQueryText :: Bool -> QueryText -> Builder
renderQueryText Bool
b = Bool -> Query -> Builder
renderQueryBuilder Bool
b forall b c a. (b -> c) -> (a -> b) -> a -> c
. QueryText -> Query
queryTextToQuery
queryToQueryText :: Query -> QueryText
queryToQueryText :: Query -> QueryText
queryToQueryText =
forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a -> b) -> a -> b
$ ByteString -> Text
go forall (a :: * -> * -> *) b c b' c'.
Arrow a =>
a b c -> a b' c' -> a (b, b') (c, c')
*** forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ByteString -> Text
go
where
go :: ByteString -> Text
go = OnDecodeError -> ByteString -> Text
decodeUtf8With OnDecodeError
lenientDecode
parseQueryText :: B.ByteString -> QueryText
parseQueryText :: ByteString -> QueryText
parseQueryText = Query -> QueryText
queryToQueryText forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Query
parseQuery
type SimpleQueryItem = (B.ByteString, B.ByteString)
type SimpleQuery = [SimpleQueryItem]
simpleQueryToQuery :: SimpleQuery -> Query
simpleQueryToQuery :: SimpleQuery -> Query
simpleQueryToQuery = forall a b. (a -> b) -> [a] -> [b]
map (forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second forall a. a -> Maybe a
Just)
renderQueryBuilder :: Bool -> Query -> B.Builder
renderQueryBuilder :: Bool -> Query -> Builder
renderQueryBuilder Bool
_ [] = forall a. Monoid a => a
mempty
renderQueryBuilder Bool
qmark' ((ByteString, Maybe ByteString)
p : Query
ps) =
forall a. Monoid a => [a] -> a
mconcat forall a b. (a -> b) -> a -> b
$
Builder -> (ByteString, Maybe ByteString) -> Builder
go (if Bool
qmark' then Builder
qmark else forall a. Monoid a => a
mempty) (ByteString, Maybe ByteString)
p
forall a. a -> [a] -> [a]
: forall a b. (a -> b) -> [a] -> [b]
map (Builder -> (ByteString, Maybe ByteString) -> Builder
go Builder
amp) Query
ps
where
qmark :: Builder
qmark = ByteString -> Builder
B.byteString ByteString
"?"
amp :: Builder
amp = ByteString -> Builder
B.byteString ByteString
"&"
equal :: Builder
equal = ByteString -> Builder
B.byteString ByteString
"="
go :: Builder -> (ByteString, Maybe ByteString) -> Builder
go Builder
sep (ByteString
k, Maybe ByteString
mv) =
forall a. Monoid a => [a] -> a
mconcat
[ Builder
sep
, Bool -> ByteString -> Builder
urlEncodeBuilder Bool
True ByteString
k
, case Maybe ByteString
mv of
Maybe ByteString
Nothing -> forall a. Monoid a => a
mempty
Just ByteString
v -> Builder
equal forall a. Monoid a => a -> a -> a
`mappend` Bool -> ByteString -> Builder
urlEncodeBuilder Bool
True ByteString
v
]
renderQuery :: Bool -> Query -> B.ByteString
renderQuery :: Bool -> Query -> ByteString
renderQuery Bool
qm = ByteString -> ByteString
BL.toStrict forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> ByteString
B.toLazyByteString forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Query -> Builder
renderQueryBuilder Bool
qm
renderSimpleQuery :: Bool -> SimpleQuery -> B.ByteString
renderSimpleQuery :: Bool -> SimpleQuery -> ByteString
renderSimpleQuery Bool
useQuestionMark = Bool -> Query -> ByteString
renderQuery Bool
useQuestionMark forall b c a. (b -> c) -> (a -> b) -> a -> c
. SimpleQuery -> Query
simpleQueryToQuery
parseQuery :: B.ByteString -> Query
parseQuery :: ByteString -> Query
parseQuery = Bool -> ByteString -> Query
parseQueryReplacePlus Bool
True
parseQueryReplacePlus :: Bool -> B.ByteString -> Query
parseQueryReplacePlus :: Bool -> ByteString -> Query
parseQueryReplacePlus Bool
replacePlus ByteString
bs = ByteString -> Query
parseQueryString' forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString
dropQuestion ByteString
bs
where
dropQuestion :: ByteString -> ByteString
dropQuestion ByteString
q =
case ByteString -> Maybe (Word8, ByteString)
B.uncons ByteString
q of
Just (Word8
63, ByteString
q') -> ByteString
q'
Maybe (Word8, ByteString)
_ -> ByteString
q
parseQueryString' :: ByteString -> Query
parseQueryString' ByteString
q | ByteString -> Bool
B.null ByteString
q = []
parseQueryString' ByteString
q =
let (ByteString
x, ByteString
xs) = ByteString -> ByteString -> (ByteString, ByteString)
breakDiscard ByteString
queryStringSeparators ByteString
q
in ByteString -> (ByteString, Maybe ByteString)
parsePair ByteString
x forall a. a -> [a] -> [a]
: ByteString -> Query
parseQueryString' ByteString
xs
where
parsePair :: ByteString -> (ByteString, Maybe ByteString)
parsePair ByteString
x =
let (ByteString
k, ByteString
v) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.break (forall a. Eq a => a -> a -> Bool
== Word8
61) ByteString
x
v'' :: Maybe ByteString
v'' =
case ByteString -> Maybe (Word8, ByteString)
B.uncons ByteString
v of
Just (Word8
_, ByteString
v') -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Bool -> ByteString -> ByteString
urlDecode Bool
replacePlus ByteString
v'
Maybe (Word8, ByteString)
_ -> forall a. Maybe a
Nothing
in (Bool -> ByteString -> ByteString
urlDecode Bool
replacePlus ByteString
k, Maybe ByteString
v'')
queryStringSeparators :: B.ByteString
queryStringSeparators :: ByteString
queryStringSeparators = [Word8] -> ByteString
B.pack [Word8
38, Word8
59]
breakDiscard :: B.ByteString -> B.ByteString -> (B.ByteString, B.ByteString)
breakDiscard :: ByteString -> ByteString -> (ByteString, ByteString)
breakDiscard ByteString
seps ByteString
s =
let (ByteString
x, ByteString
y) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.break (Word8 -> ByteString -> Bool
`B.elem` ByteString
seps) ByteString
s
in (ByteString
x, Int -> ByteString -> ByteString
B.drop Int
1 ByteString
y)
parseSimpleQuery :: B.ByteString -> SimpleQuery
parseSimpleQuery :: ByteString -> SimpleQuery
parseSimpleQuery = forall a b. (a -> b) -> [a] -> [b]
map (forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second forall a b. (a -> b) -> a -> b
$ forall a. a -> Maybe a -> a
fromMaybe ByteString
B.empty) forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Query
parseQuery
ord8 :: Char -> Word8
ord8 :: Char -> Word8
ord8 = forall a b. (Integral a, Num b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Int
ord
unreservedQS, unreservedPI :: [Word8]
unreservedQS :: [Word8]
unreservedQS = forall a b. (a -> b) -> [a] -> [b]
map Char -> Word8
ord8 [Char]
"-_.~"
unreservedPI :: [Word8]
unreservedPI = forall a b. (a -> b) -> [a] -> [b]
map Char -> Word8
ord8 [Char]
"-_.~:@&=+$,"
urlEncodeBuilder' :: [Word8] -> B.ByteString -> B.Builder
urlEncodeBuilder' :: [Word8] -> ByteString -> Builder
urlEncodeBuilder' [Word8]
extraUnreserved =
forall a. Monoid a => [a] -> a
mconcat forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map Word8 -> Builder
encodeChar forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Word8]
B.unpack
where
encodeChar :: Word8 -> Builder
encodeChar Word8
ch
| Word8 -> Bool
unreserved Word8
ch = Word8 -> Builder
B.word8 Word8
ch
| Bool
otherwise = Word8 -> Builder
h2 Word8
ch
unreserved :: Word8 -> Bool
unreserved Word8
ch
| Word8
ch forall a. Ord a => a -> a -> Bool
>= Word8
65 Bool -> Bool -> Bool
&& Word8
ch forall a. Ord a => a -> a -> Bool
<= Word8
90 = Bool
True
| Word8
ch forall a. Ord a => a -> a -> Bool
>= Word8
97 Bool -> Bool -> Bool
&& Word8
ch forall a. Ord a => a -> a -> Bool
<= Word8
122 = Bool
True
| Word8
ch forall a. Ord a => a -> a -> Bool
>= Word8
48 Bool -> Bool -> Bool
&& Word8
ch forall a. Ord a => a -> a -> Bool
<= Word8
57 = Bool
True
unreserved Word8
c = Word8
c forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Word8]
extraUnreserved
h2 :: Word8 -> Builder
h2 Word8
v = Word8 -> Builder
B.word8 Word8
37 forall a. Monoid a => a -> a -> a
`mappend` Word8 -> Builder
B.word8 (forall {a}. (Ord a, Num a) => a -> a
h Word8
a) forall a. Monoid a => a -> a -> a
`mappend` Word8 -> Builder
B.word8 (forall {a}. (Ord a, Num a) => a -> a
h Word8
b)
where
(Word8
a, Word8
b) = Word8
v forall a. Integral a => a -> a -> (a, a)
`divMod` Word8
16
h :: a -> a
h a
i
| a
i forall a. Ord a => a -> a -> Bool
< a
10 = a
48 forall a. Num a => a -> a -> a
+ a
i
| Bool
otherwise = a
65 forall a. Num a => a -> a -> a
+ a
i forall a. Num a => a -> a -> a
- a
10
urlEncodeBuilder :: Bool -> B.ByteString -> B.Builder
urlEncodeBuilder :: Bool -> ByteString -> Builder
urlEncodeBuilder Bool
True = [Word8] -> ByteString -> Builder
urlEncodeBuilder' [Word8]
unreservedQS
urlEncodeBuilder Bool
False = [Word8] -> ByteString -> Builder
urlEncodeBuilder' [Word8]
unreservedPI
urlEncode :: Bool -> B.ByteString -> B.ByteString
urlEncode :: Bool -> ByteString -> ByteString
urlEncode Bool
q = ByteString -> ByteString
BL.toStrict forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> ByteString
B.toLazyByteString forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> ByteString -> Builder
urlEncodeBuilder Bool
q
urlDecode :: Bool -> B.ByteString -> B.ByteString
urlDecode :: Bool -> ByteString -> ByteString
urlDecode Bool
replacePlus ByteString
z = forall a b. (a, b) -> a
fst forall a b. (a -> b) -> a -> b
$ forall a.
Int -> (a -> Maybe (Word8, a)) -> a -> (ByteString, Maybe a)
B.unfoldrN (ByteString -> Int
B.length ByteString
z) ByteString -> Maybe (Word8, ByteString)
go ByteString
z
where
go :: ByteString -> Maybe (Word8, ByteString)
go ByteString
bs =
case ByteString -> Maybe (Word8, ByteString)
B.uncons ByteString
bs of
Maybe (Word8, ByteString)
Nothing -> forall a. Maybe a
Nothing
Just (Word8
43, ByteString
ws) | Bool
replacePlus -> forall a. a -> Maybe a
Just (Word8
32, ByteString
ws)
Just (Word8
37, ByteString
ws) -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a. a -> Maybe a -> a
fromMaybe (Word8
37, ByteString
ws) forall a b. (a -> b) -> a -> b
$ do
(Word8
x, ByteString
xs) <- ByteString -> Maybe (Word8, ByteString)
B.uncons ByteString
ws
Word8
x' <- forall {a}. (Ord a, Num a) => a -> Maybe a
hexVal Word8
x
(Word8
y, ByteString
ys) <- ByteString -> Maybe (Word8, ByteString)
B.uncons ByteString
xs
Word8
y' <- forall {a}. (Ord a, Num a) => a -> Maybe a
hexVal Word8
y
forall a. a -> Maybe a
Just (Word8 -> Word8 -> Word8
combine Word8
x' Word8
y', ByteString
ys)
Just (Word8
w, ByteString
ws) -> forall a. a -> Maybe a
Just (Word8
w, ByteString
ws)
hexVal :: a -> Maybe a
hexVal a
w
| a
48 forall a. Ord a => a -> a -> Bool
<= a
w Bool -> Bool -> Bool
&& a
w forall a. Ord a => a -> a -> Bool
<= a
57 = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ a
w forall a. Num a => a -> a -> a
- a
48
| a
65 forall a. Ord a => a -> a -> Bool
<= a
w Bool -> Bool -> Bool
&& a
w forall a. Ord a => a -> a -> Bool
<= a
70 = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ a
w forall a. Num a => a -> a -> a
- a
55
| a
97 forall a. Ord a => a -> a -> Bool
<= a
w Bool -> Bool -> Bool
&& a
w forall a. Ord a => a -> a -> Bool
<= a
102 = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ a
w forall a. Num a => a -> a -> a
- a
87
| Bool
otherwise = forall a. Maybe a
Nothing
combine :: Word8 -> Word8 -> Word8
combine :: Word8 -> Word8 -> Word8
combine Word8
a Word8
b = forall a. Bits a => a -> Int -> a
shiftL Word8
a Int
4 forall a. Bits a => a -> a -> a
.|. Word8
b
encodePathSegments :: [Text] -> B.Builder
encodePathSegments :: [Text] -> Builder
encodePathSegments = forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (\Text
x -> forall a. Monoid a => a -> a -> a
mappend (ByteString -> Builder
B.byteString ByteString
"/" forall a. Monoid a => a -> a -> a
`mappend` Text -> Builder
encodePathSegment Text
x)) forall a. Monoid a => a
mempty
encodePathSegmentsRelative :: [Text] -> B.Builder
encodePathSegmentsRelative :: [Text] -> Builder
encodePathSegmentsRelative [Text]
xs = forall a. Monoid a => [a] -> a
mconcat forall a b. (a -> b) -> a -> b
$ forall a. a -> [a] -> [a]
intersperse (ByteString -> Builder
B.byteString ByteString
"/") (forall a b. (a -> b) -> [a] -> [b]
map Text -> Builder
encodePathSegment [Text]
xs)
encodePathSegment :: Text -> B.Builder
encodePathSegment :: Text -> Builder
encodePathSegment = Bool -> ByteString -> Builder
urlEncodeBuilder Bool
False forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
encodeUtf8
decodePathSegments :: B.ByteString -> [Text]
decodePathSegments :: ByteString -> [Text]
decodePathSegments ByteString
"" = []
decodePathSegments ByteString
"/" = []
decodePathSegments ByteString
a =
ByteString -> [Text]
go forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString
drop1Slash ByteString
a
where
drop1Slash :: ByteString -> ByteString
drop1Slash ByteString
bs =
case ByteString -> Maybe (Word8, ByteString)
B.uncons ByteString
bs of
Just (Word8
47, ByteString
bs') -> ByteString
bs'
Maybe (Word8, ByteString)
_ -> ByteString
bs
go :: ByteString -> [Text]
go ByteString
bs =
let (ByteString
x, ByteString
y) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.break (forall a. Eq a => a -> a -> Bool
== Word8
47) ByteString
bs
in ByteString -> Text
decodePathSegment ByteString
x
forall a. a -> [a] -> [a]
: if ByteString -> Bool
B.null ByteString
y
then []
else ByteString -> [Text]
go forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> ByteString
B.drop Int
1 ByteString
y
decodePathSegment :: B.ByteString -> Text
decodePathSegment :: ByteString -> Text
decodePathSegment = OnDecodeError -> ByteString -> Text
decodeUtf8With OnDecodeError
lenientDecode forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> ByteString -> ByteString
urlDecode Bool
False
extractPath :: B.ByteString -> B.ByteString
= forall {a}. (Eq a, IsString a) => a -> a
ensureNonEmpty forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
extract
where
extract :: ByteString -> ByteString
extract ByteString
path
| ByteString
"http://" ByteString -> ByteString -> Bool
`B.isPrefixOf` ByteString
path = (forall a b. (a, b) -> b
snd forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> (ByteString, ByteString)
breakOnSlash forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> ByteString -> ByteString
B.drop Int
7) ByteString
path
| ByteString
"https://" ByteString -> ByteString -> Bool
`B.isPrefixOf` ByteString
path = (forall a b. (a, b) -> b
snd forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> (ByteString, ByteString)
breakOnSlash forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> ByteString -> ByteString
B.drop Int
8) ByteString
path
| Bool
otherwise = ByteString
path
breakOnSlash :: ByteString -> (ByteString, ByteString)
breakOnSlash = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.break (forall a. Eq a => a -> a -> Bool
== Word8
47)
ensureNonEmpty :: a -> a
ensureNonEmpty a
"" = a
"/"
ensureNonEmpty a
p = a
p
encodePath :: [Text] -> Query -> B.Builder
encodePath :: [Text] -> Query -> Builder
encodePath [Text]
x [] = [Text] -> Builder
encodePathSegments [Text]
x
encodePath [Text]
x Query
y = [Text] -> Builder
encodePathSegments [Text]
x forall a. Monoid a => a -> a -> a
`mappend` Bool -> Query -> Builder
renderQueryBuilder Bool
True Query
y
decodePath :: B.ByteString -> ([Text], Query)
decodePath :: ByteString -> ([Text], Query)
decodePath ByteString
b =
let (ByteString
x, ByteString
y) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.break (forall a. Eq a => a -> a -> Bool
== Word8
63) ByteString
b
in (ByteString -> [Text]
decodePathSegments ByteString
x, ByteString -> Query
parseQuery ByteString
y)
data EscapeItem
=
QE B.ByteString
|
QN B.ByteString
deriving (Int -> EscapeItem -> ShowS
[EscapeItem] -> ShowS
EscapeItem -> [Char]
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
showList :: [EscapeItem] -> ShowS
$cshowList :: [EscapeItem] -> ShowS
show :: EscapeItem -> [Char]
$cshow :: EscapeItem -> [Char]
showsPrec :: Int -> EscapeItem -> ShowS
$cshowsPrec :: Int -> EscapeItem -> ShowS
Show, EscapeItem -> EscapeItem -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: EscapeItem -> EscapeItem -> Bool
$c/= :: EscapeItem -> EscapeItem -> Bool
== :: EscapeItem -> EscapeItem -> Bool
$c== :: EscapeItem -> EscapeItem -> Bool
Eq, Eq EscapeItem
EscapeItem -> EscapeItem -> Bool
EscapeItem -> EscapeItem -> Ordering
EscapeItem -> EscapeItem -> EscapeItem
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: EscapeItem -> EscapeItem -> EscapeItem
$cmin :: EscapeItem -> EscapeItem -> EscapeItem
max :: EscapeItem -> EscapeItem -> EscapeItem
$cmax :: EscapeItem -> EscapeItem -> EscapeItem
>= :: EscapeItem -> EscapeItem -> Bool
$c>= :: EscapeItem -> EscapeItem -> Bool
> :: EscapeItem -> EscapeItem -> Bool
$c> :: EscapeItem -> EscapeItem -> Bool
<= :: EscapeItem -> EscapeItem -> Bool
$c<= :: EscapeItem -> EscapeItem -> Bool
< :: EscapeItem -> EscapeItem -> Bool
$c< :: EscapeItem -> EscapeItem -> Bool
compare :: EscapeItem -> EscapeItem -> Ordering
$ccompare :: EscapeItem -> EscapeItem -> Ordering
Ord)
type PartialEscapeQueryItem = (B.ByteString, [EscapeItem])
type PartialEscapeQuery = [PartialEscapeQueryItem]
renderQueryPartialEscape :: Bool -> PartialEscapeQuery -> B.ByteString
renderQueryPartialEscape :: Bool -> PartialEscapeQuery -> ByteString
renderQueryPartialEscape Bool
qm =
ByteString -> ByteString
BL.toStrict forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> ByteString
B.toLazyByteString forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> PartialEscapeQuery -> Builder
renderQueryBuilderPartialEscape Bool
qm
renderQueryBuilderPartialEscape :: Bool -> PartialEscapeQuery -> B.Builder
renderQueryBuilderPartialEscape :: Bool -> PartialEscapeQuery -> Builder
renderQueryBuilderPartialEscape Bool
_ [] = forall a. Monoid a => a
mempty
renderQueryBuilderPartialEscape Bool
qmark' (PartialEscapeQueryItem
p : PartialEscapeQuery
ps) =
forall a. Monoid a => [a] -> a
mconcat forall a b. (a -> b) -> a -> b
$
Builder -> PartialEscapeQueryItem -> Builder
go (if Bool
qmark' then Builder
qmark else forall a. Monoid a => a
mempty) PartialEscapeQueryItem
p
forall a. a -> [a] -> [a]
: forall a b. (a -> b) -> [a] -> [b]
map (Builder -> PartialEscapeQueryItem -> Builder
go Builder
amp) PartialEscapeQuery
ps
where
qmark :: Builder
qmark = ByteString -> Builder
B.byteString ByteString
"?"
amp :: Builder
amp = ByteString -> Builder
B.byteString ByteString
"&"
equal :: Builder
equal = ByteString -> Builder
B.byteString ByteString
"="
go :: Builder -> PartialEscapeQueryItem -> Builder
go Builder
sep (ByteString
k, [EscapeItem]
mv) =
forall a. Monoid a => [a] -> a
mconcat
[ Builder
sep
, Bool -> ByteString -> Builder
urlEncodeBuilder Bool
True ByteString
k
, case [EscapeItem]
mv of
[] -> forall a. Monoid a => a
mempty
[EscapeItem]
vs -> Builder
equal forall a. Monoid a => a -> a -> a
`mappend` forall a. Monoid a => [a] -> a
mconcat (forall a b. (a -> b) -> [a] -> [b]
map EscapeItem -> Builder
encode [EscapeItem]
vs)
]
encode :: EscapeItem -> Builder
encode (QE ByteString
v) = Bool -> ByteString -> Builder
urlEncodeBuilder Bool
True ByteString
v
encode (QN ByteString
v) = ByteString -> Builder
B.byteString ByteString
v