entry : headerMap.entries()) {
- requestBuilder.header(entry.getKey(), entry.getValue());
+ if (entry.getKey().equals("Content-Type")) {
+ contentType = entry.getValue();
+ }
+
+ if (!entry.getKey().equals("Content-Encoding")) {
+ requestBuilder.header(entry.getKey(), entry.getValue());
+ }
}
}
+ if (contentEncoding != null) {
+ requestBuilder.header("Content-Encoding", contentEncoding);
+ }
+
+ requestBuilder.header("Host", getHostHeader(url));
+ // Disable default gzip compression by okhttp library.
+ requestBuilder.header("Accept-Encoding", "identity");
+ requestBuilder.header("User-Agent", this.userAgent);
+
String sha256Hash = null;
String md5Hash = null;
- boolean chunkedUpload = false;
if (this.accessKey != null && this.secretKey != null) {
- // Handle putobject specially to use chunked upload.
- if (method == Method.PUT && objectName != null && body != null && body instanceof InputStream && length > 0) {
- sha256Hash = "STREAMING-AWS4-HMAC-SHA256-PAYLOAD";
-
- String contentEncoding = "aws-chunked";
- if (headerMap != null) {
- contentEncoding = Stream.concat(Stream.of("aws-chunked"),
- headerMap.get("Content-Encoding").stream()).distinct().filter(encoding -> !encoding.isEmpty())
- .collect(Collectors.joining(","));
- }
- requestBuilder.header("Content-Encoding", contentEncoding);
-
- requestBuilder.header("x-amz-decoded-content-length", Integer.toString(length));
- chunkedUpload = true;
- } else if (url.isHttps()) {
+ if (url.isHttps()) {
// Fix issue #415: No need to compute sha256 if endpoint scheme is HTTPS.
sha256Hash = "UNSIGNED-PAYLOAD";
if (body != null) {
@@ -964,16 +954,9 @@ private Request createRequest(Method method, String bucketName, String objectNam
len = 0;
}
- // Disable default gzip compression by okhttp library.
- requestBuilder.header("Accept-Encoding", "identity");
- if (md5Required) {
- String[] hashes = Digest.sha256Md5Hashes(data, len);
- sha256Hash = hashes[0];
- md5Hash = hashes[1];
- } else {
- // Fix issue #567: Compute SHA256 hash only.
- sha256Hash = Digest.sha256Hash(data, len);
- }
+ String[] hashes = Digest.sha256Md5Hashes(data, len);
+ sha256Hash = hashes[0];
+ md5Hash = hashes[1];
}
} else {
// Fix issue #567: Compute MD5 hash only for anonymous access.
@@ -985,138 +968,46 @@ private Request createRequest(Method method, String bucketName, String objectNam
if (md5Hash != null) {
requestBuilder.header("Content-MD5", md5Hash);
}
- if (this.shouldOmitPortInHostHeader(url)) {
- requestBuilder.header("Host", url.host());
- } else {
- requestBuilder.header("Host", url.host() + ":" + url.port());
- }
- requestBuilder.header("User-Agent", this.userAgent);
+
if (sha256Hash != null) {
requestBuilder.header("x-amz-content-sha256", sha256Hash);
}
- DateTime date = new DateTime();
- requestBuilder.header("x-amz-date", date.toString(DateFormat.AMZ_DATE_FORMAT));
-
- if (chunkedUpload) {
- // Add empty request body for calculating seed signature.
- // The actual request body is properly set below.
- requestBuilder.method(method.toString(), RequestBody.create(null, ""));
- Request request = requestBuilder.build();
- String seedSignature = Signer.getChunkSeedSignature(request, region, secretKey);
- requestBuilder = request.newBuilder();
- ChunkedInputStream cis = new ChunkedInputStream((InputStream) body, length, date, region, this.secretKey,
- seedSignature);
- body = cis;
- length = cis.length();
- }
+ DateTime dateTimeNow = new DateTime();
+ requestBuilder.header("x-amz-date", dateTimeNow.toString(DateFormat.AMZ_DATE_FORMAT));
RequestBody requestBody = null;
if (body != null) {
- requestBody = new HttpRequestBody(contentType, body, length);
+ if (body instanceof RandomAccessFile) {
+ requestBody = new HttpRequestBody((RandomAccessFile) body, length, contentType);
+ } else if (body instanceof BufferedInputStream) {
+ requestBody = new HttpRequestBody((BufferedInputStream) body, length, contentType);
+ } else {
+ requestBody = new HttpRequestBody((byte[]) body, length, contentType);
+ }
}
requestBuilder.method(method.toString(), requestBody);
- return requestBuilder.build();
- }
-
-
- /**
- * Checks whether port should be omitted in Host header.
- *
- *
- * HTTP Spec (rfc2616) defines that port should be omitted in Host header
- * when port and service matches (i.e HTTP -> 80, HTTPS -> 443)
- *
- * @param url Url object
- */
- private boolean shouldOmitPortInHostHeader(HttpUrl url) {
- return (url.scheme().equals("http") && url.port() == 80)
- || (url.scheme().equals("https") && url.port() == 443);
- }
-
-
- /**
- * Executes given request parameters.
- *
- * @param method HTTP method.
- * @param region Amazon S3 region of the bucket.
- * @param bucketName Bucket name.
- * @param objectName Object name in the bucket.
- * @param headerMap Map of HTTP headers for the request.
- * @param queryParamMap Map of HTTP query parameters of the request.
- * @param body HTTP request body.
- * @param length Length of HTTP request body.
- */
- private HttpResponse execute(Method method, String region, String bucketName, String objectName,
- Map headerMap, Map queryParamMap,
- Object body, int length)
- throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
- InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
- return execute(method, region, bucketName, objectName, headerMap, queryParamMap,
- body, length, false);
- }
-
- /**
- * Executes given request parameters.
- *
- * @param method HTTP method.
- * @param region Amazon S3 region of the bucket.
- * @param bucketName Bucket name.
- * @param objectName Object name in the bucket.
- * @param headerMap Map of HTTP headers for the request.
- * @param queryParamMap Map of HTTP query parameters of the request.
- * @param body HTTP request body.
- * @param length Length of HTTP request body.
- * @param md5Required Validates if md5 is required.
- */
- private HttpResponse execute(Method method, String region, String bucketName, String objectName,
- Map headerMap, Map queryParamMap,
- Object body, int length, boolean md5Required)
- throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
- InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
-
- if (headerMap != null) {
- headerMap = normalizeHeaders(headerMap);
- }
-
- Multimap queryParamMultiMap = null;
- if (queryParamMap != null) {
- queryParamMultiMap = Multimaps.forMap(queryParamMap);
- }
-
- Multimap headerMultiMap = null;
- if (headerMap != null) {
- headerMultiMap = Multimaps.forMap(headerMap);
- }
-
- return executeReq(method, region, bucketName, objectName, headerMultiMap, queryParamMultiMap,
- body, length, md5Required);
+ return requestBuilder.build();
}
- private HttpResponse executeReq(Method method, String region, String bucketName, String objectName,
+ private HttpResponse execute(Method method, String bucketName, String objectName, String region,
Multimap headerMap, Multimap queryParamMap,
- Object body, int length, boolean md5Required)
- throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
- InvalidKeyException, XmlPullParserException, ErrorResponseException,
+ Object body, int length)
+ throws InvalidBucketNameException, InvalidArgumentException, NoSuchAlgorithmException, InsufficientDataException,
+ IOException, InvalidKeyException, XmlPullParserException, ErrorResponseException,
InternalException, InvalidResponseException {
- String contentType = null;
- if (headerMap != null && headerMap.get("Content-Type") != null) {
- contentType = String.join(" ", headerMap.get("Content-Type"));
- }
+ boolean traceRequestBody = false;
if (body != null && !(body instanceof InputStream || body instanceof RandomAccessFile || body instanceof byte[])) {
byte[] bytes = body.toString().getBytes(StandardCharsets.UTF_8);
body = bytes;
length = bytes.length;
+ traceRequestBody = true;
}
- Request request = createRequest(method, bucketName, objectName, region,
- headerMap, queryParamMap,
- contentType, body, length, md5Required);
-
+ HttpUrl url = buildUrl(method, bucketName, objectName, region, queryParamMap);
+ Request request = createRequest(url, method, headerMap, body, length);
if (this.accessKey != null && this.secretKey != null) {
request = Signer.signV4(request, region, accessKey, secretKey);
}
@@ -1133,6 +1024,10 @@ private HttpResponse executeReq(Method method, String region, String bucketName,
.replaceAll("Signature=([0-9a-f]+)", "Signature=*REDACTED*")
.replaceAll("Credential=([^/]+)", "Credential=*REDACTED*");
this.traceStream.println(headers);
+ if (traceRequestBody) {
+ this.traceStream.println();
+ this.traceStream.println(new String((byte[]) body, StandardCharsets.UTF_8));
+ }
}
Response response = this.httpClient.newCall(request).execute();
@@ -1151,36 +1046,29 @@ private HttpResponse executeReq(Method method, String region, String bucketName,
return new HttpResponse(header, response);
}
- ErrorResponse errorResponse = null;
-
- // HEAD returns no body, and fails on parseXml
- if (!method.equals(Method.HEAD)) {
- Scanner scanner = new Scanner(response.body().charStream());
- try {
- scanner.useDelimiter("\\A");
- String errorXml = "";
+ // Error in case of Non-XML response from server for non-HEAD requests.
+ if (!"application/xml".equals(response.headers().get("content-type")) && !method.equals(Method.HEAD)) {
+ throw new InvalidResponseException();
+ }
- // read entire body stream to string.
- if (scanner.hasNext()) {
- errorXml = scanner.next();
- }
-
- // Error in case of Non-XML response from server
- if (!("application/xml".equals(response.headers().get("content-type")))) {
- throw new InvalidResponseException();
- }
- errorResponse = new ErrorResponse(new StringReader(errorXml));
- if (this.traceStream != null) {
- this.traceStream.println(errorXml);
- }
+ String errorXml = null;
+ try {
+ errorXml = new String(response.body().bytes(), StandardCharsets.UTF_8);
+ } finally {
+ response.close();
+ }
- } finally {
- response.body().close();
- scanner.close();
- }
+ ErrorResponse errorResponse = null;
+ if (!"".equals(errorXml)) {
+ errorResponse = new ErrorResponse(new StringReader(errorXml));
+ } else if (!method.equals(Method.HEAD)) {
+ throw new InvalidResponseException();
}
if (this.traceStream != null) {
+ if (!("".equals(errorXml) && method.equals(Method.HEAD))) {
+ this.traceStream.println(errorXml);
+ }
this.traceStream.println(END_HTTP);
}
@@ -1191,7 +1079,13 @@ private HttpResponse executeReq(Method method, String region, String bucketName,
ec = ErrorCode.REDIRECT;
break;
case 400:
- ec = ErrorCode.INVALID_URI;
+ // HEAD bucket with wrong region gives 400 without body.
+ if (method.equals(Method.HEAD) && bucketName != null && objectName == null
+ && BucketRegionCache.INSTANCE.exists(bucketName)) {
+ ec = ErrorCode.RETRY_HEAD_BUCKET;
+ } else {
+ ec = ErrorCode.INVALID_URI;
+ }
break;
case 404:
if (objectName != null) {
@@ -1226,29 +1120,59 @@ private HttpResponse executeReq(Method method, String region, String bucketName,
}
// invalidate region cache if needed
- if (errorResponse.errorCode() == ErrorCode.NO_SUCH_BUCKET) {
+ if (errorResponse.errorCode() == ErrorCode.NO_SUCH_BUCKET
+ || errorResponse.errorCode() == ErrorCode.RETRY_HEAD_BUCKET) {
BucketRegionCache.INSTANCE.remove(bucketName);
// TODO: handle for other cases as well
- // observation: on HEAD of a bucket with wrong region gives 400 without body
}
throw new ErrorResponseException(errorResponse, response);
}
+ private HttpResponse execute(Method method, String bucketName, String objectName, String region,
+ Map headerMap, Map queryParamMap,
+ Object body, int length)
+ throws InvalidBucketNameException, InvalidArgumentException, NoSuchAlgorithmException, InsufficientDataException,
+ IOException, InvalidKeyException, XmlPullParserException, ErrorResponseException,
+ InternalException, InvalidResponseException {
+ Multimap headerMultiMap = null;
+ if (headerMap != null) {
+ headerMultiMap = Multimaps.forMap(normalizeHeaders(headerMap));
+ }
+
+ Multimap queryParamMultiMap = null;
+ if (queryParamMap != null) {
+ queryParamMultiMap = Multimaps.forMap(queryParamMap);
+ }
+
+ return execute(method, bucketName, objectName, region, headerMultiMap, queryParamMultiMap, body, length);
+ }
+
+ /**
+ * Returns text of given XML element.
+ *
+ * @throws XmlPullParserException upon parsing response xml
+ */
+ private String getText(XmlPullParser xpp) throws XmlPullParserException {
+ if (xpp.getEventType() == XmlPullParser.TEXT) {
+ return xpp.getText();
+ }
+ return null;
+ }
+
/**
* Updates Region cache for given bucket.
*/
private void updateRegionCache(String bucketName)
- throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
- InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
+ throws InvalidBucketNameException, InvalidArgumentException, NoSuchAlgorithmException, InsufficientDataException,
+ IOException, InvalidKeyException, XmlPullParserException, ErrorResponseException,
InternalException, InvalidResponseException {
if (bucketName != null && this.accessKey != null && this.secretKey != null
&& !BucketRegionCache.INSTANCE.exists(bucketName)) {
Map queryParamMap = new HashMap<>();
queryParamMap.put("location", null);
- HttpResponse response = execute(Method.GET, US_EAST_1, bucketName, null,
- null, queryParamMap, null, 0);
+ HttpResponse response = execute(Method.GET, bucketName, null, US_EAST_1, null, queryParamMap, null, 0);
// existing XmlEntity does not work, so fallback to regular parsing.
XmlPullParser xpp = xmlPullParserFactory.newPullParser();
@@ -1287,9 +1211,10 @@ private void updateRegionCache(String bucketName)
* Computes region of a given bucket name. If set, this.region is considered. Otherwise,
* resort to the server location API.
*/
- private String getRegion(String bucketName) throws InvalidBucketNameException, NoSuchAlgorithmException,
- InsufficientDataException, IOException, InvalidKeyException, NoResponseException, XmlPullParserException,
- ErrorResponseException, InternalException, InvalidResponseException {
+ private String getRegion(String bucketName)
+ throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, InvalidArgumentException,
+ IOException, InvalidKeyException, XmlPullParserException, ErrorResponseException, InternalException,
+ InvalidResponseException {
String region;
if (this.region == null || "".equals(this.region)) {
updateRegionCache(bucketName);
@@ -1300,271 +1225,91 @@ private String getRegion(String bucketName) throws InvalidBucketNameException, N
return region;
}
- /**
- * Returns text of given XML element.
- *
- * @throws XmlPullParserException upon parsing response xml
- */
- private String getText(XmlPullParser xpp) throws XmlPullParserException {
- if (xpp.getEventType() == XmlPullParser.TEXT) {
- return xpp.getText();
- }
- return null;
- }
-
- private void checkReadRequestSse(ServerSideEncryption sse) throws InvalidArgumentException {
- if (sse == null) {
- return;
- }
-
- if (sse.type() != ServerSideEncryption.Type.SSE_C) {
- throw new InvalidArgumentException("only SSE_C is supported for all read requests.");
- }
-
- if (sse.type().requiresTls() && !this.baseUrl.isHttps()) {
- throw new InvalidArgumentException(sse.type().name()
- + "operations must be performed over a secure connection.");
- }
- }
-
- private void checkWriteRequestSse(ServerSideEncryption sse) throws InvalidArgumentException {
- if (sse == null) {
- return;
- }
-
- if (sse.type().requiresTls() && !this.baseUrl.isHttps()) {
- throw new InvalidArgumentException(sse.type().name()
- + " operations must be performed over a secure connection.");
- }
- }
-
- /**
- * Executes GET method for given request parameters.
- *
- * @param bucketName Bucket name.
- * @param objectName Object name in the bucket.
- * @param headerMap Map of HTTP headers for the request.
- * @param queryParamMap Map of HTTP query parameters of the request.
- */
private HttpResponse executeGet(String bucketName, String objectName, Map headerMap,
Map queryParamMap)
- throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
- InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
- return execute(Method.GET, getRegion(bucketName), bucketName, objectName, headerMap, queryParamMap, null, 0);
- }
-
-
- /**
- * Executes HEAD method for given request parameters.
- *
- * @param bucketName Bucket name.
- * @param objectName Object name in the bucket.
- */
- private HttpResponse executeHead(String bucketName, String objectName)
- throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
- InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
- HttpResponse response = execute(Method.HEAD, getRegion(bucketName), bucketName, objectName, null,
- null, null, 0);
- response.body().close();
- return response;
- }
-
- /**
- * Executes HEAD method for given request parameters.
- *
- * @param bucketName Bucket name.
- * @param objectName Object name in the bucket.
- * @param headerMap Map of header parameters of the request.
- */
- private HttpResponse executeHead(String bucketName, String objectName, Map headerMap)
- throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
- InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
-
- HttpResponse response = execute(Method.HEAD, getRegion(bucketName), bucketName, objectName, headerMap,
- null, null, 0);
- response.body().close();
- return response;
- }
-
- /**
- * Executes DELETE method for given request parameters.
- *
- * @param bucketName Bucket name.
- * @param objectName Object name in the bucket.
- * @param queryParamMap Map of HTTP query parameters of the request.
- */
- private HttpResponse executeDelete(String bucketName, String objectName, Map queryParamMap)
- throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
- InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
- HttpResponse response = execute(Method.DELETE, getRegion(bucketName), bucketName, objectName, null,
- queryParamMap, null, 0);
- response.body().close();
- return response;
- }
-
-
- /**
- * Executes POST method for given request parameters.
- *
- * @param bucketName Bucket name.
- * @param objectName Object name in the bucket.
- * @param headerMap Map of HTTP headers for the request.
- * @param queryParamMap Map of HTTP query parameters of the request.
- * @param data HTTP request body data.
- */
- private HttpResponse executePost(String bucketName, String objectName, Map headerMap,
- Map queryParamMap, Object data)
- throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
- InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
+ throws InvalidBucketNameException, InvalidArgumentException, NoSuchAlgorithmException, InsufficientDataException,
+ IOException, InvalidKeyException, XmlPullParserException, ErrorResponseException,
InternalException, InvalidResponseException {
- return execute(Method.POST, getRegion(bucketName), bucketName, objectName, headerMap,
- queryParamMap, data, 0);
+ return execute(Method.GET, bucketName, objectName, getRegion(bucketName), headerMap, queryParamMap, null, 0);
}
- /**
- * Executes POST method for given request parameters.
- *
- * @param bucketName Bucket name.
- * @param objectName Object name in the bucket.
- * @param headerMap Map of HTTP headers for the request.
- * @param queryParamMap Map of HTTP query parameters of the request.
- * @param data HTTP request body data.
- * @param md5Required Is MD5 calculations required.
- */
- private HttpResponse executePost(String bucketName, String objectName, Map headerMap,
- Map queryParamMap, Object data, boolean md5Required)
- throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
- InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
+ private HttpResponse executeGet(String bucketName, String objectName, Multimap headerMap,
+ Multimap queryParamMap)
+ throws InvalidBucketNameException, InvalidArgumentException, NoSuchAlgorithmException, InsufficientDataException,
+ IOException, InvalidKeyException, XmlPullParserException, ErrorResponseException,
InternalException, InvalidResponseException {
- return execute(Method.POST, getRegion(bucketName), bucketName, objectName, headerMap,
- queryParamMap, data, 0, md5Required);
+ return execute(Method.GET, bucketName, objectName, getRegion(bucketName), null, queryParamMap, null, 0);
}
+ private HttpResponse executeHead(String bucketName, String objectName, Map headerMap,
+ Map queryParamMap)
+ throws InvalidBucketNameException, InvalidArgumentException, NoSuchAlgorithmException, InsufficientDataException,
+ IOException, InvalidKeyException, XmlPullParserException, ErrorResponseException,
+ InternalException, InvalidResponseException {
+ HttpResponse response = execute(Method.HEAD, bucketName, objectName, getRegion(bucketName),
+ headerMap, queryParamMap, null, 0);
+ response.body().close();
+ return response;
+ }
- private Map normalizeHeaders(Map headerMap) {
- Map normHeaderMap = new HashMap();
- for (Map.Entry entry : headerMap.entrySet()) {
- String key = entry.getKey();
- String value = entry.getValue();
- String keyLowerCased = key.toLowerCase(Locale.US);
- if (amzHeaders.contains(keyLowerCased)) {
- key = "x-amz-" + key;
- } else if (!standardHeaders.contains(keyLowerCased)
- && !keyLowerCased.startsWith("x-amz-")) {
- key = "x-amz-meta-" + key;
+ private HttpResponse executeHead(String bucketName, String objectName)
+ throws InvalidBucketNameException, InvalidArgumentException, NoSuchAlgorithmException, InsufficientDataException,
+ IOException, InvalidKeyException, XmlPullParserException, ErrorResponseException,
+ InternalException, InvalidResponseException {
+ try {
+ return executeHead(bucketName, objectName, null, null);
+ } catch (ErrorResponseException e) {
+ if (e.errorResponse().errorCode() != ErrorCode.RETRY_HEAD_BUCKET) {
+ throw e;
}
- normHeaderMap.put(key, value);
}
- return normHeaderMap;
+
+ // Retry once for RETRY_HEAD_BUCKET error.
+ return executeHead(bucketName, objectName, null, null);
}
- /**
- * Executes PUT method for given request parameters.
- *
- * @param bucketName Bucket name.
- * @param objectName Object name in the bucket.
- * @param headerMap Map of HTTP headers for the request.
- * @param queryParamMap Map of HTTP query parameters of the request.
- * @param region Amazon S3 region of the bucket.
- * @param data HTTP request body data.
- * @param length Length of HTTP request body data.
- */
- private HttpResponse executePut(String bucketName, String objectName, Map headerMap,
- Map queryParamMap, String region, Object data, int length)
- throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
- InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
+ private HttpResponse executeHead(String bucketName, String objectName, Map headerMap)
+ throws InvalidBucketNameException, InvalidArgumentException, NoSuchAlgorithmException, InsufficientDataException,
+ IOException, InvalidKeyException, XmlPullParserException, ErrorResponseException,
InternalException, InvalidResponseException {
- HttpResponse response = execute(Method.PUT, region, bucketName, objectName,
- headerMap, queryParamMap,
- data, length);
- return response;
+ return executeHead(bucketName, objectName, headerMap, null);
}
- /**
- * Executes PUT method for given request parameters.
- *
- * @param bucketName Bucket name.
- * @param objectName Object name in the bucket.
- * @param headerMap Map of HTTP headers for the request.
- * @param queryParamMap Map of HTTP query parameters of the request.
- * @param region Amazon S3 region of the bucket.
- * @param data HTTP request body data.
- * @param length Length of HTTP request body data.
- * @param md5Required Is MD5 calculations required.
- */
- private HttpResponse executePut(String bucketName, String objectName, Map headerMap,
- Map queryParamMap, String region, Object data, int length, boolean md5Required)
- throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
- InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
+ private HttpResponse executeDelete(String bucketName, String objectName, Map queryParamMap)
+ throws InvalidBucketNameException, InvalidArgumentException, NoSuchAlgorithmException, InsufficientDataException,
+ IOException, InvalidKeyException, XmlPullParserException, ErrorResponseException,
InternalException, InvalidResponseException {
- HttpResponse response = execute(Method.PUT, region, bucketName, objectName,
- headerMap, queryParamMap,
- data, length, md5Required);
+ HttpResponse response = execute(Method.DELETE, bucketName, objectName, getRegion(bucketName), null,
+ queryParamMap, null, 0);
+ response.body().close();
return response;
}
+ private HttpResponse executePost(String bucketName, String objectName, Map headerMap,
+ Map queryParamMap, Object data)
+ throws InvalidBucketNameException, InvalidArgumentException, NoSuchAlgorithmException, InsufficientDataException,
+ IOException, InvalidKeyException, XmlPullParserException, ErrorResponseException,
+ InternalException, InvalidResponseException {
+ return execute(Method.POST, bucketName, objectName, getRegion(bucketName), headerMap,
+ queryParamMap, data, 0);
+ }
- /**
- * Executes PUT method for given request parameters.
- *
- * @param bucketName Bucket name.
- * @param objectName Object name in the bucket.
- * @param headerMap Map of HTTP headers for the request.
- * @param queryParamMap Map of HTTP query parameters of the request.
- * @param data HTTP request body data.
- * @param length Length of HTTP request body data.
- */
- private HttpResponse executePut(String bucketName, String objectName, Map headerMap,
+ private HttpResponse executePut(String bucketName, String objectName, String region, Map headerMap,
Map queryParamMap, Object data, int length)
- throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
- InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
+ throws InvalidBucketNameException, InvalidArgumentException, NoSuchAlgorithmException, InsufficientDataException,
+ IOException, InvalidKeyException, XmlPullParserException, ErrorResponseException,
InternalException, InvalidResponseException {
- return executePut(bucketName, objectName, headerMap, queryParamMap, getRegion(bucketName), data, length, false);
+ return execute(Method.PUT, bucketName, objectName, region, headerMap, queryParamMap, data, length);
}
- /**
- * Executes PUT method for given request parameters.
- *
- * @param bucketName Bucket name.
- * @param objectName Object name in the bucket.
- * @param headerMap Map of HTTP headers for the request.
- * @param queryParamMap Map of HTTP query parameters of the request.
- * @param data HTTP request body data.
- * @param length Length of HTTP request body data.
- * @param md5Required Is MD5 calculations required.
- */
private HttpResponse executePut(String bucketName, String objectName, Map headerMap,
- Map queryParamMap, Object data, int length, boolean md5Required)
- throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
- InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
+ Map queryParamMap, Object data, int length)
+ throws InvalidBucketNameException, InvalidArgumentException, NoSuchAlgorithmException, InsufficientDataException,
+ IOException, InvalidKeyException, XmlPullParserException, ErrorResponseException,
InternalException, InvalidResponseException {
- return executePut(bucketName, objectName, headerMap, queryParamMap,
- getRegion(bucketName), data, length, md5Required);
- }
-
-
- /**
- * Sets application's name/version to user agent. For more information about user agent
- * refer #rfc2616.
- *
- * @param name Your application name.
- * @param version Your application version.
- */
- @SuppressWarnings("unused")
- public void setAppInfo(String name, String version) {
- if (name == null || version == null) {
- // nothing to do
- return;
- }
-
- this.userAgent = DEFAULT_USER_AGENT + " " + name.trim() + "/" + version.trim();
+ return executePut(bucketName, objectName, getRegion(bucketName), headerMap, queryParamMap, data, length);
}
-
/**
* Returns meta data information of given object in given bucket.
*
@@ -1678,10 +1423,8 @@ public ObjectStat statObject(String bucketName, String objectName, ServerSideEnc
public String getObjectUrl(String bucketName, String objectName)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
- Request request = createRequest(Method.GET, bucketName, objectName, getRegion(bucketName),
- null, null, null, null, 0, false);
- HttpUrl url = request.url();
+ InternalException, InvalidResponseException, InvalidArgumentException {
+ HttpUrl url = buildUrl(Method.GET, bucketName, objectName, getRegion(bucketName), null);
return url.toString();
}
@@ -2691,7 +2434,7 @@ private String uploadPartCopy(String bucketName, String objectName, String uploa
Map headerMap)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
+ InternalException, InvalidResponseException, InvalidArgumentException {
Map queryParamMap = new HashMap<>();
queryParamMap.put("partNumber", Integer.toString(partNumber));
queryParamMap.put("uploadId", uploadId);
@@ -2741,7 +2484,7 @@ public String getPresignedObjectUrl(Method method, String bucketName, String obj
Map reqParams)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidExpiresRangeException, InvalidResponseException {
+ InternalException, InvalidExpiresRangeException, InvalidResponseException, InvalidArgumentException {
// Validate input.
if (expires < 1 || expires > DEFAULT_EXPIRY_TIME) {
throw new InvalidExpiresRangeException(expires, "expires must be in range of 1 to " + DEFAULT_EXPIRY_TIME);
@@ -2761,8 +2504,9 @@ public String getPresignedObjectUrl(Method method, String bucketName, String obj
}
String region = getRegion(bucketName);
- Request request = createRequest(method, bucketName, objectName, region, null, queryParamMap, null, body, 0, false);
- HttpUrl url = Signer.presignV4(request, region, accessKey, secretKey, expires);
+ HttpUrl url = buildUrl(method, bucketName, objectName, region, queryParamMap);
+ Request request = createRequest(url, method, null, body, 0);
+ url = Signer.presignV4(request, region, accessKey, secretKey, expires);
return url.toString();
}
@@ -2800,7 +2544,7 @@ public String presignedGetObject(String bucketName, String objectName, Integer e
Map reqParams)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidExpiresRangeException, InvalidResponseException {
+ InternalException, InvalidExpiresRangeException, InvalidResponseException, InvalidArgumentException {
return getPresignedObjectUrl(Method.GET, bucketName, objectName, expires, reqParams);
}
@@ -2835,7 +2579,7 @@ public String presignedGetObject(String bucketName, String objectName, Integer e
public String presignedGetObject(String bucketName, String objectName, Integer expires)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidExpiresRangeException, InvalidResponseException {
+ InternalException, InvalidExpiresRangeException, InvalidResponseException, InvalidArgumentException {
return presignedGetObject(bucketName, objectName, expires, null);
}
@@ -2871,7 +2615,7 @@ public String presignedGetObject(String bucketName, String objectName, Integer e
public String presignedGetObject(String bucketName, String objectName)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidExpiresRangeException, InvalidResponseException {
+ InternalException, InvalidExpiresRangeException, InvalidResponseException, InvalidArgumentException {
return presignedGetObject(bucketName, objectName, DEFAULT_EXPIRY_TIME, null);
}
@@ -2907,7 +2651,7 @@ public String presignedGetObject(String bucketName, String objectName)
public String presignedPutObject(String bucketName, String objectName, Integer expires)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidExpiresRangeException, InvalidResponseException {
+ InternalException, InvalidExpiresRangeException, InvalidResponseException, InvalidArgumentException {
return getPresignedObjectUrl(Method.PUT, bucketName, objectName, expires, null);
}
@@ -2943,7 +2687,7 @@ public String presignedPutObject(String bucketName, String objectName, Integer e
public String presignedPutObject(String bucketName, String objectName)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidExpiresRangeException, InvalidResponseException {
+ InternalException, InvalidExpiresRangeException, InvalidResponseException, InvalidArgumentException {
return presignedPutObject(bucketName, objectName, DEFAULT_EXPIRY_TIME);
}
@@ -3032,24 +2776,18 @@ public void removeObject(String bucketName, String objectName)
private List removeObject(String bucketName, List objectList)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
+ InternalException, InvalidResponseException, InvalidArgumentException {
Map queryParamMap = new HashMap<>();
queryParamMap.put("delete", "");
DeleteRequest request = new DeleteRequest(objectList);
- HttpResponse response = executePost(bucketName, null, null, queryParamMap, request, true);
+ HttpResponse response = executePost(bucketName, null, null, queryParamMap, request);
String bodyContent = "";
- // Use scanner to read entire body stream to string.
- Scanner scanner = new Scanner(response.body().charStream());
try {
- scanner.useDelimiter("\\A");
- if (scanner.hasNext()) {
- bodyContent = scanner.next();
- }
+ bodyContent = new String(response.body().bytes(), StandardCharsets.UTF_8);
} finally {
response.body().close();
- scanner.close();
}
List errorList = null;
@@ -3116,7 +2854,7 @@ private synchronized void populate() {
}
} catch (InvalidBucketNameException | NoSuchAlgorithmException | InsufficientDataException | IOException
| InvalidKeyException | NoResponseException | XmlPullParserException | ErrorResponseException
- | InternalException | InvalidResponseException e) {
+ | InternalException | InvalidResponseException | InvalidArgumentException e) {
this.error = new Result<>(null, e);
} finally {
if (errorList != null) {
@@ -3312,7 +3050,7 @@ private synchronized void populate() {
this.listBucketResult = listObjectsV2(bucketName, continuationToken, prefix, delimiter);
} catch (InvalidBucketNameException | NoSuchAlgorithmException | InsufficientDataException | IOException
| InvalidKeyException | NoResponseException | XmlPullParserException | ErrorResponseException
- | InternalException | InvalidResponseException e) {
+ | InternalException | InvalidResponseException | InvalidArgumentException e) {
this.error = new Result<>(null, e);
} finally {
if (this.listBucketResult != null) {
@@ -3419,7 +3157,7 @@ public void remove() {
private ListBucketResult listObjectsV2(String bucketName, String continuationToken, String prefix, String delimiter)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
+ InternalException, InvalidResponseException, InvalidArgumentException {
Map queryParamMap = new HashMap<>();
queryParamMap.put("list-type", "2");
@@ -3483,7 +3221,7 @@ private synchronized void populate() {
this.listBucketResult = listObjectsV1(bucketName, marker, prefix, delimiter);
} catch (InvalidBucketNameException | NoSuchAlgorithmException | InsufficientDataException | IOException
| InvalidKeyException | NoResponseException | XmlPullParserException | ErrorResponseException
- | InternalException | InvalidResponseException e) {
+ | InternalException | InvalidResponseException | InvalidArgumentException e) {
this.error = new Result<>(null, e);
} finally {
if (this.listBucketResult != null) {
@@ -3591,7 +3329,7 @@ public void remove() {
private ListBucketResultV1 listObjectsV1(String bucketName, String marker, String prefix, String delimiter)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
+ InternalException, InvalidResponseException, InvalidArgumentException {
Map queryParamMap = new HashMap<>();
if (marker != null) {
@@ -3646,8 +3384,8 @@ private ListBucketResultV1 listObjectsV1(String bucketName, String marker, Strin
public List listBuckets()
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
- HttpResponse response = executeGet(null, null, null, null);
+ InternalException, InvalidResponseException, InvalidArgumentException {
+ HttpResponse response = executeGet(null, null, null, (Multimap) null);
ListAllMyBucketsResult result = new ListAllMyBucketsResult();
result.parseXml(response.body().charStream());
response.body().close();
@@ -3687,7 +3425,7 @@ public List listBuckets()
public boolean bucketExists(String bucketName)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
+ InternalException, InvalidResponseException, InvalidArgumentException {
try {
executeHead(bucketName, null);
return true;
@@ -3725,7 +3463,7 @@ public boolean bucketExists(String bucketName)
public void makeBucket(String bucketName)
throws InvalidBucketNameException, RegionConflictException, NoSuchAlgorithmException, InsufficientDataException,
IOException, InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
+ InternalException, InvalidResponseException, InvalidArgumentException {
this.makeBucket(bucketName, null, false);
}
@@ -3759,7 +3497,7 @@ public void makeBucket(String bucketName)
public void makeBucket(String bucketName, String region)
throws InvalidBucketNameException, RegionConflictException, NoSuchAlgorithmException, InsufficientDataException,
IOException, InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
+ InternalException, InvalidResponseException, InvalidArgumentException {
this.makeBucket(bucketName, region, false);
}
@@ -3794,7 +3532,7 @@ public void makeBucket(String bucketName, String region)
public void makeBucket(String bucketName, String region, boolean objectLock)
throws InvalidBucketNameException, RegionConflictException, NoSuchAlgorithmException, InsufficientDataException,
IOException, InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
+ InternalException, InvalidResponseException, InvalidArgumentException {
// If region param is not provided, set it with the one provided by constructor
if (region == null) {
region = this.region;
@@ -3820,7 +3558,7 @@ public void makeBucket(String bucketName, String region, boolean objectLock)
headerMap.put("x-amz-bucket-object-lock-enabled", "true");
}
- HttpResponse response = executePut(bucketName, null, headerMap, null, region, configString, 0);
+ HttpResponse response = executePut(bucketName, null, region, headerMap, null, configString, 0);
response.body().close();
}
@@ -3851,7 +3589,7 @@ public void makeBucket(String bucketName, String region, boolean objectLock)
public void enableVersioning(String bucketName)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException,
IOException, InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
+ InternalException, InvalidResponseException, InvalidArgumentException {
Map queryParamMap = new HashMap<>();
queryParamMap.put("versioning", "");
String config = ""
@@ -3887,7 +3625,7 @@ public void enableVersioning(String bucketName)
public void disableVersioning(String bucketName)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException,
IOException, InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
+ InternalException, InvalidResponseException, InvalidArgumentException {
Map queryParamMap = new HashMap<>();
queryParamMap.put("versioning", "");
String config = ""
@@ -3924,7 +3662,7 @@ public void disableVersioning(String bucketName)
public void setDefaultRetention(String bucketName, ObjectLockConfiguration config)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
+ InternalException, InvalidResponseException, InvalidArgumentException {
Map queryParamMap = new HashMap<>();
queryParamMap.put("object-lock", "");
@@ -3958,7 +3696,7 @@ public void setDefaultRetention(String bucketName, ObjectLockConfiguration confi
public ObjectLockConfiguration getDefaultRetention(String bucketName)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
+ InternalException, InvalidResponseException, InvalidArgumentException {
Map queryParamMap = new HashMap<>();
queryParamMap.put("object-lock", "");
@@ -4061,7 +3799,7 @@ public void setObjectRetention(String bucketName, String objectName, String vers
public ObjectRetentionConfiguration getObjectRetention(String bucketName, String objectName, String versionId)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
+ InternalException, InvalidResponseException, InvalidArgumentException {
Map queryParamMap = new HashMap<>();
queryParamMap.put("retention", "");
@@ -4110,7 +3848,7 @@ public ObjectRetentionConfiguration getObjectRetention(String bucketName, String
public void enableObjectLegalHold(String bucketName, String objectName, String versionId)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
+ InternalException, InvalidResponseException, InvalidArgumentException {
Map queryParamMap = new HashMap<>();
queryParamMap.put("legal-hold", "");
@@ -4155,7 +3893,7 @@ public void enableObjectLegalHold(String bucketName, String objectName, String v
public void disableObjectLegalHold(String bucketName, String objectName, String versionId)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
+ InternalException, InvalidResponseException, InvalidArgumentException {
Map queryParamMap = new HashMap<>();
queryParamMap.put("legal-hold", "");
@@ -4202,7 +3940,7 @@ public void disableObjectLegalHold(String bucketName, String objectName, String
public boolean isObjectLegalHoldEnabled(String bucketName, String objectName, String versionId)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
+ InternalException, InvalidResponseException, InvalidArgumentException {
Map queryParamMap = new HashMap<>();
queryParamMap.put("legal-hold", "");
@@ -4254,7 +3992,7 @@ public boolean isObjectLegalHoldEnabled(String bucketName, String objectName, St
public void removeBucket(String bucketName)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
+ InternalException, InvalidResponseException, InvalidArgumentException {
executeDelete(bucketName, null, null);
}
@@ -4379,7 +4117,7 @@ public void putObject(String bucketName, String objectName, String fileName, Str
public void putObject(String bucketName, String objectName, String fileName, ServerSideEncryption sse)
throws InvalidBucketNameException, NoSuchAlgorithmException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidArgumentException, InsufficientDataException,InvalidResponseException {
+ InternalException, InvalidArgumentException, InsufficientDataException, InvalidResponseException {
putObject(bucketName, objectName, fileName, null, null, sse, null);
}
@@ -4423,9 +4161,9 @@ public void putObject(String bucketName, String objectName, String fileName, Ser
@Deprecated
public void putObject(String bucketName, String objectName, String fileName, Long size,
Map headerMap, ServerSideEncryption sse, String contentType)
- throws InvalidBucketNameException, NoSuchAlgorithmException, IOException,
- InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidArgumentException, InsufficientDataException, InvalidResponseException {
+ throws InvalidBucketNameException, NoSuchAlgorithmException, IOException, InvalidKeyException, NoResponseException,
+ XmlPullParserException, ErrorResponseException, InternalException, InvalidArgumentException,
+ InsufficientDataException, InvalidResponseException {
if (fileName == null || "".equals(fileName)) {
throw new InvalidArgumentException("empty file name is not allowed");
}
@@ -5176,7 +4914,7 @@ private String putObject(String bucketName, String objectName, Object data, int
Map headerMap, String uploadId, int partNumber)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
+ InternalException, InvalidResponseException, InvalidArgumentException {
HttpResponse response = null;
Map queryParamMap = null;
@@ -5415,7 +5153,7 @@ public String getBucketPolicy(String bucketName)
throws InvalidBucketNameException, NoSuchAlgorithmException,
InsufficientDataException, IOException, InvalidKeyException, NoResponseException,
XmlPullParserException, ErrorResponseException, InternalException, BucketPolicyTooLargeException,
- InvalidResponseException {
+ InvalidResponseException, InvalidArgumentException {
Map queryParamMap = new HashMap<>();
queryParamMap.put("policy", "");
@@ -5503,9 +5241,9 @@ public String getBucketPolicy(String bucketName)
* @throws InvalidResponseException upon a non-xml response from server
*/
public void setBucketPolicy(String bucketName, String policy)
- throws InvalidBucketNameException, NoSuchAlgorithmException,
- InsufficientDataException, IOException, InvalidKeyException, NoResponseException,
- XmlPullParserException, ErrorResponseException, InternalException, InvalidResponseException {
+ throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
+ InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
+ InternalException, InvalidResponseException, InvalidArgumentException {
Map headerMap = new HashMap<>();
headerMap.put("Content-Type", "application/json");
@@ -5542,18 +5280,16 @@ public void setBucketPolicy(String bucketName, String policy)
* @throws InvalidResponseException upon a non-xml response from server
*/
public void setBucketLifeCycle(String bucketName, String lifeCycle)
- throws InvalidBucketNameException, NoSuchAlgorithmException,
- InsufficientDataException, IOException, InvalidKeyException, NoResponseException,
- XmlPullParserException, ErrorResponseException, InternalException,InvalidArgumentException,
- InvalidResponseException {
+ throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
+ InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
+ InternalException, InvalidArgumentException, InvalidResponseException {
if ((lifeCycle == null) || "".equals(lifeCycle)) {
throw new InvalidArgumentException("life cycle cannot be empty");
}
- Map headerMap = new HashMap<>();
- headerMap.put("Content-Length", Integer.toString(lifeCycle.length()));
+
Map queryParamMap = new HashMap<>();
queryParamMap.put("lifecycle", "");
- HttpResponse response = executePut(bucketName, null, headerMap, queryParamMap, lifeCycle, 0, true);
+ HttpResponse response = executePut(bucketName, null, null, queryParamMap, lifeCycle, 0);
response.body().close();
}
@@ -5578,12 +5314,12 @@ public void setBucketLifeCycle(String bucketName, String lifeCycle)
* @throws InvalidResponseException upon a non-xml response from server
*/
public void deleteBucketLifeCycle(String bucketName)
- throws InvalidBucketNameException, NoSuchAlgorithmException,
- InsufficientDataException, IOException, InvalidKeyException, NoResponseException,
- XmlPullParserException, ErrorResponseException, InternalException, InvalidResponseException {
+ throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
+ InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
+ InternalException, InvalidResponseException, InvalidArgumentException {
Map queryParamMap = new HashMap<>();
queryParamMap.put("lifecycle", "");
- HttpResponse response = executeDelete(bucketName, "", queryParamMap);
+ HttpResponse response = executeDelete(bucketName, "", queryParamMap);
response.body().close();
}
@@ -5609,34 +5345,26 @@ public void deleteBucketLifeCycle(String bucketName)
*
*/
public String getBucketLifeCycle(String bucketName)
- throws InvalidBucketNameException, NoSuchAlgorithmException,
- InsufficientDataException, IOException, InvalidKeyException, NoResponseException,
- XmlPullParserException, ErrorResponseException, InternalException, InvalidResponseException {
+ throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
+ InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
+ InternalException, InvalidResponseException, InvalidArgumentException {
Map queryParamMap = new HashMap<>();
queryParamMap.put("lifecycle", "");
- HttpResponse response = null;
String bodyContent = "";
- Scanner scanner = null ;
+ HttpResponse response = null;
try {
- response = executeGet(bucketName, "", null, queryParamMap);
- scanner = new Scanner(response.body().charStream());
- // read entire body stream to string.
- scanner.useDelimiter("\\A");
- if (scanner.hasNext()) {
- bodyContent = scanner.next();
- }
+ response = executeGet(bucketName, null, null, queryParamMap);
+ bodyContent = new String(response.body().bytes(), StandardCharsets.UTF_8);
} catch (ErrorResponseException e) {
if (e.errorResponse().errorCode() != ErrorCode.NO_SUCH_LIFECYCLE_CONFIGURATION) {
throw e;
}
} finally {
- if (response != null && response.body() != null) {
+ if (response != null) {
response.body().close();
}
- if (scanner != null) {
- scanner.close();
- }
}
+
return bodyContent;
}
@@ -5665,9 +5393,9 @@ public String getBucketLifeCycle(String bucketName)
*
*/
public NotificationConfiguration getBucketNotification(String bucketName)
- throws InvalidBucketNameException, NoSuchAlgorithmException,
- InsufficientDataException, IOException, InvalidKeyException, NoResponseException,
- XmlPullParserException, ErrorResponseException, InternalException, InvalidResponseException {
+ throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
+ InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
+ InternalException, InvalidResponseException, InvalidArgumentException {
Map queryParamMap = new HashMap<>();
queryParamMap.put("notification", "");
@@ -5709,9 +5437,9 @@ public NotificationConfiguration getBucketNotification(String bucketName)
*
*/
public void setBucketNotification(String bucketName, NotificationConfiguration notificationConfiguration)
- throws InvalidBucketNameException, NoSuchAlgorithmException,
- InsufficientDataException, IOException, InvalidKeyException, NoResponseException,
- XmlPullParserException, ErrorResponseException, InternalException, InvalidResponseException {
+ throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
+ InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
+ InternalException, InvalidResponseException, InvalidArgumentException {
Map queryParamMap = new HashMap<>();
queryParamMap.put("notification", "");
HttpResponse response = executePut(bucketName, null, null, queryParamMap, notificationConfiguration.toString(), 0);
@@ -5743,9 +5471,9 @@ public void setBucketNotification(String bucketName, NotificationConfiguration n
* @throws InvalidResponseException upon a non-xml response from server
*/
public void removeAllBucketNotification(String bucketName)
- throws InvalidBucketNameException, NoSuchAlgorithmException,
- InsufficientDataException, IOException, InvalidKeyException, NoResponseException,
- XmlPullParserException, ErrorResponseException, InternalException, InvalidResponseException {
+ throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
+ InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
+ InternalException, InvalidResponseException, InvalidArgumentException {
NotificationConfiguration notificationConfiguration = new NotificationConfiguration();
setBucketNotification(bucketName, notificationConfiguration);
}
@@ -5834,7 +5562,7 @@ private synchronized void populate() {
prefix, delimiter, 1000);
} catch (InvalidBucketNameException | NoSuchAlgorithmException | InsufficientDataException | IOException
| InvalidKeyException | NoResponseException | XmlPullParserException | ErrorResponseException
- | InternalException | InvalidResponseException e) {
+ | InternalException | InvalidResponseException | InvalidArgumentException e) {
this.error = new Result<>(null, e);
} finally {
if (this.listMultipartUploadsResult != null) {
@@ -5848,7 +5576,7 @@ private synchronized void populate() {
private synchronized long getAggregatedPartSize(String objectName, String uploadId)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException {
+ InternalException, InvalidArgumentException {
long aggregatedPartSize = 0;
for (Result result : listObjectParts(bucketName, objectName, uploadId)) {
@@ -5919,7 +5647,7 @@ public Result next() {
aggregatedPartSize = getAggregatedPartSize(upload.objectName(), upload.uploadId());
} catch (InvalidBucketNameException | NoSuchAlgorithmException | InsufficientDataException | IOException
| InvalidKeyException | NoResponseException | XmlPullParserException | ErrorResponseException
- | InternalException e) {
+ | InternalException | InvalidArgumentException e) {
// special case: ignore the error as we can't propagate the exception in next()
aggregatedPartSize = -1;
}
@@ -5951,7 +5679,7 @@ private ListMultipartUploadsResult listIncompleteUploads(String bucketName, Stri
String prefix, String delimiter, int maxUploads)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
+ InternalException, InvalidResponseException, InvalidArgumentException {
if (maxUploads < 0 || maxUploads > 1000) {
maxUploads = 1000;
}
@@ -5995,7 +5723,7 @@ private ListMultipartUploadsResult listIncompleteUploads(String bucketName, Stri
private String initMultipartUpload(String bucketName, String objectName, Map headerMap)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException , InvalidResponseException {
+ InternalException , InvalidResponseException, InvalidArgumentException {
// set content type if not set already
if ((headerMap != null) && (headerMap.get("Content-Type") == null)) {
headerMap.put("Content-Type", "application/octet-stream");
@@ -6019,29 +5747,20 @@ private String initMultipartUpload(String bucketName, String objectName, Map queryParamMap = new HashMap<>();
queryParamMap.put(UPLOAD_ID, uploadId);
-
CompleteMultipartUpload completeManifest = new CompleteMultipartUpload(parts);
-
HttpResponse response = executePost(bucketName, objectName, null, queryParamMap, completeManifest);
-
- // Fixing issue https://github.com/minio/minio-java/issues/391
String bodyContent = "";
- Scanner scanner = new Scanner(response.body().charStream());
try {
- // read entire body stream to string.
- scanner.useDelimiter("\\A");
- if (scanner.hasNext()) {
- bodyContent = scanner.next();
- }
+ bodyContent = new String(response.body().bytes(), StandardCharsets.UTF_8);
+ bodyContent = bodyContent.trim();
} finally {
response.body().close();
- scanner.close();
}
- bodyContent = bodyContent.trim();
+ // Handle if body contains error.
if (!bodyContent.isEmpty()) {
ErrorResponse errorResponse = new ErrorResponse(new StringReader(bodyContent));
if (errorResponse.code() != null) {
@@ -6075,7 +5794,7 @@ private synchronized void populate() {
this.listPartsResult = listObjectParts(bucketName, objectName, uploadId, nextPartNumberMarker);
} catch (InvalidBucketNameException | NoSuchAlgorithmException | InsufficientDataException | IOException
| InvalidKeyException | NoResponseException | XmlPullParserException | ErrorResponseException
- | InternalException | InvalidResponseException e) {
+ | InternalException | InvalidResponseException | InvalidArgumentException e) {
this.error = new Result<>(null, e);
} finally {
if (this.listPartsResult != null) {
@@ -6158,7 +5877,7 @@ public void remove() {
private ListPartsResult listObjectParts(String bucketName, String objectName, String uploadId, int partNumberMarker)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
+ InternalException, InvalidResponseException, InvalidArgumentException {
Map queryParamMap = new HashMap<>();
queryParamMap.put(UPLOAD_ID, uploadId);
if (partNumberMarker > 0) {
@@ -6180,7 +5899,7 @@ private ListPartsResult listObjectParts(String bucketName, String objectName, St
private void abortMultipartUpload(String bucketName, String objectName, String uploadId)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
+ InternalException, InvalidResponseException, InvalidArgumentException {
Map queryParamMap = new HashMap<>();
queryParamMap.put(UPLOAD_ID, uploadId);
executeDelete(bucketName, objectName, queryParamMap);
@@ -6214,7 +5933,7 @@ private void abortMultipartUpload(String bucketName, String objectName, String u
public void removeIncompleteUpload(String bucketName, String objectName)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
+ InternalException, InvalidResponseException, InvalidArgumentException {
for (Result r : listIncompleteUploads(bucketName, objectName, true, false)) {
Upload upload = r.get();
if (objectName.equals(upload.objectName())) {
@@ -6251,8 +5970,8 @@ public void removeIncompleteUpload(String bucketName, String objectName)
public void listenBucketNotification(String bucketName, String prefix, String suffix, String[] events,
BucketEventListener eventCallback)
throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, IOException,
- InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
- InternalException, InvalidResponseException {
+ InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
+ InternalException, InvalidResponseException, InvalidArgumentException {
Multimap queryParamMap = HashMultimap.create();
queryParamMap.put("prefix", prefix);
@@ -6267,8 +5986,7 @@ public void listenBucketNotification(String bucketName, String prefix, String su
ObjectMapper mapper = new ObjectMapper();
try {
- response = executeReq(Method.GET, getRegion(bucketName),
- bucketName, "", null, queryParamMap, null, 0, false);
+ response = executeGet(bucketName, "", null, queryParamMap);
scanner = new Scanner(response.body().charStream());
scanner.useDelimiter("\n");
while (scanner.hasNext()) {
@@ -6323,8 +6041,8 @@ public void listenBucketNotification(String bucketName, String prefix, String su
public CloseableIterator> listenBucketNotification(String bucketName, String prefix,
String suffix, String[] events)
throws IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException,
- InvalidResponseException, InternalException, NoResponseException, InvalidBucketNameException,
- XmlPullParserException, ErrorResponseException {
+ InvalidResponseException, InternalException, NoResponseException, InvalidBucketNameException,
+ XmlPullParserException, ErrorResponseException, InvalidArgumentException {
Multimap queryParamMap = HashMultimap.create();
queryParamMap.put("prefix", prefix);
@@ -6333,8 +6051,7 @@ public CloseableIterator> listenBucketNotification(Stri
queryParamMap.put("events", event);
}
- HttpResponse response = executeReq(Method.GET, getRegion(bucketName),
- bucketName, "", null, queryParamMap, null, 0, false);
+ HttpResponse response = executeGet(bucketName, "", null, queryParamMap);
return new CloseableIterator>() {
Scanner scanner = new Scanner(response.body().charStream()).useDelimiter("\n");
@@ -6468,8 +6185,7 @@ public SelectResponseStream selectObjectContent(String bucketName, String object
SelectObjectContentRequest request = new SelectObjectContentRequest(sqlExpression, requestProgress, is, os,
scanStartRange, scanEndRange);
- HttpResponse response = execute(Method.POST, getRegion(bucketName), bucketName, objectName,
- headerMap, queryParamMap, request, 0);
+ HttpResponse response = executePost(bucketName, objectName, headerMap, queryParamMap, request);
return new SelectResponseStream(response.body().byteStream());
}
@@ -6556,6 +6272,86 @@ private int getAvailableSize(Object inputStream, int expectedReadSize) throws IO
}
+ /**
+ * Sets HTTP connect, write and read timeouts. A value of 0 means no timeout, otherwise values must be between 1 and
+ * Integer.MAX_VALUE when converted to milliseconds.
+ *
+ *
Example:
+ * {@code minioClient.setTimeout(TimeUnit.SECONDS.toMillis(10), TimeUnit.SECONDS.toMillis(10),
+ * TimeUnit.SECONDS.toMillis(30)); }
+ *
+ * @param connectTimeout HTTP connect timeout in milliseconds.
+ * @param writeTimeout HTTP write timeout in milliseconds.
+ * @param readTimeout HTTP read timeout in milliseconds.
+ */
+ public void setTimeout(long connectTimeout, long writeTimeout, long readTimeout) {
+ this.httpClient = this.httpClient.newBuilder()
+ .connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
+ .writeTimeout(writeTimeout, TimeUnit.MILLISECONDS)
+ .readTimeout(readTimeout, TimeUnit.MILLISECONDS)
+ .build();
+ }
+
+
+ /**
+ * Ignores check on server certificate for HTTPS connection.
+ *
+ * Example:
+ * {@code minioClient.ignoreCertCheck(); }
+ *
+ */
+ @SuppressFBWarnings(value = "SIC", justification = "Should not be used in production anyways.")
+ public void ignoreCertCheck() throws NoSuchAlgorithmException, KeyManagementException {
+ final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return new X509Certificate[]{};
+ }
+ }
+ };
+
+ final SSLContext sslContext = SSLContext.getInstance("SSL");
+ sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
+ final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
+
+ this.httpClient = this.httpClient.newBuilder()
+ .sslSocketFactory(sslSocketFactory, (X509TrustManager)trustAllCerts[0])
+ .hostnameVerifier(new HostnameVerifier() {
+ @Override
+ public boolean verify(String hostname, SSLSession session) {
+ return true;
+ }
+ })
+ .build();
+ }
+
+
+ /**
+ * Sets application's name/version to user agent. For more information about user agent
+ * refer #rfc2616.
+ *
+ * @param name Your application name.
+ * @param version Your application version.
+ */
+ @SuppressWarnings("unused")
+ public void setAppInfo(String name, String version) {
+ if (name == null || version == null) {
+ // nothing to do
+ return;
+ }
+
+ this.userAgent = DEFAULT_USER_AGENT + " " + name.trim() + "/" + version.trim();
+ }
+
+
/**
* Enables HTTP call tracing and written to traceStream.
*
diff --git a/api/src/main/java/io/minio/Result.java b/api/src/main/java/io/minio/Result.java
index 6972638c0..b4c9c47e7 100644
--- a/api/src/main/java/io/minio/Result.java
+++ b/api/src/main/java/io/minio/Result.java
@@ -27,6 +27,7 @@
import io.minio.errors.ErrorResponseException;
import io.minio.errors.InsufficientDataException;
import io.minio.errors.InternalException;
+import io.minio.errors.InvalidArgumentException;
import io.minio.errors.InvalidBucketNameException;
import io.minio.errors.NoResponseException;
@@ -49,7 +50,7 @@ public Result(T type, Exception ex) {
* Returns given Type if exception is null, else respective exception is thrown.
*/
public T get()
- throws InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException,
+ throws InvalidBucketNameException, InvalidArgumentException, NoSuchAlgorithmException, InsufficientDataException,
JsonParseException, JsonMappingException,IOException,
InvalidKeyException, NoResponseException, XmlPullParserException, ErrorResponseException,
InternalException {
@@ -61,6 +62,10 @@ public T get()
throw (InvalidBucketNameException) ex;
}
+ if (ex instanceof InvalidArgumentException) {
+ throw (InvalidArgumentException) ex;
+ }
+
if (ex instanceof NoSuchAlgorithmException) {
throw (NoSuchAlgorithmException) ex;
}
diff --git a/functional/FunctionalTest.java b/functional/FunctionalTest.java
index 6f8555af7..76cd5bbdd 100644
--- a/functional/FunctionalTest.java
+++ b/functional/FunctionalTest.java
@@ -1628,7 +1628,7 @@ public static void listIncompleteUploads_test1() throws Exception {
if (!e.errorResponse().code().equals("IncompleteBody")) {
throw e;
}
- } catch (java.net.ProtocolException e) {
+ } catch (InsufficientDataException e) {
ignore();
}
@@ -1666,7 +1666,7 @@ public static void listIncompleteUploads_test2() throws Exception {
if (!e.errorResponse().code().equals("IncompleteBody")) {
throw e;
}
- } catch (java.net.ProtocolException e) {
+ } catch (InsufficientDataException e) {
ignore();
}
@@ -1706,7 +1706,7 @@ public static void listIncompleteUploads_test3() throws Exception {
if (!e.errorResponse().code().equals("IncompleteBody")) {
throw e;
}
- } catch (java.net.ProtocolException e) {
+ } catch (InsufficientDataException e) {
ignore();
}
@@ -1746,7 +1746,7 @@ public static void removeIncompleteUploads_test() throws Exception {
if (!e.errorResponse().code().equals("IncompleteBody")) {
throw e;
}
- } catch (java.net.ProtocolException e) {
+ } catch (InsufficientDataException e) {
ignore();
}