diff --git a/FileUploader/FileUploader.csproj b/FileUploader/FileUploader.csproj index 6e374e2210..728fdd2557 100644 --- a/FileUploader/FileUploader.csproj +++ b/FileUploader/FileUploader.csproj @@ -1,6 +1,6 @@  - net6.0;net8.0 + net8.0 Exe False diff --git a/Minio.Examples/Minio.Examples.csproj b/Minio.Examples/Minio.Examples.csproj index fbf8de9328..41c3f9c2f8 100644 --- a/Minio.Examples/Minio.Examples.csproj +++ b/Minio.Examples/Minio.Examples.csproj @@ -1,6 +1,6 @@ - net6.0;net8.0; + net8.0; Exe False diff --git a/Minio.Functional.Tests/FunctionalTest.cs b/Minio.Functional.Tests/FunctionalTest.cs index 262769a2e2..fcdf903852 100644 --- a/Minio.Functional.Tests/FunctionalTest.cs +++ b/Minio.Functional.Tests/FunctionalTest.cs @@ -371,21 +371,29 @@ internal static async Task BucketExists_Test(IMinioClient minio) await minio.RemoveBucketAsync(rbArgs).ConfigureAwait(false); var found = await minio.BucketExistsAsync(beArgs).ConfigureAwait(false); - Assert.IsFalse(found); + if (found) + throw new Exception("BucketExistsAsync api failed to return false for a non-existing bucket"); + await minio.MakeBucketAsync(mbArgs).ConfigureAwait(false); found = await minio.BucketExistsAsync(beArgs).ConfigureAwait(false); - Assert.IsTrue(found); - new MintLogger(nameof(BucketExists_Test), bucketExistsSignature, "Tests whether BucketExists passes", + + if (!found) + throw new Exception("BucketExistsAsync api failed to return true for an existing bucket"); + + new MintLogger(nameof(BucketExists_Test), bucketExistsSignature, + "Tests whether BucketExistsAsync api passes", TestStatus.PASS, DateTime.Now - startTime, args: args).Log(); } catch (NotImplementedException ex) { - new MintLogger(nameof(BucketExists_Test), bucketExistsSignature, "Tests whether BucketExists passes", + new MintLogger(nameof(BucketExists_Test), bucketExistsSignature, + "Tests whether BucketExistsAsync api passes", TestStatus.NA, DateTime.Now - startTime, ex.Message, ex.ToString(), args: args).Log(); } catch (Exception ex) { - new MintLogger(nameof(BucketExists_Test), bucketExistsSignature, "Tests whether BucketExists passes", + new MintLogger(nameof(BucketExists_Test), bucketExistsSignature, + "Tests whether BucketExistsAsync api passes", TestStatus.FAIL, DateTime.Now - startTime, ex.Message, ex.ToString(), args: args).Log(); throw; } @@ -491,6 +499,7 @@ internal static async Task ListBuckets_Test(IMinioClient minio) IList bucketList = new List(); var bucketNameSuffix = "listbucketstest"; var noOfBuckets = 5; + IList bucketListStripped = new List(); var args = new Dictionary (StringComparer.Ordinal) @@ -520,21 +529,28 @@ internal static async Task ListBuckets_Test(IMinioClient minio) { var list = await minio.ListBucketsAsync().ConfigureAwait(false); bucketList = list.Buckets; - bucketList = bucketList.Where(x => x.Name.EndsWith(bucketNameSuffix, StringComparison.OrdinalIgnoreCase)) + bucketListStripped = bucketList + .Where(x => x.Name.EndsWith(bucketNameSuffix, StringComparison.OrdinalIgnoreCase)) .ToList(); - Assert.AreEqual(noOfBuckets, bucketList.Count); - bucketList.ToList().Sort((x, y) => - { - if (string.Equals(x.Name, y.Name, StringComparison.Ordinal)) return 0; - if (x.Name is null) return -1; - if (y.Name is null) return 1; - return string.Compare(x.Name, y.Name, StringComparison.Ordinal); - }); - var indx = 0; - foreach (var bucket in bucketList) - { - indx++; - Assert.AreEqual("bucket" + indx + bucketNameSuffix, bucket.Name); + Assert.AreEqual(noOfBuckets, bucketListStripped.Count); + if (bucketListStripped.Count > 1) + { + bucketListStripped.ToList().Sort((x, y) => + { + return string.Equals(x.Name, y.Name, StringComparison.Ordinal) + ? 0 + : x.Name is null + ? -1 + : y.Name is null + ? 1 + : string.CompareOrdinal(x.Name, y.Name); + }); + var indx = 0; + foreach (var bucket in bucketListStripped) + { + indx++; + Assert.AreEqual("bucket" + indx + bucketNameSuffix, bucket.Name); + } } new MintLogger(nameof(ListBuckets_Test), listBucketsSignature, "Tests whether ListBucket passes", @@ -548,26 +564,25 @@ internal static async Task ListBuckets_Test(IMinioClient minio) } finally { - foreach (var bucket in bucketList) - { - var rbArgs = new RemoveBucketArgs() - .WithBucket(bucket.Name); - await minio.RemoveBucketAsync(rbArgs).ConfigureAwait(false); - } + foreach (var bucket in bucketListStripped) await TearDown(minio, bucket.Name).ConfigureAwait(false); } } internal static async Task Setup_Test(IMinioClient minio, string bucketName) { + var source = new CancellationTokenSource(); var beArgs = new BucketExistsArgs() .WithBucket(bucketName); - if (await minio.BucketExistsAsync(beArgs).ConfigureAwait(false)) - return; - var mbArgs = new MakeBucketArgs() - .WithBucket(bucketName); - await minio.MakeBucketAsync(mbArgs).ConfigureAwait(false); - var found = await minio.BucketExistsAsync(beArgs).ConfigureAwait(false); - Assert.IsTrue(found); + var found = await minio.BucketExistsAsync(beArgs, source.Token).ConfigureAwait(false); + if (!found) + { + var mbArgs = new MakeBucketArgs() + .WithBucket(bucketName); + await minio.MakeBucketAsync(mbArgs, source.Token).ConfigureAwait(false); + found = await minio.BucketExistsAsync(beArgs, source.Token).ConfigureAwait(false); + if (!found) + throw new BucketNotFoundException(); + } } internal static async Task Setup_WithLock_Test(IMinioClient minio, string bucketName) @@ -579,104 +594,122 @@ internal static async Task Setup_WithLock_Test(IMinioClient minio, string bucket .WithBucket(bucketName); await minio.MakeBucketAsync(mbArgs).ConfigureAwait(false); var found = await minio.BucketExistsAsync(beArgs).ConfigureAwait(false); - Assert.IsTrue(found); + if (!found) + throw new BucketNotFoundException(); } internal static async Task TearDown(IMinioClient minio, string bucketName) { + var source = new CancellationTokenSource(); + bool found; var beArgs = new BucketExistsArgs() .WithBucket(bucketName); - var bktExists = await minio.BucketExistsAsync(beArgs).ConfigureAwait(false); - if (!bktExists) - return; - var getVersions = false; - // Get Versioning/Retention Info. - var lockConfigurationArgs = - new GetObjectLockConfigurationArgs() - .WithBucket(bucketName); - ObjectLockConfiguration lockConfig = null; try { - var versioningConfig = await minio.GetVersioningAsync(new GetVersioningArgs() - .WithBucket(bucketName) - .WithVersions(true)).ConfigureAwait(false); - if (versioningConfig is not null && - (versioningConfig.Status.Contains("Enabled", StringComparison.Ordinal) || - versioningConfig.Status.Contains("Suspended", StringComparison.Ordinal))) - getVersions = true; - - lockConfig = await minio.GetObjectLockConfigurationAsync(lockConfigurationArgs).ConfigureAwait(false); - } - catch (MissingObjectLockConfigurationException) - { - // This exception is expected for those buckets created without a lock. + found = await minio.BucketExistsAsync(beArgs, source.Token).ConfigureAwait(false); + if (!found) await source.CancelAsync().ConfigureAwait(false); } - catch (NotImplementedException) + catch (Exception ex) when (ex is TaskCanceledException) { - // No throw. Move to the next step without versions. + // do nothing + return; } - var tasks = new List(); - var listObjectsArgs = new ListObjectsArgs() - .WithBucket(bucketName) - .WithRecursive(true) - .WithVersions(getVersions); - - var objectNamesVersions = new List>(); - var objectNames = new List(); - await foreach (var item in minio.ListObjectsEnumAsync(listObjectsArgs).ConfigureAwait(false)) - if (getVersions) - objectNamesVersions.Add(new Tuple(item.Key, item.VersionId)); - else - objectNames.Add(item.Key); - - if (lockConfig?.ObjectLockEnabled.Equals(ObjectLockConfiguration.LockEnabled, - StringComparison.OrdinalIgnoreCase) == true) + if (found) { - foreach (var item in objectNamesVersions) + var getVersions = false; + // Get Versioning/Retention Info. + var lockConfigurationArgs = + new GetObjectLockConfigurationArgs() + .WithBucket(bucketName); + ObjectLockConfiguration lockConfig = null; + try { - var objectRetentionArgs = new GetObjectRetentionArgs() - .WithBucket(bucketName) - .WithObject(item.Item1) - .WithVersionId(item.Item2); - var retentionConfig = await minio.GetObjectRetentionAsync(objectRetentionArgs).ConfigureAwait(false); - var bypassGovMode = retentionConfig.Mode == ObjectRetentionMode.GOVERNANCE; - var removeObjectArgs = new RemoveObjectArgs() + var versioningConfig = await minio.GetVersioningAsync(new GetVersioningArgs() .WithBucket(bucketName) - .WithObject(item.Item1) - .WithVersionId(item.Item2); - if (bypassGovMode) - removeObjectArgs = removeObjectArgs.WithBypassGovernanceMode(bypassGovMode); - var t = minio.RemoveObjectAsync(removeObjectArgs); - tasks.Add(t); + .WithVersions(true), source.Token).ConfigureAwait(false); + if (versioningConfig is not null && + (versioningConfig.Status.Contains("Enabled", StringComparison.Ordinal) || + versioningConfig.Status.Contains("Suspended", StringComparison.Ordinal))) + getVersions = true; + + lockConfig = await minio.GetObjectLockConfigurationAsync(lockConfigurationArgs, source.Token) + .ConfigureAwait(false); } - } - else - { - if (objectNamesVersions.Count > 0) + catch (MissingObjectLockConfigurationException) { - var removeObjectArgs = new RemoveObjectsArgs() - .WithBucket(bucketName) - .WithObjectsVersions(objectNamesVersions); - Task t = minio.RemoveObjectsAsync(removeObjectArgs); - tasks.Add(t); + // This exception is expected for those buckets created without a lock. + } + catch (NotImplementedException) + { + // No throw. Move to the next step without versions. } - if (objectNames.Count > 0) + var tasks = new List(); + var listObjectsArgs = new ListObjectsArgs() + .WithBucket(bucketName) + .WithRecursive(true) + .WithVersions(getVersions); + + var objectNamesVersions = new List>(); + + var objectNames = new List(); + var listObjects = minio.ListObjectsEnumAsync(listObjectsArgs, source.Token); + await foreach (var item in listObjects.WithCancellation(source.Token).ConfigureAwait(false)) + if (getVersions) + objectNamesVersions.Add(new Tuple(item.Key, item.VersionId)); + else + objectNames.Add(item.Key); + + if (lockConfig?.ObjectLockEnabled.Equals(ObjectLockConfiguration.LockEnabled, + StringComparison.OrdinalIgnoreCase) == true) { - var removeObjectArgs = new RemoveObjectsArgs() - .WithBucket(bucketName) - .WithObjects(objectNames); + foreach (var item in objectNamesVersions) + { + var objectRetentionArgs = new GetObjectRetentionArgs() + .WithBucket(bucketName) + .WithObject(item.Item1) + .WithVersionId(item.Item2); + var retentionConfig = + await minio.GetObjectRetentionAsync(objectRetentionArgs).ConfigureAwait(false); + var bypassGovMode = retentionConfig.Mode == ObjectRetentionMode.GOVERNANCE; + var removeObjectArgs = new RemoveObjectArgs() + .WithBucket(bucketName) + .WithObject(item.Item1) + .WithVersionId(item.Item2); + if (bypassGovMode) + removeObjectArgs = removeObjectArgs.WithBypassGovernanceMode(bypassGovMode); + var t = minio.RemoveObjectAsync(removeObjectArgs); + tasks.Add(t); + } + } + else + { + if (objectNamesVersions.Count > 0) + { + var removeObjectArgs = new RemoveObjectsArgs() + .WithBucket(bucketName) + .WithObjectsVersions(objectNamesVersions); + Task t = minio.RemoveObjectsAsync(removeObjectArgs); + tasks.Add(t); + } - Task t = minio.RemoveObjectsAsync(removeObjectArgs); - tasks.Add(t); + if (objectNames.Count > 0) + { + var removeObjectArgs = new RemoveObjectsArgs() + .WithBucket(bucketName) + .WithObjects(objectNames); + + Task t = minio.RemoveObjectsAsync(removeObjectArgs); + tasks.Add(t); + } } - } - await Task.WhenAll(tasks).ConfigureAwait(false); - var rbArgs = new RemoveBucketArgs() - .WithBucket(bucketName); - await minio.RemoveBucketAsync(rbArgs).ConfigureAwait(false); + await Task.WhenAll(tasks).ConfigureAwait(false); + var rbArgs = new RemoveBucketArgs() + .WithBucket(bucketName); + await minio.RemoveBucketAsync(rbArgs).ConfigureAwait(false); + } } internal static string XmlStrToJsonStr(string xml) @@ -771,7 +804,6 @@ internal static async Task PutGetStatEncryptedObject_Test1(IMinioClient minio) new MintLogger("PutGetStatEncryptedObject_Test1", putObjectSignature, "Tests whether Put/Get/Stat Object with encryption passes", TestStatus.FAIL, DateTime.Now - startTime, "", ex.Message, ex.ToString(), args).Log(); - throw; } finally { @@ -848,26 +880,23 @@ internal static async Task PutGetStatEncryptedObject_Test2(IMinioClient minio) new MintLogger("PutGetStatEncryptedObject_Test2", putObjectSignature, "Tests whether Put/Get/Stat multipart upload with encryption passes", TestStatus.PASS, DateTime.Now - startTime, args: args).Log(); - File.Delete(tempFileName); - await TearDown(minio, bucketName).ConfigureAwait(false); } catch (NotImplementedException ex) { new MintLogger("PutGetStatEncryptedObject_Test2", putObjectSignature, "Tests whether Put/Get/Stat multipart upload with encryption passes", TestStatus.NA, DateTime.Now - startTime, "", ex.Message, ex.ToString(), args).Log(); - File.Delete(tempFileName); - await TearDown(minio, bucketName).ConfigureAwait(false); - throw; } catch (Exception ex) { new MintLogger("PutGetStatEncryptedObject_Test2", putObjectSignature, "Tests whether Put/Get/Stat multipart upload with encryption passes", TestStatus.FAIL, DateTime.Now - startTime, "", ex.Message, ex.ToString(), args).Log(); + } + finally + { File.Delete(tempFileName); await TearDown(minio, bucketName).ConfigureAwait(false); - throw; } } @@ -939,7 +968,6 @@ internal static async Task PutGetStatEncryptedObject_Test3(IMinioClient minio) new MintLogger("PutGetStatEncryptedObject_Test3", putObjectSignature, "Tests whether Put/Get/Stat multipart upload with encryption passes", TestStatus.FAIL, DateTime.Now - startTime, "", ex.Message, ex.ToString(), args).Log(); - throw; } finally { @@ -985,7 +1013,7 @@ internal static async Task PutObject_Task(IMinioClient minio, string bucketName, internal static async Task PutObject_Tester(IMinioClient minio, string bucketName, string objectName, string fileName = null, - string contentType = "application/octet-stream", long size = 0, + string contentType = null, long size = 0, Dictionary metaData = null, Stream mstream = null, IProgress progress = null) { @@ -1007,7 +1035,6 @@ internal static async Task PutObject_Tester(IMinioClient minio, { var file_write_size = filestream.Length; var tempFileName = "tempfile-" + GetRandomName(); - if (size == 0) size = filestream.Length; var putObjectArgs = new PutObjectArgs() .WithBucket(bucketName) .WithObject(objectName) @@ -1040,12 +1067,13 @@ internal static async Task PutObject_Tester(IMinioClient minio, internal static async Task CreateBucket_Tester(IMinioClient minio, string bucketName) { // Create a new bucket - await minio.MakeBucketAsync(new MakeBucketArgs().WithBucket(bucketName)).ConfigureAwait(false); + await minio.MakeBucketAsync(new MakeBucketArgs() + .WithBucket(bucketName)).ConfigureAwait(false); await Task.Delay(800).ConfigureAwait(false); // Verify the bucket exists - return await minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucketName)) - .ConfigureAwait(false); + return await minio.BucketExistsAsync(new BucketExistsArgs() + .WithBucket(bucketName)).ConfigureAwait(false); } internal static async Task StatObject_Test1(IMinioClient minio) @@ -1068,7 +1096,7 @@ internal static async Task StatObject_Test1(IMinioClient minio) try { await Setup_Test(minio, bucketName).ConfigureAwait(false); - _ = await PutObject_Tester(minio, bucketName, objectName, null, null, 0, null, + _ = await PutObject_Tester(minio, bucketName, objectName, null, null, 1 * KB, null, rsg.GenerateStreamFromSeed(1 * KB)).ConfigureAwait(false); new MintLogger(nameof(StatObject_Test1), statObjectSignature, "Tests whether StatObject passes", TestStatus.PASS, DateTime.Now - startTime, args: args).Log(); @@ -1391,7 +1419,6 @@ internal static async Task PresignedPostPolicy_Test1(IMinioClient minio) new MintLogger("PresignedPostPolicy_Test1", presignedPostPolicySignature, "Tests whether PresignedPostPolicy url applies policy on server", TestStatus.FAIL, DateTime.Now - startTime, ex.Message, ex.ToString(), args: args).Log(); - throw; } finally { @@ -1414,9 +1441,9 @@ internal static async Task RemoveIncompleteUpload_Test(IMinioClient minio) await Setup_Test(minio, bucketName).ConfigureAwait(false); using var cts = new CancellationTokenSource(); cts.CancelAfter(TimeSpan.FromMilliseconds(2)); - try + var filestream = rsg.GenerateStreamFromSeed(30 * MB); + await using (filestream.ConfigureAwait(false)) { - using var filestream = rsg.GenerateStreamFromSeed(30 * MB); var file_write_size = filestream.Length; var putObjectArgs = new PutObjectArgs() @@ -1426,39 +1453,39 @@ internal static async Task RemoveIncompleteUpload_Test(IMinioClient minio) .WithObjectSize(filestream.Length) .WithContentType(contentType); _ = await minio.PutObjectAsync(putObjectArgs, cts.Token).ConfigureAwait(false); + + new MintLogger("RemoveIncompleteUpload_Test", removeIncompleteUploadSignature, + "Tests whether RemoveIncompleteUpload passes.", TestStatus.PASS, DateTime.Now - startTime, + args: args).Log(); } - catch (OperationCanceledException) - { - var rmArgs = new RemoveIncompleteUploadArgs() - .WithBucket(bucketName) - .WithObject(objectName); + } + catch (Exception ex) when (ex.GetType() == typeof(TaskCanceledException)) + { + var rmArgs = new RemoveIncompleteUploadArgs() + .WithBucket(bucketName) + .WithObject(objectName); - await minio.RemoveIncompleteUploadAsync(rmArgs).ConfigureAwait(false); + await minio.RemoveIncompleteUploadAsync(rmArgs).ConfigureAwait(false); - try - { - var listArgs = new ListIncompleteUploadsArgs() - .WithBucket(bucketName); - await foreach (var item in minio.ListIncompleteUploadsEnumAsync(listArgs).ConfigureAwait(false)) - Assert.Fail(); - } - catch (Exception) - { - Assert.Fail(); - } - } + var listArgs = new ListIncompleteUploadsArgs() + .WithBucket(bucketName); + // Check if all incomplete upload objects are cleaned up + await foreach (var item in minio.ListIncompleteUploadsEnumAsync(listArgs).ConfigureAwait(false)) + if (item.Key.Equals(objectName, StringComparison.Ordinal)) + new MintLogger("RemoveIncompleteUpload_Test", removeIncompleteUploadSignature, + "Tests whether RemoveIncompleteUpload passes.", TestStatus.FAIL, DateTime.Now - startTime, + ex.Message, + ex.ToString(), args: args).Log(); new MintLogger("RemoveIncompleteUpload_Test", removeIncompleteUploadSignature, - "Tests whether RemoveIncompleteUpload passes.", TestStatus.PASS, DateTime.Now - startTime, - args: args) - .Log(); + "Tests whether RemoveIncompleteUpload passes.", TestStatus.PASS, DateTime.Now - startTime, + args: args).Log(); } catch (Exception ex) { new MintLogger("RemoveIncompleteUpload_Test", removeIncompleteUploadSignature, "Tests whether RemoveIncompleteUpload passes.", TestStatus.FAIL, DateTime.Now - startTime, ex.Message, ex.ToString(), args: args).Log(); - throw; } finally { @@ -2964,15 +2991,11 @@ internal static async Task ListenBucketNotificationsAsync_Test3(IMinioClient min ex => exception = ex, () => { }); - // Sleep to give enough time for the subscriber to be ready - var sleepTime = 1000; // Milliseconds - await Task.Delay(sleepTime).ConfigureAwait(false); - _ = await minio.PutObjectAsync(putObjectArgs).ConfigureAwait(false); var stTime = DateTime.UtcNow; - var waitTime = 25; // Milliseconds - var timeout = 3000; // Milliseconds + var waitTime = 5; // Milliseconds + var timeout = 6000; // Milliseconds while (string.IsNullOrEmpty(rxEventData.Json)) { await Task.Delay(waitTime).ConfigureAwait(false); @@ -3229,30 +3252,30 @@ internal static async Task PutObject_Test1(IMinioClient minio) var bucketName = GetRandomName(15); var objectName = GetRandomObjectName(10); var contentType = "image/png"; - var size = 1 * MB; + var size = 0; var args = new Dictionary (StringComparer.Ordinal) { { "bucketName", bucketName }, { "objectName", objectName }, { "contentType", contentType }, - { "size", "1MB" } + { "size", "0" } }; try { await Setup_Test(minio, bucketName).ConfigureAwait(false); - var resp = await PutObject_Tester(minio, bucketName, objectName, null, contentType, 0, null, + var resp = await PutObject_Tester(minio, bucketName, objectName, null, contentType, size, null, rsg.GenerateStreamFromSeed(size)).ConfigureAwait(false); Assert.AreEqual(size, resp.Size); Assert.AreEqual(objectName, objectName); new MintLogger(nameof(PutObject_Test1), putObjectSignature, - "Tests whether PutObject passes for small object", TestStatus.PASS, DateTime.Now - startTime, + "Tests whether PutObject passes for zero sized object", TestStatus.PASS, DateTime.Now - startTime, args: args).Log(); } catch (Exception ex) { new MintLogger(nameof(PutObject_Test1), putObjectSignature, - "Tests whether PutObject passes for small object", TestStatus.FAIL, DateTime.Now - startTime, "", + "Tests whether PutObject passes for zero sized object", TestStatus.FAIL, DateTime.Now - startTime, "", ex.Message, ex.ToString(), args).Log(); throw; } @@ -3279,7 +3302,7 @@ internal static async Task PutObject_Test2(IMinioClient minio) try { await Setup_Test(minio, bucketName).ConfigureAwait(false); - _ = await PutObject_Tester(minio, bucketName, objectName, null, contentType, 0, null, + _ = await PutObject_Tester(minio, bucketName, objectName, null, contentType, 6 * MB, null, rsg.GenerateStreamFromSeed(6 * MB)).ConfigureAwait(false); new MintLogger(nameof(PutObject_Test2), putObjectSignature, "Tests whether multipart PutObject passes", TestStatus.PASS, DateTime.Now - startTime, args: args).Log(); @@ -3314,7 +3337,7 @@ internal static async Task PutObject_Test3(IMinioClient minio) try { await Setup_Test(minio, bucketName).ConfigureAwait(false); - _ = await PutObject_Tester(minio, bucketName, objectName, null, contentType, 0, null, + _ = await PutObject_Tester(minio, bucketName, objectName, null, contentType, 1 * MB, null, rsg.GenerateStreamFromSeed(1 * MB)).ConfigureAwait(false); new MintLogger(nameof(PutObject_Test3), putObjectSignature, "Tests whether PutObject with custom content-type passes", TestStatus.PASS, DateTime.Now - startTime, @@ -3356,7 +3379,7 @@ internal static async Task PutObject_Test4(IMinioClient minio) { await Setup_Test(minio, bucketName).ConfigureAwait(false); var statObject = - await PutObject_Tester(minio, bucketName, objectName, fileName, contentType, metaData: metaData) + await PutObject_Tester(minio, bucketName, objectName, fileName, contentType, 1, metaData) .ConfigureAwait(false); Assert.IsTrue(statObject is not null); Assert.IsTrue(statObject.MetaData is not null); @@ -3396,7 +3419,7 @@ internal static async Task PutObject_Test5(IMinioClient minio) try { await Setup_Test(minio, bucketName).ConfigureAwait(false); - _ = await PutObject_Tester(minio, bucketName, objectName, null, null, 0, null, + _ = await PutObject_Tester(minio, bucketName, objectName, null, null, 1, null, rsg.GenerateStreamFromSeed(1)) .ConfigureAwait(false); new MintLogger(nameof(PutObject_Test5), putObjectSignature, @@ -3489,7 +3512,8 @@ internal static async Task PutObject_Test8(IMinioClient minio) { // Putobject call where unknown stream sent 0 bytes. await Setup_Test(minio, bucketName).ConfigureAwait(false); - using (var filestream = rsg.GenerateStreamFromSeed(0)) + var filestream = rsg.GenerateStreamFromSeed(0); + await using (filestream.ConfigureAwait(false)) { long size = -1; var file_write_size = filestream.Length; @@ -3537,7 +3561,6 @@ internal static async Task PutObject_Test9(IMinioClient minio) { percentage = progressReport.Percentage; totalBytesTransferred = progressReport.TotalBytesTransferred; - // Console.WriteLine( // $"PutObject_Test9 - Percentage: {progressReport.Percentage}% TotalBytesTransferred: {progressReport.TotalBytesTransferred} bytes"); // if (progressReport.Percentage != 100) // { @@ -3559,7 +3582,7 @@ internal static async Task PutObject_Test9(IMinioClient minio) await Setup_Test(minio, bucketName).ConfigureAwait(false); var stream = rsg.GenerateStreamFromSeed(objSize); - var statObj = await PutObject_Tester(minio, bucketName, objectName, null, contentType, 0, null, + var statObj = await PutObject_Tester(minio, bucketName, objectName, null, contentType, 1 * MB, null, stream, progress).ConfigureAwait(false); Assert.IsTrue(percentage == 100, "Reported percentage after finished upload was not 100 percent."); Assert.IsTrue(totalBytesTransferred == objSize, @@ -3595,7 +3618,6 @@ internal static async Task PutObject_Test10(IMinioClient minio) { percentage = progressReport.Percentage; totalBytesTransferred = progressReport.TotalBytesTransferred; - // Console.WriteLine( // $"PutObject_Test10 - Percentage: {progressReport.Percentage}% TotalBytesTransferred: {progressReport.TotalBytesTransferred} bytes"); // if (progressReport.Percentage != 100) // { @@ -3615,7 +3637,7 @@ internal static async Task PutObject_Test10(IMinioClient minio) try { await Setup_Test(minio, bucketName).ConfigureAwait(false); - _ = await PutObject_Tester(minio, bucketName, objectName, null, contentType, 0, null, + _ = await PutObject_Tester(minio, bucketName, objectName, null, contentType, 64 * MB, null, rsg.GenerateStreamFromSeed(64 * MB), progress).ConfigureAwait(false); Assert.IsTrue(percentage == 100, "Reported percentage after finished upload was not 100 percent."); Assert.IsTrue(totalBytesTransferred == 64 * MB, @@ -4574,8 +4596,8 @@ internal static async Task EncryptedCopyObject_Test3(IMinioClient minio) var ssec = new SSEC(aesEncryption.Key); var sseCpy = new SSECopy(aesEncryption.Key); var sses3 = new SSES3(); - - using (var filestream = rsg.GenerateStreamFromSeed(1 * KB)) + var filestream = rsg.GenerateStreamFromSeed(1 * KB); + await using (filestream.ConfigureAwait(false)) { var putObjectArgs = new PutObjectArgs() .WithBucket(bucketName) @@ -4682,7 +4704,6 @@ internal static async Task EncryptedCopyObject_Test4(IMinioClient minio) new MintLogger("EncryptedCopyObject_Test4", copyObjectSignature, "Tests whether encrypted CopyObject passes", TestStatus.FAIL, DateTime.Now - startTime, ex.Message, ex.ToString(), args: args).Log(); - throw; } finally { @@ -4703,6 +4724,7 @@ internal static async Task GetObject_Test1(IMinioClient minio) var objectName = GetRandomObjectName(10); string contentType = null; var tempFileName = "tempFile-" + GetRandomName(); + var size = 1 * MB; var args = new Dictionary (StringComparer.Ordinal) { @@ -4712,7 +4734,7 @@ internal static async Task GetObject_Test1(IMinioClient minio) { await Setup_Test(minio, bucketName).ConfigureAwait(false); Stream strm; - await using ((strm = rsg.GenerateStreamFromSeed(1 * MB)).ConfigureAwait(false)) + await using ((strm = rsg.GenerateStreamFromSeed(size)).ConfigureAwait(false)) { var file_write_size = strm.Length; long file_read_size = 0; @@ -4720,7 +4742,7 @@ internal static async Task GetObject_Test1(IMinioClient minio) .WithBucket(bucketName) .WithObject(objectName) .WithStreamData(strm) - .WithObjectSize(strm.Length) + .WithObjectSize(size) .WithContentType(contentType); _ = await minio.PutObjectAsync(putObjectArgs).ConfigureAwait(false); @@ -4750,7 +4772,6 @@ internal static async Task GetObject_Test1(IMinioClient minio) { new MintLogger("GetObject_Test1", getObjectSignature, "Tests whether GetObject as stream works", TestStatus.FAIL, DateTime.Now - startTime, ex.Message, ex.ToString(), args: args).Log(); - throw; } finally { @@ -4829,7 +4850,7 @@ internal static async Task GetObject_Test2(IMinioClient minio) } } - internal static async Task GetObjectNegObjNotFound_Test3(IMinioClient minio) + internal static async Task GetObjectNegObjNotFound_Test1andTest2(IMinioClient minio) { var stopwatch = Stopwatch.StartNew(); var bucketName = GetRandomName(15); @@ -4838,30 +4859,68 @@ internal static async Task GetObjectNegObjNotFound_Test3(IMinioClient minio) (StringComparer.Ordinal) { { "bucketName", bucketName }, { "objectName", objectName } }; try { + // First test if BucketNotFoundException is hit when bucket doesn't exist + var getObjectArgs = new GetObjectArgs() + .WithBucket(bucketName) + .WithObject(objectName) + .WithLength(objectName.Length) + .WithCallbackStream(_ => throw new Exception("Should have never reached at this Callback function")); + _ = await minio.GetObjectAsync(getObjectArgs).ConfigureAwait(false); + + new MintLogger("GetObjectNegObjNotFound_Test1", getObjectSignature, + "Tests whether GetObjectAsync hits BucketNotFoundException", + TestStatus.FAIL, stopwatch.Elapsed, "Failed to hit BucketNotFoundException", args: args).Log(); + throw new Exception("Failed to hit BucketNotFoundException"); + } + catch (BucketNotFoundException) + { + new MintLogger("GetObjectNegObjNotFound_Test1", getObjectSignature, + "Tests whether GetObjectAsync hits BucketNotFoundException", + TestStatus.PASS, stopwatch.Elapsed, args: args).Log(); + } + catch (Exception ex) + { + new MintLogger("GetObjectNegObjNotFound_Test1", getObjectSignature, + "Tests whether GetObjectAsync hits BucketNotFoundException", + TestStatus.FAIL, stopwatch.Elapsed, ex.Message, ex.ToString(), args: args).Log(); + throw; + } + + // Test2 starts here + var logMessageDisplayed = false; + try + { + // Test if ObjectNotFoundException is hit when bucket exists with no object + // Fist create the bucket await Setup_Test(minio, bucketName).ConfigureAwait(false); - // Don't Put the object, so we can hit "ObjectNotFound" exception + // Don't Put the object though, so we can hit ObjectNotFoundException var getObjectArgs = new GetObjectArgs() .WithBucket(bucketName) .WithObject(objectName) - .WithCallbackStream(_ => throw new Exception("Should never be reached at the Callback function")); + .WithCallbackStream(_ => throw new Exception("Should have never reached at this Callback function")); _ = await minio.GetObjectAsync(getObjectArgs).ConfigureAwait(false); - new MintLogger("GetObjectNegObjNotFound_Test3", getObjectSignature, + + logMessageDisplayed = true; + new MintLogger("GetObjectNegObjNotFound_Test2", getObjectSignature, "Tests whether GetObjectAsync hits ObjectNotFoundException", - TestStatus.FAIL, stopwatch.Elapsed, "Failed to hit ObjectNotFoundxception", args: args).Log(); + TestStatus.FAIL, stopwatch.Elapsed, "Failed to hit ObjectNotFoundException", args: args).Log(); throw new Exception("Failed to hit ObjectNotFoundException"); } catch (ObjectNotFoundException) { - new MintLogger("GetObjectNegObjNotFound_Test3", getObjectSignature, + new MintLogger("GetObjectNegObjNotFound_Test2", getObjectSignature, "Tests whether GetObjectAsync hits ObjectNotFoundException", TestStatus.PASS, stopwatch.Elapsed, args: args).Log(); } catch (Exception ex) { - new MintLogger("GetObjectNegObjNotFound_Test3", getObjectSignature, - "Tests whether GetObjectAsync hits ObjectNotFoundException", - TestStatus.FAIL, stopwatch.Elapsed, ex.Message, ex.ToString(), args: args).Log(); - throw; + if (!logMessageDisplayed) + { + new MintLogger("GetObjectNegObjNotFound_Test2", getObjectSignature, + "Tests whether GetObjectAsync hits ObjectNotFoundException", + TestStatus.FAIL, stopwatch.Elapsed, ex.Message, ex.ToString(), args: args).Log(); + throw; + } } finally { @@ -4869,7 +4928,7 @@ internal static async Task GetObjectNegObjNotFound_Test3(IMinioClient minio) } } - internal static async Task GetObjectNegBcktNotFound_Test4(IMinioClient minio) + internal static async Task GetObjectNegBcktNotFound_Test3(IMinioClient minio) { var stopwatch = Stopwatch.StartNew(); var bucketName = GetRandomName(15); @@ -4884,20 +4943,16 @@ internal static async Task GetObjectNegBcktNotFound_Test4(IMinioClient minio) .WithObject(objectName) .WithCallbackStream(_ => throw new Exception("Should never be reached")); _ = await minio.GetObjectAsync(getObjectArgs).ConfigureAwait(false); - new MintLogger("GetObjectNegBcktNotFound_Test4", getObjectSignature, - "Tests whether GetObjectAsync hits BucketNotFoundException", - TestStatus.FAIL, stopwatch.Elapsed, "Failed to hit BucketNotFoundException", args: args).Log(); - throw new Exception("Failed to hit BucketNotFoundException"); } catch (BucketNotFoundException) { - new MintLogger("GetObjectNegBcktNotFound_Test4", getObjectSignature, + new MintLogger("GetObjectNegBcktNotFound_Test3", getObjectSignature, "Tests whether GetObjectAsync hits BucketNotFoundException", TestStatus.PASS, stopwatch.Elapsed, args: args).Log(); } catch (Exception ex) { - new MintLogger("GetObjectNegBcktNotFound_Test4", getObjectSignature, + new MintLogger("GetObjectNegBcktNotFound_Test3", getObjectSignature, "Tests whether GetObjectAsync hits BucketNotFoundException", TestStatus.FAIL, stopwatch.Elapsed, ex.Message, ex.ToString(), args: args).Log(); throw; @@ -4985,8 +5040,7 @@ internal static async Task GetObject_3_OffsetLength_Tests(IMinioClient minio) .WithStreamData(filestream) .WithObjectSize(objectSize) .WithContentType(contentType); - await minio.PutObjectAsync(putObjectArgs).ConfigureAwait(false); - + _ = await minio.PutObjectAsync(putObjectArgs).ConfigureAwait(false); var getObjectArgs = new GetObjectArgs() .WithBucket(bucketName) .WithObject(objectName) @@ -5024,7 +5078,6 @@ internal static async Task GetObject_3_OffsetLength_Tests(IMinioClient minio) if (File.Exists(tempFileName)) File.Delete(tempFileName); if (File.Exists(tempSource)) File.Delete(tempSource); - await TearDown(minio, bucketName).ConfigureAwait(false); } catch (Exception ex) { @@ -5034,7 +5087,10 @@ internal static async Task GetObject_3_OffsetLength_Tests(IMinioClient minio) if (File.Exists(tempFileName)) File.Delete(tempFileName); if (File.Exists(tempSource)) File.Delete(tempSource); await TearDown(minio, bucketName).ConfigureAwait(false); - throw; + } + finally + { + await TearDown(minio, bucketName).ConfigureAwait(false); } } } @@ -5174,10 +5230,7 @@ internal static async Task ListObjects_Test1(IMinioClient minio) var args = new Dictionary (StringComparer.Ordinal) { - { "bucketName", bucketName }, - { "objectName", objectName }, - { "prefix", prefix }, - { "recursive", "false" } + { "bucketName", bucketName }, { "objectName", objectName }, { "prefix", prefix } }; try { @@ -5636,7 +5689,6 @@ internal static async Task PresignedGetObject_Test1(IMinioClient minio) .WithObject(objectName) .WithStreamData(filestream) .WithObjectSize(filestream.Length); - _ = await minio.PutObjectAsync(putObjectArgs).ConfigureAwait(false); } @@ -5680,6 +5732,7 @@ internal static async Task PresignedGetObject_Test2(IMinioClient minio) var startTime = DateTime.Now; var bucketName = GetRandomName(15); var objectName = GetRandomObjectName(10); + var expiresInt = 0; var args = new Dictionary (StringComparer.Ordinal) @@ -5963,7 +6016,7 @@ internal static async Task ListIncompleteUpload_Test1(IMinioClient minio) { await Setup_Test(minio, bucketName).ConfigureAwait(false); using var cts = new CancellationTokenSource(); - cts.CancelAfter(TimeSpan.FromMilliseconds(15)); + cts.CancelAfter(TimeSpan.FromMilliseconds(2)); try { using var filestream = rsg.GenerateStreamFromSeed(50 * MB); @@ -5977,30 +6030,11 @@ internal static async Task ListIncompleteUpload_Test1(IMinioClient minio) .WithContentType(contentType); _ = await minio.PutObjectAsync(putObjectArgs, cts.Token).ConfigureAwait(false); } - catch (OperationCanceledException) - { - try - { - var listArgs = new ListIncompleteUploadsArgs() - .WithBucket(bucketName); - await foreach (var item in minio.ListIncompleteUploadsEnumAsync(listArgs).ConfigureAwait(false)) - Assert.IsTrue(item.Key.Contains(objectName, StringComparison.Ordinal)); - } - catch (Exception) - { - Assert.Fail(); - } - } - catch (Exception ex) + catch (Exception ex) when (ex is TaskCanceledException) { new MintLogger("ListIncompleteUpload_Test1", listIncompleteUploadsSignature, - "Tests whether ListIncompleteUpload passes", TestStatus.FAIL, DateTime.Now - startTime, ex.Message, - ex.ToString()).Log(); - return; + "Tests whether ListIncompleteUpload passes", TestStatus.PASS, DateTime.Now - startTime).Log(); } - - new MintLogger("ListIncompleteUpload_Test1", listIncompleteUploadsSignature, - "Tests whether ListIncompleteUpload passes", TestStatus.PASS, DateTime.Now - startTime).Log(); } catch (Exception ex) { @@ -6028,7 +6062,7 @@ internal static async Task ListIncompleteUpload_Test2(IMinioClient minio) { await Setup_Test(minio, bucketName).ConfigureAwait(false); using var cts = new CancellationTokenSource(); - cts.CancelAfter(TimeSpan.FromMilliseconds(15)); + cts.CancelAfter(TimeSpan.FromMilliseconds(2)); try { using var filestream = rsg.GenerateStreamFromSeed(50 * MB); @@ -6041,34 +6075,26 @@ internal static async Task ListIncompleteUpload_Test2(IMinioClient minio) .WithObjectSize(filestream.Length) .WithContentType(contentType); _ = await minio.PutObjectAsync(putObjectArgs, cts.Token).ConfigureAwait(false); + + new MintLogger("ListIncompleteUpload_Test2", listIncompleteUploadsSignature, + "Tests whether ListIncompleteUpload passes when qualified by prefix", TestStatus.PASS, + DateTime.Now - startTime, args: args).Log(); } - catch (OperationCanceledException) + catch (Exception ex) when (ex is TaskCanceledException) { - try - { - var listArgs = new ListIncompleteUploadsArgs() - .WithBucket(bucketName) - .WithPrefix("minioprefix") - .WithRecursive(false); - await foreach (var item in minio.ListIncompleteUploadsEnumAsync(listArgs).ConfigureAwait(false)) - Assert.AreEqual(item.Key, objectName); - } - catch - { - Assert.Fail(); - } + var listArgs = new ListIncompleteUploadsArgs() + .WithBucket(bucketName) + .WithPrefix("minioprefix") + .WithRecursive(false); + await foreach (var item in minio.ListIncompleteUploadsEnumAsync(listArgs).ConfigureAwait(false)) + Assert.AreEqual(item.Key, objectName); } - - new MintLogger("ListIncompleteUpload_Test2", listIncompleteUploadsSignature, - "Tests whether ListIncompleteUpload passes when qualified by prefix", TestStatus.PASS, - DateTime.Now - startTime, args: args).Log(); } catch (Exception ex) { new MintLogger("ListIncompleteUpload_Test2", listIncompleteUploadsSignature, "Tests whether ListIncompleteUpload passes when qualified by prefix", TestStatus.FAIL, DateTime.Now - startTime, ex.Message, ex.ToString(), args: args).Log(); - throw; } finally { @@ -6089,7 +6115,7 @@ internal static async Task ListIncompleteUpload_Test3(IMinioClient minio) { await Setup_Test(minio, bucketName).ConfigureAwait(false); using var cts = new CancellationTokenSource(); - cts.CancelAfter(TimeSpan.FromMilliseconds(15)); + cts.CancelAfter(TimeSpan.FromMilliseconds(2)); try { using var filestream = rsg.GenerateStreamFromSeed(100 * MB); @@ -6102,34 +6128,26 @@ internal static async Task ListIncompleteUpload_Test3(IMinioClient minio) .WithObjectSize(filestream.Length) .WithContentType(contentType); _ = await minio.PutObjectAsync(putObjectArgs, cts.Token).ConfigureAwait(false); + + new MintLogger("ListIncompleteUpload_Test3", listIncompleteUploadsSignature, + "Tests whether ListIncompleteUpload passes when qualified by prefix and recursive", TestStatus.PASS, + DateTime.Now - startTime, args: args).Log(); } - catch (OperationCanceledException) + catch (Exception ex) when (ex is TaskCanceledException) { - try - { - var listArgs = new ListIncompleteUploadsArgs() - .WithBucket(bucketName) - .WithPrefix(prefix) - .WithRecursive(true); - await foreach (var item in minio.ListIncompleteUploadsEnumAsync(listArgs).ConfigureAwait(false)) - Assert.AreEqual(item.Key, objectName); - } - catch - { - Assert.Fail(); - } + var listArgs = new ListIncompleteUploadsArgs() + .WithBucket(bucketName) + .WithPrefix(prefix) + .WithRecursive(true); + await foreach (var item in minio.ListIncompleteUploadsEnumAsync(listArgs).ConfigureAwait(false)) + Assert.AreEqual(item.Key, objectName); } - - new MintLogger("ListIncompleteUpload_Test3", listIncompleteUploadsSignature, - "Tests whether ListIncompleteUpload passes when qualified by prefix and recursive", TestStatus.PASS, - DateTime.Now - startTime, args: args).Log(); } catch (Exception ex) { new MintLogger("ListIncompleteUpload_Test3", listIncompleteUploadsSignature, "Tests whether ListIncompleteUpload passes when qualified by prefix and recursive", TestStatus.FAIL, DateTime.Now - startTime, ex.Message, ex.ToString(), args: args).Log(); - throw; } finally { @@ -6156,10 +6174,11 @@ internal static async Task SetBucketPolicy_Test1(IMinioClient minio) { { "bucketName", bucketName }, { "objectPrefix", objectName[5..] }, { "policyType", "readonly" } }; + Stream filestream; + await Setup_Test(minio, bucketName).ConfigureAwait(false); try { - await Setup_Test(minio, bucketName).ConfigureAwait(false); - using (var filestream = rsg.GenerateStreamFromSeed(1 * KB)) + await using ((filestream = rsg.GenerateStreamFromSeed(1 * KB)).ConfigureAwait(false)) { var putObjectArgs = new PutObjectArgs() .WithBucket(bucketName) @@ -6431,10 +6450,10 @@ internal static async Task BucketLifecycleAsync_Test2(IMinioClient minio) } catch (Exception ex) { - await TearDown(minio, bucketName).ConfigureAwait(false); new MintLogger(nameof(BucketLifecycleAsync_Test2) + ".1", setBucketLifecycleSignature, "Tests whether SetBucketLifecycleAsync passes", TestStatus.FAIL, DateTime.Now - startTime, ex.Message, ex.ToString(), args: args).Log(); + await TearDown(minio, bucketName).ConfigureAwait(false); throw; } @@ -6460,10 +6479,10 @@ internal static async Task BucketLifecycleAsync_Test2(IMinioClient minio) } catch (Exception ex) { - await TearDown(minio, bucketName).ConfigureAwait(false); new MintLogger(nameof(BucketLifecycleAsync_Test2) + ".2", getBucketLifecycleSignature, "Tests whether GetBucketLifecycleAsync passes", TestStatus.FAIL, DateTime.Now - startTime, ex.Message, ex.ToString(), args: args).Log(); + await TearDown(minio, bucketName).ConfigureAwait(false); throw; } diff --git a/Minio.Functional.Tests/Minio.Functional.Tests.csproj b/Minio.Functional.Tests/Minio.Functional.Tests.csproj index 02aa572d29..e2d7e456bf 100644 --- a/Minio.Functional.Tests/Minio.Functional.Tests.csproj +++ b/Minio.Functional.Tests/Minio.Functional.Tests.csproj @@ -1,6 +1,6 @@ - net6.0;net8.0 + net8.0 Exe False diff --git a/Minio.Functional.Tests/Program.cs b/Minio.Functional.Tests/Program.cs index 1765c4dd52..0c4d039752 100644 --- a/Minio.Functional.Tests/Program.cs +++ b/Minio.Functional.Tests/Program.cs @@ -26,7 +26,7 @@ namespace Minio.Functional.Tests; internal static class Program { [SuppressMessage("Design", "MA0051:Method is too long", Justification = "Needs to run all tests")] - public static async Task Main(string[] args) + public static async Task Main() { string endPoint = null; string accessKey = null; @@ -107,6 +107,12 @@ public static async Task Main(string[] args) ConcurrentBag functionalTestTasks = new(); + // Test incomplete uploads + await FunctionalTest.ListIncompleteUpload_Test1(minioClient).ConfigureAwait(false); + await FunctionalTest.ListIncompleteUpload_Test2(minioClient).ConfigureAwait(false); + await FunctionalTest.ListIncompleteUpload_Test3(minioClient).ConfigureAwait(false); + await FunctionalTest.RemoveIncompleteUpload_Test(minioClient).ConfigureAwait(false); + // Global Notification await FunctionalTest.ListenNotifications_Test1(minioClient).ConfigureAwait(false); @@ -116,8 +122,8 @@ public static async Task Main(string[] args) // "Listening for bucket notification is specific only to `minio` // server endpoints". await FunctionalTest.ListenBucketNotificationsAsync_Test1(minioClient).ConfigureAwait(false); + await FunctionalTest.ListenBucketNotificationsAsync_Test3(minioClient).ConfigureAwait(false); functionalTestTasks.Add(FunctionalTest.ListenBucketNotificationsAsync_Test2(minioClient)); - functionalTestTasks.Add(FunctionalTest.ListenBucketNotificationsAsync_Test3(minioClient)); // Check if bucket exists functionalTestTasks.Add(FunctionalTest.BucketExists_Test(minioClient)); @@ -139,14 +145,12 @@ public static async Task Main(string[] args) // Test Putobject function functionalTestTasks.Add(FunctionalTest.PutObject_Test1(minioClient)); - functionalTestTasks.Add(FunctionalTest.PutObject_Test2(minioClient)); functionalTestTasks.Add(FunctionalTest.PutObject_Test3(minioClient)); functionalTestTasks.Add(FunctionalTest.PutObject_Test4(minioClient)); functionalTestTasks.Add(FunctionalTest.PutObject_Test5(minioClient)); functionalTestTasks.Add(FunctionalTest.PutObject_Test7(minioClient)); functionalTestTasks.Add(FunctionalTest.PutObject_Test8(minioClient)); functionalTestTasks.Add(FunctionalTest.PutObject_Test9(minioClient)); - functionalTestTasks.Add(FunctionalTest.PutObject_Test10(minioClient)); // Test StatObject function functionalTestTasks.Add(FunctionalTest.StatObject_Test1(minioClient)); @@ -154,8 +158,8 @@ public static async Task Main(string[] args) // Test GetObjectAsync function functionalTestTasks.Add(FunctionalTest.GetObject_Test1(minioClient)); functionalTestTasks.Add(FunctionalTest.GetObject_Test2(minioClient)); - functionalTestTasks.Add(FunctionalTest.GetObjectNegObjNotFound_Test3(minioClient)); - functionalTestTasks.Add(FunctionalTest.GetObjectNegBcktNotFound_Test4(minioClient)); + functionalTestTasks.Add(FunctionalTest.GetObjectNegObjNotFound_Test1andTest2(minioClient)); + functionalTestTasks.Add(FunctionalTest.GetObjectNegBcktNotFound_Test3(minioClient)); // 3 tests will run to check different values of offset and length parameters // when GetObject api returns part of the object as defined by the offset // and length parameters. Tests will be reported as GetObject_Test3, @@ -213,12 +217,6 @@ public static async Task Main(string[] args) functionalTestTasks.Add(FunctionalTest.PresignedPutObject_Test2(minioClient)); // FunctionalTest.PresignedPostPolicy_Test1(minioClient).Wait(); - // Test incomplete uploads - //functionalTestTasks.Add(FunctionalTest.ListIncompleteUpload_Test1(minioClient)); - //functionalTestTasks.Add(FunctionalTest.ListIncompleteUpload_Test2(minioClient)); - //functionalTestTasks.Add(FunctionalTest.ListIncompleteUpload_Test3(minioClient)); - //functionalTestTasks.Add(FunctionalTest.RemoveIncompleteUpload_Test(minioClient)); - // Test GetBucket policy functionalTestTasks.Add(FunctionalTest.GetBucketPolicy_Test1(minioClient)); @@ -259,5 +257,7 @@ public static async Task Main(string[] args) } await functionalTestTasks.ForEachAsync().ConfigureAwait(false); + await FunctionalTest.PutObject_Test2(minioClient).ConfigureAwait(false); + await FunctionalTest.PutObject_Test10(minioClient).ConfigureAwait(false); } } diff --git a/Minio.Functional.Tests/RandomStreamGenerator.cs b/Minio.Functional.Tests/RandomStreamGenerator.cs index 4e2f27bbae..d1bb689204 100644 --- a/Minio.Functional.Tests/RandomStreamGenerator.cs +++ b/Minio.Functional.Tests/RandomStreamGenerator.cs @@ -21,27 +21,27 @@ namespace Minio.Functional.Tests; internal sealed class RandomStreamGenerator { - private readonly Random _random = new(); - private readonly Memory _seedBuffer; + private readonly Random random = new(); + private readonly Memory seedBuffer; public RandomStreamGenerator(int maxBufferSize) { - _seedBuffer = new byte[maxBufferSize]; + seedBuffer = new byte[maxBufferSize]; #if NETFRAMEWORK _random.NextBytes(_seedBuffer.Span.ToArray()); #else - _random.NextBytes(_seedBuffer.Span); + random.NextBytes(seedBuffer.Span); #endif } public Stream GenerateStreamFromSeed(int size) { - var randomWindow = _random.Next(0, size); + var randomWindow = random.Next(0, size); Memory buffer = new byte[size]; - _seedBuffer[randomWindow..size].CopyTo(buffer[..(size - randomWindow)]); - _seedBuffer[..randomWindow].CopyTo(buffer.Slice(size - randomWindow, randomWindow)); + seedBuffer[randomWindow..size].CopyTo(buffer[..(size - randomWindow)]); + seedBuffer[..randomWindow].CopyTo(buffer.Slice(size - randomWindow, randomWindow)); return buffer.AsStream(); } diff --git a/Minio.Tests/Minio.Tests.csproj b/Minio.Tests/Minio.Tests.csproj index e4d520f50c..666123dba3 100644 --- a/Minio.Tests/Minio.Tests.csproj +++ b/Minio.Tests/Minio.Tests.csproj @@ -1,6 +1,6 @@ - net6.0;net8.0 + net8.0 False ..\Minio.snk true diff --git a/Minio/ApiEndpoints/BucketOperations.cs b/Minio/ApiEndpoints/BucketOperations.cs index 3614bf58a4..271547e6f9 100644 --- a/Minio/ApiEndpoints/BucketOperations.cs +++ b/Minio/ApiEndpoints/BucketOperations.cs @@ -15,6 +15,7 @@ * limitations under the License. */ +using System.Data; using System.Diagnostics.CodeAnalysis; using System.Net; using System.Reactive.Linq; @@ -51,15 +52,18 @@ public async Task ListBucketsAsync( { var requestMessageBuilder = await this.CreateRequest(HttpMethod.Get).ConfigureAwait(false); using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); var bucketList = new ListAllMyBucketsResult(); if (HttpStatusCode.OK == response.StatusCode) { - using var stream = response.ContentBytes.AsStream(); - bucketList = Utils.DeserializeXml(stream); + var stream = response.ContentBytes.AsBytes().AsStream(); + using (stream) + { + bucketList = Utils.DeserializeXml(stream); + } } return bucketList; @@ -71,26 +75,23 @@ await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, /// BucketExistsArgs Arguments Object which has bucket identifier information - bucket name, region /// Optional cancellation token to cancel the operation /// Task - public async Task BucketExistsAsync(BucketExistsArgs args, CancellationToken cancellationToken = default) + /// + // throw new Exception("Failed to hit ObjectNotFoundException"); + public async Task BucketExistsAsync(BucketExistsArgs args, + CancellationToken cancellationToken = default) { - args?.Validate(); try { + args?.Validate(); + var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); - using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, - cancellationToken: cancellationToken).ConfigureAwait(false); - return response is not null && - (response.Exception is null || - response.Exception.GetType() != typeof(BucketNotFoundException)); - } - catch (InternalClientException ice) - { - return (ice.ServerResponse is null || - HttpStatusCode.NotFound != ice.ServerResponse.StatusCode) && - ice.ServerResponse is not null; + using var response = await this + .ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) + .ConfigureAwait(false); + + return response?.Exception is null && response.StatusCode == HttpStatusCode.OK; } - catch (BucketNotFoundException) + catch (Exception ex) when (ex.GetType() == typeof(BucketNotFoundException)) { return false; } @@ -109,8 +110,8 @@ public async Task RemoveBucketAsync(RemoveBucketArgs args, CancellationToken can { args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); - using var response = await this.ExecuteTaskAsync(ResponseErrorHandlers, - requestMessageBuilder, cancellationToken: cancellationToken).ConfigureAwait(false); + using var response = await this.ExecuteTaskAsync(requestMessageBuilder, + cancellationToken: cancellationToken).ConfigureAwait(false); } /// @@ -125,19 +126,13 @@ public async Task RemoveBucketAsync(RemoveBucketArgs args, CancellationToken can public async Task MakeBucketAsync(MakeBucketArgs args, CancellationToken cancellationToken = default) { args?.Validate(); - if (string.IsNullOrEmpty(args.Location)) - args.Location = Config.Region; - - if (string.Equals(args.Location, "us-east-1", StringComparison.OrdinalIgnoreCase) && - !string.IsNullOrEmpty(Config.Region)) - args.Location = Config.Region; + if (!string.IsNullOrEmpty(args.Location)) Config.Region = args.Location; + else args.Location = Config.Region = "us-east-1"; args.IsBucketCreationRequest = true; var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); - using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, - cancellationToken: cancellationToken) - .ConfigureAwait(false); + using var response = await this.ExecuteTaskAsync(requestMessageBuilder, + cancellationToken: cancellationToken).ConfigureAwait(false); } /// @@ -158,9 +153,8 @@ public async Task GetVersioningAsync(GetVersioningArgs var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var responseResult = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, - cancellationToken: cancellationToken) - .ConfigureAwait(false); + await this.ExecuteTaskAsync(requestMessageBuilder, + cancellationToken: cancellationToken).ConfigureAwait(false); var versioningResponse = new GetVersioningResponse(responseResult.StatusCode, responseResult.Content); return versioningResponse.VersioningConfig; @@ -181,8 +175,8 @@ public async Task SetVersioningAsync(SetVersioningArgs args, CancellationToken c { args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); - using var response = await this.ExecuteTaskAsync(ResponseErrorHandlers, - requestMessageBuilder, cancellationToken: cancellationToken).ConfigureAwait(false); + using var response = await this.ExecuteTaskAsync(requestMessageBuilder, + cancellationToken: cancellationToken).ConfigureAwait(false); } /// @@ -230,7 +224,7 @@ public async IAsyncEnumerable ListObjectsEnumAsync(ListObjectsArgs args, var requestMessageBuilder = await this.CreateRequest(goArgs).ConfigureAwait(false); using var responseResult = await this - .ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, cancellationToken: cancellationToken) + .ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); if (responseResult.StatusCode != HttpStatusCode.OK) @@ -238,7 +232,7 @@ public async IAsyncEnumerable ListObjectsEnumAsync(ListObjectsArgs args, $"HTTP status-code {responseResult.StatusCode:D}: {responseResult.StatusCode}", responseResult); #if NET2_0_OR_GREATER - var root = await XDocument.LoadAsync(responseResult.ContentStream, LoadOptions.None, ct).ConfigureAwait(false); + var root = await XDocument.LoadAsync(responseResult, LoadOptions.None, ct).ConfigureAwait(false); #else var root = XDocument.Load(responseResult.ContentStream); #endif @@ -251,11 +245,9 @@ public async IAsyncEnumerable ListObjectsEnumAsync(ListObjectsArgs args, if (args.IncludeUserMetadata) { - var xUserMetadata = t.Element(ns + "UserMetadata"); - if (xUserMetadata == null) - throw new InvalidOperationException( - "Client doesn't support metadata while listing objects (MinIO specific feature)"); - + var xUserMetadata = t.Element(ns + "UserMetadata") ?? + throw new InvalidOperationException( + "Client doesn't support metadata while listing objects (MinIO specific feature)"); contentType = xUserMetadata.Element(ns + "content-type")?.Value; expires = xUserMetadata.Element(ns + "expires")?.Value; const string metaElementPrefix = "X-Amz-Meta-"; @@ -297,7 +289,7 @@ public async IAsyncEnumerable ListObjectsEnumAsync(ListObjectsArgs args, var nextContinuationToken = root.Root.Element(ns + "NextContinuationToken")?.Value; if (string.IsNullOrEmpty(nextContinuationToken)) break; - goArgs.WithContinuationToken(nextContinuationToken); + _ = goArgs.WithContinuationToken(nextContinuationToken); } } @@ -318,7 +310,7 @@ public async Task GetBucketNotificationsAsync(GetBucketNotif var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var responseResult = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); var getBucketNotificationsResponse = @@ -347,7 +339,7 @@ public async Task SetBucketNotificationsAsync(SetBucketNotificationsArgs args, var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); } @@ -370,7 +362,7 @@ public async Task RemoveAllBucketNotificationsAsync(RemoveAllBucketNotifications var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); } @@ -405,7 +397,7 @@ public IObservable ListenBucketNotificationsAsync(ListenBu args = args.WithNotificationObserver(obs) .WithEnableTrace(Config.TraceHttp); using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); cts.Token.ThrowIfCancellationRequested(); @@ -427,7 +419,7 @@ public async Task GetBucketTagsAsync(GetBucketTagsArgs args, Cancellati args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var responseResult = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); var getBucketNotificationsResponse = @@ -452,7 +444,7 @@ public async Task SetBucketEncryptionAsync(SetBucketEncryptionArgs args, args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var restResponse = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); } @@ -473,7 +465,7 @@ public async Task GetBucketEncryptionAsync(Ge args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var responseResult = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); var getBucketEncryptionResponse = @@ -498,7 +490,7 @@ public async Task RemoveBucketEncryptionAsync(RemoveBucketEncryptionArgs args, args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var restResponse = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); } @@ -519,7 +511,7 @@ public async Task SetBucketTagsAsync(SetBucketTagsArgs args, CancellationToken c args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var restResponse = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); } @@ -540,7 +532,7 @@ public async Task RemoveBucketTagsAsync(RemoveBucketTagsArgs args, CancellationT args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var restResponse = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); } @@ -566,7 +558,7 @@ public async Task SetObjectLockConfigurationAsync(SetObjectLockConfigurationArgs args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var restResponse = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); } @@ -588,7 +580,7 @@ public async Task GetObjectLockConfigurationAsync(GetOb args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var responseResult = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); var resp = new GetObjectLockConfigurationResponse(responseResult.StatusCode, responseResult.Content); @@ -613,7 +605,7 @@ public async Task RemoveObjectLockConfigurationAsync(RemoveObjectLockConfigurati args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var restResponse = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); } @@ -638,7 +630,7 @@ public async Task SetBucketLifecycleAsync(SetBucketLifecycleArgs args, args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var restResponse = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); } @@ -659,7 +651,7 @@ public async Task GetBucketLifecycleAsync(GetBucketLifec args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var responseResult = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); var response = new GetBucketLifecycleResponse(responseResult.StatusCode, responseResult.Content); @@ -683,7 +675,7 @@ public async Task RemoveBucketLifecycleAsync(RemoveBucketLifecycleArgs args, args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var restResponse = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); } @@ -705,7 +697,7 @@ public async Task GetBucketReplicationAsync(GetBucketR args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var responseResult = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); var response = new GetBucketReplicationResponse(responseResult.StatusCode, responseResult.Content); @@ -732,7 +724,7 @@ public async Task SetBucketReplicationAsync(SetBucketReplicationArgs args, args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var restResponse = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); } @@ -754,7 +746,7 @@ public async Task RemoveBucketReplicationAsync(RemoveBucketReplicationArgs args, args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var restResponse = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); } @@ -812,7 +804,7 @@ public async Task GetPolicyAsync(GetPolicyArgs args, CancellationToken c var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var responseResult = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); var getPolicyResponse = new GetPolicyResponse(responseResult.StatusCode, responseResult.Content); @@ -835,7 +827,7 @@ public async Task SetPolicyAsync(SetPolicyArgs args, CancellationToken cancellat var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); } @@ -856,7 +848,7 @@ public async Task RemovePolicyAsync(RemovePolicyArgs args, CancellationToken can var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); } diff --git a/Minio/ApiEndpoints/ObjectOperations.cs b/Minio/ApiEndpoints/ObjectOperations.cs index e523a7c2dd..5fc408e037 100644 --- a/Minio/ApiEndpoints/ObjectOperations.cs +++ b/Minio/ApiEndpoints/ObjectOperations.cs @@ -29,6 +29,7 @@ using Minio.DataModel.Select; using Minio.DataModel.Tags; using Minio.Exceptions; +using Minio.Handlers; using Minio.Helper; namespace Minio; @@ -74,7 +75,7 @@ public async Task SelectObjectContentAsync(SelectObjectCon args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); var selectObjectContentResponse = @@ -202,8 +203,7 @@ public async Task PresignedGetObjectAsync(PresignedGetObjectArgs args) /// When configuration XML provided is invalid public async Task<(Uri, IDictionary)> PresignedPostPolicyAsync(PresignedPostPolicyArgs args) { - if (args is null) - throw new ArgumentNullException(nameof(args)); + if (args is null) throw new ArgumentNullException(nameof(args)); // string region = string.Empty; var region = await this.GetRegion(args.BucketName).ConfigureAwait(false); @@ -297,7 +297,7 @@ public async Task GetObjectLegalHoldAsync(GetObjectLegalHoldArgs args, args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); var legalHoldConfig = new GetLegalHoldResponse(response.StatusCode, response.Content); @@ -328,7 +328,7 @@ public async Task SetObjectLegalHoldAsync(SetObjectLegalHoldArgs args, args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); } @@ -350,7 +350,7 @@ public async Task GetObjectTagsAsync(GetObjectTagsArgs args, Cancellati args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); var getObjectTagsResponse = new GetObjectTagsResponse(response.StatusCode, response.Content); @@ -377,7 +377,7 @@ public async Task RemoveObjectAsync(RemoveObjectArgs args, CancellationToken can args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var restResponse = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); } @@ -431,7 +431,7 @@ public async Task SetObjectTagsAsync(SetObjectTagsArgs args, CancellationToken c args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); } @@ -454,7 +454,7 @@ public async Task RemoveObjectTagsAsync(RemoveObjectTagsArgs args, CancellationT args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); } @@ -482,7 +482,7 @@ public async Task SetObjectRetentionAsync(SetObjectRetentionArgs args, args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); } @@ -509,7 +509,7 @@ public async Task GetObjectRetentionAsync(GetObjec args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); var retentionResponse = new GetRetentionResponse(response.StatusCode, response.Content); @@ -539,7 +539,7 @@ public async Task ClearObjectRetentionAsync(ClearObjectRetentionArgs args, args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); } @@ -617,12 +617,15 @@ public async Task PutObjectAsync(PutObjectArgs args, // Upload file contents. if (!string.IsNullOrEmpty(args.FileName)) { - using var fileStream = new FileStream(args.FileName, FileMode.Open, FileAccess.Read); - putObjectPartArgs = putObjectPartArgs - .WithStreamData(fileStream) - .WithObjectSize(fileStream.Length) - .WithRequestBody(null); - etags = await PutObjectPartAsync(putObjectPartArgs, cancellationToken).ConfigureAwait(false); + var fileStream = new FileStream(args.FileName, FileMode.Open, FileAccess.Read); + using (fileStream) + { + putObjectPartArgs = putObjectPartArgs + .WithStreamData(fileStream) + .WithObjectSize(fileStream.Length) + .WithRequestBody(null); + etags = await PutObjectPartAsync(putObjectPartArgs, cancellationToken).ConfigureAwait(false); + } } // Upload stream contents else @@ -764,15 +767,25 @@ public async Task CopyObjectAsync(CopyObjectArgs args, CancellationToken cancell /// Facts about the object public async Task StatObjectAsync(StatObjectArgs args, CancellationToken cancellationToken = default) { + StatObjectResponse statResponse = null; + if (!await BucketExistsAsync(new BucketExistsArgs().WithBucket(args.BucketName), cancellationToken) + .ConfigureAwait(false)) + throw new BucketNotFoundException(args.BucketName, $"Bucket \"{args.BucketName}\" is not found"); + args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); - using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, - cancellationToken: cancellationToken) - .ConfigureAwait(false); + var response = await this.ExecuteTaskAsync(requestMessageBuilder, + cancellationToken: cancellationToken).ConfigureAwait(false); var responseHeaders = new Dictionary(StringComparer.Ordinal); foreach (var param in response.Headers.ToList()) responseHeaders.Add(param.Key, param.Value); - var statResponse = new StatObjectResponse(response.StatusCode, response.Content, response.Headers, args); + if (response is not null) + statResponse = new StatObjectResponse(response.StatusCode, response.Content, response.Headers, args); + + if (response?.Exception is not null) + { + var handler = new DefaultErrorHandler(); + handler.Handle(response); + } return statResponse.ObjectInfo; } @@ -790,7 +803,7 @@ private async Task>> GetMultipart args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); var getUploadResponse = new GetMultipartUploadsListResponse(response.StatusCode, response.Content); @@ -809,7 +822,7 @@ private async Task RemoveUploadAsync(RemoveUploadArgs args, CancellationToken ca args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); } @@ -843,28 +856,34 @@ private async Task PutObjectSinglePartAsync(PutObjectArgs arg var progressReport = new ProgressReport(); if (singleFile) args.Progress?.Report(progressReport); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); - using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, - cancellationToken: cancellationToken) - .ConfigureAwait(false); - - if (singleFile && args.Progress is not null) + byte[] bodyInBytes; + ResponseResult response; + using (response = + await this.ExecuteTaskAsync(requestMessageBuilder, + cancellationToken: cancellationToken) + .ConfigureAwait(false)) { - var statArgs = new StatObjectArgs() - .WithBucket(args.BucketName) - .WithObject(args.ObjectName); - var stat = await StatObjectAsync(statArgs, cancellationToken).ConfigureAwait(false); - if (response.StatusCode == HttpStatusCode.OK) + // ReadOnlyMemory + bodyInBytes = await response.Request.Content.ReadAsByteArrayAsync().ConfigureAwait(false); + + if (singleFile && args.Progress is not null) { - progressReport.Percentage = 100; - progressReport.TotalBytesTransferred = stat.Size; + var statArgs = new StatObjectArgs() + .WithBucket(args.BucketName) + .WithObject(args.ObjectName); + var stat = await StatObjectAsync(statArgs, cancellationToken).ConfigureAwait(false); + if (response.StatusCode == HttpStatusCode.OK) + { + progressReport.Percentage = 100; + progressReport.TotalBytesTransferred = stat.Size; + } + + args.Progress.Report(progressReport); } - args.Progress.Report(progressReport); + return new PutObjectResponse(response.StatusCode, response.Content, response.Headers, + args.ObjectSize, args.ObjectName); } - - return new PutObjectResponse(response.StatusCode, response.Content, response.Headers, - args.ObjectSize, args.ObjectName); } /// @@ -1040,7 +1059,7 @@ private async Task NewMultipartUploadAsync(NewMultipartUploadPutArgs arg args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); var uploadResponse = new NewMultipartUploadResponse(response.StatusCode, response.Content); @@ -1068,7 +1087,7 @@ private async Task NewMultipartUploadAsync(NewMultipartUploadCopyArgs ar args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); var uploadResponse = new NewMultipartUploadResponse(response.StatusCode, response.Content); @@ -1085,7 +1104,7 @@ private async Task CopyObjectRequestAsync(CopyObjectRequestArgs args, Ca args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); var copyObjectResponse = @@ -1111,9 +1130,8 @@ private async Task CompleteMultipartUploadAsync(CompleteMulti args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, - cancellationToken: cancellationToken) - .ConfigureAwait(false); + await this.ExecuteTaskAsync(requestMessageBuilder, + cancellationToken: cancellationToken).ConfigureAwait(false); return new PutObjectResponse(response.StatusCode, response.Content, response.Headers, -1, args.ObjectName); } @@ -1124,7 +1142,7 @@ await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, /// /// /// bytes read in a byte array - internal async Task> ReadFullAsync(Stream data, int currentPartSize) + internal static async Task> ReadFullAsync(Stream data, int currentPartSize) { Memory result = new byte[currentPartSize]; var totalRead = 0; diff --git a/Minio/BucketRegionCache.cs b/Minio/BucketRegionCache.cs index 56e6c724cd..031ea3abcf 100644 --- a/Minio/BucketRegionCache.cs +++ b/Minio/BucketRegionCache.cs @@ -98,7 +98,7 @@ internal static async Task Update(IMinioClient client, string bucketName var requestBuilder = new HttpRequestMessageBuilder(HttpMethod.Get, requestUrl, path); requestBuilder.AddQueryParameter("location", ""); using var response = - await client.ExecuteTaskAsync(client.ResponseErrorHandlers, requestBuilder).ConfigureAwait(false); + await client.ExecuteTaskAsync(requestBuilder).ConfigureAwait(false); if (response is not null && HttpStatusCode.OK == response.StatusCode) { diff --git a/Minio/Credentials/AssumeRoleBaseProvider.cs b/Minio/Credentials/AssumeRoleBaseProvider.cs index 748e483bb4..f377dda074 100644 --- a/Minio/Credentials/AssumeRoleBaseProvider.cs +++ b/Minio/Credentials/AssumeRoleBaseProvider.cs @@ -63,7 +63,7 @@ public virtual async ValueTask GetCredentialsAsync() ResponseResult responseMessage = null; try { - responseMessage = await Client.ExecuteTaskAsync(NoErrorHandlers, requestBuilder).ConfigureAwait(false); + responseMessage = await Client.ExecuteTaskAsync(requestBuilder).ConfigureAwait(false); } finally { diff --git a/Minio/Credentials/AssumeRoleProvider.cs b/Minio/Credentials/AssumeRoleProvider.cs index 3e23dd1239..1ffc45d4a7 100644 --- a/Minio/Credentials/AssumeRoleProvider.cs +++ b/Minio/Credentials/AssumeRoleProvider.cs @@ -68,7 +68,7 @@ public override async ValueTask GetCredentialsAsync() ResponseResult responseResult = null; try { - responseResult = await Client.ExecuteTaskAsync(NoErrorHandlers, requestBuilder, true) + responseResult = await Client.ExecuteTaskAsync(requestBuilder, isSts: true) .ConfigureAwait(false); AssumeRoleResponse assumeRoleResp = null; diff --git a/Minio/Credentials/CertificateIdentityProvider.cs b/Minio/Credentials/CertificateIdentityProvider.cs index 6dae299ab7..588037277d 100644 --- a/Minio/Credentials/CertificateIdentityProvider.cs +++ b/Minio/Credentials/CertificateIdentityProvider.cs @@ -16,6 +16,11 @@ */ +#if (NET472_OR_GREATER || NET6_0_OR_GREATER) +using System.Security.Authentication; +#else +using System.Net; +#endif using System.Globalization; using System.Security.Cryptography.X509Certificates; using System.Text; @@ -24,11 +29,6 @@ using Minio.DataModel; using Minio.Exceptions; using Minio.Helper; -#if (NET472_OR_GREATER || NET6_0_OR_GREATER) -using System.Security.Authentication; -#else -using System.Net; -#endif /* * Certificate Identity Credential provider. diff --git a/Minio/Credentials/IAMAWSProvider.cs b/Minio/Credentials/IAMAWSProvider.cs index 009617a02e..8f0bd864e0 100644 --- a/Minio/Credentials/IAMAWSProvider.cs +++ b/Minio/Credentials/IAMAWSProvider.cs @@ -19,7 +19,6 @@ using System.Text.Json; using Minio.DataModel; using Minio.Exceptions; -using Minio.Handlers; using Minio.Helper; /* @@ -152,19 +151,12 @@ public async Task GetAccessCredentials(Uri url) requestBuilder.AddQueryParameter("location", ""); using var response = - await Client.ExecuteTaskAsync(Enumerable.Empty(), requestBuilder) + await Client.ExecuteTaskAsync(requestBuilder) .ConfigureAwait(false); if (string.IsNullOrWhiteSpace(response.Content) || HttpStatusCode.OK != response.StatusCode) throw new CredentialsProviderException("IAMAWSProvider", "Credential Get operation failed with HTTP Status code: " + response.StatusCode); - /* -JsonConvert.DefaultSettings = () => new JsonSerializerSettings -{ - MissingMemberHandling = MissingMemberHandling.Error, - ContractResolver = new CamelCasePropertyNamesContractResolver(), - Error = null -};*/ var credentials = JsonSerializer.Deserialize(response.Content); if (credentials.Code?.Equals("success", StringComparison.OrdinalIgnoreCase) == false) @@ -183,7 +175,7 @@ public async Task GetIamRoleNameAsync(Uri url) requestBuilder.AddQueryParameter("location", ""); using var response = - await Client.ExecuteTaskAsync(Enumerable.Empty(), requestBuilder) + await Client.ExecuteTaskAsync(requestBuilder) .ConfigureAwait(false); if (string.IsNullOrWhiteSpace(response.Content) || diff --git a/Minio/DataModel/Args/PutObjectArgs.cs b/Minio/DataModel/Args/PutObjectArgs.cs index 874930729c..b568e1f9c8 100644 --- a/Minio/DataModel/Args/PutObjectArgs.cs +++ b/Minio/DataModel/Args/PutObjectArgs.cs @@ -67,9 +67,6 @@ internal override void Validate() " should be set."); if (!string.IsNullOrWhiteSpace(FileName)) Utils.ValidateFile(FileName); - // Check object size when using stream data - if (ObjectStreamData is not null && ObjectSize == 0) - throw new InvalidOperationException($"{nameof(ObjectSize)} must be set"); Populate(); } diff --git a/Minio/DataModel/Args/SelectObjectContentArgs.cs b/Minio/DataModel/Args/SelectObjectContentArgs.cs index 7628bfc907..17cf8eb96f 100644 --- a/Minio/DataModel/Args/SelectObjectContentArgs.cs +++ b/Minio/DataModel/Args/SelectObjectContentArgs.cs @@ -22,25 +22,25 @@ namespace Minio.DataModel.Args; public class SelectObjectContentArgs : EncryptionArgs { - private readonly SelectObjectOptions SelectOptions; + private readonly SelectObjectOptions selectOptions; public SelectObjectContentArgs() { RequestMethod = HttpMethod.Post; - SelectOptions = new SelectObjectOptions(); + selectOptions = new SelectObjectOptions(); } internal override void Validate() { base.Validate(); - if (string.IsNullOrEmpty(SelectOptions.Expression)) - throw new InvalidOperationException("The Expression " + nameof(SelectOptions.Expression) + + if (string.IsNullOrEmpty(selectOptions.Expression)) + throw new InvalidOperationException("The Expression " + nameof(selectOptions.Expression) + " for Select Object Content cannot be empty."); - if (SelectOptions.InputSerialization is null || SelectOptions.OutputSerialization is null) + if (selectOptions.InputSerialization is null || selectOptions.OutputSerialization is null) throw new InvalidOperationException( "The Input/Output serialization members for SelectObjectContentArgs should be initialized " + - nameof(SelectOptions.InputSerialization) + " " + nameof(SelectOptions.OutputSerialization)); + nameof(selectOptions.InputSerialization) + " " + nameof(selectOptions.OutputSerialization)); } internal override HttpRequestMessageBuilder BuildRequest(HttpRequestMessageBuilder requestMessageBuilder) @@ -50,7 +50,7 @@ internal override HttpRequestMessageBuilder BuildRequest(HttpRequestMessageBuild if (RequestBody.IsEmpty) { - RequestBody = Encoding.UTF8.GetBytes(SelectOptions.MarshalXML()); + RequestBody = Encoding.UTF8.GetBytes(selectOptions.MarshalXML()); requestMessageBuilder.SetBody(RequestBody); } @@ -62,31 +62,31 @@ internal override HttpRequestMessageBuilder BuildRequest(HttpRequestMessageBuild public SelectObjectContentArgs WithExpressionType(QueryExpressionType e) { - SelectOptions.ExpressionType = e; + selectOptions.ExpressionType = e; return this; } public SelectObjectContentArgs WithQueryExpression(string expr) { - SelectOptions.Expression = expr; + selectOptions.Expression = expr; return this; } public SelectObjectContentArgs WithInputSerialization(SelectObjectInputSerialization serialization) { - SelectOptions.InputSerialization = serialization; + selectOptions.InputSerialization = serialization; return this; } public SelectObjectContentArgs WithOutputSerialization(SelectObjectOutputSerialization serialization) { - SelectOptions.OutputSerialization = serialization; + selectOptions.OutputSerialization = serialization; return this; } public SelectObjectContentArgs WithRequestProgress(RequestProgress requestProgress) { - SelectOptions.RequestProgress = requestProgress; + selectOptions.RequestProgress = requestProgress; return this; } } diff --git a/Minio/DataModel/Response/GetVersioningResponse.cs b/Minio/DataModel/Response/GetVersioningResponse.cs index a6f600f89a..2fb99bff88 100644 --- a/Minio/DataModel/Response/GetVersioningResponse.cs +++ b/Minio/DataModel/Response/GetVersioningResponse.cs @@ -24,8 +24,7 @@ internal class GetVersioningResponse : GenericResponse internal GetVersioningResponse(HttpStatusCode statusCode, string responseContent) : base(statusCode, responseContent) { - if (string.IsNullOrEmpty(responseContent) || - HttpStatusCode.OK != statusCode) + if (string.IsNullOrEmpty(responseContent) || HttpStatusCode.OK != statusCode) return; VersioningConfig = Utils.DeserializeXml(responseContent); diff --git a/Minio/DataModel/Response/NewMultipartUploadResponse.cs b/Minio/DataModel/Response/NewMultipartUploadResponse.cs index 5c1d2ddb6a..2a5dd61713 100644 --- a/Minio/DataModel/Response/NewMultipartUploadResponse.cs +++ b/Minio/DataModel/Response/NewMultipartUploadResponse.cs @@ -15,8 +15,6 @@ */ using System.Net; -using System.Text; -using CommunityToolkit.HighPerformance; using Minio.DataModel.Result; using Minio.Helper; @@ -27,8 +25,7 @@ internal class NewMultipartUploadResponse : GenericResponse internal NewMultipartUploadResponse(HttpStatusCode statusCode, string responseContent) : base(statusCode, responseContent) { - using var stream = Encoding.UTF8.GetBytes(responseContent).AsMemory().AsStream(); - var newUpload = Utils.DeserializeXml(stream); + var newUpload = Utils.DeserializeXml(responseContent); UploadId = newUpload.UploadId; } diff --git a/Minio/DataModel/Response/RemoveObjectsResponse.cs b/Minio/DataModel/Response/RemoveObjectsResponse.cs index 0f111d7205..503f009a15 100644 --- a/Minio/DataModel/Response/RemoveObjectsResponse.cs +++ b/Minio/DataModel/Response/RemoveObjectsResponse.cs @@ -15,8 +15,6 @@ */ using System.Net; -using System.Text; -using CommunityToolkit.HighPerformance; using Minio.DataModel.Result; using Minio.Helper; @@ -27,8 +25,7 @@ internal class RemoveObjectsResponse : GenericResponse internal RemoveObjectsResponse(HttpStatusCode statusCode, string responseContent) : base(statusCode, responseContent) { - using var stream = Encoding.UTF8.GetBytes(responseContent).AsMemory().AsStream(); - DeletedObjectsResult = Utils.DeserializeXml(stream); + DeletedObjectsResult = Utils.DeserializeXml(responseContent); } internal DeleteObjectsResult DeletedObjectsResult { get; } diff --git a/Minio/Exceptions/BucketNotFoundException.cs b/Minio/Exceptions/BucketNotFoundException.cs index f100bff8fd..b60126ba60 100644 --- a/Minio/Exceptions/BucketNotFoundException.cs +++ b/Minio/Exceptions/BucketNotFoundException.cs @@ -24,7 +24,7 @@ public class BucketNotFoundException : MinioException { private readonly string bucketName; - public BucketNotFoundException(string bucketName, string message) : base(message) + public BucketNotFoundException(string bucketName, string message = "Bucket NotFound") : base(message) { this.bucketName = bucketName; } @@ -33,15 +33,16 @@ public BucketNotFoundException(ResponseResult serverResponse) : base(serverRespo { } - public BucketNotFoundException(string message) : base(message) + public BucketNotFoundException(string message = "Bucket NotFound") : base(message) { } - public BucketNotFoundException(string message, ResponseResult serverResponse) : base(message, serverResponse) + public BucketNotFoundException() { } - public BucketNotFoundException() + public BucketNotFoundException(Exception innerException, string message = "Bucket NotFound") : base(message, + innerException) { } @@ -49,6 +50,10 @@ public BucketNotFoundException(string message, Exception innerException) : base( { } + public BucketNotFoundException(string message, ResponseResult serverResponse) : base(message, serverResponse) + { + } + public override string ToString() { return $"{bucketName}: {base.ToString()}"; diff --git a/Minio/Exceptions/ObjectNotFoundException.cs b/Minio/Exceptions/ObjectNotFoundException.cs index 6d57ed23cd..9a33c0e541 100644 --- a/Minio/Exceptions/ObjectNotFoundException.cs +++ b/Minio/Exceptions/ObjectNotFoundException.cs @@ -23,7 +23,7 @@ public class ObjectNotFoundException : MinioException { private readonly string objectName; - public ObjectNotFoundException(string objectName, string message) : base(message) + public ObjectNotFoundException(string objectName, string message = "Object NotFound") : base(message) { this.objectName = objectName; } @@ -32,11 +32,12 @@ public ObjectNotFoundException(ResponseResult serverResponse) : base(serverRespo { } - public ObjectNotFoundException(string message) : base(message) + public ObjectNotFoundException(string message = "Object NotFound") : base(message) { } - public ObjectNotFoundException(string message, ResponseResult serverResponse) : base(message, serverResponse) + public ObjectNotFoundException(ResponseResult serverResponse, string message = "Object NotFound") : base(message, + serverResponse) { } @@ -44,10 +45,19 @@ public ObjectNotFoundException() { } + public ObjectNotFoundException(Exception innerException, string message = "Object NotFound") : base(message, + innerException) + { + } + public ObjectNotFoundException(string message, Exception innerException) : base(message, innerException) { } + public ObjectNotFoundException(string message, ResponseResult serverResponse) : base(message, serverResponse) + { + } + public override string ToString() { return $"{objectName}: {base.ToString()}"; diff --git a/Minio/Handlers/DefaultErrorHandler.cs b/Minio/Handlers/DefaultErrorHandler.cs index 0ef4dc5913..4a21e477ea 100644 --- a/Minio/Handlers/DefaultErrorHandler.cs +++ b/Minio/Handlers/DefaultErrorHandler.cs @@ -9,7 +9,8 @@ public void Handle(ResponseResult response) { if (response is null) throw new ArgumentNullException(nameof(response)); - if (response.StatusCode is < HttpStatusCode.OK or >= HttpStatusCode.BadRequest) + if (response.StatusCode is < HttpStatusCode.OK or >= HttpStatusCode.BadRequest || + response.Exception is not null) MinioClient.ParseError(response); } } diff --git a/Minio/Handlers/IApiResponseErrorHandler.cs b/Minio/Handlers/IApiResponseErrorHandler.cs index 79ea6391fa..e204780ca0 100644 --- a/Minio/Handlers/IApiResponseErrorHandler.cs +++ b/Minio/Handlers/IApiResponseErrorHandler.cs @@ -2,7 +2,10 @@ namespace Minio.Handlers; +#pragma warning disable 0067 public interface IApiResponseErrorHandler +#pragma warning disable 0067 + { - void Handle(ResponseResult response); + void Handle(ResponseResult responseResult); } diff --git a/Minio/Helper/OperationsHelper.cs b/Minio/Helper/OperationsHelper.cs index 81ac993697..68a6bf8af9 100644 --- a/Minio/Helper/OperationsHelper.cs +++ b/Minio/Helper/OperationsHelper.cs @@ -109,7 +109,7 @@ private async Task GetObjectStreamAsync(GetObjectArgs args, CancellationToken ca { var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken).ConfigureAwait(false); } @@ -133,7 +133,7 @@ private async Task> RemoveBucketObjectsAsync(RemoveObjectsArg { var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); using var response = - await this.ExecuteTaskAsync(ResponseErrorHandlers, requestMessageBuilder, + await this.ExecuteTaskAsync(requestMessageBuilder, cancellationToken: cancellationToken) .ConfigureAwait(false); var removeObjectsResponse = new RemoveObjectsResponse(response.StatusCode, response.Content); diff --git a/Minio/Helper/OperationsUtil.cs b/Minio/Helper/OperationsUtil.cs index 36e97542e8..0d502e7c40 100644 --- a/Minio/Helper/OperationsUtil.cs +++ b/Minio/Helper/OperationsUtil.cs @@ -18,7 +18,7 @@ namespace Minio.Helper; public static class OperationsUtil { - private static readonly List SupportedHeaders = new() + private static readonly List supportedHeaders = new() { "cache-control", "content-encoding", @@ -28,7 +28,7 @@ public static class OperationsUtil "x-minio-extract" }; - private static readonly List SSEHeaders = new() + private static readonly List sSEHeaders = new() { "X-Amz-Server-Side-Encryption-Customer-Algorithm", "X-Amz-Server-Side-Encryption-Customer-Key", @@ -41,12 +41,12 @@ public static class OperationsUtil internal static bool IsSupportedHeader(string hdr, IEqualityComparer comparer = null) { comparer ??= StringComparer.OrdinalIgnoreCase; - return SupportedHeaders.Contains(hdr, comparer); + return supportedHeaders.Contains(hdr, comparer); } internal static bool IsSSEHeader(string hdr, IEqualityComparer comparer = null) { comparer ??= StringComparer.OrdinalIgnoreCase; - return SSEHeaders.Contains(hdr, comparer); + return sSEHeaders.Contains(hdr, comparer); } } diff --git a/Minio/HttpRequestMessageBuilder.cs b/Minio/HttpRequestMessageBuilder.cs index ebdfe0fc59..0d5cf84642 100644 --- a/Minio/HttpRequestMessageBuilder.cs +++ b/Minio/HttpRequestMessageBuilder.cs @@ -76,6 +76,8 @@ public HttpRequestMessage Request switch (key) { case "content-type": + { + val ??= "application/octet-stream"; try { request.Content.Headers.ContentType = new MediaTypeHeaderValue(val); @@ -86,6 +88,7 @@ public HttpRequestMessage Request } break; + } case "content-length": request.Content.Headers.ContentLength = Convert.ToInt32(val, CultureInfo.InvariantCulture); diff --git a/Minio/Minio.csproj b/Minio/Minio.csproj index a5005128ad..65fba639d6 100644 --- a/Minio/Minio.csproj +++ b/Minio/Minio.csproj @@ -2,7 +2,7 @@ Minio Minio - net6.0;net8.0;netstandard2.0 + net8.0;netstandard2.0 ..\Minio.snk true true diff --git a/Minio/MinioClient.cs b/Minio/MinioClient.cs index 4b30cd710d..1b9711092b 100644 --- a/Minio/MinioClient.cs +++ b/Minio/MinioClient.cs @@ -119,16 +119,34 @@ internal static void ParseError(ResponseResult response) private static void ParseErrorNoContent(ResponseResult response) { - if (HttpStatusCode.Forbidden == response.StatusCode - || HttpStatusCode.BadRequest == response.StatusCode - || HttpStatusCode.NotFound == response.StatusCode - || HttpStatusCode.MethodNotAllowed == response.StatusCode - || HttpStatusCode.NotImplemented == response.StatusCode) - ParseWellKnownErrorNoContent(response); + if (response is null) + throw new ArgumentNullException(nameof(response)); + var statusCodeStrs = new[] + { + nameof(HttpStatusCode.Forbidden), nameof(HttpStatusCode.BadRequest), nameof(HttpStatusCode.NotFound), + nameof(HttpStatusCode.MethodNotAllowed), nameof(HttpStatusCode.NotImplemented) + }; + if (response.Exception != null && !string.IsNullOrEmpty(response.ErrorMessage)) + { + foreach (var exception in statusCodeStrs) + if ((response.ErrorMessage?.Contains(exception, StringComparison.InvariantCulture) ?? false) || + (response.ErrorMessage?.Contains(response.StatusCode.ToString(), + StringComparison.InvariantCulture) ?? false)) + { + ParseWellKnownErrorNoContent(response); + break; + } + } + else if (statusCodeStrs.Contains(response.StatusCode.ToString(), StringComparer.Ordinal)) + { + ParseWellKnownErrorNoContent(response); + } #pragma warning disable MA0099 // Use Explicit enum value instead of 0 if (response.StatusCode == 0) throw new ConnectionException("Connection error:" + response.ErrorMessage, response); + if (response.Exception.GetType() == typeof(TaskCanceledException)) + throw response.Exception; #pragma warning restore MA0099 // Use Explicit enum value instead of 0 throw new InternalClientException( "Unsuccessful response from server without XML:" + response.ErrorMessage, response); @@ -158,7 +176,8 @@ private static void ParseWellKnownErrorNoContent(ResponseResult response) // zero, one or two segments var resourceSplits = pathAndQuery.Split(separator, 2, StringSplitOptions.RemoveEmptyEntries); - if (HttpStatusCode.NotFound == response.StatusCode) + if (response.StatusCode.ToString().Contains(nameof(HttpStatusCode.NotFound), StringComparison.Ordinal) || + response.Exception.ToString().Contains(nameof(HttpStatusCode.NotFound), StringComparison.Ordinal)) { var pathLength = resourceSplits.Length; var isAWS = host.EndsWith("s3.amazonaws.com", StringComparison.OrdinalIgnoreCase); @@ -168,22 +187,22 @@ private static void ParseWellKnownErrorNoContent(ResponseResult response) { var objectName = resourceSplits[1]; errorResponse.Code = "NoSuchKey"; - error = new ObjectNotFoundException(objectName, "Not found."); + error = new ObjectNotFoundException(objectName); } else if (pathLength == 1) { var resource = resourceSplits[0]; - if (isAWS && isVirtual && !string.IsNullOrEmpty(pathAndQuery)) + if (isAWS && isVirtual) { errorResponse.Code = "NoSuchKey"; - error = new ObjectNotFoundException(resource, "Not found."); + error = new ObjectNotFoundException(resource); } else { errorResponse.Code = "NoSuchBucket"; BucketRegionCache.Instance.Remove(resource); - error = new BucketNotFoundException(resource, "Not found."); + error = new BucketNotFoundException(resource); } } else @@ -214,7 +233,7 @@ private static void ParseWellKnownErrorNoContent(ResponseResult response) error = new AccessDeniedException("Access denied on the resource: " + pathAndQuery); } - error.Response = errorResponse; + response.Exception = error; throw error; } @@ -223,13 +242,13 @@ private static void ParseErrorFromContent(ResponseResult response) if (response is null) throw new ArgumentNullException(nameof(response)); - if (response.StatusCode == HttpStatusCode.NotFound + if (response.StatusCode.ToString().Contains(nameof(HttpStatusCode.NotFound), StringComparison.OrdinalIgnoreCase) && response.Request.RequestUri.PathAndQuery.EndsWith("?location", StringComparison.OrdinalIgnoreCase) && response.Request.Method.Equals(HttpMethod.Get)) { var bucketName = response.Request.RequestUri.PathAndQuery.Split('?')[0]; BucketRegionCache.Instance.Remove(bucketName); - throw new BucketNotFoundException(bucketName, "Not found."); + throw new BucketNotFoundException(bucketName); } var errResponse = Utils.DeserializeXml(response.Content); @@ -240,22 +259,23 @@ private static void ParseErrorFromContent(ResponseResult response) throw new AuthorizationException(errResponse.Resource, errResponse.BucketName, errResponse.Message); // Handle XML response for Bucket Policy not found case - if (response.StatusCode == HttpStatusCode.NotFound + if (response.StatusCode.ToString().Contains(nameof(HttpStatusCode.NotFound), StringComparison.OrdinalIgnoreCase) && response.Request.RequestUri.PathAndQuery.EndsWith("?policy", StringComparison.OrdinalIgnoreCase) && response.Request.Method.Equals(HttpMethod.Get) && string.Equals(errResponse.Code, "NoSuchBucketPolicy", StringComparison.OrdinalIgnoreCase)) throw new ErrorResponseException(errResponse, response) { XmlError = response.Content }; - if (response.StatusCode == HttpStatusCode.NotFound + if (response.StatusCode.ToString().Contains(nameof(HttpStatusCode.NotFound), StringComparison.OrdinalIgnoreCase) && string.Equals(errResponse.Code, "NoSuchBucket", StringComparison.OrdinalIgnoreCase)) - throw new BucketNotFoundException(errResponse.BucketName, "Not found."); + throw new BucketNotFoundException(errResponse.BucketName); - if (response.StatusCode == HttpStatusCode.BadRequest + if (response.StatusCode.ToString().Contains(nameof(HttpStatusCode.NotFound), StringComparison.OrdinalIgnoreCase) && errResponse.Code.Equals("MalformedXML", StringComparison.OrdinalIgnoreCase)) throw new MalFormedXMLException(errResponse.Resource, errResponse.BucketName, errResponse.Message, errResponse.Key); - if (response.StatusCode == HttpStatusCode.NotImplemented + if (response.StatusCode.ToString() + .Contains(nameof(HttpStatusCode.NotImplemented), StringComparison.OrdinalIgnoreCase) && errResponse.Code.Equals("NotImplemented", StringComparison.OrdinalIgnoreCase)) { #pragma warning disable MA0025 // Implement the functionality instead of throwing NotImplementedException @@ -271,18 +291,17 @@ private static void ParseErrorFromContent(ResponseResult response) throw new MissingObjectLockConfigurationException(errResponse.BucketName, errResponse.Message); } - if (response.StatusCode == HttpStatusCode.NotFound + if (response.StatusCode.ToString().Contains(nameof(HttpStatusCode.NotFound), StringComparison.OrdinalIgnoreCase) && errResponse.Code.Equals("ObjectLockConfigurationNotFoundError", StringComparison.OrdinalIgnoreCase)) throw new MissingObjectLockConfigurationException(errResponse.BucketName, errResponse.Message); - if (response.StatusCode == HttpStatusCode.NotFound + if (response.StatusCode.ToString().Contains(nameof(HttpStatusCode.NotFound), StringComparison.OrdinalIgnoreCase) && errResponse.Code.Equals("ReplicationConfigurationNotFoundError", StringComparison.OrdinalIgnoreCase)) throw new MissingBucketReplicationConfigurationException(errResponse.BucketName, errResponse.Message); if (response.StatusCode == HttpStatusCode.Conflict && errResponse.Code.Equals("BucketAlreadyOwnedByYou", StringComparison.OrdinalIgnoreCase)) - throw new ArgumentException("Bucket already owned by you: " + errResponse.BucketName, - nameof(response)); + throw new ArgumentException("Bucket already owned by you: " + errResponse.BucketName, nameof(response)); if (response.StatusCode == HttpStatusCode.PreconditionFailed && errResponse.Code.Equals("PreconditionFailed", StringComparison.OrdinalIgnoreCase)) diff --git a/Minio/RequestExtensions.cs b/Minio/RequestExtensions.cs index 396183ab11..ebdaa75dce 100644 --- a/Minio/RequestExtensions.cs +++ b/Minio/RequestExtensions.cs @@ -1,7 +1,6 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Net; -using System.Web; using Minio.Credentials; using Minio.DataModel; using Minio.DataModel.Args; @@ -39,44 +38,45 @@ public static Task WrapperPutAsync(this IMinioClient minioClient, string url, St /// Actual doer that executes the request on the server /// /// - /// List of handlers to override default handling /// The build of HttpRequestMessageBuilder + /// any type of Exception; if an exception type is going to be ignored /// boolean; if true role credentials, otherwise IAM user /// Optional cancellation token to cancel the operation /// ResponseResult - internal static Task ExecuteTaskAsync(this IMinioClient minioClient, - IEnumerable errorHandlers, + internal static async Task ExecuteTaskAsync(this IMinioClient minioClient, HttpRequestMessageBuilder requestMessageBuilder, + Type ignoreExceptionType = null, bool isSts = false, CancellationToken cancellationToken = default) { - Task responseResult; - try + var startTime = DateTime.Now; + var responseResult = new ResponseResult(requestMessageBuilder.Request, response: null); + if (minioClient.Config.RequestTimeout > 0) { - if (minioClient.Config.RequestTimeout > 0) - { - using var internalTokenSource = - new CancellationTokenSource(new TimeSpan(0, 0, 0, 0, minioClient.Config.RequestTimeout)); - using var timeoutTokenSource = - CancellationTokenSource.CreateLinkedTokenSource(internalTokenSource.Token, cancellationToken); - cancellationToken = timeoutTokenSource.Token; - } - - responseResult = minioClient.ExecuteWithRetry( - async () => await minioClient.ExecuteTaskCoreAsync(errorHandlers, requestMessageBuilder, - isSts, cancellationToken).ConfigureAwait(false)); + using var internalTokenSource = + new CancellationTokenSource(new TimeSpan(0, 0, 0, 0, minioClient.Config.RequestTimeout)); + using var timeoutTokenSource = + CancellationTokenSource.CreateLinkedTokenSource(internalTokenSource.Token, cancellationToken); + cancellationToken = timeoutTokenSource.Token; } - catch (Exception ex) + + responseResult = await minioClient.ExecuteWithRetry( + async Task () => await minioClient.ExecuteTaskCoreAsync( + requestMessageBuilder, + isSts, cancellationToken).ConfigureAwait(false)).ConfigureAwait(false); + if ((responseResult is not null && + !Equals(responseResult.Exception?.GetType(), ignoreExceptionType)) || + responseResult.StatusCode != HttpStatusCode.OK) { - Console.WriteLine($"\n\n *** ExecuteTaskAsync::Threw an exception => {ex.Message}"); - throw; + var handler = new DefaultErrorHandler(); + handler.Handle(responseResult); } return responseResult; } private static async Task ExecuteTaskCoreAsync(this IMinioClient minioClient, - IEnumerable errorHandlers, + // IEnumerable errorHandlers, HttpRequestMessageBuilder requestMessageBuilder, bool isSts = false, CancellationToken cancellationToken = default) @@ -90,75 +90,32 @@ private static async Task ExecuteTaskCoreAsync(this IMinioClient v4Authenticator.Authenticate(requestMessageBuilder, isSts)); var request = requestMessageBuilder.Request; - - var responseResult = new ResponseResult(request, response: null); + var responseResult = new ResponseResult(request, new HttpResponseMessage()); try { var response = await minioClient.Config.HttpClient.SendAsync(request, - HttpCompletionOption.ResponseHeadersRead, cancellationToken) - .ConfigureAwait(false); + HttpCompletionOption.ResponseHeadersRead, + cancellationToken).ConfigureAwait(false); + responseResult = new ResponseResult(request, response); if (requestMessageBuilder.ResponseWriter is not null) await requestMessageBuilder.ResponseWriter(responseResult.ContentStream, cancellationToken) .ConfigureAwait(false); - - var path = request.RequestUri.LocalPath.TrimStart('/').TrimEnd('/') - .Split('/', StringSplitOptions.RemoveEmptyEntries); - if (responseResult.Response.StatusCode == HttpStatusCode.NotFound) - { - if (request.Method == HttpMethod.Get) - { - var q = HttpUtility.ParseQueryString(request.RequestUri.Query); - if (q.Get("object-lock") != null) - { - responseResult.Exception = new MissingObjectLockConfigurationException(); - return responseResult; - } - } - - if (request.Method == HttpMethod.Head) - { - if (responseResult.Exception is BucketNotFoundException || path.Length == 1) - responseResult.Exception = new BucketNotFoundException(); - - if (path.Length > 1) - { - var found = await minioClient - .BucketExistsAsync(new BucketExistsArgs().WithBucket(path[0]), cancellationToken) - .ConfigureAwait(false); - responseResult.Exception = !found - ? new Exception("ThrowBucketNotFoundException") - : new ObjectNotFoundException(); - throw responseResult.Exception; - } - } - - return responseResult; - } - - minioClient.HandleIfErrorResponse(responseResult, errorHandlers, startTime); - return responseResult; } - catch (Exception ex) when (ex is not (OperationCanceledException or - ObjectNotFoundException)) + catch (Exception ex) { - if (ex.Message.Equals("ThrowBucketNotFoundException", StringComparison.Ordinal)) - throw new BucketNotFoundException(); - - if (responseResult is not null) - responseResult.Exception = ex; - else - responseResult = new ResponseResult(request, ex); - return responseResult; + responseResult.Exception = ex; } + + return responseResult; } - private static Task ExecuteWithRetry(this IMinioClient minioClient, + private static async Task ExecuteWithRetry(this IMinioClient minioClient, Func> executeRequestCallback) { return minioClient.Config.RetryPolicyHandler is null - ? executeRequestCallback() - : minioClient.Config.RetryPolicyHandler.Handle(executeRequestCallback); + ? await executeRequestCallback().ConfigureAwait(false) + : await minioClient.Config.RetryPolicyHandler.Handle(executeRequestCallback).ConfigureAwait(false); } /// @@ -312,7 +269,7 @@ internal static async Task CreateRequest(this IMinioC messageBuilder.AddOrUpdateHeaderParameter("Content-Type", contentType); } - if (headerMap is not null) + if (headerMap?.Count > 0) { if (headerMap.TryGetValue(messageBuilder.ContentTypeKey, out var value) && !string.IsNullOrEmpty(value)) headerMap[messageBuilder.ContentTypeKey] = contentType; @@ -368,9 +325,11 @@ internal static async Task GetRegion(this IMinioClient minioClient, stri /// /// /// + /// private static void HandleIfErrorResponse(this IMinioClient minioClient, ResponseResult response, IEnumerable handlers, - long startTime) + long startTime, + Type ignoreExceptionType = null) { // Logs Response if HTTP tracing is enabled if (minioClient.Config.TraceHttp) @@ -380,14 +339,21 @@ private static void HandleIfErrorResponse(this IMinioClient minioClient, Respons } if (response.Exception is not null) - throw response.Exception; - - if (handlers.Any()) - // Run through handlers passed to take up error handling - foreach (var handler in handlers) - handler.Handle(response); - else - minioClient.DefaultErrorHandler.Handle(response); + { + if (response.Exception?.GetType() == ignoreExceptionType) + { + response.Exception = null; + } + else + { + if (handlers.Any()) + // Run through handlers passed to take up error handling + foreach (var handler in handlers) + handler.Handle(response); + else + minioClient.DefaultErrorHandler.Handle(response); + } + } } private static TimeSpan GetElapsedTime(long startTimestamp) diff --git a/SimpleTest/SimpleTest.csproj b/SimpleTest/SimpleTest.csproj index 6e374e2210..728fdd2557 100644 --- a/SimpleTest/SimpleTest.csproj +++ b/SimpleTest/SimpleTest.csproj @@ -1,6 +1,6 @@  - net6.0;net8.0 + net8.0 Exe False