Skip to content

Commit

Permalink
fix: prefer EndpointResolver Bucket for S3 in http label, AccountId f…
Browse files Browse the repository at this point in the history
…or S3Control host label (#660)
  • Loading branch information
Ganesh Jangir authored Oct 31, 2022
1 parent f296069 commit 31c8bb9
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class EndpointResolverMiddleware(
.indent()
.write(".withHost(host)")
.write(".withPort(awsEndpoint.endpoint.port)")
.write(".withPath(context.getPath())")
.write(".withPath(awsEndpoint.endpoint.path.appendingPathComponent(context.getPath()))")
.write(""".withHeader(name: "Host", value: host)""")
.dedent()
.write("")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/

package software.amazon.smithy.aws.swift.codegen.model

import software.amazon.smithy.model.Model
import software.amazon.smithy.model.shapes.OperationShape
import software.amazon.smithy.model.traits.EndpointTrait
import software.amazon.smithy.model.transform.ModelTransformer
import software.amazon.smithy.rulesengine.traits.StaticContextParamsTrait
import software.amazon.smithy.swift.codegen.SwiftSettings
import software.amazon.smithy.swift.codegen.integration.SwiftIntegration
import software.amazon.smithy.swift.codegen.model.getTrait

/**
* This integration is responsible for removing the EndpointTrait from the operation
* - For S3 Control, if hostPrefix is {AccountId}., then remove the Endpoint Trait because it is already handled
* within the EndpointResolver
*/
class AWSEndpointTraitTransformer : SwiftIntegration {
override fun preprocessModel(model: Model, settings: SwiftSettings): Model {
return when (settings.service.namespace) {
"com.amazonaws.s3control" -> {
ModelTransformer.create().mapShapes(model) { shape ->
when (shape) {
is OperationShape -> {
val shapeBuilder = shape.toBuilder()
shape.getTrait<StaticContextParamsTrait>()?.let { staticContextParamsTrait ->
val requiresAccountId =
staticContextParamsTrait.parameters["RequiresAccountId"]?.value
.toString()
.toBoolean()
if (requiresAccountId) {
shape.getTrait<EndpointTrait>()?.let { endpointTrait ->
val hostPrefix = endpointTrait.hostPrefix.toString()
if (hostPrefix == "{AccountId}.") {
shapeBuilder.removeTrait(endpointTrait.toShapeId())
}
}
}
}

shapeBuilder.build()
}

else -> shape
}
}
}

else -> model
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/

package software.amazon.smithy.aws.swift.codegen.model

import software.amazon.smithy.model.Model
import software.amazon.smithy.model.pattern.UriPattern
import software.amazon.smithy.model.shapes.OperationShape
import software.amazon.smithy.model.traits.HttpLabelTrait
import software.amazon.smithy.model.traits.HttpTrait
import software.amazon.smithy.model.transform.ModelTransformer
import software.amazon.smithy.rulesengine.traits.ContextParamTrait
import software.amazon.smithy.swift.codegen.SwiftSettings
import software.amazon.smithy.swift.codegen.getOrNull
import software.amazon.smithy.swift.codegen.integration.SwiftIntegration
import software.amazon.smithy.swift.codegen.model.getTrait
import software.amazon.smithy.swift.codegen.model.hasTrait

/**
* This integration is responsible for updating the `@httpLabel` trait to the input shape of an operation
* - For S3, if the HttpLabel is /{BucketName}{Suffix} then update the trait with /{Suffix} because
* the bucket name is already handled within the EndpointResolver
*/
class AWSHttpTraitTransformer : SwiftIntegration {
override fun preprocessModel(model: Model, settings: SwiftSettings): Model {
return when (settings.service.namespace) {
"com.amazonaws.s3" -> {
ModelTransformer.create().mapShapes(model) { shape ->
when (shape) {
is OperationShape -> {
val shapeBuilder = shape.toBuilder()
shape.input.getOrNull()?.let { input ->
val inputShape = model.expectShape(input.toShapeId())
shape.getTrait<HttpTrait>()?.let { httpTrait ->
val uriPattern = httpTrait.uri.toString()
val httpTraitBuilder = httpTrait.toBuilder()
val members = inputShape.members() ?: emptyList()
members.forEach { member ->
if (member.hasTrait<ContextParamTrait>() &&
member.hasTrait<HttpLabelTrait>() &&
member.memberName == "Bucket" &&
uriPattern.startsWith("/{Bucket}")
) {
var newPattern = uriPattern.substring("/{Bucket}".length)
if (!newPattern.startsWith("/")) {
newPattern = "/$newPattern"
}
httpTraitBuilder.uri(UriPattern.parse(newPattern))
shapeBuilder.addTrait(httpTraitBuilder.build())
}
}
}
}
shapeBuilder.build()
}

else -> shape
}
}
}

else -> model
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ software.amazon.smithy.aws.swift.codegen.customization.presignable.PresignableUr
software.amazon.smithy.aws.swift.codegen.customization.DisabledAuth
software.amazon.smithy.aws.swift.codegen.PresignerGenerator
software.amazon.smithy.aws.swift.codegen.model.AWSClientContextParamsTransformer
software.amazon.smithy.aws.swift.codegen.customization.ServiceGeneratorIntegration
software.amazon.smithy.aws.swift.codegen.customization.ServiceGeneratorIntegration
software.amazon.smithy.aws.swift.codegen.model.AWSHttpTraitTransformer
software.amazon.smithy.aws.swift.codegen.model.AWSEndpointTraitTransformer
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class EndpointResolverMiddlewareTests {
input.withMethod(context.getMethod())
.withHost(host)
.withPort(awsEndpoint.endpoint.port)
.withPath(context.getPath())
.withPath(awsEndpoint.endpoint.path.appendingPathComponent(context.getPath()))
.withHeader(name: "Host", value: host)
return try await next.handle(context: updatedContext, input: input)
Expand Down

0 comments on commit 31c8bb9

Please sign in to comment.