Skip to content

Commit

Permalink
Escape reserved characters in URI path after rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
alexbiehl committed Feb 12, 2024
1 parent debd16c commit 853476f
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 7 deletions.
21 changes: 14 additions & 7 deletions src/Scarf/Gateway/Rule.hs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import Data.Text (Text)
import Data.Text qualified as Text
import Data.Text.Encoding qualified as Text
import Network.HTTP.Types.URI (Query, parseQuery, parseQueryText, renderQuery)
import Network.URI (URI (..), parseRelativeReference, parseURI)
import Network.URI (URI (..), escapeURIString, isUnreserved, parseRelativeReference, parseURI)
import Network.Wai
( pathInfo,
rawQueryString,
Expand Down Expand Up @@ -643,15 +643,11 @@ rewriteQueryString ::
Wai.Request ->
ByteString
rewriteQueryString redirectTarget request
-- Fast path: In case there are no query parameters on the request
-- there is no need for rewriting.
| [] <- Wai.queryString request =
Text.encodeUtf8 redirectTarget
-- Parse the redirect target as a URI to extract, combine and replace
-- the query part of it.
-- TODO: there are an aweful lot of string conversions going on,
-- maybe there's a more direct way.
| Just uri@URI {uriQuery} <- parseURI (Text.unpack redirectTarget) =
| Just uri@URI {uriQuery, uriPath} <- parseURI (Text.unpack redirectTarget) =
let redirectTargetQuery =
parseQuery (Text.encodeUtf8 (Text.pack uriQuery))

Expand All @@ -676,7 +672,18 @@ rewriteQueryString redirectTarget request
)
in Text.encodeUtf8 $
Text.pack $
show (uri {uriQuery = Text.unpack renderedQuery})
show
( uri
{ uriQuery =
Text.unpack renderedQuery,
uriPath =
-- We go over the URI path to escape anything that is worth escaping.
-- Unfortunately rendering the URI doesn't do any escaping automatically.
escapeURIString
(\c -> c == '/' || isUnreserved c)
uriPath
}
)
-- In case the redirectTarget didn't parse as a URI we are not doing anything
-- and ideally shouldn't happen.
| otherwise =
Expand Down
Empty file.
12 changes: 12 additions & 0 deletions test/golden/file-package-escaping.output.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
capture: |-
Just
FlatfileCapture
{ fileAbsoluteUrl =
Just "https://output.com/some-nice-path/very-nice/really%2Bnice"
, fileVariables =
fromList [ ( "path" , "some-nice-path/very-nice/really+nice" ) ]
, filePackage = "21c24cd1-73fa-4970-8a6a-bc570e55b91e"
}
headers:
Location: https://output.com/some-nice-path/very-nice/really%2Bnice
status: 302
11 changes: 11 additions & 0 deletions test/golden/file-package-escaping.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# multiple variables
path: "/some-nice-path/very-nice/really+nice"
headers:
Host: nicedomain.com
manifest:
rules:
- type: file-v1
incoming-path: "/{+path}"
domain: nicedomain.com
package-id: 21c24cd1-73fa-4970-8a6a-bc570e55b91e
outgoing-url: https://output.com/{+path}

0 comments on commit 853476f

Please sign in to comment.