diff --git a/trino-aws-proxy/src/main/java/io/trino/aws/proxy/server/rest/RequestBuilder.java b/trino-aws-proxy/src/main/java/io/trino/aws/proxy/server/rest/RequestBuilder.java index 516eda09..109496e0 100644 --- a/trino-aws-proxy/src/main/java/io/trino/aws/proxy/server/rest/RequestBuilder.java +++ b/trino-aws-proxy/src/main/java/io/trino/aws/proxy/server/rest/RequestBuilder.java @@ -98,7 +98,7 @@ record BucketAndKey(String bucket, String rawKey) {} .flatMap(serverHostNameValue -> { String lowercaseServerHostName = serverHostNameValue.toLowerCase(Locale.ROOT); return Optional.of(request.requestUri().getHost()) - .filter(value -> value.endsWith(lowercaseServerHostName)) + .filter(value -> value.endsWith(lowercaseServerHostName) && !value.equals(lowercaseServerHostName)) .map(value -> value.substring(0, value.length() - lowercaseServerHostName.length())) .map(value -> value.endsWith(".") ? value.substring(0, value.length() - 1) : value); }) diff --git a/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/TestProxiedRequestsWithPathStyleOnVirtualHostProxy.java b/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/TestProxiedRequestsWithPathStyleOnVirtualHostProxy.java new file mode 100644 index 00000000..a1e71400 --- /dev/null +++ b/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/TestProxiedRequestsWithPathStyleOnVirtualHostProxy.java @@ -0,0 +1,34 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.trino.aws.proxy.server; + +import com.google.inject.Inject; +import io.trino.aws.proxy.server.testing.containers.S3Container.ForS3Container; +import io.trino.aws.proxy.server.testing.harness.TrinoAwsProxyTest; +import io.trino.aws.proxy.server.testing.harness.TrinoAwsProxyTestCommonModules.WithConfiguredBuckets; +import io.trino.aws.proxy.server.testing.harness.TrinoAwsProxyTestCommonModules.WithVirtualHostEnabledProxy; +import software.amazon.awssdk.services.s3.S3Client; + +import java.util.List; + +@TrinoAwsProxyTest(filters = {WithConfiguredBuckets.class, WithVirtualHostEnabledProxy.class}) +public class TestProxiedRequestsWithPathStyleOnVirtualHostProxy + extends AbstractTestProxiedRequests +{ + @Inject + public TestProxiedRequestsWithPathStyleOnVirtualHostProxy(S3Client s3Client, @ForS3Container S3Client storageClient, @ForS3Container List configuredBuckets) + { + super(s3Client, storageClient, configuredBuckets); + } +} diff --git a/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/TestProxiedRequestsWithVirtualHostProxy.java b/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/TestProxiedRequestsWithVirtualHostProxy.java index 274cc059..9df4fce4 100644 --- a/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/TestProxiedRequestsWithVirtualHostProxy.java +++ b/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/TestProxiedRequestsWithVirtualHostProxy.java @@ -14,6 +14,7 @@ package io.trino.aws.proxy.server; import com.google.inject.Inject; +import io.trino.aws.proxy.server.testing.TestingS3ClientModule.ForVirtualHostProxy; import io.trino.aws.proxy.server.testing.containers.S3Container.ForS3Container; import io.trino.aws.proxy.server.testing.harness.TrinoAwsProxyTest; import io.trino.aws.proxy.server.testing.harness.TrinoAwsProxyTestCommonModules.WithConfiguredBuckets; @@ -22,12 +23,12 @@ import java.util.List; -@TrinoAwsProxyTest(filters = {WithConfiguredBuckets.class, WithVirtualHostEnabledProxy.class, WithVirtualHostEnabledProxy.class}) +@TrinoAwsProxyTest(filters = {WithConfiguredBuckets.class, WithVirtualHostEnabledProxy.class}) public class TestProxiedRequestsWithVirtualHostProxy extends AbstractTestProxiedRequests { @Inject - public TestProxiedRequestsWithVirtualHostProxy(S3Client s3Client, @ForS3Container S3Client storageClient, @ForS3Container List configuredBuckets) + public TestProxiedRequestsWithVirtualHostProxy(@ForVirtualHostProxy S3Client s3Client, @ForS3Container S3Client storageClient, @ForS3Container List configuredBuckets) { super(s3Client, storageClient, configuredBuckets); } diff --git a/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/testing/TestingS3ClientModule.java b/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/testing/TestingS3ClientModule.java new file mode 100644 index 00000000..6c7f3158 --- /dev/null +++ b/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/testing/TestingS3ClientModule.java @@ -0,0 +1,70 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.trino.aws.proxy.server.testing; + +import com.google.inject.AbstractModule; +import com.google.inject.BindingAnnotation; +import com.google.inject.Provides; +import io.airlift.http.server.testing.TestingHttpServer; +import io.trino.aws.proxy.server.TrinoAwsProxyConfig; +import io.trino.aws.proxy.server.testing.TestingUtil.ForTesting; +import io.trino.aws.proxy.spi.credentials.Credential; +import io.trino.aws.proxy.spi.credentials.Credentials; +import jakarta.ws.rs.core.UriBuilder; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.services.s3.S3Client; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static com.google.common.base.Preconditions.checkArgument; +import static io.trino.aws.proxy.server.testing.TestingUtil.clientBuilder; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +public class TestingS3ClientModule + extends AbstractModule +{ + @Retention(RUNTIME) + @Target({FIELD, PARAMETER, METHOD}) + @BindingAnnotation + public @interface ForVirtualHostProxy {} + + @Provides + public S3Client getPathStyleAddressingClient(TestingHttpServer httpServer, @ForTesting Credentials credentials, TrinoAwsProxyConfig config) + { + Credential emulatedCredentials = credentials.emulated(); + AwsBasicCredentials awsBasicCredentials = AwsBasicCredentials.create(emulatedCredentials.accessKey(), emulatedCredentials.secretKey()); + return clientBuilder(UriBuilder.fromUri(httpServer.getBaseUrl()).path(config.getS3Path()).build()) + .credentialsProvider(() -> awsBasicCredentials) + .forcePathStyle(true) + .build(); + } + + @Provides + @ForVirtualHostProxy + public S3Client getVirtualHostAddressingClient(TestingHttpServer httpServer, @ForTesting Credentials credentials, TrinoAwsProxyConfig config) + { + checkArgument(config.getS3HostName().isPresent(), "virtual host addressing proxy client requested but S3 hostname is not set"); + String hostname = config.getS3HostName().orElseThrow(); + Credential emulatedCredentials = credentials.emulated(); + AwsBasicCredentials awsBasicCredentials = AwsBasicCredentials.create(emulatedCredentials.accessKey(), emulatedCredentials.secretKey()); + return clientBuilder(UriBuilder.newInstance().host(hostname).port(httpServer.getBaseUrl().getPort()).scheme("http").path(config.getS3Path()).build()) + .credentialsProvider(() -> awsBasicCredentials) + .forcePathStyle(false) + .build(); + } +} diff --git a/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/testing/TestingS3ClientProvider.java b/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/testing/TestingS3ClientProvider.java deleted file mode 100644 index 573e199b..00000000 --- a/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/testing/TestingS3ClientProvider.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.trino.aws.proxy.server.testing; - -import com.google.inject.Inject; -import com.google.inject.Provider; -import io.airlift.http.server.testing.TestingHttpServer; -import io.trino.aws.proxy.server.TrinoAwsProxyConfig; -import io.trino.aws.proxy.server.testing.TestingUtil.ForTesting; -import io.trino.aws.proxy.spi.credentials.Credential; -import io.trino.aws.proxy.spi.credentials.Credentials; -import jakarta.ws.rs.core.UriBuilder; -import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; -import software.amazon.awssdk.services.s3.S3Client; - -import java.net.URI; -import java.util.Optional; - -import static io.trino.aws.proxy.server.testing.TestingUtil.clientBuilder; -import static java.util.Objects.requireNonNull; - -public class TestingS3ClientProvider - implements Provider -{ - private final URI proxyUri; - private final Credential testingCredentials; - private final boolean forcePathStyle; - - public record TestingS3ClientConfig(Optional hostName, String s3Path) - { - public TestingS3ClientConfig - { - requireNonNull(hostName, "hostName is null"); - requireNonNull(s3Path, "s3Path is null"); - } - - @Inject - public TestingS3ClientConfig(TrinoAwsProxyConfig config) - { - this(config.getS3HostName(), config.getS3Path()); - } - } - - @Inject - public TestingS3ClientProvider(TestingHttpServer httpServer, @ForTesting Credentials testingCredentials, TestingS3ClientConfig clientConfig) - { - URI localProxyServerUri = httpServer.getBaseUrl(); - this.proxyUri = clientConfig.hostName() - .map(serverHostName -> UriBuilder.newInstance().host(serverHostName).port(localProxyServerUri.getPort()).scheme("http").path(clientConfig.s3Path()).build()) - .orElse(UriBuilder.fromUri(localProxyServerUri).path(clientConfig.s3Path()).build()); - this.testingCredentials = requireNonNull(testingCredentials, "testingCredentials is null").emulated(); - this.forcePathStyle = clientConfig.hostName().isEmpty(); - } - - @Override - public S3Client get() - { - AwsBasicCredentials awsBasicCredentials = AwsBasicCredentials.create(testingCredentials.accessKey(), testingCredentials.secretKey()); - - return clientBuilder(proxyUri) - .credentialsProvider(() -> awsBasicCredentials) - .forcePathStyle(forcePathStyle) - .build(); - } -} diff --git a/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/testing/harness/TrinoAwsProxyTestExtension.java b/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/testing/harness/TrinoAwsProxyTestExtension.java index 6a8dff84..d13eb824 100644 --- a/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/testing/harness/TrinoAwsProxyTestExtension.java +++ b/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/testing/harness/TrinoAwsProxyTestExtension.java @@ -18,7 +18,7 @@ import com.google.inject.Scopes; import io.trino.aws.proxy.server.remote.RemoteS3Facade; import io.trino.aws.proxy.server.testing.ContainerS3Facade; -import io.trino.aws.proxy.server.testing.TestingS3ClientProvider; +import io.trino.aws.proxy.server.testing.TestingS3ClientModule; import io.trino.aws.proxy.server.testing.TestingTrinoAwsProxyServer; import io.trino.aws.proxy.server.testing.TestingUtil.ForTesting; import io.trino.aws.proxy.server.testing.containers.S3Container; @@ -72,9 +72,7 @@ public Object createTestInstance(TestInstanceFactoryContext factoryContext, Exte Injector injector = trinoS3ProxyServer.getInjector() .createChildInjector(binder -> { - binder.bind(TestingS3ClientProvider.TestingS3ClientConfig.class).in(Scopes.SINGLETON); - binder.bind(TestingS3ClientProvider.class).in(Scopes.SINGLETON); - binder.bind(S3Client.class).toProvider(TestingS3ClientProvider.class).in(Scopes.SINGLETON); + binder.install(new TestingS3ClientModule()); binder.bind(TestingTrinoAwsProxyServer.class).toInstance(trinoS3ProxyServer); binder.bind(factoryContext.getTestClass()).in(Scopes.SINGLETON); });