@@ -158,9 +158,9 @@ public void handle(final HttpExchange exchange) throws IOException {
158
158
exchange .sendResponseHeaders (RestStatus .NOT_FOUND .getStatus (), -1 );
159
159
} else {
160
160
// CopyPart is UploadPart with an x-amz-copy-source header
161
- final var sourceBlobName = exchange . getRequestHeaders (). get ( "X-amz-copy-source" );
162
- if (sourceBlobName != null ) {
163
- var sourceBlob = blobs .get (sourceBlobName . getFirst () );
161
+ final var copySource = copySourceName ( exchange );
162
+ if (copySource != null ) {
163
+ var sourceBlob = blobs .get (copySource );
164
164
if (sourceBlob == null ) {
165
165
exchange .sendResponseHeaders (RestStatus .NOT_FOUND .getStatus (), -1 );
166
166
} else {
@@ -230,12 +230,10 @@ public void handle(final HttpExchange exchange) throws IOException {
230
230
exchange .sendResponseHeaders ((upload == null ? RestStatus .NOT_FOUND : RestStatus .NO_CONTENT ).getStatus (), -1 );
231
231
232
232
} else if (request .isPutObjectRequest ()) {
233
- // a copy request is a put request with a copy source header
234
- final var copySources = exchange .getRequestHeaders ().get ("X-amz-copy-source" );
235
- if (copySources != null ) {
236
- final var copySource = copySources .getFirst ();
237
- final var prefix = copySource .length () > 0 && copySource .charAt (0 ) == '/' ? "" : "/" ;
238
- var sourceBlob = blobs .get (prefix + copySource );
233
+ // a copy request is a put request with an X-amz-copy-source header
234
+ final var copySource = copySourceName (exchange );
235
+ if (copySource != null ) {
236
+ var sourceBlob = blobs .get (copySource );
239
237
if (sourceBlob == null ) {
240
238
exchange .sendResponseHeaders (RestStatus .NOT_FOUND .getStatus (), -1 );
241
239
} else {
@@ -516,6 +514,21 @@ static List<String> extractPartEtags(BytesReference completeMultipartUploadBody)
516
514
}
517
515
}
518
516
517
+ @ Nullable // if no X-amz-copy-source header present
518
+ private static String copySourceName (final HttpExchange exchange ) {
519
+ final var copySources = exchange .getRequestHeaders ().get ("X-amz-copy-source" );
520
+ if (copySources != null ) {
521
+ if (copySources .size () != 1 ) {
522
+ throw new AssertionError ("multiple X-amz-copy-source headers found: " + copySources );
523
+ }
524
+ final var copySource = copySources .get (0 );
525
+ // SDKv1 uses format /bucket/path/blob whereas SDKv2 omits the leading / so we must add it back in
526
+ return copySource .length () > 0 && copySource .charAt (0 ) == '/' ? copySource : ("/" + copySource );
527
+ } else {
528
+ return null ;
529
+ }
530
+ }
531
+
519
532
private static HttpHeaderParser .Range parsePartRange (final HttpExchange exchange ) {
520
533
final var sourceRangeHeaders = exchange .getRequestHeaders ().get ("X-amz-copy-source-range" );
521
534
if (sourceRangeHeaders == null ) {
0 commit comments