Skip to content

Commit

Permalink
functions to explicitly chose parts of the query to escape
Browse files Browse the repository at this point in the history
  • Loading branch information
tkvogt committed Jan 30, 2018
1 parent 455f1d5 commit 2ab8066
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 0 deletions.
6 changes: 6 additions & 0 deletions Network/HTTP/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,12 @@ module Network.HTTP.Types
, renderSimpleQuery
, parseQuery
, parseSimpleQuery
-- **Escape only parts
, renderQueryMinimalEscape
, renderQueryBuilderMinimalEscape
, EscItem(..)
, NonEscQueryItem
, NonEscQuery
-- *** Text query string (UTF8 encoded)
, QueryText
, queryTextToQuery
Expand Down
54 changes: 54 additions & 0 deletions Network/HTTP/Types/URI.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ module Network.HTTP.Types.URI
, renderSimpleQuery
, parseQuery
, parseSimpleQuery
-- **Escape only parts
, renderQueryMinimalEscape
, renderQueryBuilderMinimalEscape
, EscItem(..)
, NonEscQueryItem
, NonEscQuery
-- ** Text query string (UTF8 encoded)
, QueryText
, queryTextToQuery
Expand Down Expand Up @@ -323,3 +329,51 @@ decodePath :: B.ByteString -> ([Text], Query)
decodePath b =
let (x, y) = B.break (== 63) b -- question mark
in (decodePathSegments x, parseQuery y)

-----------------------------------------------------------------------------------------

-- | For some URIs characters must not be URI encoded,
-- eg '+' or ':' in q=a+language:haskell+created:2009-01-01..2009-02-01&sort=stars
-- The character list unreservedPI instead of unreservedQS would solve this.
-- But we explicitly decide what part to encode.
-- This is mandatory when searching for '+': q=%2B+language:haskell.
data EscItem = QE B.ByteString -- will be URL encoded
| QN B.ByteString -- will not be url encoded, eg '+' or ':'
deriving (Show, Eq, Ord)

-- | Query item
type NonEscQueryItem = (B.ByteString, [EscItem])

-- | Query with some chars that should not be escaped.
--
-- General form: a=b&c=d:e+f&g=h
type NonEscQuery = [NonEscQueryItem]

-- | Convert 'NonEscQuery' to 'ByteString'.
renderQueryMinimalEscape :: Bool -- ^ prepend question mark?
-> NonEscQuery -> B.ByteString
renderQueryMinimalEscape qm = BL.toStrict . B.toLazyByteString . renderQueryBuilderMinimalEscape qm

-- | Convert 'NonEscQuery' to a 'Builder'.
renderQueryBuilderMinimalEscape :: Bool -- ^ prepend a question mark?
-> NonEscQuery
-> B.Builder
renderQueryBuilderMinimalEscape _ [] = mempty
-- FIXME replace mconcat + map with foldr
renderQueryBuilderMinimalEscape qmark' (p:ps) = mconcat
$ go (if qmark' then qmark else mempty) p
: map (go amp) ps
where
qmark = B.byteString "?"
amp = B.byteString "&"
equal = B.byteString "="
go sep (k, mv) = mconcat [
sep
, urlEncodeBuilder True k
, case mv of
[] -> mempty
vs -> equal `mappend` (mconcat (map encode vs))
]
encode (QE v) = urlEncodeBuilder True v
encode (QN v) = B.byteString v

0 comments on commit 2ab8066

Please sign in to comment.