Skip to content

Commit

Permalink
Performance optimization Updates (#728)
Browse files Browse the repository at this point in the history
Co-authored-by: Waqar Ahmed Khan <waahm7@gmail.com>
  • Loading branch information
TingDaoK and waahm7 authored Nov 28, 2023
1 parent d27f864 commit 059730a
Show file tree
Hide file tree
Showing 21 changed files with 936 additions and 119 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ public class Credentials {
private byte[] accessKeyId;
private byte[] secretAccessKey;
private byte[] sessionToken;
/* Not using Instant, as Instant requires Android API 29+. The secs since epoch. */
private long expirationTimePointSecs;

/**
* Anonymous Credentials constructor. Use Anonymous Credentials when you want to skip signing.
Expand All @@ -26,15 +28,28 @@ public Credentials() {}
* @param sessionToken - (optional) session token to use
*/
public Credentials(byte[] accessKeyId, byte[] secretAccessKey, byte[] sessionToken) {
this(accessKeyId, secretAccessKey, sessionToken, Long.MAX_VALUE);
}


/**
* @param accessKeyId - access key id to use
* @param secretAccessKey - secret access key to use
* @param sessionToken - (optional) session token to use
* @param expirationTimePointSecs - Time when the credentials expires, as secs since epoch.
*/
public Credentials(byte[] accessKeyId, byte[] secretAccessKey, byte[] sessionToken, long expirationTimePointSecs) {
if (accessKeyId == null || secretAccessKey == null) {
throw new IllegalArgumentException("Credentials - accessKeyId and secretAccessKey must be non null");
}

this.accessKeyId = accessKeyId;
this.secretAccessKey = secretAccessKey;
this.sessionToken = sessionToken;
this.expirationTimePointSecs = expirationTimePointSecs;
}


/**
* Anonymous Credentials constructor. Use Anonymous Credentials when you want to skip signing.
* @return Anonymous Credentials
Expand All @@ -57,4 +72,9 @@ public static Credentials createAnonymousCredentials(){
* @return the session token of the credentials
*/
public byte[] getSessionToken() { return sessionToken; }

/**
* @return the expiration timepoint as secs since epoch.
*/
public long getExpirationTimePointSecs() { return expirationTimePointSecs; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ public enum AwsSigningAlgorithm {
SIGV4(0),

/** AWS Sigv4a signing, based on ECDSA signatures */
SIGV4_ASYMMETRIC(1);
SIGV4_ASYMMETRIC(1),

/** AWS Sigv4 S3 Express signing */
SIGV4_S3EXPRESS(2);

/**
* Constructs a Java enum value from the associated native enum value
Expand Down Expand Up @@ -61,6 +64,7 @@ private static Map<Integer, AwsSigningAlgorithm> buildEnumMapping() {
Map<Integer, AwsSigningAlgorithm> enumMapping = new HashMap<Integer, AwsSigningAlgorithm>();
enumMapping.put(SIGV4.getNativeValue(), SIGV4);
enumMapping.put(SIGV4_ASYMMETRIC.getNativeValue(), SIGV4_ASYMMETRIC);
enumMapping.put(SIGV4_S3EXPRESS.getNativeValue(), SIGV4_S3EXPRESS);

return enumMapping;
}
Expand Down
8 changes: 6 additions & 2 deletions src/main/java/software/amazon/awssdk/crt/s3/S3Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@ public S3Client(S3ClientOptions options) throws CrtRuntimeException {
options.getConnectTimeoutMs(),
options.getTcpKeepAliveOptions(),
monitoringThroughputThresholdInBytesPerSecond,
monitoringFailureIntervalInSeconds));
monitoringFailureIntervalInSeconds,
options.getEnableS3Express(),
options.getS3ExpressCredentialsProviderFactory()));

addReferenceTo(options.getClientBootstrap());
if(didCreateSigningConfig) {
Expand Down Expand Up @@ -215,7 +217,9 @@ private static native long s3ClientNew(S3Client thisObj, byte[] region, long cli
int connectTimeoutMs,
S3TcpKeepAliveOptions tcpKeepAliveOptions,
long monitoringThroughputThresholdInBytesPerSecond,
int monitoringFailureIntervalInSeconds) throws CrtRuntimeException;
int monitoringFailureIntervalInSeconds,
boolean enableS3Express,
S3ExpressCredentialsProviderFactory s3expressCredentialsProviderFactory) throws CrtRuntimeException;

private static native void s3ClientDestroy(long client);

Expand Down
41 changes: 40 additions & 1 deletion src/main/java/software/amazon/awssdk/crt/s3/S3ClientOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import software.amazon.awssdk.crt.io.StandardRetryOptions;
import software.amazon.awssdk.crt.auth.credentials.CredentialsProvider;
import software.amazon.awssdk.crt.auth.signing.AwsSigningConfig;
import software.amazon.awssdk.crt.auth.signing.AwsSigningConfig.AwsSigningAlgorithm;

public class S3ClientOptions {

Expand All @@ -28,6 +29,8 @@ public class S3ClientOptions {
private boolean readBackpressureEnabled;
private long initialReadWindowSize;
private int maxConnections;
private boolean enableS3Express;
private S3ExpressCredentialsProviderFactory s3expressCredentialsProviderFactory;
/**
* For multi-part upload, content-md5 will be calculated if the
* computeContentMd5 is set to true.
Expand Down Expand Up @@ -113,9 +116,19 @@ public CredentialsProvider getCredentialsProvider() {
/**
* The configuration related to signing used by S3 client.
* `AwsSigningConfig.getDefaultS3SigningConfig(region, credentialsProvider);` can be used as helper to create the default configuration to be used for S3.
* If no signing config provided, the client will skip signing.
* In case of public object, or the http message already has a presigned URL, signing can be skipped.
*
* If not set, a default config will be used with anonymous credentials and skip signing the request.
* If set:
* - Credentials provider is required. Other configs are all optional, and will be default to what
* needs to sign the request for S3, only overrides when Non-zero/Not-empty is set.
* - S3 Client will derive the right config for signing process based on this.
*
* Notes:
* - For SIGV4_S3EXPRESS, S3 client will use the credentials in the config to derive the S3 Express
* credentials that are used in the signing process.
* - Client may make modifications to signing config before passing it on to signer.
*
* @param signingConfig configuration related to signing via an AWS signing process.
* @return this
*/
Expand Down Expand Up @@ -307,4 +320,30 @@ public S3ClientOptions withHttpMonitoringOptions(HttpMonitoringOptions monitorin
public HttpMonitoringOptions getMonitoringOptions() {
return monitoringOptions;
}

/**
* To enable S3 Express support for client
* The typical usage for a S3 Express request is to set this to true and let the request to be signed with
* {@link AwsSigningAlgorithm#SIGV4_S3EXPRESS}, either from the client level signingConfig or override from request.
*
* @param enableS3Express To enable S3 Express support for client
* @return this
*/
public S3ClientOptions withEnableS3Express(boolean enableS3Express) {
this.enableS3Express = enableS3Express;
return this;
}

public boolean getEnableS3Express() {
return enableS3Express;
}

public S3ClientOptions withS3ExpressCredentialsProviderFactory(S3ExpressCredentialsProviderFactory s3expressCredentialsProviderFactory) {
this.s3expressCredentialsProviderFactory = s3expressCredentialsProviderFactory;
return this;
}

public S3ExpressCredentialsProviderFactory getS3ExpressCredentialsProviderFactory() {
return s3expressCredentialsProviderFactory;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
package software.amazon.awssdk.crt.s3;

public class S3ExpressCredentialsProperties {
private String hostValue;
private String region;

public S3ExpressCredentialsProperties withHostValue (String hostValue) {
this.hostValue = hostValue;
return this;
}

public String getHostValue () {
return this.hostValue;
}

public S3ExpressCredentialsProperties withRegion (String region) {
this.region = region;
return this;
}

public String getRegion () {
return this.region;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
package software.amazon.awssdk.crt.s3;

import software.amazon.awssdk.crt.auth.credentials.Credentials;

/**
* The Java object for Native code to invoke.
*/
public class S3ExpressCredentialsProvider {

private S3ExpressCredentialsProviderHandler handler;

public S3ExpressCredentialsProvider(S3ExpressCredentialsProviderHandler handler) {
this.handler = handler;
}

public void getS3ExpressCredentials(S3ExpressCredentialsProperties properties, Credentials origCredentials, long nativeHandler) {
handler.getS3ExpressCredentials(properties, origCredentials).whenComplete((result, ex) -> {
if(ex != null) {
s3expressCredentialsProviderGetCredentialsCompleted(nativeHandler, null);
} else {
s3expressCredentialsProviderGetCredentialsCompleted(nativeHandler, result);
}
});
}

public void destroyProvider() throws Exception {
/* Block until handler finishes shutdown. It doesn't matter to wait for shutdown */
this.handler.destroyProvider().get();
}

/*******************************************************************************
* native methods
******************************************************************************/
private static native void s3expressCredentialsProviderGetCredentialsCompleted(long nativeHandler, Credentials credentials);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
package software.amazon.awssdk.crt.s3;


public interface S3ExpressCredentialsProviderFactory {
/**
* A handler to create a S3ExpressCredentialsProvider for the client to use.
*
* Warning:
* You cannot use the client while creating the provider
* (You can use the client for fetching credentials)
* @param client The S3Client creates and owns the provider.
* @return S3ExpressCredentialsProvider created.
*/
public S3ExpressCredentialsProvider createS3ExpressCredentialsProvider(S3Client client);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
package software.amazon.awssdk.crt.s3;

import java.util.concurrent.CompletableFuture;

import software.amazon.awssdk.crt.auth.credentials.Credentials;

/**
* Interface to override the S3Express Credentials provider.
*/
public interface S3ExpressCredentialsProviderHandler {
/**
* To resolve the S3Express Credentials. Invoked when a single request needs to be signed.
*
* @param properties The properties needed to derive the S3Express credentials from.
* @param origCredentials The original Credentials for fetching S3Express credentials.
* @return The future to be resolved when the S3 Express credentials are resolved.
*/
public CompletableFuture<Credentials> getS3ExpressCredentials(S3ExpressCredentialsProperties properties, Credentials origCredentials);

/**
* Invoked when the S3 client starts to destroy to clean up related resource.
*
* @return The future to be resolved when the resource finishes cleaning up.
*/
public CompletableFuture<Void> destroyProvider();
}
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,16 @@ public CredentialsProvider getCredentialsProvider() {
* The configuration related to signing used by S3 client. It will override the client level configuration if provided.
* `AwsSigningConfig.getDefaultS3SigningConfig(region, credentialsProvider);` can be used as helper to create the default configuration to be used for S3.
*
* If not set, the client configuration will be used.
* If set:
* - All fields are optional. The credentials will be resolve from client if not set.
* - S3 Client will derive the right config for signing process based on this.
*
* Notes:
* - For SIGV4_S3EXPRESS, S3 client will use the credentials in the config to derive the S3Express
* credentials that are used in the signing process.
* - Client may make modifications to signing config before passing it on to signer.
*
* @param signingConfig configuration related to signing via an AWS signing process.
* @return this
*/
Expand Down
16 changes: 12 additions & 4 deletions src/native/aws_signing.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,12 +314,20 @@ int aws_build_signing_config(
env, java_config, aws_signing_config_properties.signature_type_field_id);

jstring region = (jstring)(*env)->GetObjectField(env, java_config, aws_signing_config_properties.region_field_id);
config_data->region = aws_jni_new_string_from_jstring(env, region);
config->region = aws_byte_cursor_from_string(config_data->region);
if (region == NULL) {
AWS_ZERO_STRUCT(config->region);
} else {
config_data->region = aws_jni_new_string_from_jstring(env, region);
config->region = aws_byte_cursor_from_string(config_data->region);
}

jstring service = (jstring)(*env)->GetObjectField(env, java_config, aws_signing_config_properties.service_field_id);
config_data->service = aws_jni_new_string_from_jstring(env, service);
config->service = aws_byte_cursor_from_string(config_data->service);
if (service == NULL) {
AWS_ZERO_STRUCT(config->service);
} else {
config_data->service = aws_jni_new_string_from_jstring(env, service);
config->service = aws_byte_cursor_from_string(config_data->service);
}

int64_t epoch_time_millis = (*env)->GetLongField(env, java_config, aws_signing_config_properties.time_field_id);
aws_date_time_init_epoch_millis(&config->date, (uint64_t)epoch_time_millis);
Expand Down
Loading

0 comments on commit 059730a

Please sign in to comment.