Skip to content

Commit

Permalink
Fail codegen for Query protocol operations with explicit String paylo…
Browse files Browse the repository at this point in the history
…ad (#4553)

* Fail codegen for Query protocol operations with explicit String payload

* Update exception message

* Move validation to CodegenCustomizationProcessor
  • Loading branch information
davidh44 authored Oct 6, 2023
1 parent 4bdff30 commit 13985e0
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ private static boolean isBlobShape(Shape shape) {
* @return True if shape is a String type. False otherwise
*/
private static boolean isStringShape(Shape shape) {
return shape != null && "String".equals(shape.getType());
return shape != null && "String".equalsIgnoreCase(shape.getType());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ public static CodegenCustomizationProcessor getProcessorFor(
new UseLegacyEventGenerationSchemeProcessor(),
new NewAndLegacyEventStreamProcessor(),
new S3RemoveBucketFromUriProcessor(),
new S3ControlRemoveAccountIdHostPrefixProcessor()
new S3ControlRemoveAccountIdHostPrefixProcessor(),
new ExplicitStringPayloadQueryProtocolProcessor()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright 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.codegen.customization.processors;

import java.util.Map;
import software.amazon.awssdk.codegen.customization.CodegenCustomizationProcessor;
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
import software.amazon.awssdk.codegen.model.service.Input;
import software.amazon.awssdk.codegen.model.service.Member;
import software.amazon.awssdk.codegen.model.service.Output;
import software.amazon.awssdk.codegen.model.service.ServiceModel;
import software.amazon.awssdk.codegen.model.service.Shape;

/**
* Operations with explicit String payloads are not supported for services with Query protocol. We fail the codegen if the
* httpPayload or eventPayload trait is set on a String.
*/
public class ExplicitStringPayloadQueryProtocolProcessor implements CodegenCustomizationProcessor {
@Override
public void preprocess(ServiceModel serviceModel) {
String protocol = serviceModel.getMetadata().getProtocol();
if (!"ec2".equals(protocol) && !"query".equals(protocol)) {
return;
}

Map<String, Shape> c2jShapes = serviceModel.getShapes();

serviceModel.getOperations().forEach((operationName, op) -> {

Input input = op.getInput();
if (input != null && isExplicitStringPayload(c2jShapes, c2jShapes.get(input.getShape()))) {
throw new RuntimeException("Operations with explicit String payloads are not supported for Query "
+ "protocols. Unsupported operation: " + operationName);

}

Output output = op.getOutput();
if (output != null && isExplicitStringPayload(c2jShapes, c2jShapes.get(output.getShape()))) {
throw new RuntimeException("Operations with explicit String payloads are not supported for Query "
+ "protocols. Unsupported operation: " + operationName);

}
});
}

@Override
public void postprocess(IntermediateModel intermediateModel) {
// no-op
}

private boolean isExplicitStringPayload(Map<String, Shape> c2jShapes, Shape shape) {
if (shape.getPayload() == null) {
return false;
}

Member payloadMember = shape.getMembers().get(shape.getPayload());
Shape payloadShape = c2jShapes.get(payloadMember.getShape());
return payloadShape != null && "String".equalsIgnoreCase(payloadShape.getType());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@
"ChecksumStructure":{
"type":"structure",
"members":{
"stringMember":{"shape":"subMember"},
"Body":{"shape":"Body"},
"ChecksumMode":{
"shape":"ChecksumMode",
"location":"header",
Expand All @@ -337,7 +337,7 @@
"locationName":"x-amz-checksum-algorithm"
}
},
"payload":"stringMember"
"payload":"Body"
},
"String":{"type":"string"},
"BearerAuthOperationRequest": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,7 @@ public CompletableFuture<GetOperationWithChecksumResponse> getOperationWithCheck
apiCallMetricCollector.reportMetric(CoreMetric.SERVICE_ID, "Json Service");
apiCallMetricCollector.reportMetric(CoreMetric.OPERATION_NAME, "GetOperationWithChecksum");
JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false)
.isPayloadJson(true).build();
.isPayloadJson(false).build();

HttpResponseHandler<GetOperationWithChecksumResponse> responseHandler = protocolFactory.createResponseHandler(
operationMetadata, GetOperationWithChecksumResponse::builder);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ public GetOperationWithChecksumResponse getOperationWithChecksum(
GetOperationWithChecksumRequest getOperationWithChecksumRequest) throws AwsServiceException, SdkClientException,
JsonException {
JsonOperationMetadata operationMetadata = JsonOperationMetadata.builder().hasStreamingSuccessResponse(false)
.isPayloadJson(true).build();
.isPayloadJson(false).build();

HttpResponseHandler<GetOperationWithChecksumResponse> responseHandler = protocolFactory.createResponseHandler(
operationMetadata, GetOperationWithChecksumResponse::builder);
Expand Down

0 comments on commit 13985e0

Please sign in to comment.