From 32174d95ae24d7932762a5fca483a411e37a1867 Mon Sep 17 00:00:00 2001 From: poornas Date: Sun, 12 Feb 2017 21:25:42 -0800 Subject: [PATCH] refactor client and exception handling --- API.md | 395 ++++---- FileUploader/FileUpload.cs | 49 +- FileUploader/FileUploader.csproj | 3 + Minio.Api/ApiEndpoints/BucketOperations.cs | 137 ++- Minio.Api/ApiEndpoints/IBucketOperations.cs | 47 +- Minio.Api/ApiEndpoints/IObjectOperations.cs | 96 +- Minio.Api/ApiEndpoints/ObjectOperations.cs | 347 +++---- Minio.Api/BucketRegionCache.cs | 20 +- Minio.Api/ClassDiagram1.cd | 2 - Minio.Api/DataModel/Bucket.cs | 2 +- Minio.Api/DataModel/CopyConditions.cs | 2 +- Minio.Api/DataModel/CopyObjectResult.cs | 2 +- .../DataModel/CreateBucketConfiguration.cs | 2 +- Minio.Api/DataModel/DateFormat.cs | 2 +- Minio.Api/DataModel/Grant.cs | 2 +- Minio.Api/DataModel/GranteeUser.cs | 2 +- .../InitiateMultipartUploadResult.cs | 2 +- Minio.Api/DataModel/Item.cs | 2 +- Minio.Api/DataModel/ListAllMyBucketsResult.cs | 2 +- Minio.Api/DataModel/ListBucketResult.cs | 2 +- .../DataModel/ListMultipartUploadsResult.cs | 2 +- Minio.Api/DataModel/ListPartsResult.cs | 2 +- Minio.Api/DataModel/LocationConstraint.cs | 2 +- Minio.Api/DataModel/ObjectStat.cs | 2 +- Minio.Api/DataModel/Part.cs | 14 +- .../DataModel/Policy/ActionJsonConverter.cs | 9 +- Minio.Api/DataModel/Policy/BucketPolicy.cs | 8 +- Minio.Api/DataModel/Policy/ConditionKeyMap.cs | 5 +- Minio.Api/DataModel/Policy/ConditionMap.cs | 6 +- Minio.Api/DataModel/Policy/Constants.cs | 5 +- Minio.Api/DataModel/Policy/PolicyType.cs | 13 +- Minio.Api/DataModel/Policy/Principal.cs | 6 +- .../Policy/PrincipalJsonConverter.cs | 9 +- .../DataModel/Policy/ResourceJsonConverter.cs | 10 +- Minio.Api/DataModel/Policy/Resources.cs | 8 +- .../Policy/SingleOrArrayConverter.cs | 11 +- Minio.Api/DataModel/Policy/Statement.cs | 7 +- .../Policy/StatementJsonConverter.cs | 6 +- Minio.Api/DataModel/PostPolicy.cs | 2 +- Minio.Api/DataModel/Prefix.cs | 2 +- Minio.Api/DataModel/Upload.cs | 2 +- Minio.Api/Exceptions/AccessDeniedException.cs | 2 +- .../Exceptions/BucketNotFoundException.cs | 2 +- Minio.Api/Exceptions/ConnectionException.cs | 2 +- .../Exceptions/EntityTooLargeException.cs | 2 +- Minio.Api/Exceptions/ErrorResponse.cs | 4 +- Minio.Api/Exceptions/ForbiddenException.cs | 2 +- .../Exceptions/InternalClientException.cs | 2 +- .../Exceptions/InternalServerException.cs | 2 +- .../Exceptions/InvalidBucketNameException.cs | 2 +- .../InvalidContentLengthException.cs | 2 +- .../Exceptions/InvalidEndpointException.cs | 2 +- .../Exceptions/InvalidKeyNameException.cs | 2 +- .../Exceptions/InvalidObjectNameException.cs | 2 +- .../InvalidObjectPrefixException.cs | 2 +- Minio.Api/Exceptions/InvalidPortException.cs | 2 +- ...alidTransferAccelerationBucketException.cs | 26 - .../Exceptions/MaxBucketsReachedException.cs | 2 +- .../Exceptions/MethodNotAllowedException.cs | 2 +- Minio.Api/Exceptions/MinioException.cs | 2 +- .../Exceptions/ObjectNotFoundException.cs | 2 +- Minio.Api/Exceptions/RedirectionException.cs | 2 +- .../UnexpectedShortReadException.cs | 2 +- Minio.Api/Helper/Constants.cs | 2 +- Minio.Api/Helper/Enum.cs | 26 + Minio.Api/Helper/s3utils.cs | 2 +- Minio.Api/Helper/utils.cs | 2 +- Minio.Api/MinioApi.csproj | 18 +- Minio.Api/MinioClient.cs | 270 +++--- Minio.Api/Regions.cs | 2 +- Minio.Api/V4Authenticator.cs | 5 +- Minio.Api/packages.config | 4 +- Minio.Examples/Cases/BucketExists.cs | 23 +- Minio.Examples/Cases/CopyObject.cs | 23 +- Minio.Examples/Cases/FGetObject.cs | 23 +- Minio.Examples/Cases/FPutObject.cs | 23 +- Minio.Examples/Cases/GetBucketPolicy.cs | 24 +- Minio.Examples/Cases/GetObject.cs | 26 +- Minio.Examples/Cases/ListBuckets.cs | 20 +- Minio.Examples/Cases/ListIncompleteUploads.cs | 20 +- Minio.Examples/Cases/ListObjects.cs | 29 +- Minio.Examples/Cases/MakeBucket.cs | 20 +- Minio.Examples/Cases/PresignedGetObject.cs | 15 +- Minio.Examples/Cases/PresignedPostPolicy.cs | 33 +- Minio.Examples/Cases/PresignedPutObject.cs | 34 +- Minio.Examples/Cases/PutObject.cs | 20 +- Minio.Examples/Cases/RemoveBucket.cs | 20 +- .../Cases/RemoveIncompleteUpload.cs | 20 +- Minio.Examples/Cases/RemoveObject.cs | 20 +- Minio.Examples/Cases/SetBucketPolicy.cs | 20 +- Minio.Examples/Cases/StatObject.cs | 20 +- Minio.Examples/Minio.Examples.csproj | 6 +- Minio.Examples/Program.cs | 83 +- Minio.Examples/packages.config | 2 + Minio.Tests/Minio.Tests.csproj | 8 +- Minio.Tests/UnitTest1.cs | 2 +- Minio.sln | 36 +- MinioCore2/AWSS3Endpoints.cs | 75 ++ MinioCore2/ApiEndpoints/BucketOperations.cs | 307 +++++++ MinioCore2/ApiEndpoints/IBucketOperations.cs | 76 ++ MinioCore2/ApiEndpoints/IObjectOperations.cs | 122 +++ MinioCore2/ApiEndpoints/ObjectOperations.cs | 848 ++++++++++++++++++ MinioCore2/BucketRegionCache.cs | 139 +++ MinioCore2/DataModel/Bucket.cs | 33 + MinioCore2/DataModel/CopyConditions.cs | 107 +++ MinioCore2/DataModel/CopyObjectResult.cs | 31 + .../DataModel/CreateBucketConfiguration.cs | 32 + MinioCore2/DataModel/DateFormat.cs | 49 + MinioCore2/DataModel/Grant.cs | 32 + MinioCore2/DataModel/GranteeUser.cs | 34 + .../InitiateMultipartUploadResult.cs | 28 + MinioCore2/DataModel/Item.cs | 58 ++ .../DataModel/ListAllMyBucketsResult.cs | 35 + MinioCore2/DataModel/ListBucketResult.cs | 42 + .../DataModel/ListMultipartUploadsResult.cs | 34 + MinioCore2/DataModel/ListPartsResult.cs | 29 + MinioCore2/DataModel/LocationConstraint.cs | 31 + MinioCore2/DataModel/ObjectStat.cs | 50 ++ MinioCore2/DataModel/Part.cs | 53 ++ .../DataModel/Policy/ActionJsonConverter.cs | 60 ++ MinioCore2/DataModel/Policy/BucketPolicy.cs | 550 ++++++++++++ .../DataModel/Policy/ConditionKeyMap.cs | 66 ++ MinioCore2/DataModel/Policy/ConditionMap.cs | 58 ++ MinioCore2/DataModel/Policy/Constants.cs | 69 ++ MinioCore2/DataModel/Policy/PolicyType.cs | 36 + MinioCore2/DataModel/Policy/Principal.cs | 58 ++ .../Policy/PrincipalJsonConverter.cs | 65 ++ .../DataModel/Policy/ResourceJsonConverter.cs | 71 ++ MinioCore2/DataModel/Policy/Resources.cs | 90 ++ .../Policy/SingleOrArrayConverter.cs | 53 ++ MinioCore2/DataModel/Policy/Statement.cs | 287 ++++++ .../Policy/StatementJsonConverter.cs | 52 ++ MinioCore2/DataModel/PostPolicy.cs | 243 +++++ MinioCore2/DataModel/Prefix.cs | 28 + MinioCore2/DataModel/Upload.cs | 25 + .../Exceptions/AccessDeniedException.cs | 37 + .../Exceptions/BucketNotFoundException.cs | 38 + MinioCore2/Exceptions/ConnectionException.cs | 25 + .../Exceptions/EntityTooLargeException.cs | 26 + MinioCore2/Exceptions/ErrorResponse.cs | 35 + MinioCore2/Exceptions/ForbiddenException.cs | 30 + .../Exceptions/InternalClientException.cs | 25 + .../Exceptions/InternalServerException.cs | 30 + .../Exceptions/InvalidBucketNameException.cs | 33 + .../InvalidContentLengthException.cs | 34 + .../Exceptions/InvalidEndpointException.cs | 44 + .../Exceptions/InvalidKeyNameException.cs | 30 + .../Exceptions/InvalidObjectNameException.cs | 33 + .../InvalidObjectPrefixException.cs | 33 + .../Exceptions/MaxBucketsReachedException.cs | 30 + .../Exceptions/MethodNotAllowedException.cs | 30 + MinioCore2/Exceptions/MinioException.cs | 50 ++ .../Exceptions/ObjectNotFoundException.cs | 33 + MinioCore2/Exceptions/RedirectionException.cs | 30 + .../UnexpectedShortReadException.cs | 31 + MinioCore2/Helper/Constants.cs | 48 + MinioCore2/Helper/Enum.cs | 26 + MinioCore2/Helper/s3utils.cs | 86 ++ MinioCore2/Helper/utils.cs | 176 ++++ MinioCore2/MinioClient.cs | 638 +++++++++++++ MinioCore2/MinioCore2.xproj | 19 + MinioCore2/Properties/AssemblyInfo.cs | 19 + MinioCore2/Regions.cs | 75 ++ MinioCore2/V4Authenticator.cs | 512 +++++++++++ MinioCore2/project.json | 41 + .../Cases/BucketExists.cs | 32 +- MinioCoreTest/Cases/CopyObject.cs | 48 + MinioCoreTest/Cases/FGetObject.cs | 41 + MinioCoreTest/Cases/FPutObject.cs | 45 + MinioCoreTest/Cases/GetBucketPolicy.cs | 41 + MinioCoreTest/Cases/GetObject.cs | 44 + MinioCoreTest/Cases/ListBuckets.cs | 45 + MinioCoreTest/Cases/ListIncompleteUploads.cs | 47 + MinioCoreTest/Cases/ListObjects.cs | 51 ++ MinioCoreTest/Cases/MakeBucket.cs | 41 + MinioCoreTest/Cases/PresignedGetObject.cs | 32 + MinioCoreTest/Cases/PresignedPostPolicy.cs | 45 + MinioCoreTest/Cases/PresignedPutObject.cs | 29 + MinioCoreTest/Cases/PutObject.cs | 51 ++ MinioCoreTest/Cases/RemoveBucket.cs | 40 + MinioCoreTest/Cases/RemoveIncompleteUpload.cs | 42 + MinioCoreTest/Cases/RemoveObject.cs | 41 + MinioCoreTest/Cases/SetBucketPolicy.cs | 44 + MinioCoreTest/Cases/StatObject.cs | 41 + MinioCoreTest/MinioCoreTest.xproj | 21 + MinioCoreTest/Program.cs | 84 ++ MinioCoreTest/Properties/AssemblyInfo.cs | 19 + MinioCoreTest/project.json | 22 + README.md | 74 +- SimpleTest/App.config | 11 - SimpleTest/Program.cs | 72 -- SimpleTest2/App.config | 6 + .../Program.cs | 12 +- .../Properties/AssemblyInfo.cs | 6 +- .../SimpleTest2.csproj | 13 +- 195 files changed, 8672 insertions(+), 1041 deletions(-) delete mode 100644 Minio.Api/ClassDiagram1.cd delete mode 100644 Minio.Api/Exceptions/InvalidTransferAccelerationBucketException.cs create mode 100644 Minio.Api/Helper/Enum.cs create mode 100644 MinioCore2/AWSS3Endpoints.cs create mode 100644 MinioCore2/ApiEndpoints/BucketOperations.cs create mode 100644 MinioCore2/ApiEndpoints/IBucketOperations.cs create mode 100644 MinioCore2/ApiEndpoints/IObjectOperations.cs create mode 100644 MinioCore2/ApiEndpoints/ObjectOperations.cs create mode 100644 MinioCore2/BucketRegionCache.cs create mode 100644 MinioCore2/DataModel/Bucket.cs create mode 100644 MinioCore2/DataModel/CopyConditions.cs create mode 100644 MinioCore2/DataModel/CopyObjectResult.cs create mode 100644 MinioCore2/DataModel/CreateBucketConfiguration.cs create mode 100644 MinioCore2/DataModel/DateFormat.cs create mode 100644 MinioCore2/DataModel/Grant.cs create mode 100644 MinioCore2/DataModel/GranteeUser.cs create mode 100644 MinioCore2/DataModel/InitiateMultipartUploadResult.cs create mode 100644 MinioCore2/DataModel/Item.cs create mode 100644 MinioCore2/DataModel/ListAllMyBucketsResult.cs create mode 100644 MinioCore2/DataModel/ListBucketResult.cs create mode 100644 MinioCore2/DataModel/ListMultipartUploadsResult.cs create mode 100644 MinioCore2/DataModel/ListPartsResult.cs create mode 100644 MinioCore2/DataModel/LocationConstraint.cs create mode 100644 MinioCore2/DataModel/ObjectStat.cs create mode 100644 MinioCore2/DataModel/Part.cs create mode 100644 MinioCore2/DataModel/Policy/ActionJsonConverter.cs create mode 100644 MinioCore2/DataModel/Policy/BucketPolicy.cs create mode 100644 MinioCore2/DataModel/Policy/ConditionKeyMap.cs create mode 100644 MinioCore2/DataModel/Policy/ConditionMap.cs create mode 100644 MinioCore2/DataModel/Policy/Constants.cs create mode 100644 MinioCore2/DataModel/Policy/PolicyType.cs create mode 100644 MinioCore2/DataModel/Policy/Principal.cs create mode 100644 MinioCore2/DataModel/Policy/PrincipalJsonConverter.cs create mode 100644 MinioCore2/DataModel/Policy/ResourceJsonConverter.cs create mode 100644 MinioCore2/DataModel/Policy/Resources.cs create mode 100644 MinioCore2/DataModel/Policy/SingleOrArrayConverter.cs create mode 100644 MinioCore2/DataModel/Policy/Statement.cs create mode 100644 MinioCore2/DataModel/Policy/StatementJsonConverter.cs create mode 100644 MinioCore2/DataModel/PostPolicy.cs create mode 100644 MinioCore2/DataModel/Prefix.cs create mode 100644 MinioCore2/DataModel/Upload.cs create mode 100644 MinioCore2/Exceptions/AccessDeniedException.cs create mode 100644 MinioCore2/Exceptions/BucketNotFoundException.cs create mode 100644 MinioCore2/Exceptions/ConnectionException.cs create mode 100644 MinioCore2/Exceptions/EntityTooLargeException.cs create mode 100644 MinioCore2/Exceptions/ErrorResponse.cs create mode 100644 MinioCore2/Exceptions/ForbiddenException.cs create mode 100644 MinioCore2/Exceptions/InternalClientException.cs create mode 100644 MinioCore2/Exceptions/InternalServerException.cs create mode 100644 MinioCore2/Exceptions/InvalidBucketNameException.cs create mode 100644 MinioCore2/Exceptions/InvalidContentLengthException.cs create mode 100644 MinioCore2/Exceptions/InvalidEndpointException.cs create mode 100644 MinioCore2/Exceptions/InvalidKeyNameException.cs create mode 100644 MinioCore2/Exceptions/InvalidObjectNameException.cs create mode 100644 MinioCore2/Exceptions/InvalidObjectPrefixException.cs create mode 100644 MinioCore2/Exceptions/MaxBucketsReachedException.cs create mode 100644 MinioCore2/Exceptions/MethodNotAllowedException.cs create mode 100644 MinioCore2/Exceptions/MinioException.cs create mode 100644 MinioCore2/Exceptions/ObjectNotFoundException.cs create mode 100644 MinioCore2/Exceptions/RedirectionException.cs create mode 100644 MinioCore2/Exceptions/UnexpectedShortReadException.cs create mode 100644 MinioCore2/Helper/Constants.cs create mode 100644 MinioCore2/Helper/Enum.cs create mode 100644 MinioCore2/Helper/s3utils.cs create mode 100644 MinioCore2/Helper/utils.cs create mode 100644 MinioCore2/MinioClient.cs create mode 100644 MinioCore2/MinioCore2.xproj create mode 100644 MinioCore2/Properties/AssemblyInfo.cs create mode 100644 MinioCore2/Regions.cs create mode 100644 MinioCore2/V4Authenticator.cs create mode 100644 MinioCore2/project.json rename Minio.Api/ApiEndpoints/ClientApiOperations.cs => MinioCoreTest/Cases/BucketExists.cs (54%) create mode 100644 MinioCoreTest/Cases/CopyObject.cs create mode 100644 MinioCoreTest/Cases/FGetObject.cs create mode 100644 MinioCoreTest/Cases/FPutObject.cs create mode 100644 MinioCoreTest/Cases/GetBucketPolicy.cs create mode 100644 MinioCoreTest/Cases/GetObject.cs create mode 100644 MinioCoreTest/Cases/ListBuckets.cs create mode 100644 MinioCoreTest/Cases/ListIncompleteUploads.cs create mode 100644 MinioCoreTest/Cases/ListObjects.cs create mode 100644 MinioCoreTest/Cases/MakeBucket.cs create mode 100644 MinioCoreTest/Cases/PresignedGetObject.cs create mode 100644 MinioCoreTest/Cases/PresignedPostPolicy.cs create mode 100644 MinioCoreTest/Cases/PresignedPutObject.cs create mode 100644 MinioCoreTest/Cases/PutObject.cs create mode 100644 MinioCoreTest/Cases/RemoveBucket.cs create mode 100644 MinioCoreTest/Cases/RemoveIncompleteUpload.cs create mode 100644 MinioCoreTest/Cases/RemoveObject.cs create mode 100644 MinioCoreTest/Cases/SetBucketPolicy.cs create mode 100644 MinioCoreTest/Cases/StatObject.cs create mode 100644 MinioCoreTest/MinioCoreTest.xproj create mode 100644 MinioCoreTest/Program.cs create mode 100644 MinioCoreTest/Properties/AssemblyInfo.cs create mode 100644 MinioCoreTest/project.json delete mode 100644 SimpleTest/App.config delete mode 100644 SimpleTest/Program.cs create mode 100644 SimpleTest2/App.config rename Minio.Api/ApiEndpoints/RequestHelper.cs => SimpleTest2/Program.cs (50%) rename {SimpleTest => SimpleTest2}/Properties/AssemblyInfo.cs (90%) rename SimpleTest/SimpleTest.csproj => SimpleTest2/SimpleTest2.csproj (85%) diff --git a/API.md b/API.md index a1993bcd2..050f76ea8 100644 --- a/API.md +++ b/API.md @@ -96,7 +96,7 @@ MinioClient s3Client = new MinioClient("s3.amazonaws.com:80", ### MakeBucketAsync(string bucketName,string location="us-east-1") -`Task MakeBucketAsync(string bucketName, string location = "us-east-1")` +`Task MakeBucketAsync(string bucketName, string location = "us-east-1")` Creates a new bucket. @@ -123,18 +123,24 @@ __Example__ ```cs -try { - // Create bucket if it doesn't exist. - bool found = await minioClient.Api.bucketExistsAsync("mybucket"); - if (found) { - Console.Out.WriteLine("mybucket already exists"); - } else { - // Create bucket 'my-bucketname'. - await minioClient.Api.makeBucketAsync("mybucket"); - Console.Out.WriteLine("mybucket is created successfully"); - } -} catch (MinioException e) { - Console.Out.WriteLine("Error occurred: " + e); +try +{ + // Create bucket if it doesn't exist. + bool found = await minioClient.BucketExistsAsync("mybucket"); + if (found) + { + Console.Out.WriteLine("mybucket already exists"); + } + else + { + // Create bucket 'my-bucketname'. + await minioClient.MakeBucketAsync("mybucket"); + Console.Out.WriteLine("mybucket is created successfully"); + } +} +catch (MinioException e) +{ + Console.Out.WriteLine("Error occurred: " + e); } ``` @@ -162,14 +168,16 @@ __Example__ ```cs try { - // List buckets that have read access. - var list = await minioClient.Api.ListBucketsAsync(); - foreach (Bucket bucket in list.Buckets) - { - Console.Out.WriteLine(bucket.Name + " " + bucket.CreationDateDateTime); - } -} catch (MinioException e) { - Console.Out.WriteLine("Error occurred: " + e); + // List buckets that have read access. + var list = await minioClient.ListBucketsAsync(); + foreach (Bucket bucket in list.Buckets) + { + Console.Out.WriteLine(bucket.Name + " " + bucket.CreationDateDateTime); + } +} +catch (MinioException e) +{ + Console.Out.WriteLine("Error occurred: " + e); } ``` @@ -204,12 +212,15 @@ __Example__ ```cs -try { - // Check whether 'my-bucketname' exists or not. - bool found = await minioClient.Api.BucketExistsAsync(bucketName); - Console.Out.WriteLine("bucket-name was " + ((found == true) ? "found" : "not found")); -} catch (MinioException e) { - Console.WriteLine("[Bucket] Exception: {0}", e); +try +{ + // Check whether 'my-bucketname' exists or not. + bool found = await minioClient.BucketExistsAsync(bucketName); + Console.Out.WriteLine("bucket-name was " + ((found == true) ? "found" : "not found")); +} +catch (MinioException e) +{ + Console.WriteLine("[Bucket] Exception: {0}", e); } ``` @@ -249,17 +260,21 @@ __Example__ ```cs try { - // Check if my-bucket exists before removing it. - bool found = await minioClient.Api.bucketExists("mybucket"); - if (found) { - // Remove bucket my-bucketname. This operation will succeed only if the bucket is empty. - await minioClient.Api.removeBucket("mybucket"); - Console.Out.WriteLine("mybucket is removed successfully"); - } else { - Console.Out.WriteLine("mybucket does not exist"); - } -} catch(MinioException e) { - Console.Out.WriteLine("Error occurred: " + e); + // Check if my-bucket exists before removing it. + bool found = await minioClient.BucketExistsAsync("mybucket"); + 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 + { + Console.Out.WriteLine("mybucket does not exist"); + } +} +catch(MinioException e) +{ + Console.Out.WriteLine("Error occurred: " + e); } ``` @@ -290,21 +305,25 @@ __Example__ ```cs try { - // Check whether 'mybucket' exists or not. - bool found = minioClient.Api.bucketExists("mybucket"); - if (found) { - // List objects from 'my-bucketname' - IObservable observable = minioClient.Api.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.Out.WriteLine("mybucket does not exist"); - } -} catch (MinioException e) { - Console.Out.WriteLine("Error occurred: " + e); + // Check whether 'mybucket' exists or not. + bool found = minioClient.BucketExistsAsync("mybucket"); + 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.Out.WriteLine("mybucket does not exist"); + } +} +catch (MinioException e) +{ + Console.Out.WriteLine("Error occurred: " + e); } ``` @@ -337,20 +356,25 @@ __Example__ ```cs try { - // Check whether 'mybucket' exist or not. - bool found = minioClient.Api.bucketExists("mybucket"); - if (found) { - // List all incomplete multipart upload of objects in 'my-bucketname - IObservable observable = miniClient.Api.ListIncompleteUploads("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.Out.WriteLine("mybucket does not exist"); - } -} catch (MinioException e) { - Console.Out.WriteLine("Error occurred: " + e); + // Check whether 'mybucket' exist or not. + bool found = minioClient.BucketExistsAsync("mybucket"); + if (found) + { + // List all incomplete multipart upload of objects in 'mybucket' + IObservable observable = miniClient.ListIncompleteUploads("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.Out.WriteLine("mybucket does not exist"); + } +} +catch (MinioException e) +{ + Console.Out.WriteLine("Error occurred: " + e); } ``` @@ -384,11 +408,14 @@ __Example__ ```cs -try { - PolicyType policy = await minioClient.Api.GetPolicyAsync("myBucket", objectPrefix:"downloads"); - Console.Out.WriteLine("Current policy: " + policy.GetType().ToString()); -} catch (MinioException e) { - Console.Out.WriteLine("Error occurred: " + e); +try +{ + PolicyType policy = await minioClient.GetPolicyAsync("myBucket", objectPrefix:"downloads"); + Console.Out.WriteLine("Current policy: " + policy.GetType().ToString()); +} +catch (MinioException e) +{ + Console.Out.WriteLine("Error occurred: " + e); } ``` @@ -422,10 +449,13 @@ __Example__ ```cs -try { - await minioClient.Api.SetPolicyAsync("myBucket", "uploads",PolicyType.WRITE_ONLY); -} catch (MinioException e) { - Console.Out.WriteLine("Error occurred: " + e); +try +{ + await minioClient.SetPolicyAsync("myBucket", "uploads",PolicyType.WRITE_ONLY); +} +catch (MinioException e) +{ + Console.Out.WriteLine("Error occurred: " + e); } ``` @@ -461,21 +491,24 @@ __Example__ ```cs -try { - // Check whether the object exists using statObject(). - // If the object is not found, statObject() throws an exception, - // else it means that the object exists. - // Execution is successful. - await minioClient.Api.StatObjectAsync("mybucket", "myobject"); - - // Get input stream to have content of 'my-objectname' from 'my-bucketname' - await minio.Api.GetObjectAsync("mybucket", "myobject", - (stream) => - { - stream.CopyTo(Console.OpenStandardOutput()); - }); +try +{ + // Check whether the object exists using statObject(). + // If the object is not found, statObject() throws an exception, + // else it means that the object exists. + // Execution is successful. + await minioClient.StatObjectAsync("mybucket", "myobject"); + + // Get input stream to have content of 'my-objectname' from 'my-bucketname' + await minioClient.GetObjectAsync("mybucket", "myobject", + (stream) => + { + stream.CopyTo(Console.OpenStandardOutput()); + }); - } catch (MinioException e) { + } + catch (MinioException e) + { Console.Out.WriteLine("Error occurred: " + e); } ``` @@ -508,18 +541,21 @@ __Parameters__ __Example__ ```cs -try { - // Check whether the object exists using statObjectAsync(). - // If the object is not found, statObjectAsync() throws an exception, - // else it means that the object exists. - // Execution is successful. - await minioClient.Api.StatObjectAsync("mybucket", "myobject"); +try +{ + // Check whether the object exists using statObjectAsync(). + // If the object is not found, statObjectAsync() throws an exception, + // else it means that the object exists. + // Execution is successful. + await minioClient.StatObjectAsync("mybucket", "myobject"); - // Gets the object's data and stores it in photo.jpg - await minioClient.Api.GetObjectAsync("mybucket", "myobject", "photo.jpg"); + // Gets the object's data and stores it in photo.jpg + await minioClient.GetObjectAsync("mybucket", "myobject", "photo.jpg"); -} catch (MinioException e) { - Console.Out.WriteLine("Error occurred: " + e); +} +catch (MinioException e) +{ + Console.Out.WriteLine("Error occurred: " + e); } ``` @@ -560,20 +596,22 @@ The maximum size of a single object is limited to 5TB. putObject transparently u ```cs -try { - byte[] bs = File.ReadAllBytes(fileName); - System.IO.MemoryStream filestream = new System.IO.MemoryStream(bs); - - await minio.Api.PutObjectAsync("mybucket", - "island.jpg", - filestream, - filestream.Length, - "application/octet-stream"); - Console.Out.WriteLine("island.jpg is uploaded successfully"); -} catch(MinioException e) { - Console.Out.WriteLine("Error occurred: " + e); +try +{ + byte[] bs = File.ReadAllBytes(fileName); + System.IO.MemoryStream filestream = new System.IO.MemoryStream(bs); + + await minio.PutObjectAsync("mybucket", + "island.jpg", + filestream, + filestream.Length, + "application/octet-stream"); + Console.Out.WriteLine("island.jpg is uploaded successfully"); +} +catch(MinioException e) +{ + Console.Out.WriteLine("Error occurred: " + e); } - ``` @@ -611,11 +649,14 @@ The maximum size of a single object is limited to 5TB. putObject transparently u ```cs -try { - await minio.Api.PutObjectAsync("mybucket", "island.jpg", "/mnt/photos/island.jpg",contentType: "application/octet-stream"); - Console.Out.WriteLine("island.jpg is uploaded successfully"); -} catch(MinioException e) { - Console.Out.WriteLine("Error occurred: " + e); +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) +{ + Console.Out.WriteLine("Error occurred: " + e); } ``` @@ -648,12 +689,15 @@ __Example__ ```cs -try { - // Get the metadata of the object. - ObjectStat objectStat = await minioClient.Api.statObjectAsync("mybucket", "myobject"); - Console.Out.WriteLine(objectStat); -} catch(MinioException e) { - Console.Out.WriteLine("Error occurred: " + e); +try +{ + // Get the metadata of the object. + ObjectStat objectStat = await minioClient.StatObjectAsync("mybucket", "myobject"); + Console.Out.WriteLine(objectStat); +} +catch(MinioException e) +{ + Console.Out.WriteLine("Error occurred: " + e); } ``` @@ -691,13 +735,16 @@ __Example__ This API performs a server side copy operation from a given source object to destination object. ```cs -try { - CopyConditions copyConditions = new CopyConditions(); - copyConditions.setMatchETagNone("TestETag"); +try +{ + CopyConditions copyConditions = new CopyConditions(); + copyConditions.setMatchETagNone("TestETag"); - await minioClient.Api.copyObjectAsync("mybucket", "island.jpg", "mydestbucket", "processed.png", copyConditions); - Console.Out.WriteLine("island.jpg is uploaded successfully"); -} catch(MinioException e) { + await minioClient.CopyObjectAsync("mybucket", "island.jpg", "mydestbucket", "processed.png", copyConditions); + Console.Out.WriteLine("island.jpg is uploaded successfully"); +} +catch(MinioException e) +{ Console.Out.WriteLine("Error occurred: " + e); } ``` @@ -730,11 +777,13 @@ __Example__ ```cs -try { - // Remove my-objectname from the bucket my-bucketname. - await minioClient.Api.RemoveObjectAsync("mybucket", "myobject"); - Console.Out.WriteLine("successfully removed mybucket/myobject"); -} catch (MinioException e) +try +{ + // Remove my-objectname from the bucket my-bucketname. + await minioClient.RemoveObjectAsync("mybucket", "myobject"); + Console.Out.WriteLine("successfully removed mybucket/myobject"); +} +catch (MinioException e) { Console.Out.WriteLine("Error: " + e); } @@ -768,12 +817,15 @@ __Example__ ```cs -try { - // Removes partially uploaded objects from buckets. - await minioClient.Api.RemoveIncompleteUploadAsync("mybucket", "myobject"); +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) { - Console.Out.WriteLine("Error occurred: " + e); +} +catch(MinioException e) +{ + Console.Out.WriteLine("Error occurred: " + e); } ``` @@ -806,11 +858,14 @@ __Example__ ```cs -try { - String url = minioClient.Api.PresignedGetObject("mybucket", "myobject", 60 * 60 * 24); +try +{ + String url = minioClient.PresignedGetObject("mybucket", "myobject", 60 * 60 * 24); Console.Out.WriteLine(url); -} catch(MinioException e) { - Console.Out.WriteLine("Error occurred: " + e); +} +catch(MinioException e) +{ + Console.Out.WriteLine("Error occurred: " + e); } ``` @@ -840,14 +895,15 @@ __Parameters__ __Example__ - - ```cs -try { - String url = minioClient.Api.PresignedPutObject("mybucket", "myobject", 60 * 60 * 24); +try +{ + String url = minioClient.PresignedPutObject("mybucket", "myobject", 60 * 60 * 24); Console.Out.WriteLine(url); -} catch(MinioException e) { - Console.Out.WriteLine("Error occurred: " + e); +} +catch(MinioException e) +{ + Console.Out.WriteLine("Error occurred: " + e); } ``` @@ -879,25 +935,28 @@ __Example__ ```cs -try { - PostPolicy policy = new PostPolicy(); - policy.SetContentType("image/png"); - DateTime expiration = DateTime.UtcNow; - policy.SetExpires(expiration.AddDays(10)); - policy.SetKey("my-objectname"); - policy.SetBucket("my-bucketname"); - - Dictionary formData = client.Api.PresignedPostPolicy(policy); - string curlCommand = "curl "; - foreach (KeyValuePair pair in formData) - { - curlCommand = curlCommand + " -F " + pair.Key + "=" + pair.Value; - } - curlCommand = curlCommand + " -F file=@/etc/bashrc https://s3.amazonaws.com/my-bucketname"; - Console.Out.WriteLine(curlCommand); - -} catch(MinioException e) { +try +{ + PostPolicy policy = new PostPolicy(); + policy.SetContentType("image/png"); + DateTime expiration = DateTime.UtcNow; + policy.SetExpires(expiration.AddDays(10)); + policy.SetKey("my-objectname"); + policy.SetBucket("my-bucketname"); + + Dictionary formData = minioClient.Api.PresignedPostPolicy(policy); + string curlCommand = "curl "; + foreach (KeyValuePair pair in formData) + { + curlCommand = curlCommand + " -F " + pair.Key + "=" + pair.Value; + } + curlCommand = curlCommand + " -F file=@/etc/bashrc https://s3.amazonaws.com/my-bucketname"; + Console.Out.WriteLine(curlCommand); +} +catch(MinioException e) +{ Console.Out.WriteLine("Error occurred: " + e); +} ``` ## Client Custom Settings diff --git a/FileUploader/FileUpload.cs b/FileUploader/FileUpload.cs index 39211509a..d9f304205 100644 --- a/FileUploader/FileUpload.cs +++ b/FileUploader/FileUpload.cs @@ -1,14 +1,29 @@ -using System; -using Minio; -using Minio.Exceptions; -using Minio.DataModel; +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; using System.Threading.Tasks; using System.Net; +using Minio; namespace FileUploader { /// - /// + /// This example creates a new bucket if it does not already exist, and uploads a file + /// to the bucket. /// class FileUpload { @@ -31,7 +46,12 @@ static void Main(string[] args) } Console.ReadLine(); } - //Check if a bucket exists + + /// + /// Task that uploads a file to a bucket + /// + /// + /// private async static Task Run(MinioClient minio) { // Make a new bucket called mymusic. @@ -44,20 +64,17 @@ private async static Task Run(MinioClient minio) try { - bool success = await minio.Api.MakeBucketAsync(bucketName, location); - if (!success) { - bool found = await minio.Api.BucketExistsAsync(bucketName); - Console.Out.WriteLine("bucket-name was " + ((found == true) ? "found" : "not found")); - } - else { - await minio.Api.PutObjectAsync(bucketName, objectName, filePath, contentType); - Console.Out.WriteLine("Successfully uploaded " + objectName ); + bool found = await minio.BucketExistsAsync(bucketName); + if (!found) + { + await minio.MakeBucketAsync(bucketName, location); } - + await minio.PutObjectAsync(bucketName, objectName, filePath, contentType); + Console.Out.WriteLine("Successfully uploaded " + objectName ); } catch (Exception e) { - Console.WriteLine("[Bucket] Exception: {0}", e); + Console.Out.WriteLine(e); } } diff --git a/FileUploader/FileUploader.csproj b/FileUploader/FileUploader.csproj index 3db77330a..8a08bb7c4 100644 --- a/FileUploader/FileUploader.csproj +++ b/FileUploader/FileUploader.csproj @@ -49,6 +49,9 @@ + + + {cc30cade-342a-4ced-858d-b60200c075b0} diff --git a/Minio.Api/ApiEndpoints/BucketOperations.cs b/Minio.Api/ApiEndpoints/BucketOperations.cs index 4e9b8929a..afd7699ae 100644 --- a/Minio.Api/ApiEndpoints/BucketOperations.cs +++ b/Minio.Api/ApiEndpoints/BucketOperations.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + using System; using System.Collections.Generic; using System.Net; @@ -24,15 +25,14 @@ using System.Xml.Linq; using System.Xml.Serialization; using Minio.Exceptions; -using System.Text.RegularExpressions; using System.Globalization; using System.Reactive.Linq; -using Minio.Helper; namespace Minio { - public partial class ClientApiOperations : IBucketOperations + public partial class MinioClient : IBucketOperations { + /// /// List all objects in a bucket /// @@ -40,12 +40,12 @@ public partial class ClientApiOperations : IBucketOperations /// An iterator lazily populated with objects public async Task ListBucketsAsync() { + // Initialize a new client + PrepareClient(); + var request = new RestRequest("/", Method.GET); - var response = await this.client.ExecuteTaskAsync(this.client.NoErrorHandlers, request); - if (response.StatusCode != HttpStatusCode.OK) - { - this.client.ParseError(response); - } + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + ListAllMyBucketsResult bucketList = new ListAllMyBucketsResult(); if (HttpStatusCode.OK.Equals(response.StatusCode)) { @@ -61,31 +61,27 @@ public async Task ListBucketsAsync() } /// - /// Create a private bucket with a give name. + /// Create a private bucket with the given name. /// /// Name of the new bucket - public async Task MakeBucketAsync(string bucketName, string location = "us-east-1") + public async Task MakeBucketAsync(string bucketName, string location = "us-east-1") { - var request = new RestRequest("/" + bucketName, Method.PUT); + // Initialize a new client + PrepareClient(); + var request = new RestRequest("/" + bucketName, Method.PUT); // ``us-east-1`` is not a valid location constraint according to amazon, so we skip it. if (location != "us-east-1") { CreateBucketConfiguration config = new CreateBucketConfiguration(location); request.AddBody(config); } - - var response = await this.client.ExecuteTaskAsync(this.client.NoErrorHandlers, request); - if (response.StatusCode == HttpStatusCode.OK) - { - return true; - } - this.client.ParseError(response); - return false; + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + } - + /// /// Returns true if the specified bucketName exists, otherwise returns false. /// @@ -93,29 +89,20 @@ public async Task MakeBucketAsync(string bucketName, string location = "us /// true if exists and user has access public async Task BucketExistsAsync(string bucketName) { - - var request = await client.CreateRequest(Method.HEAD, - bucketName, - region: BucketRegionCache.Instance.Region(bucketName)); - - var response = await this.client.ExecuteTaskAsync(this.client.NoErrorHandlers, request); - - if (response.StatusCode != HttpStatusCode.OK) + try { - try - { - this.client.ParseError(response); - } - catch (Exception ex) + var request = await this.CreateRequest(Method.HEAD, + bucketName,region:"us-east-1"); + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + } + catch (Exception ex) + { + if (ex.GetType() == typeof(BucketNotFoundException)) { - if (ex.GetType() == typeof(BucketNotFoundException)) - { - return false; - } - throw ex; + return false; } + throw ex; } - return true; } @@ -125,16 +112,10 @@ public async Task BucketExistsAsync(string bucketName) /// Name of bucket to remove public async Task RemoveBucketAsync(string bucketName) { - var request =await client.CreateRequest(Method.DELETE, bucketName, - region: BucketRegionCache.Instance.Region(bucketName), - resourcePath:"/"); + var request = await this.CreateRequest(Method.DELETE, bucketName, resourcePath: "/"); - var response = await this.client.ExecuteTaskAsync(this.client.NoErrorHandlers, request); + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); - if (!response.StatusCode.Equals(HttpStatusCode.NoContent)) - { - this.client.ParseError(response); - } } /// @@ -172,9 +153,9 @@ public IObservable ListObjectsAsync(string bucketName, string prefix = nul } }); } - + /// - /// + /// 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 @@ -204,20 +185,15 @@ private async Task>> GetObjectListAsync(strin { path += "?" + query; } - - var request = await client.CreateRequest(Method.GET, - bucketName, - region: BucketRegionCache.Instance.Region(bucketName), - resourcePath:"?" + query); - + var request = await this.CreateRequest(Method.GET, + bucketName, + resourcePath: "?" + query); - var response = await this.client.ExecuteTaskAsync(this.client.NoErrorHandlers, request); - if (response.StatusCode != HttpStatusCode.OK) - { - this.client.ParseError(response); - } + + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + var contentBytes = System.Text.Encoding.UTF8.GetBytes(response.Content); var stream = new MemoryStream(contentBytes); ListBucketResult listBucketResult = (ListBucketResult)(new XmlSerializer(typeof(ListBucketResult)).Deserialize(stream)); @@ -245,6 +221,7 @@ private async Task>> GetObjectListAsync(strin return new Tuple>(listBucketResult, items.ToList()); } + /// /// Returns current policy stored on the server for this bucket /// @@ -255,17 +232,13 @@ private async Task GetPolicyAsync(string bucketName) BucketPolicy policy = null; IRestResponse response = null; - var path =bucketName + "?policy"; + var path = bucketName + "?policy"; + + var request = await this.CreateRequest(Method.GET, bucketName, + contentType: "application/json", + resourcePath: "?policy"); + response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); - var request = await client.CreateRequest(Method.GET, bucketName, - region: BucketRegionCache.Instance.Region(bucketName), - contentType:"application/json", - resourcePath:"?policy"); - response = await this.client.ExecuteTaskAsync(this.client.NoErrorHandlers, request); - if (response.StatusCode != HttpStatusCode.OK) - { - this.client.ParseError(response); - } var contentBytes = System.Text.Encoding.UTF8.GetBytes(response.Content); var stream = new MemoryStream(contentBytes); policy = BucketPolicy.parseJson(stream, bucketName); @@ -277,15 +250,14 @@ private async Task GetPolicyAsync(string bucketName) return policy; } - - + /// /// Get bucket policy at given objectPrefix /// /// Bucket name. /// Name of the object prefix /// Returns the PolicyType - public async Task GetPolicyAsync(string bucketName, string objectPrefix ="") + public async Task GetPolicyAsync(string bucketName, string objectPrefix = "") { BucketPolicy policy = await GetPolicyAsync(bucketName); return policy.getPolicy(objectPrefix); @@ -299,15 +271,14 @@ public async Task GetPolicyAsync(string bucketName, string objectPre /// private async Task setPolicyAsync(string bucketName, BucketPolicy policy) { - + string policyJson = policy.getJson(); - var request = await client.CreateRequest(Method.PUT, bucketName, - resourcePath:"?policy", - region: BucketRegionCache.Instance.Region(bucketName), + var request = await this.CreateRequest(Method.PUT, bucketName, + resourcePath: "?policy", contentType: "application/json", - body:policyJson); + body: policyJson); - IRestResponse response = await this.client.ExecuteTaskAsync(this.client.NoErrorHandlers, request); + IRestResponse response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); } /// @@ -333,8 +304,4 @@ public async Task SetPolicyAsync(String bucketName, String objectPrefix, PolicyT await setPolicyAsync(bucketName, policy); } } -} - - - - +} \ No newline at end of file diff --git a/Minio.Api/ApiEndpoints/IBucketOperations.cs b/Minio.Api/ApiEndpoints/IBucketOperations.cs index 9ba2cbf35..b3d93121e 100644 --- a/Minio.Api/ApiEndpoints/IBucketOperations.cs +++ b/Minio.Api/ApiEndpoints/IBucketOperations.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,19 +21,56 @@ namespace Minio { public interface IBucketOperations { + /// + /// Create a private bucket with the given name. + /// + /// Name of the new bucket + Task MakeBucketAsync(string bucketName, string location = "us-east-1"); - Task MakeBucketAsync(string bucketName, string location = "us-east-1"); - + /// + /// List all objects in a bucket + /// + /// Bucket to list objects from + /// An iterator lazily populated with objects Task ListBucketsAsync(); + /// + /// Returns true if the specified bucketName exists, otherwise returns false. + /// + /// Bucket to test existence of + /// true if exists and user has access Task BucketExistsAsync(string bucketName); + /// + /// Remove a bucket + /// + /// Name of bucket to remove Task RemoveBucketAsync(string bucketName); - // IObservable ListObjectsAsync(string bucketName, string prefix = null, bool recursive = true); + /// + /// 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 + /// An observable of items that client can subscribe to + + /// + /// Get bucket policy at given objectPrefix + /// + /// Bucket name. + /// Name of the object prefix + /// Returns the PolicyType Task GetPolicyAsync(String bucketName, String objectPrefix); + /// + /// Sets the current bucket policy + /// + /// Bucket Name + /// Name of the object prefix. + /// Desired Policy type change + /// Task SetPolicyAsync(String bucketName, String objectPrefix, PolicyType policyType); - + } } \ No newline at end of file diff --git a/Minio.Api/ApiEndpoints/IObjectOperations.cs b/Minio.Api/ApiEndpoints/IObjectOperations.cs index c3029fae4..3e928459c 100644 --- a/Minio.Api/ApiEndpoints/IObjectOperations.cs +++ b/Minio.Api/ApiEndpoints/IObjectOperations.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,29 +16,107 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; using System.Threading.Tasks; using Minio.DataModel; -using RestSharp; + namespace Minio { public interface IObjectOperations { + + /// + /// Get an object. The object will be streamed to the callback given by the user. + /// + /// Bucket to retrieve object from + /// Name of object to retrieve + /// A stream will be passed to the callback Task GetObjectAsync(string bucketName, string objectName, Action callback); + + /// + /// Creates an object from file + /// + /// Bucket to create object in + /// Key of the new object + /// Path of file to upload + /// Content type of the new object, null defaults to "application/octet-stream" Task PutObjectAsync(string bucketName, string objectName, Stream data, long size, string contentType); + + /// + /// Removes an object with given name in specific bucket + /// + /// Bucket to list incomplete uploads from + /// Key of object to list incomplete uploads from + /// Task RemoveObjectAsync(string bucketName, string objectName); + + /// + /// Tests the object's existence and returns metadata about existing objects. + /// + /// Bucket to test object in + /// Name of the object to stat + /// Facts about the object Task StatObjectAsync(string bucketName, string objectName); + + /// + /// 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 + /// A lazily populated list of incomplete uploads IObservable ListIncompleteUploads(string bucketName, string prefix, bool recursive); + + /// + /// Remove incomplete uploads from a given bucket and objectName + /// + /// Bucket to remove incomplete uploads from + /// Key to remove incomplete uploads from Task RemoveIncompleteUploadAsync(string bucketName, string objectName); + + /// + /// Copy a source object into a new destination object. + /// + /// Bucket name where the object to be copied exists. + /// Object name source to be copied. + /// Bucket name where the object will be copied to. + /// Object name to be created, if not provided uses source object name as destination object name. + /// optionally can take a key value CopyConditions as well for conditionally attempting copyObject. + /// + Task CopyObjectAsync(string bucketName, string objectName, string destBucketName, string destObjectName = null, CopyConditions copyConditions = null); - Task PutObjectAsync(string bucketName, string objectName, string filePath, string contentType=null); + + Task PutObjectAsync(string bucketName, string objectName, string filePath, string contentType = null); + + /// + /// Get an object. The object will be streamed to the callback given by the user. + /// + /// Bucket to retrieve object from + /// Name of object to retrieve + /// string with file path + /// Task GetObjectAsync(string bucketName, string objectName, string filePath); - - + + /// + /// Presigned Get url. + /// + /// Bucket to retrieve object from + /// Key of object to retrieve + /// Expiration time in seconds string PresignedGetObject(string bucketName, string objectName, int expiresInt); + + /// + /// Presigned Put url. + /// + /// Bucket to retrieve object from + /// Key of object to retrieve + /// Expiration time in seconds + string PresignedPutObject(string bucketName, string objectName, int expiresInt); + + /// + /// Presigned post policy + /// Dictionary PresignedPostPolicy(PostPolicy policy); - + } -} +} \ No newline at end of file diff --git a/Minio.Api/ApiEndpoints/ObjectOperations.cs b/Minio.Api/ApiEndpoints/ObjectOperations.cs index f6e8a7f18..8e552bbdd 100644 --- a/Minio.Api/ApiEndpoints/ObjectOperations.cs +++ b/Minio.Api/ApiEndpoints/ObjectOperations.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,9 +33,9 @@ namespace Minio { - public partial class ClientApiOperations : IObjectOperations + public partial class MinioClient : IObjectOperations { - + /// /// Get an object. The object will be streamed to the callback given by the user. /// @@ -45,21 +45,15 @@ public partial class ClientApiOperations : IObjectOperations public async Task GetObjectAsync(string bucketName, string objectName, Action cb) { - var request = await client.CreateRequest(Method.GET, + var request = await this.CreateRequest(Method.GET, bucketName, - objectName: objectName, - region: BucketRegionCache.Instance.Region(bucketName) - ); + objectName: objectName); + request.ResponseWriter = cb; - var response = await this.client.ExecuteTaskAsync(this.client.NoErrorHandlers, request); + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); - if (response.StatusCode != HttpStatusCode.OK) - { - this.client.ParseError(response); - } - - return; } + /// /// Get an object. The object will be streamed to the callback given by the user. /// @@ -69,7 +63,7 @@ public async Task GetObjectAsync(string bucketName, string objectName, Action public async Task GetObjectAsync(string bucketName, string objectName, string fileName) { - + bool fileExists = File.Exists(fileName); utils.ValidateFile(fileName); @@ -78,11 +72,11 @@ public async Task GetObjectAsync(string bucketName, string objectName, string fi string etag = objectStat.ETag; string tempFileName = fileName + "." + etag + ".part.minio"; - + bool tempFileExists = File.Exists(tempFileName); utils.ValidateFile(tempFileName); - + FileInfo tempFileInfo = new FileInfo(tempFileName); long tempFileSize = 0; if (tempFileExists) @@ -131,8 +125,9 @@ await GetObjectAsync(bucketName, objectName, (stream) => { } utils.MoveWithReplace(tempFileName, fileName); }); - + } + /// /// Creates an object from file /// @@ -140,7 +135,7 @@ await GetObjectAsync(bucketName, objectName, (stream) => { /// Key of the new object /// Path of file to upload /// Content type of the new object, null defaults to "application/octet-stream" - public async Task PutObjectAsync(string bucketName, string objectName, string fileName, string contentType=null) + public async Task PutObjectAsync(string bucketName, string objectName, string fileName, string contentType = null) { utils.ValidateFile(fileName, contentType); FileInfo fileInfo = new FileInfo(fileName); @@ -148,7 +143,7 @@ public async Task PutObjectAsync(string bucketName, string objectName, string fi using (FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read)) { await PutObjectAsync(bucketName, objectName, file, size, contentType); - } + } } @@ -168,7 +163,7 @@ public async Task PutObjectAsync(string bucketName, string objectName, Stream da { throw new ArgumentNullException("Invalid input stream,cannot be null"); } - + //for sizes less than 5Mb , put a single object if (size < Constants.MinimumPartSize && size >= 0) { @@ -181,7 +176,7 @@ public async Task PutObjectAsync(string bucketName, string objectName, Stream da return; } // For all sizes greater than 5MiB do multipart. - + dynamic multiPartInfo = CalculateMultiPartSize(size); double partSize = multiPartInfo.partSize; double partCount = multiPartInfo.partCount; @@ -198,7 +193,7 @@ public async Task PutObjectAsync(string bucketName, string objectName, Stream da } else { - existingParts = await this.ListParts(bucketName, objectName,uploadId).ToArray(); + existingParts = await this.ListParts(bucketName, objectName, uploadId).ToArray(); } double expectedReadSize = partSize; @@ -224,15 +219,16 @@ public async Task PutObjectAsync(string bucketName, string objectName, Stream da { totalParts[partNumber - 1] = new Part() { PartNumber = part.PartNumber, ETag = part.ETag, size = part.partSize() }; skipUpload = true; - + } } - } else + } + else { skipUpload = false; } - + if (!skipUpload) { string etag = await this.PutObjectAsync(bucketName, objectName, uploadId, partNumber, dataToCopy, contentType); @@ -243,13 +239,13 @@ public async Task PutObjectAsync(string bucketName, string objectName, Stream da Dictionary etags = new Dictionary(); for (partNumber = 1; partNumber <= partCount; partNumber++) { - etags[partNumber] = totalParts[partNumber-1].ETag; + etags[partNumber] = totalParts[partNumber - 1].ETag; } await this.CompleteMultipartUploadAsync(bucketName, objectName, uploadId, etags); - } + } /// - /// internal method to complete multi part upload of object to server + /// Internal method to complete multi part upload of object to server. /// /// Bucket Name /// Object to be uploaded @@ -260,12 +256,11 @@ private async Task CompleteMultipartUploadAsync(string bucketName, string object { string resourcePath = "?uploadId=" + uploadId; - var request = await client.CreateRequest(Method.POST, bucketName, + var request = await this.CreateRequest(Method.POST, bucketName, objectName: objectName, - resourcePath:resourcePath, - region: BucketRegionCache.Instance.Region(bucketName) + resourcePath: resourcePath ); - + List parts = new List(); for (int i = 1; i <= etags.Count; i++) @@ -283,16 +278,12 @@ private async Task CompleteMultipartUploadAsync(string bucketName, string object request.AddParameter("application/xml", body, RestSharp.ParameterType.RequestBody); - var response = await this.client.ExecuteTaskAsync(this.client.NoErrorHandlers,request); - if (response.StatusCode.Equals(HttpStatusCode.OK)) - { - return; - } - this.client.ParseError(response); + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + } /// - /// Calculate part size and number of parts required + /// Calculate part size and number of parts required. /// /// /// @@ -307,18 +298,25 @@ private Object CalculateMultiPartSize(long size) { throw new EntityTooLargeException("Your proposed upload size " + size + " exceeds the maximum allowed object size " + Constants.MaxMultipartPutObjectSize); } - double partSize = (double) Math.Ceiling((decimal)size / Constants.MaxParts); + double partSize = (double)Math.Ceiling((decimal)size / Constants.MaxParts); partSize = (double)Math.Ceiling((decimal)partSize / Constants.MinimumPartSize) * Constants.MinimumPartSize; double partCount = (double)Math.Ceiling(size / partSize); double lastPartSize = size - (partCount - 1) * partSize; return new { partSize = partSize, - partCount =partCount , + partCount = partCount, lastPartSize = lastPartSize }; } - //Returns an async observable of parts corresponding to a uploadId for a specific bucket and objectName + + /// + /// Returns an async observable of parts corresponding to a uploadId for a specific bucket and objectName + /// + /// + /// + /// + /// private IObservable ListParts(string bucketName, string objectName, string uploadId) { @@ -338,7 +336,7 @@ private IObservable ListParts(string bucketName, string objectName, string isRunning = uploads.Item1.IsTruncated; } }); - + } /// /// Gets the list of parts corresponding to a uploadId for given bucket and object @@ -356,36 +354,39 @@ private async Task>> GetListPartsAsync(string resourcePath += "&part-number-marker=" + partNumberMarker; } resourcePath += "&max-parts=1000"; - var request = await client.CreateRequest(Method.GET, bucketName, + var request = await this.CreateRequest(Method.GET, bucketName, objectName: objectName, - resourcePath: resourcePath, - region: BucketRegionCache.Instance.Region(bucketName) - ); - - var response = await this.client.ExecuteTaskAsync(this.client.NoErrorHandlers,request); - if (!response.StatusCode.Equals(HttpStatusCode.OK)) - { - this.client.ParseError(response); - } + resourcePath: resourcePath + ); + + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + var contentBytes = System.Text.Encoding.UTF8.GetBytes(response.Content); var stream = new MemoryStream(contentBytes); ListPartsResult listPartsResult = (ListPartsResult)(new XmlSerializer(typeof(ListPartsResult)).Deserialize(stream)); XDocument root = XDocument.Parse(response.Content); - + var uploads = (from c in root.Root.Descendants("{http://s3.amazonaws.com/doc/2006-03-01/}Part") - select new Part() - { - PartNumber = int.Parse(c.Element("{http://s3.amazonaws.com/doc/2006-03-01/}PartNumber").Value, CultureInfo.CurrentCulture), - ETag = c.Element("{http://s3.amazonaws.com/doc/2006-03-01/}ETag").Value.Replace("\"", ""), - size = long.Parse(c.Element("{http://s3.amazonaws.com/doc/2006-03-01/}Size").Value, CultureInfo.CurrentCulture) - }); - + select new Part() + { + PartNumber = int.Parse(c.Element("{http://s3.amazonaws.com/doc/2006-03-01/}PartNumber").Value, CultureInfo.CurrentCulture), + ETag = c.Element("{http://s3.amazonaws.com/doc/2006-03-01/}ETag").Value.Replace("\"", ""), + size = long.Parse(c.Element("{http://s3.amazonaws.com/doc/2006-03-01/}Size").Value, CultureInfo.CurrentCulture) + }); + return new Tuple>(listPartsResult, uploads.ToList()); - + } - - //starts a multi-part upload request + + + /// + /// Start a new multi-part upload request + /// + /// + /// + /// + /// private async Task NewMultipartUploadAsync(string bucketName, string objectName, string contentType) { var resource = "?uploads"; @@ -394,22 +395,28 @@ private async Task NewMultipartUploadAsync(string bucketName, string obj contentType = "application/octet-stream"; } - var request = await client.CreateRequest(Method.POST, bucketName, objectName: objectName, - contentType: contentType, resourcePath: resource, - region: BucketRegionCache.Instance.Region(bucketName) - ); - var response = await this.client.ExecuteTaskAsync(this.client.NoErrorHandlers,request); - if (!response.StatusCode.Equals(HttpStatusCode.OK)) - { - this.client.ParseError(response); - } + var request = await this.CreateRequest(Method.POST, bucketName, objectName: objectName, + contentType: contentType, resourcePath: resource); + + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + var contentBytes = System.Text.Encoding.UTF8.GetBytes(response.Content); var stream = new MemoryStream(contentBytes); InitiateMultipartUploadResult newUpload = (InitiateMultipartUploadResult)(new XmlSerializer(typeof(InitiateMultipartUploadResult)).Deserialize(stream)); return newUpload.UploadId; } - //Actual doer + + /// + /// Upload object part to bucket for particular uploadId + /// + /// + /// + /// + /// + /// + /// + /// private async Task PutObjectAsync(string bucketName, string objectName, string uploadId, int partNumber, byte[] data, string contentType) { var resource = ""; @@ -417,19 +424,15 @@ private async Task PutObjectAsync(string bucketName, string objectName, { resource += "?uploadId=" + uploadId + "&partNumber=" + partNumber; } - var request = await client.CreateRequest(Method.PUT, bucketName, + var request = await this.CreateRequest(Method.PUT, bucketName, objectName: objectName, contentType: contentType, - body: data, - resourcePath: resource, - region: BucketRegionCache.Instance.Region(bucketName) + body: data, + resourcePath: resource ); - - var response = await this.client.ExecuteTaskAsync(this.client.NoErrorHandlers,request); - if (!response.StatusCode.Equals(HttpStatusCode.OK)) - { - this.client.ParseError(response); - } + + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + string etag = null; foreach (Parameter parameter in response.Headers) { @@ -439,10 +442,19 @@ private async Task PutObjectAsync(string bucketName, string objectName, } } return etag; - - + + } - + + /// + /// Get list of multi-part uploads matching particular uploadIdMarker + /// + /// bucketName + /// prefix + /// + /// + /// + /// private async Task>> GetMultipartUploadsListAsync(string bucketName, string prefix, string keyMarker, @@ -472,15 +484,11 @@ private async Task>> GetMultipart string query = string.Join("&", queries); - var request = await client.CreateRequest(Method.GET, bucketName, - region: BucketRegionCache.Instance.Region(bucketName), - resourcePath:"?" + query); - - var response = await this.client.ExecuteTaskAsync(this.client.NoErrorHandlers,request); - if (response.StatusCode != HttpStatusCode.OK) - { - this.client.ParseError(response); - } + var request = await this.CreateRequest(Method.GET, bucketName, + resourcePath: "?" + query); + + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + var contentBytes = System.Text.Encoding.UTF8.GetBytes(response.Content); var stream = new MemoryStream(contentBytes); ListMultipartUploadsResult listBucketResult = (ListMultipartUploadsResult)(new XmlSerializer(typeof(ListMultipartUploadsResult)).Deserialize(stream)); @@ -488,15 +496,15 @@ private async Task>> GetMultipart XDocument root = XDocument.Parse(response.Content); var uploads = (from c in root.Root.Descendants("{http://s3.amazonaws.com/doc/2006-03-01/}Upload") - select new Upload() - { - Key = c.Element("{http://s3.amazonaws.com/doc/2006-03-01/}Key").Value, - UploadId = c.Element("{http://s3.amazonaws.com/doc/2006-03-01/}UploadId").Value, - Initiated = c.Element("{http://s3.amazonaws.com/doc/2006-03-01/}Initiated").Value - }); + select new Upload() + { + Key = c.Element("{http://s3.amazonaws.com/doc/2006-03-01/}Key").Value, + UploadId = c.Element("{http://s3.amazonaws.com/doc/2006-03-01/}UploadId").Value, + Initiated = c.Element("{http://s3.amazonaws.com/doc/2006-03-01/}Initiated").Value + }); return new Tuple>(listBucketResult, uploads.ToList()); - + } /// @@ -506,7 +514,7 @@ private async Task>> GetMultipart /// prefix to list all incomplete uploads /// option to list incomplete uploads recursively /// A lazily populated list of incomplete uploads - public IObservable ListIncompleteUploads(string bucketName, string prefix="", bool recursive=true) + public IObservable ListIncompleteUploads(string bucketName, string prefix = "", bool recursive = true) { if (recursive) { @@ -515,14 +523,14 @@ public IObservable ListIncompleteUploads(string bucketName, string pref return this.listIncompleteUploads(bucketName, prefix, "/"); } - + /// /// Lists all or delimited incomplete uploads in a given bucket with a given objectName /// /// Bucket to list incomplete uploads from /// Key of object to list incomplete uploads from /// delimiter of object to list incomplete uploads - /// + /// Observable that notifies when next next upload becomes available private IObservable listIncompleteUploads(string bucketName, string prefix, string delimiter) { return Observable.Create( @@ -544,13 +552,19 @@ private IObservable listIncompleteUploads(string bucketName, string pref isRunning = uploads.Item1.IsTruncated; } }); - + } - // find uploadId of most recent unsuccessful attempt to put object + + /// + /// Find uploadId of most recent unsuccessful attempt to upload object to bucket. + /// + /// + /// + /// private async Task getLatestIncompleteUploadIdAsync(string bucketName, string objectName) { Upload latestUpload = null; - var uploads = await this.ListIncompleteUploads(bucketName, objectName).ToArray(); + var uploads = await this.ListIncompleteUploads(bucketName, objectName).ToArray(); foreach (Upload upload in uploads) { if (objectName == upload.Key && (latestUpload == null || latestUpload.Initiated.CompareTo(upload.Initiated) < 0)) @@ -581,28 +595,32 @@ public async Task RemoveIncompleteUploadAsync(string bucketName, string objectNa { if (objectName == upload.Key) { - await this.RemoveUploadAsync(bucketName, objectName, upload.UploadId); + await this.RemoveUploadAsync(bucketName, objectName, upload.UploadId); } } } + + /// + /// Remove object with matching uploadId from bucket + /// + /// + /// + /// + /// private async Task RemoveUploadAsync(string bucketName, string objectName, string uploadId) { - // var resourcePath = "/" + utils.UrlEncode(objectName) + "?uploadId=" + uploadId; + // var resourcePath = "/" + utils.UrlEncode(objectName) + "?uploadId=" + uploadId; var resourcePath = "?uploadId=" + uploadId; - var request = await client.CreateRequest(Method.DELETE, bucketName, + var request = await this.CreateRequest(Method.DELETE, bucketName, objectName: objectName, - region: BucketRegionCache.Instance.Region(bucketName), resourcePath: resourcePath ); - - var response = await this.client.ExecuteTaskAsync(this.client.NoErrorHandlers,request); - if (response.StatusCode != HttpStatusCode.NoContent) - { - this.client.ParseError(response); - } + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + } + /// /// Removes an object with given name in specific bucket /// @@ -612,18 +630,14 @@ private async Task RemoveUploadAsync(string bucketName, string objectName, strin public async Task RemoveObjectAsync(string bucketName, string objectName) { - var request = await client.CreateRequest(Method.DELETE, bucketName, - objectName: objectName, - region: BucketRegionCache.Instance.Region(bucketName) - ); - - var response = await this.client.ExecuteTaskAsync(this.client.NoErrorHandlers, request); + var request = await this.CreateRequest(Method.DELETE, bucketName, + objectName: objectName); + + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + - if (!response.StatusCode.Equals(HttpStatusCode.NoContent)) - { - this.client.ParseError(response); - } } + /// /// Tests the object's existence and returns metadata about existing objects. /// @@ -632,17 +646,13 @@ public async Task RemoveObjectAsync(string bucketName, string objectName) /// Facts about the object public async Task StatObjectAsync(string bucketName, string objectName) { - var request = await client.CreateRequest(Method.HEAD, bucketName, - objectName: objectName, - region: BucketRegionCache.Instance.Region(bucketName) - ); - var response = await this.client.ExecuteTaskAsync(this.client.NoErrorHandlers, request); + var request = await this.CreateRequest(Method.HEAD, bucketName, + objectName: objectName); - if (response.StatusCode != HttpStatusCode.OK) - { - this.client.ParseError(response); - } - + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + + + //Extract stats from response long size = 0; DateTime lastModified = new DateTime(); string etag = ""; @@ -668,15 +678,15 @@ public async Task StatObjectAsync(string bucketName, string objectNa } } return new ObjectStat(objectName, size, lastModified, etag, contentType); - + } - /// - /// Advances in the stream upto currentPartSize or End of Stream - /// - /// - /// - /// bytes read in a byte array + /// + /// Advances in the stream upto currentPartSize or End of Stream + /// + /// + /// + /// bytes read in a byte array internal byte[] ReadFull(Stream data, int currentPartSize) { byte[] result = new byte[currentPartSize]; @@ -717,7 +727,7 @@ internal byte[] ReadFull(Stream data, int currentPartSize) /// Object name to be created, if not provided uses source object name as destination object name. /// optionally can take a key value CopyConditions as well for conditionally attempting copyObject. /// - public async Task CopyObjectAsync(string bucketName, string objectName, string destBucketName,string destObjectName=null,CopyConditions copyConditions=null) + public async Task CopyObjectAsync(string bucketName, string objectName, string destBucketName, string destObjectName = null, CopyConditions copyConditions = null) { if (bucketName == null) { @@ -740,11 +750,11 @@ public async Task CopyObjectAsync(string bucketName, string ob destObjectName = objectName; } - var path = destBucketName + "/" + utils.UrlEncode(destObjectName); - var request = await client.CreateRequest(Method.PUT, bucketName, - objectName: objectName, - region: BucketRegionCache.Instance.Region(bucketName), resourcePath:path - ); + var path = destBucketName + "/" + utils.UrlEncode(destObjectName); + var request = await this.CreateRequest(Method.PUT, bucketName, + objectName: objectName, + resourcePath: path); + // Set the object source request.AddHeader("x-amz-copy-source", sourceObjectPath); @@ -757,22 +767,16 @@ public async Task CopyObjectAsync(string bucketName, string ob } } - var response = await this.client.ExecuteTaskAsync(this.client.NoErrorHandlers, request); - if (!response.StatusCode.Equals(HttpStatusCode.OK)) - { - this.client.ParseError(response); - } - + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); // For now ignore the copyObjectResult, just read and parse it. var contentBytes = System.Text.Encoding.UTF8.GetBytes(response.Content); var stream = new MemoryStream(contentBytes); - CopyObjectResult copyObjectResult = (CopyObjectResult)(new XmlSerializer(typeof(CopyObjectResult)).Deserialize(stream)); + CopyObjectResult copyObjectResult = (CopyObjectResult)(new XmlSerializer(typeof(CopyObjectResult)).Deserialize(stream)); return copyObjectResult; } - /// /// Presigned Get url. /// @@ -781,8 +785,11 @@ public async Task CopyObjectAsync(string bucketName, string ob /// Expiration time in seconds public string PresignedGetObject(string bucketName, string objectName, int expiresInt) { + // Initialize a new client. + PrepareClient(bucketName); + RestRequest request = new RestRequest(bucketName + "/" + utils.UrlEncode(objectName), Method.GET); - return this.client.authenticator.PresignURL(this.client.restClient, request, expiresInt); + return this.authenticator.PresignURL(this.restClient, request, expiresInt); } /// @@ -793,8 +800,10 @@ public string PresignedGetObject(string bucketName, string objectName, int expir /// Expiration time in seconds public string PresignedPutObject(string bucketName, string objectName, int expiresInt) { + //Initialize a new client. + PrepareClient(bucketName); RestRequest request = new RestRequest(bucketName + "/" + utils.UrlEncode(objectName), Method.PUT); - return this.client.authenticator.PresignURL(this.client.restClient, request, expiresInt); + return this.authenticator.PresignURL(this.restClient, request, expiresInt); } /// @@ -802,6 +811,9 @@ public string PresignedPutObject(string bucketName, string objectName, int expir /// public Dictionary PresignedPostPolicy(PostPolicy policy) { + //Initialize a new client. + PrepareClient(); + if (!policy.IsBucketSet()) { throw new ArgumentException("bucket should be set"); @@ -817,15 +829,15 @@ public Dictionary PresignedPostPolicy(PostPolicy policy) throw new ArgumentException("expiration should be set"); } - string region = Regions.GetRegion(this.client.restClient.BaseUrl.Host); + string region = Regions.GetRegion(this.restClient.BaseUrl.Host); DateTime signingDate = DateTime.UtcNow; policy.SetAlgorithm("AWS4-HMAC-SHA256"); - policy.SetCredential(this.client.authenticator.GetCredentialString(signingDate, region)); + policy.SetCredential(this.authenticator.GetCredentialString(signingDate, region)); policy.SetDate(signingDate); string policyBase64 = policy.Base64(); - string signature = this.client.authenticator.PresignPostSignature(region, signingDate, policyBase64); + string signature = this.authenticator.PresignPostSignature(region, signingDate, policyBase64); policy.SetPolicy(policyBase64); policy.SetSignature(signature); @@ -833,5 +845,4 @@ public Dictionary PresignedPostPolicy(PostPolicy policy) return policy.GetFormData(); } } -} - +} \ No newline at end of file diff --git a/Minio.Api/BucketRegionCache.cs b/Minio.Api/BucketRegionCache.cs index b18e6b3b9..32d9c11c3 100644 --- a/Minio.Api/BucketRegionCache.cs +++ b/Minio.Api/BucketRegionCache.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,11 @@ using Minio.Helper; using RestSharp; + using System; using System.Collections.Concurrent; using System.IO; -using System.Linq; using System.Net; -using System.Text; using System.Threading.Tasks; using System.Xml.Linq; @@ -32,6 +31,7 @@ public sealed class BucketRegionCache { private static readonly Lazy lazy = new Lazy(() => new BucketRegionCache()); + private ConcurrentDictionary regionMap; public static BucketRegionCache Instance @@ -87,7 +87,7 @@ public bool Exists(String bucketName) /// Updates Region cache for given bucket. /// /// - internal async Task Update(MinioClient client,string bucketName) + internal async Task Update(MinioClient client, string bucketName) { string region = null; @@ -96,8 +96,11 @@ internal async Task Update(MinioClient client,string bucketName) { string location = null; var path = bucketName + "?location"; + //Initialize client + client.PrepareClient(); + var request = new RestRequest(path, Method.GET); - + var response = await client.ExecuteTaskAsync(client.NoErrorHandlers, request); if (HttpStatusCode.OK.Equals(response.StatusCode)) @@ -132,10 +135,5 @@ internal async Task Update(MinioClient client,string bucketName) } - /// - /// Updates Region cache for given bucket. - /// - /// - } -} +} \ No newline at end of file diff --git a/Minio.Api/ClassDiagram1.cd b/Minio.Api/ClassDiagram1.cd deleted file mode 100644 index 7b894197b..000000000 --- a/Minio.Api/ClassDiagram1.cd +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/Minio.Api/DataModel/Bucket.cs b/Minio.Api/DataModel/Bucket.cs index 5d801c261..da26cff8f 100644 --- a/Minio.Api/DataModel/Bucket.cs +++ b/Minio.Api/DataModel/Bucket.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/DataModel/CopyConditions.cs b/Minio.Api/DataModel/CopyConditions.cs index dd5b35636..14c9ca1a0 100644 --- a/Minio.Api/DataModel/CopyConditions.cs +++ b/Minio.Api/DataModel/CopyConditions.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/DataModel/CopyObjectResult.cs b/Minio.Api/DataModel/CopyObjectResult.cs index 310ac2fc7..29857de28 100644 --- a/Minio.Api/DataModel/CopyObjectResult.cs +++ b/Minio.Api/DataModel/CopyObjectResult.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/DataModel/CreateBucketConfiguration.cs b/Minio.Api/DataModel/CreateBucketConfiguration.cs index 3797846ba..fe58e3e76 100644 --- a/Minio.Api/DataModel/CreateBucketConfiguration.cs +++ b/Minio.Api/DataModel/CreateBucketConfiguration.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/DataModel/DateFormat.cs b/Minio.Api/DataModel/DateFormat.cs index a4897ae31..a8b49af8f 100644 --- a/Minio.Api/DataModel/DateFormat.cs +++ b/Minio.Api/DataModel/DateFormat.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/DataModel/Grant.cs b/Minio.Api/DataModel/Grant.cs index 87d33929c..02dd663d6 100644 --- a/Minio.Api/DataModel/Grant.cs +++ b/Minio.Api/DataModel/Grant.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/DataModel/GranteeUser.cs b/Minio.Api/DataModel/GranteeUser.cs index 8ab4a8e0b..2393f7341 100644 --- a/Minio.Api/DataModel/GranteeUser.cs +++ b/Minio.Api/DataModel/GranteeUser.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/DataModel/InitiateMultipartUploadResult.cs b/Minio.Api/DataModel/InitiateMultipartUploadResult.cs index bfb741671..b117b49bd 100644 --- a/Minio.Api/DataModel/InitiateMultipartUploadResult.cs +++ b/Minio.Api/DataModel/InitiateMultipartUploadResult.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/DataModel/Item.cs b/Minio.Api/DataModel/Item.cs index f63fef5b8..1cd62995f 100644 --- a/Minio.Api/DataModel/Item.cs +++ b/Minio.Api/DataModel/Item.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/DataModel/ListAllMyBucketsResult.cs b/Minio.Api/DataModel/ListAllMyBucketsResult.cs index 4db24918b..7aac1bcf6 100644 --- a/Minio.Api/DataModel/ListAllMyBucketsResult.cs +++ b/Minio.Api/DataModel/ListAllMyBucketsResult.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/DataModel/ListBucketResult.cs b/Minio.Api/DataModel/ListBucketResult.cs index 8674d7790..93aca607a 100644 --- a/Minio.Api/DataModel/ListBucketResult.cs +++ b/Minio.Api/DataModel/ListBucketResult.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/DataModel/ListMultipartUploadsResult.cs b/Minio.Api/DataModel/ListMultipartUploadsResult.cs index 153fffbdd..25b243e6a 100644 --- a/Minio.Api/DataModel/ListMultipartUploadsResult.cs +++ b/Minio.Api/DataModel/ListMultipartUploadsResult.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/DataModel/ListPartsResult.cs b/Minio.Api/DataModel/ListPartsResult.cs index fd823487f..a3e760d49 100644 --- a/Minio.Api/DataModel/ListPartsResult.cs +++ b/Minio.Api/DataModel/ListPartsResult.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/DataModel/LocationConstraint.cs b/Minio.Api/DataModel/LocationConstraint.cs index 94a9349ec..c4b9f7283 100644 --- a/Minio.Api/DataModel/LocationConstraint.cs +++ b/Minio.Api/DataModel/LocationConstraint.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/DataModel/ObjectStat.cs b/Minio.Api/DataModel/ObjectStat.cs index 62d5f5829..2b51c5133 100644 --- a/Minio.Api/DataModel/ObjectStat.cs +++ b/Minio.Api/DataModel/ObjectStat.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/DataModel/Part.cs b/Minio.Api/DataModel/Part.cs index c9442d4cb..27486bedb 100644 --- a/Minio.Api/DataModel/Part.cs +++ b/Minio.Api/DataModel/Part.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,17 +25,7 @@ public class Part public int PartNumber { get; set; } public long size { get; set; } public DateTime lastModified { get; set; } - //public Part(int partNumber, string etag,long size) - //{ - // this.etag = etag; - // this.PartNumber = partNumber; - // this.size = size; - //} - //public Part(int partNumber, string etag) - //{ - // this.etag = etag; - // this.PartNumber = partNumber; - //} + public string ETag { get diff --git a/Minio.Api/DataModel/Policy/ActionJsonConverter.cs b/Minio.Api/DataModel/Policy/ActionJsonConverter.cs index 304d92ce8..8c4a811f4 100644 --- a/Minio.Api/DataModel/Policy/ActionJsonConverter.cs +++ b/Minio.Api/DataModel/Policy/ActionJsonConverter.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,13 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Newtonsoft.Json; -using Minio.DataModel.Policy; + namespace Minio.DataModel.Policy { class ActionJsonConverter : JsonConverter diff --git a/Minio.Api/DataModel/Policy/BucketPolicy.cs b/Minio.Api/DataModel/Policy/BucketPolicy.cs index 484661c26..32047199a 100644 --- a/Minio.Api/DataModel/Policy/BucketPolicy.cs +++ b/Minio.Api/DataModel/Policy/BucketPolicy.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,16 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - using System; + +using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Newtonsoft.Json; using System.IO; using Newtonsoft.Json.Linq; using Minio.Policy; -using Minio.DataModel.Policy; namespace Minio.DataModel { diff --git a/Minio.Api/DataModel/Policy/ConditionKeyMap.cs b/Minio.Api/DataModel/Policy/ConditionKeyMap.cs index bc2118db6..c9e5d9451 100644 --- a/Minio.Api/DataModel/Policy/ConditionKeyMap.cs +++ b/Minio.Api/DataModel/Policy/ConditionKeyMap.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,11 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Minio.DataModel { diff --git a/Minio.Api/DataModel/Policy/ConditionMap.cs b/Minio.Api/DataModel/Policy/ConditionMap.cs index 71c60469c..869795cab 100644 --- a/Minio.Api/DataModel/Policy/ConditionMap.cs +++ b/Minio.Api/DataModel/Policy/ConditionMap.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,7 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - using System.Collections.Generic; + +using System.Collections.Generic; + namespace Minio.DataModel { internal class ConditionMap: Dictionary diff --git a/Minio.Api/DataModel/Policy/Constants.cs b/Minio.Api/DataModel/Policy/Constants.cs index 8b9114879..5c88f7635 100644 --- a/Minio.Api/DataModel/Policy/Constants.cs +++ b/Minio.Api/DataModel/Policy/Constants.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,11 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Minio.Policy { diff --git a/Minio.Api/DataModel/Policy/PolicyType.cs b/Minio.Api/DataModel/Policy/PolicyType.cs index 6656d6c3b..78ec1f130 100644 --- a/Minio.Api/DataModel/Policy/PolicyType.cs +++ b/Minio.Api/DataModel/Policy/PolicyType.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,15 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Minio.DataModel { - + public class PolicyType { private PolicyType(string value) { Value = value; } @@ -32,6 +27,10 @@ public class PolicyType public static PolicyType READ_WRITE { get { return new PolicyType("readwrite"); } } public static PolicyType WRITE_ONLY { get { return new PolicyType("writeonly"); } } + public override string ToString() + { + return string.Format("{0}", this.Value); + } } } diff --git a/Minio.Api/DataModel/Policy/Principal.cs b/Minio.Api/DataModel/Policy/Principal.cs index 79d1d1bb4..220b2c0c7 100644 --- a/Minio.Api/DataModel/Policy/Principal.cs +++ b/Minio.Api/DataModel/Policy/Principal.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,11 +15,7 @@ */ using System.Collections.Generic; using System.Runtime.Serialization; -using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; -using Newtonsoft.Json.Converters; -using Newtonsoft.Json.Schema; -using Newtonsoft.Json.Bson; using Newtonsoft.Json; using Minio.DataModel.Policy; diff --git a/Minio.Api/DataModel/Policy/PrincipalJsonConverter.cs b/Minio.Api/DataModel/Policy/PrincipalJsonConverter.cs index 8e302c21a..b81111cec 100644 --- a/Minio.Api/DataModel/Policy/PrincipalJsonConverter.cs +++ b/Minio.Api/DataModel/Policy/PrincipalJsonConverter.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,13 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Newtonsoft.Json; -using Minio.DataModel.Policy; + namespace Minio.DataModel.Policy { class PrincipalJsonConverter : JsonConverter diff --git a/Minio.Api/DataModel/Policy/ResourceJsonConverter.cs b/Minio.Api/DataModel/Policy/ResourceJsonConverter.cs index b724d64e3..570d6f81e 100644 --- a/Minio.Api/DataModel/Policy/ResourceJsonConverter.cs +++ b/Minio.Api/DataModel/Policy/ResourceJsonConverter.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,14 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - using System; + +using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using Minio.DataModel.Policy; + namespace Minio.DataModel.Policy { class ResourceJsonConverter : JsonConverter diff --git a/Minio.Api/DataModel/Policy/Resources.cs b/Minio.Api/DataModel/Policy/Resources.cs index 226660f80..cc79daf96 100644 --- a/Minio.Api/DataModel/Policy/Resources.cs +++ b/Minio.Api/DataModel/Policy/Resources.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,12 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Text.RegularExpressions; + namespace Minio.DataModel { internal class Resources : HashSet diff --git a/Minio.Api/DataModel/Policy/SingleOrArrayConverter.cs b/Minio.Api/DataModel/Policy/SingleOrArrayConverter.cs index 1c97a289b..184a79504 100644 --- a/Minio.Api/DataModel/Policy/SingleOrArrayConverter.cs +++ b/Minio.Api/DataModel/Policy/SingleOrArrayConverter.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,17 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Newtonsoft.Json; using Newtonsoft.Json.Linq; + namespace Minio.DataModel.Policy { - - class SingleOrArrayConverter : JsonConverter + + class SingleOrArrayConverter : JsonConverter { public override bool CanConvert(Type objectType) { diff --git a/Minio.Api/DataModel/Policy/Statement.cs b/Minio.Api/DataModel/Policy/Statement.cs index c622ecc10..930b0ef61 100644 --- a/Minio.Api/DataModel/Policy/Statement.cs +++ b/Minio.Api/DataModel/Policy/Statement.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,12 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -using System; + using System.Collections.Generic; -using System.Runtime.Serialization; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Newtonsoft.Json; using Minio.Policy; using Minio.DataModel.Policy; diff --git a/Minio.Api/DataModel/Policy/StatementJsonConverter.cs b/Minio.Api/DataModel/Policy/StatementJsonConverter.cs index 1c73413c5..a54096186 100644 --- a/Minio.Api/DataModel/Policy/StatementJsonConverter.cs +++ b/Minio.Api/DataModel/Policy/StatementJsonConverter.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,11 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + using System; -using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Newtonsoft.Json; using Newtonsoft.Json.Linq; diff --git a/Minio.Api/DataModel/PostPolicy.cs b/Minio.Api/DataModel/PostPolicy.cs index 44943499a..82bee6ce4 100644 --- a/Minio.Api/DataModel/PostPolicy.cs +++ b/Minio.Api/DataModel/PostPolicy.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/DataModel/Prefix.cs b/Minio.Api/DataModel/Prefix.cs index 2eacc8308..63f76b3f8 100644 --- a/Minio.Api/DataModel/Prefix.cs +++ b/Minio.Api/DataModel/Prefix.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/DataModel/Upload.cs b/Minio.Api/DataModel/Upload.cs index 3a9967427..81953e56e 100644 --- a/Minio.Api/DataModel/Upload.cs +++ b/Minio.Api/DataModel/Upload.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/Exceptions/AccessDeniedException.cs b/Minio.Api/Exceptions/AccessDeniedException.cs index e89858e10..02f567aa0 100644 --- a/Minio.Api/Exceptions/AccessDeniedException.cs +++ b/Minio.Api/Exceptions/AccessDeniedException.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/Exceptions/BucketNotFoundException.cs b/Minio.Api/Exceptions/BucketNotFoundException.cs index 1c9c52b69..668932539 100644 --- a/Minio.Api/Exceptions/BucketNotFoundException.cs +++ b/Minio.Api/Exceptions/BucketNotFoundException.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/Exceptions/ConnectionException.cs b/Minio.Api/Exceptions/ConnectionException.cs index bea0448d9..4ae3808df 100644 --- a/Minio.Api/Exceptions/ConnectionException.cs +++ b/Minio.Api/Exceptions/ConnectionException.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/Exceptions/EntityTooLargeException.cs b/Minio.Api/Exceptions/EntityTooLargeException.cs index d0732e8f1..607c0aa72 100644 --- a/Minio.Api/Exceptions/EntityTooLargeException.cs +++ b/Minio.Api/Exceptions/EntityTooLargeException.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/Exceptions/ErrorResponse.cs b/Minio.Api/Exceptions/ErrorResponse.cs index 47b173701..d0b47444b 100644 --- a/Minio.Api/Exceptions/ErrorResponse.cs +++ b/Minio.Api/Exceptions/ErrorResponse.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ namespace Minio.Exceptions { [Serializable] - [XmlRoot(ElementName="Exception", Namespace = "")] + [XmlRoot(ElementName="Error", Namespace = "")] public class ErrorResponse { public string Code { get; set; } diff --git a/Minio.Api/Exceptions/ForbiddenException.cs b/Minio.Api/Exceptions/ForbiddenException.cs index 48b362979..ef8461fb3 100644 --- a/Minio.Api/Exceptions/ForbiddenException.cs +++ b/Minio.Api/Exceptions/ForbiddenException.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/Exceptions/InternalClientException.cs b/Minio.Api/Exceptions/InternalClientException.cs index ab3a99a11..6a3a91fcb 100644 --- a/Minio.Api/Exceptions/InternalClientException.cs +++ b/Minio.Api/Exceptions/InternalClientException.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/Exceptions/InternalServerException.cs b/Minio.Api/Exceptions/InternalServerException.cs index 53c8f0236..55c51a290 100644 --- a/Minio.Api/Exceptions/InternalServerException.cs +++ b/Minio.Api/Exceptions/InternalServerException.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/Exceptions/InvalidBucketNameException.cs b/Minio.Api/Exceptions/InvalidBucketNameException.cs index 66f939fd3..d3b6c6548 100644 --- a/Minio.Api/Exceptions/InvalidBucketNameException.cs +++ b/Minio.Api/Exceptions/InvalidBucketNameException.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/Exceptions/InvalidContentLengthException.cs b/Minio.Api/Exceptions/InvalidContentLengthException.cs index 5397e9a4f..a1275f49c 100644 --- a/Minio.Api/Exceptions/InvalidContentLengthException.cs +++ b/Minio.Api/Exceptions/InvalidContentLengthException.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/Exceptions/InvalidEndpointException.cs b/Minio.Api/Exceptions/InvalidEndpointException.cs index 1bbf437f5..33835b137 100644 --- a/Minio.Api/Exceptions/InvalidEndpointException.cs +++ b/Minio.Api/Exceptions/InvalidEndpointException.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/Exceptions/InvalidKeyNameException.cs b/Minio.Api/Exceptions/InvalidKeyNameException.cs index 691024ade..26e740e39 100644 --- a/Minio.Api/Exceptions/InvalidKeyNameException.cs +++ b/Minio.Api/Exceptions/InvalidKeyNameException.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/Exceptions/InvalidObjectNameException.cs b/Minio.Api/Exceptions/InvalidObjectNameException.cs index 95d788fdd..8fd54748e 100644 --- a/Minio.Api/Exceptions/InvalidObjectNameException.cs +++ b/Minio.Api/Exceptions/InvalidObjectNameException.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/Exceptions/InvalidObjectPrefixException.cs b/Minio.Api/Exceptions/InvalidObjectPrefixException.cs index f1cb8cf68..93c2a4031 100644 --- a/Minio.Api/Exceptions/InvalidObjectPrefixException.cs +++ b/Minio.Api/Exceptions/InvalidObjectPrefixException.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/Exceptions/InvalidPortException.cs b/Minio.Api/Exceptions/InvalidPortException.cs index 9ff6b5473..ab8dbaa8e 100644 --- a/Minio.Api/Exceptions/InvalidPortException.cs +++ b/Minio.Api/Exceptions/InvalidPortException.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/Exceptions/InvalidTransferAccelerationBucketException.cs b/Minio.Api/Exceptions/InvalidTransferAccelerationBucketException.cs deleted file mode 100644 index b1b57d55f..000000000 --- a/Minio.Api/Exceptions/InvalidTransferAccelerationBucketException.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Minio.Exceptions -{ - class InvalidTransferAccelerationBucketException : MinioException - { - private string bucketName; - public InvalidTransferAccelerationBucketException() - { - - } - public InvalidTransferAccelerationBucketException(string bucketName, string message = null) : base(message) - - { - this.bucketName = bucketName; - } - public override string ToString() - { - return this.bucketName + ": The name of the bucket used for Transfer Acceleration must be DNS-compliant and must not contain periods \".\""; - } - } -} diff --git a/Minio.Api/Exceptions/MaxBucketsReachedException.cs b/Minio.Api/Exceptions/MaxBucketsReachedException.cs index e8ab5d102..e1ef4bf88 100644 --- a/Minio.Api/Exceptions/MaxBucketsReachedException.cs +++ b/Minio.Api/Exceptions/MaxBucketsReachedException.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/Exceptions/MethodNotAllowedException.cs b/Minio.Api/Exceptions/MethodNotAllowedException.cs index 4328e6789..c2ed0ff6a 100644 --- a/Minio.Api/Exceptions/MethodNotAllowedException.cs +++ b/Minio.Api/Exceptions/MethodNotAllowedException.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/Exceptions/MinioException.cs b/Minio.Api/Exceptions/MinioException.cs index f90d07130..48e1c0c8b 100644 --- a/Minio.Api/Exceptions/MinioException.cs +++ b/Minio.Api/Exceptions/MinioException.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/Exceptions/ObjectNotFoundException.cs b/Minio.Api/Exceptions/ObjectNotFoundException.cs index 2a6a86bfa..90f2a8909 100644 --- a/Minio.Api/Exceptions/ObjectNotFoundException.cs +++ b/Minio.Api/Exceptions/ObjectNotFoundException.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/Exceptions/RedirectionException.cs b/Minio.Api/Exceptions/RedirectionException.cs index d87b3352b..5b2bfba21 100644 --- a/Minio.Api/Exceptions/RedirectionException.cs +++ b/Minio.Api/Exceptions/RedirectionException.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/Exceptions/UnexpectedShortReadException.cs b/Minio.Api/Exceptions/UnexpectedShortReadException.cs index 84729d56f..fe4995298 100644 --- a/Minio.Api/Exceptions/UnexpectedShortReadException.cs +++ b/Minio.Api/Exceptions/UnexpectedShortReadException.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/Helper/Constants.cs b/Minio.Api/Helper/Constants.cs index 1fc536018..37b873dd3 100644 --- a/Minio.Api/Helper/Constants.cs +++ b/Minio.Api/Helper/Constants.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/Helper/Enum.cs b/Minio.Api/Helper/Enum.cs new file mode 100644 index 000000000..76a198662 --- /dev/null +++ b/Minio.Api/Helper/Enum.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Minio +{ + class Enum + { + /// + /// HTTP method to use when making requests + /// + public enum Method + { + GET, + POST, + PUT, + DELETE, + HEAD, + OPTIONS, + PATCH, + MERGE, + } + } +} diff --git a/Minio.Api/Helper/s3utils.cs b/Minio.Api/Helper/s3utils.cs index a1f2128ad..4d4e808b4 100644 --- a/Minio.Api/Helper/s3utils.cs +++ b/Minio.Api/Helper/s3utils.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/Helper/utils.cs b/Minio.Api/Helper/utils.cs index ae7895c2d..b13ea73af 100644 --- a/Minio.Api/Helper/utils.cs +++ b/Minio.Api/Helper/utils.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/MinioApi.csproj b/Minio.Api/MinioApi.csproj index 0fe862c30..216137819 100644 --- a/Minio.Api/MinioApi.csproj +++ b/Minio.Api/MinioApi.csproj @@ -30,12 +30,16 @@ 4 + + ..\packages\AutoMapper.5.2.0\lib\net45\AutoMapper.dll + True + ..\packages\Newtonsoft.Json.9.0.2-beta2\lib\net45\Newtonsoft.Json.dll True - - ..\packages\RestSharp.105.2.2\lib\net452\RestSharp.dll + + ..\packages\RestSharp.105.2.3\lib\net452\RestSharp.dll True @@ -62,17 +66,19 @@ - + + ..\packages\System.Xml.Linq.3.5.21022.801\lib\net20\System.Xml.Linq.dll + True + - @@ -131,10 +137,9 @@ - + - @@ -142,7 +147,6 @@ - diff --git a/Minio.Api/MinioClient.cs b/Minio.Api/MinioClient.cs index dec16317e..7d6b4849e 100644 --- a/Minio.Api/MinioClient.cs +++ b/Minio.Api/MinioClient.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,28 +25,39 @@ using System.Threading; using System.Threading.Tasks; using Minio.Helper; -using Newtonsoft.Json; +using Newtonsoft.Json; +using System.Net.Http; namespace Minio { - public sealed class MinioClient + public partial class MinioClient { - public string AccessKey { get; private set; } - public string SecretKey { get; private set; } - public string Endpoint { get; private set; } + // Save Credentials from user + internal string AccessKey { get; private set; } + internal string SecretKey { get; private set; } internal string BaseUrl { get; private set; } - internal bool Secure { get; private set; } - internal bool Anonymous { get; } + // Reconstructed endpoint with scheme and host.In the case of Amazon, this url + // is the virtual style path or location based endpoint + internal string Endpoint { get; private set; } + // Corresponding URI for above endpoint internal Uri uri; - internal string s3AccelerateEndpoint; + + // Indicates if we are using HTTPS or not + internal bool Secure { get; private set; } + + // RESTSharp client internal RestClient restClient; + // Custom authenticator for RESTSharp internal V4Authenticator authenticator; + + // Cache holding bucket to region mapping for buckets seen so far. internal BucketRegionCache regionCache; + // Enables HTTP tracing if set to true private bool trace = false; - public ClientApiOperations Api; + private const string RegistryAuthHeaderKey = "X-Registry-Auth"; internal readonly IEnumerable NoErrorHandlers = Enumerable.Empty(); @@ -55,7 +66,7 @@ public sealed class MinioClient { if (response.StatusCode < HttpStatusCode.OK || response.StatusCode >= HttpStatusCode.BadRequest) { - throw new MinioException(response); + ParseError(response); } }; @@ -70,7 +81,7 @@ private static string SystemUserAgent } private string CustomUserAgent = ""; - + // returns the User-Agent header for the request private string FullUserAgent { get @@ -80,24 +91,24 @@ private string FullUserAgent } /// - /// Constructs a RestRequest. For AWS, this function overrides the baseUrl in the RestClient - /// with region specific host path or virtual style path. + /// Constructs a RestRequest. For AWS, this function has the side-effect of overriding the baseUrl + /// in the RestClient with region specific host path or virtual style path. /// /// HTTP method /// Bucket Name /// Object Name - /// Region - applies only to AWS - /// unused headerMap + /// headerMap /// unused queryParamMap /// Content Type /// request body /// query string - /// + /// A RestRequest internal async Task CreateRequest(Method method, string bucketName, string objectName = null, - string region = null, Dictionary headerMap = null, + Dictionary headerMap = null, string contentType = "application/xml", - Object body = null, string resourcePath=null) + Object body = null, string resourcePath = null, string region = null) { + //Validate bucket name and object name if (bucketName == null && objectName == null) { throw new InvalidBucketNameException(bucketName, "null bucket name for object '" + objectName + "'"); @@ -108,41 +119,31 @@ internal async Task CreateRequest(Method method, string bucketName, utils.validateObjectName(objectName); } + + // Start with user specified endpoint string host = this.BaseUrl; //Fetch correct region for bucket - if (!BucketRegionCache.Instance.Exists(bucketName)) + if (region == null) { - region = await BucketRegionCache.Instance.Update(this, bucketName); - } - - string baseUrl = null; //Base url path - string resource = null; //Resource being requested - bool usePathStyle = false; - if (s3utils.IsAmazonEndPoint(this.BaseUrl)) - { - if (this.s3AccelerateEndpoint != null && bucketName != null) + if (!BucketRegionCache.Instance.Exists(bucketName)) { - // http://docs.aws.amazon.com/AmazonS3/latest/dev/transfer-acceleration.html - // Disable transfer acceleration for non-compliant bucket names. - if (bucketName.Contains(".")) - { - throw new InvalidTransferAccelerationBucketException(bucketName); - } - // If transfer acceleration is requested set new host. - // For more details about enabling transfer acceleration read here. - // http://docs.aws.amazon.com/AmazonS3/latest/dev/transfer-acceleration.html - host = s3AccelerateEndpoint; + region = await BucketRegionCache.Instance.Update(this, bucketName); } else { - // Fetch new host based on the bucket location. - host = AWSS3Endpoints.Instance.endpoint(region); - + region = BucketRegionCache.Instance.Region(bucketName); } + } + + // This section reconstructs the url with scheme followed by location specific endpoint( s3.region.amazonaws.com) + // or Virtual Host styled endpoint (bucketname.s3.region.amazonaws.com) for Amazon requests. + string resource = null; //Resource being requested + bool usePathStyle = false; + if (s3utils.IsAmazonEndPoint(this.BaseUrl)) + { usePathStyle = false; - var scheme = this.Secure ? Uri.UriSchemeHttps : Uri.UriSchemeHttp; if (method == Method.PUT && objectName == null && resourcePath == null) { @@ -163,30 +164,24 @@ internal async Task CreateRequest(Method method, string bucketName, { usePathStyle = true; } - + if (usePathStyle) { resource = utils.UrlEncode(bucketName) + "/"; } else { - baseUrl = scheme + "://" + utils.UrlEncode(bucketName) + "." + utils.UrlEncode(host) + "/"; resource = "/"; } } else - { + { resource = utils.UrlEncode(bucketName) + "/"; } - if (s3utils.IsAmazonEndPoint(this.BaseUrl) && region != null) - { - //override the baseUrl in RestClient with virtual style path or region - // specific deviation from AWS default url. - _constructUri(region, bucketName); - this.restClient.BaseUrl = usePathStyle == true ? this.uri : new Uri(baseUrl); + // Prepare client state + PrepareClient(bucketName, region, usePathStyle); - } if (objectName != null) { // Limitation: OkHttp does not allow to add '.' and '..' as path segment. @@ -196,12 +191,14 @@ internal async Task CreateRequest(Method method, string bucketName, } } + + // Append query string passed in if (resourcePath != null) { resource += resourcePath; } - RestRequest request = new RestRequest(resource,method); + RestRequest request = new RestRequest(resource, method); if (body != null) { @@ -213,6 +210,7 @@ internal async Task CreateRequest(Method method, string bucketName, { request.AddHeader("Content-Type", contentType); } + if (headerMap != null) { foreach (KeyValuePair entry in headerMap) @@ -223,38 +221,61 @@ internal async Task CreateRequest(Method method, string bucketName, return request; } - - /// - /// Helper function to construct URI and validate it - /// - /// Region - applies only to AWS - /// Bucket Name - private void _constructUri(string region = null, string bucketName = null) + + /// + /// This method initializes a new RESTClient. The host URI for Amazon is set to virtual hosted style + /// if usePathStyle is false. Otherwise path style URL is constructed. + /// + /// bucketName + /// Region bucket resides in. + /// bool controlling if pathstyle URL needs to be constructed or virtual hosted style URL + internal void PrepareClient(string bucketName = null, string region = null, bool usePathStyle = true) { if (string.IsNullOrEmpty(this.BaseUrl)) { throw new InvalidEndpointException("Endpoint cannot be empty."); } + string host = this.BaseUrl; + // For Amazon S3 endpoint, try to fetch location based endpoint. if (s3utils.IsAmazonEndPoint(this.BaseUrl)) { // Fetch new host based on the bucket location. host = AWSS3Endpoints.Instance.endpoint(region); + if (!usePathStyle) + { + host = utils.UrlEncode(bucketName) + "." + utils.UrlEncode(host) + "/"; + } } - var scheme = Secure ? Uri.UriSchemeHttps : Uri.UriSchemeHttp; - + + // This is the actual url pointed to for all HTTP requests this.Endpoint = string.Format("{0}://{1}", scheme, host); this.uri = new Uri(this.Endpoint); + _validateEndpoint(); + + // Initialize a new REST client. This uri will be modified if region specific endpoint/virtual style request + // is decided upon while constructing a request for Amazon. + restClient = new RestSharp.RestClient(this.uri); + restClient.UserAgent = this.FullUserAgent; + + authenticator = new V4Authenticator(this.AccessKey, this.SecretKey); + restClient.Authenticator = authenticator; } - + /// - /// validates URI + /// Validates URI to check if it is well formed. Otherwise cry foul. /// - private void _validateUri() + private void _validateEndpoint() { + if (string.IsNullOrEmpty(this.BaseUrl)) + { + throw new InvalidEndpointException("Endpoint cannot be empty."); + } + string host = this.BaseUrl; + if (!this.isValidEndpoint(this.uri.Host)) { throw new InvalidEndpointException(this.Endpoint, "Invalid endpoint."); @@ -273,19 +294,19 @@ private void _validateUri() { throw new InvalidEndpointException(this.Endpoint, "Invalid scheme detected in endpoint."); } - string amzHost = this.uri.Host; + string amzHost = this.BaseUrl; if ((amzHost.EndsWith(".amazonaws.com", StringComparison.CurrentCultureIgnoreCase)) && !(amzHost.Equals("s3.amazonaws.com", StringComparison.CurrentCultureIgnoreCase))) - { - throw new InvalidEndpointException(this.Endpoint, "For Amazon S3, host should be \'s3.amazonaws.com\' in endpoint."); - } + { + throw new InvalidEndpointException(amzHost, "For Amazon S3, host should be \'s3.amazonaws.com\' in endpoint."); + } } /// /// Validate Url endpoint /// /// - /// + /// true/false private bool isValidEndpoint(string endpoint) { // endpoint may be a hostname @@ -316,7 +337,7 @@ private bool isValidEndpoint(string endpoint) } /// - ///Sets app version and name + ///Sets app version and name. Used by RestSharp for constructing User-Agent header in all HTTP requests /// /// /// @@ -331,47 +352,29 @@ public void SetAppInfo(string appName, string appVersion) { throw new ArgumentException("Appversion cannot be null or empty"); } - string customAgent = appName + "/" + appVersion; - - this.restClient.UserAgent = this.FullUserAgent; + this.CustomUserAgent = appName + "/" + appVersion; } /// /// Creates and returns an Cloud Storage client /// /// Location of the server, supports HTTP and HTTPS - /// Access Key for authenticated requests - /// Secret Key for authenticated requests - /// Client with the uri set as the server location and authentication parameters set. - + /// Access Key for authenticated requests (Optional,can be omitted for anonymous requests) + /// Secret Key for authenticated requests (Optional,can be omitted for anonymous requests) + /// Client initialized with user credentials public MinioClient(string endpoint, string accessKey = "", string secretKey = "") { this.Secure = false; + + // Save user entered credentials this.BaseUrl = endpoint; this.AccessKey = accessKey; this.SecretKey = secretKey; - this.s3AccelerateEndpoint = null; - this.regionCache = BucketRegionCache.Instance; - this.Anonymous = utils.isAnonymousClient(accessKey, secretKey); - _constructUri(); - _validateUri(); - - restClient = new RestSharp.RestClient(this.uri); - restClient.UserAgent = this.FullUserAgent; - authenticator = new V4Authenticator(accessKey, secretKey); - restClient.Authenticator = authenticator; - if (accessKey == "" || secretKey == "") - { - this.Anonymous = true; - } - else - { - this.Anonymous = false; - } + //Instantiate a region cache + this.regionCache = BucketRegionCache.Instance; - this.Api = new ClientApiOperations(this); return; } @@ -383,24 +386,35 @@ public MinioClient(string endpoint, string accessKey = "", string secretKey = "" public MinioClient WithSSL() { this.Secure = true; - _constructUri(); - this.restClient.BaseUrl = this.uri; return this; } internal async Task> ExecuteTaskAsync(IEnumerable errorHandlers, IRestRequest request) where T : new() { + DateTime startTime = DateTime.Now; var response = await this.restClient.ExecuteTaskAsync(request, CancellationToken.None); - HandleIfErrorResponse(response, errorHandlers); + HandleIfErrorResponse(response, errorHandlers, startTime); return response; } + /// + /// Actual doer that executes the REST request to the server + /// + /// List of handlers to override default handling + /// request + /// IRESTResponse internal async Task ExecuteTaskAsync(IEnumerable errorHandlers, IRestRequest request) { + DateTime startTime = DateTime.Now; + // Logs full url when HTTPtracing is enabled. + if (this.trace) + { + var fullUrl = this.restClient.BuildUri(request); + Console.Out.WriteLine("Full URL of Request", fullUrl); + } + var response = await this.restClient.ExecuteTaskAsync(request, CancellationToken.None); - var fullUrl = this.restClient.BuildUri(request); - Console.Out.WriteLine(fullUrl); - HandleIfErrorResponse(response, errorHandlers); + HandleIfErrorResponse(response, errorHandlers, startTime); return response; } @@ -408,7 +422,7 @@ internal async Task ExecuteTaskAsync(IEnumerable /// - internal void ParseError(IRestResponse response) + internal static void ParseError(IRestResponse response) { if (response == null) { @@ -451,8 +465,16 @@ internal void ParseError(IRestResponse response) if (pathLength > 1) { errorResponse.Code = "NoSuchKey"; + var bucketName = response.Request.Resource.Split('/')[0]; var objectName = response.Request.Resource.Split('/')[1]; - e = new ObjectNotFoundException(objectName, "Not found."); + if (objectName == "") + { + e = new BucketNotFoundException(bucketName, "Not found."); + } + else + { + e = new ObjectNotFoundException(objectName, "Not found."); + } } else if (pathLength == 1) { @@ -477,6 +499,15 @@ internal void ParseError(IRestResponse response) throw new InternalClientException("Unsuccessful response from server without XML error: " + response.StatusCode); } + if (response.StatusCode.Equals(HttpStatusCode.NotFound) && response.Request.Resource.EndsWith("?location") + && response.Request.Method.Equals(Method.GET)) + { + var bucketName = response.Request.Resource.Split('?')[0]; + BucketRegionCache.Instance.Remove(bucketName); + throw new BucketNotFoundException(bucketName, "Not found."); + } + + var contentBytes = System.Text.Encoding.UTF8.GetBytes(response.Content); var stream = new MemoryStream(contentBytes); ErrorResponse errResponse = (ErrorResponse)(new XmlSerializer(typeof(ErrorResponse)).Deserialize(stream)); @@ -491,19 +522,25 @@ internal void ParseError(IRestResponse response) /// /// /// - private void HandleIfErrorResponse(IRestResponse response, IEnumerable handlers) + private void HandleIfErrorResponse(IRestResponse response, IEnumerable handlers, DateTime startTime) { - LogRequest(response.Request, response, 10); + //Logs Response if HTTP tracing is enabled + if (this.trace) + { + DateTime now = DateTime.Now; + LogRequest(response.Request, response, (now - startTime).TotalMilliseconds); + } if (handlers == null) { throw new ArgumentNullException(nameof(handlers)); } - + // Runs through handlers passed to take up error handling foreach (var handler in handlers) { handler(response); } + //Fall back default error handler _defaultErrorHandlingDelegate(response); } /// @@ -520,7 +557,14 @@ public void SetTraceOff() { this.trace = false; } - private void LogRequest(IRestRequest request, IRestResponse response, long durationMs) + + /// + /// Logs the request sent to server and corresponding response + /// + /// + /// + /// + private void LogRequest(IRestRequest request, IRestResponse response, double durationMs) { var requestToLog = new { @@ -551,11 +595,11 @@ private void LogRequest(IRestRequest request, IRestResponse response, long durat Console.Out.WriteLine(string.Format("Request completed in {0} ms, Request: {1}, Response: {2}", durationMs, - JsonConvert.SerializeObject(requestToLog,Formatting.Indented), - JsonConvert.SerializeObject(responseToLog,Formatting.Indented))); + JsonConvert.SerializeObject(requestToLog, Formatting.Indented), + JsonConvert.SerializeObject(responseToLog, Formatting.Indented))); } } internal delegate void ApiResponseErrorHandlingDelegate(IRestResponse response); - + } diff --git a/Minio.Api/Regions.cs b/Minio.Api/Regions.cs index b20536e3c..c29f0d390 100644 --- a/Minio.Api/Regions.cs +++ b/Minio.Api/Regions.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.Api/V4Authenticator.cs b/Minio.Api/V4Authenticator.cs index b51f6c905..500a2fcdb 100644 --- a/Minio.Api/V4Authenticator.cs +++ b/Minio.Api/V4Authenticator.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -106,6 +106,7 @@ public void Authenticate(IRestClient client, IRestRequest request) string authorization = GetAuthorizationHeader(signedHeaders, signature, signingDate, region); request.AddHeader("Authorization", authorization); + } @@ -397,7 +398,7 @@ private SortedDictionary GetHeadersToSign(IRestRequest request) { string headerName = header.Name.ToLower(); string headerValue = header.Value.ToString(); - if (!ignoredHeaders.Contains(headerName)) + if (!ignoredHeaders.Contains(headerName)) { sortedHeaders.Add(headerName, headerValue); } diff --git a/Minio.Api/packages.config b/Minio.Api/packages.config index da2abe5ea..716b87e16 100644 --- a/Minio.Api/packages.config +++ b/Minio.Api/packages.config @@ -1,11 +1,13 @@  + - + + \ No newline at end of file diff --git a/Minio.Examples/Cases/BucketExists.cs b/Minio.Examples/Cases/BucketExists.cs index b47b8d8b4..5a40752a5 100644 --- a/Minio.Examples/Cases/BucketExists.cs +++ b/Minio.Examples/Cases/BucketExists.cs @@ -1,7 +1,20 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; using System.Threading.Tasks; namespace Minio.Examples.Cases @@ -14,7 +27,7 @@ public async static Task Run(Minio.MinioClient minio, { try { - bool found = await minio.Api.BucketExistsAsync(bucketName); + bool found = await minio.BucketExistsAsync(bucketName); Console.Out.WriteLine("bucket-name was " + ((found == true) ? "found" : "not found")); } catch (Exception e) diff --git a/Minio.Examples/Cases/CopyObject.cs b/Minio.Examples/Cases/CopyObject.cs index b623ee213..c74a1f121 100644 --- a/Minio.Examples/Cases/CopyObject.cs +++ b/Minio.Examples/Cases/CopyObject.cs @@ -1,7 +1,20 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; using System.Threading.Tasks; namespace Minio.Examples.Cases @@ -18,7 +31,7 @@ public async static Task Run(Minio.MinioClient minio, try { //Optionally pass copy conditions - await minio.Api.CopyObjectAsync(fromBucketName, + await minio.CopyObjectAsync(fromBucketName, fromObjectName, destBucketName, destObjectName, diff --git a/Minio.Examples/Cases/FGetObject.cs b/Minio.Examples/Cases/FGetObject.cs index 6166e4375..d037d97e9 100644 --- a/Minio.Examples/Cases/FGetObject.cs +++ b/Minio.Examples/Cases/FGetObject.cs @@ -1,7 +1,20 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; using System.Threading.Tasks; namespace Minio.Examples.Cases @@ -16,7 +29,7 @@ public async static Task Run(Minio.MinioClient minio, { try { - await minio.Api.GetObjectAsync(bucketName, objectName, fileName); + await minio.GetObjectAsync(bucketName, objectName, fileName); } catch (Exception e) diff --git a/Minio.Examples/Cases/FPutObject.cs b/Minio.Examples/Cases/FPutObject.cs index ddbba227c..ba83381a0 100644 --- a/Minio.Examples/Cases/FPutObject.cs +++ b/Minio.Examples/Cases/FPutObject.cs @@ -1,7 +1,20 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; using System.Threading.Tasks; namespace Minio.Examples.Cases @@ -17,7 +30,7 @@ public async static Task Run(Minio.MinioClient minio, { try { - await minio.Api.PutObjectAsync(bucketName, + await minio.PutObjectAsync(bucketName, objectName, fileName, contentType: "application/octet-stream"); diff --git a/Minio.Examples/Cases/GetBucketPolicy.cs b/Minio.Examples/Cases/GetBucketPolicy.cs index 3f169777f..83153a7ee 100644 --- a/Minio.Examples/Cases/GetBucketPolicy.cs +++ b/Minio.Examples/Cases/GetBucketPolicy.cs @@ -1,9 +1,23 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; using System.Threading.Tasks; using Minio.DataModel; + namespace Minio.Examples.Cases { class GetBucketPolicy @@ -15,7 +29,7 @@ public async static Task Run(Minio.MinioClient minio, { try { - PolicyType policy = await minio.Api.GetPolicyAsync(bucketName,objectPrefix:prefix); + PolicyType policy = await minio.GetPolicyAsync(bucketName,objectPrefix:prefix); Console.Out.WriteLine("POLICY: " + policy.GetType().ToString()); } catch (Exception e) diff --git a/Minio.Examples/Cases/GetObject.cs b/Minio.Examples/Cases/GetObject.cs index c030603ad..9190c36f5 100644 --- a/Minio.Examples/Cases/GetObject.cs +++ b/Minio.Examples/Cases/GetObject.cs @@ -1,10 +1,22 @@ -using System; -using System.IO; -using System.Collections.Generic; -using System.Linq; -using System.Text; +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; using System.Threading.Tasks; -using System.Net; + namespace Minio.Examples.Cases { class GetObject @@ -16,7 +28,7 @@ public async static Task Run(Minio.MinioClient minio, { try { - await minio.Api.GetObjectAsync(bucketName, objectName, + await minio.GetObjectAsync(bucketName, objectName, (stream) => { stream.CopyTo(Console.OpenStandardOutput()); diff --git a/Minio.Examples/Cases/ListBuckets.cs b/Minio.Examples/Cases/ListBuckets.cs index 1d2c14066..bce2ebdaa 100644 --- a/Minio.Examples/Cases/ListBuckets.cs +++ b/Minio.Examples/Cases/ListBuckets.cs @@ -1,4 +1,20 @@ -using System; +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; using System.Threading.Tasks; using Minio.DataModel; @@ -11,7 +27,7 @@ public async static Task Run(Minio.MinioClient minio) { try { - var list = await minio.Api.ListBucketsAsync(); + var list = await minio.ListBucketsAsync(); foreach (Bucket bucket in list.Buckets) { Console.Out.WriteLine(bucket.Name + " " + bucket.CreationDateDateTime); diff --git a/Minio.Examples/Cases/ListIncompleteUploads.cs b/Minio.Examples/Cases/ListIncompleteUploads.cs index 590ed4600..b99ff3ed5 100644 --- a/Minio.Examples/Cases/ListIncompleteUploads.cs +++ b/Minio.Examples/Cases/ListIncompleteUploads.cs @@ -1,4 +1,20 @@ -using Minio.DataModel; +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using Minio.DataModel; using System; @@ -14,7 +30,7 @@ public static void Run(Minio.MinioClient minio, { try { - IObservable observable = minio.Api.ListIncompleteUploads(bucketName, prefix, recursive); + IObservable observable = minio.ListIncompleteUploads(bucketName, prefix, recursive); IDisposable subscription = observable.Subscribe( item => Console.WriteLine("OnNext: {0}", item.Key), diff --git a/Minio.Examples/Cases/ListObjects.cs b/Minio.Examples/Cases/ListObjects.cs index fdb21513b..3183a8fb4 100644 --- a/Minio.Examples/Cases/ListObjects.cs +++ b/Minio.Examples/Cases/ListObjects.cs @@ -1,4 +1,20 @@ -using System; +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; using Minio.DataModel; namespace Minio.Examples.Cases @@ -14,20 +30,16 @@ public static void Run(Minio.MinioClient minio, { try { - bucketName = "mountshasta"; - prefix = null; - - /* IObservable observable = minio.Buckets.ListObjectsAsync(bucketName, prefix, recursive); - IObservable observable = minio.Api.ListObjectsAsync(bucketName, prefix, recursive); + IObservable observable = minio.ListObjectsAsync(bucketName, prefix, recursive); IDisposable subscription = observable.Subscribe( item => Console.WriteLine("OnNext: {0}", item.Key), - ex => Console.WriteLine("OnError: {0}", ex.Message), + ex => Console.WriteLine("OnError: {0}", ex), () => Console.WriteLine("OnComplete: {0}")); - */ + // subscription.Dispose(); } catch (Exception e) @@ -37,3 +49,4 @@ public static void Run(Minio.MinioClient minio, } } } + diff --git a/Minio.Examples/Cases/MakeBucket.cs b/Minio.Examples/Cases/MakeBucket.cs index a62dc3abb..cce7410c7 100644 --- a/Minio.Examples/Cases/MakeBucket.cs +++ b/Minio.Examples/Cases/MakeBucket.cs @@ -1,4 +1,20 @@ -using System; +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; using System.Threading.Tasks; namespace Minio.Examples.Cases @@ -11,7 +27,7 @@ public async static Task Run(Minio.MinioClient minio, { try { - await minio.Api.MakeBucketAsync(bucketName); + await minio.MakeBucketAsync(bucketName); Console.Out.WriteLine("bucket-name created successfully"); } catch (Exception e) diff --git a/Minio.Examples/Cases/PresignedGetObject.cs b/Minio.Examples/Cases/PresignedGetObject.cs index 061fc0f6b..054142eaa 100644 --- a/Minio.Examples/Cases/PresignedGetObject.cs +++ b/Minio.Examples/Cases/PresignedGetObject.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,23 +15,14 @@ */ using System; -using Minio; namespace Minio.Examples.Cases { public class PresignedGetObject { - public static int Run() + public static int Run(MinioClient client) { - /// Note: s3 AccessKey and SecretKey needs to be added in App.config file - /// See instructions in README.md on running examples for more information. - var client = new MinioClient( - Environment.GetEnvironmentVariable("AWS_ENDPOINT"), - Environment.GetEnvironmentVariable("AWS_ACCESS_KEY"), - Environment.GetEnvironmentVariable("AWS_SECRET_KEY") - ).WithSSL(); - - Console.Out.WriteLine(client.Api.PresignedGetObject("my-bucketname", "my-objectname", 1000)); + Console.Out.WriteLine(client.PresignedGetObject("my-bucketname", "my-objectname", 1000)); return 0; } } diff --git a/Minio.Examples/Cases/PresignedPostPolicy.cs b/Minio.Examples/Cases/PresignedPostPolicy.cs index cf34b9e31..2c2e601a4 100644 --- a/Minio.Examples/Cases/PresignedPostPolicy.cs +++ b/Minio.Examples/Cases/PresignedPostPolicy.cs @@ -1,31 +1,36 @@ -using Minio.DataModel; +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using Minio.DataModel; using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Minio.Examples.Cases { public class PresignedPostPolicy { - public static int Run() + public static int Run(MinioClient client) { - /// Note: s3 AccessKey and SecretKey needs to be added in App.config file - /// See instructions in README.md on running examples for more information. - var client = new MinioClient( - Environment.GetEnvironmentVariable("AWS_ENDPOINT"), - Environment.GetEnvironmentVariable("AWS_ACCESS_KEY"), - Environment.GetEnvironmentVariable("AWS_SECRET_KEY") - ).WithSSL(); - PostPolicy form = new PostPolicy(); DateTime expiration = DateTime.UtcNow; form.SetExpires(expiration.AddDays(10)); form.SetKey("my-objectname"); form.SetBucket("my-bucketname"); - Dictionary formData = client.Api.PresignedPostPolicy(form); + Dictionary formData = client.PresignedPostPolicy(form); string curlCommand = "curl "; foreach (KeyValuePair pair in formData) { diff --git a/Minio.Examples/Cases/PresignedPutObject.cs b/Minio.Examples/Cases/PresignedPutObject.cs index 3267fc098..3c707a62b 100644 --- a/Minio.Examples/Cases/PresignedPutObject.cs +++ b/Minio.Examples/Cases/PresignedPutObject.cs @@ -1,24 +1,28 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; namespace Minio.Examples.Cases { public class PresignedPutObject { - public static int Run() + public static int Run(MinioClient client) { - /// Note: s3 AccessKey and SecretKey needs to be added in App.config file - /// See instructions in README.md on running examples for more information. - var client = new MinioClient( - Environment.GetEnvironmentVariable("AWS_ENDPOINT"), - Environment.GetEnvironmentVariable("AWS_ACCESS_KEY"), - Environment.GetEnvironmentVariable("AWS_SECRET_KEY") - ).WithSSL(); - - Console.Out.WriteLine(client.Api.PresignedPutObject("my-bucketname", "my-objectname", 1000)); + Console.Out.WriteLine(client.PresignedPutObject("my-bucketname", "my-objectname", 1000)); return 0; } } diff --git a/Minio.Examples/Cases/PutObject.cs b/Minio.Examples/Cases/PutObject.cs index f6c822bad..47034f7b0 100644 --- a/Minio.Examples/Cases/PutObject.cs +++ b/Minio.Examples/Cases/PutObject.cs @@ -1,4 +1,20 @@ -using System; +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; using System.IO; using System.Threading.Tasks; @@ -17,7 +33,7 @@ public async static Task Run(Minio.MinioClient minio, byte[] bs = File.ReadAllBytes(fileName); System.IO.MemoryStream filestream = new System.IO.MemoryStream(bs); - await minio.Api.PutObjectAsync(bucketName, + await minio.PutObjectAsync(bucketName, objectName, filestream, filestream.Length, diff --git a/Minio.Examples/Cases/RemoveBucket.cs b/Minio.Examples/Cases/RemoveBucket.cs index 335175682..e8961af6a 100644 --- a/Minio.Examples/Cases/RemoveBucket.cs +++ b/Minio.Examples/Cases/RemoveBucket.cs @@ -1,4 +1,20 @@ -using System; +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; using System.Threading.Tasks; namespace Minio.Examples.Cases @@ -11,7 +27,7 @@ public async static Task Run(MinioClient minio, { try { - await minio.Api.RemoveBucketAsync(bucketName); + await minio.RemoveBucketAsync(bucketName); Console.Out.WriteLine("bucket-name removed successfully"); } catch (Exception e) diff --git a/Minio.Examples/Cases/RemoveIncompleteUpload.cs b/Minio.Examples/Cases/RemoveIncompleteUpload.cs index 9b0bac331..29a3d467a 100644 --- a/Minio.Examples/Cases/RemoveIncompleteUpload.cs +++ b/Minio.Examples/Cases/RemoveIncompleteUpload.cs @@ -1,4 +1,20 @@ -using System; +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; using System.Threading.Tasks; namespace Minio.Examples.Cases @@ -13,7 +29,7 @@ public async static Task Run(MinioClient minio, { try { - await minio.Api.RemoveIncompleteUploadAsync(bucketName, objectName); + await minio.RemoveIncompleteUploadAsync(bucketName, objectName); Console.Out.WriteLine("object-name removed from bucket-name successfully"); } catch (Exception e) diff --git a/Minio.Examples/Cases/RemoveObject.cs b/Minio.Examples/Cases/RemoveObject.cs index 78ce4eb8a..3ca0a2764 100644 --- a/Minio.Examples/Cases/RemoveObject.cs +++ b/Minio.Examples/Cases/RemoveObject.cs @@ -1,4 +1,20 @@ -using System; +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; using System.Threading.Tasks; namespace Minio.Examples.Cases @@ -12,7 +28,7 @@ public async static Task Run(MinioClient minio, { try { - await minio.Api.RemoveObjectAsync(bucketName,objectName); + await minio.RemoveObjectAsync(bucketName,objectName); Console.Out.WriteLine("object-name removed from bucket-name successfully"); } catch (Exception e) diff --git a/Minio.Examples/Cases/SetBucketPolicy.cs b/Minio.Examples/Cases/SetBucketPolicy.cs index a08a11d6e..0d343964c 100644 --- a/Minio.Examples/Cases/SetBucketPolicy.cs +++ b/Minio.Examples/Cases/SetBucketPolicy.cs @@ -1,4 +1,20 @@ -using System; +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; using System.Threading.Tasks; using Minio.DataModel; @@ -14,7 +30,7 @@ public async static Task Run(Minio.MinioClient minio, try { //Change policy type parameter - await minio.Api.SetPolicyAsync(bucketName, + await minio.SetPolicyAsync(bucketName, objectPrefix, PolicyType.READ_ONLY); diff --git a/Minio.Examples/Cases/StatObject.cs b/Minio.Examples/Cases/StatObject.cs index 5b5b8d391..76a9ef3ee 100644 --- a/Minio.Examples/Cases/StatObject.cs +++ b/Minio.Examples/Cases/StatObject.cs @@ -1,4 +1,20 @@ -using System; +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; using System.Threading.Tasks; using Minio.DataModel; @@ -13,7 +29,7 @@ public async static Task Run(Minio.MinioClient minio, { try { - ObjectStat statObject = await minio.Api.StatObjectAsync(bucketName, bucketObject); + ObjectStat statObject = await minio.StatObjectAsync(bucketName, bucketObject); Console.Out.WriteLine(statObject); } catch (Exception e) diff --git a/Minio.Examples/Minio.Examples.csproj b/Minio.Examples/Minio.Examples.csproj index 427642689..e99b3b718 100644 --- a/Minio.Examples/Minio.Examples.csproj +++ b/Minio.Examples/Minio.Examples.csproj @@ -38,6 +38,7 @@ True + ..\packages\System.Reactive.Core.3.1.1\lib\net45\System.Reactive.Core.dll @@ -51,12 +52,15 @@ ..\packages\System.Reactive.Linq.3.1.1\lib\net45\System.Reactive.Linq.dll True - + + ..\packages\System.Xml.Linq.3.5.21022.801\lib\net20\System.Xml.Linq.dll + True + diff --git a/Minio.Examples/Program.cs b/Minio.Examples/Program.cs index 55f4a7007..de0983eb3 100644 --- a/Minio.Examples/Program.cs +++ b/Minio.Examples/Program.cs @@ -1,4 +1,20 @@ -using System; +/* +* Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; using System.Net; using Minio.Exceptions; @@ -8,62 +24,67 @@ class Program { public static void Main(string[] args) { - /* - * Uncomment to use Play minio server + // * Uncomment to use Play minio server + /* var minioClient = new Minio.MinioClient("play.minio.io:9000", "Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG" ).WithSSL(); */ + ServicePointManager.Expect100Continue = true; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; - - var endPoint = Environment.GetEnvironmentVariable("AWS_ENDPOINT"); - var accessKey = Environment.GetEnvironmentVariable("AWS_ACCESS_KEY"); - var secretKey = Environment.GetEnvironmentVariable("AWS_SECRET_KEY"); + var endPoint = Environment.GetEnvironmentVariable("AWS_ENDPOINT"); + var accessKey = Environment.GetEnvironmentVariable("MY_AWS_ACCESS_KEY"); + var secretKey = Environment.GetEnvironmentVariable("MY_AWS_SECRET_KEY"); + var minioClient = new MinioClient(endPoint, - accessKey: accessKey, + accessKey: accessKey, secretKey: secretKey).WithSSL(); + try { // Change these parameters before running examples - string bucketName = "sanfrancisco"; - string objectName = "goldengate_pic"; - string objectPrefix = "gold"; - string smallFilePath = "C:\\Users\\vagrant\\Downloads\\hello.txt"; - string uploadFilePath = "C:\\Users\\vagrant\\Downloads\\go1.7.4.windows-amd64.msi"; + string bucketName = "testminiopolicy"; + string objectName = "goldengate.jpg"; + string objectPrefix = "gold"; + string smallFilePath = "C:\\Users\\vagrant\\Downloads\\hellotext"; + string uploadFilePath = "C:\\Users\\vagrant\\Downloads\\go1.7.4.windows-amd64.msi"; string downloadFilePath = "C:\\Users\\vagrant\\Downloads\\downloaded-object"; - string destBucketName = "backup_folder"; - string destObjectName = "goldengate_copy"; - string removeObject = "goldengate_pic"; - + string destBucketName = "testminiopoli"; + string destObjectName = "goldengate_copy.jpg"; + string removeObject = "goldengate_pic"; + // Set app Info minioClient.SetAppInfo("app-name", "app-version"); - + // Set HTTP Tracing On minioClient.SetTraceOn(); - // Set HTTP Tracing On - minioClient.SetTraceOff(); + // Set HTTP Tracing Off + // minioClient.SetTraceOff(); //* UNCOMMENT CASE TO RUN A TEST - //Cases.MakeBucket.Run(minioClient, bucketName).Wait(); //Cases.BucketExists.Run(minioClient, bucketName).Wait(); - //Cases.ListBuckets.Run(minioClient).Wait(); + + //Cases.MakeBucket.Run(minioClient, bucketName).Wait(); + + Cases.ListBuckets.Run(minioClient).Wait(); //Cases.ListObjects.Run(minioClient, bucketName); //Cases.PutObject.Run(minioClient, bucketName, objectName, smallFilePath).Wait(); - //Cases.GetObject.Run(minioClient, bucketName, objectName).Wait(); - //Cases.FPutObject.Run(minioClient, bucketName, objectName,uploadFilePath).Wait(); + Cases.GetObject.Run(minioClient, bucketName, objectName).Wait(); + //Cases.FPutObject.Run(minioClient, bucketName, objectName, uploadFilePath).Wait(); - //Cases.FGetObject.Run(minioClient, bucketName, objectName,downloadFilePath).Wait(); + //Cases.FGetObject.Run(minioClient, bucketName, objectName, downloadFilePath).Wait(); + //Cases.RemoveObject.Run(minioClient, bucketName, objectName).Wait(); //Cases.RemoveBucket.Run(minioClient, bucketName).Wait(); - //Cases.ListIncompleteUploads.Run(minioClient, bucketName, prefix:objectPrefix); + //Cases.ListIncompleteUploads.Run(minioClient, bucketName, prefix: objectPrefix); //Cases.RemoveIncompleteUpload.Run(minioClient, bucketName, removeObject).Wait(); //Cases.GetBucketPolicy.Run(minioClient, bucketName).Wait(); @@ -71,17 +92,17 @@ public static void Main(string[] args) //Cases.SetBucketPolicy.Run(minioClient, bucketName).Wait(); //Cases.StatObject.Run(minioClient, bucketName, objectName).Wait(); //Cases.CopyObject.Run(minioClient, bucketName, objectName, destBucketName, destObjectName).Wait(); - // Cases.PresignedGetObject.Run(); - // Cases.PresignedPostPolicy.Run(); - // Cases.PresignedPutObject.Run(); + //Cases.PresignedGetObject.Run(minioClient); + //Cases.PresignedPostPolicy.Run(minioClient); + //Cases.PresignedPutObject.Run(minioClient); Console.ReadLine(); } - catch(MinioException ex) + catch (MinioException ex) { Console.Out.WriteLine(ex.Message); } - + } } diff --git a/Minio.Examples/packages.config b/Minio.Examples/packages.config index 2a448fa25..c58ffc64a 100644 --- a/Minio.Examples/packages.config +++ b/Minio.Examples/packages.config @@ -4,4 +4,6 @@ + + \ No newline at end of file diff --git a/Minio.Tests/Minio.Tests.csproj b/Minio.Tests/Minio.Tests.csproj index 6770fc8d4..2f54a75f2 100644 --- a/Minio.Tests/Minio.Tests.csproj +++ b/Minio.Tests/Minio.Tests.csproj @@ -56,15 +56,15 @@ + + + - {cc30cade-342a-4ced-858d-b60200c075b0} + {CC30CADE-342A-4CED-858D-B60200C075B0} MinioApi - - - diff --git a/Minio.Tests/UnitTest1.cs b/Minio.Tests/UnitTest1.cs index 9729d5a01..f7472e0d8 100644 --- a/Minio.Tests/UnitTest1.cs +++ b/Minio.Tests/UnitTest1.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Minio.sln b/Minio.sln index 2e00ddd9f..f7ce85bef 100644 --- a/Minio.sln +++ b/Minio.sln @@ -3,10 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MinioApi", "Minio.Api\MinioApi.csproj", "{CC30CADE-342A-4CED-858D-B60200C075B0}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleTest", "SimpleTest\SimpleTest.csproj", "{AF2DF297-402B-46B8-8954-C5A934967A51}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C8111804-63DA-4E74-9C1F-FEC46632A33B}" ProjectSection(SolutionItems) = preProject README.md = README.md @@ -23,20 +19,20 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{30E4FEE3-B API.md = API.md EndProjectSection EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MinioCoreTest", "MinioCoreTest\MinioCoreTest.xproj", "{64264A30-E6AB-49D8-8F84-3AE4FAC54E09}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MinioCore2", "MinioCore2\MinioCore2.xproj", "{C7579CAD-6D2A-45E0-8737-8E66C78EBE2F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MinioApi", "Minio.Api\MinioApi.csproj", "{CC30CADE-342A-4CED-858D-B60200C075B0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleTest2", "SimpleTest2\SimpleTest2.csproj", "{1BC68272-97B9-4CFC-84AC-1C6365273A94}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {CC30CADE-342A-4CED-858D-B60200C075B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CC30CADE-342A-4CED-858D-B60200C075B0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CC30CADE-342A-4CED-858D-B60200C075B0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CC30CADE-342A-4CED-858D-B60200C075B0}.Release|Any CPU.Build.0 = Release|Any CPU - {AF2DF297-402B-46B8-8954-C5A934967A51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AF2DF297-402B-46B8-8954-C5A934967A51}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AF2DF297-402B-46B8-8954-C5A934967A51}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AF2DF297-402B-46B8-8954-C5A934967A51}.Release|Any CPU.Build.0 = Release|Any CPU {04E6286A-50DA-444B-B663-6D7386D4CC4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {04E6286A-50DA-444B-B663-6D7386D4CC4A}.Debug|Any CPU.Build.0 = Debug|Any CPU {04E6286A-50DA-444B-B663-6D7386D4CC4A}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -49,6 +45,22 @@ Global {040B2A3E-8003-4460-80CF-6262DDDAE89D}.Debug|Any CPU.Build.0 = Debug|Any CPU {040B2A3E-8003-4460-80CF-6262DDDAE89D}.Release|Any CPU.ActiveCfg = Release|Any CPU {040B2A3E-8003-4460-80CF-6262DDDAE89D}.Release|Any CPU.Build.0 = Release|Any CPU + {64264A30-E6AB-49D8-8F84-3AE4FAC54E09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {64264A30-E6AB-49D8-8F84-3AE4FAC54E09}.Debug|Any CPU.Build.0 = Debug|Any CPU + {64264A30-E6AB-49D8-8F84-3AE4FAC54E09}.Release|Any CPU.ActiveCfg = Release|Any CPU + {64264A30-E6AB-49D8-8F84-3AE4FAC54E09}.Release|Any CPU.Build.0 = Release|Any CPU + {C7579CAD-6D2A-45E0-8737-8E66C78EBE2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C7579CAD-6D2A-45E0-8737-8E66C78EBE2F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C7579CAD-6D2A-45E0-8737-8E66C78EBE2F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C7579CAD-6D2A-45E0-8737-8E66C78EBE2F}.Release|Any CPU.Build.0 = Release|Any CPU + {CC30CADE-342A-4CED-858D-B60200C075B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CC30CADE-342A-4CED-858D-B60200C075B0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CC30CADE-342A-4CED-858D-B60200C075B0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CC30CADE-342A-4CED-858D-B60200C075B0}.Release|Any CPU.Build.0 = Release|Any CPU + {1BC68272-97B9-4CFC-84AC-1C6365273A94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1BC68272-97B9-4CFC-84AC-1C6365273A94}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1BC68272-97B9-4CFC-84AC-1C6365273A94}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1BC68272-97B9-4CFC-84AC-1C6365273A94}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/MinioCore2/AWSS3Endpoints.cs b/MinioCore2/AWSS3Endpoints.cs new file mode 100644 index 000000000..10dc5a6c6 --- /dev/null +++ b/MinioCore2/AWSS3Endpoints.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Concurrent; + +namespace MinioCore2 +{ + + /** + * Amazon AWS S3 endpoints for various regions. + */ + public sealed class AWSS3Endpoints + { + private static readonly Lazy lazy = + new Lazy(() => new AWSS3Endpoints()); + + private ConcurrentDictionary endpoints; + + public static AWSS3Endpoints Instance + { + get { return lazy.Value; } + } + private AWSS3Endpoints() + { + endpoints = new ConcurrentDictionary(); + // ap-northeast-1 + endpoints.TryAdd("ap-northeast-1", "s3-ap-northeast-1.amazonaws.com"); + // ap-northeast-2 + endpoints.TryAdd("ap-northeast-2", "s3-ap-northeast-2.amazonaws.com"); + //ap-south-1 + endpoints.TryAdd("ap-south-1", "s3-ap-south-1.amazonaws.com"); + // ap-southeast-1 + endpoints.TryAdd("ap-southeast-1", "s3-ap-southeast-1.amazonaws.com"); + // ap-southeast-2 + endpoints.TryAdd("ap-southeast-2", "s3-ap-southeast-2.amazonaws.com"); + // eu-central-1 + endpoints.TryAdd("eu-central-1", "s3-eu-central-1.amazonaws.com"); + // eu-west-1 + endpoints.TryAdd("eu-west-1", "s3-eu-west-1.amazonaws.com"); + // eu-west-2 + endpoints.TryAdd("eu-west-2", "s3-eu-west-2.amazonaws.com"); + // sa-east-1 + endpoints.TryAdd("sa-east-1", "s3-sa-east-1.amazonaws.com"); + // us-west-1 + endpoints.TryAdd("us-west-1", "s3-us-west-1.amazonaws.com"); + // us-west-2 + endpoints.TryAdd("us-west-2", "s3-us-west-2.amazonaws.com"); + // us-east-1 + endpoints.TryAdd("us-east-1", "s3.amazonaws.com"); + // us-east-2 + endpoints.TryAdd("us-east-2", "s3-us-east-2.amazonaws.com"); + //ca-central-1 + endpoints.TryAdd("ca-central-1", "s3.ca-central-1.amazonaws.com"); + // cn-north-1 + endpoints.TryAdd("cn-north-1", "s3.cn-north-1.amazonaws.com.cn"); + } + + /** + * Gets Amazon S3 endpoint for the relevant region. + */ + public string endpoint(string region) + { + + string endpoint = null; + if (region != null) + { + AWSS3Endpoints.Instance.endpoints.TryGetValue(region, out endpoint); + } + if (endpoint == null) + { + endpoint = "s3.amazonaws.com"; + } + return endpoint; + } + + } +} diff --git a/MinioCore2/ApiEndpoints/BucketOperations.cs b/MinioCore2/ApiEndpoints/BucketOperations.cs new file mode 100644 index 000000000..e798cbb8c --- /dev/null +++ b/MinioCore2/ApiEndpoints/BucketOperations.cs @@ -0,0 +1,307 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Collections.Generic; +using System.Net; +using System.Threading.Tasks; +using MinioCore2.DataModel; +using RestSharp; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using System.Xml.Serialization; +using MinioCore2.Exceptions; +using System.Globalization; +using System.Reactive.Linq; + +namespace MinioCore2 +{ + public partial class MinioClient : IBucketOperations + { + + /// + /// List all objects in a bucket + /// + /// Bucket to list objects from + /// An iterator lazily populated with objects + public async Task ListBucketsAsync() + { + // Initialize a new client + PrepareClient(); + + var request = new RestRequest("/", Method.GET); + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + + ListAllMyBucketsResult bucketList = new ListAllMyBucketsResult(); + if (HttpStatusCode.OK.Equals(response.StatusCode)) + { + var contentBytes = System.Text.Encoding.UTF8.GetBytes(response.Content); + var stream = new MemoryStream(contentBytes); + bucketList = (ListAllMyBucketsResult)(new XmlSerializer(typeof(ListAllMyBucketsResult)).Deserialize(stream)); + return bucketList; + + } + + return bucketList; + + } + + /// + /// Create a private bucket with the given name. + /// + /// Name of the new bucket + public async Task MakeBucketAsync(string bucketName, string location = "us-east-1") + { + // Initialize a new client + PrepareClient(); + + var request = new RestRequest("/" + bucketName, Method.PUT); + // ``us-east-1`` is not a valid location constraint according to amazon, so we skip it. + if (location != "us-east-1") + { + CreateBucketConfiguration config = new CreateBucketConfiguration(location); + request.AddBody(config); + } + + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + + } + + + /// + /// Returns true if the specified bucketName exists, otherwise returns false. + /// + /// Bucket to test existence of + /// true if exists and user has access + public async Task BucketExistsAsync(string bucketName) + { + try + { + var request = await this.CreateRequest(Method.HEAD, + bucketName,region:"us-east-1"); + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + } + catch (Exception ex) + { + if (ex.GetType() == typeof(BucketNotFoundException)) + { + return false; + } + throw ex; + } + return true; + } + + /// + /// Remove a bucket + /// + /// Name of bucket to remove + public async Task RemoveBucketAsync(string bucketName) + { + var request = await this.CreateRequest(Method.DELETE, bucketName, resourcePath: "/"); + + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + + } + + /// + /// 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 + /// An observable of items that client can subscribe to + public IObservable ListObjectsAsync(string bucketName, string prefix = null, bool recursive = true) + { + return Observable.Create( + async obs => + { + bool isRunning = true; + string marker = null; + while (isRunning) + { + Tuple> result = await GetObjectListAsync(bucketName, prefix, recursive, marker); + Item lastItem = null; + foreach (Item item in result.Item2) + { + lastItem = item; + obs.OnNext(item); + } + if (result.Item1.NextMarker != null) + { + marker = result.Item1.NextMarker; + } + else if (lastItem != null) + { + marker = lastItem.Key; + } + isRunning = result.Item1.IsTruncated; + } + }); + } + + /// + /// 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 + /// marks location in the iterator sequence + /// A tuple populated with objects + private async Task>> GetObjectListAsync(string bucketName, string prefix, bool recursive, string marker) + { + var queries = new List(); + if (!recursive) + { + queries.Add("delimiter=%2F"); + } + if (prefix != null) + { + queries.Add("prefix=" + Uri.EscapeDataString(prefix)); + } + if (marker != null) + { + queries.Add("marker=" + Uri.EscapeDataString(marker)); + } + queries.Add("max-keys=1000"); + string query = string.Join("&", queries); + + string path = bucketName; + if (query.Length > 0) + { + path += "?" + query; + } + + var request = await this.CreateRequest(Method.GET, + bucketName, + resourcePath: "?" + query); + + + + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + + var contentBytes = System.Text.Encoding.UTF8.GetBytes(response.Content); + var stream = new MemoryStream(contentBytes); + ListBucketResult listBucketResult = (ListBucketResult)(new XmlSerializer(typeof(ListBucketResult)).Deserialize(stream)); + + XDocument root = XDocument.Parse(response.Content); + + var items = (from c in root.Root.Descendants("{http://s3.amazonaws.com/doc/2006-03-01/}Contents") + select new Item() + { + Key = c.Element("{http://s3.amazonaws.com/doc/2006-03-01/}Key").Value, + LastModified = c.Element("{http://s3.amazonaws.com/doc/2006-03-01/}LastModified").Value, + ETag = c.Element("{http://s3.amazonaws.com/doc/2006-03-01/}ETag").Value, + Size = UInt64.Parse(c.Element("{http://s3.amazonaws.com/doc/2006-03-01/}Size").Value, CultureInfo.CurrentCulture), + IsDir = false + }); + + var prefixes = (from c in root.Root.Descendants("{http://s3.amazonaws.com/doc/2006-03-01/}CommonPrefixes") + select new Item() + { + Key = c.Element("{http://s3.amazonaws.com/doc/2006-03-01/}Prefix").Value, + IsDir = true + }); + + items = items.Concat(prefixes); + + return new Tuple>(listBucketResult, items.ToList()); + } + + /// + /// Returns current policy stored on the server for this bucket + /// + /// Bucket name. + /// Returns the Bucket policy + private async Task GetPolicyAsync(string bucketName) + { + BucketPolicy policy = null; + IRestResponse response = null; + + var path = bucketName + "?policy"; + + var request = await this.CreateRequest(Method.GET, bucketName, + contentType: "application/json", + resourcePath: "?policy"); + response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + + var contentBytes = System.Text.Encoding.UTF8.GetBytes(response.Content); + var stream = new MemoryStream(contentBytes); + policy = BucketPolicy.parseJson(stream, bucketName); + if (policy == null) + { + policy = new BucketPolicy(bucketName); + } + + return policy; + } + + + /// + /// Get bucket policy at given objectPrefix + /// + /// Bucket name. + /// Name of the object prefix + /// Returns the PolicyType + public async Task GetPolicyAsync(string bucketName, string objectPrefix = "") + { + BucketPolicy policy = await GetPolicyAsync(bucketName); + return policy.getPolicy(objectPrefix); + } + + /// + /// Internal method that sets the bucket access policy + /// + /// Bucket Name. + /// Valid Json policy object + /// + private async Task setPolicyAsync(string bucketName, BucketPolicy policy) + { + + string policyJson = policy.getJson(); + var request = await this.CreateRequest(Method.PUT, bucketName, + resourcePath: "?policy", + contentType: "application/json", + body: policyJson); + + IRestResponse response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + } + + /// + /// Sets the current bucket policy + /// + /// Bucket Name + /// Name of the object prefix. + /// Desired Policy type change + /// + public async Task SetPolicyAsync(String bucketName, String objectPrefix, PolicyType policyType) + { + utils.validateObjectPrefix(objectPrefix); + BucketPolicy policy = await GetPolicyAsync(bucketName); + if (policyType == PolicyType.NONE && policy.Statements() == null) + { + // As the request is for removing policy and the bucket + // has empty policy statements, just return success. + return; + } + + policy.setPolicy(policyType, objectPrefix); + + await setPolicyAsync(bucketName, policy); + } + } +} \ No newline at end of file diff --git a/MinioCore2/ApiEndpoints/IBucketOperations.cs b/MinioCore2/ApiEndpoints/IBucketOperations.cs new file mode 100644 index 000000000..547c47941 --- /dev/null +++ b/MinioCore2/ApiEndpoints/IBucketOperations.cs @@ -0,0 +1,76 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System; +using System.Threading.Tasks; +using MinioCore2.DataModel; + +namespace MinioCore2 +{ + public interface IBucketOperations + { + /// + /// Create a private bucket with the given name. + /// + /// Name of the new bucket + Task MakeBucketAsync(string bucketName, string location = "us-east-1"); + + /// + /// List all objects in a bucket + /// + /// Bucket to list objects from + /// An iterator lazily populated with objects + Task ListBucketsAsync(); + + /// + /// Returns true if the specified bucketName exists, otherwise returns false. + /// + /// Bucket to test existence of + /// true if exists and user has access + Task BucketExistsAsync(string bucketName); + + /// + /// Remove a bucket + /// + /// Name of bucket to remove + Task RemoveBucketAsync(string bucketName); + + /// + /// 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 + /// An observable of items that client can subscribe to + + /// + /// Get bucket policy at given objectPrefix + /// + /// Bucket name. + /// Name of the object prefix + /// Returns the PolicyType + Task GetPolicyAsync(String bucketName, String objectPrefix); + + /// + /// Sets the current bucket policy + /// + /// Bucket Name + /// Name of the object prefix. + /// Desired Policy type change + /// + Task SetPolicyAsync(String bucketName, String objectPrefix, PolicyType policyType); + + } +} \ No newline at end of file diff --git a/MinioCore2/ApiEndpoints/IObjectOperations.cs b/MinioCore2/ApiEndpoints/IObjectOperations.cs new file mode 100644 index 000000000..0b51e0e4b --- /dev/null +++ b/MinioCore2/ApiEndpoints/IObjectOperations.cs @@ -0,0 +1,122 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using MinioCore2.DataModel; + +namespace MinioCore2 +{ + public interface IObjectOperations + { + + /// + /// Get an object. The object will be streamed to the callback given by the user. + /// + /// Bucket to retrieve object from + /// Name of object to retrieve + /// A stream will be passed to the callback + Task GetObjectAsync(string bucketName, string objectName, Action callback); + + /// + /// Creates an object from file + /// + /// Bucket to create object in + /// Key of the new object + /// Path of file to upload + /// Content type of the new object, null defaults to "application/octet-stream" + Task PutObjectAsync(string bucketName, string objectName, Stream data, long size, string contentType); + + /// + /// Removes an object with given name in specific bucket + /// + /// Bucket to list incomplete uploads from + /// Key of object to list incomplete uploads from + /// + Task RemoveObjectAsync(string bucketName, string objectName); + + /// + /// Tests the object's existence and returns metadata about existing objects. + /// + /// Bucket to test object in + /// Name of the object to stat + /// Facts about the object + Task StatObjectAsync(string bucketName, string objectName); + + /// + /// 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 + /// A lazily populated list of incomplete uploads + IObservable ListIncompleteUploads(string bucketName, string prefix, bool recursive); + + /// + /// Remove incomplete uploads from a given bucket and objectName + /// + /// Bucket to remove incomplete uploads from + /// Key to remove incomplete uploads from + Task RemoveIncompleteUploadAsync(string bucketName, string objectName); + + /// + /// Copy a source object into a new destination object. + /// + /// Bucket name where the object to be copied exists. + /// Object name source to be copied. + /// Bucket name where the object will be copied to. + /// Object name to be created, if not provided uses source object name as destination object name. + /// optionally can take a key value CopyConditions as well for conditionally attempting copyObject. + /// + + Task CopyObjectAsync(string bucketName, string objectName, string destBucketName, string destObjectName = null, CopyConditions copyConditions = null); + + Task PutObjectAsync(string bucketName, string objectName, string filePath, string contentType = null); + + /// + /// Get an object. The object will be streamed to the callback given by the user. + /// + /// Bucket to retrieve object from + /// Name of object to retrieve + /// string with file path + /// + Task GetObjectAsync(string bucketName, string objectName, string filePath); + + /// + /// Presigned Get url. + /// + /// Bucket to retrieve object from + /// Key of object to retrieve + /// Expiration time in seconds + string PresignedGetObject(string bucketName, string objectName, int expiresInt); + + /// + /// Presigned Put url. + /// + /// Bucket to retrieve object from + /// Key of object to retrieve + /// Expiration time in seconds + + string PresignedPutObject(string bucketName, string objectName, int expiresInt); + + /// + /// Presigned post policy + /// + Dictionary PresignedPostPolicy(PostPolicy policy); + + } +} \ No newline at end of file diff --git a/MinioCore2/ApiEndpoints/ObjectOperations.cs b/MinioCore2/ApiEndpoints/ObjectOperations.cs new file mode 100644 index 000000000..74b190d50 --- /dev/null +++ b/MinioCore2/ApiEndpoints/ObjectOperations.cs @@ -0,0 +1,848 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Collections.Generic; +using System.Net; +using RestSharp; + +using System.Threading.Tasks; +using System.Linq; + +using System.Reactive.Linq; +using MinioCore2.DataModel; +using System.IO; +using System.Xml.Linq; +using System.Xml.Serialization; +using MinioCore2.Exceptions; +using System.Globalization; +using MinioCore2.Helper; + +namespace MinioCore2 +{ + public partial class MinioClient : IObjectOperations + { + + /// + /// Get an object. The object will be streamed to the callback given by the user. + /// + /// Bucket to retrieve object from + /// Name of object to retrieve + /// A stream will be passed to the callback + public async Task GetObjectAsync(string bucketName, string objectName, Action cb) + { + + var request = await this.CreateRequest(Method.GET, + bucketName, + objectName: objectName); + + request.ResponseWriter = cb; + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + + } + + /// + /// Get an object. The object will be streamed to the callback given by the user. + /// + /// Bucket to retrieve object from + /// Name of object to retrieve + /// string with file path + /// + public async Task GetObjectAsync(string bucketName, string objectName, string fileName) + { + + bool fileExists = File.Exists(fileName); + utils.ValidateFile(fileName); + + ObjectStat objectStat = await StatObjectAsync(bucketName, objectName); + long length = objectStat.Size; + string etag = objectStat.ETag; + + string tempFileName = fileName + "." + etag + ".part.minio"; + + bool tempFileExists = File.Exists(tempFileName); + + utils.ValidateFile(tempFileName); + + FileInfo tempFileInfo = new FileInfo(tempFileName); + long tempFileSize = 0; + if (tempFileExists) + { + tempFileSize = tempFileInfo.Length; + if (tempFileSize > length) + { + File.Delete(tempFileName); + tempFileExists = false; + tempFileSize = 0; + } + } + + if (fileExists) + { + FileInfo fileInfo = new FileInfo(fileName); + long fileSize = fileInfo.Length; + if (fileSize == length) + { + // already downloaded. nothing to do + return; + } + else if (fileSize > length) + { + throw new ArgumentException("'" + fileName + "': object size " + length + " is smaller than file size " + + fileSize); + } + else if (!tempFileExists) + { + // before resuming the download, copy filename to tempfilename + File.Copy(fileName, tempFileName); + tempFileSize = fileSize; + tempFileExists = true; + } + } + await GetObjectAsync(bucketName, objectName, (stream) => { + var fileStream = File.Create(tempFileName); + stream.CopyTo(fileStream); + fileStream.Dispose(); + FileInfo writtenInfo = new FileInfo(tempFileName); + long writtenSize = writtenInfo.Length; + if (writtenSize != length - tempFileSize) + { + new IOException(tempFileName + ": unexpected data written. expected = " + (length - tempFileSize) + + ", written = " + writtenSize); + } + utils.MoveWithReplace(tempFileName, fileName); + }); + + } + + /// + /// Creates an object from file + /// + /// Bucket to create object in + /// Key of the new object + /// Path of file to upload + /// Content type of the new object, null defaults to "application/octet-stream" + public async Task PutObjectAsync(string bucketName, string objectName, string fileName, string contentType = null) + { + utils.ValidateFile(fileName, contentType); + FileInfo fileInfo = new FileInfo(fileName); + long size = fileInfo.Length; + using (FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read)) + { + await PutObjectAsync(bucketName, objectName, file, size, contentType); + } + + } + + /// + /// Creates an object from inputstream + /// + /// Bucket to create object in + /// Key of the new object + /// Total size of bytes to be written, must match with data's length + /// Content type of the new object, null defaults to "application/octet-stream" + /// Stream of bytes to send + public async Task PutObjectAsync(string bucketName, string objectName, Stream data, long size, string contentType) + { + utils.validateBucketName(bucketName); + utils.validateObjectName(objectName); + if (data == null) + { + throw new ArgumentNullException("Invalid input stream,cannot be null"); + } + + //for sizes less than 5Mb , put a single object + if (size < Constants.MinimumPartSize && size >= 0) + { + var bytes = ReadFull(data, (int)size); + if (bytes.Length != (int)size) + { + throw new UnexpectedShortReadException("Data read " + bytes.Length + " is shorter than the size " + size + " of input buffer."); + } + await this.PutObjectAsync(bucketName, objectName, null, 0, bytes, contentType); + return; + } + // For all sizes greater than 5MiB do multipart. + + dynamic multiPartInfo = CalculateMultiPartSize(size); + double partSize = multiPartInfo.partSize; + double partCount = multiPartInfo.partCount; + double lastPartSize = multiPartInfo.lastPartSize; + Part[] totalParts = new Part[(int)partCount]; + Part part = null; + Part[] existingParts = null; + + string uploadId = await this.getLatestIncompleteUploadIdAsync(bucketName, objectName); + + if (uploadId == null) + { + uploadId = await this.NewMultipartUploadAsync(bucketName, objectName, contentType); + } + else + { + existingParts = await this.ListParts(bucketName, objectName, uploadId).ToArray(); + } + + double expectedReadSize = partSize; + int partNumber; + bool skipUpload = false; + for (partNumber = 1; partNumber <= partCount; partNumber++) + { + byte[] dataToCopy = ReadFull(data, (int)partSize); + + if (partNumber == partCount) + { + expectedReadSize = lastPartSize; + } + if (existingParts != null && partNumber <= existingParts.Length) + { + part = existingParts[partNumber - 1]; + if (part != null && partNumber == part.PartNumber && expectedReadSize == part.partSize()) + { + System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create(); + byte[] hash = md5.ComputeHash(dataToCopy); + string etag = BitConverter.ToString(hash).Replace("-", string.Empty).ToLower(); + if (etag.Equals(part.ETag)) + { + totalParts[partNumber - 1] = new Part() { PartNumber = part.PartNumber, ETag = part.ETag, size = part.partSize() }; + skipUpload = true; + + } + + } + } + else + { + skipUpload = false; + } + + if (!skipUpload) + { + string etag = await this.PutObjectAsync(bucketName, objectName, uploadId, partNumber, dataToCopy, contentType); + totalParts[partNumber - 1] = new Part() { PartNumber = partNumber, ETag = etag, size = (long)expectedReadSize }; + } + + } + Dictionary etags = new Dictionary(); + for (partNumber = 1; partNumber <= partCount; partNumber++) + { + etags[partNumber] = totalParts[partNumber - 1].ETag; + } + await this.CompleteMultipartUploadAsync(bucketName, objectName, uploadId, etags); + + } + /// + /// Internal method to complete multi part upload of object to server. + /// + /// Bucket Name + /// Object to be uploaded + /// Upload Id + /// Etags + /// + private async Task CompleteMultipartUploadAsync(string bucketName, string objectName, string uploadId, Dictionary etags) + { + + string resourcePath = "?uploadId=" + uploadId; + var request = await this.CreateRequest(Method.POST, bucketName, + objectName: objectName, + resourcePath: resourcePath + ); + + List parts = new List(); + + for (int i = 1; i <= etags.Count; i++) + { + parts.Add(new XElement("Part", + new XElement("PartNumber", i), + new XElement("ETag", etags[i]))); + } + + var completeMultipartUploadXml = new XElement("CompleteMultipartUpload", parts); + + var bodyString = completeMultipartUploadXml.ToString(); + + var body = System.Text.Encoding.UTF8.GetBytes(bodyString); + + request.AddParameter("application/xml", body, RestSharp.ParameterType.RequestBody); + + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + + } + + /// + /// Calculate part size and number of parts required. + /// + /// + /// + private Object CalculateMultiPartSize(long size) + { + // make sure to have enough buffer for last part, use 9999 instead of 10000 + if (size == -1) + { + size = Constants.MaximumStreamObjectSize; + } + if (size > Constants.MaxMultipartPutObjectSize) + { + throw new EntityTooLargeException("Your proposed upload size " + size + " exceeds the maximum allowed object size " + Constants.MaxMultipartPutObjectSize); + } + double partSize = (double)Math.Ceiling((decimal)size / Constants.MaxParts); + partSize = (double)Math.Ceiling((decimal)partSize / Constants.MinimumPartSize) * Constants.MinimumPartSize; + double partCount = (double)Math.Ceiling(size / partSize); + double lastPartSize = size - (partCount - 1) * partSize; + return new + { + partSize = partSize, + partCount = partCount, + lastPartSize = lastPartSize + }; + } + + /// + /// Returns an async observable of parts corresponding to a uploadId for a specific bucket and objectName + /// + /// + /// + /// + /// + private IObservable ListParts(string bucketName, string objectName, string uploadId) + { + + return Observable.Create( + async obs => + { + int nextPartNumberMarker = 0; + bool isRunning = true; + while (isRunning) + { + var uploads = await this.GetListPartsAsync(bucketName, objectName, uploadId, nextPartNumberMarker); + foreach (Part part in uploads.Item2) + { + obs.OnNext(part); + } + nextPartNumberMarker = uploads.Item1.NextPartNumberMarker; + isRunning = uploads.Item1.IsTruncated; + } + }); + + } + /// + /// Gets the list of parts corresponding to a uploadId for given bucket and object + /// + /// + /// + /// + /// + /// + private async Task>> GetListPartsAsync(string bucketName, string objectName, string uploadId, int partNumberMarker) + { + var resourcePath = "?uploadId=" + uploadId; + if (partNumberMarker > 0) + { + resourcePath += "&part-number-marker=" + partNumberMarker; + } + resourcePath += "&max-parts=1000"; + var request = await this.CreateRequest(Method.GET, bucketName, + objectName: objectName, + resourcePath: resourcePath + ); + + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + + var contentBytes = System.Text.Encoding.UTF8.GetBytes(response.Content); + var stream = new MemoryStream(contentBytes); + ListPartsResult listPartsResult = (ListPartsResult)(new XmlSerializer(typeof(ListPartsResult)).Deserialize(stream)); + + XDocument root = XDocument.Parse(response.Content); + + var uploads = (from c in root.Root.Descendants("{http://s3.amazonaws.com/doc/2006-03-01/}Part") + select new Part() + { + PartNumber = int.Parse(c.Element("{http://s3.amazonaws.com/doc/2006-03-01/}PartNumber").Value, CultureInfo.CurrentCulture), + ETag = c.Element("{http://s3.amazonaws.com/doc/2006-03-01/}ETag").Value.Replace("\"", ""), + size = long.Parse(c.Element("{http://s3.amazonaws.com/doc/2006-03-01/}Size").Value, CultureInfo.CurrentCulture) + }); + + return new Tuple>(listPartsResult, uploads.ToList()); + + } + + + /// + /// Start a new multi-part upload request + /// + /// + /// + /// + /// + private async Task NewMultipartUploadAsync(string bucketName, string objectName, string contentType) + { + var resource = "?uploads"; + if (string.IsNullOrWhiteSpace(contentType)) + { + contentType = "application/octet-stream"; + } + + var request = await this.CreateRequest(Method.POST, bucketName, objectName: objectName, + contentType: contentType, resourcePath: resource); + + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + + var contentBytes = System.Text.Encoding.UTF8.GetBytes(response.Content); + var stream = new MemoryStream(contentBytes); + InitiateMultipartUploadResult newUpload = (InitiateMultipartUploadResult)(new XmlSerializer(typeof(InitiateMultipartUploadResult)).Deserialize(stream)); + return newUpload.UploadId; + } + + + /// + /// Upload object part to bucket for particular uploadId + /// + /// + /// + /// + /// + /// + /// + /// + private async Task PutObjectAsync(string bucketName, string objectName, string uploadId, int partNumber, byte[] data, string contentType) + { + var resource = ""; + if (!string.IsNullOrEmpty(uploadId) && partNumber > 0) + { + resource += "?uploadId=" + uploadId + "&partNumber=" + partNumber; + } + var request = await this.CreateRequest(Method.PUT, bucketName, + objectName: objectName, + contentType: contentType, + body: data, + resourcePath: resource + ); + + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + + string etag = null; + foreach (Parameter parameter in response.Headers) + { + if (parameter.Name == "ETag") + { + etag = parameter.Value.ToString(); + } + } + return etag; + + + } + + /// + /// Get list of multi-part uploads matching particular uploadIdMarker + /// + /// bucketName + /// prefix + /// + /// + /// + /// + private async Task>> GetMultipartUploadsListAsync(string bucketName, + string prefix, + string keyMarker, + string uploadIdMarker, + string delimiter) + { + var queries = new List(); + queries.Add("uploads"); + if (prefix != null) + { + queries.Add("prefix=" + Uri.EscapeDataString(prefix)); + } + if (keyMarker != null) + { + queries.Add("key-marker=" + Uri.EscapeDataString(keyMarker)); + } + if (uploadIdMarker != null) + { + queries.Add("upload-id-marker=" + uploadIdMarker); + } + if (delimiter != null) + { + queries.Add("delimiter=" + delimiter); + } + + queries.Add("max-uploads=1000"); + + string query = string.Join("&", queries); + + var request = await this.CreateRequest(Method.GET, bucketName, + resourcePath: "?" + query); + + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + + var contentBytes = System.Text.Encoding.UTF8.GetBytes(response.Content); + var stream = new MemoryStream(contentBytes); + ListMultipartUploadsResult listBucketResult = (ListMultipartUploadsResult)(new XmlSerializer(typeof(ListMultipartUploadsResult)).Deserialize(stream)); + + XDocument root = XDocument.Parse(response.Content); + + var uploads = (from c in root.Root.Descendants("{http://s3.amazonaws.com/doc/2006-03-01/}Upload") + select new Upload() + { + Key = c.Element("{http://s3.amazonaws.com/doc/2006-03-01/}Key").Value, + UploadId = c.Element("{http://s3.amazonaws.com/doc/2006-03-01/}UploadId").Value, + Initiated = c.Element("{http://s3.amazonaws.com/doc/2006-03-01/}Initiated").Value + }); + + return new Tuple>(listBucketResult, uploads.ToList()); + + } + + /// + /// 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 + /// A lazily populated list of incomplete uploads + public IObservable ListIncompleteUploads(string bucketName, string prefix = "", bool recursive = true) + { + if (recursive) + { + return this.listIncompleteUploads(bucketName, prefix, null); + } + return this.listIncompleteUploads(bucketName, prefix, "/"); + } + + + /// + /// Lists all or delimited incomplete uploads in a given bucket with a given objectName + /// + /// Bucket to list incomplete uploads from + /// Key of object to list incomplete uploads from + /// delimiter of object to list incomplete uploads + /// Observable that notifies when next next upload becomes available + private IObservable listIncompleteUploads(string bucketName, string prefix, string delimiter) + { + return Observable.Create( + async obs => + { + string nextKeyMarker = null; + string nextUploadIdMarker = null; + bool isRunning = true; + + while (isRunning) + { + var uploads = await this.GetMultipartUploadsListAsync(bucketName, prefix, nextKeyMarker, nextUploadIdMarker, delimiter); + foreach (Upload upload in uploads.Item2) + { + obs.OnNext(upload); + } + nextKeyMarker = uploads.Item1.NextKeyMarker; + nextUploadIdMarker = uploads.Item1.NextUploadIdMarker; + isRunning = uploads.Item1.IsTruncated; + } + }); + + } + + /// + /// Find uploadId of most recent unsuccessful attempt to upload object to bucket. + /// + /// + /// + /// + private async Task getLatestIncompleteUploadIdAsync(string bucketName, string objectName) + { + Upload latestUpload = null; + var uploads = await this.ListIncompleteUploads(bucketName, objectName).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 + /// + /// Bucket to remove incomplete uploads from + /// Key to remove incomplete uploads from + public async Task RemoveIncompleteUploadAsync(string bucketName, string objectName) + { + var uploads = await this.ListIncompleteUploads(bucketName, objectName).ToArray(); + foreach (Upload upload in uploads) + { + if (objectName == upload.Key) + { + await this.RemoveUploadAsync(bucketName, objectName, upload.UploadId); + } + } + } + + /// + /// Remove object with matching uploadId from bucket + /// + /// + /// + /// + /// + private async Task RemoveUploadAsync(string bucketName, string objectName, string uploadId) + { + // var resourcePath = "/" + utils.UrlEncode(objectName) + "?uploadId=" + uploadId; + var resourcePath = "?uploadId=" + uploadId; + + var request = await this.CreateRequest(Method.DELETE, bucketName, + objectName: objectName, + resourcePath: resourcePath + ); + + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + + } + + /// + /// Removes an object with given name in specific bucket + /// + /// Bucket to list incomplete uploads from + /// Key of object to list incomplete uploads from + /// + public async Task RemoveObjectAsync(string bucketName, string objectName) + { + + var request = await this.CreateRequest(Method.DELETE, bucketName, + objectName: objectName); + + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + + + } + + /// + /// Tests the object's existence and returns metadata about existing objects. + /// + /// Bucket to test object in + /// Name of the object to stat + /// Facts about the object + public async Task StatObjectAsync(string bucketName, string objectName) + { + var request = await this.CreateRequest(Method.HEAD, bucketName, + objectName: objectName); + + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + + + //Extract stats from response + long size = 0; + DateTime lastModified = new DateTime(); + string etag = ""; + string contentType = null; + foreach (Parameter parameter in response.Headers) + { + switch (parameter.Name) + { + case "Content-Length": + size = long.Parse(parameter.Value.ToString()); + break; + case "Last-Modified": + lastModified = DateTime.Parse(parameter.Value.ToString()); + break; + case "ETag": + etag = parameter.Value.ToString().Replace("\"", ""); + break; + case "Content-Type": + contentType = parameter.Value.ToString(); + break; + default: + break; + } + } + return new ObjectStat(objectName, size, lastModified, etag, contentType); + + } + + /// + /// Advances in the stream upto currentPartSize or End of Stream + /// + /// + /// + /// bytes read in a byte array + internal byte[] ReadFull(Stream data, int currentPartSize) + { + byte[] result = new byte[currentPartSize]; + int totalRead = 0; + while (totalRead < currentPartSize) + { + byte[] curData = new byte[currentPartSize - totalRead]; + int curRead = data.Read(curData, 0, currentPartSize - totalRead); + if (curRead == 0) + { + break; + } + for (int i = 0; i < curRead; i++) + { + result[totalRead + i] = curData[i]; + } + totalRead += curRead; + } + + if (totalRead == 0) return null; + + if (totalRead == currentPartSize) return result; + + byte[] truncatedResult = new byte[totalRead]; + for (int i = 0; i < totalRead; i++) + { + truncatedResult[i] = result[i]; + } + return truncatedResult; + } + + /// + /// Copy a source object into a new destination object. + /// + /// Bucket name where the object to be copied exists. + /// Object name source to be copied. + /// Bucket name where the object will be copied to. + /// Object name to be created, if not provided uses source object name as destination object name. + /// optionally can take a key value CopyConditions as well for conditionally attempting copyObject. + /// + public async Task CopyObjectAsync(string bucketName, string objectName, string destBucketName, string destObjectName = null, CopyConditions copyConditions = null) + { + if (bucketName == null) + { + throw new ArgumentException("Source bucket name cannot be empty"); + } + if (objectName == null) + { + throw new ArgumentException("Source object name cannot be empty"); + } + if (destBucketName == null) + { + throw new ArgumentException("Destination bucket name cannot be empty"); + } + // Escape source object path. + string sourceObjectPath = bucketName + "/" + utils.UrlEncode(objectName); + + // Destination object name is optional, if empty default to source object name. + if (destObjectName == null) + { + destObjectName = objectName; + } + + var path = destBucketName + "/" + utils.UrlEncode(destObjectName); + var request = await this.CreateRequest(Method.PUT, bucketName, + objectName: objectName, + resourcePath: path); + + // Set the object source + request.AddHeader("x-amz-copy-source", sourceObjectPath); + + // If no conditions available, skip addition else add the conditions to the header + if (copyConditions != null) + { + foreach (var item in copyConditions.GetConditions()) + { + request.AddHeader(item.Key, item.Value); + } + } + + var response = await this.ExecuteTaskAsync(this.NoErrorHandlers, request); + + // For now ignore the copyObjectResult, just read and parse it. + var contentBytes = System.Text.Encoding.UTF8.GetBytes(response.Content); + var stream = new MemoryStream(contentBytes); + + CopyObjectResult copyObjectResult = (CopyObjectResult)(new XmlSerializer(typeof(CopyObjectResult)).Deserialize(stream)); + return copyObjectResult; + } + + /// + /// Presigned Get url. + /// + /// Bucket to retrieve object from + /// Key of object to retrieve + /// Expiration time in seconds + public string PresignedGetObject(string bucketName, string objectName, int expiresInt) + { + // Initialize a new client. + PrepareClient(bucketName); + + RestRequest request = new RestRequest(bucketName + "/" + utils.UrlEncode(objectName), Method.GET); + return this.authenticator.PresignURL(this.restClient, request, expiresInt); + } + + /// + /// Presigned Put url. + /// + /// Bucket to retrieve object from + /// Key of object to retrieve + /// Expiration time in seconds + public string PresignedPutObject(string bucketName, string objectName, int expiresInt) + { + //Initialize a new client. + PrepareClient(bucketName); + RestRequest request = new RestRequest(bucketName + "/" + utils.UrlEncode(objectName), Method.PUT); + return this.authenticator.PresignURL(this.restClient, request, expiresInt); + } + + /// + /// Presigned post policy + /// + public Dictionary PresignedPostPolicy(PostPolicy policy) + { + //Initialize a new client. + PrepareClient(); + + if (!policy.IsBucketSet()) + { + throw new ArgumentException("bucket should be set"); + } + + if (!policy.IsKeySet()) + { + throw new ArgumentException("key should be set"); + } + + if (!policy.IsExpirationSet()) + { + throw new ArgumentException("expiration should be set"); + } + + string region = Regions.GetRegion(this.restClient.BaseUrl.Host); + DateTime signingDate = DateTime.UtcNow; + + policy.SetAlgorithm("AWS4-HMAC-SHA256"); + policy.SetCredential(this.authenticator.GetCredentialString(signingDate, region)); + policy.SetDate(signingDate); + + string policyBase64 = policy.Base64(); + string signature = this.authenticator.PresignPostSignature(region, signingDate, policyBase64); + + policy.SetPolicy(policyBase64); + policy.SetSignature(signature); + + return policy.GetFormData(); + } + } +} \ No newline at end of file diff --git a/MinioCore2/BucketRegionCache.cs b/MinioCore2/BucketRegionCache.cs new file mode 100644 index 000000000..bde597163 --- /dev/null +++ b/MinioCore2/BucketRegionCache.cs @@ -0,0 +1,139 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using MinioCore2.Helper; +using RestSharp; + +using System; +using System.Collections.Concurrent; +using System.IO; +using System.Net; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace MinioCore2 +{ + // A singleton bucket/region cache map. + public sealed class BucketRegionCache + { + private static readonly Lazy lazy = + new Lazy(() => new BucketRegionCache()); + + private ConcurrentDictionary regionMap; + + public static BucketRegionCache Instance + { + get { return lazy.Value; } + } + private BucketRegionCache() + { + regionMap = new ConcurrentDictionary(); + } + /** + * Returns AWS region for given bucket name. + */ + public string Region(string bucketName) + { + string value = null; + this.regionMap.TryGetValue(bucketName, out value); + return value != null ? value : "us-east-1"; + } + + + /** + * Adds bucket name and its region to BucketRegionCache. + */ + public void Add(string bucketName, string region) + { + this.regionMap.TryAdd(bucketName, region); + } + + + /** + * Removes region cache of the bucket if any. + */ + public void Remove(string bucketName) + { + string value; + this.regionMap.TryRemove(bucketName, out value); + } + + + /** + * Returns true if given bucket name is in the map else false. + */ + public bool Exists(String bucketName) + { + string value = null; + this.regionMap.TryGetValue(bucketName, out value); + return value != null; + + } + + /// + /// Updates Region cache for given bucket. + /// + /// + internal async Task Update(MinioClient client, string bucketName) + { + string region = null; + + if (bucketName != null && s3utils.IsAmazonEndPoint(client.BaseUrl) && client.AccessKey != null + && client.SecretKey != null && !Instance.Exists(bucketName)) + { + string location = null; + var path = bucketName + "?location"; + //Initialize client + client.PrepareClient(); + + var request = new RestRequest(path, Method.GET); + + var response = await client.ExecuteTaskAsync(client.NoErrorHandlers, request); + + if (HttpStatusCode.OK.Equals(response.StatusCode)) + { + var contentBytes = System.Text.Encoding.UTF8.GetBytes(response.Content); + var stream = new MemoryStream(contentBytes); + XDocument root = XDocument.Parse(response.Content); + location = root.Root.Value; + + } + if (location == null || location == "") + { + region = "us-east-1"; + } + else + { + // eu-west-1 can be sometimes 'EU'. + if ("EU".Equals(location)) + { + region = "eu-west-1"; + } + else + { + region = location; + } + } + + // Add the new location. + Instance.Add(bucketName, region); + } + return region; + + } + + } +} \ No newline at end of file diff --git a/MinioCore2/DataModel/Bucket.cs b/MinioCore2/DataModel/Bucket.cs new file mode 100644 index 000000000..2f369e34a --- /dev/null +++ b/MinioCore2/DataModel/Bucket.cs @@ -0,0 +1,33 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; + +namespace MinioCore2.DataModel +{ + [Serializable] + public class Bucket + { + public string Name { get; set; } + public string CreationDate { get; set; } + + public DateTime CreationDateDateTime { + get { + return DateTime.Parse(this.CreationDate); + } + } + } +} diff --git a/MinioCore2/DataModel/CopyConditions.cs b/MinioCore2/DataModel/CopyConditions.cs new file mode 100644 index 000000000..bf2139041 --- /dev/null +++ b/MinioCore2/DataModel/CopyConditions.cs @@ -0,0 +1,107 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MinioCore2.DataModel +{ + /** + * A container class to hold all the Conditions to be checked + * before copying an object. + */ + public class CopyConditions + { + private Dictionary copyConditions; + + /** + * Set modified condition, copy object modified since given time. + * + * @throws ArgumentException + * When date is null + */ + + public void SetModified(DateTime date) + { + if (date == null) + { + throw new ArgumentException("Date cannot be empty"); + } + copyConditions["x-amz-copy-source-if-modified-since"] = date.ToUniversalTime().ToString("r"); + } + + /** + * Unset modified condition, copy object modified since given time. + * + * @throws ArgumentException + * When date is null + */ + + public void SetUnmodified(DateTime date) + { + if (date == null) + { + throw new ArgumentException("Date cannot be empty"); + } + copyConditions["x-amz-copy-source-if-unmodified-since"] = date.ToUniversalTime().ToString("r"); + } + /** + * Set matching ETag condition, copy object which matches + * the following ETag. + * + * @throws ArgumentException when etag is null + */ + public void SetMatchETag(string etag) + { + if (etag == null) + { + throw new ArgumentException("ETag cannot be empty"); + } + copyConditions["x-amz-copy-source-if-match"] = etag; + } + + /** + * Set matching ETag none condition, copy object which does not + * match the following ETag. + * + * @throws InvalidArgumentException + * When etag is null + */ + public void SetMatchETagNone(string etag) + { + if (etag == null) + { + throw new ArgumentException("ETag cannot be empty"); + } + copyConditions["x-amz-copy-source-if-none-match"] = etag; + } + + /** + * Get all the set copy conditions map. + * + */ + public ReadOnlyDictionary GetConditions() + { + return new ReadOnlyDictionary(copyConditions); + + } + + } +} diff --git a/MinioCore2/DataModel/CopyObjectResult.cs b/MinioCore2/DataModel/CopyObjectResult.cs new file mode 100644 index 000000000..5eae1c947 --- /dev/null +++ b/MinioCore2/DataModel/CopyObjectResult.cs @@ -0,0 +1,31 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Xml.Serialization; + +namespace MinioCore2.DataModel +{ + [Serializable] + [XmlRoot(ElementName = "CopyObjectResult", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/")] + + public class CopyObjectResult + { + public string ETag { get; set; } + + public string lastModified { get; set; } + } +} diff --git a/MinioCore2/DataModel/CreateBucketConfiguration.cs b/MinioCore2/DataModel/CreateBucketConfiguration.cs new file mode 100644 index 000000000..8f15ce521 --- /dev/null +++ b/MinioCore2/DataModel/CreateBucketConfiguration.cs @@ -0,0 +1,32 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Xml.Serialization; + +namespace MinioCore2.DataModel +{ + [Serializable] + public class CreateBucketConfiguration + { + public CreateBucketConfiguration(string location=null) + { + this.LocationConstraint = location; + } + [XmlAttribute] + public string LocationConstraint { get; private set; } + } +} diff --git a/MinioCore2/DataModel/DateFormat.cs b/MinioCore2/DataModel/DateFormat.cs new file mode 100644 index 000000000..a9e3ad19c --- /dev/null +++ b/MinioCore2/DataModel/DateFormat.cs @@ -0,0 +1,49 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MinioCore2.DataModel +{ + /** + * Global constants for various date formats. They are used to convert string to DateTime object and vise verse. + */ + public class DateFormat + { + /* + public static const DateTimeFormatter AMZ_DATE_FORMAT = + DateTimeFormat.forPattern("yyyyMMdd'T'HHmmss'Z'").withZoneUTC().withLocale(Locale.US); + + public static const DateTimeFormatter EXPIRATION_DATE_FORMAT = + DateTimeFormat.forPattern("yyyy-MM-dd'T'HH':'mm':'ss'.'SSS'Z'").withZoneUTC().withLocale(Locale.US); + + public static const DateTimeFormatter RESPONSE_DATE_FORMAT = EXPIRATION_DATE_FORMAT; + + public static const DateTimeFormatter SIGNER_DATE_FORMAT = + DateTimeFormat.forPattern("yyyyMMdd").withZoneUTC().withLocale(Locale.US); + + public static const DateTimeFormatter HTTP_HEADER_DATE_FORMAT = + DateTimeFormat.forPattern("EEE',' dd MMM yyyy HH':'mm':'ss zzz").withZoneUTC().withLocale(Locale.US); + + private DateFormat() { } + } +*/ + } +} diff --git a/MinioCore2/DataModel/Grant.cs b/MinioCore2/DataModel/Grant.cs new file mode 100644 index 000000000..4f927cf34 --- /dev/null +++ b/MinioCore2/DataModel/Grant.cs @@ -0,0 +1,32 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using MinioCore2.DataModel; +using System; +using System.Xml.Serialization; + +namespace MinioCore2.Datamodel +{ + [Serializable] + [XmlInclude(typeof(GranteeUser))] + public class Grant + { + public string Permission { get; set; } + + [XmlElement] + public GranteeUser Grantee; + } +} diff --git a/MinioCore2/DataModel/GranteeUser.cs b/MinioCore2/DataModel/GranteeUser.cs new file mode 100644 index 000000000..65473f46d --- /dev/null +++ b/MinioCore2/DataModel/GranteeUser.cs @@ -0,0 +1,34 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; + +namespace MinioCore2.DataModel +{ + [Serializable] + public class GranteeUser + { + public string Id { get; set; } + + public string DisplayName { get; set; } + + public string EmailAddress { get; set; } + + public string Type { get; set; } + + public string Uri { get; set; } + } +} diff --git a/MinioCore2/DataModel/InitiateMultipartUploadResult.cs b/MinioCore2/DataModel/InitiateMultipartUploadResult.cs new file mode 100644 index 000000000..6827bb7c7 --- /dev/null +++ b/MinioCore2/DataModel/InitiateMultipartUploadResult.cs @@ -0,0 +1,28 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Xml.Serialization; + +namespace MinioCore2.DataModel +{ + [Serializable] + [XmlRoot(ElementName = "InitiateMultipartUploadResult", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/")] + public class InitiateMultipartUploadResult + { + public string UploadId { get; set; } + } +} diff --git a/MinioCore2/DataModel/Item.cs b/MinioCore2/DataModel/Item.cs new file mode 100644 index 000000000..c0db7b734 --- /dev/null +++ b/MinioCore2/DataModel/Item.cs @@ -0,0 +1,58 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; + +namespace MinioCore2.DataModel +{ + [Serializable] + public class Item + { + private string etag; + + public string Key { get; set; } + public string LastModified { get; set; } + public string ETag + { + get + { + return etag; + } + set + { + if (value != null) + { + etag = value.Replace("\"", ""); + } + else + { + etag = null; + } + } + } + public UInt64 Size { get; set; } + + public bool IsDir { get; set; } + + public DateTime LastModifiedDateTime + { + get + { + return DateTime.Parse(this.LastModified); + } + } + } +} diff --git a/MinioCore2/DataModel/ListAllMyBucketsResult.cs b/MinioCore2/DataModel/ListAllMyBucketsResult.cs new file mode 100644 index 000000000..9e356e182 --- /dev/null +++ b/MinioCore2/DataModel/ListAllMyBucketsResult.cs @@ -0,0 +1,35 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Collections.Generic; +using System.Xml.Serialization; + +namespace MinioCore2.DataModel +{ + [Serializable] + [XmlRoot(ElementName = "ListAllMyBucketsResult", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/")] + [XmlInclude(typeof(Bucket))] + public class ListAllMyBucketsResult + { + [XmlAttribute] + public string Owner { get; set; } + + [XmlArray("Buckets")] + [XmlArrayItem(typeof(Bucket))] + public List Buckets { get; set; } + } +} diff --git a/MinioCore2/DataModel/ListBucketResult.cs b/MinioCore2/DataModel/ListBucketResult.cs new file mode 100644 index 000000000..a64fde371 --- /dev/null +++ b/MinioCore2/DataModel/ListBucketResult.cs @@ -0,0 +1,42 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Xml.Serialization; + +namespace MinioCore2.DataModel +{ + [Serializable] + [XmlRoot(ElementName = "ListBucketResult", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/")] + [XmlInclude(typeof(Item))] + [XmlInclude(typeof(Prefix))] + public class ListBucketResult + { + public string Name { get; set; } + + public string Prefix { get; set; } + + public string Marker { get; set; } + + public string NextMarker { get; set; } + + public string MaxKeys { get; set; } + + public string Delimiter { get; set; } + + public bool IsTruncated { get; set; } + } +} diff --git a/MinioCore2/DataModel/ListMultipartUploadsResult.cs b/MinioCore2/DataModel/ListMultipartUploadsResult.cs new file mode 100644 index 000000000..9b236ba82 --- /dev/null +++ b/MinioCore2/DataModel/ListMultipartUploadsResult.cs @@ -0,0 +1,34 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Xml.Serialization; + +namespace MinioCore2.DataModel +{ + [Serializable] + [XmlRoot(ElementName = "ListMultipartUploadsResult", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/")] + public class ListMultipartUploadsResult + { + public string Bucket { get; set; } + public string KeyMarker { get; set; } + public string UploadIdMarker { get; set; } + public string NextKeyMarker { get; set; } + public string NextUploadIdMarker { get; set; } + public int MaxUploads { get; set; } + public bool IsTruncated { get; set; } + } +} diff --git a/MinioCore2/DataModel/ListPartsResult.cs b/MinioCore2/DataModel/ListPartsResult.cs new file mode 100644 index 000000000..a530324f4 --- /dev/null +++ b/MinioCore2/DataModel/ListPartsResult.cs @@ -0,0 +1,29 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Xml.Serialization; + +namespace MinioCore2.DataModel +{ + [Serializable] + [XmlRoot(ElementName = "ListPartsResult", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/")] + public class ListPartsResult + { + public int NextPartNumberMarker { get; set; } + public bool IsTruncated { get; set; } + } +} diff --git a/MinioCore2/DataModel/LocationConstraint.cs b/MinioCore2/DataModel/LocationConstraint.cs new file mode 100644 index 000000000..61a80c32f --- /dev/null +++ b/MinioCore2/DataModel/LocationConstraint.cs @@ -0,0 +1,31 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Xml.Serialization; + + +namespace MinioCore2.DataModel +{ + [Serializable] + [XmlRoot(ElementName = "LocationConstraint", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/")] + + public class LocationConstraint + { + internal string location { get; set; } + } +} + diff --git a/MinioCore2/DataModel/ObjectStat.cs b/MinioCore2/DataModel/ObjectStat.cs new file mode 100644 index 000000000..be513cbe5 --- /dev/null +++ b/MinioCore2/DataModel/ObjectStat.cs @@ -0,0 +1,50 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; + +namespace MinioCore2.DataModel +{ + public class ObjectStat + { + /// + /// Object metadata information. + /// + /// Object name + /// Object size + /// Last when object was modified + /// Unique entity tag for the object + /// Object content type + public ObjectStat(string objectName, long size, DateTime lastModified, string etag, string contentType) + { + this.ObjectName = objectName; + this.Size = size; + this.LastModified = lastModified; + this.ETag = etag; + this.ContentType = contentType; + } + public string ObjectName { get; private set; } + public long Size { get; private set; } + public DateTime LastModified { get; private set; } + public string ETag { get; private set; } + public string ContentType { get; private set; } + + public override string ToString() + { + return string.Format("{0} : Size({1}) LastModified({2}) ETag({3}) Content-Type({4})",this.ObjectName, this.Size, this.LastModified, this.ETag, this.ContentType); + } + } +} diff --git a/MinioCore2/DataModel/Part.cs b/MinioCore2/DataModel/Part.cs new file mode 100644 index 000000000..d0377702b --- /dev/null +++ b/MinioCore2/DataModel/Part.cs @@ -0,0 +1,53 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; + +namespace MinioCore2.DataModel +{ + [Serializable] + public class Part + { + private string etag; + public int PartNumber { get; set; } + public long size { get; set; } + public DateTime lastModified { get; set; } + + public string ETag + { + get + { + return etag; + } + set + { + if (value != null) + { + etag = value.Replace("\"", ""); + } + else + { + etag = null; + } + } + } + public long partSize() + { + return size; + } + + } +} diff --git a/MinioCore2/DataModel/Policy/ActionJsonConverter.cs b/MinioCore2/DataModel/Policy/ActionJsonConverter.cs new file mode 100644 index 000000000..d92e09d8d --- /dev/null +++ b/MinioCore2/DataModel/Policy/ActionJsonConverter.cs @@ -0,0 +1,60 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using Newtonsoft.Json; + +namespace MinioCore2.DataModel.Policy +{ + class ActionJsonConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + throw new NotImplementedException(); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + object retVal = new Object(); + if (reader.TokenType == JsonToken.StartObject) + { + Principal instance = (Principal)serializer.Deserialize(reader, typeof(Principal)); + retVal = instance ; + + } + else if (reader.TokenType == JsonToken.String) + { + if (reader.Value.Equals("*")) + { + Principal instance = new Principal("AWS"); + instance.CanonicalUser(reader.Value.ToString()); + retVal = instance; + } + } + else if (reader.TokenType == JsonToken.StartArray) + { + retVal = serializer.Deserialize(reader, objectType); + } + return retVal; + + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + throw new NotImplementedException(); + } + } +} diff --git a/MinioCore2/DataModel/Policy/BucketPolicy.cs b/MinioCore2/DataModel/Policy/BucketPolicy.cs new file mode 100644 index 000000000..c2ffe0fe9 --- /dev/null +++ b/MinioCore2/DataModel/Policy/BucketPolicy.cs @@ -0,0 +1,550 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using System.IO; +using Newtonsoft.Json.Linq; +using MinioCore2.Policy; + +namespace MinioCore2.DataModel +{ + public class BucketPolicy + { + [JsonIgnore] + private string bucketName; + [JsonProperty("Version")] + private string version; + + [JsonProperty("Statement")] + private List statements { get; set; } + + public BucketPolicy(string bucketName=null) + { + if (bucketName != null) + { + this.bucketName = bucketName; + this.version = "2012-10-17"; + } + } + + + /** + * Reads JSON from given {@link Reader} and returns new {@link BucketPolicy} of given bucket name. + */ + public static BucketPolicy parseJson(MemoryStream reader , String bucketName) + { + string toparse = new StreamReader(reader).ReadToEnd(); + JObject jsonData = JObject.Parse(toparse); + + BucketPolicy bucketPolicy = JsonConvert.DeserializeObject(toparse); + bucketPolicy.bucketName = bucketName; + + return bucketPolicy; + } + + internal List Statements() + { + return this.statements; + } + /** + * Generates JSON of this BucketPolicy object. + */ + //JsonIgnore + public string getJson() + { + return JsonConvert.SerializeObject(this,Formatting.None, + new JsonSerializerSettings { + NullValueHandling = NullValueHandling.Ignore + }); + } + + + /** + * Returns new bucket statements for given policy type. + */ + private List newBucketStatement(PolicyType policy, String prefix) + { + List statements = new List(); + + if (policy == PolicyType.NONE || bucketName == null || bucketName.Length == 0) + { + return statements; + } + + Resources resources = new Resources(Constants.AWS_RESOURCE_PREFIX + bucketName); + + Statement statement = new Statement(); + statement.actions = Constants.COMMON_BUCKET_ACTIONS; + statement.effect = "Allow"; + statement.principal= new Principal("*"); + statement.resources = resources; + statement.sid = ""; + + statements.Add(statement); + + if (policy == PolicyType.READ_ONLY || policy == PolicyType.READ_WRITE) + { + statement = new Statement(); + statement.actions = Constants.READ_ONLY_BUCKET_ACTIONS; + statement.effect = "Allow"; + statement.principal = new Principal("*"); + statement.resources = resources; + statement.sid = ""; + + if (prefix != null && prefix.Length != 0) + { + ConditionKeyMap map = new ConditionKeyMap(); + map.put("s3:prefix", prefix); + statement.conditions = new ConditionMap("StringEquals",map); + } + + statements.Add(statement); + } + + if (policy == PolicyType.WRITE_ONLY || policy == PolicyType.READ_WRITE) + { + statement = new Statement(); + statement.actions = Constants.WRITE_ONLY_BUCKET_ACTIONS; + statement.effect = "Allow"; + statement.principal = new Principal("*"); + statement.resources = resources; + statement.sid = ""; + + statements.Add(statement); + } + + return statements; + } + + + /** + * Returns new object statements for given policy type. + */ + private List newObjectStatement(PolicyType policy, String prefix) + { + List statements = new List(); + + if (policy == PolicyType.NONE || bucketName == null || bucketName.Length == 0) + { + return statements; + } + + Resources resources = new Resources(Constants.AWS_RESOURCE_PREFIX + bucketName + "/" + prefix + "*"); + + Statement statement = new Statement(); + statement.effect = "Allow"; + statement.principal = new Principal("*"); + statement.resources = resources; + statement.sid = ""; + if (policy.Equals(PolicyType.READ_ONLY)) + { + statement.actions = Constants.READ_ONLY_OBJECT_ACTIONS; + } + else if (policy.Equals(PolicyType.WRITE_ONLY)) + { + statement.actions = Constants.WRITE_ONLY_OBJECT_ACTIONS; + } + else if (policy.Equals(PolicyType.READ_WRITE)) + { + statement.actions = Constants.READ_WRITE_OBJECT_ACTIONS(); + } + + statements.Add(statement); + return statements; + } + + + /** + * Returns new statements for given policy type. + */ + private List newStatements(PolicyType policy, String prefix) + { + List statements = this.newBucketStatement(policy, prefix); + List objectStatements = this.newObjectStatement(policy, prefix); + + statements.AddRange(objectStatements); + + return statements; + } + + + /** + * Returns whether statements are used by other than given prefix statements. + */ + //@JsonIgnore + private bool[] getInUsePolicy(string prefix) + { + string resourcePrefix = Constants.AWS_RESOURCE_PREFIX + bucketName + "/"; + string objectResource = Constants.AWS_RESOURCE_PREFIX + bucketName + "/" + prefix + "*"; + + bool readOnlyInUse = false; + bool writeOnlyInUse = false; + + foreach( Statement statement in statements) + { + if (!statement.resources.Contains(objectResource) + && statement.resources.startsWith(resourcePrefix).Count() != 0) + { + if (utils.isSupersetOf(statement.actions,Constants.READ_ONLY_OBJECT_ACTIONS)) + { + readOnlyInUse = true; + } + if (utils.isSupersetOf(statement.actions,Constants.WRITE_ONLY_OBJECT_ACTIONS)) + { + writeOnlyInUse = true; + } + } + + if (readOnlyInUse && writeOnlyInUse) + { + break; + } + } + + bool[] rv = { readOnlyInUse, writeOnlyInUse }; + return rv; + } + + + /** + * Returns all statements of given prefix. + */ + private void removeStatements(String prefix) + { + String bucketResource = Constants.AWS_RESOURCE_PREFIX + bucketName; + String objectResource = Constants.AWS_RESOURCE_PREFIX + bucketName + "/" + prefix + "*"; + bool[] inUse = getInUsePolicy(prefix); + bool readOnlyInUse = inUse[0]; + bool writeOnlyInUse = inUse[1]; + + List outList = new List(); + ISet s3PrefixValues = new HashSet(); + List readOnlyBucketStatements = new List(); + + foreach (Statement statement in statements) + { + if (!statement.isValid(bucketName)) + { + outList.Add(statement); + continue; + } + + if (statement.resources.Contains(bucketResource)) + { + if (statement.conditions != null) + { + statement.removeBucketActions(prefix, bucketResource, false, false); + } + else + { + statement.removeBucketActions(prefix, bucketResource, readOnlyInUse, writeOnlyInUse); + } + } + else if (statement.resources.Contains(objectResource)) + { + statement.removeObjectActions(objectResource); + } + + if (statement.actions.Count != 0) + { + if (statement.resources.Contains(bucketResource) + && (utils.isSupersetOf(statement.actions,Constants.READ_ONLY_BUCKET_ACTIONS)) + && statement.effect.Equals("Allow") + && statement.principal.aws().Contains("*")) + { + + if (statement.conditions != null) + { + ConditionKeyMap stringEqualsValue; + statement.conditions.TryGetValue("StringEquals",out stringEqualsValue); + if (stringEqualsValue != null) + { + ISet values; + stringEqualsValue.TryGetValue("s3:prefix",out values); + if (values != null) + { + foreach(string v in values) + { + s3PrefixValues.Add(bucketResource + "/" + v + "*"); + } + } + } + } + else if (s3PrefixValues.Count() != 0) + { + readOnlyBucketStatements.Add(statement); + continue; + } + } + + outList.Add(statement); + } + } + + bool skipBucketStatement = true; + String resourcePrefix = Constants.AWS_RESOURCE_PREFIX + bucketName + "/"; + foreach (Statement statement in outList) + { + ISet intersection = new HashSet(s3PrefixValues); + intersection.IntersectWith(statement.resources); + + if (statement.resources.startsWith(resourcePrefix).Count() != 0 + && intersection.Count() == 0) + { + skipBucketStatement = false; + break; + } + } + + foreach (Statement statement in readOnlyBucketStatements) + { + IList aws = statement.principal.aws(); + if (skipBucketStatement + && statement.resources.Contains(bucketResource) + && statement.effect.Equals("Allow") + && aws != null && aws.Contains("*") + && statement.conditions == null) + { + continue; + } + + outList.Add(statement); + } + + if (outList.Count() == 1) { + Statement statement = outList[0]; + IList aws = statement.principal.aws(); + if (statement.resources.Contains(bucketResource) + && (utils.isSupersetOf(statement.actions,Constants.COMMON_BUCKET_ACTIONS)) + && statement.effect.Equals("Allow") + && aws != null && aws.Contains("*") + && statement.conditions == null) + { + outList = new List(); + } + } + + statements = outList; + } + + + /** + * Appends given statement into statement list to have unique statements. + * - If statement already exists in statement list, it ignores. + * - If statement exists with different conditions, they are merged. + * - Else the statement is appended to statement list. + */ + private void appendStatement(Statement statement) + { + foreach (Statement s in statements) + { + IList aws = s.principal.aws(); + ConditionMap conditions = s.conditions; + + if ((utils.isSupersetOf(s.actions,statement.actions) + && s.effect.Equals(statement.effect) + && aws != null && (utils.isSupersetOf(aws,statement.principal.aws())) + && conditions != null && conditions.Equals(statement.conditions))) + { + s.resources.UnionWith(statement.resources); + return; + } + + if (s.resources.IsSupersetOf(statement.resources) + && s.effect.Equals(statement.effect) + && aws != null && (utils.isSupersetOf(aws,statement.principal.aws())) + && conditions != null && conditions.Equals(statement.conditions)) + { + s.actions.Union(statement.actions); + return; + } + + if (s.resources.IsSupersetOf(statement.resources) + && (utils.isSupersetOf(s.actions,statement.actions) + && s.effect.Equals(statement.effect) + && aws != null && utils.isSupersetOf(aws,statement.principal.aws()))) + { + if (conditions != null && conditions.Equals(statement.conditions)) + { + return; + } + + if (conditions != null && statement.conditions!= null) + { + conditions.putAll(statement.conditions); + return; + } + } + } + if (statement.actions != null && statement.resources != null && statement.actions.Count() != 0 && statement.resources.Count() != 0) + { + statements.Add(statement); + } + } + + + /** + * Appends new statements for given policy type. + */ + private void appendStatements(PolicyType policy, String prefix) + { + List appendStatements = newStatements(policy, prefix); + foreach (Statement statement in appendStatements) + { + appendStatement(statement); + } + } + + + /** + * Returns policy type of this bucket policy. + */ + // @JsonIgnore + public PolicyType getPolicy(string prefix) + { + string bucketResource = Constants.AWS_RESOURCE_PREFIX + bucketName; + string objectResource = Constants.AWS_RESOURCE_PREFIX + bucketName + "/" + prefix + "*"; + + bool bucketCommonFound = false; + bool bucketReadOnly = false; + bool bucketWriteOnly = false; + string matchedResource = ""; + bool objReadOnly = false; + bool objWriteOnly = false; + + foreach (Statement s in statements) + { + ISet matchedObjResources = new HashSet(); + if (s.resources.Contains(objectResource)) + { + matchedObjResources.Add(objectResource); + } + else + { + matchedObjResources = s.resources.match(objectResource); + } + + if (matchedObjResources.Count() != 0) + { + bool[] rv = s.getObjectPolicy(); + bool readOnly = rv[0]; + bool writeOnly = rv[1]; + + foreach (string resource in matchedObjResources) + { + if (matchedResource.Length < resource.Length) + { + objReadOnly = readOnly; + objWriteOnly = writeOnly; + matchedResource = resource; + } + else if (matchedResource.Length == resource.Length) + { + objReadOnly = objReadOnly || readOnly; + objWriteOnly = objWriteOnly || writeOnly; + matchedResource = resource; + } + } + } + else if (s.resources.Contains(bucketResource)) + { + bool[] rv = s.getBucketPolicy(prefix); + bool commonFound = rv[0]; + bool readOnly = rv[1]; + bool writeOnly = rv[2]; + bucketCommonFound = bucketCommonFound || commonFound; + bucketReadOnly = bucketReadOnly || readOnly; + bucketWriteOnly = bucketWriteOnly || writeOnly; + } + } + + if (bucketCommonFound) + { + if (bucketReadOnly && bucketWriteOnly && objReadOnly && objWriteOnly) + { + return PolicyType.READ_WRITE; + } + else if (bucketReadOnly && objReadOnly) + { + return PolicyType.READ_ONLY; + } + else if (bucketWriteOnly && objWriteOnly) + { + return PolicyType.WRITE_ONLY; + } + } + + return PolicyType.NONE; + } + + + /** + * Returns policy type of all prefixes. + */ + //@JsonIgnore + public Dictionary getPolicies() + { + Dictionary policyRules = new Dictionary(); + ISet objResources = new HashSet(); + + String bucketResource = Constants.AWS_RESOURCE_PREFIX + bucketName; + + // Search all resources related to objects policy + foreach (Statement s in statements) + { + objResources.UnionWith(s.resources.startsWith(bucketResource + "/")); + } + + // Pretend that policy resource as an actual object and fetch its policy + foreach (string r in objResources) + { + // Put trailing * if exists in asterisk + string asterisk = ""; + string resource = r; + if (r.EndsWith("*")) + { + resource = r.Substring(0, r.Length - 1); + asterisk = "*"; + } + + String objectPath = resource.Substring(bucketResource.Length + 1, resource.Length); + PolicyType policy = this.getPolicy(objectPath); + policyRules.Add(bucketName + "/" + objectPath + asterisk, policy); + } + + return policyRules; + } + + + /** + * Sets policy type for given prefix. + */ + // @JsonIgnore + public void setPolicy(PolicyType policy, String prefix) + { + if (statements == null) + { + statements = new List(); + } + + removeStatements(prefix); + appendStatements(policy, prefix); + } + } +} diff --git a/MinioCore2/DataModel/Policy/ConditionKeyMap.cs b/MinioCore2/DataModel/Policy/ConditionKeyMap.cs new file mode 100644 index 000000000..0e8d43271 --- /dev/null +++ b/MinioCore2/DataModel/Policy/ConditionKeyMap.cs @@ -0,0 +1,66 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System.Collections.Generic; +using System.Linq; + +namespace MinioCore2.DataModel +{ + internal class ConditionKeyMap:Dictionary> + { + public ConditionKeyMap(ConditionKeyMap map=null):base(map) + { + } + public ConditionKeyMap(string key, ISet value) + { + this.Add(key, value); + } + public ISet put(string key, string value) + { + ISet set = new HashSet(); + set.Add(value); + this.Add(key, set); + return set; + } + public ISet put(string key, ISet value) + { + ISet existingValue; + this.TryGetValue(key, out existingValue); + if (existingValue == null) + { + existingValue = new HashSet(); + } + existingValue.UnionWith(value); + this[key] = existingValue; + return existingValue; + } + public void remove(string key,ISet value) + { + ISet existingValue; + this.TryGetValue(key, out existingValue); + if (existingValue == null) + { + return; + } + existingValue.Except(value); + if (existingValue.Count == 0) + { + this.Remove(key); + } + this[key] = existingValue; + } + + } +} diff --git a/MinioCore2/DataModel/Policy/ConditionMap.cs b/MinioCore2/DataModel/Policy/ConditionMap.cs new file mode 100644 index 000000000..f91960480 --- /dev/null +++ b/MinioCore2/DataModel/Policy/ConditionMap.cs @@ -0,0 +1,58 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System.Collections.Generic; + +namespace MinioCore2.DataModel +{ + internal class ConditionMap: Dictionary + { + public ConditionMap(string key=null,ConditionKeyMap value=null): base() + { + if (key != null && value != null) + { + this.Add(key, value); + } + } + + public ConditionKeyMap put(string key,ConditionKeyMap value) + { + ConditionKeyMap existingValue; + base.TryGetValue(key,out existingValue); + if (existingValue == null) + { + existingValue = new ConditionKeyMap(value); + } + else + { + foreach (var item in value) + { + existingValue.Add(item.Key, item.Value); + } + } + this[key] = existingValue; + return existingValue; + } + public void putAll(ConditionMap cmap) + { + foreach (var item in cmap) + { + this[item.Key] = item.Value; + } + } + + } +} diff --git a/MinioCore2/DataModel/Policy/Constants.cs b/MinioCore2/DataModel/Policy/Constants.cs new file mode 100644 index 000000000..fa3ee1d92 --- /dev/null +++ b/MinioCore2/DataModel/Policy/Constants.cs @@ -0,0 +1,69 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MinioCore2.Policy +{ + class Constants + { + // Resource prefix for all aws resources. + public static readonly String AWS_RESOURCE_PREFIX = "arn:aws:s3:::"; + + // Common bucket actions for both read and write policies. + public static readonly List COMMON_BUCKET_ACTIONS = new List() { "s3:GetBucketLocation" }; + + // Read only bucket actions. + public static readonly List READ_ONLY_BUCKET_ACTIONS = new List() { "s3:ListBucket"}; + + // Write only bucket actions. + public static readonly List WRITE_ONLY_BUCKET_ACTIONS = + new List() { "s3:ListBucketMultipartUploads" }; + + // Read only object actions. + public static readonly List READ_ONLY_OBJECT_ACTIONS = new List() { "s3:GetObject" }; + + // Write only object actions. + public static readonly List WRITE_ONLY_OBJECT_ACTIONS = + new List() { "s3:AbortMultipartUpload", + "s3:DeleteObject", + "s3:ListMultipartUploadParts", + "s3:PutObject" }; + + // Read and write object actions. + public static IList READ_WRITE_OBJECT_ACTIONS() + { + IList res = new List(); + res.Union(READ_ONLY_OBJECT_ACTIONS); + res.Union(WRITE_ONLY_OBJECT_ACTIONS); + return res; + } + // All valid bucket and object actions. + + public static List VALID_ACTIONS() + { + List res = new List(); + res.Union(COMMON_BUCKET_ACTIONS); + res.Union(READ_ONLY_BUCKET_ACTIONS); + res.Union(WRITE_ONLY_BUCKET_ACTIONS); + res.Union(READ_WRITE_OBJECT_ACTIONS()); + return res; + } + + } +} diff --git a/MinioCore2/DataModel/Policy/PolicyType.cs b/MinioCore2/DataModel/Policy/PolicyType.cs new file mode 100644 index 000000000..58d286f0e --- /dev/null +++ b/MinioCore2/DataModel/Policy/PolicyType.cs @@ -0,0 +1,36 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace MinioCore2.DataModel +{ + + public class PolicyType + { + private PolicyType(string value) { Value = value; } + public string Value { get; set; } + + public static PolicyType NONE { get { return new PolicyType("none"); } } + public static PolicyType READ_ONLY { get { return new PolicyType("readonly"); } } + public static PolicyType READ_WRITE { get { return new PolicyType("readwrite"); } } + public static PolicyType WRITE_ONLY { get { return new PolicyType("writeonly"); } } + + public override string ToString() + { + return string.Format("{0}", this.Value); + } + } + +} diff --git a/MinioCore2/DataModel/Policy/Principal.cs b/MinioCore2/DataModel/Policy/Principal.cs new file mode 100644 index 000000000..642edd357 --- /dev/null +++ b/MinioCore2/DataModel/Policy/Principal.cs @@ -0,0 +1,58 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System.Collections.Generic; +using System.Runtime.Serialization; +using Newtonsoft.Json.Serialization; +using Newtonsoft.Json; +using MinioCore2.DataModel.Policy; + +namespace MinioCore2.DataModel +{ + [DataContract] + internal class Principal + { + [JsonProperty("AWS")] + [JsonConverter(typeof(SingleOrArrayConverter))] + + internal IList awsList { get; set; } + [JsonProperty("CanonicalUser")] + internal IList canonicalUser { get; set; } + public Principal() + { + + } + public Principal(string aws=null) + { + this.awsList = new List(); + if (aws != null) + { + this.awsList.Add(aws); + } + } + public void CanonicalUser(string val) + { + this.canonicalUser = new List(); + if (val != null) + { + this.canonicalUser.Add(val); + } + } + public IList aws() + { + return this.awsList; + } + } +} diff --git a/MinioCore2/DataModel/Policy/PrincipalJsonConverter.cs b/MinioCore2/DataModel/Policy/PrincipalJsonConverter.cs new file mode 100644 index 000000000..284e5f4ba --- /dev/null +++ b/MinioCore2/DataModel/Policy/PrincipalJsonConverter.cs @@ -0,0 +1,65 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using Newtonsoft.Json; + +namespace MinioCore2.DataModel.Policy +{ + class PrincipalJsonConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + throw new NotImplementedException(); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + object retVal = new Object(); + + if (reader.TokenType == JsonToken.StartObject) + { + Principal instance = (Principal)serializer.Deserialize(reader, typeof(Principal)); + retVal = instance ; + + } + else if (reader.TokenType == JsonToken.String) + { + if (reader.Value.Equals("*")) + { + Principal instance = new Principal("AWS"); + instance.awsList.Add(reader.Value.ToString()); + instance.CanonicalUser(reader.Value.ToString()); + retVal = instance; + } + } + else if (reader.TokenType == JsonToken.StartArray) + { + retVal = serializer.Deserialize(reader, objectType); + } + return retVal; + + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value != null) + { + serializer.Serialize(writer, value); + } + } +} +} diff --git a/MinioCore2/DataModel/Policy/ResourceJsonConverter.cs b/MinioCore2/DataModel/Policy/ResourceJsonConverter.cs new file mode 100644 index 000000000..4a6993399 --- /dev/null +++ b/MinioCore2/DataModel/Policy/ResourceJsonConverter.cs @@ -0,0 +1,71 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace MinioCore2.DataModel.Policy +{ + class ResourceJsonConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + throw new NotImplementedException(); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + object retVal = new Object(); + if (reader.TokenType == JsonToken.StartObject) + { + Resources instance = (Resources)serializer.Deserialize(reader, typeof(Resources)); + retVal = instance ; + + } + else if (reader.TokenType == JsonToken.String) + { + Resources instance = new Resources(); + instance.Add(reader.Value.ToString()); + retVal = instance; + + } + else if (reader.TokenType == JsonToken.StartArray) + { + // retVal = serializer.Deserialize(reader, objectType); + JArray array = JArray.Load(reader); + var rs = array.ToObject>(); + Resources instance = new Resources(); + foreach (var el in rs) + { + instance.Add(el); + } + retVal = instance; + } + return retVal; + + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value != null) + { + serializer.Serialize(writer, value); + } + } + } +} diff --git a/MinioCore2/DataModel/Policy/Resources.cs b/MinioCore2/DataModel/Policy/Resources.cs new file mode 100644 index 000000000..b0e762d88 --- /dev/null +++ b/MinioCore2/DataModel/Policy/Resources.cs @@ -0,0 +1,90 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace MinioCore2.DataModel +{ + internal class Resources : HashSet + { + public Resources(string resource=null) : base() + { + if (resource != null) + { + Add(resource); + } + } + public ISet startsWith(string resourcePrefix) + { + HashSet res = new HashSet(); + foreach(string resource in this) + { + if (resource.StartsWith(resourcePrefix)) + { + res.Add(resource); + } + } + return res; + } + private bool matched(string pattern, string resource) + { + if (pattern.Length == 0) + { + return resource.Equals(pattern); + } + if (pattern.Equals("*")) + { + return true; + } + string[] parts = Regex.Split(pattern, "\\*"); + if (parts.Length == 1) + { + return resource.Equals(parts[0]); + } + bool tglob = pattern.EndsWith("*"); + int end = parts.Length - 1; + + if (!resource.StartsWith(parts[0])) + { + return false; + } + for (int i = 1; i < end; i++) + { + if (!resource.Contains(parts[i])) + { + return false; + } + int idx = resource.IndexOf(parts[i]) + parts[i].Length; + resource = resource.Substring(idx); + } + return tglob || resource.EndsWith(parts[end]); + + } + public ISet match(string resource) + { + ISet res = new HashSet(); + foreach (string pattern in this) + { + if (matched(pattern,resource)) + { + res.Add(pattern); + } + } + return res; + } + } +} diff --git a/MinioCore2/DataModel/Policy/SingleOrArrayConverter.cs b/MinioCore2/DataModel/Policy/SingleOrArrayConverter.cs new file mode 100644 index 000000000..18c877794 --- /dev/null +++ b/MinioCore2/DataModel/Policy/SingleOrArrayConverter.cs @@ -0,0 +1,53 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace MinioCore2.DataModel.Policy +{ + + class SingleOrArrayConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return (objectType == typeof(List)); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + JToken token = JToken.Load(reader); + if (token.Type == JTokenType.Array) + { + return token.ToObject>(); + } + return new List { token.ToObject() }; + } + + public override bool CanWrite + { + get { return false; } + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + throw new NotImplementedException(); + } + } +} + diff --git a/MinioCore2/DataModel/Policy/Statement.cs b/MinioCore2/DataModel/Policy/Statement.cs new file mode 100644 index 000000000..ad69c600a --- /dev/null +++ b/MinioCore2/DataModel/Policy/Statement.cs @@ -0,0 +1,287 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using MinioCore2.Policy; +using MinioCore2.DataModel.Policy; + +namespace MinioCore2.DataModel +{ + + internal class Statement + { + [JsonProperty("Action")] + [JsonConverter(typeof(SingleOrArrayConverter))] + public IList actions { get; set; } + [JsonProperty("Condition")] + public ConditionMap conditions { get; set; } + + [JsonProperty("Effect")] + public string effect { get; set; } + + [JsonProperty("Principal")] + [JsonConverter(typeof(PrincipalJsonConverter))] + public Principal principal { get; set; } + + [JsonProperty("Resource")] + [JsonConverter(typeof(ResourceJsonConverter))] + public Resources resources { get; set; } + + [JsonProperty("Sid")] + public string sid { get; set; } + /** + * Returns whether given statement is valid to process for given bucket name. + */ + public bool isValid(string bucketName) + { + ISet intersection = new HashSet(this.actions); + intersection.IntersectWith(Constants.VALID_ACTIONS()); + if (intersection.Count == 0) + { + return false; + } + if (!this.effect.Equals("Allow")) + { + return false; + } + + IList aws = this.principal.aws(); + if (aws == null || !aws.Contains("*")) + { + return false; + } + + string bucketResource = Constants.AWS_RESOURCE_PREFIX + bucketName; + + if (this.resources.Contains(bucketResource)) + { + return true; + } + + if (this.resources.startsWith(bucketResource + "/").Count == 0) + { + return false; + } + + return true; + } + + /** + * Removes object actions for given object resource. + */ + public void removeObjectActions(string objectResource) + { + if (this.conditions != null) + { + return; + } + + if (this.resources.Count > 1) + { + this.resources.Remove(objectResource); + } + else + { + this.actions.Except(Constants.READ_WRITE_OBJECT_ACTIONS()); + } + } + private void removeReadOnlyBucketActions(string prefix) + { + if (!utils.isSupersetOf(this.actions,Constants.READ_ONLY_BUCKET_ACTIONS)) + { + return; + } + + this.actions.Except(Constants.READ_ONLY_BUCKET_ACTIONS); + + if (this.conditions == null) + { + return; + } + + if (prefix == null || prefix.Count() == 0) + { + return; + } + + ConditionKeyMap stringEqualsValue; + this.conditions.TryGetValue("StringEquals", out stringEqualsValue); + if (stringEqualsValue == null) + { + return; + } + + ISet values; + stringEqualsValue.TryGetValue("s3:prefix", out values); + if (values != null) + { + values.Remove(prefix); + } + + if (values == null || values.Count == 0) + { + stringEqualsValue.Remove("s3:prefix"); + } + + if (stringEqualsValue.Count == 0) + { + this.conditions.Remove("StringEquals"); + } + + if (this.conditions.Count == 0) + { + this.conditions = null; + } + } + + private void removeWriteOnlyBucketActions() + { + if (this.conditions == null) + { + this.actions.Except(Constants.WRITE_ONLY_BUCKET_ACTIONS); + } + } + + /** + * Removes bucket actions for given prefix and bucketResource. + */ + public void removeBucketActions(string prefix, string bucketResource, + bool readOnlyInUse, bool writeOnlyInUse) + { + if (this.resources.Count > 1) + { + this.resources.Remove(bucketResource); + return; + } + + if (!readOnlyInUse) + { + removeReadOnlyBucketActions(prefix); + } + + if (!writeOnlyInUse) + { + removeWriteOnlyBucketActions(); + } + + return; + } + + /** + * Returns bucket policy types for given prefix. + */ + // [JsonIgnore] + public bool[] getBucketPolicy(string prefix) + { + bool commonFound = false; + bool readOnly = false; + bool writeOnly = false; + + IList aws = this.principal.aws(); + if (!(this.effect.Equals("Allow") && aws != null && aws.Contains("*"))) + { + return new bool[] { commonFound, readOnly, writeOnly }; + } + + if (utils.isSupersetOf(this.actions,Constants.COMMON_BUCKET_ACTIONS) && this.conditions == null) + { + commonFound = true; + } + + if (utils.isSupersetOf(this.actions,Constants.WRITE_ONLY_BUCKET_ACTIONS) && this.conditions == null) + { + writeOnly = true; + } + + if (utils.isSupersetOf(this.actions,Constants.READ_ONLY_BUCKET_ACTIONS)) + { + if (prefix != null && prefix.Count() != 0 && this.conditions != null) + { + ConditionKeyMap stringEqualsValue; + this.conditions.TryGetValue("StringEquals", out stringEqualsValue); + if (stringEqualsValue != null) + { + ISet s3PrefixValues; + stringEqualsValue.TryGetValue("s3:prefix", out s3PrefixValues); + if (s3PrefixValues != null && s3PrefixValues.Contains(prefix)) + { + readOnly = true; + } + } + else + { + ConditionKeyMap stringNotEqualsValue; + this.conditions.TryGetValue("StringNotEquals", out stringNotEqualsValue); + if (stringNotEqualsValue != null) + { + ISet s3PrefixValues; + stringNotEqualsValue.TryGetValue("s3:prefix", out s3PrefixValues); + if (s3PrefixValues != null && !s3PrefixValues.Contains(prefix)) + { + readOnly = true; + } + } + } + } + else if ((prefix == null || prefix.Count() == 0) && this.conditions == null) + { + readOnly = true; + } + else if (prefix != null && prefix.Count() != 0 && this.conditions == null) + { + readOnly = true; + } + } + + return new bool[] { commonFound, readOnly, writeOnly }; + } + + /** + * Returns object policy types. + */ + // [JsonIgnore] + public bool[] getObjectPolicy() + { + bool readOnly = false; + bool writeOnly = false; + + IList aws = null; + if (this.principal != null) + { + aws = this.principal.aws(); + } + + if (this.effect.Equals("Allow") + && aws != null && aws.Contains("*") + && this.conditions == null) + { + if (utils.isSupersetOf(this.actions,Constants.READ_ONLY_OBJECT_ACTIONS)) + { + readOnly = true; + } + if (utils.isSupersetOf(this.actions,Constants.WRITE_ONLY_OBJECT_ACTIONS)) + { + writeOnly = true; + } + } + + return new bool[] { readOnly, writeOnly }; + } + + } +} diff --git a/MinioCore2/DataModel/Policy/StatementJsonConverter.cs b/MinioCore2/DataModel/Policy/StatementJsonConverter.cs new file mode 100644 index 000000000..14614540f --- /dev/null +++ b/MinioCore2/DataModel/Policy/StatementJsonConverter.cs @@ -0,0 +1,52 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Linq; +using System.Reflection; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace MinioCore2.DataModel.Policy +{ + class StatementJsonConverter : JsonConverter + { + + public override bool CanConvert(Type objectType) + { + return typeof(Statement).GetTypeInfo().IsInstanceOfType(objectType); + + //KP return typeof(Statement).IsAssignableFrom(objectType); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + JObject jsonObject = JObject.Load(reader); + var properties = jsonObject.Properties().ToList(); + return new StatementJsonConverter + { + //Name = properties[0].Name.Replace("$", ""), + //Value = (string)properties[0].Value + }; + + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + throw new NotImplementedException(); + } + } +} diff --git a/MinioCore2/DataModel/PostPolicy.cs b/MinioCore2/DataModel/PostPolicy.cs new file mode 100644 index 000000000..61b3d8b93 --- /dev/null +++ b/MinioCore2/DataModel/PostPolicy.cs @@ -0,0 +1,243 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.IO; +using System.Text; +using System.Collections.Generic; + +namespace MinioCore2.DataModel +{ + public class PostPolicy + { + private DateTime expiration; + private List> policies = + new List>(); + private Dictionary formData = new Dictionary(); + public string Key { get; private set; } + public string Bucket { get; private set; } + + /// + /// Set expiration policy. + /// + /// Expiration time for the policy + public void SetExpires(DateTime expiration) + { + this.expiration = expiration; + } + + /// + /// Set key policy. + /// + /// Object name for the policy + public void SetKey(string key) + { + if (string.IsNullOrEmpty(key)) + { + throw new ArgumentException("Object key cannot be null or empty"); + } + this.policies.Add(new Tuple("eq", "$key", key)); + this.formData.Add("key", key); + this.Key = key; + } + + /// + /// Set key prefix policy. + /// + /// Object name prefix for the policy + public void SetKeyStartsWith(string keyStartsWith) + { + if (string.IsNullOrEmpty(keyStartsWith)) + { + throw new ArgumentException("Object key prefix cannot be null or empty"); + } + this.policies.Add(new Tuple("starts-with", "$key", keyStartsWith)); + this.formData.Add("key", keyStartsWith); + } + + /// + /// Set bucket policy. + /// + /// Bucket name for the policy + public void SetBucket(string bucket) + { + if (string.IsNullOrEmpty(bucket)) + { + throw new ArgumentException("Bucket name cannot be null or empty"); + } + this.policies.Add(new Tuple("eq", "$bucket", bucket)); + this.formData.Add("bucket", bucket); + this.Bucket = bucket; + } + + /// + /// Set content type policy. + /// + /// ContentType for the policy + public void SetcontentType(string contentType) + { + if (string.IsNullOrEmpty(contentType)) + { + throw new ArgumentException("Content-Type argument cannot be null or empty"); + } + this.policies.Add(new Tuple("eq", "$Content-Type", contentType)); + this.formData.Add("Content-Type", contentType); + } + + /// + /// Set signature algorithm policy. + /// + /// Set signature algorithm used for the policy + public void SetAlgorithm(string algorithm) + { + if (string.IsNullOrEmpty(algorithm)) + { + throw new ArgumentException("Algorithm argument cannot be null or empty"); + } + this.policies.Add(new Tuple("eq", "$x-amz-algorithm", algorithm)); + this.formData.Add("x-amz-algorithm", algorithm); + } + + /// + /// Set credential policy. + /// + /// Set credential string for the policy + public void SetCredential(string credential) + { + if (string.IsNullOrEmpty(credential)) + { + throw new ArgumentException("credential argument cannot be null or empty"); + } + this.policies.Add(new Tuple("eq", "$x-amz-credential", credential)); + this.formData.Add("x-amz-credential", credential); + } + + /// + /// Set date policy. + /// + /// Set date for the policy + public void SetDate(DateTime date) + { + string dateStr = date.ToString("yyyyMMddTHHmmssZ"); + this.policies.Add(new Tuple("eq", "$x-amz-date", dateStr)); + this.formData.Add("x-amz-date", dateStr); + } + + /// + /// Set base64 encoded policy to form dictionary. + /// + /// Base64 encoded policy + public void SetPolicy(string policyBase64) + { + this.formData.Add("policy", policyBase64); + } + + /// + /// Set computed signature for the policy to form dictionary. + /// + /// Computed signature + public void SetSignature(string signature) + { + this.formData.Add("x-amz-signature", signature); + } + + /// + /// Serialize policy into JSON string. + /// + /// Serialized JSON policy + private byte[] marshalJSON() + { + List policyList = new List(); + StringBuilder sb = new StringBuilder(); + + foreach (var policy in this.policies) + { + policyList.Add("[\"" + policy.Item1 + "\",\"" + policy.Item2 + "\",\"" + policy.Item3+"\"]"); + } + // expiration and conditions will never be empty because of checks at PresignedPostPolicy() + sb.Append("{"); + sb.Append("\"expiration\":\"").Append(this.expiration.ToString("yyyy-MM-ddTHH:mm:ss.000Z")).Append("\"").Append(","); + sb.Append("\"conditions\":[").Append(String.Join(",", policyList)).Append("]"); + sb.Append("}"); + return System.Text.Encoding.UTF8.GetBytes(sb.ToString() as string); + } + + /// + /// Compute base64 encoded form of JSON policy. + /// + /// Base64 encoded string of JSON policy + public string Base64() + { + byte[] policyStrBytes = this.marshalJSON(); + return Convert.ToBase64String(policyStrBytes); + } + + /// + /// Verify if bucket is set in policy. + /// + /// true if bucket is set + public bool IsBucketSet() + { + string value = ""; + if (this.formData.TryGetValue("bucket", out value)) + { + if (!string.IsNullOrEmpty(value)) + { + return true; + } + } + return false; + } + + /// + /// Verify if key is set in policy. + /// + /// true if key is set + public bool IsKeySet() + { + string value = ""; + if (this.formData.TryGetValue("key", out value)) + { + if (!string.IsNullOrEmpty(value)) + { + return true; + } + } + return false; + } + + /// + /// Verify if expiration is set in policy. + /// + /// true if expiration is set + public bool IsExpirationSet() + { + if (!string.IsNullOrEmpty(this.expiration.ToString())) + { + return true; + } + return false; + } + + /// + /// Get the populated dictionary of policy data. + /// + /// Dictionary of policy data + public Dictionary GetFormData() { + return this.formData; + } + } +} diff --git a/MinioCore2/DataModel/Prefix.cs b/MinioCore2/DataModel/Prefix.cs new file mode 100644 index 000000000..eb4ffd637 --- /dev/null +++ b/MinioCore2/DataModel/Prefix.cs @@ -0,0 +1,28 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Xml.Serialization; + +namespace MinioCore2.DataModel +{ + [Serializable] + public class Prefix + { + [XmlAttribute("Prefix")] + public string Name { get; set; } + } +} diff --git a/MinioCore2/DataModel/Upload.cs b/MinioCore2/DataModel/Upload.cs new file mode 100644 index 000000000..a93653808 --- /dev/null +++ b/MinioCore2/DataModel/Upload.cs @@ -0,0 +1,25 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace MinioCore2.DataModel +{ + public class Upload + { + public string Key { get; set; } + public string UploadId { get; set; } + public string Initiated { get; set; } + } +} diff --git a/MinioCore2/Exceptions/AccessDeniedException.cs b/MinioCore2/Exceptions/AccessDeniedException.cs new file mode 100644 index 000000000..79381fd56 --- /dev/null +++ b/MinioCore2/Exceptions/AccessDeniedException.cs @@ -0,0 +1,37 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; + +namespace MinioCore2.Exceptions +{ + [Serializable] + public class AccessDeniedException : MinioException + { + public AccessDeniedException() + { + } + + public AccessDeniedException(string message) : base(message) + { + } + + public override string ToString() + { + return base.ToString(); + } + } +} diff --git a/MinioCore2/Exceptions/BucketNotFoundException.cs b/MinioCore2/Exceptions/BucketNotFoundException.cs new file mode 100644 index 000000000..00aa485db --- /dev/null +++ b/MinioCore2/Exceptions/BucketNotFoundException.cs @@ -0,0 +1,38 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; + +namespace MinioCore2.Exceptions +{ + [Serializable] + public class BucketNotFoundException : MinioException + { + private string bucketName; + public BucketNotFoundException() + { + + } + public BucketNotFoundException(string bucketName, string message) : base(message) + { + this.bucketName = bucketName; + } + public override string ToString() + { + return this.bucketName + ": " + base.ToString(); + } + } +} diff --git a/MinioCore2/Exceptions/ConnectionException.cs b/MinioCore2/Exceptions/ConnectionException.cs new file mode 100644 index 000000000..1dd19ef34 --- /dev/null +++ b/MinioCore2/Exceptions/ConnectionException.cs @@ -0,0 +1,25 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace MinioCore2.Exceptions +{ + public class ConnectionException : MinioException + { + public ConnectionException(string message) : base(message) + { + } + } +} diff --git a/MinioCore2/Exceptions/EntityTooLargeException.cs b/MinioCore2/Exceptions/EntityTooLargeException.cs new file mode 100644 index 000000000..b6f2fd710 --- /dev/null +++ b/MinioCore2/Exceptions/EntityTooLargeException.cs @@ -0,0 +1,26 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace MinioCore2.Exceptions +{ + class EntityTooLargeException : MinioException + { + + public EntityTooLargeException(string message) : base(message) + { + } + } +} diff --git a/MinioCore2/Exceptions/ErrorResponse.cs b/MinioCore2/Exceptions/ErrorResponse.cs new file mode 100644 index 000000000..533928b56 --- /dev/null +++ b/MinioCore2/Exceptions/ErrorResponse.cs @@ -0,0 +1,35 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Xml.Serialization; + +namespace MinioCore2.Exceptions +{ + [Serializable] + [XmlRoot(ElementName="Error", Namespace = "")] + public class ErrorResponse + { + public string Code { get; set; } + public string Message { get; set; } + public string RequestId { get; set; } + public string HostId { get; set; } + public string Resource { get; set; } + public string BucketName { get; set; } + public string Key { get; set; } + public string BucketRegion { get; set; } + } +} diff --git a/MinioCore2/Exceptions/ForbiddenException.cs b/MinioCore2/Exceptions/ForbiddenException.cs new file mode 100644 index 000000000..a3a755892 --- /dev/null +++ b/MinioCore2/Exceptions/ForbiddenException.cs @@ -0,0 +1,30 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace MinioCore2.Exceptions +{ + public class ForbiddenException : MinioException + { + public ForbiddenException(string message) : base(message) + { + } + + public override string ToString() + { + return base.ToString(); + } + } +} diff --git a/MinioCore2/Exceptions/InternalClientException.cs b/MinioCore2/Exceptions/InternalClientException.cs new file mode 100644 index 000000000..aa10a3bd2 --- /dev/null +++ b/MinioCore2/Exceptions/InternalClientException.cs @@ -0,0 +1,25 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace MinioCore2.Exceptions +{ + public class InternalClientException : MinioException + { + public InternalClientException(string message) : base(message) + { + } + } +} diff --git a/MinioCore2/Exceptions/InternalServerException.cs b/MinioCore2/Exceptions/InternalServerException.cs new file mode 100644 index 000000000..cf579a7ff --- /dev/null +++ b/MinioCore2/Exceptions/InternalServerException.cs @@ -0,0 +1,30 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace MinioCore2.Exceptions +{ + public class InternalServerException : MinioException + { + public InternalServerException(string message) : base(message) + { + } + + public override string ToString() + { + return base.ToString(); + } + } +} diff --git a/MinioCore2/Exceptions/InvalidBucketNameException.cs b/MinioCore2/Exceptions/InvalidBucketNameException.cs new file mode 100644 index 000000000..2ffbbbcb8 --- /dev/null +++ b/MinioCore2/Exceptions/InvalidBucketNameException.cs @@ -0,0 +1,33 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace MinioCore2.Exceptions +{ + public class InvalidBucketNameException : MinioException + { + private string bucketName; + + public InvalidBucketNameException(string bucketName, string message) : base(message) + { + this.bucketName = bucketName; + } + + public override string ToString() + { + return this.bucketName + ": " + base.ToString(); + } + } +} diff --git a/MinioCore2/Exceptions/InvalidContentLengthException.cs b/MinioCore2/Exceptions/InvalidContentLengthException.cs new file mode 100644 index 000000000..2081eaca1 --- /dev/null +++ b/MinioCore2/Exceptions/InvalidContentLengthException.cs @@ -0,0 +1,34 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace MinioCore2.Exceptions +{ + class InvalidContentLengthException :MinioException + { + private string bucketName; + private string objectName; + public InvalidContentLengthException(string bucketName, string objectName, string message) : base(message) + { + this.bucketName = bucketName; + this.objectName = objectName; + } + + public override string ToString() + { + return this.bucketName + " :" + this.objectName + ": " + base.ToString(); + } + } +} diff --git a/MinioCore2/Exceptions/InvalidEndpointException.cs b/MinioCore2/Exceptions/InvalidEndpointException.cs new file mode 100644 index 000000000..3ad67d464 --- /dev/null +++ b/MinioCore2/Exceptions/InvalidEndpointException.cs @@ -0,0 +1,44 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace MinioCore2.Exceptions +{ + public class InvalidEndpointException : MinioException + { + private string endpoint; + + public InvalidEndpointException(string endpoint, string message) : base(message) + { + this.endpoint = endpoint; + } + + public InvalidEndpointException(string message) : base(message) + { + } + + public override string ToString() + { + if (string.IsNullOrEmpty(this.endpoint)) + { + return base.ToString(); + } + else + { + return this.endpoint + ": " + base.ToString(); + } + } + } +} diff --git a/MinioCore2/Exceptions/InvalidKeyNameException.cs b/MinioCore2/Exceptions/InvalidKeyNameException.cs new file mode 100644 index 000000000..4a2bfc8a2 --- /dev/null +++ b/MinioCore2/Exceptions/InvalidKeyNameException.cs @@ -0,0 +1,30 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace MinioCore2.Exceptions +{ + public class InvalidKeyNameException : MinioException + { + public InvalidKeyNameException(string message) : base(message) + { + } + + public override string ToString() + { + return base.ToString(); + } + } +} diff --git a/MinioCore2/Exceptions/InvalidObjectNameException.cs b/MinioCore2/Exceptions/InvalidObjectNameException.cs new file mode 100644 index 000000000..422e68932 --- /dev/null +++ b/MinioCore2/Exceptions/InvalidObjectNameException.cs @@ -0,0 +1,33 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace MinioCore2.Exceptions +{ + class InvalidObjectNameException : MinioException + { + private string objectName; + + public InvalidObjectNameException(string objectName, string message) : base(message) + { + this.objectName = objectName; + } + + public override string ToString() + { + return this.objectName + ": " + base.ToString(); + } + } +} diff --git a/MinioCore2/Exceptions/InvalidObjectPrefixException.cs b/MinioCore2/Exceptions/InvalidObjectPrefixException.cs new file mode 100644 index 000000000..81d968e2d --- /dev/null +++ b/MinioCore2/Exceptions/InvalidObjectPrefixException.cs @@ -0,0 +1,33 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace MinioCore2.Exceptions +{ + class InvalidObjectPrefixException : MinioException + { + private string objectPrefix; + + public InvalidObjectPrefixException(string objectPrefix, string message) : base(message) + { + this.objectPrefix = objectPrefix; + } + + public override string ToString() + { + return this.objectPrefix + ": " + base.ToString(); + } + } +} diff --git a/MinioCore2/Exceptions/MaxBucketsReachedException.cs b/MinioCore2/Exceptions/MaxBucketsReachedException.cs new file mode 100644 index 000000000..66de4b30a --- /dev/null +++ b/MinioCore2/Exceptions/MaxBucketsReachedException.cs @@ -0,0 +1,30 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace MinioCore2.Exceptions +{ + public class MaxBucketsReachedException : MinioException + { + public MaxBucketsReachedException(string message) : base(message) + { + } + + public override string ToString() + { + return base.ToString(); + } + } +} diff --git a/MinioCore2/Exceptions/MethodNotAllowedException.cs b/MinioCore2/Exceptions/MethodNotAllowedException.cs new file mode 100644 index 000000000..ddc4c3a6c --- /dev/null +++ b/MinioCore2/Exceptions/MethodNotAllowedException.cs @@ -0,0 +1,30 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace MinioCore2.Exceptions +{ + public class MethodNotAllowedException : MinioException + { + public MethodNotAllowedException(string message) : base(message) + { + } + + public override string ToString() + { + return base.ToString(); + } + } +} diff --git a/MinioCore2/Exceptions/MinioException.cs b/MinioCore2/Exceptions/MinioException.cs new file mode 100644 index 000000000..279d75dbb --- /dev/null +++ b/MinioCore2/Exceptions/MinioException.cs @@ -0,0 +1,50 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using RestSharp; + +namespace MinioCore2.Exceptions +{ + [Serializable] + public class MinioException : Exception + { + public string message { get; private set; } + public IRestResponse response { get; private set; } + public MinioException(IRestResponse response) + : base($"Minio API responded with status code={response.StatusCode}, response={response.ErrorMessage}, content={response.Content}") + { + this.response = response; + + } + public MinioException() + { + + } + public MinioException(string message) : base($"Minio API responded with message={message}") + { + this.message = message; + } + + public ErrorResponse Response { get; set; } + public string XmlError { get; set; } + + public override string ToString() + { + return this.message + ": " + base.ToString(); + } + } +} diff --git a/MinioCore2/Exceptions/ObjectNotFoundException.cs b/MinioCore2/Exceptions/ObjectNotFoundException.cs new file mode 100644 index 000000000..f0a32f6d5 --- /dev/null +++ b/MinioCore2/Exceptions/ObjectNotFoundException.cs @@ -0,0 +1,33 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace MinioCore2.Exceptions +{ + public class ObjectNotFoundException : MinioException + { + private string objectName; + + public ObjectNotFoundException(string objectName, string message) : base(message) + { + this.objectName = objectName; + } + + public override string ToString() + { + return this.objectName + ": " + base.ToString(); + } + } +} diff --git a/MinioCore2/Exceptions/RedirectionException.cs b/MinioCore2/Exceptions/RedirectionException.cs new file mode 100644 index 000000000..48318fe7d --- /dev/null +++ b/MinioCore2/Exceptions/RedirectionException.cs @@ -0,0 +1,30 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace MinioCore2.Exceptions +{ + public class RedirectionException : MinioException + { + public RedirectionException(string message) : base(message) + { + } + + public override string ToString() + { + return base.ToString(); + } + } +} diff --git a/MinioCore2/Exceptions/UnexpectedShortReadException.cs b/MinioCore2/Exceptions/UnexpectedShortReadException.cs new file mode 100644 index 000000000..0d8e8dbd6 --- /dev/null +++ b/MinioCore2/Exceptions/UnexpectedShortReadException.cs @@ -0,0 +1,31 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace MinioCore2.Exceptions +{ + public class UnexpectedShortReadException : MinioException + { + + public UnexpectedShortReadException(string message) : base(message) + { + } + + public override string ToString() + { + return base.ToString(); + } + } +} diff --git a/MinioCore2/Helper/Constants.cs b/MinioCore2/Helper/Constants.cs new file mode 100644 index 000000000..e10ede638 --- /dev/null +++ b/MinioCore2/Helper/Constants.cs @@ -0,0 +1,48 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MinioCore2.Helper +{ + static class Constants + { + // Maximum number of parts. + public static int MaxParts = 10000; + // Minimum part size. + public static long MinimumPartSize = 5 * 1024L * 1024L; + // Maximum part size. + public static long MaximumPartSize = 5 * 1024L * 1024L * 1024L; + // Maximum streaming object size. + public static long MaximumStreamObjectSize = MaxParts * MinimumPartSize; + // maxSinglePutObjectSize - maximum size 5GiB of object per PUT + // operation. + public static long MaxSinglePutObjectSize = 1024L * 1024L * 1024L * 5; + + // maxMultipartPutObjectSize - maximum size 5TiB of object for + // Multipart operation. + public static long MaxMultipartPutObjectSize = 1024L * 1024L * 1024L * 1024L * 5; + + // optimalReadBufferSize - optimal buffer 5MiB used for reading + // through Read operation. + public static long OptimalReadBufferSize = 1024L * 1024L * 5; + + + } +} diff --git a/MinioCore2/Helper/Enum.cs b/MinioCore2/Helper/Enum.cs new file mode 100644 index 000000000..a8d5afe22 --- /dev/null +++ b/MinioCore2/Helper/Enum.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MinioCore2 +{ + class Enum + { + /// + /// HTTP method to use when making requests + /// + public enum Method + { + GET, + POST, + PUT, + DELETE, + HEAD, + OPTIONS, + PATCH, + MERGE, + } + } +} diff --git a/MinioCore2/Helper/s3utils.cs b/MinioCore2/Helper/s3utils.cs new file mode 100644 index 000000000..8ce6e9df3 --- /dev/null +++ b/MinioCore2/Helper/s3utils.cs @@ -0,0 +1,86 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System; +using System.IO; + +namespace MinioCore2.Helper +{ + class s3utils + { + + internal static bool IsAmazonEndPoint(string endpoint) + { + if (IsAmazonChinaEndPoint(endpoint)) + { + return true; + } + return endpoint == "s3.amazonaws.com"; + } + // IsAmazonChinaEndpoint - Match if it is exactly Amazon S3 China endpoint. + // Customers who wish to use the new Beijing Region are required + // to sign up for a separate set of account credentials unique to + // the China (Beijing) Region. Customers with existing AWS credentials + // will not be able to access resources in the new Region, and vice versa. + // For more info https://aws.amazon.com/about-aws/whats-new/2013/12/18/announcing-the-aws-china-beijing-region/ + internal static bool IsAmazonChinaEndPoint(string endpoint) + { + + return endpoint == "s3.cn-north-1.amazonaws.com.cn"; + } + // IsGoogleEndpoint - Match if it is exactly Google cloud storage endpoint. + internal static bool IsGoogleEndPoint(string endpoint) + { + return endpoint == "storage.googleapis.com"; + } + + + // IsVirtualHostSupported - verifies if bucketName can be part of + // virtual host. Currently only Amazon S3 and Google Cloud Storage + // would support this. + internal static bool IsVirtualHostSupported(Uri endpointURL,string bucketName) + { + if (endpointURL == null) + { + return false; + } + // bucketName can be valid but '.' in the hostname will fail SSL + // certificate validation. So do not use host-style for such buckets. + if (endpointURL.Scheme == "https" && bucketName.Contains(".")) + { + return false; + } + // Return true for all other cases + return IsAmazonEndPoint(endpointURL.Host) || IsGoogleEndPoint(endpointURL.Host); + } + internal static string GetPath(string p1, string p2) + { + try + { + string combination = Path.Combine(p1, p2); + combination = Uri.EscapeUriString(combination); + return combination; + } + catch (Exception ex) + { + throw new ArgumentException(ex.Message); + } + + } + + + + } +} diff --git a/MinioCore2/Helper/utils.cs b/MinioCore2/Helper/utils.cs new file mode 100644 index 000000000..ef0613908 --- /dev/null +++ b/MinioCore2/Helper/utils.cs @@ -0,0 +1,176 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using MinioCore2.Exceptions; +using System.IO; +using Microsoft.Win32; + +namespace MinioCore2 +{ + class utils + { + // We support '.' with bucket names but we fallback to using path + // style requests instead for such buckets. + static Regex validBucketName = new Regex("^[a-z0-9][a-z0-9\\.\\-]{1,61}[a-z0-9]$"); + + // Invalid bucket name with double dot. + static Regex invalidDotBucketName = new Regex("`/./."); + + /// + /// isValidBucketName - verify bucket name in accordance with + /// - http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html + /// + /// Bucket to test existence of + internal static void validateBucketName(string bucketName) + { + if (bucketName.Trim() == "") + { + throw new InvalidBucketNameException(bucketName,"Bucket name cannot be empty."); + } + if (bucketName.Length < 3) + { + throw new InvalidBucketNameException(bucketName,"Bucket name cannot be smaller than 3 characters."); + } + if (bucketName.Length > 63) + { + throw new InvalidBucketNameException(bucketName,"Bucket name cannot be greater than 63 characters."); + } + if (bucketName[0] == '.' || bucketName[bucketName.Length - 1] == '.') + { + throw new InvalidBucketNameException(bucketName,"Bucket name cannot start or end with a '.' dot."); + } + if (bucketName.Any(c => char.IsUpper(c))) + { + throw new InvalidBucketNameException(bucketName, "Bucket name cannot have upper case characters"); + } + if (invalidDotBucketName.IsMatch(bucketName)) + { + throw new InvalidBucketNameException(bucketName,"Bucket name cannot have successive periods."); + } + if (!validBucketName.IsMatch(bucketName)) + { + throw new InvalidBucketNameException(bucketName, "Bucket name contains invalid characters."); + } + } + // isValidObjectName - verify object name in accordance with + // - http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html + internal static void validateObjectName(String objectName) + { + if (objectName.Trim() == "") + { + throw new InvalidObjectNameException(objectName, "Object name cannot be empty."); + } + if (objectName.Length > 1024) + { + throw new InvalidObjectNameException(objectName, "Object name cannot be greater than 1024 characters."); + } + //c# strings are in utf16 format. they are already in unicode format when they arrive here. + // if !utf8.ValidString(objectName) + // return ErrInvalidBucketName("Object name with non UTF-8 strings are not supported.") + + return; + } + internal static void validateObjectPrefix(string objectPrefix) + { + if (objectPrefix.Length > 1024) + { + throw new InvalidObjectPrefixException(objectPrefix, "Object prefix cannot be greater than 1024 characters."); + } + return; + } + + internal static string UrlEncode(string input) + { + return Uri.EscapeDataString(input).Replace("%2F", "/"); + } + + internal static bool isAnonymousClient(string accessKey, string secretKey) + { + return (secretKey == "" || accessKey == ""); + } + internal static void ValidateFile(string filePath,string contentType=null) + { + if (filePath == null || filePath == "") + { + throw new ArgumentException("empty file name is not allowed"); + } + + string fileName = Path.GetFileName(filePath); + bool fileExists = File.Exists(filePath); + if (fileExists) + { + FileAttributes attr = File.GetAttributes(filePath); + if (attr.HasFlag(FileAttributes.Directory)) + { + throw new ArgumentException("'" + fileName + "': not a regular file"); + } + } + + if (contentType == null) + { + contentType = GetContentType(filePath); + } + + } + internal static string GetContentType(string fileName) + { + // set a default mimetype if not found. + string contentType = "application/octet-stream"; + + try + { + // get the registry classes root + RegistryKey classes = Registry.ClassesRoot; + + // find the sub key based on the file extension + RegistryKey fileClass = classes.OpenSubKey(Path.GetExtension(fileName)); + contentType = fileClass.GetValue("Content Type").ToString(); + } + catch { } + + return contentType; + } + public static void MoveWithReplace(string sourceFileName, string destFileName) + { + + //first, delete target file if exists, as File.Move() does not support overwrite + if (File.Exists(destFileName)) + { + File.Delete(destFileName); + } + + File.Move(sourceFileName, destFileName); + } + + internal static bool isSupersetOf(IList l1, IList l2) + { + if (l2 == null) + { + return true; + } + if (l1 == null) + { + return false; + } + return (!l2.Except(l1).Any()); + } + } +} + + diff --git a/MinioCore2/MinioClient.cs b/MinioCore2/MinioClient.cs new file mode 100644 index 000000000..b54c20a37 --- /dev/null +++ b/MinioCore2/MinioClient.cs @@ -0,0 +1,638 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System; +using System.Collections.Generic; +using MinioCore2.Exceptions; +using System.Text.RegularExpressions; +using RestSharp; +using System.Net; +using System.Linq; +using System.IO; +using System.Xml.Serialization; +using System.Threading; +using System.Threading.Tasks; +using MinioCore2.Helper; +using Newtonsoft.Json; +using System.Runtime.InteropServices; + +namespace MinioCore2 +{ + public partial class MinioClient + { + // Save Credentials from user + internal string AccessKey { get; private set; } + internal string SecretKey { get; private set; } + internal string BaseUrl { get; private set; } + + // Reconstructed endpoint with scheme and host.In the case of Amazon, this url + // is the virtual style path or location based endpoint + internal string Endpoint { get; private set; } + // Corresponding URI for above endpoint + internal Uri uri; + + // Indicates if we are using HTTPS or not + internal bool Secure { get; private set; } + + // RESTSharp client + internal RestClient restClient; + // Custom authenticator for RESTSharp + internal V4Authenticator authenticator; + + // Cache holding bucket to region mapping for buckets seen so far. + internal BucketRegionCache regionCache; + + // Enables HTTP tracing if set to true + private bool trace = false; + + private const string RegistryAuthHeaderKey = "X-Registry-Auth"; + + internal readonly IEnumerable NoErrorHandlers = Enumerable.Empty(); + + // Default error handling delegate + private readonly ApiResponseErrorHandlingDelegate _defaultErrorHandlingDelegate = (response) => + { + if (response.StatusCode < HttpStatusCode.OK || response.StatusCode >= HttpStatusCode.BadRequest) + { + ParseError(response); + } + }; + + private static string SystemUserAgent + { + get + { +#if net452 + string arch = System.Environment.Is64BitOperatingSystem ? "x86_64" : "x86"; +#else + string arch = RuntimeInformation.OSArchitecture.ToString(); +#endif + string release = "minio-dotnet/0.2.1"; + return String.Format("Minio ({0};{1}) {2}", RuntimeInformation.OSDescription, arch, release); + } + } + + private string CustomUserAgent = ""; + // returns the User-Agent header for the request + private string FullUserAgent + { + get + { + return SystemUserAgent + " " + CustomUserAgent; + } + + } + /// + /// Constructs a RestRequest. For AWS, this function has the side-effect of overriding the baseUrl + /// in the RestClient with region specific host path or virtual style path. + /// + /// HTTP method + /// Bucket Name + /// Object Name + /// headerMap + /// unused queryParamMap + /// Content Type + /// request body + /// query string + /// A RestRequest + internal async Task CreateRequest(Method method, string bucketName, string objectName = null, + Dictionary headerMap = null, + string contentType = "application/xml", + Object body = null, string resourcePath = null, string region = null) + { + //Validate bucket name and object name + if (bucketName == null && objectName == null) + { + throw new InvalidBucketNameException(bucketName, "null bucket name for object '" + objectName + "'"); + } + utils.validateBucketName(bucketName); + if (objectName != null) + { + utils.validateObjectName(objectName); + + } + + // Start with user specified endpoint + string host = this.BaseUrl; + + //Fetch correct region for bucket + if (region == null) + { + if (!BucketRegionCache.Instance.Exists(bucketName)) + { + region = await BucketRegionCache.Instance.Update(this, bucketName); + } + else + { + region = BucketRegionCache.Instance.Region(bucketName); + } + } + + + // This section reconstructs the url with scheme followed by location specific endpoint( s3.region.amazonaws.com) + // or Virtual Host styled endpoint (bucketname.s3.region.amazonaws.com) for Amazon requests. + string resource = null; //Resource being requested + bool usePathStyle = false; + if (s3utils.IsAmazonEndPoint(this.BaseUrl)) + { + usePathStyle = false; + + if (method == Method.PUT && objectName == null && resourcePath == null) + { + // use path style for make bucket to workaround "AuthorizationHeaderMalformed" error from s3.amazonaws.com + usePathStyle = true; + } + else if (resourcePath != null && resourcePath.Contains("location")) + { + // use path style for location query + usePathStyle = true; + } + else if (bucketName.Contains(".") && this.Secure) + { + // use path style where '.' in bucketName causes SSL certificate validation error + usePathStyle = true; + } + else if (method == Method.HEAD) + { + usePathStyle = true; + } + + if (usePathStyle) + { + resource = utils.UrlEncode(bucketName) + "/"; + } + else + { + resource = "/"; + } + } + else + { + resource = utils.UrlEncode(bucketName) + "/"; + } + + // Prepare client state + PrepareClient(bucketName, region, usePathStyle); + + if (objectName != null) + { + // Limitation: OkHttp does not allow to add '.' and '..' as path segment. + foreach (String pathSegment in objectName.Split('/')) + { + resource += utils.UrlEncode(pathSegment); + } + + } + + // Append query string passed in + if (resourcePath != null) + { + resource += resourcePath; + } + + RestRequest request = new RestRequest(resource, method); + + if (body != null) + { + request.AddParameter(contentType, body, RestSharp.ParameterType.RequestBody); + + } + + if (contentType != null) + { + request.AddHeader("Content-Type", contentType); + } + + if (headerMap != null) + { + foreach (KeyValuePair entry in headerMap) + { + request.AddHeader(entry.Key, entry.Value); + } + } + + return request; + } + + /// + /// This method initializes a new RESTClient. The host URI for Amazon is set to virtual hosted style + /// if usePathStyle is false. Otherwise path style URL is constructed. + /// + /// bucketName + /// Region bucket resides in. + /// bool controlling if pathstyle URL needs to be constructed or virtual hosted style URL + internal void PrepareClient(string bucketName = null, string region = null, bool usePathStyle = true) + { + if (string.IsNullOrEmpty(this.BaseUrl)) + { + throw new InvalidEndpointException("Endpoint cannot be empty."); + } + + string host = this.BaseUrl; + + // For Amazon S3 endpoint, try to fetch location based endpoint. + if (s3utils.IsAmazonEndPoint(this.BaseUrl)) + { + // Fetch new host based on the bucket location. + host = AWSS3Endpoints.Instance.endpoint(region); + if (!usePathStyle) + { + host = utils.UrlEncode(bucketName) + "." + utils.UrlEncode(host) + "/"; + } + } + var scheme = Secure ? utils.UrlEncode("https") : utils.UrlEncode("http"); + + // This is the actual url pointed to for all HTTP requests + this.Endpoint = string.Format("{0}://{1}", scheme, host); + this.uri = TryCreateUri(this.Endpoint); + _validateEndpoint(); + + // Initialize a new REST client. This uri will be modified if region specific endpoint/virtual style request + // is decided upon while constructing a request for Amazon. + restClient = new RestSharp.RestClient(this.uri); + restClient.UserAgent = this.FullUserAgent; + + authenticator = new V4Authenticator(this.AccessKey, this.SecretKey); + restClient.Authenticator = authenticator; + } + + private Uri TryCreateUri(string endpoint) + { + Uri uri = null; + try + { + uri = new Uri(endpoint); + } + catch( UriFormatException e) + { + throw new InvalidEndpointException(e.Message); + } + return uri; + } + + /// + /// Validates URI to check if it is well formed. Otherwise cry foul. + /// + private void _validateEndpoint() + { + if (string.IsNullOrEmpty(this.BaseUrl)) + { + throw new InvalidEndpointException("Endpoint cannot be empty."); + } + string host = this.BaseUrl; + + if (!this.isValidEndpoint(this.uri.Host)) + { + throw new InvalidEndpointException(this.Endpoint, "Invalid endpoint."); + } + if (!this.uri.AbsolutePath.Equals("/", StringComparison.CurrentCultureIgnoreCase)) + { + throw new InvalidEndpointException(this.Endpoint, "No path allowed in endpoint."); + } + + if (!string.IsNullOrEmpty(this.uri.Query)) + { + throw new InvalidEndpointException(this.Endpoint, "No query parameter allowed in endpoint."); + } + if ((!this.uri.Scheme.ToLowerInvariant().Equals("https")) && (!this.uri.Scheme.ToLowerInvariant().Equals("http"))) + //kp if (!(this.uri.Scheme.Equals(Uri.UriSchemeHttp) || this.uri.Scheme.Equals(Uri.UriSchemeHttps))) + { + throw new InvalidEndpointException(this.Endpoint, "Invalid scheme detected in endpoint."); + } + string amzHost = this.BaseUrl; + if ((amzHost.EndsWith(".amazonaws.com", StringComparison.CurrentCultureIgnoreCase)) + && !(amzHost.Equals("s3.amazonaws.com", StringComparison.CurrentCultureIgnoreCase))) + { + throw new InvalidEndpointException(amzHost, "For Amazon S3, host should be \'s3.amazonaws.com\' in endpoint."); + } + } + + /// + /// Validate Url endpoint + /// + /// + /// true/false + private bool isValidEndpoint(string endpoint) + { + // endpoint may be a hostname + // refer https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names + // why checks are as shown below. + if (endpoint.Length < 1 || endpoint.Length > 253) + { + return false; + } + + foreach (var label in endpoint.Split('.')) + { + if (label.Length < 1 || label.Length > 63) + { + return false; + } + + Regex validLabel = new Regex("^[a-zA-Z0-9][a-zA-Z0-9-]*"); + Regex validEndpoint = new Regex(".*[a-zA-Z0-9]$"); + + if (!(validLabel.IsMatch(label) && validEndpoint.IsMatch(endpoint))) + { + return false; + } + } + + return true; + } + + /// + ///Sets app version and name. Used by RestSharp for constructing User-Agent header in all HTTP requests + /// + /// + /// + /// + public void SetAppInfo(string appName, string appVersion) + { + if (string.IsNullOrEmpty(appName)) + { + throw new ArgumentException("Appname cannot be null or empty"); + } + if (string.IsNullOrEmpty(appVersion)) + { + throw new ArgumentException("Appversion cannot be null or empty"); + } + this.CustomUserAgent = appName + "/" + appVersion; + } + + /// + /// Creates and returns an Cloud Storage client + /// + /// Location of the server, supports HTTP and HTTPS + /// Access Key for authenticated requests (Optional,can be omitted for anonymous requests) + /// Secret Key for authenticated requests (Optional,can be omitted for anonymous requests) + /// Client initialized with user credentials + public MinioClient(string endpoint, string accessKey = "", string secretKey = "") + { + + this.Secure = false; + + // Save user entered credentials + this.BaseUrl = endpoint; + this.AccessKey = accessKey; + this.SecretKey = secretKey; + + //Instantiate a region cache + this.regionCache = BucketRegionCache.Instance; + + return; + + } + + /// + /// Connects to Cloud Storage with HTTPS if this method is invoked on client object + /// + /// + public MinioClient WithSSL() + { + this.Secure = true; + return this; + } + + internal async Task> ExecuteTaskAsync(IEnumerable errorHandlers, IRestRequest request) where T : new() + { + DateTime startTime = DateTime.Now; + TaskCompletionSource> tcs = new TaskCompletionSource>(); + RestRequestAsyncHandle handle = this.restClient.ExecuteAsync( + request, r => + { + tcs.SetResult(r); + + }); + //var response = await this.restClient.ExecuteTaskAsync(request, CancellationToken.None); + var response = await tcs.Task; + HandleIfErrorResponse(response, errorHandlers, startTime); + return response; + } + /// + /// Actual doer that executes the REST request to the server + /// + /// List of handlers to override default handling + /// request + /// IRESTResponse + internal async Task ExecuteTaskAsync(IEnumerable errorHandlers, IRestRequest request) + { + DateTime startTime = DateTime.Now; + // Logs full url when HTTPtracing is enabled. + if (this.trace) + { + var fullUrl = this.restClient.BuildUri(request); + Console.Out.WriteLine("Full URL of Request {0}", fullUrl); + } + TaskCompletionSource tcs = new TaskCompletionSource(); + RestRequestAsyncHandle handle = this.restClient.ExecuteAsync( + request, resp => + { + tcs.SetResult(resp); + + }); + IRestResponse response = await tcs.Task; + HandleIfErrorResponse(response, errorHandlers, startTime); + return response; + // var response = await this.restClient.ExecuteTaskAsync(request, CancellationToken.None); + + } + + + /// + /// Parse response errors if any and return relevant error messages + /// + /// + internal static void ParseError(IRestResponse response) + { + if (response == null) + { + throw new ConnectionException("Response is nil. Please report this issue https://github.com/minio/minio-dotnet/issues"); + } + if (HttpStatusCode.Redirect.Equals(response.StatusCode) || HttpStatusCode.TemporaryRedirect.Equals(response.StatusCode) || HttpStatusCode.MovedPermanently.Equals(response.StatusCode)) + { + throw new RedirectionException("Redirection detected. Please report this issue https://github.com/minio/minio-dotnet/issues"); + } + + if (string.IsNullOrWhiteSpace(response.Content)) + { + if (HttpStatusCode.Forbidden.Equals(response.StatusCode) || HttpStatusCode.NotFound.Equals(response.StatusCode) || + HttpStatusCode.MethodNotAllowed.Equals(response.StatusCode) || HttpStatusCode.NotImplemented.Equals(response.StatusCode)) + { + MinioException e = null; + ErrorResponse errorResponse = new ErrorResponse(); + + foreach (Parameter parameter in response.Headers) + { + if (parameter.Name.Equals("x-amz-id-2", StringComparison.CurrentCultureIgnoreCase)) + { + errorResponse.HostId = parameter.Value.ToString(); + } + if (parameter.Name.Equals("x-amz-request-id", StringComparison.CurrentCultureIgnoreCase)) + { + errorResponse.RequestId = parameter.Value.ToString(); + } + if (parameter.Name.Equals("x-amz-bucket-region", StringComparison.CurrentCultureIgnoreCase)) + { + errorResponse.BucketRegion = parameter.Value.ToString(); + } + } + + errorResponse.Resource = response.Request.Resource; + + if (HttpStatusCode.NotFound.Equals(response.StatusCode)) + { + int pathLength = response.Request.Resource.Split('/').Count(); + if (pathLength > 1) + { + errorResponse.Code = "NoSuchKey"; + var bucketName = response.Request.Resource.Split('/')[0]; + var objectName = response.Request.Resource.Split('/')[1]; + if (objectName == "") + { + e = new BucketNotFoundException(bucketName, "Not found."); + } + else + { + e = new ObjectNotFoundException(objectName, "Not found."); + } + } + else if (pathLength == 1) + { + errorResponse.Code = "NoSuchBucket"; + var bucketName = response.Request.Resource.Split('/')[0]; + BucketRegionCache.Instance.Remove(bucketName); + e = new BucketNotFoundException(bucketName, "Not found."); + } + else + { + e = new InternalClientException("404 without body resulted in path with less than two components"); + } + } + else if (HttpStatusCode.Forbidden.Equals(response.StatusCode)) + { + errorResponse.Code = "Forbidden"; + e = new AccessDeniedException("Access denied on the resource: " + response.Request.Resource); + } + e.Response = errorResponse; + throw e; + } + throw new InternalClientException("Unsuccessful response from server without XML error: " + response.ErrorMessage); + } + + if (response.StatusCode.Equals(HttpStatusCode.NotFound) && response.Request.Resource.EndsWith("?location") + && response.Request.Method.Equals(Method.GET)) + { + var bucketName = response.Request.Resource.Split('?')[0]; + BucketRegionCache.Instance.Remove(bucketName); + throw new BucketNotFoundException(bucketName, "Not found."); + } + + + var contentBytes = System.Text.Encoding.UTF8.GetBytes(response.Content); + var stream = new MemoryStream(contentBytes); + ErrorResponse errResponse = (ErrorResponse)(new XmlSerializer(typeof(ErrorResponse)).Deserialize(stream)); + + MinioException MinioException = new MinioException(errResponse.Message); + MinioException.Response = errResponse; + MinioException.XmlError = response.Content; + throw MinioException; + } + /// + /// Delegate errors to handlers + /// + /// + /// + private void HandleIfErrorResponse(IRestResponse response, IEnumerable handlers, DateTime startTime) + { + //Logs Response if HTTP tracing is enabled + if (this.trace) + { + DateTime now = DateTime.Now; + LogRequest(response.Request, response, (now - startTime).TotalMilliseconds); + } + if (handlers == null) + { + throw new ArgumentNullException(nameof(handlers)); + } + // Runs through handlers passed to take up error handling + foreach (var handler in handlers) + { + handler(response); + } + + //Fall back default error handler + _defaultErrorHandlingDelegate(response); + } + /// + /// Sets HTTP tracing On.Writes output to Console + /// + public void SetTraceOn() + { + this.trace = true; + } + /// + /// Sets HTTP tracing Off. + /// + public void SetTraceOff() + { + this.trace = false; + } + + /// + /// Logs the request sent to server and corresponding response + /// + /// + /// + /// + private void LogRequest(IRestRequest request, IRestResponse response, double durationMs) + { + var requestToLog = new + { + resource = request.Resource, + // Parameters are custom anonymous objects in order to have the parameter type as a nice string + // otherwise it will just show the enum value + parameters = request.Parameters.Select(parameter => new + { + name = parameter.Name, + value = parameter.Value, + type = parameter.Type.ToString() + }), + // ToString() here to have the method as a nice string otherwise it will just show the enum value + method = request.Method.ToString(), + // This will generate the actual Uri used in the request + uri = restClient.BuildUri(request), + }; + + var responseToLog = new + { + statusCode = response.StatusCode, + content = response.Content, + headers = response.Headers, + // The Uri that actually responded (could be different from the requestUri if a redirection occurred) + responseUri = response.ResponseUri, + errorMessage = response.ErrorMessage, + }; + + Console.Out.WriteLine(string.Format("Request completed in {0} ms, Request: {1}, Response: {2}", + durationMs, + JsonConvert.SerializeObject(requestToLog, Formatting.Indented), + JsonConvert.SerializeObject(responseToLog, Formatting.Indented))); + } + + } + internal delegate void ApiResponseErrorHandlingDelegate(IRestResponse response); + +} diff --git a/MinioCore2/MinioCore2.xproj b/MinioCore2/MinioCore2.xproj new file mode 100644 index 000000000..a944e0ea0 --- /dev/null +++ b/MinioCore2/MinioCore2.xproj @@ -0,0 +1,19 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + c7579cad-6d2a-45e0-8737-8e66c78ebe2f + MinioCore2 + .\obj + .\bin\ + v4.5.2 + + + 2.0 + + + \ No newline at end of file diff --git a/MinioCore2/Properties/AssemblyInfo.cs b/MinioCore2/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..942e27b77 --- /dev/null +++ b/MinioCore2/Properties/AssemblyInfo.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Vagrant Inc.")] +[assembly: AssemblyProduct("MinioCore22")] +[assembly: AssemblyTrademark("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c7579cad-6d2a-45e0-8737-8e66c78ebe2f")] diff --git a/MinioCore2/Regions.cs b/MinioCore2/Regions.cs new file mode 100644 index 000000000..8dac488ed --- /dev/null +++ b/MinioCore2/Regions.cs @@ -0,0 +1,75 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Text.RegularExpressions; +namespace MinioCore2 +{ + public class Regions + { + private Regions() + { + } + + /// + /// Get corresponding region for input host. + /// + /// S3 API endpoint + /// Region corresponding to the endpoint. Default is 'us-east-1' + internal static string GetRegion(string endpoint) + { + if (endpoint.EndsWith("s3 - ap - northeast - 1.amazonaws.com")) + { + return "ap-northeast-1"; + } + if (endpoint.EndsWith("s3-ap-southeast-1.amazonaws.com")) + { + return "ap-southeast-1"; + } + if (endpoint.EndsWith("s3-ap-southeast-2.amazonaws.com")) + { + return "ap-southeast-2"; + + } + if (endpoint.EndsWith("s3-eu-central-1.amazonaws.com")) + { + return "eu-central-1"; + } + if (endpoint.EndsWith("s3-eu-west-1.amazonaws.com")) + { + return "eu-west-1"; + } + if (endpoint.EndsWith("s3-sa-east-1.amazonaws.com")) + { + return "sa-east-1"; + } + if (endpoint.EndsWith("s3.amazonaws.com")) + { + return "us-east-1"; + } + if (endpoint.EndsWith("s3-us-west-1.amazonaws.com")) + { + return "us-west-1"; + } + if (endpoint.EndsWith("s3-us-west-2.amazonaws.com")) + { + return "us-west-2"; + } + return "us-east-1"; + } + + } +} diff --git a/MinioCore2/V4Authenticator.cs b/MinioCore2/V4Authenticator.cs new file mode 100644 index 000000000..04a4a07a6 --- /dev/null +++ b/MinioCore2/V4Authenticator.cs @@ -0,0 +1,512 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using RestSharp; +using RestSharp.Authenticators; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; + +namespace MinioCore2 +{ + /// + /// V4Authenticator implements IAuthenticator interface. + /// + internal class V4Authenticator : IAuthenticator + { + private readonly string accessKey; + private readonly string secretKey; + + // + // Excerpts from @lsegal - https://github.com/aws/aws-sdk-js/issues/659#issuecomment-120477258 + // + // User-Agent: + // + // This is ignored from signing because signing this causes problems with generating pre-signed URLs + // (that are executed by other agents) or when customers pass requests through proxies, which may + // modify the user-agent. + // + // Content-Length: + // + // This is ignored from signing because generating a pre-signed URL should not provide a content-length + // constraint, specifically when vending a S3 pre-signed PUT URL. The corollary to this is that when + // sending regular requests (non-pre-signed), the signature contains a checksum of the body, which + // implicitly validates the payload length (since changing the number of bytes would change the checksum) + // and therefore this header is not valuable in the signature. + // + // Content-Type: + // + // Signing this header causes quite a number of problems in browser environments, where browsers + // like to modify and normalize the content-type header in different ways. There is more information + // on this in https://github.com/aws/aws-sdk-js/issues/244. Avoiding this field simplifies logic + // and reduces the possibility of future bugs + // + // Authorization: + // + // Is skipped for obvious reasons + // + private static HashSet ignoredHeaders = new HashSet() { + "authorization", + "content-length", + "content-type", + "user-agent" + }; + + /// + /// Authenticator constructor. + /// + /// Access key id + /// Secret access key + public V4Authenticator(string accessKey, string secretKey) + { + this.accessKey = accessKey; + this.secretKey = secretKey; + } + + /// + /// Implements Authenticate interface method for IAuthenticator. + /// + /// Instantiated IRestClient object + /// Instantiated IRestRequest object + public void Authenticate(IRestClient client, IRestRequest request) + { + DateTime signingDate = DateTime.UtcNow; + SetContentMd5(request); + SetContentSha256(request); + SetHostHeader(request, client); + SetDateHeader(request, signingDate); + SortedDictionary headersToSign = GetHeadersToSign(request); + string signedHeaders = GetSignedHeaders(headersToSign); + string region = Regions.GetRegion(client.BaseUrl.Host); + string canonicalRequest = GetCanonicalRequest(client, request, headersToSign); + byte[] canonicalRequestBytes = System.Text.Encoding.UTF8.GetBytes(canonicalRequest); + string canonicalRequestHash = BytesToHex(ComputeSha256(canonicalRequestBytes)); + string stringToSign = GetStringToSign(region, signingDate, canonicalRequestHash); + byte[] signingKey = GenerateSigningKey(region, signingDate); + + byte[] stringToSignBytes = System.Text.Encoding.UTF8.GetBytes(stringToSign); + + byte[] signatureBytes = SignHmac(signingKey, stringToSignBytes); + + string signature = BytesToHex(signatureBytes); + + string authorization = GetAuthorizationHeader(signedHeaders, signature, signingDate, region); + request.AddHeader("Authorization", authorization); + + } + + /// + /// Get credential string of form /date/region/s3/aws4_request. + /// + /// Signature initated date + /// Region for the credential string + /// Credential string for the authorization header + public string GetCredentialString(DateTime signingDate, string region) + { + return this.accessKey + "/" + GetScope(region, signingDate); + } + + /// + /// Constructs an authorization header. + /// + /// All signed http headers + /// Hexadecimally encoded computed signature + /// Date for signature to be signed + /// Requested region + /// Fully formed authorization header + private string GetAuthorizationHeader(string signedHeaders, string signature, DateTime signingDate, string region) + { + return "AWS4-HMAC-SHA256 Credential=" + this.accessKey + "/" + GetScope(region, signingDate) + + ", SignedHeaders=" + signedHeaders + ", Signature=" + signature; + } + + /// + /// Concatenates sorted list of signed http headers. + /// + /// Sorted dictionary of headers to be signed + /// All signed headers + private string GetSignedHeaders(SortedDictionary headersToSign) + { + return string.Join(";", headersToSign.Keys); + } + + /// + /// Generates signing key based on the region and date. + /// + /// Requested region + /// Date for signature to be signed + /// bytes of computed hmac + private byte[] GenerateSigningKey(string region, DateTime signingDate) + { + byte[] formattedDateBytes = System.Text.Encoding.UTF8.GetBytes(signingDate.ToString("yyyMMdd")); + byte[] formattedKeyBytes = System.Text.Encoding.UTF8.GetBytes("AWS4" + this.secretKey); + byte[] dateKey = SignHmac(formattedKeyBytes, formattedDateBytes); + + byte[] regionBytes = System.Text.Encoding.UTF8.GetBytes(region); + byte[] dateRegionKey = SignHmac(dateKey, regionBytes); + + byte[] serviceBytes = System.Text.Encoding.UTF8.GetBytes("s3"); + byte[] dateRegionServiceKey = SignHmac(dateRegionKey, serviceBytes); + + byte[] requestBytes = System.Text.Encoding.UTF8.GetBytes("aws4_request"); + return SignHmac(dateRegionServiceKey, requestBytes); + } + + /// + /// Compute hmac of input content with key. + /// + /// Hmac key + /// Bytes to be hmac computed + /// Computed hmac of input content + private byte[] SignHmac(byte[] key, byte[] content) + { + HMACSHA256 hmac = new HMACSHA256(key); + hmac.Initialize(); + return hmac.ComputeHash(content); + } + + /// + /// Get string to sign. + /// + /// Requested region + /// Date for signature to be signed + /// Hexadecimal encoded sha256 checksum of canonicalRequest + /// String to sign + private string GetStringToSign(string region, DateTime signingDate, string canonicalRequestHash) + { + return "AWS4-HMAC-SHA256\n" + + signingDate.ToString("yyyyMMddTHHmmssZ") + "\n" + + GetScope(region, signingDate) + "\n" + + canonicalRequestHash; + } + + /// + /// Get scope. + /// + /// Requested region + /// Date for signature to be signed + /// Scope string + private string GetScope(string region, DateTime signingDate) + { + string formattedDate = signingDate.ToString("yyyyMMdd"); + return formattedDate + "/" + region + "/s3/aws4_request"; + } + + /// + /// Compute sha256 checksum. + /// + /// Bytes body + /// Bytes of sha256 checksum + private byte[] ComputeSha256(byte[] body) + { + + SHA256 sha256 = System.Security.Cryptography.SHA256.Create(); + return sha256.ComputeHash(body); + } + + /// + /// Convert bytes to hexadecimal string. + /// + /// Bytes of any checksum + /// Hexlified string of input bytes + private string BytesToHex(byte[] checkSum) + { + return BitConverter.ToString(checkSum).Replace("-", string.Empty).ToLower(); + } + + /// + /// Generate signature for post policy. + /// + /// Requested region + /// Date for signature to be signed + /// Base64 encoded policy JSON + /// Computed signature + public string PresignPostSignature(string region, DateTime signingDate, string policyBase64) + { + byte[] signingKey = this.GenerateSigningKey(region, signingDate); + byte[] stringToSignBytes = System.Text.Encoding.UTF8.GetBytes(policyBase64); + + byte[] signatureBytes = SignHmac(signingKey, stringToSignBytes); + string signature = BytesToHex(signatureBytes); + + return signature; + } + + /// + /// Presigns any input client object with a requested expiry. + /// + /// Instantiated client + /// Instantiated request + /// Expiration in seconds + /// Presigned url + public string PresignURL(IRestClient client, IRestRequest request, int expires) + { + DateTime signingDate = DateTime.UtcNow; + string region = Regions.GetRegion(client.BaseUrl.Host); + string requestQuery = ""; + string path = request.Resource; + + requestQuery = "X-Amz-Algorithm=AWS4-HMAC-SHA256&"; + requestQuery += "X-Amz-Credential=" + + this.accessKey + + Uri.EscapeDataString("/" + GetScope(region, signingDate)) + + "&"; + requestQuery += "X-Amz-Date=" + + signingDate.ToString("yyyyMMddTHHmmssZ") + + "&"; + requestQuery += "X-Amz-Expires=" + + expires + + "&"; + requestQuery += "X-Amz-SignedHeaders=host"; + + string canonicalRequest = GetPresignCanonicalRequest(client, request, requestQuery); + byte[] canonicalRequestBytes = System.Text.Encoding.UTF8.GetBytes(canonicalRequest); + string canonicalRequestHash = BytesToHex(ComputeSha256(canonicalRequestBytes)); + string stringToSign = GetStringToSign(region, signingDate, canonicalRequestHash); + byte[] signingKey = GenerateSigningKey(region, signingDate); + byte[] stringToSignBytes = System.Text.Encoding.UTF8.GetBytes(stringToSign); + byte[] signatureBytes = SignHmac(signingKey, stringToSignBytes); + string signature = BytesToHex(signatureBytes); + + // Return presigned url. + return client.BaseUrl + path + "?" + requestQuery + "&X-Amz-Signature=" + signature; + } + + /// + /// Get presign canonical request. + /// + /// Instantiated client object + /// Instantiated request object + /// Additional request query params + /// Presigned canonical request + private string GetPresignCanonicalRequest(IRestClient client, IRestRequest request, string requestQuery) + { + LinkedList canonicalStringList = new LinkedList(); + // METHOD + canonicalStringList.AddLast(request.Method.ToString()); + + string path = request.Resource; + if (!path.StartsWith("/")) + { + path = "/" + path; + } + canonicalStringList.AddLast(path); + canonicalStringList.AddLast(requestQuery); + if (client.BaseUrl.Port > 0) + { + canonicalStringList.AddLast("host:" + client.BaseUrl.Host + ":" + client.BaseUrl.Port); + } + else + { + canonicalStringList.AddLast("host:" + client.BaseUrl.Host); + } + canonicalStringList.AddLast(""); + canonicalStringList.AddLast("host"); + canonicalStringList.AddLast("UNSIGNED-PAYLOAD"); + + return string.Join("\n", canonicalStringList); + } + + /// + /// Get canonical request. + /// + /// Instantiated client object + /// Instantiated request object + /// Dictionary of http headers to be signed + /// Canonical Request + private string GetCanonicalRequest(IRestClient client, IRestRequest request, + SortedDictionary headersToSign) + { + LinkedList canonicalStringList = new LinkedList(); + // METHOD + canonicalStringList.AddLast(request.Method.ToString()); + + string[] path = request.Resource.Split(new char[] { '?' }, 2); + if (!path[0].StartsWith("/")) + { + path[0] = "/" + path[0]; + } + canonicalStringList.AddLast(path[0]); + + string query = ""; + // QUERY + if (path.Length == 2) + { + var parameterString = path[1]; + var parameterList = parameterString.Split('&'); + SortedSet sortedQueries = new SortedSet(); + foreach (string individualParameterString in parameterList) + { + if (individualParameterString.Contains('=')) + { + string[] splitQuery = individualParameterString.Split(new char[] { '=' }, 2); + sortedQueries.Add(splitQuery[0] + "=" + splitQuery[1]); + } + else + { + sortedQueries.Add(individualParameterString + "="); + } + } + query = string.Join("&", sortedQueries); + } + canonicalStringList.AddLast(query); + + foreach (string header in headersToSign.Keys) + { + canonicalStringList.AddLast(header + ":" + headersToSign[header]); + } + canonicalStringList.AddLast(""); + canonicalStringList.AddLast(string.Join(";", headersToSign.Keys)); + if (headersToSign.Keys.Contains("x-amz-content-sha256")) + { + canonicalStringList.AddLast(headersToSign["x-amz-content-sha256"]); + } + else + { + canonicalStringList.AddLast("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + } + + return string.Join("\n", canonicalStringList); + } + + /// + /// Get headers to be signed. + /// + /// Instantiated requesst + /// Sorted dictionary of headers to be signed + private SortedDictionary GetHeadersToSign(IRestRequest request) + { + var headers = request.Parameters.Where(p => p.Type.Equals(ParameterType.HttpHeader)).ToList(); + + SortedDictionary sortedHeaders = new SortedDictionary(); + foreach (Parameter header in headers) + { + string headerName = header.Name.ToLower(); + string headerValue = header.Value.ToString(); + if (headerName.Equals("host")) + { + var host = headerValue.Split(':')[0]; + var port = headerValue.Split(':')[1]; + if (port.Equals("80") || port.Equals("443")) + { + sortedHeaders.Add(headerName, host); + } + else + { + sortedHeaders.Add(headerName, headerValue); + } + } + else if (!ignoredHeaders.Contains(headerName)) + { + sortedHeaders.Add(headerName, headerValue); + } + } + return sortedHeaders; + } + /// + /// Sets 'x-amz-date' http header. + /// + /// Instantiated request object + /// Date for signature to be signed + private void SetDateHeader(IRestRequest request, DateTime signingDate) + { + request.AddHeader("x-amz-date", signingDate.ToString("yyyyMMddTHHmmssZ")); + } + + /// + /// Set 'Host' http header. + /// + /// Instantiated request object + /// Instantiated client object + private void SetHostHeader(IRestRequest request, IRestClient client) + { + request.AddHeader("Host", client.BaseUrl.Host + ":" + client.BaseUrl.Port); + } + + /// + /// Set 'x-amz-content-sha256' http header. + /// + /// Instantiated request object + private void SetContentSha256(IRestRequest request) + { + if (request.Method == Method.PUT || request.Method.Equals(Method.POST)) + { + var bodyParameter = request.Parameters.Where(p => p.Type.Equals(ParameterType.RequestBody)).FirstOrDefault(); + if (bodyParameter == null) + { + request.AddHeader("x-amz-content-sha256", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + return; + } + byte[] body = null; + if (bodyParameter.Value is string) + { + body = System.Text.Encoding.UTF8.GetBytes(bodyParameter.Value as string); + } + if (bodyParameter.Value is byte[]) + { + body = bodyParameter.Value as byte[]; + } + if (body == null) + { + body = new byte[0]; + } + SHA256 sha256 = System.Security.Cryptography.SHA256.Create(); + byte[] hash = sha256.ComputeHash(body); + string hex = BitConverter.ToString(hash).Replace("-", string.Empty).ToLower(); + request.AddHeader("x-amz-content-sha256", hex); + } + else + { + request.AddHeader("x-amz-content-sha256", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + } + } + + /// + /// Set 'Content-MD5' http header. + /// + /// Instantiated request object + private void SetContentMd5(IRestRequest request) + { + if (request.Method == Method.PUT || request.Method.Equals(Method.POST)) + { + var bodyParameter = request.Parameters.Where(p => p.Type.Equals(ParameterType.RequestBody)).FirstOrDefault(); + if (bodyParameter == null) + { + return; + } + byte[] body = null; + if (bodyParameter.Value is string) + { + body = System.Text.Encoding.UTF8.GetBytes(bodyParameter.Value as string); + } + if (bodyParameter.Value is byte[]) + { + body = bodyParameter.Value as byte[]; + } + if (body == null) + { + body = new byte[0]; + } + MD5 md5 = System.Security.Cryptography.MD5.Create(); + byte[] hash = md5.ComputeHash(body); + + string base64 = Convert.ToBase64String(hash); + request.AddHeader("Content-MD5", base64); + } + } + } +} diff --git a/MinioCore2/project.json b/MinioCore2/project.json new file mode 100644 index 000000000..f08e7552f --- /dev/null +++ b/MinioCore2/project.json @@ -0,0 +1,41 @@ +{ + "dependencies": { + "Newtonsoft.Json": "9.0.2-beta2", + "System.Reactive": "3.1.1", + "System.Reactive.Core": "3.1.1", + "System.Reactive.Interfaces": "3.1.1", + "System.Reactive.Linq": "3.1.1", + "System.Reactive.PlatformServices": "3.1.1", + "System.Runtime.InteropServices.RuntimeInformation": "4.3.0" + }, + "frameworks": { + "netstandard1.6": { + "imports": "dnxcore50", + "dependencies": { + "Microsoft.Build.Utilities.Core": "14.3.0", + "Microsoft.Win32.Registry": "4.3.0", + "NETStandard.Library": "1.6.1", + "RestSharp.NetCore": "105.2.4-rc4-24214-01", + + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.InteropServices": "4.3.0" + } + }, + "net452": { + "dependencies": { + "RestSharp": "105.2.3", + "System.Reactive.Windows.Threading": "3.1.1", + "System.Xml.Linq": "3.5.21022.801" + }, + "frameworkAssemblies": { + "System.Runtime.Serialization": "4.0.0.0", + "System.Xml": "4.0.0.0", + "System.Runtime": "4.0.10.0" + + } + + } + }, + "version": "1.0.0-*" +} diff --git a/Minio.Api/ApiEndpoints/ClientApiOperations.cs b/MinioCoreTest/Cases/BucketExists.cs similarity index 54% rename from Minio.Api/ApiEndpoints/ClientApiOperations.cs rename to MinioCoreTest/Cases/BucketExists.cs index 8a29b3c7b..4fdca57c3 100644 --- a/Minio.Api/ApiEndpoints/ClientApiOperations.cs +++ b/MinioCoreTest/Cases/BucketExists.cs @@ -1,5 +1,5 @@ /* - * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc. + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,31 +13,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading.Tasks; -using Minio.Exceptions; -using System.Net; -namespace Minio +namespace MinioCoreTest.Cases { - public partial class ClientApiOperations + class BucketExists { - internal MinioClient client; - private const string RegistryAuthHeaderKey = "X-Registry-Auth"; - internal static readonly ApiResponseErrorHandlingDelegate NoSuchBucketHandler = (response) => + //Check if a bucket exists + public async static Task Run(MinioCore2.MinioClient minio, + string bucketName = "my-bucket-name") { - if (response.StatusCode != HttpStatusCode.OK) + try { - throw new BucketNotFoundException(); + bool found = await minio.BucketExistsAsync(bucketName); + Console.Out.WriteLine("bucket-name was " + ((found == true) ? "found" : "not found")); + } + catch (Exception e) + { + Console.WriteLine("[Bucket] Exception: {0}", e); } - }; - public ClientApiOperations(MinioClient client) - { - this.client = client; } } } - diff --git a/MinioCoreTest/Cases/CopyObject.cs b/MinioCoreTest/Cases/CopyObject.cs new file mode 100644 index 000000000..30b921c50 --- /dev/null +++ b/MinioCoreTest/Cases/CopyObject.cs @@ -0,0 +1,48 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Threading.Tasks; + +namespace MinioCoreTest.Cases +{ + class CopyObject + { + //copy object from one bucket to another + public async static Task Run(MinioCore2.MinioClient minio, + string fromBucketName="from-bucket-name", + string fromObjectName="from-object-name", + string destBucketName="dest-bucket", + string destObjectName="to-object-name") + { + try + { + //Optionally pass copy conditions + await minio.CopyObjectAsync(fromBucketName, + fromObjectName, + destBucketName, + destObjectName, + copyConditions:null); + Console.Out.WriteLine("done copying"); + } + catch (Exception e) + { + Console.WriteLine("[Bucket] Exception: {0}", e); + } + } + + } +} \ No newline at end of file diff --git a/MinioCoreTest/Cases/FGetObject.cs b/MinioCoreTest/Cases/FGetObject.cs new file mode 100644 index 000000000..92eb3416d --- /dev/null +++ b/MinioCoreTest/Cases/FGetObject.cs @@ -0,0 +1,41 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Threading.Tasks; + +namespace MinioCoreTest.Cases +{ + class FGetObject + { + //Download object from bucket into local file + public async static Task Run(MinioCore2.MinioClient minio, + string bucketName = "my-bucket-name", + string objectName = "my-object-name", + string fileName="local-filename") + { + try + { + await minio.GetObjectAsync(bucketName, objectName, fileName); + + } + catch (Exception e) + { + Console.WriteLine("[Bucket] Exception: {0}", e); + } + } + } +} diff --git a/MinioCoreTest/Cases/FPutObject.cs b/MinioCoreTest/Cases/FPutObject.cs new file mode 100644 index 000000000..ed649e15d --- /dev/null +++ b/MinioCoreTest/Cases/FPutObject.cs @@ -0,0 +1,45 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Threading.Tasks; + +namespace MinioCoreTest.Cases +{ + class FPutObject + { + + //Upload object to bucket from file + public async static Task Run(MinioCore2.MinioClient minio, + string bucketName = "my-bucket-name", + string objectName = "my-object-name", + string fileName = "from where") + { + try + { + await minio.PutObjectAsync(bucketName, + objectName, + fileName, + contentType: "application/octet-stream"); + Console.Out.WriteLine("done uploading"); + } + catch (Exception e) + { + Console.WriteLine("[Bucket] Exception: {0}", e); + } + } + } +} diff --git a/MinioCoreTest/Cases/GetBucketPolicy.cs b/MinioCoreTest/Cases/GetBucketPolicy.cs new file mode 100644 index 000000000..8443a1df5 --- /dev/null +++ b/MinioCoreTest/Cases/GetBucketPolicy.cs @@ -0,0 +1,41 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Threading.Tasks; +using MinioCore2.DataModel; + +namespace MinioCoreTest.Cases +{ + class GetBucketPolicy + { + //get bucket policy + public async static Task Run(MinioCore2.MinioClient minio, + string bucketName = "my-bucket-name", + string prefix="") + { + try + { + PolicyType policy = await minio.GetPolicyAsync(bucketName,objectPrefix:prefix); + Console.Out.WriteLine("POLICY: " + policy.GetType().ToString()); + } + catch (Exception e) + { + Console.WriteLine("[Bucket] Exception: {0}", e); + } + } + } +} diff --git a/MinioCoreTest/Cases/GetObject.cs b/MinioCoreTest/Cases/GetObject.cs new file mode 100644 index 000000000..fe63bfced --- /dev/null +++ b/MinioCoreTest/Cases/GetObject.cs @@ -0,0 +1,44 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Threading.Tasks; + +namespace MinioCoreTest.Cases +{ + class GetObject + { + //get object in a bucket + public async static Task Run(MinioCore2.MinioClient minio, + string bucketName="my-bucket-name", + string objectName="my-object-name") + { + try + { + await minio.GetObjectAsync(bucketName, objectName, + (stream) => + { + stream.CopyTo(Console.OpenStandardOutput()); + }); + + } + catch (Exception e) + { + Console.WriteLine("[Bucket] Exception: {0}", e); + } + } + } +} diff --git a/MinioCoreTest/Cases/ListBuckets.cs b/MinioCoreTest/Cases/ListBuckets.cs new file mode 100644 index 000000000..c5dff9b4c --- /dev/null +++ b/MinioCoreTest/Cases/ListBuckets.cs @@ -0,0 +1,45 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Threading.Tasks; +using MinioCore2.DataModel; + +namespace MinioCoreTest.Cases +{ + class ListBuckets + { + // List all buckets on host + public async static Task Run(MinioCore2.MinioClient minio) + { + try + { + var list = await minio.ListBucketsAsync(); + foreach (Bucket bucket in list.Buckets) + { + Console.Out.WriteLine(bucket.Name + " " + bucket.CreationDateDateTime); + } + + } + catch (Exception e) + { + Console.WriteLine("[Bucket] Exception: {0}", e); + } + } + + + } +} diff --git a/MinioCoreTest/Cases/ListIncompleteUploads.cs b/MinioCoreTest/Cases/ListIncompleteUploads.cs new file mode 100644 index 000000000..1812fb9af --- /dev/null +++ b/MinioCoreTest/Cases/ListIncompleteUploads.cs @@ -0,0 +1,47 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using MinioCore2.DataModel; +using System; + + +namespace MinioCoreTest.Cases +{ + class ListIncompleteUploads + { + //List incomplete uploads on the bucket matching specified prefix + public static void Run(MinioCore2.MinioClient minio, + string bucketName = "my-bucket-name", + string prefix = "my-object-name", + bool recursive = true) + { + try + { + IObservable observable = minio.ListIncompleteUploads(bucketName, prefix, recursive); + + IDisposable subscription = observable.Subscribe( + item => Console.WriteLine("OnNext: {0}", item.Key), + ex => Console.WriteLine("OnError: {0}", ex.Message), + () => Console.WriteLine("OnComplete: {0}")); + + } + catch (Exception e) + { + Console.WriteLine("Exception: {0}", e); + } + } + } +} diff --git a/MinioCoreTest/Cases/ListObjects.cs b/MinioCoreTest/Cases/ListObjects.cs new file mode 100644 index 000000000..f359dcd33 --- /dev/null +++ b/MinioCoreTest/Cases/ListObjects.cs @@ -0,0 +1,51 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using MinioCore2.DataModel; + +namespace MinioCoreTest.Cases +{ + + class ListObjects + { + //List objects matching optional prefix in a specified bucket. + public static void Run(MinioCore2.MinioClient minio, + string bucketName = "my-bucket-name", + string prefix = null, + bool recursive = false) + { + try + { + + IObservable observable = minio.ListObjectsAsync(bucketName, prefix, recursive); + + + IDisposable subscription = observable.Subscribe( + item => Console.WriteLine("OnNext: {0}", item.Key), + ex => Console.WriteLine("OnError: {0}", ex), + () => Console.WriteLine("OnComplete: {0}")); + + + // subscription.Dispose(); + } + catch (Exception e) + { + Console.WriteLine("[Bucket] Exception: {0}", e); + } + } + } +} diff --git a/MinioCoreTest/Cases/MakeBucket.cs b/MinioCoreTest/Cases/MakeBucket.cs new file mode 100644 index 000000000..90c673399 --- /dev/null +++ b/MinioCoreTest/Cases/MakeBucket.cs @@ -0,0 +1,41 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Threading.Tasks; + +namespace MinioCoreTest.Cases +{ + public class MakeBucket + { + //Make a bucket + public async static Task Run(MinioCore2.MinioClient minio, + string bucketName="my-bucket-name") + { + try + { + await minio.MakeBucketAsync(bucketName); + Console.Out.WriteLine("bucket-name created successfully"); + } + catch (Exception e) + { + Console.WriteLine("[Bucket] Exception: {0}", e); + } + } + + + } +} diff --git a/MinioCoreTest/Cases/PresignedGetObject.cs b/MinioCoreTest/Cases/PresignedGetObject.cs new file mode 100644 index 000000000..b6072a6e7 --- /dev/null +++ b/MinioCoreTest/Cases/PresignedGetObject.cs @@ -0,0 +1,32 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using MinioCore2; +using System; + +namespace MinioCoreTest.Cases +{ + public class PresignedGetObject + { + public static int Run(MinioClient client) + { + Console.Out.WriteLine(client.PresignedGetObject("my-bucketname", "my-objectname", 1000)); + return 0; + } + } +} + + \ No newline at end of file diff --git a/MinioCoreTest/Cases/PresignedPostPolicy.cs b/MinioCoreTest/Cases/PresignedPostPolicy.cs new file mode 100644 index 000000000..6da5f5e98 --- /dev/null +++ b/MinioCoreTest/Cases/PresignedPostPolicy.cs @@ -0,0 +1,45 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using MinioCore2; +using MinioCore2.DataModel; +using System; +using System.Collections.Generic; + +namespace MinioCoreTest.Cases +{ + public class PresignedPostPolicy + { + public static int Run(MinioClient client) + { + PostPolicy form = new PostPolicy(); + DateTime expiration = DateTime.UtcNow; + form.SetExpires(expiration.AddDays(10)); + form.SetKey("my-objectname"); + form.SetBucket("my-bucketname"); + + Dictionary formData = client.PresignedPostPolicy(form); + string curlCommand = "curl "; + foreach (KeyValuePair pair in formData) + { + curlCommand = curlCommand + " -F " + pair.Key + "=" + pair.Value; + } + curlCommand = curlCommand + " -F file=@/etc/bashrc https://s3.amazonaws.com/my-bucketname"; + Console.Out.WriteLine(curlCommand); + return 0; + } + } +} diff --git a/MinioCoreTest/Cases/PresignedPutObject.cs b/MinioCoreTest/Cases/PresignedPutObject.cs new file mode 100644 index 000000000..358271ae5 --- /dev/null +++ b/MinioCoreTest/Cases/PresignedPutObject.cs @@ -0,0 +1,29 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using MinioCore2; +namespace MinioCoreTest.Cases +{ + public class PresignedPutObject + { + public static int Run(MinioClient client) + { + Console.Out.WriteLine(client.PresignedPutObject("my-bucketname", "my-objectname", 1000)); + return 0; + } + } +} diff --git a/MinioCoreTest/Cases/PutObject.cs b/MinioCoreTest/Cases/PutObject.cs new file mode 100644 index 000000000..fa333eb10 --- /dev/null +++ b/MinioCoreTest/Cases/PutObject.cs @@ -0,0 +1,51 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.IO; +using System.Threading.Tasks; + +namespace MinioCoreTest.Cases +{ + class PutObject + { + //Put an object from a local stream into bucket + public async static Task Run(MinioCore2.MinioClient minio, + string bucketName = "my-bucket-name", + string objectName = "my-object-name", + string fileName="location-of-file") + { + try + { + byte[] bs = File.ReadAllBytes(fileName); + System.IO.MemoryStream filestream = new System.IO.MemoryStream(bs); + + await minio.PutObjectAsync(bucketName, + objectName, + filestream, + filestream.Length, + "application/octet-stream"); + + Console.Out.WriteLine("done uploading"); + } + catch (Exception e) + { + Console.WriteLine("[Bucket] Exception: {0}", e); + } + } + + } +} diff --git a/MinioCoreTest/Cases/RemoveBucket.cs b/MinioCoreTest/Cases/RemoveBucket.cs new file mode 100644 index 000000000..f0ef3cf2a --- /dev/null +++ b/MinioCoreTest/Cases/RemoveBucket.cs @@ -0,0 +1,40 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using MinioCore2; +using System; +using System.Threading.Tasks; + +namespace MinioCoreTest.Cases +{ + class RemoveBucket + { + //Remove a bucket + public async static Task Run(MinioClient minio, + string bucketName = "my-bucket-name") + { + try + { + await minio.RemoveBucketAsync(bucketName); + Console.Out.WriteLine("bucket-name removed successfully"); + } + catch (Exception e) + { + Console.WriteLine("[Bucket] Exception: {0}", e); + } + } + } +} diff --git a/MinioCoreTest/Cases/RemoveIncompleteUpload.cs b/MinioCoreTest/Cases/RemoveIncompleteUpload.cs new file mode 100644 index 000000000..e41f28f32 --- /dev/null +++ b/MinioCoreTest/Cases/RemoveIncompleteUpload.cs @@ -0,0 +1,42 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using MinioCore2; +using System; +using System.Threading.Tasks; + +namespace MinioCoreTest.Cases +{ + class RemoveIncompleteUpload + { + + //Remove incomplete upload object from a bucket + public async static Task Run(MinioClient minio, + string bucketName = "my-bucket-name", + string objectName = "my-object-name") + { + try + { + await minio.RemoveIncompleteUploadAsync(bucketName, objectName); + Console.Out.WriteLine("object-name removed from bucket-name successfully"); + } + catch (Exception e) + { + Console.WriteLine("[Bucket-Object] Exception: {0}", e); + } + } + } +} diff --git a/MinioCoreTest/Cases/RemoveObject.cs b/MinioCoreTest/Cases/RemoveObject.cs new file mode 100644 index 000000000..58021c981 --- /dev/null +++ b/MinioCoreTest/Cases/RemoveObject.cs @@ -0,0 +1,41 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using MinioCore2; +using System; +using System.Threading.Tasks; + +namespace MinioCoreTest.Cases +{ + class RemoveObject + { + //Remove an object from a bucket + public async static Task Run(MinioClient minio, + string bucketName = "my-bucket-name", + string objectName = "my-object-name") + { + try + { + await minio.RemoveObjectAsync(bucketName,objectName); + Console.Out.WriteLine("object-name removed from bucket-name successfully"); + } + catch (Exception e) + { + Console.WriteLine("[Bucket-Object] Exception: {0}", e); + } + } + } +} diff --git a/MinioCoreTest/Cases/SetBucketPolicy.cs b/MinioCoreTest/Cases/SetBucketPolicy.cs new file mode 100644 index 000000000..f984994c6 --- /dev/null +++ b/MinioCoreTest/Cases/SetBucketPolicy.cs @@ -0,0 +1,44 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Threading.Tasks; +using MinioCore2.DataModel; + +namespace MinioCoreTest.Cases +{ + class SetBucketPolicy + { + //set bucket policy + public async static Task Run(MinioCore2.MinioClient minio, + string bucketName = "my-bucket-name", + string objectPrefix="") + { + try + { + //Change policy type parameter + await minio.SetPolicyAsync(bucketName, + objectPrefix, + PolicyType.READ_ONLY); + + } + catch (Exception e) + { + Console.WriteLine("[Bucket] Exception: {0}", e); + } + } + } +} diff --git a/MinioCoreTest/Cases/StatObject.cs b/MinioCoreTest/Cases/StatObject.cs new file mode 100644 index 000000000..a39df998e --- /dev/null +++ b/MinioCoreTest/Cases/StatObject.cs @@ -0,0 +1,41 @@ +/* + * Minio .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Threading.Tasks; +using MinioCore2.DataModel; + +namespace MinioCoreTest.Cases +{ + class StatObject + { + //get stats on a object + public async static Task Run(MinioCore2.MinioClient minio, + string bucketName = "my-bucket-name", + string bucketObject="my-object-name") + { + try + { + ObjectStat statObject = await minio.StatObjectAsync(bucketName, bucketObject); + Console.Out.WriteLine(statObject); + } + catch (Exception e) + { + Console.WriteLine("[StatObject] {0}-{1} Exception: {2}",bucketName, bucketObject, e); + } + } + } +} diff --git a/MinioCoreTest/MinioCoreTest.xproj b/MinioCoreTest/MinioCoreTest.xproj new file mode 100644 index 000000000..ada33f412 --- /dev/null +++ b/MinioCoreTest/MinioCoreTest.xproj @@ -0,0 +1,21 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + 64264a30-e6ab-49d8-8f84-3ae4fac54e09 + MinioCoreTest + .\obj + .\bin\ + v4.5.2 + + + + 2.0 + + + diff --git a/MinioCoreTest/Program.cs b/MinioCoreTest/Program.cs new file mode 100644 index 000000000..2b359f95b --- /dev/null +++ b/MinioCoreTest/Program.cs @@ -0,0 +1,84 @@ +using MinioCore2; +using MinioCore2.Exceptions; +using System; +namespace MinioCoreTest +{ + public class Program + { + static void Main(string[] args) + { + + //ServicePointManager.Expect100Continue = true; + //ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 + // | SecurityProtocolType.Tls11 + // | SecurityProtocolType.Tls12; + // WinHttpHandler httpHandler = new WinHttpHandler(); + // httpHandler.SslProtocols = System.Security.Authentication.SslProtocols.Tls12; + var endPoint = "play.minio.io:9000"; + var accessKey = "Q3AM3UQ867SPQQA43P2F"; + var secretKey = "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG"; + // var endPoint = Environment.GetEnvironmentVariable("AWS_ENDPOINT"); + // var accessKey = Environment.GetEnvironmentVariable("AWS_ACCESS_KEY"); + // var secretKey = Environment.GetEnvironmentVariable("AWS_SECRET_KEY"); + + var minioClient = new MinioClient(endPoint, accessKey, secretKey).WithSSL(); + try + { + // Change these parameters before running examples + string bucketName = "testminiopolicy"; + string objectName = "goldengate.jpg"; + string objectPrefix = "gold"; + string smallFilePath = "C:\\Users\\vagrant\\Downloads\\hellotext"; + string uploadFilePath = "C:\\Users\\vagrant\\Downloads\\go1.7.4.windows-amd64.msi"; + string downloadFilePath = "C:\\Users\\vagrant\\Downloads\\downloaded-object"; + string destBucketName = "testminiopoli"; + string destObjectName = "goldengate_copy.jpg"; + string removeObject = "goldengate_pic"; + + // Set app Info + minioClient.SetAppInfo("app-name", "app-version"); + + // Set HTTP Tracing On + // minioClient.SetTraceOn(); + + // Set HTTP Tracing Off + // minioClient.SetTraceOff(); + + //* UNCOMMENT CASE TO RUN A TEST + + // Cases.BucketExists.Run(minioClient, bucketName).Wait(); + + Cases.MakeBucket.Run(minioClient, bucketName).Wait(); + + Cases.ListBuckets.Run(minioClient).Wait(); + Cases.ListObjects.Run(minioClient, bucketName); + Cases.PutObject.Run(minioClient, bucketName, objectName, smallFilePath).Wait(); + Cases.GetObject.Run(minioClient, bucketName, objectName).Wait(); + Cases.FPutObject.Run(minioClient, bucketName, objectName, uploadFilePath).Wait(); + + Cases.FGetObject.Run(minioClient, bucketName, objectName, downloadFilePath).Wait(); + + Cases.RemoveObject.Run(minioClient, bucketName, objectName).Wait(); + Cases.RemoveBucket.Run(minioClient, bucketName).Wait(); + Cases.ListIncompleteUploads.Run(minioClient, bucketName, prefix: objectPrefix); + Cases.RemoveIncompleteUpload.Run(minioClient, bucketName, removeObject).Wait(); + + Cases.GetBucketPolicy.Run(minioClient, bucketName).Wait(); + + Cases.SetBucketPolicy.Run(minioClient, bucketName).Wait(); + Cases.StatObject.Run(minioClient, bucketName, objectName).Wait(); + Cases.CopyObject.Run(minioClient, bucketName, objectName, destBucketName, destObjectName).Wait(); + + Cases.PresignedGetObject.Run(minioClient); + Cases.PresignedPostPolicy.Run(minioClient); + Cases.PresignedPutObject.Run(minioClient); + + Console.ReadLine(); + } + catch (MinioException ex) + { + Console.Out.WriteLine(ex.Message); + } + } + } +} diff --git a/MinioCoreTest/Properties/AssemblyInfo.cs b/MinioCoreTest/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..c76d0decb --- /dev/null +++ b/MinioCoreTest/Properties/AssemblyInfo.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Vagrant Inc.")] +[assembly: AssemblyProduct("MinioCoreTest")] +[assembly: AssemblyTrademark("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("64264a30-e6ab-49d8-8f84-3ae4fac54e09")] diff --git a/MinioCoreTest/project.json b/MinioCoreTest/project.json new file mode 100644 index 000000000..c78cd57d5 --- /dev/null +++ b/MinioCoreTest/project.json @@ -0,0 +1,22 @@ +{ + "version": "1.0.0-*", + "buildOptions": { + "emitEntryPoint": true + }, + + "dependencies": { + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.1" + }, + "MinioCore2": "1.0.0-*", + "System.Net.Http.WinHttpHandler": "4.3.0" + }, + + "frameworks": { + "netcoreapp1.0": { + "imports": "dnxcore50" + } + } +} + diff --git a/README.md b/README.md index a6f03f891..2f6cced77 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Minio Client SDK for .NET [![Slack](https://slack.minio.io/slack?type=svg)](https://slack.minio.io) +# Minio Client SDK for .NET [![Slack](https://slack.minio.io/slack?type=svg)](https://slack.minio.io) [![Build Status](https://travis-ci.org/minio/minio-dotnet.svg?branch=master)](https://travis-ci.org/minio/minio-dotnet) Minio Client SDK provides higher level APIs for Minio and Amazon S3 compatible cloud storage services. @@ -7,9 +7,8 @@ For a complete list of APIs and examples, please take a look at the [Dotnet Clie This document assumes that you have a working VisualStudio development environment. ## Minimum Requirements - -- .NET 4.5 or higher -- Visual Studio 10 or higher + .NET 4.5 or higher + Visual Studio 2015 ## Install from NuGet @@ -30,25 +29,6 @@ To connect to an Amazon S3 compatible cloud storage service, you will need to sp | secure | Enable/Disable HTTPS support. | The following examples uses a freely hosted public Minio service 'play.minio.io' for development purposes. -```cs -using Minio; - -private static MinioClient minio = new MinioClient("play.minio.io:9000", - "Q3AM3UQ867SPQQA43P2F", - "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG" - ).WithSSL(); - -// List buckets on the play.minio.io server -var getListBucketsTask = minio.Api.ListBucketsAsync(); -Task.WaitAll(getListBucketsTask); // block while the task completes -var list = getListBucketsTask.Result; - -foreach (Bucket bucket in list.Buckets) -{ - Console.Out.WriteLine(bucket.Name + " " + bucket.CreationDate.DateTime); -} - -``` ```cs using Minio; @@ -60,7 +40,7 @@ private static MinioClient minio = new MinioClient("play.minio.io:9000", ).WithSSL(); // Create an async task for listing buckets. -var getListBucketsTask = minio.Api.ListBucketsAsync(); +var getListBucketsTask = minio.ListBucketsAsync(); // Iterate over the list of buckets. foreach (Bucket bucket in getListBucketsTask.Result.Buckets) @@ -112,13 +92,16 @@ namespace FileUploader try { - // Make a bucket on the server. - await minio.Api.MakeBucketAsync(bucketName, location); - - // Upload a file to bucket. - await minio.Api.PutObjectAsync(bucketName, objectName, filePath, contentType); - - Console.Out.WriteLine("Successfully uploaded " + objectName); + // Make a bucket on the server, if not already present. + bool found = await minio.BucketExistsAsync(bucketName); + if (!found) + { + await minio.MakeBucketAsync(bucketName, location); + } + + // Upload a file to bucket. + await minio.PutObjectAsync(bucketName, objectName, filePath, contentType); + Console.Out.WriteLine("Successfully uploaded " + objectName ); } catch (MinioException e) { @@ -129,9 +112,17 @@ namespace FileUploader } ``` -## Full Examples +## Running Minio Client Examples +* Clone this repository. -#### Full Examples: Bucket Operations +* Build the project to produce the Minio.Examples console app. + +* Move into Minio.Examples directory and enter your credentials and bucket name, object name etc. + Uncomment the example test cases such as below in Program.cs to run an example. +```cs + //Cases.MakeBucket.Run(minioClient, bucketName).Wait(); +``` +#### Bucket Operations * [MakeBucket.cs](./Minio.Examples/Cases/MakeBucket.cs) * [ListBuckets.cs](./Minio.Examples/Cases/ListBuckets.cs) @@ -140,15 +131,15 @@ namespace FileUploader * [Listobjects.cs](./Minio.Examples/Cases/Listobjects.cs) * [ListIncompleteUploads.cs](./Minio.Examples/Cases/ListIncompleteUploads.cs) -#### Full Examples: Bucket Policy Operations +#### Bucket policy Operations * [GetPolicy.cs](./Minio.Examples/Cases/GetPolicy.cs) * [SetPolicy.cs](./Minio.Examples/Cases/SetPolicy.cs) -#### Full Examples: File Object Operations +#### File Object Operations * [FGetObject.cs](./Minio.Examples/Cases/FGetObject.cs) * [FPutObject.cs](./Minio.Examples/Cases/FPutObject.cs) -#### Full Examples: Object Operations +#### Object Operations * [GetObject.cs](./Minio.Examples/Cases/GetObject.cs) * [PutObject.cs](./Minio.Examples/Cases/PutObject.cs) * [StatObject.cs](./Minio.Examples/Cases/StatObject.cs) @@ -156,16 +147,19 @@ namespace FileUploader * [CopyObject.cs](./Minio.Examples/Cases/CopyObject.cs) * [RemoveIncompleteUpload.cs](./Minio.Examples/Cases/RemoveIncompleteUpload.cs) -#### Full Examples: Presigned Operations +#### Presigned Operations * [PresignedGetObject.cs](./Minio.Examples/Cases/PresignedGetObject.cs) * [PresignedPutObject.cs](./Minio.Examples/Cases/PresignedPutObject.cs) * [PresignedPostPolicy.cs](./Minio.Examples/Cases/PresignedPostPolicy.cs) +#### Client Custom Settings +* [SetAppInfo](./Minio.Examples/Program.cs) +* [SetTraceOn](./Minio.Examples/Program.cs) +* [SetTraceOff](./Minio.Examples/Program.cs) + ## Explore Further * [Complete Documentation](https://docs.minio.io) ## Contribute -[Contributors Guide](https://github.com/minio/minio-go/blob/master/CONTRIBUTING.md) - -[![Build Status](https://travis-ci.org/minio/minio-dotnet.svg?branch=master)](https://travis-ci.org/minio/minio-dotnet) \ No newline at end of file +[Contributors Guide](https://github.com/minio/minio-go/blob/master/CONTRIBUTING.md) \ No newline at end of file diff --git a/SimpleTest/App.config b/SimpleTest/App.config deleted file mode 100644 index e677effec..000000000 --- a/SimpleTest/App.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/SimpleTest/Program.cs b/SimpleTest/Program.cs deleted file mode 100644 index 98f4c52c9..000000000 --- a/SimpleTest/Program.cs +++ /dev/null @@ -1,72 +0,0 @@ - -using System; -using Minio; -using Minio.DataModel; - -using System.Configuration; -using System.Threading.Tasks; - -using System.Net; - -namespace SimpleTest -{ - class Program - { - static void Main(string[] args) - { - - ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 - | SecurityProtocolType.Tls11 - | SecurityProtocolType.Tls12; - - - /// Note: s3 AccessKey and SecretKey needs to be added in App.config file - /// See instructions in README.md on running examples for more information. - var minio = new MinioClient(ConfigurationManager.AppSettings["Endpoint"], - ConfigurationManager.AppSettings["AccessKey"], - ConfigurationManager.AppSettings["SecretKey"]).WithSSL(); - - var getListBucketsTask = minio.Api.ListBucketsAsync(); - try - { - Task.WaitAll(getListBucketsTask); // block while the task completes - } catch(AggregateException aggEx) - { - aggEx.Handle(HandleBatchExceptions); - } - var list = getListBucketsTask.Result; - - foreach (Bucket bucket in list.Buckets) - { - Console.Out.WriteLine(bucket.Name + " " + bucket.CreationDateDateTime); - } - - //Supply a new bucket name - Task.WaitAll(minio.Api.MakeBucketAsync("mynewbucket")); - - var bucketExistTask = minio.Api.BucketExistsAsync("mynewbucket"); - Task.WaitAll(bucketExistTask); - var found = bucketExistTask.Result; - Console.Out.WriteLine("bucket was " + found); - Console.ReadLine(); - } - private static bool HandleBatchExceptions(Exception exceptionToHandle) - { - if (exceptionToHandle is ArgumentNullException) - { - //I'm handling the ArgumentNullException. - Console.WriteLine("Handling the ArgumentNullException."); - //I handled this Exception, return true. - return true; - } - else - { - //I'm only handling ArgumentNullExceptions. - Console.WriteLine(string.Format("I'm not handling the {0}.", exceptionToHandle.GetType())); - //I didn't handle this Exception, return false. - return false; - } - } - - } -} diff --git a/SimpleTest2/App.config b/SimpleTest2/App.config new file mode 100644 index 000000000..88fa4027b --- /dev/null +++ b/SimpleTest2/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Minio.Api/ApiEndpoints/RequestHelper.cs b/SimpleTest2/Program.cs similarity index 50% rename from Minio.Api/ApiEndpoints/RequestHelper.cs rename to SimpleTest2/Program.cs index 838f0768a..c7b67b5d3 100644 --- a/Minio.Api/ApiEndpoints/RequestHelper.cs +++ b/SimpleTest2/Program.cs @@ -1,15 +1,15 @@ -using RestSharp; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Minio.Helper +namespace SimpleTest2 { - public partial class ClientApiOperations + class Program { - - + static void Main(string[] args) + { + } } } diff --git a/SimpleTest/Properties/AssemblyInfo.cs b/SimpleTest2/Properties/AssemblyInfo.cs similarity index 90% rename from SimpleTest/Properties/AssemblyInfo.cs rename to SimpleTest2/Properties/AssemblyInfo.cs index ddb428c51..e37f83a64 100644 --- a/SimpleTest/Properties/AssemblyInfo.cs +++ b/SimpleTest2/Properties/AssemblyInfo.cs @@ -5,11 +5,11 @@ // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("SimpleTest")] +[assembly: AssemblyTitle("SimpleTest2")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Vagrant Inc.")] -[assembly: AssemblyProduct("SimpleTest")] +[assembly: AssemblyProduct("SimpleTest2")] [assembly: AssemblyCopyright("Copyright © Vagrant Inc. 2017")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -20,7 +20,7 @@ [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("af2df297-402b-46b8-8954-c5a934967a51")] +[assembly: Guid("1bc68272-97b9-4cfc-84ac-1c6365273a94")] // Version information for an assembly consists of the following four values: // diff --git a/SimpleTest/SimpleTest.csproj b/SimpleTest2/SimpleTest2.csproj similarity index 85% rename from SimpleTest/SimpleTest.csproj rename to SimpleTest2/SimpleTest2.csproj index de08d690f..9e91f6505 100644 --- a/SimpleTest/SimpleTest.csproj +++ b/SimpleTest2/SimpleTest2.csproj @@ -4,11 +4,11 @@ Debug AnyCPU - {AF2DF297-402B-46B8-8954-C5A934967A51} + {1BC68272-97B9-4CFC-84AC-1C6365273A94} Exe Properties - SimpleTest - SimpleTest + SimpleTest2 + SimpleTest2 v4.5.2 512 true @@ -34,7 +34,6 @@ - @@ -50,12 +49,6 @@ - - - {cc30cade-342a-4ced-858d-b60200c075b0} - MinioApi - -