Skip to content

Commit

Permalink
Add arg builder to getPresignedObjectUrl() (#948)
Browse files Browse the repository at this point in the history
  • Loading branch information
sinhaashish authored Jun 5, 2020
1 parent fdd00c7 commit 377213e
Show file tree
Hide file tree
Showing 8 changed files with 502 additions and 267 deletions.
81 changes: 81 additions & 0 deletions api/src/main/java/io/minio/GetPresignedObjectUrlArgs.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.minio;

import io.minio.http.Method;
import java.util.concurrent.TimeUnit;

/** Argument class of MinioClient.getPresignedObjectUrl(). */
public class GetPresignedObjectUrlArgs extends ObjectArgs {
// default expiration for a presigned URL is 7 days in seconds
public static final int DEFAULT_EXPIRY_TIME = (int) TimeUnit.DAYS.toSeconds(7);

private Method method;
private int expiry = DEFAULT_EXPIRY_TIME;

public Method method() {
return method;
}

public int expiry() {
return expiry;
}

public static Builder builder() {
return new Builder();
}

/** Argument builder of {@link GetPresignedObjectUrlArgs}. */
public static final class Builder extends ObjectArgs.Builder<Builder, GetPresignedObjectUrlArgs> {
private void validateMethod(Method method) {
validateNotNull(method, "method");
}

private void validateExpiry(int expiry) {
if (expiry < 1 || expiry > DEFAULT_EXPIRY_TIME) {
throw new IllegalArgumentException(
"expiry must be minimum 1 second to maximum "
+ TimeUnit.SECONDS.toDays(DEFAULT_EXPIRY_TIME)
+ " days");
}
}

/* method HTTP {@link Method} to generate presigned URL. */
public Builder method(Method method) {
validateMethod(method);
operations.add(args -> args.method = method);
return this;
}

/*expires Expiry in seconds; defaults to 7 days. */
public Builder expiry(int expiry) {
validateExpiry(expiry);
operations.add(args -> args.expiry = expiry);
return this;
}

public Builder expiry(int duration, TimeUnit unit) {
return expiry((int) unit.toSeconds(duration));
}

@Override
protected void validate(GetPresignedObjectUrlArgs args) {
super.validate(args);
validateMethod(args.method);
}
}
}
159 changes: 135 additions & 24 deletions api/src/main/java/io/minio/MinioClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -2640,7 +2640,9 @@ public void composeObject(
* @throws IOException thrown to indicate I/O error on S3 operation.
* @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library.
* @throws XmlParserException thrown to indicate XML parsing error.
* @deprecated use {@link #getPresignedObjectUrl(GetPresignedObjectUrlArgs)}
*/
@Deprecated
public String getPresignedObjectUrl(
Method method,
String bucketName,
Expand All @@ -2651,29 +2653,95 @@ public String getPresignedObjectUrl(
InternalException, InvalidBucketNameException, InvalidExpiresRangeException,
InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException,
ServerException, XmlParserException {
// Validate input.
if (expires < 1 || expires > DEFAULT_EXPIRY_TIME) {
throw new InvalidExpiresRangeException(
expires, "expires must be in range of 1 to " + DEFAULT_EXPIRY_TIME);
}

byte[] body = null;
if (method == Method.PUT || method == Method.POST) {
body = new byte[0];
}
return getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.bucket(bucketName)
.object(objectName)
.method(method)
.expiry(expires)
.extraQueryParams(reqParams)
.build());
}

Multimap<String, String> queryParamMap = null;
if (reqParams != null) {
queryParamMap = HashMultimap.create();
for (Map.Entry<String, String> m : reqParams.entrySet()) {
queryParamMap.put(m.getKey(), m.getValue());
}
/**
* Gets presigned URL of an object for HTTP method, expiry time and custom request parameters.
*
* <pre>Example:{@code
* // Get presigned URL string to delete 'my-objectname' in 'my-bucketname' and its life time
* // is one day.
* String url =
* minioClient.getPresignedObjectUrl(
* GetPresignedObjectUrlArgs.builder()
* .method(Method.DELETE)
* .bucket("my-bucketname")
* .object("my-objectname")
* .expiry(24 * 60 * 60)
* .build());
* System.out.println(url);
*
* // Get presigned URL string to upload 'my-objectname' in 'my-bucketname'
* // with response-content-type as application/json and life time as one day.
* Map<String, String> reqParams = new HashMap<String, String>();
* reqParams.put("response-content-type", "application/json");
*
* String url =
* minioClient.getPresignedObjectUrl(
* GetPresignedObjectUrlArgs.builder()
* .method(Method.PUT)
* .bucket("my-bucketname")
* .object("my-objectname")
* .expiry(1, TimeUnit.DAYS)
* .extraQueryParams(reqParams)
* .build());
* System.out.println(url);
*
* // Get presigned URL string to download 'my-objectname' in 'my-bucketname' and its life time
* // is 2 hours.
* String url =
* minioClient.getPresignedObjectUrl(
* GetPresignedObjectUrlArgs.builder()
* .method(Method.GET)
* .bucket("my-bucketname")
* .object("my-objectname")
* .expiry(2, TimeUnit.HOURS)
* .build());
* System.out.println(url);
* }</pre>
*
* @param args {@link GetPresignedObjectUrlArgs} object.
* @return String - URL string.
* @throws ErrorResponseException thrown to indicate S3 service returned an error response.
* @throws IllegalArgumentException throws to indicate invalid argument passed.
* @throws InsufficientDataException thrown to indicate not enough data available in InputStream.
* @throws InternalException thrown to indicate internal library error.
* @throws InvalidBucketNameException thrown to indicate invalid bucket name passed.
* @throws InvalidExpiresRangeException thrown to indicate invalid expiry duration passed.
* @throws InvalidKeyException thrown to indicate missing of HMAC SHA-256 library.
* @throws InvalidResponseException thrown to indicate S3 service returned invalid or no error
* response.
* @throws IOException thrown to indicate I/O error on S3 operation.
* @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library.
* @throws XmlParserException thrown to indicate XML parsing error.
* @throws ServerException
*/
public String getPresignedObjectUrl(GetPresignedObjectUrlArgs args)
throws ErrorResponseException, IllegalArgumentException, InsufficientDataException,
InternalException, InvalidBucketNameException, InvalidExpiresRangeException,
InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException,
XmlParserException, ServerException {
checkArgs(args);

byte[] body = null;
if (args.method() == Method.PUT || args.method() == Method.POST) {
body = EMPTY_BODY;
}

String region = getRegion(bucketName);
HttpUrl url = buildUrl(method, bucketName, objectName, region, queryParamMap);
Request request = createRequest(url, method, null, body, 0);
url = Signer.presignV4(request, region, accessKey, secretKey, expires);
String region = getRegion(args.bucket());
HttpUrl url =
buildUrl(args.method(), args.bucket(), args.object(), region, args.extraQueryParams());
Request request = createRequest(url, args.method(), null, body, 0);
url = Signer.presignV4(request, region, accessKey, secretKey, args.expiry());
return url.toString();
}

Expand Down Expand Up @@ -2705,14 +2773,24 @@ public String getPresignedObjectUrl(
* @throws IOException thrown to indicate I/O error on S3 operation.
* @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library.
* @throws XmlParserException thrown to indicate XML parsing error.
* @deprecated use {@link #getPresignedObjectUrl(GetPresignedObjectUrlArgs)}
*/
@Deprecated
public String presignedGetObject(
String bucketName, String objectName, Integer expires, Map<String, String> reqParams)
throws ErrorResponseException, IllegalArgumentException, InsufficientDataException,
InternalException, InvalidBucketNameException, InvalidExpiresRangeException,
InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException,
ServerException, XmlParserException {
return getPresignedObjectUrl(Method.GET, bucketName, objectName, expires, reqParams);

return getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket(bucketName)
.object(objectName)
.expiry(expires)
.extraQueryParams(reqParams)
.build());
}

/**
Expand Down Expand Up @@ -2740,13 +2818,21 @@ public String presignedGetObject(
* @throws IOException thrown to indicate I/O error on S3 operation.
* @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library.
* @throws XmlParserException thrown to indicate XML parsing error.
* @deprecated use {@link #getPresignedObjectUrl(GetPresignedObjectUrlArgs)}
*/
@Deprecated
public String presignedGetObject(String bucketName, String objectName, Integer expires)
throws ErrorResponseException, IllegalArgumentException, InsufficientDataException,
InternalException, InvalidBucketNameException, InvalidExpiresRangeException,
InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException,
ServerException, XmlParserException {
return presignedGetObject(bucketName, objectName, expires, null);
return getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket(bucketName)
.object(objectName)
.expiry(expires)
.build());
}

/**
Expand All @@ -2771,13 +2857,21 @@ public String presignedGetObject(String bucketName, String objectName, Integer e
* @throws IOException thrown to indicate I/O error on S3 operation.
* @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library.
* @throws XmlParserException thrown to indicate XML parsing error.
* @deprecated use {@link #getPresignedObjectUrl(GetPresignedObjectUrlArgs)}
*/
@Deprecated
public String presignedGetObject(String bucketName, String objectName)
throws ErrorResponseException, IllegalArgumentException, InsufficientDataException,
InternalException, InvalidBucketNameException, InvalidExpiresRangeException,
InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException,
ServerException, XmlParserException {
return presignedGetObject(bucketName, objectName, DEFAULT_EXPIRY_TIME, null);

return getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket(bucketName)
.object(objectName)
.build());
}

/**
Expand Down Expand Up @@ -2805,13 +2899,22 @@ public String presignedGetObject(String bucketName, String objectName)
* @throws IOException thrown to indicate I/O error on S3 operation.
* @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library.
* @throws XmlParserException thrown to indicate XML parsing error.
* @deprecated use {@link #getPresignedObjectUrl(GetPresignedObjectUrlArgs)}
*/
@Deprecated
public String presignedPutObject(String bucketName, String objectName, Integer expires)
throws ErrorResponseException, IllegalArgumentException, InsufficientDataException,
InternalException, InvalidBucketNameException, InvalidExpiresRangeException,
InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException,
ServerException, XmlParserException {
return getPresignedObjectUrl(Method.PUT, bucketName, objectName, expires, null);

return getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.method(Method.PUT)
.bucket(bucketName)
.object(objectName)
.expiry(expires)
.build());
}

/**
Expand All @@ -2836,13 +2939,21 @@ public String presignedPutObject(String bucketName, String objectName, Integer e
* @throws IOException thrown to indicate I/O error on S3 operation.
* @throws NoSuchAlgorithmException thrown to indicate missing of MD5 or SHA-256 digest library.
* @throws XmlParserException thrown to indicate XML parsing error.
* @deprecated use {@link #getPresignedObjectUrl(GetPresignedObjectUrlArgs)}
*/
@Deprecated
public String presignedPutObject(String bucketName, String objectName)
throws ErrorResponseException, IllegalArgumentException, InsufficientDataException,
InternalException, InvalidBucketNameException, InvalidExpiresRangeException,
InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException,
ServerException, XmlParserException {
return presignedPutObject(bucketName, objectName, DEFAULT_EXPIRY_TIME);

return getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.method(Method.PUT)
.bucket(bucketName)
.object(objectName)
.build());
}

/**
Expand Down
21 changes: 16 additions & 5 deletions api/src/test/java/io/minio/MinioClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
package io.minio;

import io.minio.errors.InvalidBucketNameException;
import io.minio.errors.InvalidExpiresRangeException;
import io.minio.errors.InvalidResponseException;
import io.minio.errors.MinioException;
import io.minio.errors.RegionConflictException;
Expand Down Expand Up @@ -423,18 +422,30 @@ public void testMakeBucketRegionConflicts()
Assert.fail("exception should be thrown");
}

@Test(expected = InvalidExpiresRangeException.class)
@Test(expected = IllegalArgumentException.class)
public void testInvalidExpiresRange1()
throws NoSuchAlgorithmException, IOException, InvalidKeyException, MinioException {
MinioClient client = new MinioClient("https://play.min.io:9000");
client.getPresignedObjectUrl(Method.GET, "mybucket", "myobject", 0, null);
client.getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket("mybucket")
.object("myobject")
.expiry(0)
.build());
}

@Test(expected = InvalidExpiresRangeException.class)
@Test(expected = IllegalArgumentException.class)
public void testInvalidExpiresRange2()
throws NoSuchAlgorithmException, IOException, InvalidKeyException, MinioException {
MinioClient client = new MinioClient("https://play.min.io:9000");
client.getPresignedObjectUrl(Method.GET, "mybucket", "myobject", 8 * 24 * 3600, null);
client.getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket("mybucket")
.object("myobject")
.expiry(8 * 24 * 3600)
.build());
}

@Test(expected = IllegalArgumentException.class)
Expand Down
Loading

0 comments on commit 377213e

Please sign in to comment.