com.qcloud.cos.internal.SkipMd5CheckStrategy Maven / Gradle / Ivy
Show all versions of cos_api Show documentation
package com.qcloud.cos.internal;
import com.qcloud.cos.model.GetObjectRequest;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.UploadPartRequest;
/**
* Logic for determining whether MD5 checksum validation should be performed or not.
*/
public class SkipMd5CheckStrategy {
/**
* System property to disable MD5 validation for GetObject. Any value set for this property will
* disable validation.
*/
public static final String DISABLE_GET_OBJECT_MD5_VALIDATION_PROPERTY =
"com.Qcloud.services.cos.disableGetObjectMD5Validation";
/**
* System property to disable MD5 validation for both PutObject and UploadPart. Any value set
* for this property will disable validation.
*/
public static final String DISABLE_PUT_OBJECT_MD5_VALIDATION_PROPERTY =
"com.Qcloud.services.cos.disablePutObjectMD5Validation";
public static final SkipMd5CheckStrategy INSTANCE = new SkipMd5CheckStrategy();
// Singleton
private SkipMd5CheckStrategy() {}
/**
* Determines whether the client should use the {@link Headers#ETAG} header returned by COS to
* validate the integrity of the message client side based on the server response. We skip the
* client side check if any of the following conditions are true:
*
* - The system property {@value #DISABLE_GET_OBJECT_MD5_VALIDATION_PROPERTY} is set
* - The request involves SSE-C or SSE-KMS
* - The Etag header is missing
* - The Etag indicates that the object was created by a MultiPart Upload
*
*
* @return True if client side validation should be skipped, false otherwise.
*/
public boolean skipClientSideValidationPerGetResponse(ObjectMetadata metadata) {
if (isGetObjectMd5ValidationDisabledByProperty()) {
return true;
}
return skipClientSideValidationPerResponse(metadata);
}
/**
* Determines whether the client should use the {@link Headers#ETAG} header returned by COS to
* validate the integrity of the message client side based on the server response. We skip the
* client side check if any of the following conditions are true:
*
* - The system property {@value #DISABLE_PUT_OBJECT_MD5_VALIDATION_PROPERTY} is set
* - The request involves SSE-C or SSE-KMS
* - The Etag header is missing
*
*
* @return True if client side validation should be skipped, false otherwise.
*/
public boolean skipClientSideValidationPerPutResponse(ObjectMetadata metadata) {
if (isPutObjectMd5ValidationDisabledByProperty()) {
return true;
}
return skipClientSideValidationPerResponse(metadata);
}
/**
* Determines whether the client should use the {@link Headers#ETAG} header returned by COS to
* validate the integrity of the message client side based on the server response. We skip the
* client side check if any of the following conditions are true:
*
* - The system property {@value #DISABLE_PUT_OBJECT_MD5_VALIDATION_PROPERTY} is set
* - The request involves SSE-C or SSE-KMS
* - The Etag header is missing
*
*
* @return True if client side validation should be skipped, false otherwise.
*/
public boolean skipClientSideValidationPerUploadPartResponse(ObjectMetadata metadata) {
return skipClientSideValidationPerPutResponse(metadata);
}
/**
* Conveience method to determine whether to do client side validation of a GetObject call based
* on both the request and the response. See
* {@link #skipClientSideValidationPerRequest(GetObjectRequest)} and
* {@link #skipClientSideValidationPerGetResponse(ObjectMetadata)} for more details on the
* criterion.
*
* @param request Original {@link GetObjectRequest}
* @param returnedMetadata Metadata returned in {@link COSObject}
* @return True if client side validation should be skipped, false otherwise.
*/
/*
public boolean skipClientSideValidation(GetObjectRequest request,
ObjectMetadata returnedMetadata) {
return skipClientSideValidationPerRequest(request)
|| skipClientSideValidationPerGetResponse(returnedMetadata);
}
*/
/**
* Determines whether the client should use the {@link Headers#ETAG} header returned by COS to
* validate the integrity of the message client side. We skip the client side check if any of
* the following conditions are true:
*
* - The system property {@value #DISABLE_PUT_OBJECT_MD5_VALIDATION_PROPERTY} is set
* - The request involves SSE-C or SSE-KMS
*
*
* @return True if client side validation should be skipped, false otherwise.
*/
public boolean skipClientSideValidationPerRequest(PutObjectRequest request) {
if (isPutObjectMd5ValidationDisabledByProperty()) {
return true;
}
return putRequestInvolvesSse(request) || metadataInvolvesSse(request.getMetadata());
}
/**
* Determines whether the client should use the {@link Headers#ETAG} header returned by COS to
* validate the integrity of the message client side. We skip the client side check if any of
* the following conditions are true:
*
* - The system property {@value #DISABLE_PUT_OBJECT_MD5_VALIDATION_PROPERTY} is set
* - The request involves SSE-C or SSE-KMS
*
*
* @return True if client side validation should be skipped, false otherwise.
*/
public boolean skipClientSideValidationPerRequest(UploadPartRequest request) {
if (isPutObjectMd5ValidationDisabledByProperty()) {
return true;
}
return false;
// return request.getSSECustomerKey() != null;
}
/**
* Determines whether the client should calculate and send the {@link Headers#CONTENT_MD5}
* header to be validated by COS per the request.
*
* Currently we always try and do server side validation unless it's been explicitly disabled by
* the {@value #DISABLE_PUT_OBJECT_MD5_VALIDATION_PROPERTY} property. Whether or not we actually
* calculate the MD5 header is determined in the client based on the source of the data (i.e. if
* it's a file we calculate, if not then we don't)
*
*/
public boolean skipServerSideValidation(PutObjectRequest request) {
if (isPutObjectMd5ValidationDisabledByProperty()) {
return true;
}
return false;
}
/**
* Determines whether the client should calculate and send the {@link Headers#CONTENT_MD5}
* header to be validated by COS per the request.
*
* Currently we always try and do server side validation unless it's been explicitly disabled by
* the {@value #DISABLE_PUT_OBJECT_MD5_VALIDATION_PROPERTY} property. Whether or not we actually
* calculate the MD5 header is determined in the client based on the source of the data (i.e. if
* it's a file we calculate, if not then we don't)
*
*/
/*
public boolean skipServerSideValidation(UploadPartRequest request) {
if (isPutObjectMd5ValidationDisabledByProperty()) {
return true;
}
return false;
}
*/
/**
* Based on the given {@link GetObjectRequest}, returns whether the specified request should
* skip MD5 check on the requested object content. Specifically, MD5 check should be skipped if
* one of the following conditions are true:
*
* - The system property {@value #DISABLE_GET_OBJECT_MD5_VALIDATION_PROPERTY} is set.
* - The request is a range-get operation
* - The request is a GET object operation that involves SSE-C
*
* Otherwise, MD5 check should not be skipped.
*/
public boolean skipClientSideValidationPerRequest(GetObjectRequest request) {
if (isGetObjectMd5ValidationDisabledByProperty()) {
return true;
}
// Skip MD5 check for range get
if (request.getRange() != null) {
return true;
}
return false;
}
private boolean skipClientSideValidationPerResponse(ObjectMetadata metadata) {
if (metadata == null) {
return true;
}
// If Etag is not provided or was computed from a multipart upload then skip the check, the
// etag won't be the MD5 of the original content
if (metadata.getETag() == null || isMultipartUploadETag(metadata.getETag())) {
return true;
}
return metadataInvolvesSse(metadata);
}
private boolean isGetObjectMd5ValidationDisabledByProperty() {
return System.getProperty(DISABLE_GET_OBJECT_MD5_VALIDATION_PROPERTY) != null;
}
private boolean isPutObjectMd5ValidationDisabledByProperty() {
return System.getProperty(DISABLE_PUT_OBJECT_MD5_VALIDATION_PROPERTY) != null;
}
/**
* If SSE-C or SSE-KMS is involved then the Etag will be the MD5 of the ciphertext not the
* plaintext so we can't validate it client side. Plain SSE with COS managed keys will return an
* Etag that does match the MD5 of the plaintext so it's still eligible for client side
* validation.
*
* @param metadata Metadata of request or response
* @return True if the metadata indicates that SSE-C or SSE-KMS is used. False otherwise
*/
private boolean metadataInvolvesSse(ObjectMetadata metadata) {
if (metadata == null) {
return false;
}
// return containsNonNull(metadata.getSSECustomerAlgorithm(),
// metadata.getSSECustomerKeyMd5(),
// metadata.getSSECOSKmsKeyId());
return true;
}
/**
* @param request
* @return True if {@link PutObjectRequest} has been configured to use SSE-C or SSE-KMS
*/
private boolean putRequestInvolvesSse(PutObjectRequest request) {
// return containsNonNull(request.getSSECustomerKey(),
// request.getSSECOSKeyManagementParams());
return true;
}
/**
* Returns true if the specified ETag was from a multipart upload.
*
* @param eTag The ETag to test.
* @return True if the specified ETag was from a multipart upload, otherwise false it if belongs
* to an object that was uploaded in a single part.
*/
private static boolean isMultipartUploadETag(String eTag) {
return eTag.contains("-");
}
/**
* Helper method to avoid long chains of non null checks
*
* @param items
* @return True if any of the provided items is not null. False if all items are null.
*/
private static boolean containsNonNull(Object... items) {
for (Object item : items) {
if (item != null) {
return true;
}
}
return false;
}
}