Skip to content
Snippets Groups Projects
Commit 2d01e016 authored by philenius's avatar philenius
Browse files

improve error handling in bucketExists()

Added call of validate() in bucketExists(). Reason: if the request for
checking whether a bucket exists contains invalid credentials (see unit
test), then S3 does not return an XML response. Instead the HTTP
response body is empty. This in turn caused the validate() function
to throw an XML parsing exception which in turn shadowed the original
error. This behavior is different compared to when we list buckets. In
this case, the response contains an HTTP body with a detailed error
message encoded as XML.
parent 7e4a09d3
Branches
Tags
No related merge requests found
......@@ -75,10 +75,13 @@ class Minio {
MinioInvalidBucketNameError.check(bucket);
try {
final response = await _client.request(method: 'HEAD', bucket: bucket);
validate(response);
return (response.statusCode == 200 || response.statusCode == 403);
} on MinioS3Error catch (e) {
final code = e.error.code;
if (code == 'NoSuchBucket' || code == 'NotFound') return false;
if (code == 'NoSuchBucket' || code == 'NotFound' || code == 'Not Found') {
return false;
}
rethrow;
} on StateError catch (e) {
// Insight from testing: in most cases, AWS S3 returns the HTTP status code
......@@ -87,11 +90,11 @@ class Minio {
// status code 404 as officially documented. Then, this redirect response
// lacks the HTTP header `location` which causes this exception in Dart's
// HTTP library (`http_impl.dart`).
if (e.message == 'Response has no Location header for redirect')
if (e.message == 'Response has no Location header for redirect') {
return false;
}
rethrow;
}
return true;
}
int _calculatePartSize(int size) {
......@@ -456,6 +459,7 @@ class Minio {
method: 'GET',
region: region ?? 'us-east-1',
);
validate(resp);
final bucketsNode =
xml.XmlDocument.parse(resp.body).findAllElements('Buckets').first;
return bucketsNode.children.map((n) => Bucket.fromXml(n)).toList();
......
......@@ -217,9 +217,17 @@ Future<void> validateStreamed(
void validate(Response response, {int expect}) {
if (response.statusCode >= 400) {
final body = xml.XmlDocument.parse(response.body);
final error = Error.fromXml(body.rootElement);
throw MinioS3Error(error.message, error, response);
var error;
// Parse HTTP response body as XML only when not empty
if (response.body == null || response.body.isEmpty) {
error = Error(response.reasonPhrase, null, response.reasonPhrase, null);
} else {
final body = xml.XmlDocument.parse(response.body);
error = Error.fromXml(body.rootElement);
}
throw MinioS3Error(error?.message, error, response);
}
if (expect != null && response.statusCode != expect) {
......
......@@ -39,6 +39,58 @@ void main() {
);
});
});
group('bucketExists', () {
final bucketName = DateTime.now().millisecondsSinceEpoch.toString();
setUpAll(() async {
final minio = _getClient();
await minio.makeBucket(bucketName);
});
tearDownAll(() async {
final minio = _getClient();
await minio.removeBucket(bucketName);
});
test('bucketExists() returns true for an existing bucket', () async {
final minio = _getClient();
expect(await minio.bucketExists(bucketName), equals(true));
});
test('bucketExists() returns false for a non-existent bucket', () async {
final minio = _getClient();
expect(await minio.bucketExists('non-existing-bucket-name'), equals(false));
});
test('bucketExists() fails due to wrong access key', () async {
final minio = _getClient(accessKey: 'incorrect-access-key');
expect(
() async => await minio.bucketExists(bucketName),
throwsA(
isA<MinioError>().having(
(e) => e.message,
'message',
'Forbidden',
),
),
);
});
test('bucketExists() fails due to wrong secret key', () async {
final minio = _getClient(secretKey: 'incorrect-secret-key');
expect(
() async => await minio.bucketExists(bucketName),
throwsA(
isA<MinioError>().having(
(e) => e.message,
'message',
'Forbidden',
),
),
);
});
});
}
/// Initializes an instance of [Minio] with per default valid configuration.
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment