1 /* 2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"). 5 * You may not use this file except in compliance with the License. 6 * A copy of the License is located at 7 * 8 * http://aws.amazon.com/apache2.0 9 * 10 * or in the "license" file accompanying this file. This file is distributed 11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 * express or implied. See the License for the specific language governing 13 * permissions and limitations under the License. 14 */ 15 16 package software.amazon.awssdk.services.s3.internal.handlers; 17 18 import static software.amazon.awssdk.utils.FunctionalUtils.invokeSafely; 19 20 import java.io.InputStream; 21 import java.nio.ByteBuffer; 22 import java.util.Optional; 23 import java.util.function.Predicate; 24 import org.reactivestreams.Publisher; 25 import software.amazon.awssdk.annotations.SdkInternalApi; 26 import software.amazon.awssdk.core.interceptor.Context; 27 import software.amazon.awssdk.core.interceptor.ExecutionAttributes; 28 import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; 29 import software.amazon.awssdk.core.internal.async.SdkPublishers; 30 import software.amazon.awssdk.http.AbortableInputStream; 31 import software.amazon.awssdk.services.s3.model.GetBucketPolicyRequest; 32 import software.amazon.awssdk.utils.IoUtils; 33 import software.amazon.awssdk.utils.StringInputStream; 34 35 /** 36 * GetBucketPolicy returns just JSON so we wrap in XML so that it is unmarshalled correctly. 37 */ 38 @SdkInternalApi 39 public final class GetBucketPolicyInterceptor implements ExecutionInterceptor { 40 private static final String XML_ENVELOPE_PREFIX = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Policy><![CDATA["; 41 private static final String XML_ENVELOPE_SUFFIX = "]]></Policy>"; 42 43 private static final Predicate<Context.ModifyHttpResponse> INTERCEPTOR_CONTEXT_PREDICATE = 44 context -> context.request() instanceof GetBucketPolicyRequest && context.httpResponse().isSuccessful(); 45 46 @Override modifyHttpResponseContent(Context.ModifyHttpResponse context, ExecutionAttributes executionAttributes)47 public Optional<InputStream> modifyHttpResponseContent(Context.ModifyHttpResponse context, 48 ExecutionAttributes executionAttributes) { 49 if (INTERCEPTOR_CONTEXT_PREDICATE.test(context)) { 50 51 String policy = context.responseBody() 52 .map(r -> invokeSafely(() -> IoUtils.toUtf8String(r))) 53 .orElse(null); 54 55 if (policy != null) { 56 String xml = XML_ENVELOPE_PREFIX + policy + XML_ENVELOPE_SUFFIX; 57 return Optional.of(AbortableInputStream.create(new StringInputStream(xml))); 58 } 59 } 60 61 return context.responseBody(); 62 } 63 64 @Override modifyAsyncHttpResponseContent(Context.ModifyHttpResponse context, ExecutionAttributes executionAttributes)65 public Optional<Publisher<ByteBuffer>> modifyAsyncHttpResponseContent(Context.ModifyHttpResponse context, 66 ExecutionAttributes executionAttributes) { 67 if (INTERCEPTOR_CONTEXT_PREDICATE.test(context)) { 68 return context.responsePublisher().map( 69 body -> SdkPublishers.envelopeWrappedPublisher(body, XML_ENVELOPE_PREFIX, XML_ENVELOPE_SUFFIX)); 70 } 71 72 return context.responsePublisher(); 73 } 74 } 75