diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/Metadata.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/Metadata.java
index c320a5a21e5d..d4724384f55e 100644
--- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/Metadata.java
+++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/Metadata.java
@@ -519,6 +519,11 @@ public boolean isXmlProtocol() {
protocol == Protocol.REST_XML;
}
+ public boolean isQueryProtocol() {
+ return protocol == Protocol.EC2 ||
+ protocol == Protocol.QUERY;
+ }
+
/**
* @return True for RESTful protocols. False for all other protocols (RPC, Query, etc).
*/
diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java
index c2a0e8aaac35..70570438a9de 100644
--- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java
+++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java
@@ -24,8 +24,12 @@
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeVariableName;
+
+import java.util.Collections;
import java.util.List;
import javax.lang.model.element.Modifier;
import software.amazon.awssdk.annotations.SdkInternalApi;
@@ -46,6 +50,7 @@
import software.amazon.awssdk.core.signer.Signer;
import software.amazon.awssdk.http.Protocol;
import software.amazon.awssdk.http.SdkHttpConfigurationOption;
+import software.amazon.awssdk.protocols.query.interceptor.QueryParametersToBodyInterceptor;
import software.amazon.awssdk.utils.AttributeMap;
import software.amazon.awssdk.utils.CollectionUtils;
import software.amazon.awssdk.utils.StringUtils;
@@ -177,6 +182,16 @@ private MethodSpec finalizeServiceConfigurationMethod() {
.addCode("interceptors = $T.mergeLists(interceptors, config.option($T.EXECUTION_INTERCEPTORS));\n",
CollectionUtils.class, SdkClientOption.class);
+ if (model.getMetadata().isQueryProtocol()) {
+ TypeName listType = ParameterizedTypeName.get(List.class, ExecutionInterceptor.class);
+ builder.addStatement("$T protocolInterceptors = $T.singletonList(new $T())",
+ listType,
+ Collections.class,
+ QueryParametersToBodyInterceptor.class);
+ builder.addStatement("interceptors = $T.mergeLists(interceptors, protocolInterceptors)",
+ CollectionUtils.class);
+ }
+
if (model.getEndpointOperation().isPresent()) {
builder.beginControlFlow("if (!endpointDiscoveryEnabled)")
.addStatement("endpointDiscoveryEnabled = CHAIN.resolveEndpointDiscovery()")
diff --git a/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/interceptor/QueryParametersToBodyInterceptor.java b/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/interceptor/QueryParametersToBodyInterceptor.java
new file mode 100644
index 000000000000..f094df4b6346
--- /dev/null
+++ b/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/interceptor/QueryParametersToBodyInterceptor.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2010-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.protocols.query.interceptor;
+
+import static java.util.Collections.singletonList;
+import static software.amazon.awssdk.utils.StringUtils.lowerCase;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+
+import software.amazon.awssdk.annotations.SdkProtectedApi;
+import software.amazon.awssdk.core.interceptor.Context;
+import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
+import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
+import software.amazon.awssdk.http.SdkHttpFullRequest;
+import software.amazon.awssdk.http.SdkHttpMethod;
+import software.amazon.awssdk.http.SdkHttpRequest;
+import software.amazon.awssdk.utils.CollectionUtils;
+import software.amazon.awssdk.utils.http.SdkHttpUtils;
+
+/**
+ * Modifies an HTTP request by moving query parameters to the body under the following conditions:
+ * - It is a POST request
+ * - There is no content stream provider
+ * - There are query parameters to transfer
+ *
+ * This interceptor is automatically inserted by codegen for services using Query Protocol
+ */
+@SdkProtectedApi
+public final class QueryParametersToBodyInterceptor implements ExecutionInterceptor {
+
+ private static final String DEFAULT_CONTENT_TYPE = "application/x-www-form-urlencoded; charset=" +
+ lowerCase(StandardCharsets.UTF_8.toString());
+
+ @Override
+ public SdkHttpRequest modifyHttpRequest(Context.ModifyHttpRequest context,
+ ExecutionAttributes executionAttributes) {
+
+ SdkHttpRequest httpRequest = context.httpRequest();
+
+ if (!(httpRequest instanceof SdkHttpFullRequest)) {
+ return httpRequest;
+ }
+
+ SdkHttpFullRequest httpFullRequest = (SdkHttpFullRequest) httpRequest;
+ if (shouldPutParamsInBody(httpFullRequest)) {
+ return changeQueryParametersToFormData(httpFullRequest);
+ }
+ return httpFullRequest;
+ }
+
+ private boolean shouldPutParamsInBody(SdkHttpFullRequest input) {
+ return input.method() == SdkHttpMethod.POST &&
+ !input.contentStreamProvider().isPresent() &&
+ !CollectionUtils.isNullOrEmpty(input.rawQueryParameters());
+ }
+
+ private SdkHttpRequest changeQueryParametersToFormData(SdkHttpFullRequest input) {
+ byte[] params = SdkHttpUtils.encodeAndFlattenFormData(input.rawQueryParameters()).orElse("")
+ .getBytes(StandardCharsets.UTF_8);
+
+ return input.toBuilder().clearQueryParameters()
+ .contentStreamProvider(() -> new ByteArrayInputStream(params))
+ .putHeader("Content-Length", singletonList(String.valueOf(params.length)))
+ .putHeader("Content-Type", singletonList(DEFAULT_CONTENT_TYPE))
+ .build();
+ }
+
+}
diff --git a/core/protocols/aws-query-protocol/src/test/java/software/amazon/awssdk/protocols/query/interceptor/QueryParametersToBodyInterceptorTest.java b/core/protocols/aws-query-protocol/src/test/java/software/amazon/awssdk/protocols/query/interceptor/QueryParametersToBodyInterceptorTest.java
new file mode 100644
index 000000000000..604674f6b11b
--- /dev/null
+++ b/core/protocols/aws-query-protocol/src/test/java/software/amazon/awssdk/protocols/query/interceptor/QueryParametersToBodyInterceptorTest.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2010-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.protocols.query.interceptor;
+
+import org.junit.Before;
+import org.junit.Test;
+import software.amazon.awssdk.core.Protocol;
+import software.amazon.awssdk.core.SdkRequest;
+import software.amazon.awssdk.core.async.AsyncRequestBody;
+import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
+import software.amazon.awssdk.core.sync.RequestBody;
+import software.amazon.awssdk.http.ContentStreamProvider;
+import software.amazon.awssdk.http.SdkHttpFullRequest;
+import software.amazon.awssdk.http.SdkHttpMethod;
+import software.amazon.awssdk.http.SdkHttpRequest;
+import software.amazon.awssdk.utils.IoUtils;
+
+import java.io.ByteArrayInputStream;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import static java.util.Collections.singletonList;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class QueryParametersToBodyInterceptorTest {
+
+ public static final URI HTTP_LOCALHOST = URI.create("http://localhost:8080");
+
+ private QueryParametersToBodyInterceptor interceptor;
+ private ExecutionAttributes executionAttributes;
+
+ private SdkHttpFullRequest.Builder requestBuilder;
+
+ @Before
+ public void setup() {
+
+ interceptor = new QueryParametersToBodyInterceptor();
+ executionAttributes = new ExecutionAttributes();
+
+ requestBuilder = SdkHttpFullRequest.builder()
+ .protocol(Protocol.HTTPS.toString())
+ .method(SdkHttpMethod.POST)
+ .putRawQueryParameter("key", singletonList("value"))
+ .uri(HTTP_LOCALHOST);
+ }
+
+ @Test
+ public void postRequestsWithNoBodyHaveTheirParametersMovedToTheBody() throws Exception {
+
+ SdkHttpFullRequest request = requestBuilder.build();
+
+ SdkHttpFullRequest output = (SdkHttpFullRequest) interceptor.modifyHttpRequest(
+ new HttpRequestOnlyContext(request, null), executionAttributes);
+
+ assertThat(output.rawQueryParameters()).hasSize(0);
+ assertThat(output.headers())
+ .containsKey("Content-Length")
+ .containsEntry("Content-Type", singletonList("application/x-www-form-urlencoded; charset=utf-8"));
+ assertThat(output.contentStreamProvider()).isNotEmpty();
+ }
+
+ @Test
+ public void nonPostRequestsWithNoBodyAreUnaltered() throws Exception {
+ Stream.of(SdkHttpMethod.values())
+ .filter(m -> !m.equals(SdkHttpMethod.POST))
+ .forEach(this::nonPostRequestsUnaltered);
+ }
+
+ @Test
+ public void postWithContentIsUnaltered() throws Exception {
+ byte[] contentBytes = "hello".getBytes(StandardCharsets.UTF_8);
+ ContentStreamProvider contentProvider = () -> new ByteArrayInputStream(contentBytes);
+
+ SdkHttpFullRequest request = requestBuilder.contentStreamProvider(contentProvider).build();
+
+ SdkHttpFullRequest output = (SdkHttpFullRequest) interceptor.modifyHttpRequest(
+ new HttpRequestOnlyContext(request, null), executionAttributes);
+
+ assertThat(output.rawQueryParameters()).hasSize(1);
+ assertThat(output.headers()).hasSize(0);
+ assertThat(IoUtils.toByteArray(output.contentStreamProvider().get().newStream())).isEqualTo(contentBytes);
+ }
+
+ @Test
+ public void onlyAlterRequestsIfParamsArePresent() throws Exception {
+ SdkHttpFullRequest request = requestBuilder.clearQueryParameters().build();
+
+ SdkHttpFullRequest output = (SdkHttpFullRequest) interceptor.modifyHttpRequest(
+ new HttpRequestOnlyContext(request, null), executionAttributes);
+
+ assertThat(output.rawQueryParameters()).hasSize(0);
+ assertThat(output.headers()).hasSize(0);
+ assertThat(output.contentStreamProvider()).isEmpty();
+ }
+
+ private void nonPostRequestsUnaltered(SdkHttpMethod method) {
+
+ SdkHttpFullRequest request = requestBuilder.method(method).build();
+
+ SdkHttpFullRequest output = (SdkHttpFullRequest) interceptor.modifyHttpRequest(
+ new HttpRequestOnlyContext(request, null), executionAttributes);
+
+ assertThat(output.rawQueryParameters()).hasSize(1);
+ assertThat(output.headers()).hasSize(0);
+ assertThat(output.contentStreamProvider()).isEmpty();
+ }
+
+ public final class HttpRequestOnlyContext implements software.amazon.awssdk.core.interceptor.Context.ModifyHttpRequest {
+
+ private final SdkHttpRequest request;
+ private final RequestBody requestBody;
+
+ public HttpRequestOnlyContext(SdkHttpRequest request,
+ RequestBody requestBody) {
+ this.request = request;
+ this.requestBody = requestBody;
+ }
+
+ @Override
+ public SdkRequest request() {
+ return null;
+ }
+
+ @Override
+ public SdkHttpRequest httpRequest() {
+ return request;
+ }
+
+ @Override
+ public Optional requestBody() {
+ return Optional.ofNullable(requestBody);
+ }
+
+ @Override
+ public Optional asyncRequestBody() {
+ return Optional.empty();
+ }
+ }
+}
diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/AmazonAsyncHttpClient.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/AmazonAsyncHttpClient.java
index 04ec7d53ba1c..90ab4fad1b7c 100644
--- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/AmazonAsyncHttpClient.java
+++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/AmazonAsyncHttpClient.java
@@ -40,7 +40,6 @@
import software.amazon.awssdk.core.internal.http.pipeline.stages.MakeRequestMutableStage;
import software.amazon.awssdk.core.internal.http.pipeline.stages.MergeCustomHeadersStage;
import software.amazon.awssdk.core.internal.http.pipeline.stages.MergeCustomQueryParamsStage;
-import software.amazon.awssdk.core.internal.http.pipeline.stages.MoveParametersToBodyStage;
import software.amazon.awssdk.core.internal.http.pipeline.stages.SigningStage;
import software.amazon.awssdk.core.internal.http.pipeline.stages.UnwrapResponseContainer;
import software.amazon.awssdk.core.internal.retry.SdkDefaultRetrySetting;
@@ -178,7 +177,6 @@ public CompletableFuture execute(
.then(ApplyUserAgentStage::new)
.then(MergeCustomHeadersStage::new)
.then(MergeCustomQueryParamsStage::new)
- .then(MoveParametersToBodyStage::new)
.then(MakeRequestImmutableStage::new)
.then(RequestPipelineBuilder
.first(SigningStage::new)
diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/AmazonSyncHttpClient.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/AmazonSyncHttpClient.java
index b98361021d3f..3bdcc23d5966 100644
--- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/AmazonSyncHttpClient.java
+++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/AmazonSyncHttpClient.java
@@ -40,7 +40,6 @@
import software.amazon.awssdk.core.internal.http.pipeline.stages.MakeRequestMutableStage;
import software.amazon.awssdk.core.internal.http.pipeline.stages.MergeCustomHeadersStage;
import software.amazon.awssdk.core.internal.http.pipeline.stages.MergeCustomQueryParamsStage;
-import software.amazon.awssdk.core.internal.http.pipeline.stages.MoveParametersToBodyStage;
import software.amazon.awssdk.core.internal.http.pipeline.stages.RetryableStage;
import software.amazon.awssdk.core.internal.http.pipeline.stages.SigningStage;
import software.amazon.awssdk.core.internal.http.pipeline.stages.TimeoutExceptionHandlingStage;
@@ -178,7 +177,6 @@ public OutputT execute(HttpResponseHandler> response
.then(ApplyUserAgentStage::new)
.then(MergeCustomHeadersStage::new)
.then(MergeCustomQueryParamsStage::new)
- .then(MoveParametersToBodyStage::new)
.then(MakeRequestImmutableStage::new)
// End of mutating request
.then(RequestPipelineBuilder
diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/pipeline/stages/MoveParametersToBodyStage.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/pipeline/stages/MoveParametersToBodyStage.java
deleted file mode 100644
index d7b02781998a..000000000000
--- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/pipeline/stages/MoveParametersToBodyStage.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2010-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License").
- * You may not use this file except in compliance with the License.
- * A copy of the License is located at
- *
- * http://aws.amazon.com/apache2.0
- *
- * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.core.internal.http.pipeline.stages;
-
-import static java.util.Collections.singletonList;
-import static software.amazon.awssdk.utils.StringUtils.lowerCase;
-
-import java.io.ByteArrayInputStream;
-import java.nio.charset.StandardCharsets;
-import software.amazon.awssdk.annotations.SdkInternalApi;
-import software.amazon.awssdk.core.internal.http.RequestExecutionContext;
-import software.amazon.awssdk.core.internal.http.pipeline.MutableRequestToRequestPipeline;
-import software.amazon.awssdk.http.SdkHttpFullRequest;
-import software.amazon.awssdk.http.SdkHttpMethod;
-import software.amazon.awssdk.utils.CollectionUtils;
-import software.amazon.awssdk.utils.http.SdkHttpUtils;
-
-@SdkInternalApi
-//TODO Might only need to do this for certain protocols - ie query?
-public final class MoveParametersToBodyStage implements MutableRequestToRequestPipeline {
- @Override
- public SdkHttpFullRequest.Builder execute(SdkHttpFullRequest.Builder input, RequestExecutionContext context) {
- if (shouldPutParamsInBody(input)) {
- return changeQueryParametersToFormData(input);
- }
- return input;
- }
-
- private boolean shouldPutParamsInBody(SdkHttpFullRequest.Builder input) {
- return input.method() == SdkHttpMethod.POST &&
- input.contentStreamProvider() == null &&
- !CollectionUtils.isNullOrEmpty(input.rawQueryParameters());
- }
-
- private static SdkHttpFullRequest.Builder changeQueryParametersToFormData(SdkHttpFullRequest.Builder input) {
- byte[] params = SdkHttpUtils.encodeAndFlattenFormData(input.rawQueryParameters()).orElse("")
- .getBytes(StandardCharsets.UTF_8);
-
- return input.clearQueryParameters()
- .contentStreamProvider(() -> new ByteArrayInputStream(params))
- .putHeader("Content-Length", singletonList(String.valueOf(params.length)))
- .putHeader("Content-Type", singletonList("application/x-www-form-urlencoded; charset=" +
- lowerCase(StandardCharsets.UTF_8.toString())));
- }
-}
diff --git a/core/sdk-core/src/test/java/software/amazon/awssdk/core/internal/http/pipeline/stages/MoveParametersToBodyStageTest.java b/core/sdk-core/src/test/java/software/amazon/awssdk/core/internal/http/pipeline/stages/MoveParametersToBodyStageTest.java
deleted file mode 100644
index c4f481b363b2..000000000000
--- a/core/sdk-core/src/test/java/software/amazon/awssdk/core/internal/http/pipeline/stages/MoveParametersToBodyStageTest.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright 2010-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License").
- * You may not use this file except in compliance with the License.
- * A copy of the License is located at
- *
- * http://aws.amazon.com/apache2.0
- *
- * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.core.internal.http.pipeline.stages;
-
-import static java.util.Collections.singletonList;
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.io.ByteArrayInputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.stream.Stream;
-import org.junit.Test;
-import software.amazon.awssdk.core.http.ExecutionContext;
-import software.amazon.awssdk.core.http.NoopTestRequest;
-import software.amazon.awssdk.core.internal.http.RequestExecutionContext;
-import software.amazon.awssdk.core.internal.http.timers.ClientExecutionAndRequestTimerTestUtils;
-import software.amazon.awssdk.http.ContentStreamProvider;
-import software.amazon.awssdk.http.SdkHttpFullRequest;
-import software.amazon.awssdk.http.SdkHttpMethod;
-import software.amazon.awssdk.utils.IoUtils;
-import utils.ValidSdkObjects;
-
-public class MoveParametersToBodyStageTest {
-
- private final MoveParametersToBodyStage sut = new MoveParametersToBodyStage();
-
- @Test
- public void postRequestsWithNoBodyHaveTheirParametersMovedToTheBody() throws Exception {
- SdkHttpFullRequest.Builder mutableRequest = ValidSdkObjects.sdkHttpFullRequest()
- .method(SdkHttpMethod.POST)
- .putRawQueryParameter("key", singletonList("value"));
-
- SdkHttpFullRequest output = sut.execute(mutableRequest, requestContext(mutableRequest)).build();
-
- assertThat(output.rawQueryParameters()).hasSize(0);
- assertThat(output.headers())
- .containsKey("Content-Length")
- .containsEntry("Content-Type", singletonList("application/x-www-form-urlencoded; charset=utf-8"));
- assertThat(output.contentStreamProvider()).isNotEmpty();
- }
-
- @Test
- public void nonPostRequestsWithNoBodyAreUnaltered() throws Exception {
- Stream.of(SdkHttpMethod.values())
- .filter(m -> !m.equals(SdkHttpMethod.POST))
- .forEach(this::nonPostRequestsUnaltered);
- }
-
- @Test
- public void postWithContentIsUnaltered() throws Exception {
- byte[] contentBytes = "hello".getBytes(StandardCharsets.UTF_8);
- ContentStreamProvider contentProvider = () -> new ByteArrayInputStream(contentBytes);
- SdkHttpFullRequest.Builder mutableRequest = ValidSdkObjects.sdkHttpFullRequest()
- .contentStreamProvider(contentProvider)
- .method(SdkHttpMethod.POST)
- .clearHeaders()
- .putRawQueryParameter("key", singletonList("value"));
-
- SdkHttpFullRequest output = sut.execute(mutableRequest, requestContext(mutableRequest)).build();
-
- assertThat(output.rawQueryParameters()).hasSize(1);
- assertThat(output.headers()).hasSize(0);
- assertThat(IoUtils.toByteArray(output.contentStreamProvider().get().newStream())).isEqualTo(contentBytes);
- }
-
- @Test
- public void onlyAlterRequestsIfParamsArePresent() throws Exception {
- SdkHttpFullRequest.Builder mutableRequest = ValidSdkObjects.sdkHttpFullRequest()
- .clearHeaders()
- .method(SdkHttpMethod.POST);
-
- SdkHttpFullRequest output = sut.execute(mutableRequest, requestContext(mutableRequest)).build();
-
- assertThat(output.rawQueryParameters()).hasSize(0);
- assertThat(output.headers()).hasSize(0);
- assertThat(output.contentStreamProvider()).isEmpty();
- }
-
- private void nonPostRequestsUnaltered(SdkHttpMethod method) {
- SdkHttpFullRequest.Builder mutableRequest = ValidSdkObjects.sdkHttpFullRequest()
- .method(method)
- .clearHeaders()
- .putRawQueryParameter("key", singletonList("value"));
-
- SdkHttpFullRequest output = sut.execute(mutableRequest, requestContext(mutableRequest)).build();
-
- assertThat(output.rawQueryParameters()).hasSize(1);
- assertThat(output.headers()).hasSize(0);
- assertThat(output.contentStreamProvider()).isEmpty();
- }
-
- private RequestExecutionContext requestContext(SdkHttpFullRequest.Builder mutableRequest) {
- ExecutionContext executionContext = ClientExecutionAndRequestTimerTestUtils.executionContext(mutableRequest.build());
- return RequestExecutionContext.builder()
- .executionContext(executionContext)
- .originalRequest(NoopTestRequest.builder().build())
- .build();
- }
-}
diff --git a/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/QueryRequestTransformTest.java b/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/QueryRequestTransformTest.java
new file mode 100644
index 000000000000..5be7f51a4460
--- /dev/null
+++ b/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/QueryRequestTransformTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.protocol.tests;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl;
+import static com.github.tomakehurst.wiremock.client.WireMock.containing;
+import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
+import static com.github.tomakehurst.wiremock.client.WireMock.getAllServeEvents;
+import static com.github.tomakehurst.wiremock.client.WireMock.matching;
+import static com.github.tomakehurst.wiremock.client.WireMock.post;
+import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.verify;
+
+import com.github.tomakehurst.wiremock.junit.WireMockRule;
+import com.github.tomakehurst.wiremock.stubbing.ServeEvent;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
+import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
+import software.amazon.awssdk.http.Header;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.protocolquery.ProtocolQueryAsyncClient;
+import software.amazon.awssdk.services.protocolquery.ProtocolQueryClient;
+import software.amazon.awssdk.services.protocolquery.model.IdempotentOperationRequest;
+
+import java.net.URI;
+import java.util.List;
+
+public class QueryRequestTransformTest {
+
+ @Rule
+ public WireMockRule wireMock = new WireMockRule(0);
+
+ private ProtocolQueryClient client;
+ private ProtocolQueryAsyncClient asyncClient;
+
+ @Before
+ public void setupClient() {
+ client = ProtocolQueryClient.builder()
+ .credentialsProvider(StaticCredentialsProvider.create(
+ AwsBasicCredentials.create("akid", "skid")))
+ .region(Region.US_EAST_1)
+ .endpointOverride(URI.create("http://localhost:" + wireMock.port()))
+ .build();
+
+ asyncClient = ProtocolQueryAsyncClient.builder()
+ .credentialsProvider(StaticCredentialsProvider.create(
+ AwsBasicCredentials.create("akid", "skid")))
+ .region(Region.US_EAST_1)
+ .endpointOverride(URI.create("http://localhost:" + wireMock.port()))
+ .build();
+ }
+
+ @Test
+ public void syncRequest_isMovingParamsToBodyStage() {
+ stubSimpleResponse();
+ IdempotentOperationRequest request = IdempotentOperationRequest.builder().idempotencyToken("test").build();
+ client.idempotentOperation(request);
+ verifyResponseMetadata();
+ }
+
+ @Test
+ public void asyncRequest_isMovingParamsToBodyStage() {
+ stubSimpleResponse();
+ IdempotentOperationRequest request = IdempotentOperationRequest.builder().idempotencyToken("test").build();
+ asyncClient.idempotentOperation(request).join();
+ verifyResponseMetadata();
+ }
+
+ private void verifyResponseMetadata() {
+ verify(postRequestedFor(anyUrl())
+ .withHeader(Header.CONTENT_TYPE, equalTo("application/x-www-form-urlencoded; charset=UTF-8"))
+ .withHeader(Header.CONTENT_LENGTH, matching("\\d+"))
+ .withUrl("/")
+ .withRequestBody(containing("Action=IdempotentOperation"))
+ .withRequestBody(containing("Version="))
+ .withRequestBody(containing("IdempotencyToken=test")));
+ }
+
+ private void stubSimpleResponse() {
+ stubFor(post(anyUrl()).willReturn(aResponse()
+ .withStatus(200)
+ .withBody("")));
+ }
+
+}