Search code examples
scalahttpsuridecodingsttp

Sttp Uri Avoid Decoding


I am trying to download a file from a pre-signed s3 url:

val url: String = "https://s3-us-west-2.amazonaws.com/exports.mandrillapp.com/<id>/activity-2021-02-01_00%3A34%3A43.zip?AWSAccessKeyId=<access_key>&Expires=1612744535&Signature=<signature>"

when I convert it to a Uri

val uri: Uri = uri"$url"

it decodes the %3A. activity-2021-02-01_00%3A34%3A43.zip -> activity-2021-02-01_00:34:43.zip:

https://s3-us-west-2.amazonaws.com/exports.mandrillapp.com/<id>/activity-2021-02-01_00:34:43.zip?AWSAccessKeyId=<access_key>&Expires=1612744535&Signature=<signature>

When I try to get file with the decoded Uri I get this error message:

The request signature we calculated does not match the signature you provided. Check your key and signing method.

I think the uri decoding is causing problems because the curl on the %3A works but : doesn't.

Is there a way to avoid decoding the path? I couldn't find anything about it.

I am using the following sttp versions.

"com.softwaremill.sttp"       %% "core"                                 % "1.5.11",
"com.softwaremill.sttp"       %% "async-http-client-backend-future"     % "1.5.11"

Solution

  • You will need to change the encoding of the path segments in the parsed URI to a more strict one:

    parsed.copy(
      pathSegments = Uri.AbsolutePath(parsed.pathSegments.segments
        .map(s => s.copy(encoding = QuerySegmentEncoding.All)).toList
      )
    )
    

    This is using sttp3, so might have to be edited slightly for sttp1. We are using the query encoding here, which according to rfc3986 escapes : in the query, but not in the path (where it's a legal character).

    You could also try using quicklens to make this a bit more readable: