1
15
16 package software.amazon.awssdk.services.s3.internal.handlers;
17
18 import static software.amazon.awssdk.utils.http.SdkHttpUtils.urlDecode;
19
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.stream.Collectors;
23 import software.amazon.awssdk.annotations.SdkInternalApi;
24 import software.amazon.awssdk.core.SdkResponse;
25 import software.amazon.awssdk.core.interceptor.Context;
26 import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
27 import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
28 import software.amazon.awssdk.services.s3.model.CommonPrefix;
29 import software.amazon.awssdk.services.s3.model.EncodingType;
30 import software.amazon.awssdk.services.s3.model.ListMultipartUploadsResponse;
31 import software.amazon.awssdk.services.s3.model.ListObjectVersionsResponse;
32 import software.amazon.awssdk.services.s3.model.ListObjectsResponse;
33 import software.amazon.awssdk.services.s3.model.ListObjectsV2Response;
34 import software.amazon.awssdk.services.s3.model.MultipartUpload;
35 import software.amazon.awssdk.services.s3.model.ObjectVersion;
36 import software.amazon.awssdk.services.s3.model.S3Object;
37
38
50 @SdkInternalApi
51 public final class DecodeUrlEncodedResponseInterceptor implements ExecutionInterceptor {
52
53 @Override
54 public SdkResponse modifyResponse(Context.ModifyResponse context,
55 ExecutionAttributes executionAttributes) {
56 SdkResponse response = context.response();
57 if (shouldHandle(response)) {
58 if (response instanceof ListObjectsResponse) {
59 return modifyListObjectsResponse((ListObjectsResponse) response);
60 }
61
62 if (response instanceof ListObjectsV2Response) {
63 return modifyListObjectsV2Response((ListObjectsV2Response) response);
64 }
65
66 if (response instanceof ListObjectVersionsResponse) {
67 return modifyListObjectVersionsResponse((ListObjectVersionsResponse) response);
68 }
69
70 if (response instanceof ListMultipartUploadsResponse) {
71 return modifyListMultipartUploadsResponse((ListMultipartUploadsResponse) response);
72 }
73 }
74 return response;
75 }
76
77 private static boolean shouldHandle(SdkResponse sdkResponse) {
78 return sdkResponse.getValueForField("EncodingType", String.class)
79 .map(et -> EncodingType.URL.toString().equals(et))
80 .orElse(false);
81 }
82
83
84 private static SdkResponse modifyListObjectsResponse(ListObjectsResponse response) {
85 return response.toBuilder()
86 .delimiter(urlDecode(response.delimiter()))
87 .marker(urlDecode(response.marker()))
88 .prefix(urlDecode(response.prefix()))
89 .nextMarker(urlDecode(response.nextMarker()))
90 .contents(decodeContents(response.contents()))
91 .commonPrefixes(decodeCommonPrefixes(response.commonPrefixes()))
92 .build();
93 }
94
95
96 private static SdkResponse modifyListObjectsV2Response(ListObjectsV2Response response) {
97 return response.toBuilder()
98 .delimiter(urlDecode(response.delimiter()))
99 .prefix(urlDecode(response.prefix()))
100 .startAfter(urlDecode(response.startAfter()))
101 .contents(decodeContents(response.contents()))
102 .commonPrefixes(decodeCommonPrefixes(response.commonPrefixes()))
103 .build();
104 }
105
106
107
108 private SdkResponse modifyListObjectVersionsResponse(ListObjectVersionsResponse response) {
109
110 return response.toBuilder()
111 .prefix(urlDecode(response.prefix()))
112 .keyMarker(urlDecode(response.keyMarker()))
113 .delimiter(urlDecode(response.delimiter()))
114 .nextKeyMarker(urlDecode(response.nextKeyMarker()))
115 .commonPrefixes(decodeCommonPrefixes(response.commonPrefixes()))
116 .versions(decodeObjectVersions(response.versions()))
117 .build();
118 }
119
120
121
122 private SdkResponse modifyListMultipartUploadsResponse(ListMultipartUploadsResponse response) {
123 return response.toBuilder()
124 .delimiter(urlDecode(response.delimiter()))
125 .keyMarker(urlDecode(response.keyMarker()))
126 .nextKeyMarker(urlDecode(response.nextKeyMarker()))
127 .prefix(urlDecode(response.prefix()))
128 .commonPrefixes(decodeCommonPrefixes(response.commonPrefixes()))
129 .uploads(decodeMultipartUpload(response.uploads()))
130 .build();
131
132 }
133
134 private static List<S3Object> decodeContents(List<S3Object> contents) {
135 if (contents == null) {
136 return null;
137 }
138 return Collections.unmodifiableList(contents.stream()
139 .map(o -> o.toBuilder().key(urlDecode(o.key())).build())
140 .collect(Collectors.toList()));
141 }
142
143 private static List<ObjectVersion> decodeObjectVersions(List<ObjectVersion> objectVersions) {
144 if (objectVersions == null) {
145 return null;
146 }
147
148 return Collections.unmodifiableList(objectVersions.stream()
149 .map(o -> o.toBuilder().key(urlDecode(o.key())).build())
150 .collect(Collectors.toList()));
151 }
152
153 private static List<CommonPrefix> decodeCommonPrefixes(List<CommonPrefix> commonPrefixes) {
154 if (commonPrefixes == null) {
155 return null;
156 }
157
158 return Collections.unmodifiableList(commonPrefixes.stream()
159 .map(p -> p.toBuilder().prefix(urlDecode(p.prefix())).build())
160 .collect(Collectors.toList()));
161 }
162
163 private static List<MultipartUpload> decodeMultipartUpload(List<MultipartUpload> multipartUploads) {
164 if (multipartUploads == null) {
165 return null;
166 }
167
168 return Collections.unmodifiableList(multipartUploads.stream()
169 .map(u -> u.toBuilder().key(urlDecode(u.key())).build())
170 .collect(Collectors.toList()));
171 }
172 }
173