From e37300dd3fdd1bb94aa646b130109259f4cd7af6 Mon Sep 17 00:00:00 2001 From: Timur Alperovich Date: Mon, 24 Jun 2019 15:03:55 -0700 Subject: [PATCH] UploadPartCopy: Fail if improper source range. S3Proxy should check the format of the x-amz-copy-source-range value when handling an UploadPartCopy request. The patch changes the behavior to return an InvalidArgument error along with the matching error description to AWS S3. To match the error format, the S3Exception class is modified to return the actual error message, rather than the String version of the error code. Corresponding tests will be added to ceph/s3-tests. Fixes: #304 --- .../java/org/gaul/s3proxy/S3Exception.java | 2 +- .../java/org/gaul/s3proxy/S3ProxyHandler.java | 41 ++++++++++++------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/gaul/s3proxy/S3Exception.java b/src/main/java/org/gaul/s3proxy/S3Exception.java index 81b3d86..0d4010a 100644 --- a/src/main/java/org/gaul/s3proxy/S3Exception.java +++ b/src/main/java/org/gaul/s3proxy/S3Exception.java @@ -63,7 +63,7 @@ public final class S3Exception extends Exception { @Override public String getMessage() { - StringBuilder builder = new StringBuilder().append(error); + StringBuilder builder = new StringBuilder().append(super.getMessage()); if (!elements.isEmpty()) { builder.append(" ").append(elements); } diff --git a/src/main/java/org/gaul/s3proxy/S3ProxyHandler.java b/src/main/java/org/gaul/s3proxy/S3ProxyHandler.java index 0ebdfc7..2f19a9b 100644 --- a/src/main/java/org/gaul/s3proxy/S3ProxyHandler.java +++ b/src/main/java/org/gaul/s3proxy/S3ProxyHandler.java @@ -2469,20 +2469,33 @@ public class S3ProxyHandler { GetOptions options = new GetOptions(); String range = request.getHeader(AwsHttpHeaders.COPY_SOURCE_RANGE); long expectedSize = -1; - if (range != null && range.startsWith("bytes=") && - // ignore multiple ranges - range.indexOf(',') == -1) { - range = range.substring("bytes=".length()); - String[] ranges = range.split("-", 2); - if (ranges[0].isEmpty()) { - options.tail(Long.parseLong(ranges[1])); - } else if (ranges[1].isEmpty()) { - options.startAt(Long.parseLong(ranges[0])); - } else { - long start = Long.parseLong(ranges[0]); - long end = Long.parseLong(ranges[1]); - expectedSize = end - start + 1; - options.range(start, end); + if (range != null) { + if (!range.startsWith("bytes=") || range.indexOf(',') != -1 || + range.indexOf('-') == -1) { + throw new S3Exception(S3ErrorCode.INVALID_ARGUMENT, + "The x-amz-copy-source-range value must be of the form " + + "bytes=first-last where first and last are the " + + "zero-based offsets of the first and last bytes to copy"); + } + try { + range = range.substring("bytes=".length()); + String[] ranges = range.split("-", 2); + if (ranges[0].isEmpty()) { + options.tail(Long.parseLong(ranges[1])); + } else if (ranges[1].isEmpty()) { + options.startAt(Long.parseLong(ranges[0])); + } else { + long start = Long.parseLong(ranges[0]); + long end = Long.parseLong(ranges[1]); + expectedSize = end - start + 1; + options.range(start, end); + } + } catch (NumberFormatException nfe) { + throw new S3Exception(S3ErrorCode.INVALID_ARGUMENT, + "The x-amz-copy-source-range value must be of the form " + + "bytes=first-last where first and last are the " + + "zero-based offsets of the first and last bytes to copy", + nfe); } }