feat(S3): add error handling
This commit is contained in:
parent
68203fb88a
commit
13b9fbedf5
@ -0,0 +1,22 @@
|
||||
package org.cryptomator.data.cloud.s3;
|
||||
|
||||
public enum S3CloudApiErrorCodes {
|
||||
ACCESS_DENIED("AccessDenied"),
|
||||
ACCOUNT_PROBLEM("AccountProblem"),
|
||||
INTERNAL_ERROR("InternalError"),
|
||||
INVALID_ACCESS_KEY_ID("InvalidAccessKeyId"),
|
||||
INVALID_BUCKET_NAME("InvalidBucketName"),
|
||||
INVALID_OBJECT_STATE("InvalidObjectState"),
|
||||
NO_SUCH_BUCKET("NoSuchBucket"),
|
||||
NO_SUCH_KEY("NoSuchKey");
|
||||
|
||||
private final String value;
|
||||
|
||||
S3CloudApiErrorCodes(final String newValue) {
|
||||
value = newValue;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
@ -2,18 +2,13 @@ package org.cryptomator.data.cloud.s3;
|
||||
|
||||
public class S3CloudApiExceptions {
|
||||
|
||||
public enum S3CloudApiErrorCodes {
|
||||
NO_SUCH_BUCKET("NoSuchBucket");
|
||||
|
||||
private final String value;
|
||||
|
||||
S3CloudApiErrorCodes(final String newValue) {
|
||||
value = newValue;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
public static boolean isAccessProblem(String errorCode) {
|
||||
return errorCode.equals(S3CloudApiErrorCodes.ACCESS_DENIED.getValue())
|
||||
|| errorCode.equals(S3CloudApiErrorCodes.ACCOUNT_PROBLEM.getValue())
|
||||
|| errorCode.equals(S3CloudApiErrorCodes.INVALID_ACCESS_KEY_ID.getValue());
|
||||
}
|
||||
|
||||
public static boolean isNoSuchBucketException(String errorCode) {
|
||||
return errorCode.equals(S3CloudApiErrorCodes.NO_SUCH_BUCKET.getValue());
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,14 @@ package org.cryptomator.data.cloud.s3;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.amazonaws.services.s3.model.AmazonS3Exception;
|
||||
|
||||
import org.cryptomator.data.cloud.InterceptingCloudContentRepository;
|
||||
import org.cryptomator.domain.S3Cloud;
|
||||
import org.cryptomator.domain.exception.BackendException;
|
||||
import org.cryptomator.domain.exception.FatalBackendException;
|
||||
import org.cryptomator.domain.exception.NetworkConnectionException;
|
||||
import org.cryptomator.domain.exception.NoSuchBucketException;
|
||||
import org.cryptomator.domain.exception.authentication.WrongCredentialsException;
|
||||
import org.cryptomator.domain.repository.CloudContentRepository;
|
||||
import org.cryptomator.domain.usecases.ProgressAware;
|
||||
@ -31,29 +34,36 @@ class S3CloudContentRepository extends InterceptingCloudContentRepository<S3Clou
|
||||
this.cloud = cloud;
|
||||
}
|
||||
|
||||
//TODO: add proper error handling
|
||||
|
||||
@Override
|
||||
protected void throwWrappedIfRequired(Exception e) throws BackendException {
|
||||
// throwConnectionErrorIfRequired(e);
|
||||
// throwWrongCredentialsExceptionIfRequired(e);
|
||||
throwNoSuchBucketExceptionIfRequired(e);
|
||||
throwConnectionErrorIfRequired(e);
|
||||
throwWrongCredentialsExceptionIfRequired(e);
|
||||
}
|
||||
|
||||
// private void throwConnectionErrorIfRequired(Exception e) throws NetworkConnectionException {
|
||||
// if (contains(e, IOException.class)) {
|
||||
// throw new NetworkConnectionException(e);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void throwWrongCredentialsExceptionIfRequired(Exception e) {
|
||||
// if (e instanceof ApiError) {
|
||||
// int errorCode = ((ApiError) e).errorCode();
|
||||
// if (errorCode == PCloudApiError.PCloudApiErrorCodes.INVALID_ACCESS_TOKEN.getValue() //
|
||||
// || errorCode == PCloudApiError.PCloudApiErrorCodes.ACCESS_TOKEN_REVOKED.getValue()) {
|
||||
// throw new WrongCredentialsException(cloud);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
private void throwNoSuchBucketExceptionIfRequired(Exception e) throws NoSuchBucketException {
|
||||
if (e instanceof AmazonS3Exception) {
|
||||
String errorCode = ((AmazonS3Exception)e).getErrorCode();
|
||||
if(S3CloudApiExceptions.isNoSuchBucketException(errorCode)) {
|
||||
throw new NoSuchBucketException(cloud.s3Bucket());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void throwConnectionErrorIfRequired(Exception e) throws NetworkConnectionException {
|
||||
if (contains(e, IOException.class)) {
|
||||
throw new NetworkConnectionException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void throwWrongCredentialsExceptionIfRequired(Exception e) {
|
||||
if (e instanceof AmazonS3Exception) {
|
||||
String errorCode = ((AmazonS3Exception) e).getErrorCode();
|
||||
if (S3CloudApiExceptions.isAccessProblem(errorCode)) {
|
||||
throw new WrongCredentialsException(cloud);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Intercepted implements CloudContentRepository<S3Cloud, S3Node, S3Folder, S3File> {
|
||||
|
||||
|
@ -8,6 +8,7 @@ import com.amazonaws.mobileconnectors.s3.transferutility.TransferState;
|
||||
import com.amazonaws.mobileconnectors.s3.transferutility.TransferUtility;
|
||||
import com.amazonaws.mobileconnectors.s3.transferutility.UploadOptions;
|
||||
import com.amazonaws.services.s3.AmazonS3;
|
||||
import com.amazonaws.services.s3.model.AmazonS3Exception;
|
||||
import com.amazonaws.services.s3.model.CopyObjectResult;
|
||||
import com.amazonaws.services.s3.model.DeleteObjectsRequest;
|
||||
import com.amazonaws.services.s3.model.DeleteObjectsRequest.KeyVersion;
|
||||
@ -26,8 +27,10 @@ import org.cryptomator.domain.S3Cloud;
|
||||
import org.cryptomator.domain.exception.BackendException;
|
||||
import org.cryptomator.domain.exception.CloudNodeAlreadyExistsException;
|
||||
import org.cryptomator.domain.exception.FatalBackendException;
|
||||
import org.cryptomator.domain.exception.ForbiddenException;
|
||||
import org.cryptomator.domain.exception.NoSuchBucketException;
|
||||
import org.cryptomator.domain.exception.NoSuchCloudFileException;
|
||||
import org.cryptomator.domain.exception.UnauthorizedException;
|
||||
import org.cryptomator.domain.exception.authentication.WrongCredentialsException;
|
||||
import org.cryptomator.domain.usecases.ProgressAware;
|
||||
import org.cryptomator.domain.usecases.cloud.DataSource;
|
||||
@ -46,6 +49,7 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
@ -161,8 +165,12 @@ class S3Impl {
|
||||
|
||||
InputStream emptyContent = new ByteArrayInputStream(new byte[0]);
|
||||
|
||||
PutObjectRequest putObjectRequest = new PutObjectRequest(cloud.s3Bucket(), folder.getKey(), emptyContent, metadata);
|
||||
client().putObject(putObjectRequest);
|
||||
try {
|
||||
PutObjectRequest putObjectRequest = new PutObjectRequest(cloud.s3Bucket(), folder.getKey(), emptyContent, metadata);
|
||||
client().putObject(putObjectRequest);
|
||||
} catch(AmazonS3Exception ex) {
|
||||
handleApiError(ex, folder.getName());
|
||||
}
|
||||
|
||||
return S3CloudNodeFactory.folder(folder.getParent(), folder.getName());
|
||||
}
|
||||
@ -206,10 +214,14 @@ class S3Impl {
|
||||
|
||||
final CompletableFuture<Optional<ObjectMetadata>> result = new CompletableFuture<>();
|
||||
|
||||
if (size <= CHUNKED_UPLOAD_MAX_SIZE) {
|
||||
uploadFile(file, data, progressAware, result, size);
|
||||
} else {
|
||||
uploadChunkedFile(file, data, progressAware, result, size);
|
||||
try {
|
||||
if (size <= CHUNKED_UPLOAD_MAX_SIZE) {
|
||||
uploadFile(file, data, progressAware, result, size);
|
||||
} else {
|
||||
uploadChunkedFile(file, data, progressAware, result, size);
|
||||
}
|
||||
} catch(AmazonS3Exception ex) {
|
||||
handleApiError(ex, file.getName());
|
||||
}
|
||||
|
||||
try {
|
||||
@ -336,16 +348,20 @@ class S3Impl {
|
||||
GetObjectRequest request = new GetObjectRequest(cloud.s3Bucket(), file.getPath());
|
||||
request.setGeneralProgressListener(listener);
|
||||
|
||||
S3Object s3Object = client().getObject(request);
|
||||
try {
|
||||
S3Object s3Object = client().getObject(request);
|
||||
|
||||
CopyStream.copyStreamToStream(s3Object.getObjectContent(), data);
|
||||
CopyStream.copyStreamToStream(s3Object.getObjectContent(), data);
|
||||
|
||||
if (sharedPreferencesHandler.useLruCache() && encryptedTmpFile.isPresent() && cacheKey.isPresent()) {
|
||||
try {
|
||||
storeToLruCache(diskLruCache, cacheKey.get(), encryptedTmpFile.get());
|
||||
} catch (IOException e) {
|
||||
Timber.tag("S3Impl").e(e, "Failed to write downloaded file in LRU cache");
|
||||
if (sharedPreferencesHandler.useLruCache() && encryptedTmpFile.isPresent() && cacheKey.isPresent()) {
|
||||
try {
|
||||
storeToLruCache(diskLruCache, cacheKey.get(), encryptedTmpFile.get());
|
||||
} catch (IOException e) {
|
||||
Timber.tag("S3Impl").e(e, "Failed to write downloaded file in LRU cache");
|
||||
}
|
||||
}
|
||||
} catch(AmazonS3Exception ex) {
|
||||
handleApiError(ex, file.getName());
|
||||
}
|
||||
|
||||
}
|
||||
@ -386,4 +402,17 @@ class S3Impl {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void handleApiError(AmazonS3Exception ex, String name) throws BackendException {
|
||||
String errorCode = ex.getErrorCode();
|
||||
if (S3CloudApiExceptions.isAccessProblem(errorCode)) {
|
||||
throw new ForbiddenException();
|
||||
} else if (S3CloudApiErrorCodes.NO_SUCH_BUCKET.getValue().equals(errorCode)) {
|
||||
throw new NoSuchBucketException(name);
|
||||
} else if (S3CloudApiErrorCodes.NO_SUCH_KEY.getValue().equals(errorCode)) {
|
||||
throw new NoSuchCloudFileException(name);
|
||||
} else {
|
||||
throw new FatalBackendException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user