Correctly URI-encode HTTP Label values#1668
Correctly URI-encode HTTP Label values#1668kubukoz merged 12 commits intodisneystreaming:series/0.18from
Conversation
|
|
| else { | ||
| // Other services double encode and normalize | ||
|
|
||
| if (preparedRequest.uri.path.segments.exists(s => dotSegments.contains(s.encoded))) { |
There was a problem hiding this comment.
FYI, I think it would also be valid to simply use java.net.URI#normalize regardless of whether the path contains any dot segments. (The tests pass if I make that change.) I can switch to that if you'd prefer.
(That would also remove the reference to org.http4s.internal.CharPredicate.AlphaNum on line 163, which may be problematic since it appears to be an internal http4s API?)
There was a problem hiding this comment.
yeah let's move 👍, thank you for raising the concern
|
@kubukoz @Baccata I think this is ready for review (CLA aside), at least for the portions that are specific to AWS. I think we agreed in Discord that the signing changes don't need to be configurable from Smithy traits, so I didn't make any changes in that direction. I wasn't sure if the changes to |
| val genPathSegment: Gen[String] = | ||
| Gen | ||
| .frequency( | ||
| 1 -> Gen.oneOf("..", "."), |
There was a problem hiding this comment.
Path normalization should remove these when it's enabled, so these dot segments are sometimes added to the path to make sure that happens.
| ), | ||
| 1 -> Gen.oneOf( | ||
| // this list from https://github.com/http4s/http4s/blob/ac5c5cc40f732df238ef38c8ef8f571b4e66bfe3/core/shared/src/main/scala/org/http4s/Uri.scala#L1069 | ||
| "!$&'()*+,;=:/?@".toIndexedSeq |
There was a problem hiding this comment.
These are characters that should get encoded if they're present in a path segment and encoding is enabled.
| httpMethod <- Gen.oneOf(SdkHttpMethod.values().toList) | ||
| host <- Gen.identifier | ||
| path <- Gen.listOfN(3, Gen.identifier).map(_.mkString("/")) | ||
| path <- Gen |
There was a problem hiding this comment.
When I was working on this and trying to address some edge cases, I commented out this generator and used a variety of generators specific to the edge case I was working on. For example, things like Gen.const("foo/../."), Gen.const("this:might:be:an:aws:arn"), etc. Unfortunately I didn't save the specifics, but they should be encoded in this generator.
|
Unfortunately I think this implementation escapes too much. After running the protocol compliance suite from Alloy and Smithy itself, I noticed that the spec actually says only values inserted into the URI via the (Or at least, that's how I'm now reading the spec: "Patterns with no labels will match only requests containing the exact literal characters declared in the pattern", and then "Every label … MUST have the I don't think we have enough information in |
cc8b59e to
37607ab
Compare
|
FWIW, I think we need to merge disneystreaming/alloy#210 before this will be fully tested by the Alloy compliance tests, but when I ran that locally before rebasing, it passed. (For some reason I can't get it to run now after pulling the latest updates; I get errors like "Unable to resolve trait |
|
smithy4s/modules/aws-http4s/src/smithy4s/aws/AwsClient.scala Lines 91 to 108 in 87897b8 Other than |
modules/core/src/smithy4s/internals/StructurePatternRefinementProvider.scala
Outdated
Show resolved
Hide resolved
| def encode(a: A, urlEncode: Boolean): List[String] | ||
| def encodeGreedy(a: A, urlEncode: Boolean): List[String] |
There was a problem hiding this comment.
I'm not sure whether it makes sense to do it at this level to be honest. I'd rather it was a constructor parameter (in the SchemaVisitorPathEncode construct, for instance).
There was a problem hiding this comment.
I'm not sure how to implement it at the instance level and also maintain the distinction between the old path and the new encodedPath methods in the implementation of HttpEndpoint[I].
I guess I could change SchemaVisitorPathEncoder from an object to a class, and then construct two PathEncoder[I]s in HttpEndpoint.cast, where HttpEndpoint[I]s are constructed, in case downstream code calls the old path method? Is that what you meant?
In addition to not disturbing the public API (most of this work has been to internal APIs, but HttpEndpoint is not marked as internal), we also need to maintain the distinction in behavior in order to continue the existing behavior in the AWS codecs other than AWS_REST_JSON_1, as requested.
There was a problem hiding this comment.
Thank you, that is indeed what I meant 👍
modules/core/src/smithy4s/http/internals/SchemaVisitorPathEncoder.scala
Outdated
Show resolved
Hide resolved
modules/http4s/test/src/smithy4s/http4s/SimpleRestJsonComplianceSuite.scala
Outdated
Show resolved
Hide resolved
Let's leave it unchanged for now and revisit on a case-by-case basis (unless we find some evidence by analysis the spec that some protocols are inherently and unilateraly abiding by one rule) |
|
A few comments, but great work overall ! |
FYI, it looks like |
kubukoz
left a comment
There was a problem hiding this comment.
please add an entry in the changelog file, it'll be 0.18.40 at this point
…ts not being sent to S3
…e request in the PR (the imperative code was converted from Java to Scala by IntelliJ)
7f913d6 to
6faed70
Compare
…ciding based on method parameter values
…hen signing AWS requests
| ) | ||
| def path(input: I): List[String] | ||
|
|
||
| def encodedPath(input: I): List[String] |
There was a problem hiding this comment.
I'm a little surprised this new method didn't trigger a MiMa error, but I didn't see anything that would have suppressed it, so I'm hoping it's ok.
There was a problem hiding this comment.
I don't get it either, tbh. At least the hope is that nobody creates HttpEndpoint manually (as in, not via its unapply and cast)
btw. maybe we should seal this trait.
There was a problem hiding this comment.
I tried a similar case and it emits ReversedMissingMethod. We actually have a filter for all of these (ProblemFilters.exclude[ReversedMissingMethodProblem]("smithy4s.*") in project/MimaVersionPlugin.scala) because it's a forward-compatibility problem.
personally I don't buy it, it's a binary risk like any other. What saves us is that nobody else should be implementing HttpEndpoint, as per the comment above.
There was a problem hiding this comment.
Yep, makes sense. I missed MimaVersionPlugin.
personally I don't buy it, it's a binary risk like any other. What saves us is that nobody else should be implementing HttpEndpoint, as per the comment above.
Are you suggesting I change something so that it wouldn't emit a ReversedMissingMethod error if they weren't being suppressed? I'm not sure what the best way to do that is; none of the options I can think of are very good. (e.g. use ???, or delegate to path)
There was a problem hiding this comment.
I wasn't suggesting any particular action in this case, just a more general wondering...ment for the other maintainers (@Baccata I'm looking at you) :)
in this case I think we're pretty safe because in practice this is "kinda sealed"
There was a problem hiding this comment.
Ok. I made the changes necessary to seal HttpEndpoint, but I'm happy to revert them if that's not the path we want to take.
There was a problem hiding this comment.
oh I wasn't suggesting to actually seal it yet.
I would probably keep it open - the reasoning is, if someone has a custom implementation, their experience will be:
- runtime linkage error
- they add the missing implementation, whatever it is
- no more error
whereas if we seal it now, they may be unable to build with the new smithy4s at all.
Not super realistic, but who knows. I'd leave this kind of change for 0.19
There was a problem hiding this comment.
Ok, works for me. I unsealed it.
4f9bffc to
42e38ff
Compare
kubukoz
left a comment
There was a problem hiding this comment.
just waiting for https://github.com/disneystreaming/alloy/actions/runs/16455931297 now so that we can bump alloy here
I was a little surprised to find that I didn't need to modify
toSmithy4sHttpUrito make this test pass, so I wanted to get some feedback before I get too much further into modifyingAwsClientandSimpleRestJsonas laid out in #1663.Needs disneystreaming/alloy#210