From 9b7b5989624a2e807b75bad85d0ed77a7bc3b1b6 Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Tue, 29 Jan 2019 12:18:35 -0800 Subject: [PATCH] Set prefix, delimiter params even when empty We have never set values which are empty on the request because they are perhaps not useful in the List query, but this assumption is wrong when there are restricted policies for a given user, because empty is actually a valid value in IAM or Bucket policy conditions. For example following condition would never work with our ListObjects call and AWS cli would work fine. "Condition": { "StringEquals": { "s3:prefix": [ "", "data/", "data" ], "s3:delimiter": [ "/", "" ] } } The reason is empty or not prefix and delimiter should be added to the query param in List operation, such that server can use the value to validate the policies for the incoming request. Refer minio/minio-go#1064 --- Docs/API.md | 192 +++++++++++------------ Docs/zh_CN/API.md | 186 +++++++++++----------- Minio.Examples/Cases/ListObjects.cs | 7 +- Minio.Functional.Tests/FunctionalTest.cs | 71 +++++---- Minio/ApiEndpoints/BucketOperations.cs | 58 ++++--- Minio/ApiEndpoints/IBucketOperations.cs | 17 +- Minio/ApiEndpoints/IObjectOperations.cs | 13 +- Minio/ApiEndpoints/ObjectOperations.cs | 67 +++----- 8 files changed, 300 insertions(+), 311 deletions(-) diff --git a/Docs/API.md b/Docs/API.md index abb38315f..eb361dbd3 100644 --- a/Docs/API.md +++ b/Docs/API.md @@ -1,12 +1,12 @@ # .NET Client API Reference [![Slack](https://slack.minio.io/slack?type=svg)](https://slack.minio.io) - + ## Initialize Minio Client object. ## Minio ```cs var minioClient = new MinioClient("play.minio.io:9000", - "Q3AM3UQ867SPQQA43P2F", + "Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG" ).WithSSL(); ``` @@ -15,7 +15,7 @@ var minioClient = new MinioClient("play.minio.io:9000", ```cs -var s3Client = new MinioClient("s3.amazonaws.com", +var s3Client = new MinioClient("s3.amazonaws.com", "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY" ).WithSSL(); @@ -39,7 +39,7 @@ var s3Client = new MinioClient("s3.amazonaws.com", | | |---| |`public MinioClient(string endpoint, string accessKey = "", string secretKey = "", string region="", string sessionToken="")` | -| Creates Minio client object with given endpoint.AccessKey,secretKey, region and sessionToken are optional parameters,and can be omitted for anonymous access. +| Creates Minio client object with given endpoint.AccessKey,secretKey, region and sessionToken are optional parameters,and can be omitted for anonymous access. The client object uses Http access by default. To use Https, chain method WithSSL() to client object to use secure transfer protocol | @@ -80,8 +80,8 @@ __Example__ MinioClient minioClient = new MinioClient("play.minio.io:9000"); // 2. public MinioClient(String endpoint, String accessKey, String secretKey) -MinioClient minioClient = new MinioClient("play.minio.io:9000", - accessKey:"Q3AM3UQ867SPQQA43P2F", +MinioClient minioClient = new MinioClient("play.minio.io:9000", + accessKey:"Q3AM3UQ867SPQQA43P2F", secretKey:"zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG" ).WithSSL(); @@ -102,8 +102,8 @@ MinioClient minioClient = new MinioClient("my-ip-address:9000","tempuserid","tem MinioClient s3Client = new MinioClient("s3.amazonaws.com").WithSSL(); // 2. public MinioClient(String endpoint, String accessKey, String secretKey) -MinioClient s3Client = new MinioClient("s3.amazonaws.com:80", - accessKey:"YOUR-ACCESSKEYID", +MinioClient s3Client = new MinioClient("s3.amazonaws.com:80", + accessKey:"YOUR-ACCESSKEYID", secretKey:"YOUR-SECRETACCESSKEY").WithSSL(); ``` @@ -138,22 +138,22 @@ __Example__ ```cs -try +try { // Create bucket if it doesn't exist. bool found = await minioClient.BucketExistsAsync("mybucket"); - if (found) + if (found) { Console.Out.WriteLine("mybucket already exists"); - } - else + } + else { // Create bucket 'my-bucketname'. await minioClient.MakeBucketAsync("mybucket"); Console.Out.WriteLine("mybucket is created successfully"); } -} -catch (MinioException e) +} +catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -185,7 +185,7 @@ __Example__ ```cs -try +try { // List buckets that have read access. var list = await minioClient.ListBucketsAsync(); @@ -193,8 +193,8 @@ try { Console.Out.WriteLine(bucket.Name + " " + bucket.CreationDateDateTime); } -} -catch (MinioException e) +} +catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -238,7 +238,7 @@ try bool found = await minioClient.BucketExistsAsync(bucketName); Console.Out.WriteLine("bucket-name " + ((found == true) ? "exists" : "does not exist")); } -catch (MinioException e) +catch (MinioException e) { Console.WriteLine("[Bucket] Exception: {0}", e); } @@ -280,22 +280,22 @@ __Example__ ```cs -try +try { // Check if my-bucket exists before removing it. bool found = await minioClient.BucketExistsAsync("mybucket"); - if (found) - { + if (found) + { // Remove bucket my-bucketname. This operation will succeed only if the bucket is empty. await minioClient.RemoveBucketAsync("mybucket"); Console.Out.WriteLine("mybucket is removed successfully"); } - else + else { Console.Out.WriteLine("mybucket does not exist"); } -} -catch(MinioException e) +} +catch(MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -304,9 +304,9 @@ catch(MinioException e) ### ListObjectsAsync(string bucketName, string prefix = null, bool recursive = true) -`IObservable ListObjectsAsync(string bucketName, string prefix = null, bool recursive = true, CancellationToken cancellationToken = default(CancellationToken))` +`IObservable ListObjectsAsync(string bucketName, string prefix = null, bool recursive = false, CancellationToken cancellationToken = default(CancellationToken))` -Lists all objects in a bucket. +Lists all objects in a bucket. __Parameters__ @@ -315,7 +315,7 @@ __Parameters__ |:--- |:--- |:--- | | ``bucketName`` | _string_ | Name of the bucket | | ``prefix`` | _string_ | Prefix string. List objects whose name starts with ``prefix`` | -| ``recursive`` | _bool_ | when false, emulates a directory structure where each listing returned is either a full object or part of the object's key up to the first '/'. All objects with the same prefix up to the first '/' will be merged into one entry | +| ``recursive`` | _bool_ | when false, emulates a directory structure where each listing returned is either a full object or part of the object's key up to the first '/'. All objects with the same prefix up to the first '/' will be merged into one entry. Defaults to `false`| | ``cancellationToken``| _System.Threading.CancellationToken_ | Optional parameter. Defaults to default(CancellationToken) | @@ -328,25 +328,25 @@ __Example__ ```cs -try +try { // Check whether 'mybucket' exists or not. bool found = minioClient.BucketExistsAsync("mybucket"); - if (found) + if (found) { // List objects from 'my-bucketname' IObservable observable = minioClient.ListObjectsAsync("mybucket", "prefix", true); IDisposable subscription = observable.Subscribe( item => Console.WriteLine("OnNext: {0}", item.Key), ex => Console.WriteLine("OnError: {0}", ex.Message), - () => Console.WriteLine("OnComplete: {0}")); - } - else + () => Console.WriteLine("OnComplete: {0}")); + } + else { Console.Out.WriteLine("mybucket does not exist"); } -} -catch (MinioException e) +} +catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -381,11 +381,11 @@ __Example__ ```cs -try +try { // Check whether 'mybucket' exist or not. bool found = minioClient.BucketExistsAsync("mybucket"); - if (found) + if (found) { // List all incomplete multipart upload of objects in 'mybucket' IObservable observable = minioClient.ListIncompleteUploads("mybucket", "prefix", true); @@ -393,13 +393,13 @@ try item => Console.WriteLine("OnNext: {0}", item.Key), ex => Console.WriteLine("OnError: {0}", ex.Message), () => Console.WriteLine("OnComplete: {0}")); - } - else + } + else { Console.Out.WriteLine("mybucket does not exist"); } -} -catch (MinioException e) +} +catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -435,12 +435,12 @@ __Example__ ```cs -try +try { String policyJson = await minioClient.GetPolicyAsync("myBucket"); Console.Out.WriteLine("Current policy: " + policy.GetType().ToString()); -} -catch (MinioException e) +} +catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -475,11 +475,11 @@ __Parameters__ __Example__ ```cs -try +try { await minioClient.SetPolicyAsync("myBucket"); } -catch (MinioException e) +catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -513,11 +513,11 @@ __Parameters__ __Example__ ```cs -try +try { BucketNotification notification = new BucketNotification(); Arn topicArn = new Arn("aws", "sns", "us-west-1", "412334153608", "topicminio"); - + TopicConfig topicConfiguration = new TopicConfig(topicArn); List events = new List(){ EventType.ObjectCreatedPut , EventType.ObjectCreatedCopy }; topicConfiguration.AddEvents(events); @@ -527,13 +527,13 @@ try QueueConfig queueConfiguration = new QueueConfig("arn:aws:sqs:us-west-1:482314153608:testminioqueue1"); queueConfiguration.AddEvents(new List() { EventType.ObjectCreatedCompleteMultipartUpload }); - notification.AddQueue(queueConfiguration); - - await minio.SetBucketNotificationsAsync(bucketName, + notification.AddQueue(queueConfiguration); + + await minio.SetBucketNotificationsAsync(bucketName, notification); Console.Out.WriteLine("Notifications set for the bucket " + bucketName + " successfully"); } -catch (MinioException e) +catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -569,12 +569,12 @@ __Example__ ```cs -try +try { BucketNotification notifications = await minioClient.GetBucketNotificationAsync(bucketName); Console.Out.WriteLine("Notifications is " + notifications.ToXML()); -} -catch (MinioException e) +} +catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -610,12 +610,12 @@ __Example__ ```cs -try +try { await minioClient.RemoveAllBucketNotificationsAsync(bucketName); Console.Out.WriteLine("Notifications successfully removed from the bucket " + bucketName); -} -catch (MinioException e) +} +catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -655,7 +655,7 @@ __Example__ ```cs -try +try { // Check whether the object exists using statObject(). // If the object is not found, statObject() throws an exception, @@ -664,13 +664,13 @@ try await minioClient.StatObjectAsync("mybucket", "myobject"); // Get input stream to have content of 'my-objectname' from 'my-bucketname' - await minioClient.GetObjectAsync("mybucket", "myobject", + await minioClient.GetObjectAsync("mybucket", "myobject", (stream) => { stream.CopyTo(Console.OpenStandardOutput()); }); - } - catch (MinioException e) + } + catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -692,7 +692,7 @@ __Parameters__ | ``bucketName`` | _string_ | Name of the bucket. | | ``objectName`` | _string_ | Object name in the bucket. | | ``offset``| _long_ | Offset of the object from where stream will start | -| ``length``| _long_| Length of the object to read in from the stream | +| ``length``| _long_| Length of the object to read in from the stream | | ``callback`` | _Action_ | Call back to process stream | | ``sse`` | _ServerSideEncryption_ | Server-side encryption option | Optional parameter. Defaults to null | | ``cancellationToken``| _System.Threading.CancellationToken_ | Optional parameter. Defaults to default(CancellationToken) | @@ -710,7 +710,7 @@ __Example__ ```cs -try +try { // Check whether the object exists using statObject(). // If the object is not found, statObject() throws an exception, @@ -724,8 +724,8 @@ try { stream.CopyTo(Console.OpenStandardOutput()); }); - } - catch (MinioException e) + } + catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -761,7 +761,7 @@ __Parameters__ __Example__ ```cs -try +try { // Check whether the object exists using statObjectAsync(). // If the object is not found, statObjectAsync() throws an exception, @@ -772,8 +772,8 @@ try // Gets the object's data and stores it in photo.jpg await minioClient.GetObjectAsync("mybucket", "myobject", "photo.jpg"); -} -catch (MinioException e) +} +catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -820,7 +820,7 @@ The maximum size of a single object is limited to 5TB. putObject transparently u ```cs -try +try { byte[] bs = File.ReadAllBytes(fileName); System.IO.MemoryStream filestream = new System.IO.MemoryStream(bs); @@ -835,8 +835,8 @@ try filestream.Length, "application/octet-stream",ssec); Console.Out.WriteLine("island.jpg is uploaded successfully"); -} -catch(MinioException e) +} +catch(MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -881,12 +881,12 @@ The maximum size of a single object is limited to 5TB. putObject transparently u ```cs -try +try { await minio.PutObjectAsync("mybucket", "island.jpg", "/mnt/photos/island.jpg",contentType: "application/octet-stream"); Console.Out.WriteLine("island.jpg is uploaded successfully"); -} -catch(MinioException e) +} +catch(MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -923,13 +923,13 @@ __Example__ ```cs -try +try { // Get the metadata of the object. ObjectStat objectStat = await minioClient.StatObjectAsync("mybucket", "myobject"); Console.Out.WriteLine(objectStat); -} -catch(MinioException e) +} +catch(MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -988,8 +988,8 @@ try */ await minioClient.CopyObjectAsync("mybucket", "island.jpg", "mydestbucket", "processed.png", copyConditions,sseSrc:sseSrc, sseDest:sseDst); Console.Out.WriteLine("island.jpg is uploaded successfully"); -} -catch(MinioException e) +} +catch(MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -1024,13 +1024,13 @@ __Example__ ```cs -try +try { // Remove objectname from the bucket my-bucketname. await minioClient.RemoveObjectAsync("mybucket", "myobject"); Console.Out.WriteLine("successfully removed mybucket/myobject"); -} -catch (MinioException e) +} +catch (MinioException e) { Console.Out.WriteLine("Error: " + e); } @@ -1064,7 +1064,7 @@ __Example__ ```cs -try +try { List objectNames = new LinkedList(); objectNames.add("my-objectname1"); @@ -1079,8 +1079,8 @@ try { Console.WriteLine("Listed all delete errors for remove objects on " + bucketName + "\n"); }); -} -catch (MinioException e) +} +catch (MinioException e) { Console.Out.WriteLine("Error: " + e); } @@ -1115,13 +1115,13 @@ __Example__ ```cs -try +try { // Removes partially uploaded objects from buckets. await minioClient.RemoveIncompleteUploadAsync("mybucket", "myobject"); Console.Out.WriteLine("successfully removed all incomplete upload session of my-bucketname/my-objectname"); -} -catch(MinioException e) +} +catch(MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -1157,12 +1157,12 @@ __Example__ ```cs -try +try { String url = await minioClient.PresignedGetObjectAsync("mybucket", "myobject", 60 * 60 * 24); Console.Out.WriteLine(url); -} -catch(MinioException e) +} +catch(MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -1196,12 +1196,12 @@ __Parameters__ __Example__ ```cs -try +try { String url = await minioClient.PresignedPutObjectAsync("mybucket", "myobject", 60 * 60 * 24); Console.Out.WriteLine(url); } -catch(MinioException e) +catch(MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -1235,7 +1235,7 @@ __Example__ ```cs -try +try { PostPolicy policy = new PostPolicy(); policy.SetContentType("image/png"); @@ -1253,8 +1253,8 @@ try } curlCommand = curlCommand + " -F file=@/etc/bashrc https://s3.amazonaws.com/my-bucketname"; Console.Out.WriteLine(curlCommand); -} -catch(MinioException e) +} +catch(MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } diff --git a/Docs/zh_CN/API.md b/Docs/zh_CN/API.md index 88499677c..472a99ba8 100644 --- a/Docs/zh_CN/API.md +++ b/Docs/zh_CN/API.md @@ -1,12 +1,12 @@ # .NET Client API参考文档 [![Slack](https://slack.minio.io/slack?type=svg)](https://slack.minio.io) - + ## 初始化Minio Client object。 ## Minio ```cs var minioClient = new MinioClient("play.minio.io:9000", - "Q3AM3UQ867SPQQA43P2F", + "Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG" ).WithSSL(); ``` @@ -14,8 +14,8 @@ var minioClient = new MinioClient("play.minio.io:9000", ## AWS S3 -```cs -var s3Client = new MinioClient("s3.amazonaws.com", +```cs +var s3Client = new MinioClient("s3.amazonaws.com", "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY" ).WithSSL(); @@ -73,8 +73,8 @@ __示例__ MinioClient minioClient = new MinioClient("play.minio.io:9000"); // 2. public MinioClient(String endpoint, String accessKey, String secretKey) -MinioClient minioClient = new MinioClient("play.minio.io:9000", - accessKey:"Q3AM3UQ867SPQQA43P2F", +MinioClient minioClient = new MinioClient("play.minio.io:9000", + accessKey:"Q3AM3UQ867SPQQA43P2F", secretKey:"zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG" ).WithSSL(); ``` @@ -88,8 +88,8 @@ MinioClient minioClient = new MinioClient("play.minio.io:9000", MinioClient s3Client = new MinioClient("s3.amazonaws.com").WithSSL(); // 2. public MinioClient(String endpoint, String accessKey, String secretKey) -MinioClient s3Client = new MinioClient("s3.amazonaws.com:80", - accessKey:"YOUR-ACCESSKEYID", +MinioClient s3Client = new MinioClient("s3.amazonaws.com:80", + accessKey:"YOUR-ACCESSKEYID", secretKey:"YOUR-SECRETACCESSKEY").WithSSL(); ``` @@ -124,22 +124,22 @@ __示例__ ```cs -try +try { // Create bucket if it doesn't exist. bool found = await minioClient.BucketExistsAsync("mybucket"); - if (found) + if (found) { Console.Out.WriteLine("mybucket already exists"); - } - else + } + else { // Create bucket 'my-bucketname'. await minioClient.MakeBucketAsync("mybucket"); Console.Out.WriteLine("mybucket is created successfully"); } -} -catch (MinioException e) +} +catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -171,7 +171,7 @@ __示例__ ```cs -try +try { // List buckets that have read access. var list = await minioClient.ListBucketsAsync(); @@ -179,8 +179,8 @@ try { Console.Out.WriteLine(bucket.Name + " " + bucket.CreationDateDateTime); } -} -catch (MinioException e) +} +catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -224,7 +224,7 @@ try bool found = await minioClient.BucketExistsAsync(bucketName); Console.Out.WriteLine("bucket-name " + ((found == true) ? "exists" : "does not exist")); } -catch (MinioException e) +catch (MinioException e) { Console.WriteLine("[Bucket] Exception: {0}", e); } @@ -266,22 +266,22 @@ __示例__ ```cs -try +try { // Check if my-bucket exists before removing it. bool found = await minioClient.BucketExistsAsync("mybucket"); - if (found) - { + if (found) + { // Remove bucket my-bucketname. This operation will succeed only if the bucket is empty. await minioClient.RemoveBucketAsync("mybucket"); Console.Out.WriteLine("mybucket is removed successfully"); } - else + else { Console.Out.WriteLine("mybucket does not exist"); } -} -catch(MinioException e) +} +catch(MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -314,25 +314,25 @@ __示例__ ```cs -try +try { // Check whether 'mybucket' exists or not. bool found = minioClient.BucketExistsAsync("mybucket"); - if (found) + if (found) { // List objects from 'my-bucketname' IObservable observable = minioClient.ListObjectsAsync("mybucket", "prefix", true); IDisposable subscription = observable.Subscribe( item => Console.WriteLine("OnNext: {0}", item.Key), ex => Console.WriteLine("OnError: {0}", ex.Message), - () => Console.WriteLine("OnComplete: {0}")); - } - else + () => Console.WriteLine("OnComplete: {0}")); + } + else { Console.Out.WriteLine("mybucket does not exist"); } -} -catch (MinioException e) +} +catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -367,11 +367,11 @@ __示例__ ```cs -try +try { // Check whether 'mybucket' exist or not. bool found = minioClient.BucketExistsAsync("mybucket"); - if (found) + if (found) { // List all incomplete multipart upload of objects in 'mybucket' IObservable observable = minioClient.ListIncompleteUploads("mybucket", "prefix", true); @@ -379,13 +379,13 @@ try item => Console.WriteLine("OnNext: {0}", item.Key), ex => Console.WriteLine("OnError: {0}", ex.Message), () => Console.WriteLine("OnComplete: {0}")); - } - else + } + else { Console.Out.WriteLine("mybucket does not exist"); } -} -catch (MinioException e) +} +catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -422,12 +422,12 @@ __示例__ ```cs -try +try { PolicyType policy = await minioClient.GetPolicyAsync("myBucket", objectPrefix:"downloads"); Console.Out.WriteLine("Current policy: " + policy.GetType().ToString()); -} -catch (MinioException e) +} +catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -463,11 +463,11 @@ __参数__ __示例__ ```cs -try +try { await minioClient.SetPolicyAsync("myBucket", "uploads",PolicyType.WRITE_ONLY); } -catch (MinioException e) +catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -501,11 +501,11 @@ __参数__ __示例__ ```cs -try +try { BucketNotification notification = new BucketNotification(); Arn topicArn = new Arn("aws", "sns", "us-west-1", "412334153608", "topicminio"); - + TopicConfig topicConfiguration = new TopicConfig(topicArn); List events = new List(){ EventType.ObjectCreatedPut , EventType.ObjectCreatedCopy }; topicConfiguration.AddEvents(events); @@ -515,13 +515,13 @@ try QueueConfig queueConfiguration = new QueueConfig("arn:aws:sqs:us-west-1:482314153608:testminioqueue1"); queueConfiguration.AddEvents(new List() { EventType.ObjectCreatedCompleteMultipartUpload }); - notification.AddQueue(queueConfiguration); - - await minio.SetBucketNotificationsAsync(bucketName, + notification.AddQueue(queueConfiguration); + + await minio.SetBucketNotificationsAsync(bucketName, notification); Console.Out.WriteLine("Notifications set for the bucket " + bucketName + " successfully"); } -catch (MinioException e) +catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -557,12 +557,12 @@ __示例__ ```cs -try +try { BucketNotification notifications = await minioClient.GetBucketNotificationAsync(bucketName); Console.Out.WriteLine("Notifications is " + notifications.ToXML()); -} -catch (MinioException e) +} +catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -598,12 +598,12 @@ __示例__ ```cs -try +try { await minioClient.RemoveAllBucketNotificationsAsync(bucketName); Console.Out.WriteLine("Notifications successfully removed from the bucket " + bucketName); -} -catch (MinioException e) +} +catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -642,7 +642,7 @@ __示例__ ```cs -try +try { // Check whether the object exists using statObject(). // If the object is not found, statObject() throws an exception, @@ -651,13 +651,13 @@ try await minioClient.StatObjectAsync("mybucket", "myobject"); // Get input stream to have content of 'my-objectname' from 'my-bucketname' - await minioClient.GetObjectAsync("mybucket", "myobject", + await minioClient.GetObjectAsync("mybucket", "myobject", (stream) => { stream.CopyTo(Console.OpenStandardOutput()); }); - } - catch (MinioException e) + } + catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -679,7 +679,7 @@ __参数__ | ``bucketName`` | _string_ | 存储桶名称。 | | ``objectName`` | _string_ | 存储桶里的对象名称。 | | ``offset``| _long_ | ``offset`` 是起始字节的位置。 | -| ``length``| _long_| ``length``是要读取的长度。 | +| ``length``| _long_| ``length``是要读取的长度。 | | ``callback`` | _Action_ | 处理流的回调函数。 | | ``cancellationToken``| _System.Threading.CancellationToken_ | 可选参数。默认是default(CancellationToken) | @@ -696,7 +696,7 @@ __示例__ ```cs -try +try { // Check whether the object exists using statObject(). // If the object is not found, statObject() throws an exception, @@ -710,8 +710,8 @@ try { stream.CopyTo(Console.OpenStandardOutput()); }); - } - catch (MinioException e) + } + catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -746,7 +746,7 @@ __参数__ __示例__ ```cs -try +try { // Check whether the object exists using statObjectAsync(). // If the object is not found, statObjectAsync() throws an exception, @@ -757,8 +757,8 @@ try // Gets the object's data and stores it in photo.jpg await minioClient.GetObjectAsync("mybucket", "myobject", "photo.jpg"); -} -catch (MinioException e) +} +catch (MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -804,7 +804,7 @@ __示例__ ```cs -try +try { byte[] bs = File.ReadAllBytes(fileName); System.IO.MemoryStream filestream = new System.IO.MemoryStream(bs); @@ -815,8 +815,8 @@ try filestream.Length, "application/octet-stream"); Console.Out.WriteLine("island.jpg is uploaded successfully"); -} -catch(MinioException e) +} +catch(MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -860,12 +860,12 @@ __示例__ ```cs -try +try { await minio.PutObjectAsync("mybucket", "island.jpg", "/mnt/photos/island.jpg",contentType: "application/octet-stream"); Console.Out.WriteLine("island.jpg is uploaded successfully"); -} -catch(MinioException e) +} +catch(MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -901,13 +901,13 @@ __示例__ ```cs -try +try { // Get the metadata of the object. ObjectStat objectStat = await minioClient.StatObjectAsync("mybucket", "myobject"); Console.Out.WriteLine(objectStat); -} -catch(MinioException e) +} +catch(MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -955,8 +955,8 @@ try await minioClient.CopyObjectAsync("mybucket", "island.jpg", "mydestbucket", "processed.png", copyConditions); Console.Out.WriteLine("island.jpg is uploaded successfully"); -} -catch(MinioException e) +} +catch(MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -991,13 +991,13 @@ __示例__ ```cs -try +try { // Remove objectname from the bucket my-bucketname. await minioClient.RemoveObjectAsync("mybucket", "myobject"); Console.Out.WriteLine("successfully removed mybucket/myobject"); -} -catch (MinioException e) +} +catch (MinioException e) { Console.Out.WriteLine("Error: " + e); } @@ -1031,7 +1031,7 @@ __示例__ ```cs -try +try { List objectNames = new LinkedList(); objectNames.add("my-objectname1"); @@ -1046,8 +1046,8 @@ try { Console.WriteLine("Listed all delete errors for remove objects on " + bucketName + "\n"); }); -} -catch (MinioException e) +} +catch (MinioException e) { Console.Out.WriteLine("Error: " + e); } @@ -1082,13 +1082,13 @@ __示例__ ```cs -try +try { // Removes partially uploaded objects from buckets. await minioClient.RemoveIncompleteUploadAsync("mybucket", "myobject"); Console.Out.WriteLine("successfully removed all incomplete upload session of my-bucketname/my-objectname"); -} -catch(MinioException e) +} +catch(MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -1124,12 +1124,12 @@ __示例__ ```cs -try +try { String url = await minioClient.PresignedGetObjectAsync("mybucket", "myobject", 60 * 60 * 24); Console.Out.WriteLine(url); -} -catch(MinioException e) +} +catch(MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -1164,12 +1164,12 @@ __参数__ __示例__ ```cs -try +try { String url = await minioClient.PresignedPutObjectAsync("mybucket", "myobject", 60 * 60 * 24); Console.Out.WriteLine(url); } -catch(MinioException e) +catch(MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } @@ -1203,7 +1203,7 @@ __示例__ ```cs -try +try { PostPolicy policy = new PostPolicy(); policy.SetContentType("image/png"); @@ -1221,8 +1221,8 @@ try } curlCommand = curlCommand + " -F file=@/etc/bashrc https://s3.amazonaws.com/my-bucketname"; Console.Out.WriteLine(curlCommand); -} -catch(MinioException e) +} +catch(MinioException e) { Console.Out.WriteLine("Error occurred: " + e); } diff --git a/Minio.Examples/Cases/ListObjects.cs b/Minio.Examples/Cases/ListObjects.cs index be060dfc4..4e2216be6 100644 --- a/Minio.Examples/Cases/ListObjects.cs +++ b/Minio.Examples/Cases/ListObjects.cs @@ -19,20 +19,20 @@ namespace Minio.Examples.Cases { - + class ListObjects { // List objects matching optional prefix in a specified bucket. public static void Run(Minio.MinioClient minio, string bucketName = "my-bucket-name", string prefix = null, - bool recursive = false) + bool recursive = true) { try { Console.Out.WriteLine("Running example for API: ListObjectsAsync"); IObservable observable = minio.ListObjectsAsync(bucketName, prefix, recursive); - + IDisposable subscription = observable.Subscribe( item => Console.WriteLine("Object: {0}", item.Key), ex => Console.WriteLine("OnError: {0}", ex), @@ -47,4 +47,3 @@ public static void Run(Minio.MinioClient minio, } } } - diff --git a/Minio.Functional.Tests/FunctionalTest.cs b/Minio.Functional.Tests/FunctionalTest.cs index 96c740e2c..d9727d3d0 100644 --- a/Minio.Functional.Tests/FunctionalTest.cs +++ b/Minio.Functional.Tests/FunctionalTest.cs @@ -1,5 +1,6 @@ /* -* Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. +* Minio .NET Library for Amazon S3 Compatible Cloud Storage, +* (C) 2017, 2018, 2019 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,7 +46,7 @@ public class FunctionalTest private static string listBucketsSignature = "Task ListBucketsAsync(CancellationToken cancellationToken = default(CancellationToken))"; private static string bucketExistsSignature = "Task BucketExistsAsync(string bucketName, CancellationToken cancellationToken = default(CancellationToken))"; private static string removeBucketSignature = "Task RemoveBucketAsync(string bucketName, CancellationToken cancellationToken = default(CancellationToken))"; - private static string listObjectsSignature = "IObservable ListObjectsAsync(string bucketName, string prefix = null, bool recursive = true, CancellationToken cancellationToken = default(CancellationToken))"; + private static string listObjectsSignature = "IObservable ListObjectsAsync(string bucketName, string prefix = null, bool recursive = false, CancellationToken cancellationToken = default(CancellationToken))"; private static string listIncompleteUploadsSignature = "IObservable ListIncompleteUploads(string bucketName, string prefix, bool recursive, CancellationToken cancellationToken = default(CancellationToken))"; private static string getObjectSignature1 = "Task GetObjectAsync(string bucketName, string objectName, Action callback, CancellationToken cancellationToken = default(CancellationToken))"; private static string getObjectSignature2 = "Task GetObjectAsync(string bucketName, string objectName, Action callback, CancellationToken cancellationToken = default(CancellationToken))"; @@ -80,7 +81,7 @@ private static String CreateFile(int size, string dataFileName = null) File.WriteAllBytes(fileName, data); return GetFilePath(fileName); } - + return GetFilePath(dataFileName); } @@ -98,8 +99,8 @@ public static String GetRandomName(int length = 5) } return "miniodotnet" + result.ToString(); } - // Return true if running in Mint mode - public static bool IsMintEnv() + // Return true if running in Mint mode + public static bool IsMintEnv() { return !String.IsNullOrEmpty(Environment.GetEnvironmentVariable("MINT_DATA_DIR")); } @@ -150,13 +151,13 @@ public static void Main(string[] args) else minioClient = new MinioClient(endPoint, accessKey, secretKey); - // Assign parameters before starting the test + // Assign parameters before starting the test string bucketName = GetRandomName(); string objectName = GetRandomName(); string destBucketName = GetRandomName(); string destObjectName = GetRandomName(); - // Set app Info + // Set app Info minioClient.SetAppInfo("app-name", "app-version"); // Set HTTP Tracing On // minioClient.SetTraceOn(new JsonNetLogger()); @@ -268,7 +269,7 @@ public static void Main(string[] args) EncryptedCopyObject_Test3(minioClient).Wait(); EncryptedCopyObject_Test4(minioClient).Wait(); } - + } private static void runCoreTests(MinioClient minioClient) { @@ -282,7 +283,7 @@ private static void runCoreTests(MinioClient minioClient) ListObjects_Test1(minioClient).Wait(); RemoveObject_Test1(minioClient).Wait(); CopyObject_Test1(minioClient).Wait(); - + // Test SetPolicyAsync function SetBucketPolicy_Test1(minioClient).Wait(); @@ -318,7 +319,7 @@ private async static Task BucketExists_Test(MinioClient minio) catch (MinioException ex) { new MintLogger("BucketExists_Test",bucketExistsSignature,"Tests whether BucketExists passes",TestStatus.FAIL,(DateTime.Now - startTime),"",ex.Message, ex.ToString(),args).Log(); - } + } } private async static Task MakeBucket_Test1(MinioClient minio) @@ -342,7 +343,7 @@ private async static Task MakeBucket_Test1(MinioClient minio) catch (MinioException ex) { new MintLogger("MakeBucket_Test1",makeBucketSignature,"Tests whether MakeBucket passes",TestStatus.FAIL,(DateTime.Now - startTime),"",ex.Message,ex.ToString(),args).Log(); - } + } } private async static Task MakeBucket_Test2(MinioClient minio) @@ -368,7 +369,7 @@ private async static Task MakeBucket_Test2(MinioClient minio) { new MintLogger("MakeBucket_Test2",makeBucketSignature,testType,TestStatus.FAIL,(DateTime.Now - startTime),"",ex.Message, ex.ToString(),args).Log(); } - + } private async static Task MakeBucket_Test3(MinioClient minio, bool aws = false) { @@ -509,7 +510,7 @@ private async static Task PutObject_Test1(MinioClient minio) } } - + private async static Task PutObject_Test2(MinioClient minio) { DateTime startTime = DateTime.Now; @@ -676,7 +677,7 @@ private async static Task PutObject_Test7(MinioClient minio) await Setup_Test(minio, bucketName); using (System.IO.MemoryStream filestream = rsg.GenerateStreamFromSeed(10 * KB)) { - + long size = -1; long file_write_size = filestream.Length; @@ -749,7 +750,7 @@ private async static Task PutGetStatEncryptedObject_Test1(MinioClient minio) }; try { - // Putobject with SSE-C encryption. + // Putobject with SSE-C encryption. await Setup_Test(minio, bucketName); Aes aesEncryption = Aes.Create(); aesEncryption.KeySize = 256; @@ -1273,7 +1274,7 @@ await minio.PutObjectAsync(bucketName, new MintLogger("CopyObject_Test5",copyObjectSignature,"Tests whether CopyObject multi-part copy upload for large files works",TestStatus.FAIL,(DateTime.Now - startTime),"",ex.Message, ex.ToString(),args).Log(); } } - + } private async static Task CopyObject_Test6(MinioClient minio) @@ -1708,7 +1709,7 @@ await minio.GetObjectAsync(bucketName, objectName, { new MintLogger("GetObject_Test1",getObjectSignature1,"Tests whether GetObject as stream works",TestStatus.FAIL,(DateTime.Now - startTime),"",ex.Message, ex.ToString(),args).Log(); } - + } private async static Task GetObject_Test2(MinioClient minio) { @@ -1742,7 +1743,7 @@ private async static Task GetObject_Test2(MinioClient minio) { new MintLogger("GetObject_Test2",getObjectSignature1,"Tests for non-existent GetObject",TestStatus.FAIL,(DateTime.Now - startTime),"",ex.Message, ex.ToString(),args).Log(); } - + } private async static Task GetObject_Test3(MinioClient minio) { @@ -1828,7 +1829,7 @@ await minio.PutObjectAsync(bucketName, { new MintLogger("FGetObject_Test1",getObjectSignature3,"Tests whether FGetObject passes for small upload",TestStatus.FAIL,(DateTime.Now - startTime),"",ex.Message, ex.ToString(),args).Log(); } - + } private async static Task FPutObject_Test1(MinioClient minio) @@ -1919,9 +1920,10 @@ private async static Task ListObjects_Test1(MinioClient minio) tasks[i]= PutObject_Task(minio, bucketName, objectName + i.ToString(), null, null, 0, null, rsg.GenerateStreamFromSeed(1)); } await Task.WhenAll(tasks); - + ListObjects_Test(minio, bucketName, prefix, 2,false).Wait(); System.Threading.Thread.Sleep(2000); + await minio.RemoveObjectAsync(bucketName, objectName + "0"); await minio.RemoveObjectAsync(bucketName, objectName + "1"); await TearDown(minio, bucketName); @@ -1977,7 +1979,7 @@ private async static Task ListObjects_Test3(MinioClient minio) } await Task.WhenAll(tasks); - ListObjects_Test(minio, bucketName, prefix, 2,true).Wait(); + ListObjects_Test(minio, bucketName, prefix, 2, true).Wait(); System.Threading.Thread.Sleep(2000); await minio.RemoveObjectAsync(bucketName, objectName + "0"); await minio.RemoveObjectAsync(bucketName, objectName + "1"); @@ -2009,9 +2011,10 @@ private async static Task ListObjects_Test4(MinioClient minio) tasks[i]= PutObject_Task(minio, bucketName, objectName + i.ToString(), null, null, 0, null, rsg.GenerateStreamFromSeed(1*KB)); } await Task.WhenAll(tasks); - - ListObjects_Test(minio, bucketName, null, 2,false).Wait(); + + ListObjects_Test(minio, bucketName, "", 2, false).Wait(); System.Threading.Thread.Sleep(2000); + await minio.RemoveObjectAsync(bucketName, objectName + "0"); await minio.RemoveObjectAsync(bucketName, objectName + "1"); await TearDown(minio, bucketName); @@ -2046,8 +2049,8 @@ private async static Task ListObjects_Test5(MinioClient minio) } } await Task.WhenAll(tasks); - - ListObjects_Test(minio, bucketName, objectNamePrefix, numObjects,false).Wait(); + + ListObjects_Test(minio, bucketName, objectNamePrefix, numObjects, false).Wait(); System.Threading.Thread.Sleep(5000); for(int index=1; index <= numObjects; index++) { @@ -2366,7 +2369,7 @@ await minio.PutObjectAsync(bucketName, new MintLogger("PresignedPutObject_Test2",presignedPutObjectSignature,"Tests whether PresignedPutObject url retrieves object from bucket when invalid expiry is set.",TestStatus.FAIL,(DateTime.Now - startTime),"",ex.Message, ex.ToString(),args).Log(); } } - + private static async Task UploadObjectAsync(string url, string filePath) { HttpWebRequest httpRequest = WebRequest.Create(url) as HttpWebRequest; @@ -2408,7 +2411,7 @@ private async static Task PresignedPostPolicy_Test1(MinioClient minio) await Setup_Test(minio, bucketName); await minio.PutObjectAsync(bucketName, objectName, - fileName); + fileName); var pairs = new List>(); string url = "https://s3.amazonaws.com/" + bucketName; Tuple> policyTuple = await minio.PresignedPostPolicyAsync(form); @@ -2479,7 +2482,7 @@ await minio.PutObjectAsync(bucketName, IDisposable subscription = observable.Subscribe( item => Assert.AreEqual(item.Key, objectName), - ex => Assert.Fail()); + ex => Assert.Fail()); await minio.RemoveIncompleteUploadAsync(bucketName, objectName); } @@ -2500,7 +2503,7 @@ private async static Task ListIncompleteUpload_Test2(MinioClient minio) { DateTime startTime = DateTime.Now; string bucketName = GetRandomName(15); - string prefix = "minioprefix/"; + string prefix = "minioprefix/"; string objectName = prefix + GetRandomName(10); string contentType = "gzip"; Dictionary args = new Dictionary @@ -2529,11 +2532,11 @@ await minio.PutObjectAsync(bucketName, } catch (OperationCanceledException) { - IObservable observable = minio.ListIncompleteUploads(bucketName,"minioprefix",false); + IObservable observable = minio.ListIncompleteUploads(bucketName, "minioprefix", false); IDisposable subscription = observable.Subscribe( item => Assert.AreEqual(item.Key, objectName), - ex => Assert.Fail()); + ex => Assert.Fail()); await minio.RemoveIncompleteUploadAsync(bucketName, objectName); } @@ -2579,11 +2582,11 @@ await minio.PutObjectAsync(bucketName, } catch (OperationCanceledException) { - IObservable observable = minio.ListIncompleteUploads(bucketName,prefix,true); + IObservable observable = minio.ListIncompleteUploads(bucketName, prefix, true); IDisposable subscription = observable.Subscribe( item => Assert.AreEqual(item.Key, objectName), - ex => Assert.Fail()); + ex => Assert.Fail()); await minio.RemoveIncompleteUploadAsync(bucketName, objectName); } @@ -2633,7 +2636,7 @@ await minio.PutObjectAsync(bucketName, IDisposable subscription = observable.Subscribe( item => Assert.Fail(), - ex => Assert.Fail()); + ex => Assert.Fail()); } await TearDown(minio, bucketName); new MintLogger("RemoveIncompleteUpload_Test",removeIncompleteUploadSignature,"Tests whether RemoveIncompleteUpload passes.",TestStatus.PASS,(DateTime.Now - startTime), args:args).Log(); diff --git a/Minio/ApiEndpoints/BucketOperations.cs b/Minio/ApiEndpoints/BucketOperations.cs index 12f6e6ff5..a9994bf37 100644 --- a/Minio/ApiEndpoints/BucketOperations.cs +++ b/Minio/ApiEndpoints/BucketOperations.cs @@ -1,5 +1,6 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, + * (C) 2017, 2018, 2019 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -72,7 +73,7 @@ public partial class MinioClient : IBucketOperations location = this.Region; } } - + // Set Target URL Uri requestUrl = RequestUtil.MakeTargetURL(this.BaseUrl, this.Secure,location); SetTargetURL(requestUrl); @@ -134,20 +135,27 @@ public partial class MinioClient : IBucketOperations /// List all objects non-recursively in a bucket with a given prefix, optionally emulating a directory /// /// Bucket to list objects from - /// Filters all objects not beginning with a given prefix - /// Set to false to emulate a directory + /// Filters all objects beginning with a given prefix + /// Set to true to recursively list all objects /// Optional cancellation token to cancel the operation /// An observable of items that client can subscribe to - public IObservable ListObjectsAsync(string bucketName, string prefix = null, bool recursive = true, CancellationToken cancellationToken = default(CancellationToken)) + public IObservable ListObjectsAsync(string bucketName, string prefix = null, bool recursive = false, CancellationToken cancellationToken = default(CancellationToken)) { return Observable.Create( async obs => { bool isRunning = true; string marker = null; + + var delimiter = "/"; + if (recursive) + { + delimiter = ""; + } + while (isRunning) { - Tuple> result = await GetObjectListAsync(bucketName, prefix, recursive, marker, cancellationToken).ConfigureAwait(false); + Tuple> result = await GetObjectListAsync(bucketName, prefix, delimiter, marker, cancellationToken).ConfigureAwait(false); Item lastItem = null; foreach (Item item in result.Item2) { @@ -171,35 +179,39 @@ public partial class MinioClient : IBucketOperations /// Gets the list of objects in the bucket filtered by prefix /// /// Bucket to list objects from - /// Filters all objects not beginning with a given prefix - /// Set to false to emulate a directory + /// Filters all objects starting with a given prefix + /// Delimit the output upto this character /// marks location in the iterator sequence /// Task with a tuple populated with objects /// Optional cancellation token to cancel the operation - private async Task>> GetObjectListAsync(string bucketName, string prefix, bool recursive, string marker, CancellationToken cancellationToken = default(CancellationToken)) + private async Task>> GetObjectListAsync(string bucketName, string prefix, string delimiter, string marker, CancellationToken cancellationToken = default(CancellationToken)) { var queries = new List(); - if (!recursive) - { - queries.Add("delimiter=%2F"); + + // null values are treated as empty strings. + if (delimiter == null) { + delimiter = ""; } - if (prefix != null) - { - queries.Add("prefix=" + Uri.EscapeDataString(prefix)); + if (prefix == null) { + prefix = ""; } - if (marker != null) - { - queries.Add("marker=" + Uri.EscapeDataString(marker)); + if (marker == null) { + marker = ""; } + + queries.Add("delimiter="+ Uri.EscapeDataString(delimiter)); + queries.Add("prefix=" + Uri.EscapeDataString(prefix)); queries.Add("max-keys=1000"); + queries.Add("marker=" + Uri.EscapeDataString(marker)); + string query = string.Join("&", queries); var request = await this.CreateRequest(Method.GET, bucketName, resourcePath: "?" + query) .ConfigureAwait(false); - + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request, cancellationToken).ConfigureAwait(false); var contentBytes = System.Text.Encoding.UTF8.GetBytes(response.Content); @@ -292,7 +304,7 @@ public partial class MinioClient : IBucketOperations resourcePath: "?notification") .ConfigureAwait(false); BucketNotification notification = null; - + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request, cancellationToken).ConfigureAwait(false); var contentBytes = System.Text.Encoding.UTF8.GetBytes(response.Content); using (var stream = new MemoryStream(contentBytes)) @@ -314,11 +326,11 @@ public partial class MinioClient : IBucketOperations var request = await this.CreateRequest(Method.PUT, bucketName, resourcePath: "?notification") .ConfigureAwait(false); - + request.XmlSerializer = new RestSharp.Serializers.DotNetXmlSerializer(); request.RequestFormat = DataFormat.Xml; request.AddBody(notification); - + IRestResponse response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request, cancellationToken).ConfigureAwait(false); } @@ -335,4 +347,4 @@ public partial class MinioClient : IBucketOperations return SetBucketNotificationsAsync(bucketName, notification, cancellationToken); } } -} \ No newline at end of file +} diff --git a/Minio/ApiEndpoints/IBucketOperations.cs b/Minio/ApiEndpoints/IBucketOperations.cs index 33c8cfacc..d8708c9ae 100644 --- a/Minio/ApiEndpoints/IBucketOperations.cs +++ b/Minio/ApiEndpoints/IBucketOperations.cs @@ -1,5 +1,6 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, + * (C) 2017, 2018, 2019 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -58,11 +59,11 @@ public interface IBucketOperations /// List all objects non-recursively in a bucket with a given prefix, optionally emulating a directory /// /// Bucket to list objects from - /// Filters all objects not beginning with a given prefix - /// Set to false to emulate a directory + /// Filter all incomplete uploads starting with this prefix + /// List incomplete uploads recursively /// /// An observable of items that client can subscribe to - IObservable ListObjectsAsync(string bucketName, string prefix = null, bool recursive = true, CancellationToken cancellationToken = default(CancellationToken)); + IObservable ListObjectsAsync(string bucketName, string prefix = null, bool recursive = false, CancellationToken cancellationToken = default(CancellationToken)); /// /// Get bucket policy @@ -80,7 +81,7 @@ public interface IBucketOperations /// Optional cancellation token to cancel the operation /// Returns Task that sets the current bucket policy Task SetPolicyAsync(String bucketName, String policyJson, CancellationToken cancellationToken = default(CancellationToken)); - + /// /// Gets the notification configuration set for this bucket /// @@ -105,8 +106,8 @@ public interface IBucketOperations /// optional cancellation token /// Task RemoveAllBucketNotificationsAsync(string bucketName, CancellationToken cancellationToken = default(CancellationToken)); - + // Task ListenBucketNotificationsAsync(string bucketName, string prefix = "", string suffix = "", List events,CancellationToken cancellationToken = default(CancellationToken)); - + } -} \ No newline at end of file +} diff --git a/Minio/ApiEndpoints/IObjectOperations.cs b/Minio/ApiEndpoints/IObjectOperations.cs index 8f98be1da..eff04be75 100644 --- a/Minio/ApiEndpoints/IObjectOperations.cs +++ b/Minio/ApiEndpoints/IObjectOperations.cs @@ -1,5 +1,6 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, + * (C) 2017, 2018, 2019 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -94,10 +95,10 @@ public interface IObjectOperations /// /// Bucket to list all incomplepte uploads from /// prefix to list all incomplete uploads - /// option to list incomplete uploads recursively + /// Set to true to recursively list all incomplete uploads /// Optional cancellation token to cancel the operation /// A lazily populated list of incomplete uploads - IObservable ListIncompleteUploads(string bucketName, string prefix, bool recursive, CancellationToken cancellationToken = default(CancellationToken)); + IObservable ListIncompleteUploads(string bucketName, string prefix = "", bool recursive = false, CancellationToken cancellationToken = default(CancellationToken)); /// /// Remove incomplete uploads from a given bucket and objectName @@ -151,7 +152,7 @@ public interface IObjectOperations Task GetObjectAsync(string bucketName, string objectName, string filePath, ServerSideEncryption sse = null ,CancellationToken cancellationToken = default(CancellationToken)); /// - /// Presigned get url - returns a presigned url to access an object's data without credentials.URL can have a maximum expiry of + /// Presigned get url - returns a presigned url to access an object's data without credentials.URL can have a maximum expiry of /// upto 7 days or a minimum of 1 second.Additionally, you can override a set of response headers using reqParams. /// /// Bucket to retrieve object from @@ -161,7 +162,7 @@ public interface IObjectOperations Task PresignedGetObjectAsync(string bucketName, string objectName, int expiresInt, Dictionary reqParams = null); /// - /// Presigned Put url - returns a presigned url to upload an object without credentials.URL can have a maximum expiry of + /// Presigned Put url - returns a presigned url to upload an object without credentials.URL can have a maximum expiry of /// upto 7 days or a minimum of 1 second. /// /// Bucket to retrieve object from @@ -176,4 +177,4 @@ public interface IObjectOperations Task>> PresignedPostPolicyAsync(PostPolicy policy); } -} \ No newline at end of file +} diff --git a/Minio/ApiEndpoints/ObjectOperations.cs b/Minio/ApiEndpoints/ObjectOperations.cs index d0fceace7..27d725c2a 100644 --- a/Minio/ApiEndpoints/ObjectOperations.cs +++ b/Minio/ApiEndpoints/ObjectOperations.cs @@ -1,5 +1,6 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, + * (C) 2017, 2018, 2019 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -522,24 +523,26 @@ private async Task>> GetMultipart CancellationToken cancellationToken) { var queries = new List(); - queries.Add("uploads"); - if (prefix != null) - { - queries.Add("prefix=" + Uri.EscapeDataString(prefix)); + + // null values are treated as empty strings. + if (delimiter == null) { + delimiter = ""; } - if (keyMarker != null) - { - queries.Add("key-marker=" + Uri.EscapeDataString(keyMarker)); + if (prefix == null) { + prefix = ""; } - if (uploadIdMarker != null) - { - queries.Add("upload-id-marker=" + uploadIdMarker); + if (keyMarker == null) { + keyMarker = ""; } - if (delimiter != null) - { - queries.Add("delimiter=" + delimiter); + if (uploadIdMarker == null) { + uploadIdMarker = ""; } + queries.Add("uploads"); + queries.Add("prefix=" + Uri.EscapeDataString(prefix)); + queries.Add("delimiter=" + Uri.EscapeDataString(delimiter)); + queries.Add("key-marker=" + Uri.EscapeDataString(keyMarker)); + queries.Add("upload-id-marker=" + uploadIdMarker); queries.Add("max-uploads=1000"); string query = string.Join("&", queries); @@ -571,11 +574,11 @@ private async Task>> GetMultipart /// Lists all incomplete uploads in a given bucket and prefix recursively /// /// Bucket to list all incomplepte uploads from - /// prefix to list all incomplete uploads - /// option to list incomplete uploads recursively + /// Filter all incomplete uploads starting with this prefix + /// Set to true to recursively list all incomplete uploads /// Optional cancellation token to cancel the operation /// A lazily populated list of incomplete uploads - public IObservable ListIncompleteUploads(string bucketName, string prefix = "", bool recursive = true, CancellationToken cancellationToken = default(CancellationToken)) + public IObservable ListIncompleteUploads(string bucketName, string prefix = null, bool recursive = true, CancellationToken cancellationToken = default(CancellationToken)) { if (recursive) { @@ -617,36 +620,6 @@ private IObservable listIncompleteUploads(string bucketName, string pref } - /// - /// Find uploadId of most recent unsuccessful attempt to upload object to bucket. - /// - /// - /// - /// Optional cancellation token to cancel the operation - /// - private async Task getLatestIncompleteUploadIdAsync(string bucketName, string objectName, CancellationToken cancellationToken) - { - Upload latestUpload = null; - var uploads = await this.ListIncompleteUploads(bucketName, objectName, cancellationToken: cancellationToken).ToArray(); - - foreach (Upload upload in uploads) - { - if (objectName == upload.Key && (latestUpload == null || latestUpload.Initiated.CompareTo(upload.Initiated) < 0)) - { - latestUpload = upload; - - } - } - if (latestUpload != null) - { - return latestUpload.UploadId; - } - else - { - return null; - } - - } /// /// Remove incomplete uploads from a given bucket and objectName ///