diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a90ac70..4704139a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,7 +46,7 @@ ENDIF (${CMAKE_BINARY_DIR} STREQUAL ${CMAKE_SOURCE_DIR}) SET(requiredlibs) IF(CMAKE_COMPILER_IS_GNUCC) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Wconversion") IF(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0 AND NOT MINGW) list(APPEND requiredlibs stdc++fs) ENDIF() diff --git a/examples/BucketExists.cc b/examples/BucketExists.cc index e07d8376..16fb2db2 100644 --- a/examples/BucketExists.cc +++ b/examples/BucketExists.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/ComposeObject.cc b/examples/ComposeObject.cc index 9fcd83af..2139fe69 100644 --- a/examples/ComposeObject.cc +++ b/examples/ComposeObject.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/CopyObject.cc b/examples/CopyObject.cc index 290f2dca..d978a1ff 100644 --- a/examples/CopyObject.cc +++ b/examples/CopyObject.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/DeleteBucketEncryption.cc b/examples/DeleteBucketEncryption.cc index 45991047..851a0dd2 100644 --- a/examples/DeleteBucketEncryption.cc +++ b/examples/DeleteBucketEncryption.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/DeleteBucketLifecycle.cc b/examples/DeleteBucketLifecycle.cc index 81842892..51e86427 100644 --- a/examples/DeleteBucketLifecycle.cc +++ b/examples/DeleteBucketLifecycle.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/DeleteBucketNotification.cc b/examples/DeleteBucketNotification.cc index c1504374..c296b054 100644 --- a/examples/DeleteBucketNotification.cc +++ b/examples/DeleteBucketNotification.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/DeleteBucketPolicy.cc b/examples/DeleteBucketPolicy.cc index b29b93b1..d4590226 100644 --- a/examples/DeleteBucketPolicy.cc +++ b/examples/DeleteBucketPolicy.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/DeleteBucketReplication.cc b/examples/DeleteBucketReplication.cc index 45991047..851a0dd2 100644 --- a/examples/DeleteBucketReplication.cc +++ b/examples/DeleteBucketReplication.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/DeleteBucketTags.cc b/examples/DeleteBucketTags.cc index da5c667f..3db668f2 100644 --- a/examples/DeleteBucketTags.cc +++ b/examples/DeleteBucketTags.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/DeleteObjectLockConfig.cc b/examples/DeleteObjectLockConfig.cc index 481c475e..4774755f 100644 --- a/examples/DeleteObjectLockConfig.cc +++ b/examples/DeleteObjectLockConfig.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/DeleteObjectTags.cc b/examples/DeleteObjectTags.cc index c95ecd8e..669bc4e1 100644 --- a/examples/DeleteObjectTags.cc +++ b/examples/DeleteObjectTags.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/DisableObjectLegalHold.cc b/examples/DisableObjectLegalHold.cc index d111a7df..648314f7 100644 --- a/examples/DisableObjectLegalHold.cc +++ b/examples/DisableObjectLegalHold.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/DownloadObject.cc b/examples/DownloadObject.cc index b678b781..e1941b03 100644 --- a/examples/DownloadObject.cc +++ b/examples/DownloadObject.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/EnableObjectLegalHold.cc b/examples/EnableObjectLegalHold.cc index c2646d73..5d6e09bd 100644 --- a/examples/EnableObjectLegalHold.cc +++ b/examples/EnableObjectLegalHold.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/GetBucketEncryption.cc b/examples/GetBucketEncryption.cc index a47c4778..f8987d2c 100644 --- a/examples/GetBucketEncryption.cc +++ b/examples/GetBucketEncryption.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/GetBucketLifecycle.cc b/examples/GetBucketLifecycle.cc index f09ea39d..bc6f28e2 100644 --- a/examples/GetBucketLifecycle.cc +++ b/examples/GetBucketLifecycle.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/GetBucketNotification.cc b/examples/GetBucketNotification.cc index 5c9630cd..4732e8d5 100644 --- a/examples/GetBucketNotification.cc +++ b/examples/GetBucketNotification.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/GetBucketPolicy.cc b/examples/GetBucketPolicy.cc index 48cce26f..138aa8c6 100644 --- a/examples/GetBucketPolicy.cc +++ b/examples/GetBucketPolicy.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/GetBucketReplication.cc b/examples/GetBucketReplication.cc index a47c4778..f8987d2c 100644 --- a/examples/GetBucketReplication.cc +++ b/examples/GetBucketReplication.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/GetBucketTags.cc b/examples/GetBucketTags.cc index 68b45429..81bd8b36 100644 --- a/examples/GetBucketTags.cc +++ b/examples/GetBucketTags.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/GetBucketVersioning.cc b/examples/GetBucketVersioning.cc index f1b798d3..58aa5430 100644 --- a/examples/GetBucketVersioning.cc +++ b/examples/GetBucketVersioning.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/GetObject.cc b/examples/GetObject.cc index 85fe35c5..fbd311eb 100644 --- a/examples/GetObject.cc +++ b/examples/GetObject.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/GetObjectLockConfig.cc b/examples/GetObjectLockConfig.cc index 7539fbc7..4249d25e 100644 --- a/examples/GetObjectLockConfig.cc +++ b/examples/GetObjectLockConfig.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/GetObjectProgress.cc b/examples/GetObjectProgress.cc index f78fcf7e..be65bbf4 100644 --- a/examples/GetObjectProgress.cc +++ b/examples/GetObjectProgress.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/GetObjectRetention.cc b/examples/GetObjectRetention.cc index 9b1d56bb..40587a3f 100644 --- a/examples/GetObjectRetention.cc +++ b/examples/GetObjectRetention.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/GetObjectTags.cc b/examples/GetObjectTags.cc index 8b0d8804..e862a7cd 100644 --- a/examples/GetObjectTags.cc +++ b/examples/GetObjectTags.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/GetPresignedObjectUrl.cc b/examples/GetPresignedObjectUrl.cc index bf215be5..85906458 100644 --- a/examples/GetPresignedObjectUrl.cc +++ b/examples/GetPresignedObjectUrl.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/GetPresignedPostFormData.cc b/examples/GetPresignedPostFormData.cc index 36a9f41c..ef960a92 100644 --- a/examples/GetPresignedPostFormData.cc +++ b/examples/GetPresignedPostFormData.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/IsObjectLegalHoldEnabled.cc b/examples/IsObjectLegalHoldEnabled.cc index 9154c365..781bbf0c 100644 --- a/examples/IsObjectLegalHoldEnabled.cc +++ b/examples/IsObjectLegalHoldEnabled.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/ListBuckets.cc b/examples/ListBuckets.cc index bd0650b2..39a095e6 100644 --- a/examples/ListBuckets.cc +++ b/examples/ListBuckets.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/ListObjects.cc b/examples/ListObjects.cc index 6a2c6c51..3bc35953 100644 --- a/examples/ListObjects.cc +++ b/examples/ListObjects.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/ListenBucketNotification.cc b/examples/ListenBucketNotification.cc index 1f6119fc..2f8ede44 100644 --- a/examples/ListenBucketNotification.cc +++ b/examples/ListenBucketNotification.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/MakeBucket.cc b/examples/MakeBucket.cc index 41382938..44837bc6 100644 --- a/examples/MakeBucket.cc +++ b/examples/MakeBucket.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/PutObject.cc b/examples/PutObject.cc index 17a83465..14071d38 100644 --- a/examples/PutObject.cc +++ b/examples/PutObject.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/PutObjectProgress.cc b/examples/PutObjectProgress.cc index e291cda0..aae1cc8d 100644 --- a/examples/PutObjectProgress.cc +++ b/examples/PutObjectProgress.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/RemoveBucket.cc b/examples/RemoveBucket.cc index 824912c9..0045e0fe 100644 --- a/examples/RemoveBucket.cc +++ b/examples/RemoveBucket.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/RemoveObject.cc b/examples/RemoveObject.cc index 71a207ed..85257285 100644 --- a/examples/RemoveObject.cc +++ b/examples/RemoveObject.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/RemoveObjects.cc b/examples/RemoveObjects.cc index c4496e27..35b1436f 100644 --- a/examples/RemoveObjects.cc +++ b/examples/RemoveObjects.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/SelectObjectContent.cc b/examples/SelectObjectContent.cc index d552a7d5..7538a77f 100644 --- a/examples/SelectObjectContent.cc +++ b/examples/SelectObjectContent.cc @@ -16,7 +16,7 @@ #include "client.h" #include "select.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/SetBucketEncryption.cc b/examples/SetBucketEncryption.cc index 92693042..e249411b 100644 --- a/examples/SetBucketEncryption.cc +++ b/examples/SetBucketEncryption.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/SetBucketLifecycle.cc b/examples/SetBucketLifecycle.cc index a2f73f9c..c358f233 100644 --- a/examples/SetBucketLifecycle.cc +++ b/examples/SetBucketLifecycle.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/SetBucketNotification.cc b/examples/SetBucketNotification.cc index e64f1651..dddbb86c 100644 --- a/examples/SetBucketNotification.cc +++ b/examples/SetBucketNotification.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/SetBucketPolicy.cc b/examples/SetBucketPolicy.cc index 070ea66e..0a25c185 100644 --- a/examples/SetBucketPolicy.cc +++ b/examples/SetBucketPolicy.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/SetBucketReplication.cc b/examples/SetBucketReplication.cc index 32890a01..e9758f24 100644 --- a/examples/SetBucketReplication.cc +++ b/examples/SetBucketReplication.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/SetBucketTags.cc b/examples/SetBucketTags.cc index 24d51186..b0be1da5 100644 --- a/examples/SetBucketTags.cc +++ b/examples/SetBucketTags.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/SetBucketVersioning.cc b/examples/SetBucketVersioning.cc index dec2c4f2..26627df5 100644 --- a/examples/SetBucketVersioning.cc +++ b/examples/SetBucketVersioning.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/SetObjectLockConfig.cc b/examples/SetObjectLockConfig.cc index e8c8a33d..77236da3 100644 --- a/examples/SetObjectLockConfig.cc +++ b/examples/SetObjectLockConfig.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/SetObjectRetention.cc b/examples/SetObjectRetention.cc index e0e17dc9..95a74505 100644 --- a/examples/SetObjectRetention.cc +++ b/examples/SetObjectRetention.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/SetObjectTags.cc b/examples/SetObjectTags.cc index 3201fe19..fa675506 100644 --- a/examples/SetObjectTags.cc +++ b/examples/SetObjectTags.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/StatObject.cc b/examples/StatObject.cc index 30d822e6..ac367b21 100644 --- a/examples/StatObject.cc +++ b/examples/StatObject.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/examples/UploadObject.cc b/examples/UploadObject.cc index ff4ada5c..364bbc12 100644 --- a/examples/UploadObject.cc +++ b/examples/UploadObject.cc @@ -15,7 +15,7 @@ #include "client.h" -int main(int argc, char* argv[]) { +int main() { // Create S3 base URL. minio::s3::BaseUrl base_url("play.min.io"); diff --git a/include/args.h b/include/args.h index d55d3c12..9fb1d8f8 100644 --- a/include/args.h +++ b/include/args.h @@ -16,9 +16,6 @@ #ifndef _MINIO_S3_ARGS_H #define _MINIO_S3_ARGS_H -#include -#include - #include "http.h" #include "signer.h" #include "sse.h" @@ -29,56 +26,80 @@ namespace s3 { struct BaseArgs { utils::Multimap extra_headers; utils::Multimap extra_query_params; + + BaseArgs() = default; + ~BaseArgs() = default; }; // struct BaseArgs struct BucketArgs : public BaseArgs { std::string bucket; std::string region; - error::Error Validate(); + BucketArgs() = default; + ~BucketArgs() = default; + + error::Error Validate() const; }; // struct BucketArgs struct ObjectArgs : public BucketArgs { std::string object; - error::Error Validate(); + ObjectArgs() = default; + ~ObjectArgs() = default; + + error::Error Validate() const; }; // struct ObjectArgs struct ObjectWriteArgs : public ObjectArgs { utils::Multimap headers; utils::Multimap user_metadata; - Sse *sse = NULL; + Sse *sse = nullptr; std::map tags; - Retention *retention = NULL; + Retention *retention = nullptr; bool legal_hold = false; - utils::Multimap Headers(); + ObjectWriteArgs() = default; + ~ObjectWriteArgs() = default; + + utils::Multimap Headers() const; }; // struct ObjectWriteArgs struct ObjectVersionArgs : public ObjectArgs { std::string version_id; + + ObjectVersionArgs() = default; + ~ObjectVersionArgs() = default; }; // struct ObjectVersionArgs struct ObjectReadArgs : public ObjectVersionArgs { - SseCustomerKey *ssec = NULL; + SseCustomerKey *ssec = nullptr; + + ObjectReadArgs() = default; + ~ObjectReadArgs() = default; }; // struct ObjectReadArgs struct ObjectConditionalReadArgs : public ObjectReadArgs { - size_t *offset = NULL; - size_t *length = NULL; + size_t *offset = nullptr; + size_t *length = nullptr; std::string match_etag; std::string not_match_etag; utils::Time modified_since; utils::Time unmodified_since; - utils::Multimap Headers(); - utils::Multimap CopyHeaders(); + ObjectConditionalReadArgs() = default; + ~ObjectConditionalReadArgs() = default; + + utils::Multimap Headers() const; + utils::Multimap CopyHeaders() const; }; // struct ObjectConditionalReadArgs struct MakeBucketArgs : public BucketArgs { bool object_lock = false; - error::Error Validate(); + MakeBucketArgs() = default; + ~MakeBucketArgs() = default; + + error::Error Validate() const; }; // struct MakeBucketArgs using ListBucketsArgs = BaseArgs; @@ -90,18 +111,27 @@ using RemoveBucketArgs = BucketArgs; struct AbortMultipartUploadArgs : public ObjectArgs { std::string upload_id; - error::Error Validate(); + AbortMultipartUploadArgs() = default; + ~AbortMultipartUploadArgs() = default; + + error::Error Validate() const; }; // struct AbortMultipartUploadArgs struct CompleteMultipartUploadArgs : public ObjectArgs { std::string upload_id; std::list parts; - error::Error Validate(); + CompleteMultipartUploadArgs() = default; + ~CompleteMultipartUploadArgs() = default; + + error::Error Validate() const; }; // struct CompleteMultipartUploadArgs struct CreateMultipartUploadArgs : public ObjectArgs { utils::Multimap headers; + + CreateMultipartUploadArgs() = default; + ~CreateMultipartUploadArgs() = default; }; // struct CreateMultipartUploadArgs struct PutObjectBaseArgs : public ObjectWriteArgs { @@ -109,23 +139,32 @@ struct PutObjectBaseArgs : public ObjectWriteArgs { size_t part_size = 0; long part_count = 0; std::string content_type; + + PutObjectBaseArgs() = default; + ~PutObjectBaseArgs() = default; }; // struct PutObjectBaseArgs struct PutObjectApiArgs : public PutObjectBaseArgs { std::string_view data; utils::Multimap query_params; - http::ProgressFunction progressfunc = NULL; - void *progress_userdata = NULL; + http::ProgressFunction progressfunc = nullptr; + void *progress_userdata = nullptr; + + PutObjectApiArgs() = default; + ~PutObjectApiArgs() = default; }; // struct PutObjectApiArgs struct UploadPartArgs : public ObjectWriteArgs { std::string upload_id; unsigned int part_number; std::string_view data; - http::ProgressFunction progressfunc = NULL; - void *progress_userdata = NULL; + http::ProgressFunction progressfunc = nullptr; + void *progress_userdata = nullptr; - error::Error Validate(); + UploadPartArgs() = default; + ~UploadPartArgs() = default; + + error::Error Validate() const; }; // struct UploadPartArgs struct UploadPartCopyArgs : public ObjectWriteArgs { @@ -133,7 +172,10 @@ struct UploadPartCopyArgs : public ObjectWriteArgs { unsigned int part_number; utils::Multimap headers; - error::Error Validate(); + UploadPartCopyArgs() = default; + ~UploadPartCopyArgs() = default; + + error::Error Validate() const; }; // struct UploadPartCopyArgs using StatObjectArgs = ObjectConditionalReadArgs; @@ -143,19 +185,25 @@ using RemoveObjectArgs = ObjectVersionArgs; struct DownloadObjectArgs : public ObjectReadArgs { std::string filename; bool overwrite; - http::ProgressFunction progressfunc = NULL; - void *progress_userdata = NULL; + http::ProgressFunction progressfunc = nullptr; + void *progress_userdata = nullptr; - error::Error Validate(); + DownloadObjectArgs() = default; + ~DownloadObjectArgs() = default; + + error::Error Validate() const; }; // struct DownloadObjectArgs struct GetObjectArgs : public ObjectConditionalReadArgs { http::DataFunction datafunc; - void *userdata = NULL; - http::ProgressFunction progressfunc = NULL; - void *progress_userdata = NULL; + void *userdata = nullptr; + http::ProgressFunction progressfunc = nullptr; + void *progress_userdata = nullptr; - error::Error Validate(); + GetObjectArgs() = default; + ~GetObjectArgs() = default; + + error::Error Validate() const; }; // struct GetObjectArgs struct ListObjectsArgs : public BucketArgs { @@ -173,6 +221,9 @@ struct ListObjectsArgs : public BucketArgs { bool recursive = false; bool use_api_v1 = false; bool include_versions = false; + + ListObjectsArgs() = default; + ~ListObjectsArgs() = default; }; // struct ListObjectsArgs struct ListObjectsCommonArgs : public BucketArgs { @@ -180,6 +231,9 @@ struct ListObjectsCommonArgs : public BucketArgs { std::string encoding_type; unsigned int max_keys = 1000; std::string prefix; + + ListObjectsCommonArgs() = default; + ~ListObjectsCommonArgs() = default; }; // struct ListObjectsCommonArgs struct ListObjectsV1Args : public ListObjectsCommonArgs { @@ -187,16 +241,18 @@ struct ListObjectsV1Args : public ListObjectsCommonArgs { ListObjectsV1Args(); ListObjectsV1Args(ListObjectsArgs args); + ~ListObjectsV1Args() = default; }; // struct ListObjectsV1Args struct ListObjectsV2Args : public ListObjectsCommonArgs { std::string start_after; std::string continuation_token; - bool fetch_owner; - bool include_user_metadata; + bool fetch_owner = false; + bool include_user_metadata = false; ListObjectsV2Args(); ListObjectsV2Args(ListObjectsArgs args); + ~ListObjectsV2Args() = default; }; // struct ListObjectsV2Args struct ListObjectVersionsArgs : public ListObjectsCommonArgs { @@ -205,14 +261,17 @@ struct ListObjectVersionsArgs : public ListObjectsCommonArgs { ListObjectVersionsArgs(); ListObjectVersionsArgs(ListObjectsArgs args); + ~ListObjectVersionsArgs() = default; }; // struct ListObjectVersionsArgs struct PutObjectArgs : public PutObjectBaseArgs { std::istream &stream; - http::ProgressFunction progressfunc = NULL; - void *progress_userdata = NULL; + http::ProgressFunction progressfunc = nullptr; + void *progress_userdata = nullptr; PutObjectArgs(std::istream &stream, long object_size, long part_size); + ~PutObjectArgs() = default; + error::Error Validate(); }; // struct PutObjectArgs @@ -220,16 +279,22 @@ using CopySource = ObjectConditionalReadArgs; struct CopyObjectArgs : public ObjectWriteArgs { CopySource source; - Directive *metadata_directive = NULL; - Directive *tagging_directive = NULL; + Directive *metadata_directive = nullptr; + Directive *tagging_directive = nullptr; - error::Error Validate(); + CopyObjectArgs() = default; + ~CopyObjectArgs() = default; + + error::Error Validate() const; }; // struct CopyObjectArgs struct ComposeSource : public ObjectConditionalReadArgs { - error::Error BuildHeaders(size_t object_size, std::string &etag); - size_t ObjectSize(); - utils::Multimap Headers(); + ComposeSource() = default; + ~ComposeSource() = default; + + error::Error BuildHeaders(size_t object_size, const std::string &etag); + size_t ObjectSize() const; + utils::Multimap Headers() const; private: long object_size_ = -1; @@ -239,13 +304,19 @@ struct ComposeSource : public ObjectConditionalReadArgs { struct ComposeObjectArgs : public ObjectWriteArgs { std::list sources; - error::Error Validate(); + ComposeObjectArgs() = default; + ~ComposeObjectArgs() = default; + + error::Error Validate() const; }; // struct ComposeObjectArgs struct UploadObjectArgs : public PutObjectBaseArgs { std::string filename; - http::ProgressFunction progressfunc = NULL; - void *progress_userdata = NULL; + http::ProgressFunction progressfunc = nullptr; + void *progress_userdata = nullptr; + + UploadObjectArgs() = default; + ~UploadObjectArgs() = default; error::Error Validate(); }; // struct UploadObjectArgs @@ -254,33 +325,45 @@ struct RemoveObjectsApiArgs : public BucketArgs { bool bypass_governance_mode = false; bool quiet = true; std::list objects; + + RemoveObjectsApiArgs() = default; + ~RemoveObjectsApiArgs() = default; }; // struct RemoveObjectsApiArgs using DeleteObjectFunction = std::function; struct RemoveObjectsArgs : public BucketArgs { bool bypass_governance_mode = false; - DeleteObjectFunction func = NULL; + DeleteObjectFunction func = nullptr; - error::Error Validate(); + RemoveObjectsArgs() = default; + ~RemoveObjectsArgs() = default; + + error::Error Validate() const; }; // struct RemoveObjectsArgs struct SelectObjectContentArgs : public ObjectReadArgs { SelectRequest &request; - SelectResultFunction resultfunc = NULL; + SelectResultFunction resultfunc = nullptr; SelectObjectContentArgs(SelectRequest &req, SelectResultFunction func) : request(req), resultfunc(func) {} - error::Error Validate(); + + ~SelectObjectContentArgs() = default; + + error::Error Validate() const; }; // struct SelectObjectContentArgs struct ListenBucketNotificationArgs : public BucketArgs { std::string prefix; std::string suffix; std::list events; - NotificationRecordsFunction func = NULL; + NotificationRecordsFunction func = nullptr; - error::Error Validate(); + ListenBucketNotificationArgs() = default; + ~ListenBucketNotificationArgs() = default; + + error::Error Validate() const; }; // struct ListenBucketNotificationArgs using DeleteBucketPolicyArgs = BucketArgs; @@ -290,7 +373,10 @@ using GetBucketPolicyArgs = BucketArgs; struct SetBucketPolicyArgs : public BucketArgs { std::string policy; - error::Error Validate(); + SetBucketPolicyArgs() = default; + ~SetBucketPolicyArgs() = default; + + error::Error Validate() const; }; // struct SetBucketPolicy using DeleteBucketNotificationArgs = BucketArgs; @@ -302,6 +388,8 @@ struct SetBucketNotificationArgs : public BucketArgs { SetBucketNotificationArgs(NotificationConfig &configvalue) : config(configvalue) {} + + ~SetBucketNotificationArgs() = default; }; // struct SetBucketNotification using DeleteBucketEncryptionArgs = BucketArgs; @@ -312,7 +400,9 @@ struct SetBucketEncryptionArgs : public BucketArgs { SseConfig &config; SetBucketEncryptionArgs(SseConfig &sseconfig) : config(sseconfig) {} - error::Error Validate(); + ~SetBucketEncryptionArgs() = default; + + error::Error Validate() const; }; // struct SetBucketEncryption using GetBucketVersioningArgs = BucketArgs; @@ -321,7 +411,10 @@ struct SetBucketVersioningArgs : public BucketArgs { Boolean status; Boolean mfa_delete; - error::Error Validate(); + SetBucketVersioningArgs() = default; + ~SetBucketVersioningArgs() = default; + + error::Error Validate() const; }; // struct SetBucketVersioning using DeleteBucketReplicationArgs = BucketArgs; @@ -332,6 +425,7 @@ struct SetBucketReplicationArgs : public BucketArgs { ReplicationConfig &config; SetBucketReplicationArgs(ReplicationConfig &value) : config(value) {} + ~SetBucketReplicationArgs() = default; }; // struct SetBucketReplication using DeleteBucketLifecycleArgs = BucketArgs; @@ -342,6 +436,7 @@ struct SetBucketLifecycleArgs : public BucketArgs { LifecycleConfig &config; SetBucketLifecycleArgs(LifecycleConfig &value) : config(value) {} + ~SetBucketLifecycleArgs() = default; }; // struct SetBucketLifecycle using DeleteBucketTagsArgs = BucketArgs; @@ -351,7 +446,10 @@ using GetBucketTagsArgs = BucketArgs; struct SetBucketTagsArgs : public BucketArgs { std::map tags; - error::Error Validate(); + SetBucketTagsArgs() = default; + ~SetBucketTagsArgs() = default; + + error::Error Validate() const; }; // struct SetBucketTags using DeleteObjectLockConfigArgs = BucketArgs; @@ -361,7 +459,10 @@ using GetObjectLockConfigArgs = BucketArgs; struct SetObjectLockConfigArgs : public BucketArgs { ObjectLockConfig config; - error::Error Validate(); + SetObjectLockConfigArgs() = default; + ~SetObjectLockConfigArgs() = default; + + error::Error Validate() const; }; // struct SetObjectLockConfig using DeleteObjectTagsArgs = ObjectVersionArgs; @@ -371,7 +472,10 @@ using GetObjectTagsArgs = ObjectVersionArgs; struct SetObjectTagsArgs : public ObjectVersionArgs { std::map tags; - error::Error Validate(); + SetObjectTagsArgs() = default; + ~SetObjectTagsArgs() = default; + + error::Error Validate() const; }; // struct SetObjectTags using EnableObjectLegalHoldArgs = ObjectVersionArgs; @@ -386,7 +490,10 @@ struct SetObjectRetentionArgs : public ObjectVersionArgs { RetentionMode retention_mode; utils::Time retain_until_date; - error::Error Validate(); + SetObjectRetentionArgs() = default; + ~SetObjectRetentionArgs() = default; + + error::Error Validate() const; }; // struct SetObjectRetention inline constexpr unsigned int kDefaultExpirySeconds = @@ -397,141 +504,34 @@ struct GetPresignedObjectUrlArgs : public ObjectVersionArgs { unsigned int expiry_seconds = kDefaultExpirySeconds; utils::Time request_time; - error::Error Validate(); + GetPresignedObjectUrlArgs() = default; + ~GetPresignedObjectUrlArgs() = default; + + error::Error Validate() const; }; // struct GetPresignedObjectUrlArgs struct PostPolicy { std::string bucket; std::string region; - PostPolicy(std::string bucket, utils::Time expiration) { - this->bucket = bucket; - this->expiration_ = expiration; - } - - operator bool() const { return !bucket.empty() && !expiration_; } - - error::Error AddEqualsCondition(std::string element, std::string value) { - if (element.empty()) { - return error::Error("condition element cannot be empty"); - } - - element = trimDollar(element); - if (element == "success_action_redirect" || element == "redirect" || - element == "content-length-range") { - return error::Error(element + " is unsupported for equals condition"); - } - - if (isReservedElement(element)) { - return error::Error(element + " cannot be set"); - } - - conditions_[eq_][element] = value; - return error::SUCCESS; - } - - error::Error RemoveEqualsCondition(std::string element) { - if (element.empty()) { - return error::Error("condition element cannot be empty"); - } - conditions_[eq_].erase(element); - return error::SUCCESS; - } - - error::Error AddStartsWithCondition(std::string element, std::string value) { - if (element.empty()) { - return error::Error("condition element cannot be empty"); - } - - element = trimDollar(element); - if (element == "success_action_status" || - element == "content-length-range" || - (utils::StartsWith(element, "x-amz-") && - utils::StartsWith(element, "x-amz-meta-"))) { - return error::Error(element + - " is unsupported for starts-with condition"); - } - - if (isReservedElement(element)) { - return error::Error(element + " cannot be set"); - } - - conditions_[starts_with_][element] = value; - return error::SUCCESS; - } - - error::Error RemoveStartsWithCondition(std::string element) { - if (element.empty()) { - return error::Error("condition element cannot be empty"); - } - conditions_[starts_with_].erase(element); - return error::SUCCESS; - } + PostPolicy(std::string bucket, utils::Time expiration) + : bucket(std::move(bucket)), expiration_(std::move(expiration)) {} + + ~PostPolicy() = default; + explicit operator bool() const { return !bucket.empty() && !expiration_; } + + error::Error AddEqualsCondition(std::string element, std::string value); + error::Error RemoveEqualsCondition(std::string element); + error::Error AddStartsWithCondition(std::string element, std::string value); + error::Error RemoveStartsWithCondition(std::string element); error::Error AddContentLengthRangeCondition(size_t lower_limit, - size_t upper_limit) { - if (lower_limit > upper_limit) { - return error::Error("lower limit cannot be greater than upper limit"); - } - lower_limit_ = Integer(lower_limit); - upper_limit_ = Integer(upper_limit); - return error::SUCCESS; - } - - void RemoveContentLengthRangeCondition() { - lower_limit_ = Integer(); - upper_limit_ = Integer(); - } + size_t upper_limit); + void RemoveContentLengthRangeCondition(); error::Error FormData(std::map &data, std::string access_key, std::string secret_key, - std::string session_token, std::string region) { - if (region.empty()) return error::Error("region cannot be empty"); - if (conditions_[eq_]["key"].empty() && - conditions_[starts_with_]["key"].empty()) { - return error::Error("key condition must be set"); - } - - nlohmann::json policy; - policy["expiration"] = expiration_.ToISO8601UTC(); - - nlohmann::json conditions = nlohmann::json::array(); - conditions.push_back({eq_, "$bucket", bucket}); - for (auto &[cond_key, cond] : conditions_) { - for (auto &[key, value] : cond) { - conditions.push_back({cond_key, "$" + key, value}); - } - } - if (lower_limit_ && upper_limit_) { - conditions.push_back( - {"content-length-range", lower_limit_.Get(), upper_limit_.Get()}); - } - utils::Time date = utils::Time::Now(); - std::string credential = getCredentialString(access_key, date, region); - std::string amz_date = date.ToAmzDate(); - conditions.push_back({eq_, "$x-amz-algorithm", algorithm_}); - conditions.push_back({eq_, "$x-amz-credential", credential}); - if (!session_token.empty()) { - conditions.push_back({eq_, "$x-amz-security-token", session_token}); - } - conditions.push_back({eq_, "$x-amz-date", amz_date}); - policy["conditions"] = conditions; - - std::string encoded_policy = utils::Base64Encode(policy.dump()); - std::string signature = - signer::PostPresignV4(encoded_policy, secret_key, date, region); - - data["x-amz-algorithm"] = algorithm_; - data["x-amz-credential"] = credential; - data["x-amz-date"] = amz_date; - data["policy"] = encoded_policy; - data["x-amz-signature"] = signature; - if (!session_token.empty()) { - data["x-amz-security-token"] = session_token; - } - - return error::SUCCESS; - } + std::string session_token, std::string region); private: static constexpr const char *eq_ = "eq"; @@ -543,22 +543,10 @@ struct PostPolicy { Integer lower_limit_; Integer upper_limit_; - static std::string trimDollar(std::string value) { - if (value.front() == '$') value.erase(0, 1); - return value; - } - + static std::string trimDollar(std::string value); static std::string getCredentialString(std::string access_key, - utils::Time date, std::string region) { - return access_key + "/" + date.ToSignerDate() + "/" + region + - "/s3/aws4_request"; - } - - static bool isReservedElement(std::string element) { - return element == "bucket" || element == "x-amz-algorithm" || - element == "x-amz-credential" || element == "x-amz-date" || - element == "policy" || element == "x-amz-signature"; - } + utils::Time date, std::string region); + static bool isReservedElement(std::string element); }; // struct PostPolicy } // namespace s3 } // namespace minio diff --git a/include/baseclient.h b/include/baseclient.h index abd41b8d..3ceb1a50 100644 --- a/include/baseclient.h +++ b/include/baseclient.h @@ -24,18 +24,17 @@ namespace minio { namespace s3 { -utils::Multimap GetCommonListObjectsQueryParams(std::string& delimiter, - std::string& encoding_type, - unsigned int max_keys, - std::string& prefix); +utils::Multimap GetCommonListObjectsQueryParams( + const std::string& delimiter, const std::string& encoding_type, + unsigned int max_keys, const std::string& prefix); /** * Base client to perform S3 APIs. */ class BaseClient { protected: - BaseUrl& base_url_; - creds::Provider* provider_ = NULL; + BaseUrl base_url_; + creds::Provider* const provider_ = nullptr; std::map region_map_; bool debug_ = false; bool ignore_cert_check_ = false; @@ -43,14 +42,16 @@ class BaseClient { std::string user_agent_ = DEFAULT_USER_AGENT; public: - BaseClient(BaseUrl& base_url, creds::Provider* provider = NULL); + explicit BaseClient(BaseUrl base_url, + creds::Provider* const provider = nullptr); + virtual ~BaseClient() = default; void Debug(bool flag) { debug_ = flag; } void IgnoreCertCheck(bool flag) { ignore_cert_check_ = flag; } void SetSslCertFile(std::string ssl_cert_file) { - ssl_cert_file_ = ssl_cert_file; + ssl_cert_file_ = std::move(ssl_cert_file); } error::Error SetAppInfo(std::string_view app_name, @@ -58,14 +59,16 @@ class BaseClient { void HandleRedirectResponse(std::string& code, std::string& message, int status_code, http::Method method, - utils::Multimap headers, std::string& bucket_name, + const utils::Multimap& headers, + const std::string& bucket_name, bool retry = false); Response GetErrorResponse(http::Response resp, std::string_view resource, - http::Method method, std::string& bucket_name, - std::string& object_name); + http::Method method, const std::string& bucket_name, + const std::string& object_name); Response execute(Request& req); Response Execute(Request& req); - GetRegionResponse GetRegion(std::string& bucket_name, std::string& region); + GetRegionResponse GetRegion(const std::string& bucket_name, + const std::string& region); AbortMultipartUploadResponse AbortMultipartUpload( AbortMultipartUploadArgs args); diff --git a/include/client.h b/include/client.h index 2787938f..b13be18b 100644 --- a/include/client.h +++ b/include/client.h @@ -30,7 +30,7 @@ class Client; class ListObjectsResult { private: - Client* client_ = NULL; + Client* client_ = nullptr; ListObjectsArgs args_; bool failed_ = false; ListObjectsResponse resp_; @@ -40,9 +40,12 @@ class ListObjectsResult { public: ListObjectsResult(error::Error err); - ListObjectsResult(Client* client, ListObjectsArgs args); + ListObjectsResult(Client* const client, const ListObjectsArgs& args); + ListObjectsResult(Client* const client, ListObjectsArgs&& args); + ~ListObjectsResult() = default; + Item& operator*() const { return *itr_; } - operator bool() const { return itr_ != resp_.contents.end(); } + explicit operator bool() const { return itr_ != resp_.contents.end(); } ListObjectsResult& operator++() { itr_++; if (!failed_ && itr_ == resp_.contents.end() && resp_.is_truncated) { @@ -59,7 +62,7 @@ class ListObjectsResult { class RemoveObjectsResult { private: - Client* client_ = NULL; + Client* client_ = nullptr; RemoveObjectsArgs args_; bool done_ = false; RemoveObjectsResponse resp_; @@ -69,9 +72,12 @@ class RemoveObjectsResult { public: RemoveObjectsResult(error::Error err); - RemoveObjectsResult(Client* client, RemoveObjectsArgs args); + RemoveObjectsResult(Client* const client, const RemoveObjectsArgs& args); + RemoveObjectsResult(Client* const client, RemoveObjectsArgs&& args); + ~RemoveObjectsResult() = default; + DeleteError& operator*() const { return *itr_; } - operator bool() const { return itr_ != resp_.errors.end(); } + explicit operator bool() const { return itr_ != resp_.errors.end(); } RemoveObjectsResult& operator++() { itr_++; if (!done_ && itr_ == resp_.errors.end()) { @@ -96,11 +102,13 @@ class Client : public BaseClient { std::list sources); ComposeObjectResponse ComposeObject(ComposeObjectArgs args, std::string& upload_id); - PutObjectResponse PutObject(PutObjectArgs& args, std::string& upload_id, + PutObjectResponse PutObject(PutObjectArgs args, std::string& upload_id, char* buf); public: - Client(BaseUrl& base_url, creds::Provider* provider = NULL); + Client(BaseUrl& base_url, creds::Provider* const provider = nullptr); + ~Client() = default; + ComposeObjectResponse ComposeObject(ComposeObjectArgs args); CopyObjectResponse CopyObject(CopyObjectArgs args); DownloadObjectResponse DownloadObject(DownloadObjectArgs args); diff --git a/include/credentials.h b/include/credentials.h index 197d78c5..68e21db8 100644 --- a/include/credentials.h +++ b/include/credentials.h @@ -16,18 +16,11 @@ #ifndef _MINIO_CREDS_CREDENTIALS_H #define _MINIO_CREDS_CREDENTIALS_H -#include - #include "utils.h" namespace minio { namespace creds { -static bool expired(utils::Time expiration) { - if (!expiration) return false; - utils::Time now = utils::Time::Now(); - now.Add(10); - return expiration < now; -} +bool expired(const utils::Time& expiration); /** * Credentials contains access key and secret key with optional session token @@ -35,39 +28,21 @@ static bool expired(utils::Time expiration) { */ struct Credentials { error::Error err; - std::string access_key; - std::string secret_key; - std::string session_token; - utils::Time expiration; + std::string access_key = {}; + std::string secret_key = {}; + std::string session_token = {}; + utils::Time expiration = {}; + + Credentials() = default; + ~Credentials() = default; - bool IsExpired() { return expired(expiration); } + bool IsExpired() const { return expired(expiration); } - operator bool() const { + explicit operator bool() const { return !err && !access_key.empty() && expired(expiration); } - static Credentials ParseXML(std::string_view data, std::string root) { - pugi::xml_document xdoc; - pugi::xml_parse_result result = xdoc.load_string(data.data()); - if (!result) return Credentials{error::Error("unable to parse XML")}; - - auto credentials = xdoc.select_node((root + "/Credentials").c_str()); - - auto text = credentials.node().select_node("AccessKeyId/text()"); - std::string access_key = text.node().value(); - - text = credentials.node().select_node("SecretAccessKey/text()"); - std::string secret_key = text.node().value(); - - text = credentials.node().select_node("SessionToken/text()"); - std::string session_token = text.node().value(); - - text = credentials.node().select_node("Expiration/text()"); - auto expiration = utils::Time::FromISO8601UTC(text.node().value()); - - return Credentials{error::SUCCESS, access_key, secret_key, session_token, - expiration}; - } + static Credentials ParseXML(std::string_view data, const std::string& root); }; // class Credentials } // namespace creds } // namespace minio diff --git a/include/error.h b/include/error.h index 6b24a03e..d8035d13 100644 --- a/include/error.h +++ b/include/error.h @@ -16,6 +16,7 @@ #ifndef _MINIO_ERROR_H #define _MINIO_ERROR_H +#include #include namespace minio { @@ -25,10 +26,29 @@ class Error { std::string msg_; public: - Error() {} - Error(std::string_view msg) { this->msg_ = std::string(msg); } - std::string String() { return msg_; } - operator bool() const { return !msg_.empty(); } + Error() = default; + Error(std::string_view msg) : msg_(msg) {} + + Error(const Error&) = default; + Error& operator=(const Error&) = default; + + Error(Error&& v) : msg_(std::move(v.msg_)) {} + + Error& operator=(Error&& v) { + if (this != &v) { + msg_ = std::move(v.msg_); + } + return *this; + } + + ~Error() = default; + + std::string String() const { return msg_; } + explicit operator bool() const { return !msg_.empty(); } + + friend std::ostream& operator<<(std::ostream& s, const Error& e) { + return s << e.msg_; + } }; // class Error const static Error SUCCESS; diff --git a/include/http.h b/include/http.h index 284cb5e7..30e45bee 100644 --- a/include/http.h +++ b/include/http.h @@ -33,7 +33,7 @@ namespace http { enum class Method { kGet, kHead, kPost, kPut, kDelete }; // MethodToString converts http Method enum to string. -constexpr const char* MethodToString(Method& method) throw() { +constexpr const char* MethodToString(Method method) noexcept { switch (method) { case Method::kGet: return "GET"; @@ -51,109 +51,27 @@ constexpr const char* MethodToString(Method& method) throw() { std::terminate(); } } - return NULL; + return nullptr; } /** * Url represents HTTP URL and it's components. */ struct Url { - bool https; + bool https = false; std::string host; unsigned int port = 0; std::string path; std::string query_string; - operator bool() const { return !host.empty(); } + Url() = default; + ~Url() = default; - std::string String() { - if (host.empty()) return ""; + explicit operator bool() const { return !host.empty(); } - std::string url = (https ? "https://" : "http://") + host; - if (port) url += ":" + std::to_string(port); - if (!path.empty()) { - if (path.front() != '/') url += '/'; - url += path; - } - if (!query_string.empty()) url += "?" + query_string; - - return url; - } - - std::string HostHeaderValue() { - if (!port) return host; - return host + ":" + std::to_string(port); - } - - static Url Parse(std::string value) { - std::string scheme; - size_t pos = value.find("://"); - if (pos != std::string::npos) { - scheme = value.substr(0, pos); - value.erase(0, pos + 3); - } - scheme = utils::ToLower(scheme); - - if (!scheme.empty() && scheme != "http" && scheme != "https") return Url{}; - - bool https = (scheme.empty() || scheme == "https"); - - std::string host; - std::string path; - std::string query_string; - pos = value.find("/"); - if (pos != std::string::npos) { - host = value.substr(0, pos); - value.erase(0, pos + 1); - - pos = value.find("?"); - if (pos != std::string::npos) { - path = value.substr(0, pos); - value.erase(0, pos + 1); - query_string = value; - } else { - path = value; - } - } else { - pos = value.find("?"); - if (pos != std::string::npos) { - host = value.substr(0, pos); - value.erase(0, pos + 1); - query_string = value; - } else { - host = value; - } - } - - if (host.empty()) return Url{}; - - unsigned int port = 0; - struct sockaddr_in6 dst; - if (inet_pton(AF_INET6, host.c_str(), &(dst.sin6_addr)) <= 0) { - if (host.front() != '[' || host.back() != ']') { - std::stringstream ss(host); - std::string portstr; - while (std::getline(ss, portstr, ':')) { - } - - if (!portstr.empty()) { - try { - port = std::stoi(portstr); - host = host.substr(0, host.rfind(":" + portstr)); - } catch (std::invalid_argument) { - port = 0; - } - } - } - } else { - host = "[" + host + "]"; - } - - if (!https && port == 80) port = 0; - if (https && port == 443) port = 0; - - return Url{https, host, port, path, query_string}; - } + std::string String() const; + std::string HostHeaderValue() const; + static Url Parse(std::string value); }; // struct Url struct DataFunctionArgs; @@ -167,31 +85,37 @@ using ProgressFunction = std::function; struct Response; struct DataFunctionArgs { - curlpp::Easy* handle = NULL; - Response* response = NULL; + curlpp::Easy* handle = nullptr; + Response* response = nullptr; std::string datachunk; - void* userdata = NULL; + void* userdata = nullptr; + + DataFunctionArgs() = default; + ~DataFunctionArgs() = default; }; // struct DataFunctionArgs struct ProgressFunctionArgs { - double download_total_bytes = 0; - double downloaded_bytes = 0; - double upload_total_bytes = 0; - double uploaded_bytes = 0; - double download_speed = 0; - double upload_speed = 0; - void* userdata = NULL; + double download_total_bytes = 0.0; + double downloaded_bytes = 0.0; + double upload_total_bytes = 0.0; + double uploaded_bytes = 0.0; + double download_speed = 0.0; + double upload_speed = 0.0; + void* userdata = nullptr; + + ProgressFunctionArgs() = default; + ~ProgressFunctionArgs() = default; }; // struct ProgressFunctionArgs struct Request { Method method; http::Url url; utils::Multimap headers; - std::string_view body = ""; - DataFunction datafunc = NULL; - void* userdata = NULL; - ProgressFunction progressfunc = NULL; - void* progress_userdata = NULL; + std::string_view body; + DataFunction datafunc = nullptr; + void* userdata = nullptr; + ProgressFunction progressfunc = nullptr; + void* progress_userdata = nullptr; bool debug = false; bool ignore_cert_check = false; std::string ssl_cert_file; @@ -199,10 +123,13 @@ struct Request { std::string cert_file; Request(Method method, Url url); + ~Request() = default; + Response Execute(); - operator bool() const { + + explicit operator bool() const { if (method < Method::kGet || method > Method::kDelete) return false; - return url; + return static_cast(url); } private: @@ -211,25 +138,24 @@ struct Request { struct Response { std::string error; - DataFunction datafunc = NULL; - void* userdata = NULL; + DataFunction datafunc = nullptr; + void* userdata = nullptr; int status_code = 0; utils::Multimap headers; std::string body; - size_t ResponseCallback(curlpp::Multi* requests, curlpp::Easy* request, - char* buffer, size_t size, size_t length); - operator bool() const { + Response() = default; + ~Response() = default; + + size_t ResponseCallback(curlpp::Multi* const requests, + curlpp::Easy* const request, const char* const buffer, + size_t size, size_t length); + + explicit operator bool() const { return error.empty() && status_code >= 200 && status_code <= 299; } - error::Error Error() { - if (!error.empty()) return error::Error(error); - if (status_code && (status_code < 200 || status_code > 299)) { - return error::Error("failed with HTTP status code " + - std::to_string(status_code)); - } - return error::SUCCESS; - } + + error::Error Error() const; private: std::string response_; diff --git a/include/providers.h b/include/providers.h index b61d83d9..2c36a473 100644 --- a/include/providers.h +++ b/include/providers.h @@ -16,24 +16,12 @@ #ifndef _MINIO_CREDS_PROVIDERS_H #define _MINIO_CREDS_PROVIDERS_H -#include -#ifdef _WIN32 -#include -#include -#else -#include -#include -#include -#endif #include -#include -#include #include #include "credentials.h" -#include "signer.h" -#include "utils.h" +#include "http.h" #define DEFAULT_DURATION_SECONDS (60 * 60 * 24) // 1 day. #define MIN_DURATION_SECONDS (60 * 15) // 15 minutes. @@ -45,33 +33,15 @@ struct Jwt { std::string token; unsigned int expiry = 0; - operator bool() const { return !token.empty(); } + Jwt() = default; + ~Jwt() = default; + + explicit operator bool() const { return !token.empty(); } }; // struct Jwt using JwtFunction = std::function; -static error::Error checkLoopbackHost(std::string host) { - struct addrinfo hints = {0}; - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - - int status; - struct addrinfo* res = NULL; - if ((status = getaddrinfo(host.c_str(), NULL, &hints, &res)) != 0) { - return error::Error(std::string("getaddrinfo: ") + gai_strerror(status)); - } - - for (struct addrinfo* ai = res; ai != NULL; ai = ai->ai_next) { - std::string ip(inet_ntoa(((struct sockaddr_in*)ai->ai_addr)->sin_addr)); - if (!utils::StartsWith(ip, "127.")) { - return error::Error(host + " is not loopback only host"); - } - } - - freeaddrinfo(res); // free the linked list - - return error::SUCCESS; -} +error::Error checkLoopbackHost(const std::string& host); /** * Credential provider interface. @@ -82,11 +52,10 @@ class Provider { Credentials creds_; public: - Provider() {} - - virtual ~Provider() {} + Provider() = default; + virtual ~Provider(); - operator bool() const { return !err_; } + explicit operator bool() const { return !err_; } virtual Credentials Fetch() = 0; }; // class Provider @@ -94,31 +63,15 @@ class Provider { class ChainedProvider : public Provider { private: std::list providers_; - Provider* provider_ = NULL; + Provider* provider_ = nullptr; public: - ChainedProvider(std::list providers) { - this->providers_ = providers; - } - - Credentials Fetch() { - if (err_) return Credentials{err_}; - - if (creds_) return creds_; + ChainedProvider(std::list providers) + : providers_(std::move(providers)) {} - if (provider_ != NULL) { - creds_ = provider_->Fetch(); - if (creds_) return creds_; - } + virtual ~ChainedProvider(); - for (auto provider : providers_) { - provider_ = provider; - creds_ = provider_->Fetch(); - if (creds_) return creds_; - } - - return Credentials{error::Error("All providers fail to fetch credentials")}; - } + virtual Credentials Fetch() override; }; // class ChainedProvider /** @@ -127,113 +80,42 @@ class ChainedProvider : public Provider { class StaticProvider : public Provider { public: StaticProvider(std::string access_key, std::string secret_key, - std::string session_token = "") { - this->creds_ = - Credentials{error::SUCCESS, access_key, secret_key, session_token}; - } + std::string session_token = {}); + virtual ~StaticProvider(); - Credentials Fetch() { return creds_; } + virtual Credentials Fetch() override; }; // class StaticProvider class EnvAwsProvider : public Provider { public: - EnvAwsProvider() { - std::string access_key; - std::string secret_key; - std::string session_token; - - if (!utils::GetEnv(access_key, "AWS_ACCESS_KEY_ID")) { - utils::GetEnv(access_key, "AWS_ACCESS_KEY"); - } - if (!utils::GetEnv(secret_key, "AWS_SECRET_ACCESS_KEY")) { - utils::GetEnv(secret_key, "AWS_SECRET_KEY"); - } - utils::GetEnv(session_token, "AWS_SESSION_TOKEN"); - - this->creds_ = - Credentials{error::SUCCESS, access_key, secret_key, session_token}; - } - - Credentials Fetch() { return creds_; } + EnvAwsProvider(); + virtual ~EnvAwsProvider(); + + virtual Credentials Fetch() override; }; // class EnvAwsProvider class EnvMinioProvider : public Provider { public: - EnvMinioProvider() { - std::string access_key; - std::string secret_key; + EnvMinioProvider(); + virtual ~EnvMinioProvider(); - utils::GetEnv(access_key, "MINIO_ACCESS_KEY"); - utils::GetEnv(secret_key, "MINIO_SECRET_KEY"); - this->creds_ = Credentials{error::SUCCESS, access_key, secret_key}; - } - - Credentials Fetch() { return creds_; } + virtual Credentials Fetch() override; }; // class EnvMinioProvider class AwsConfigProvider : public Provider { public: - AwsConfigProvider(std::string filename = "", std::string profile = "") { - if (filename.empty()) { - if (!utils::GetEnv(filename, "AWS_SHARED_CREDENTIALS_FILE")) { - filename = utils::GetHomeDir() + "/aws/credentials"; - } - } - - if (profile.empty()) { - if (!utils::GetEnv(profile, "AWS_PROFILE")) profile = "default"; - } - - INIReader reader(filename); - if (reader.ParseError() < 0) { - this->creds_ = Credentials{error::Error("unable to read " + filename)}; - } else { - this->creds_ = Credentials{ - error::SUCCESS, reader.Get(profile, "aws_access_key_id", ""), - reader.Get(profile, "aws_secret_access_key", ""), - reader.Get(profile, "aws_session_token", "")}; - } - } - - Credentials Fetch() { return creds_; } + AwsConfigProvider(std::string filename = {}, std::string profile = {}); + virtual ~AwsConfigProvider(); + + virtual Credentials Fetch() override; }; // class AwsConfigProvider class MinioClientConfigProvider : public Provider { public: - MinioClientConfigProvider(std::string filename = "", std::string alias = "") { - if (filename.empty()) filename = utils::GetHomeDir() + "/.mc/config.json"; - - if (alias.empty()) { - if (!utils::GetEnv(alias, "MINIO_ALIAS")) alias = "s3"; - } - - std::ifstream ifs(filename); - nlohmann::json json = nlohmann::json::parse(ifs); - ifs.close(); - - nlohmann::json aliases; - if (json.contains("hosts")) { - aliases = json["hosts"]; - } else if (json.contains("aliases")) { - aliases = json["aliases"]; - } else { - this->creds_ = Credentials{ - error::Error("invalid configuration in file " + filename)}; - return; - } - - if (!aliases.contains(alias)) { - this->creds_ = Credentials{error::Error( - "alias " + alias + " not found in MinIO client configuration file " + - filename)}; - return; - } - - this->creds_ = Credentials{error::SUCCESS, aliases[alias]["accessKey"], - aliases[alias]["secretKey"]}; - } - - Credentials Fetch() { return creds_; } + MinioClientConfigProvider(std::string filename = {}, std::string alias = {}); + virtual ~MinioClientConfigProvider(); + + virtual Credentials Fetch() override; }; // class MinioClientConfigProvider class AssumeRoleProvider : public Provider { @@ -248,67 +130,19 @@ class AssumeRoleProvider : public Provider { public: AssumeRoleProvider(http::Url sts_endpoint, std::string access_key, std::string secret_key, unsigned int duration_seconds = 0, - std::string policy = "", std::string region = "", - std::string role_arn = "", - std::string role_session_name = "", - std::string external_id = "") { - this->sts_endpoint_ = sts_endpoint; - this->access_key_ = access_key; - this->secret_key_ = secret_key; - this->region_ = region; - - if (duration_seconds < DEFAULT_DURATION_SECONDS) { - duration_seconds = DEFAULT_DURATION_SECONDS; - } - - utils::Multimap map; - map.Add("Action", "AssumeRole"); - map.Add("Version", "2011-06-15"); - map.Add("DurationSeconds", std::to_string(duration_seconds)); - if (!role_arn.empty()) map.Add("RoleArn", role_arn); - if (!role_session_name.empty()) { - map.Add("RoleSessionName", role_session_name); - } - if (!policy.empty()) map.Add("Policy", policy); - if (!external_id.empty()) map.Add("ExternalId", external_id); - - this->body_ = map.ToQueryString(); - this->content_sha256_ = utils::Sha256Hash(body_); - } - - Credentials Fetch() { - if (err_) return Credentials{err_}; - - if (creds_) return creds_; - - utils::Time date = utils::Time::Now(); - utils::Multimap headers; - headers.Add("Content-Type", "application/x-www-form-urlencoded"); - headers.Add("Host", sts_endpoint_.host); - headers.Add("X-Amz-Date", date.ToAmzDate()); - - http::Method method = http::Method::kPost; - signer::SignV4STS(method, sts_endpoint_.path, region_, headers, - utils::Multimap(), access_key_, secret_key_, - content_sha256_, date); - - http::Request req(method, sts_endpoint_); - req.headers = headers; - req.body = body_; - http::Response resp = req.Execute(); - if (!resp) { - creds_ = Credentials{resp.Error()}; - } else { - creds_ = Credentials::ParseXML(resp.body, "AssumeRoleResult"); - } - - return creds_; - } + std::string policy = {}, std::string region = {}, + std::string role_arn = {}, + std::string role_session_name = {}, + std::string external_id = {}); + + virtual ~AssumeRoleProvider(); + + virtual Credentials Fetch() override; }; // class AssumeRoleProvider class WebIdentityClientGrantsProvider : public Provider { private: - JwtFunction jwtfunc_ = NULL; + JwtFunction jwtfunc_ = nullptr; http::Url sts_endpoint_; unsigned int duration_seconds_ = 0; std::string policy_; @@ -318,91 +152,41 @@ class WebIdentityClientGrantsProvider : public Provider { public: WebIdentityClientGrantsProvider(JwtFunction jwtfunc, http::Url sts_endpoint, unsigned int duration_seconds = 0, - std::string policy = "", - std::string role_arn = "", - std::string role_session_name = "") { - this->jwtfunc_ = jwtfunc; - this->sts_endpoint_ = sts_endpoint; - this->duration_seconds_ = duration_seconds; - this->policy_ = policy; - this->role_arn_ = role_arn; - this->role_session_name_ = role_session_name; - } - - virtual bool IsWebIdentity() = 0; - - unsigned int getDurationSeconds(unsigned int expiry) { - if (duration_seconds_) expiry = duration_seconds_; - if (expiry > MAX_DURATION_SECONDS) return MAX_DURATION_SECONDS; - if (expiry == 0) return expiry; - if (expiry < MIN_DURATION_SECONDS) return MIN_DURATION_SECONDS; - return expiry; - } - - Credentials Fetch() { - if (creds_) return creds_; - - Jwt jwt = jwtfunc_(); - - utils::Multimap map; - map.Add("Version", "2011-06-15"); - unsigned int duration_seconds = getDurationSeconds(jwt.expiry); - if (duration_seconds) { - map.Add("DurationSeconds", std::to_string(duration_seconds)); - } - if (!policy_.empty()) map.Add("Policy", policy_); - - if (IsWebIdentity()) { - map.Add("Action", "AssumeRoleWithWebIdentity"); - map.Add("WebIdentityToken", jwt.token); - if (!role_arn_.empty()) { - map.Add("RoleArn", role_arn_); - if (!role_session_name_.empty()) { - map.Add("RoleSessionName", role_session_name_); - } else { - map.Add("RoleSessionName", utils::Time::Now().ToISO8601UTC()); - } - } - } else { - map.Add("Action", "AssumeRoleWithClientGrants"); - map.Add("Token", jwt.token); - } - - http::Url url = sts_endpoint_; - url.query_string = map.ToQueryString(); - http::Request req(http::Method::kPost, url); - http::Response resp = req.Execute(); - if (!resp) { - creds_ = Credentials{resp.Error()}; - } else { - creds_ = Credentials::ParseXML( - resp.body, IsWebIdentity() ? "AssumeRoleWithWebIdentityResult" - : "AssumeRoleWithClientGrantsResult"); - } - return creds_; - } + std::string policy = {}, + std::string role_arn = {}, + std::string role_session_name = {}); + + virtual ~WebIdentityClientGrantsProvider(); + + virtual bool IsWebIdentity() const = 0; + + unsigned int getDurationSeconds(unsigned int expiry) const; + + virtual Credentials Fetch() override; }; // class WebIdentityClientGrantsProvider class ClientGrantsProvider : public WebIdentityClientGrantsProvider { public: ClientGrantsProvider(JwtFunction jwtfunc, http::Url sts_endpoint, unsigned int duration_seconds = 0, - std::string policy = "", std::string role_arn = "", - std::string role_session_name = "") - : WebIdentityClientGrantsProvider(jwtfunc, sts_endpoint, duration_seconds, - policy, role_arn, role_session_name) {} - bool IsWebIdentity() { return false; } + std::string policy = {}, std::string role_arn = {}, + std::string role_session_name = {}); + + virtual ~ClientGrantsProvider(); + + virtual bool IsWebIdentity() const override; }; // class ClientGrantsProvider class WebIdentityProvider : public WebIdentityClientGrantsProvider { public: WebIdentityProvider(JwtFunction jwtfunc, http::Url sts_endpoint, unsigned int duration_seconds = 0, - std::string policy = "", std::string role_arn = "", - std::string role_session_name = "") - : WebIdentityClientGrantsProvider(jwtfunc, sts_endpoint, duration_seconds, - policy, role_arn, role_session_name) {} - bool IsWebIdentity() { return true; } + std::string policy = {}, std::string role_arn = {}, + std::string role_session_name = {}); + + virtual ~WebIdentityProvider(); + + virtual bool IsWebIdentity() const override; }; // class WebIdentityProvider class IamAwsProvider : public Provider { @@ -415,121 +199,15 @@ class IamAwsProvider : public Provider { std::string relative_uri_; std::string full_uri_; - Credentials fetch(http::Url url) { - http::Request req(http::Method::kGet, url); - http::Response resp = req.Execute(); - if (!resp) return Credentials{resp.Error()}; - - nlohmann::json json = nlohmann::json::parse(resp.body); - std::string code = json.value("Code", "Success"); - if (code != "Success") { - return Credentials{error::Error(url.String() + " failed with code " + - code + " and message " + - json.value("Message", ""))}; - } - - std::string expiration = json["Expiration"]; - return Credentials{error::SUCCESS, json["AccessKeyId"], - json["SecretAccessKey"], json["Token"], - utils::Time::FromISO8601UTC(expiration.c_str())}; - } - - error::Error getRoleName(std::string& role_name, http::Url url) { - http::Request req(http::Method::kGet, url); - http::Response resp = req.Execute(); - if (!resp) return resp.Error(); - - std::list role_names; - std::string lines = resp.body; - size_t pos; - while ((pos = lines.find("\n")) != std::string::npos) { - role_names.push_back(lines.substr(0, pos)); - lines.erase(0, pos + 1); - } - if (!lines.empty()) role_names.push_back(lines); - - if (role_names.empty()) { - const char* err; - err = "no IAM roles attached to EC2 service "; - err += url; - return error::Error(err); - } - - role_name = utils::Trim(role_names.front(), '\r'); - return error::SUCCESS; - } - public: - IamAwsProvider(http::Url custom_endpoint = http::Url()) { - this->custom_endpoint_ = custom_endpoint; - utils::GetEnv(this->token_file_, "AWS_WEB_IDENTITY_TOKEN_FILE"); - utils::GetEnv(this->aws_region_, "AWS_REGION"); - utils::GetEnv(this->role_arn_, "AWS_ROLE_ARN"); - utils::GetEnv(this->role_session_name_, "AWS_ROLE_SESSION_NAME"); - utils::GetEnv(this->relative_uri_, - "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"); - if (!this->relative_uri_.empty() && this->relative_uri_.front() != '/') { - this->relative_uri_ = "/" + this->relative_uri_; - } - utils::GetEnv(this->full_uri_, "AWS_CONTAINER_CREDENTIALS_FULL_URI"); - } - - Credentials Fetch() { - if (creds_) return creds_; - - http::Url url = custom_endpoint_; - if (!token_file_.empty()) { - if (!url) { - url.https = true; - url.host = "sts.amazonaws.com"; - if (!aws_region_.empty()) { - url.host = "sts." + aws_region_ + ".amazonaws.com"; - } - } - - WebIdentityProvider provider = WebIdentityProvider( - [&token_file = token_file_]() -> Jwt { - std::ifstream ifs(token_file); - nlohmann::json json = nlohmann::json::parse(ifs); - ifs.close(); - return Jwt{json["access_token"], json["expires_in"]}; - }, - url, 0, "", role_arn_, role_session_name_); - creds_ = provider.Fetch(); - return creds_; - } - - if (!relative_uri_.empty()) { - if (!url) { - url.https = true; - url.host = "169.254.170.2"; - url.path = relative_uri_; - } - } else if (!full_uri_.empty()) { - if (!url) url = http::Url::Parse(full_uri_); - if (error::Error err = checkLoopbackHost(url.host)) { - creds_ = Credentials{err}; - return creds_; - } - } else { - if (!url) { - url.https = true; - url.host = "169.254.169.254"; - url.path = "/latest/meta-data/iam/security-credentials/"; - } - - std::string role_name; - if (error::Error err = getRoleName(role_name, url)) { - creds_ = Credentials{err}; - return creds_; - } - - url.path += "/" + role_name; - } - - creds_ = fetch(url); - return creds_; - } + IamAwsProvider(http::Url custom_endpoint = http::Url()); + virtual ~IamAwsProvider(); + + virtual Credentials Fetch() override; + + private: + Credentials fetch(http::Url url); + error::Error getRoleName(std::string& role_name, http::Url url) const; }; // class IamAwsProvider class LdapIdentityProvider : public Provider { @@ -538,27 +216,11 @@ class LdapIdentityProvider : public Provider { public: LdapIdentityProvider(http::Url sts_endpoint, std::string ldap_username, - std::string ldap_password) { - this->sts_endpoint_ = sts_endpoint; - utils::Multimap map; - map.Add("Action", "AssumeRoleWithLDAPIdentity"); - map.Add("Version", "2011-06-15"); - map.Add("LDAPUsername", ldap_username); - map.Add("LDAPPassword", ldap_password); - this->sts_endpoint_.query_string = map.ToQueryString(); - } - - Credentials Fetch() { - if (creds_) return creds_; - - http::Request req(http::Method::kPost, sts_endpoint_); - http::Response resp = req.Execute(); - if (!resp) return Credentials{resp.Error()}; - - creds_ = - Credentials::ParseXML(resp.body, "AssumeRoleWithLDAPIdentityResult"); - return creds_; - } + std::string ldap_password); + + virtual ~LdapIdentityProvider(); + + virtual Credentials Fetch() override; }; // class LdapIdentityProvider struct CertificateIdentityProvider : public Provider { @@ -571,52 +233,12 @@ struct CertificateIdentityProvider : public Provider { public: CertificateIdentityProvider(http::Url sts_endpoint, std::string key_file, std::string cert_file, - std::string ssl_cert_file = "", - unsigned int duration_seconds = 0) { - if (!sts_endpoint.https) { - this->err_ = error::Error("sts endpoint scheme must be HTTPS"); - return; - } - - if (key_file.empty() || cert_file.empty()) { - this->err_ = error::Error("client key and certificate must be provided"); - return; - } - - unsigned int expiry = duration_seconds; - if (duration_seconds < DEFAULT_DURATION_SECONDS) { - expiry = DEFAULT_DURATION_SECONDS; - } - - utils::Multimap map; - map.Add("Action", "AssumeRoleWithCertificate"); - map.Add("Version", "2011-06-15"); - map.Add("DurationSeconds", std::to_string(expiry)); - - sts_endpoint_ = sts_endpoint; - sts_endpoint_.query_string = map.ToQueryString(); - key_file_ = key_file; - cert_file_ = cert_file; - ssl_cert_file_ = ssl_cert_file; - } - - Credentials Fetch() { - if (err_) return Credentials{err_}; - - if (creds_) return creds_; - - http::Request req(http::Method::kPost, sts_endpoint_); - req.ssl_cert_file = ssl_cert_file_; - req.key_file = key_file_; - req.cert_file = cert_file_; - - http::Response resp = req.Execute(); - if (!resp) return Credentials{resp.Error()}; - - creds_ = - Credentials::ParseXML(resp.body, "AssumeRoleWithCertificateResult"); - return creds_; - } + std::string ssl_cert_file = {}, + unsigned int duration_seconds = 0); + + virtual ~CertificateIdentityProvider(); + + virtual Credentials Fetch() override; }; // struct CertificateIdentityProvider } // namespace creds } // namespace minio diff --git a/include/request.h b/include/request.h index 8d356418..46098770 100644 --- a/include/request.h +++ b/include/request.h @@ -48,29 +48,13 @@ const std::regex AWS_S3_PREFIX_REGEX(AWS_S3_PREFIX, const std::regex REGION_REGEX("^((?!_)(?!-)[a-z_\\d-]{1,63})$", std::regex_constants::icase); -bool awsRegexMatch(std::string_view value, std::regex regex); +bool awsRegexMatch(std::string_view value, const std::regex& regex); -error::Error getAwsInfo(std::string host, bool https, std::string& region, - std::string& aws_s3_prefix, +error::Error getAwsInfo(const std::string& host, bool https, + std::string& region, std::string& aws_s3_prefix, std::string& aws_domain_suffix, bool& dualstack); -static std::string extractRegion(std::string& host) { - std::stringstream str_stream(host); - std::string token; - std::vector tokens; - while (std::getline(str_stream, token, '.')) tokens.push_back(token); - - token = tokens[1]; - - // If token is "dualstack", then region might be in next token. - if (token == "dualstack") token = tokens[2]; - - // If token is equal to "amazonaws", region is not passed in the host. - if (token == "amazonaws") return ""; - - // Return token as region. - return token; -} +std::string extractRegion(const std::string& host); struct BaseUrl { bool https = true; @@ -82,14 +66,19 @@ struct BaseUrl { bool dualstack = false; bool virtual_style = false; - BaseUrl() {} - BaseUrl(std::string host, bool https = true, std::string region = ""); - error::Error BuildUrl(http::Url& url, http::Method method, std::string region, - utils::Multimap query_params, - std::string bucket_name = "", - std::string object_name = ""); - operator bool() const { return !err_ && !host.empty(); } - error::Error Error() { + BaseUrl() = default; + BaseUrl(std::string host, bool https = true, std::string region = {}); + ~BaseUrl() = default; + + error::Error BuildUrl(http::Url& url, http::Method method, + const std::string& region, + const utils::Multimap& query_params, + const std::string& bucket_name, + const std::string& object_name); + + explicit operator bool() const { return !err_ && !host.empty(); } + + error::Error Error() const { if (host.empty() && !err_) return error::Error("empty host"); return err_; } @@ -97,9 +86,9 @@ struct BaseUrl { private: error::Error err_; - error::Error BuildAwsUrl(http::Url& url, std::string bucket_name, - bool enforce_path_style, std::string region); - void BuildListBucketsUrl(http::Url& url, std::string region); + error::Error BuildAwsUrl(http::Url& url, const std::string& bucket_name, + bool enforce_path_style, const std::string& region); + void BuildListBucketsUrl(http::Url& url, const std::string& region); }; // struct Url struct Request { @@ -115,13 +104,13 @@ struct Request { std::string bucket_name; std::string object_name; - std::string_view body = ""; + std::string_view body; - http::DataFunction datafunc = NULL; - void* userdata = NULL; + http::DataFunction datafunc = nullptr; + void* userdata = nullptr; - http::ProgressFunction progressfunc = NULL; - void* progress_userdata = NULL; + http::ProgressFunction progressfunc = nullptr; + void* progress_userdata = nullptr; std::string sha256; utils::Time date; @@ -132,10 +121,13 @@ struct Request { Request(http::Method method, std::string region, BaseUrl& baseurl, utils::Multimap extra_headers, utils::Multimap extra_query_params); - http::Request ToHttpRequest(creds::Provider* provider = NULL); + + ~Request() = default; + + http::Request ToHttpRequest(creds::Provider* const provider = nullptr); private: - void BuildHeaders(http::Url& url, creds::Provider* provider); + void BuildHeaders(http::Url& url, creds::Provider* const provider); }; // struct Request } // namespace s3 } // namespace minio diff --git a/include/response.h b/include/response.h index 7bc8e12b..352ade4e 100644 --- a/include/response.h +++ b/include/response.h @@ -35,39 +35,23 @@ struct Response { std::string bucket_name; std::string object_name; - Response() {} - - Response(error::Error err) { this->err_ = err; } - - Response(const Response& resp) { - this->err_ = resp.err_; - - this->status_code = resp.status_code; - this->headers = resp.headers; - this->data = resp.data; - this->code = resp.code; - this->message = resp.message; - this->resource = resp.resource; - this->request_id = resp.request_id; - this->host_id = resp.host_id; - this->bucket_name = resp.bucket_name; - this->object_name = resp.object_name; - } + Response(); + Response(error::Error err) : err_(std::move(err)) {} + + Response(const Response& resp) = default; + Response& operator=(const Response& resp) = default; + + Response(Response&& resp) = default; + Response& operator=(Response&& resp) = default; - operator bool() const { + ~Response(); + + explicit operator bool() const { return !err_ && code.empty() && message.empty() && - (status_code == 0 || status_code >= 200 && status_code <= 299); + (status_code == 0 || (status_code >= 200 && status_code <= 299)); } - error::Error Error() { - if (err_) return err_; - if (!code.empty()) return error::Error(code + ": " + message); - if (status_code && (status_code < 200 || status_code > 299)) { - return error::Error("failed with HTTP status code " + - std::to_string(status_code)); - } - return error::SUCCESS; - } + error::Error Error() const; static Response ParseXML(std::string_view data, int status_code, utils::Multimap headers); @@ -79,11 +63,13 @@ struct Response { struct GetRegionResponse : public Response { std::string region; - GetRegionResponse(std::string region) { this->region = region; } + GetRegionResponse(std::string region) : region(std::move(region)) {} - GetRegionResponse(error::Error err) : Response(err) {} + GetRegionResponse(error::Error err) : Response(std::move(err)) {} GetRegionResponse(const Response& resp) : Response(resp) {} + + ~GetRegionResponse() = default; }; // struct GetRegionResponse using MakeBucketResponse = Response; @@ -91,23 +77,28 @@ using MakeBucketResponse = Response; struct ListBucketsResponse : public Response { std::list buckets; - ListBucketsResponse(std::list buckets) { this->buckets = buckets; } + ListBucketsResponse(std::list buckets) + : buckets(std::move(buckets)) {} - ListBucketsResponse(error::Error err) : Response(err) {} + ListBucketsResponse(error::Error err) : Response(std::move(err)) {} ListBucketsResponse(const Response& resp) : Response(resp) {} + ~ListBucketsResponse() = default; + static ListBucketsResponse ParseXML(std::string_view data); }; // struct ListBucketsResponse struct BucketExistsResponse : public Response { bool exist = false; - BucketExistsResponse(bool exist) { this->exist = exist; } + BucketExistsResponse(bool exist) : exist(exist) {} - BucketExistsResponse(error::Error err) : Response(err) {} + BucketExistsResponse(error::Error err) : Response(std::move(err)) {} BucketExistsResponse(const Response& resp) : Response(resp) {} + + ~BucketExistsResponse() = default; }; // struct BucketExistsResponse using RemoveBucketResponse = Response; @@ -119,12 +110,15 @@ struct CompleteMultipartUploadResponse : public Response { std::string etag; std::string version_id; - CompleteMultipartUploadResponse() {} + CompleteMultipartUploadResponse() = default; - CompleteMultipartUploadResponse(error::Error err) : Response(err) {} + CompleteMultipartUploadResponse(error::Error err) + : Response(std::move(err)) {} CompleteMultipartUploadResponse(const Response& resp) : Response(resp) {} + ~CompleteMultipartUploadResponse() = default; + static CompleteMultipartUploadResponse ParseXML(std::string_view data, std::string version_id); }; // struct CompleteMultipartUploadResponse @@ -132,30 +126,30 @@ struct CompleteMultipartUploadResponse : public Response { struct CreateMultipartUploadResponse : public Response { std::string upload_id; - CreateMultipartUploadResponse(std::string upload_id) { - this->upload_id = upload_id; - } + CreateMultipartUploadResponse(std::string upload_id) + : upload_id(std::move(upload_id)) {} - CreateMultipartUploadResponse(error::Error err) : Response(err) {} + CreateMultipartUploadResponse(error::Error err) : Response(std::move(err)) {} CreateMultipartUploadResponse(const Response& resp) : Response(resp) {} + + ~CreateMultipartUploadResponse() = default; }; // struct CreateMultipartUploadResponse struct PutObjectResponse : public Response { std::string etag; std::string version_id; - PutObjectResponse() {} + PutObjectResponse() = default; + + PutObjectResponse(error::Error err) : Response(std::move(err)) {} PutObjectResponse(const Response& resp) : Response(resp) {} PutObjectResponse(const CompleteMultipartUploadResponse& resp) - : Response(resp) { - this->etag = resp.etag; - this->version_id = resp.version_id; - } + : Response(resp), etag(resp.etag), version_id(resp.version_id) {} - PutObjectResponse(error::Error err) : Response(err) {} + ~PutObjectResponse() = default; }; // struct PutObjectResponse using UploadPartResponse = PutObjectResponse; @@ -173,11 +167,13 @@ struct StatObjectResponse : public Response { bool delete_marker; utils::Multimap user_metadata; - StatObjectResponse() {} + StatObjectResponse() = default; - StatObjectResponse(error::Error err) : Response(err) {} + StatObjectResponse(error::Error err) : Response(std::move(err)) {} StatObjectResponse(const Response& resp) : Response(resp) {} + + ~StatObjectResponse() = default; }; // struct StatObjectResponse using RemoveObjectResponse = Response; @@ -201,11 +197,13 @@ struct Item : public Response { bool is_delete_marker = false; std::string encoding_type; - Item() {} + Item() = default; - Item(error::Error err) : Response(err) {} + Item(error::Error err) : Response(std::move(err)) {} Item(const Response& resp) : Response(resp) {} + + ~Item() = default; }; // struct Item struct ListObjectsResponse : public Response { @@ -234,12 +232,14 @@ struct ListObjectsResponse : public Response { std::string version_id_marker; std::string next_version_id_marker; - ListObjectsResponse() {} + ListObjectsResponse() = default; - ListObjectsResponse(error::Error err) : Response(err) {} + ListObjectsResponse(error::Error err) : Response(std::move(err)) {} ListObjectsResponse(const Response& resp) : Response(resp) {} + ~ListObjectsResponse() = default; + static ListObjectsResponse ParseXML(std::string_view data, bool version); }; // struct ListObjectsResponse @@ -254,28 +254,35 @@ struct DeletedObject : public Response { std::string version_id; bool delete_marker; std::string delete_marker_version_id; + + DeletedObject() = default; + ~DeletedObject() = default; }; // struct DeletedObject struct DeleteError : public Response { std::string version_id; - DeleteError() {} + DeleteError() = default; - DeleteError(error::Error err) : Response(err) {} + DeleteError(error::Error err) : Response(std::move(err)) {} DeleteError(const Response& resp) : Response(resp) {} + + ~DeleteError() = default; }; // struct DeleteError struct RemoveObjectsResponse : public Response { std::list objects; std::list errors; - RemoveObjectsResponse() {} + RemoveObjectsResponse() = default; - RemoveObjectsResponse(error::Error err) : Response(err) {} + RemoveObjectsResponse(error::Error err) : Response(std::move(err)) {} RemoveObjectsResponse(const Response& resp) : Response(resp) {} + ~RemoveObjectsResponse() = default; + static RemoveObjectsResponse ParseXML(std::string_view data); }; // struct RemoveObjectsResponse @@ -288,11 +295,13 @@ using DeleteBucketPolicyResponse = Response; struct GetBucketPolicyResponse : public Response { std::string policy; - GetBucketPolicyResponse(std::string policy) { this->policy = policy; } + GetBucketPolicyResponse(std::string policy) : policy(std::move(policy)) {} - GetBucketPolicyResponse(error::Error err) : Response(err) {} + GetBucketPolicyResponse(error::Error err) : Response(std::move(err)) {} GetBucketPolicyResponse(const Response& resp) : Response(resp) {} + + ~GetBucketPolicyResponse() = default; }; // struct GetBucketPolicyResponse using SetBucketPolicyResponse = Response; @@ -302,14 +311,15 @@ using DeleteBucketNotificationResponse = Response; struct GetBucketNotificationResponse : public Response { NotificationConfig config; - GetBucketNotificationResponse(NotificationConfig config) { - this->config = config; - } + GetBucketNotificationResponse(NotificationConfig config) + : config(std::move(config)) {} - GetBucketNotificationResponse(error::Error err) : Response(err) {} + GetBucketNotificationResponse(error::Error err) : Response(std::move(err)) {} GetBucketNotificationResponse(const Response& resp) : Response(resp) {} + ~GetBucketNotificationResponse() = default; + static GetBucketNotificationResponse ParseXML(std::string_view data); }; // struct GetBucketNotificationResponse @@ -320,12 +330,14 @@ using DeleteBucketEncryptionResponse = Response; struct GetBucketEncryptionResponse : public Response { SseConfig config; - GetBucketEncryptionResponse(SseConfig config) { this->config = config; } + GetBucketEncryptionResponse(SseConfig config) : config(std::move(config)) {} - GetBucketEncryptionResponse(error::Error err) : Response(err) {} + GetBucketEncryptionResponse(error::Error err) : Response(std::move(err)) {} GetBucketEncryptionResponse(const Response& resp) : Response(resp) {} + ~GetBucketEncryptionResponse() = default; + static GetBucketEncryptionResponse ParseXML(std::string_view data); }; // struct GetBucketEncryptionResponse @@ -335,18 +347,21 @@ struct GetBucketVersioningResponse : public Response { Boolean status; Boolean mfa_delete; - GetBucketVersioningResponse() {} + GetBucketVersioningResponse() = default; - GetBucketVersioningResponse(error::Error err) : Response(err) {} + GetBucketVersioningResponse(error::Error err) : Response(std::move(err)) {} GetBucketVersioningResponse(const Response& resp) : Response(resp) {} - std::string Status() { + ~GetBucketVersioningResponse() = default; + + std::string Status() const { if (!status) return "Off"; return status.Get() ? "Enabled" : "Suspended"; } - std::string MfaDelete() { - if (!mfa_delete) return ""; + + std::string MfaDelete() const { + if (!mfa_delete) return {}; return mfa_delete.Get() ? "Enabled" : "Disabled"; } }; // struct GetBucketVersioningResponse @@ -358,14 +373,15 @@ using DeleteBucketReplicationResponse = Response; struct GetBucketReplicationResponse : public Response { ReplicationConfig config; - GetBucketReplicationResponse(ReplicationConfig config) { - this->config = config; - } + GetBucketReplicationResponse(ReplicationConfig config) + : config(std::move(config)) {} - GetBucketReplicationResponse(error::Error err) : Response(err) {} + GetBucketReplicationResponse(error::Error err) : Response(std::move(err)) {} GetBucketReplicationResponse(const Response& resp) : Response(resp) {} + ~GetBucketReplicationResponse() = default; + static GetBucketReplicationResponse ParseXML(std::string_view data); }; // struct GetBucketReplicationResponse @@ -376,9 +392,10 @@ using DeleteBucketLifecycleResponse = Response; struct GetBucketLifecycleResponse : public Response { LifecycleConfig config; - GetBucketLifecycleResponse(LifecycleConfig config) { this->config = config; } + GetBucketLifecycleResponse(LifecycleConfig config) + : config(std::move(config)) {} - GetBucketLifecycleResponse(error::Error err) : Response(err) {} + GetBucketLifecycleResponse(error::Error err) : Response(std::move(err)) {} GetBucketLifecycleResponse(const Response& resp) : Response(resp) {} @@ -392,14 +409,15 @@ using DeleteBucketTagsResponse = Response; struct GetBucketTagsResponse : public Response { std::map tags; - GetBucketTagsResponse(std::map tags) { - this->tags = tags; - } + GetBucketTagsResponse(std::map tags) + : tags(std::move(tags)) {} - GetBucketTagsResponse(error::Error err) : Response(err) {} + GetBucketTagsResponse(error::Error err) : Response(std::move(err)) {} GetBucketTagsResponse(const Response& resp) : Response(resp) {} + ~GetBucketTagsResponse() = default; + static GetBucketTagsResponse ParseXML(std::string_view data); }; // struct GetBucketTagsResponse @@ -410,13 +428,14 @@ using DeleteObjectLockConfigResponse = Response; struct GetObjectLockConfigResponse : public Response { ObjectLockConfig config; - GetObjectLockConfigResponse(ObjectLockConfig config) { - this->config = config; - } + GetObjectLockConfigResponse(ObjectLockConfig config) + : config(std::move(config)) {} - GetObjectLockConfigResponse(error::Error err) : Response(err) {} + GetObjectLockConfigResponse(error::Error err) : Response(std::move(err)) {} GetObjectLockConfigResponse(const Response& resp) : Response(resp) {} + + ~GetObjectLockConfigResponse() = default; }; // struct GetObjectLockConfigResponse using SetObjectLockConfigResponse = Response; @@ -426,14 +445,15 @@ using DeleteObjectTagsResponse = Response; struct GetObjectTagsResponse : public Response { std::map tags; - GetObjectTagsResponse(std::map tags) { - this->tags = tags; - } + GetObjectTagsResponse(std::map tags) + : tags(std::move(tags)) {} - GetObjectTagsResponse(error::Error err) : Response(err) {} + GetObjectTagsResponse(error::Error err) : Response(std::move(err)) {} GetObjectTagsResponse(const Response& resp) : Response(resp) {} + ~GetObjectTagsResponse() = default; + static GetObjectTagsResponse ParseXML(std::string_view data); }; // struct GetObjectTagsResponse @@ -446,22 +466,27 @@ using DisableObjectLegalHoldResponse = Response; struct IsObjectLegalHoldEnabledResponse : public Response { bool enabled = false; - IsObjectLegalHoldEnabledResponse(bool enabled) { this->enabled = enabled; } + IsObjectLegalHoldEnabledResponse(bool enabled) : enabled(enabled) {} - IsObjectLegalHoldEnabledResponse(error::Error err) : Response(err) {} + IsObjectLegalHoldEnabledResponse(error::Error err) + : Response(std::move(err)) {} IsObjectLegalHoldEnabledResponse(const Response& resp) : Response(resp) {} + + ~IsObjectLegalHoldEnabledResponse() = default; }; // struct IsObjectLegalHoldEnabledResponse struct GetObjectRetentionResponse : public Response { RetentionMode retention_mode; utils::Time retain_until_date; - GetObjectRetentionResponse() {} + GetObjectRetentionResponse() = default; - GetObjectRetentionResponse(error::Error err) : Response(err) {} + GetObjectRetentionResponse(error::Error err) : Response(std::move(err)) {} GetObjectRetentionResponse(const Response& resp) : Response(resp) {} + + ~GetObjectRetentionResponse() = default; }; // struct GetObjectRetentionResponse using SetObjectRetentionResponse = Response; @@ -469,24 +494,27 @@ using SetObjectRetentionResponse = Response; struct GetPresignedObjectUrlResponse : public Response { std::string url; - GetPresignedObjectUrlResponse(std::string url) { this->url = url; } + GetPresignedObjectUrlResponse(std::string url) : url(std::move(url)) {} - GetPresignedObjectUrlResponse(error::Error err) : Response(err) {} + GetPresignedObjectUrlResponse(error::Error err) : Response(std::move(err)) {} GetPresignedObjectUrlResponse(const Response& resp) : Response(resp) {} + + ~GetPresignedObjectUrlResponse() = default; }; // struct GetPresignedObjectUrlResponse struct GetPresignedPostFormDataResponse : public Response { std::map form_data; - GetPresignedPostFormDataResponse( - std::map form_data) { - this->form_data = form_data; - } + GetPresignedPostFormDataResponse(std::map form_data) + : form_data(std::move(form_data)) {} - GetPresignedPostFormDataResponse(error::Error err) : Response(err) {} + GetPresignedPostFormDataResponse(error::Error err) + : Response(std::move(err)) {} GetPresignedPostFormDataResponse(const Response& resp) : Response(resp) {} + + ~GetPresignedPostFormDataResponse() = default; }; // struct GetPresignedPostFormDataResponse } // namespace s3 } // namespace minio diff --git a/include/select.h b/include/select.h index 3245db83..e1da0a5b 100644 --- a/include/select.h +++ b/include/select.h @@ -25,7 +25,7 @@ namespace minio { namespace s3 { class SelectHandler { private: - SelectResultFunction result_func_ = NULL; + SelectResultFunction result_func_ = nullptr; bool done_ = false; std::string response_; @@ -51,14 +51,15 @@ class SelectHandler { bool ReadMessageCrc(); error::Error DecodeHeader(std::map& headers, std::string data); - bool process(http::DataFunctionArgs args, bool& cont); + bool process(const http::DataFunctionArgs& args, bool& cont); public: - SelectHandler(SelectResultFunction result_func) { - this->result_func_ = result_func; - } + SelectHandler(SelectResultFunction result_func) + : result_func_(std::move(result_func)) {} - bool DataFunction(http::DataFunctionArgs args); + ~SelectHandler() = default; + + bool DataFunction(const http::DataFunctionArgs& args); }; // struct SelectHandler } // namespace s3 } // namespace minio diff --git a/include/signer.h b/include/signer.h index 84ade924..5c5b67cc 100644 --- a/include/signer.h +++ b/include/signer.h @@ -22,46 +22,56 @@ namespace minio { namespace signer { -std::string GetScope(utils::Time& time, std::string& region, - std::string& service_name); -std::string GetCanonicalRequestHash(std::string& method, std::string& uri, - std::string& query_string, - std::string& headers, - std::string& signed_headers, - std::string& content_sha256); -std::string GetStringToSign(utils::Time& date, std::string& scope, - std::string& canonical_request_hash); +std::string GetScope(const utils::Time& time, const std::string& region, + const std::string& service_name); +std::string GetCanonicalRequestHash(const std::string& method, + const std::string& uri, + const std::string& query_string, + const std::string& headers, + const std::string& signed_headers, + const std::string& content_sha256); +std::string GetStringToSign(const utils::Time& date, const std::string& scope, + const std::string& canonical_request_hash); std::string HmacHash(std::string_view key, std::string_view data); -std::string GetSigningKey(std::string& secret_key, utils::Time& date, - std::string_view region, +std::string GetSigningKey(const std::string& secret_key, + const utils::Time& date, std::string_view region, std::string_view service_name); std::string GetSignature(std::string_view signing_key, std::string_view string_to_sign); -std::string GetAuthorization(std::string& access_key, std::string& scope, - std::string& signed_headers, - std::string& signature); -utils::Multimap& SignV4(std::string& service_name, http::Method& method, - std::string& uri, std::string& region, - utils::Multimap& headers, utils::Multimap& query_params, - std::string& access_key, std::string& secret_key, - std::string& content_sha256, utils::Time& date); -utils::Multimap& SignV4S3(http::Method method, std::string& uri, - std::string& region, utils::Multimap& headers, - utils::Multimap query_params, std::string& access_key, - std::string& secret_key, std::string& content_sha256, - utils::Time& date); -utils::Multimap& SignV4STS(http::Method method, std::string& uri, - std::string& region, utils::Multimap& headers, - utils::Multimap query_params, - std::string& access_key, std::string& secret_key, - std::string& content_sha256, utils::Time& date); -utils::Multimap& PresignV4(http::Method method, std::string& host, - std::string& uri, std::string& region, - utils::Multimap& query_params, - std::string& access_key, std::string& secret_key, - utils::Time& date, unsigned int expires); -std::string PostPresignV4(std::string data, std::string& secret_key, - utils::Time& date, std::string& region); +std::string GetAuthorization(const std::string& access_key, + const std::string& scope, + const std::string& signed_headers, + const std::string& signature); +utils::Multimap SignV4(const std::string& service_name, http::Method method, + const std::string& uri, const std::string& region, + utils::Multimap& headers, utils::Multimap query_params, + const std::string& access_key, + const std::string& secret_key, + const std::string& content_sha256, + const utils::Time& date); +utils::Multimap SignV4S3(http::Method method, const std::string& uri, + const std::string& region, utils::Multimap& headers, + utils::Multimap query_params, + const std::string& access_key, + const std::string& secret_key, + const std::string& content_sha256, + const utils::Time& date); +utils::Multimap SignV4STS(http::Method method, const std::string& uri, + const std::string& region, utils::Multimap& headers, + utils::Multimap query_params, + const std::string& access_key, + const std::string& secret_key, + const std::string& content_sha256, + const utils::Time& date); +utils::Multimap PresignV4(http::Method method, const std::string& host, + const std::string& uri, const std::string& region, + utils::Multimap query_params, + const std::string& access_key, + const std::string& secret_key, + const utils::Time& date, unsigned int expires); +std::string PostPresignV4(const std::string& data, + const std::string& secret_key, + const utils::Time& date, const std::string& region); } // namespace signer } // namespace minio #endif // #ifndef __MINIO_SIGNER_H diff --git a/include/sse.h b/include/sse.h index 02089d0c..3edeb7b9 100644 --- a/include/sse.h +++ b/include/sse.h @@ -26,60 +26,37 @@ class Sse { utils::Multimap copy_headers_; public: - Sse() {} + Sse(); + virtual ~Sse(); - virtual ~Sse() {} + utils::Multimap Headers() const; + utils::Multimap CopyHeaders() const; - utils::Multimap Headers() { return headers_; } - - utils::Multimap CopyHeaders() { return copy_headers_; } - - virtual bool TlsRequired() = 0; + virtual bool TlsRequired() const = 0; }; // class Sse class SseCustomerKey : public Sse { public: - SseCustomerKey(std::string_view key) { - std::string b64key = utils::Base64Encode(key); - std::string md5key = utils::Md5sumHash(key); - - this->headers_.Add("X-Amz-Server-Side-Encryption-Customer-Algorithm", - "AES256"); - this->headers_.Add("X-Amz-Server-Side-Encryption-Customer-Key", b64key); - this->headers_.Add("X-Amz-Server-Side-Encryption-Customer-Key-MD5", md5key); - - this->copy_headers_.Add( - "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Algorithm", - "AES256"); - this->copy_headers_.Add( - "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key", b64key); - this->copy_headers_.Add( - "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key-MD5", md5key); - } + SseCustomerKey(std::string_view key); + virtual ~SseCustomerKey(); - bool TlsRequired() { return true; } + virtual bool TlsRequired() const override; }; // class SseCustomerKey class SseKms : public Sse { public: - SseKms(std::string_view key, std::string_view context) { - this->headers_.Add("X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id", - std::string(key)); - this->headers_.Add("X-Amz-Server-Side-Encryption", "aws:kms"); - if (!context.empty()) { - this->headers_.Add("X-Amz-Server-Side-Encryption-Context", - utils::Base64Encode(context)); - } - } + SseKms(std::string_view key, std::string_view context); + virtual ~SseKms(); - bool TlsRequired() { return true; } + virtual bool TlsRequired() const override; }; // class SseKms class SseS3 : public Sse { public: - SseS3() { this->headers_.Add("X-Amz-Server-Side-Encryption", "AES256"); } + SseS3(); + virtual ~SseS3(); - bool TlsRequired() { return false; } + virtual bool TlsRequired() const override; }; // class SseS3 } // namespace s3 } // namespace minio diff --git a/include/types.h b/include/types.h index 6e84150e..ab1ebd5a 100644 --- a/include/types.h +++ b/include/types.h @@ -18,6 +18,7 @@ #include #include +#include #include "utils.h" @@ -26,9 +27,9 @@ namespace s3 { enum class RetentionMode { kGovernance, kCompliance }; // StringToRetentionMode converts string to retention mode enum. -RetentionMode StringToRetentionMode(std::string_view str) throw(); +RetentionMode StringToRetentionMode(std::string_view str) noexcept; -constexpr bool IsRetentionModeValid(RetentionMode& retention) { +constexpr bool IsRetentionModeValid(RetentionMode retention) { switch (retention) { case RetentionMode::kGovernance: case RetentionMode::kCompliance: @@ -38,7 +39,7 @@ constexpr bool IsRetentionModeValid(RetentionMode& retention) { } // RetentionModeToString converts retention mode enum to string. -constexpr const char* RetentionModeToString(RetentionMode& retention) throw() { +constexpr const char* RetentionModeToString(RetentionMode retention) noexcept { switch (retention) { case RetentionMode::kGovernance: return "GOVERNANCE"; @@ -50,15 +51,15 @@ constexpr const char* RetentionModeToString(RetentionMode& retention) throw() { std::terminate(); } } - return NULL; + return nullptr; } enum class LegalHold { kOn, kOff }; // StringToLegalHold converts string to legal hold enum. -LegalHold StringToLegalHold(std::string_view str) throw(); +LegalHold StringToLegalHold(std::string_view str) noexcept; -constexpr bool IsLegalHoldValid(LegalHold& legal_hold) { +constexpr bool IsLegalHoldValid(LegalHold legal_hold) { switch (legal_hold) { case LegalHold::kOn: case LegalHold::kOff: @@ -68,7 +69,7 @@ constexpr bool IsLegalHoldValid(LegalHold& legal_hold) { } // LegalHoldToString converts legal hold enum to string. -constexpr const char* LegalHoldToString(LegalHold& legal_hold) throw() { +constexpr const char* LegalHoldToString(LegalHold legal_hold) noexcept { switch (legal_hold) { case LegalHold::kOn: return "ON"; @@ -80,16 +81,16 @@ constexpr const char* LegalHoldToString(LegalHold& legal_hold) throw() { std::terminate(); } } - return NULL; + return nullptr; } enum class Directive { kCopy, kReplace }; // StringToDirective converts string to directive enum. -Directive StringToDirective(std::string_view str) throw(); +Directive StringToDirective(std::string_view str) noexcept; // DirectiveToString converts directive enum to string. -constexpr const char* DirectiveToString(Directive& directive) throw() { +constexpr const char* DirectiveToString(Directive directive) noexcept { switch (directive) { case Directive::kCopy: return "COPY"; @@ -101,13 +102,13 @@ constexpr const char* DirectiveToString(Directive& directive) throw() { std::terminate(); } } - return NULL; + return nullptr; } enum class CompressionType { kNone, kGZip, kBZip2 }; // CompressionTypeToString converts compression type enum to string. -constexpr const char* CompressionTypeToString(CompressionType& ctype) throw() { +constexpr const char* CompressionTypeToString(CompressionType ctype) noexcept { switch (ctype) { case CompressionType::kNone: return "NONE"; @@ -121,13 +122,13 @@ constexpr const char* CompressionTypeToString(CompressionType& ctype) throw() { std::terminate(); } } - return NULL; + return nullptr; } enum class FileHeaderInfo { kUse, kIgnore, kNone }; // FileHeaderInfoToString converts file header info enum to string. -constexpr const char* FileHeaderInfoToString(FileHeaderInfo& info) throw() { +constexpr const char* FileHeaderInfoToString(FileHeaderInfo info) noexcept { switch (info) { case FileHeaderInfo::kUse: return "USE"; @@ -141,13 +142,13 @@ constexpr const char* FileHeaderInfoToString(FileHeaderInfo& info) throw() { std::terminate(); } } - return NULL; + return nullptr; } enum class JsonType { kDocument, kLines }; // JsonTypeToString converts JSON type enum to string. -constexpr const char* JsonTypeToString(JsonType& jtype) throw() { +constexpr const char* JsonTypeToString(JsonType jtype) noexcept { switch (jtype) { case JsonType::kDocument: return "DOCUMENT"; @@ -159,13 +160,13 @@ constexpr const char* JsonTypeToString(JsonType& jtype) throw() { std::terminate(); } } - return NULL; + return nullptr; } enum class QuoteFields { kAlways, kAsNeeded }; // QuoteFieldsToString converts quote fields enum to string. -constexpr const char* QuoteFieldsToString(QuoteFields& qtype) throw() { +constexpr const char* QuoteFieldsToString(QuoteFields qtype) noexcept { switch (qtype) { case QuoteFields::kAlways: return "ALWAYS"; @@ -177,95 +178,106 @@ constexpr const char* QuoteFieldsToString(QuoteFields& qtype) throw() { std::terminate(); } } - return NULL; + return nullptr; } struct CsvInputSerialization { - CompressionType* compression_type = NULL; + CompressionType* compression_type = nullptr; bool allow_quoted_record_delimiter = false; char comments = 0; char field_delimiter = 0; - FileHeaderInfo* file_header_info = NULL; + FileHeaderInfo* file_header_info = nullptr; char quote_character = 0; char quote_escape_character = 0; char record_delimiter = 0; + + CsvInputSerialization() = default; + ~CsvInputSerialization() = default; }; // struct CsvInputSerialization struct JsonInputSerialization { - CompressionType* compression_type = NULL; - JsonType* json_type = NULL; + CompressionType* compression_type = nullptr; + JsonType* json_type = nullptr; + + JsonInputSerialization() = default; + ~JsonInputSerialization() = default; }; // struct JsonInputSerialization -struct ParquetInputSerialization {}; // struct ParquetInputSerialization +struct ParquetInputSerialization { + ParquetInputSerialization() = default; + ~ParquetInputSerialization() = default; +}; // struct ParquetInputSerialization struct CsvOutputSerialization { char field_delimiter = 0; char quote_character = 0; char quote_escape_character = 0; - QuoteFields* quote_fields = NULL; + QuoteFields* quote_fields = nullptr; char record_delimiter = 0; + + CsvOutputSerialization() = default; + ~CsvOutputSerialization() = default; }; // struct CsvOutputSerialization struct JsonOutputSerialization { char record_delimiter = 0; + + JsonOutputSerialization() = default; + ~JsonOutputSerialization() = default; }; // struct JsonOutputSerialization struct SelectRequest { std::string expr; - CsvInputSerialization* csv_input = NULL; - JsonInputSerialization* json_input = NULL; - ParquetInputSerialization* parquet_input = NULL; - CsvOutputSerialization* csv_output = NULL; - JsonOutputSerialization* json_output = NULL; + CsvInputSerialization* csv_input = nullptr; + JsonInputSerialization* json_input = nullptr; + ParquetInputSerialization* parquet_input = nullptr; + CsvOutputSerialization* csv_output = nullptr; + JsonOutputSerialization* json_output = nullptr; bool request_progress = false; - size_t* scan_start_range = NULL; - size_t* scan_end_range = NULL; + size_t* scan_start_range = nullptr; + size_t* scan_end_range = nullptr; SelectRequest(std::string expression, CsvInputSerialization* csv_input, - CsvOutputSerialization* csv_output) { - this->expr = expression; - this->csv_input = csv_input; - this->csv_output = csv_output; - } + CsvOutputSerialization* csv_output) + : expr(std::move(expression)), + csv_input(csv_input), + csv_output(csv_output) {} SelectRequest(std::string expression, CsvInputSerialization* csv_input, - JsonOutputSerialization* json_output) { - this->expr = expression; - this->csv_input = csv_input; - this->json_output = json_output; - } + JsonOutputSerialization* json_output) + : expr(std::move(expression)), + csv_input(csv_input), + json_output(json_output) {} SelectRequest(std::string expression, JsonInputSerialization* json_input, - CsvOutputSerialization* csv_output) { - this->expr = expression; - this->json_input = json_input; - this->csv_output = csv_output; - } + CsvOutputSerialization* csv_output) + : expr(std::move(expression)), + json_input(json_input), + csv_output(csv_output) {} SelectRequest(std::string expression, JsonInputSerialization* json_input, - JsonOutputSerialization* json_output) { - this->expr = expression; - this->json_input = json_input; - this->json_output = json_output; - } + JsonOutputSerialization* json_output) + : expr(std::move(expression)), + json_input(json_input), + json_output(json_output) {} SelectRequest(std::string expression, ParquetInputSerialization* parquet_input, - CsvOutputSerialization* csv_output) { - this->expr = expression; - this->parquet_input = parquet_input; - this->csv_output = csv_output; - } + CsvOutputSerialization* csv_output) + : expr(std::move(expression)), + parquet_input(parquet_input), + csv_output(csv_output) {} SelectRequest(std::string expression, ParquetInputSerialization* parquet_input, - JsonOutputSerialization* json_output) { - this->expr = expression; - this->parquet_input = parquet_input; - this->json_output = json_output; - } + JsonOutputSerialization* json_output) + : expr(std::move(expression)), + parquet_input(parquet_input), + json_output(json_output) {} - std::string ToXML(); + ~SelectRequest() = default; + + std::string ToXML() const; }; // struct SelectRequest struct SelectResult { @@ -276,21 +288,19 @@ struct SelectResult { long int bytes_returned = -1; std::string records; - SelectResult() { this->ended = true; } + SelectResult() : ended(true) {} - SelectResult(error::Error err) { - this->err = err; - this->ended = true; - } + SelectResult(error::Error err) : err(std::move(err)), ended(true) {} SelectResult(long int bytes_scanned, long int bytes_processed, - long int bytes_returned) { - this->bytes_scanned = bytes_scanned; - this->bytes_processed = bytes_processed; - this->bytes_returned = bytes_returned; - } + long int bytes_returned) + : bytes_scanned(bytes_scanned), + bytes_processed(bytes_processed), + bytes_returned(bytes_returned) {} + + SelectResult(std::string records) : records(std::move(records)) {} - SelectResult(std::string records) { this->records = records; } + ~SelectResult() = default; }; using SelectResultFunction = std::function; @@ -298,23 +308,35 @@ using SelectResultFunction = std::function; struct Bucket { std::string name; utils::Time creation_date; + + Bucket() = default; + ~Bucket() = default; }; // struct Bucket struct Part { unsigned int number; std::string etag; - utils::Time last_modified; - size_t size; + utils::Time last_modified = {}; + size_t size = 0; + + Part() = default; + ~Part() = default; }; // struct Part struct Retention { RetentionMode mode; utils::Time retain_until_date; + + Retention() = default; + ~Retention() = default; }; // struct Retention struct DeleteObject { - std::string name; - std::string version_id; + std::string name = {}; + std::string version_id = {}; + + DeleteObject() = default; + ~DeleteObject() = default; }; // struct DeleteObject struct NotificationRecord { @@ -362,6 +384,9 @@ struct NotificationRecord { std::string user_agent; } source; + NotificationRecord() = default; + ~NotificationRecord() = default; + static NotificationRecord ParseJSON(nlohmann::json j_record); }; // struct NotificationRecord @@ -374,27 +399,35 @@ struct FilterValue { bool is_value_set_ = false; public: - FilterValue() {} - FilterValue(std::string value) { - this->value_ = value; - this->is_value_set_ = true; - } - operator bool() const { return is_value_set_; } - std::string Value() { return value_; } + FilterValue() = default; + + FilterValue(std::string value) + : value_(std::move(value)), is_value_set_(true) {} + + ~FilterValue() = default; + + explicit operator bool() const { return is_value_set_; } + std::string Value() const { return value_; } }; // struct FilterValue struct PrefixFilterRule : public FilterValue { static constexpr const char* name = "prefix"; - PrefixFilterRule() {} - PrefixFilterRule(std::string value) : FilterValue(value) {} + PrefixFilterRule() = default; + + PrefixFilterRule(std::string value) : FilterValue(std::move(value)) {} + + ~PrefixFilterRule() = default; }; // struct PrefixFilterRule struct SuffixFilterRule : public FilterValue { static constexpr const char* name = "suffix"; - SuffixFilterRule() {} - SuffixFilterRule(std::string value) : FilterValue(value) {} + SuffixFilterRule() = default; + + SuffixFilterRule(std::string value) : FilterValue(std::move(value)) {} + + ~SuffixFilterRule() = default; }; // struct SuffixFilterRule struct NotificationCommonConfig { @@ -402,18 +435,30 @@ struct NotificationCommonConfig { std::string id; PrefixFilterRule prefix_filter_rule; SuffixFilterRule suffix_filter_rule; + + NotificationCommonConfig() = default; + ~NotificationCommonConfig() = default; }; // struct NotificationCommonConfig struct CloudFuncConfig : public NotificationCommonConfig { std::string cloud_func; + + CloudFuncConfig() = default; + ~CloudFuncConfig() = default; }; // struct CloudFuncConfig struct QueueConfig : public NotificationCommonConfig { std::string queue; + + QueueConfig() = default; + ~QueueConfig() = default; }; // struct QueueConfig struct TopicConfig : public NotificationCommonConfig { std::string topic; + + TopicConfig() = default; + ~TopicConfig() = default; }; // struct TopicConfig struct NotificationConfig { @@ -421,33 +466,33 @@ struct NotificationConfig { std::list queue_config_list; std::list topic_config_list; - std::string ToXML(); + NotificationConfig() = default; + ~NotificationConfig() = default; + + std::string ToXML() const; }; // struct NotificationConfig struct SseConfig { std::string sse_algorithm; std::string kms_master_key_id; - SseConfig() {} - static SseConfig S3() { - SseConfig config; - config.sse_algorithm = "AES256"; - return config; - } - static SseConfig Kms(std::string masterkeyid = "") { - SseConfig config; - config.sse_algorithm = "aws:kms"; - config.kms_master_key_id = masterkeyid; - return config; - } - operator bool() const { return !sse_algorithm.empty(); } + SseConfig() = default; + ~SseConfig() = default; + + static SseConfig S3(); + static SseConfig Kms(std::string masterkeyid = {}); + + explicit operator bool() const { return !sse_algorithm.empty(); } }; // struct SseConfig struct Tag { std::string key; std::string value; - operator bool() const { return !key.empty(); } + Tag() = default; + ~Tag() = default; + + explicit operator bool() const { return !key.empty(); } }; // struct Tag struct Prefix { @@ -456,13 +501,18 @@ struct Prefix { bool is_set_ = false; public: - Prefix() {} - Prefix(std::string value) { - this->value_ = value; - this->is_set_ = true; + Prefix() = default; + + Prefix(std::string value) : value_(std::move(value)), is_set_(true) {} + + ~Prefix() = default; + + explicit operator bool() const { return is_set_; } + std::string Get() const { return value_; } + + friend std::ostream& operator<<(std::ostream& s, const Prefix& v) { + return s << v.value_; } - operator bool() const { return is_set_; } - std::string Get() { return value_; } }; // struct Prefix struct Integer { @@ -471,13 +521,18 @@ struct Integer { bool is_set_ = false; public: - Integer() {} - Integer(int value) { - this->value_ = value; - this->is_set_ = true; + Integer() = default; + + Integer(int value) : value_(value), is_set_(true) {} + + ~Integer() = default; + + explicit operator bool() const { return is_set_; } + int Get() const { return value_; } + + friend std::ostream& operator<<(std::ostream& s, const Integer& v) { + return s << v.value_; } - operator bool() const { return is_set_; } - int Get() { return value_; } }; // struct Integer struct Boolean { @@ -486,20 +541,28 @@ struct Boolean { bool is_set_ = false; public: - Boolean() {} - Boolean(bool value) { - this->value_ = value; - this->is_set_ = true; + Boolean() = default; + + Boolean(bool value) : value_(value), is_set_(true) {} + + ~Boolean() = default; + + explicit operator bool() const { return is_set_; } + bool Get() const { return value_; } + + friend std::ostream& operator<<(std::ostream& s, const Boolean& v) { + return s << utils::BoolToString(v.value_); } - operator bool() const { return is_set_; } - bool Get() { return value_; } }; // struct Boolean struct AndOperator { Prefix prefix; std::map tags; - operator bool() const { return prefix || !tags.empty(); } + AndOperator() = default; + ~AndOperator() = default; + + explicit operator bool() const { return prefix || !tags.empty(); } }; // struct AndOperator struct Filter { @@ -507,14 +570,23 @@ struct Filter { Prefix prefix; Tag tag; - operator bool() const { return and_operator ^ prefix ^ tag; } + Filter() = default; + ~Filter() = default; + + explicit operator bool() const { + return static_cast(and_operator) ^ static_cast(prefix) ^ + static_cast(tag); + } }; // struct Filter struct AccessControlTranslation { std::string owner = "Destination"; + AccessControlTranslation() = default; + ~AccessControlTranslation() = default; + void Enable() { enabled_ = true; } - operator bool() const { return enabled_; } + explicit operator bool() const { return enabled_; } private: bool enabled_ = false; @@ -523,8 +595,11 @@ struct AccessControlTranslation { struct EncryptionConfig { std::string replica_kms_key_id; + EncryptionConfig() = default; + ~EncryptionConfig() = default; + void Enable() { enabled_ = true; } - operator bool() const { return enabled_; } + explicit operator bool() const { return enabled_; } private: bool enabled_ = false; @@ -534,8 +609,11 @@ struct Metrics { unsigned int event_threshold_minutes = 15; bool status = false; + Metrics() = default; + ~Metrics() = default; + void Enable() { enabled_ = true; } - operator bool() const { return enabled_; } + explicit operator bool() const { return enabled_; } private: bool enabled_ = false; @@ -545,8 +623,11 @@ struct ReplicationTime { unsigned int time_minutes = 15; bool status = false; + ReplicationTime() = default; + ~ReplicationTime() = default; + void Enable() { enabled_ = true; } - operator bool() const { return enabled_; } + explicit operator bool() const { return enabled_; } private: bool enabled_ = false; @@ -560,13 +641,19 @@ struct Destination { Metrics metrics; ReplicationTime replication_time; std::string storage_class; + + Destination() = default; + ~Destination() = default; }; // struct Destination struct SourceSelectionCriteria { Boolean sse_kms_encrypted_objects_status; + SourceSelectionCriteria() = default; + ~SourceSelectionCriteria() = default; + void Enable() { enabled_ = true; } - operator bool() const { return enabled_; } + explicit operator bool() const { return enabled_; } private: bool enabled_ = false; @@ -583,13 +670,19 @@ struct ReplicationRule { SourceSelectionCriteria source_selection_criteria; Boolean delete_replication_status; bool status = false; + + ReplicationRule() = default; + ~ReplicationRule() = default; }; // struct ReplicationRule struct ReplicationConfig { std::string role; std::list rules; - std::string ToXML(); + ReplicationConfig() = default; + ~ReplicationConfig() = default; + + std::string ToXML() const; }; // status ReplicationConfig struct LifecycleRule { @@ -607,13 +700,19 @@ struct LifecycleRule { Integer transition_days; std::string transition_storage_class; - error::Error Validate(); + LifecycleRule() = default; + ~LifecycleRule() = default; + + error::Error Validate() const; }; // struct LifecycleRule struct LifecycleConfig { std::list rules; - std::string ToXML(); + LifecycleConfig() = default; + ~LifecycleConfig() = default; + + std::string ToXML() const; }; // struct LifecycleConfig struct ObjectLockConfig { @@ -621,7 +720,10 @@ struct ObjectLockConfig { Integer retention_duration_days; Integer retention_duration_years; - error::Error Validate(); + ObjectLockConfig() = default; + ~ObjectLockConfig() = default; + + error::Error Validate() const; }; // struct ObjectLockConfig } // namespace s3 } // namespace minio diff --git a/include/utils.h b/include/utils.h index 10cf378d..59ce16e2 100644 --- a/include/utils.h +++ b/include/utils.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -48,11 +49,12 @@ inline constexpr unsigned long long kMaxObjectSize = 5497558138880ULL; // 5TiB inline constexpr unsigned long long kMaxPartSize = 5368709120UL; // 5GiB inline constexpr unsigned int kMinPartSize = 5 * 1024 * 1024; // 5MiB +// GetEnv copies the environment variable name into var bool GetEnv(std::string& var, const char* name); std::string GetHomeDir(); -std::string Printable(std::string s); +std::string Printable(const std::string& s); unsigned long CRC32(std::string_view str); @@ -62,10 +64,10 @@ unsigned int Int(std::string_view str); std::string FormatTime(const std::tm* time, const char* format); // StringToBool converts string to bool. -bool StringToBool(std::string str); +bool StringToBool(const std::string& str); // BoolToString converts bool to string. -inline const char* const BoolToString(bool b) { return b ? "true" : "false"; } +inline const char* BoolToString(bool b) { return b ? "true" : "false"; } // Trim trims leading and trailing character of a string. std::string Trim(std::string_view str, char ch = ' '); @@ -75,7 +77,7 @@ std::string Trim(std::string_view str, char ch = ' '); bool CheckNonEmptyString(std::string_view str); // ToLower converts string to lower case. -std::string ToLower(std::string str); +std::string ToLower(const std::string& str); // StartsWith returns whether str starts with prefix or not. bool StartsWith(std::string_view str, std::string_view prefix); @@ -90,13 +92,15 @@ bool Contains(std::string_view str, char ch); bool Contains(std::string_view str, std::string_view substr); // Join returns a string of joined values by delimiter. -std::string Join(std::list values, std::string delimiter); +std::string Join(const std::list& values, + const std::string& delimiter); // Join returns a string of joined values by delimiter. -std::string Join(std::vector values, std::string delimiter); +std::string Join(const std::vector& values, + const std::string& delimiter); // EncodePath does URL encoding of path. It also normalizes multiple slashes. -std::string EncodePath(std::string& path); +std::string EncodePath(const std::string& path); // Sha256hash computes SHA-256 of data and return hash as hex encoded value. std::string Sha256Hash(std::string_view str); @@ -118,44 +122,64 @@ error::Error CalcPartInfo(long object_size, size_t& part_size, */ class Time { private: - struct timeval tv_ = {0, 0}; + struct timeval tv_ = {}; bool utc_ = false; public: - Time() {} + Time() = default; - Time(std::time_t tv_sec, long tv_usec, bool utc) { - this->tv_.tv_sec = tv_sec; - this->tv_.tv_usec = tv_usec; - this->utc_ = utc; + Time(std::time_t tv_sec, long tv_usec, bool utc) : utc_(utc) { + tv_.tv_sec = static_cast(tv_sec); + tv_.tv_usec = static_cast(tv_usec); } - void Add(time_t seconds) { tv_.tv_sec += seconds; } + ~Time() = default; - std::tm* ToUTC(); + void Add(std::time_t seconds) { + tv_.tv_sec += static_cast(seconds); + } + + std::tm* ToUTC() const; - std::string ToSignerDate(); + std::string ToSignerDate() const; - std::string ToAmzDate(); + std::string ToAmzDate() const; - std::string ToHttpHeaderValue(); + std::string ToHttpHeaderValue() const; static Time FromHttpHeaderValue(const char* value); - std::string ToISO8601UTC(); + std::string ToISO8601UTC() const; static Time FromISO8601UTC(const char* value); - static Time Now() { - Time t; - auto usec = std::chrono::system_clock::now().time_since_epoch() / - std::chrono::microseconds(1); - t.tv_.tv_sec = static_cast(usec / 1000000); - t.tv_.tv_usec = static_cast(usec % 1000000); - return t; - } + static Time Now(); + + explicit operator bool() const { return tv_.tv_sec != 0 && tv_.tv_usec != 0; } + + int Compare(const Time& rhs) const; + + bool Equal(const Time& rhs) const { return Compare(rhs) == 0; } + + bool operator==(const Time& rhs) const { return Equal(rhs); } + + bool operator!=(const Time& rhs) const { return !operator==(rhs); } + + bool operator<(const Time& rhs) const { return Compare(rhs) < 0; } - operator bool() const { return tv_.tv_sec != 0 && tv_.tv_usec != 0; } + bool operator>(const Time& rhs) const { return Compare(rhs) > 0; } + + bool operator<=(const Time& rhs) const { return !operator>(rhs); } + + bool operator>=(const Time& rhs) const { return !operator<(rhs); } + +#if __cplusplus >= 202002L + auto operator<=>(const Time& rhs) const { return Compare(rhs); } +#endif + + friend std::ostream& operator<<(std::ostream& s, const Time& v) { + return s << v.ToISO8601UTC(); + } }; // class Time /** @@ -167,32 +191,35 @@ class Multimap { std::map> keys_; public: - Multimap() {} - - Multimap(const Multimap& headers) { this->AddAll(headers); } + Multimap() = default; + Multimap(const Multimap& headers) = default; + Multimap& operator=(const Multimap& headers) = default; + Multimap(Multimap&& headers) = default; + Multimap& operator=(Multimap&& headers) = default; + ~Multimap() = default; void Add(std::string key, std::string value); void AddAll(const Multimap& headers); - std::list ToHttpHeaders(); + std::list ToHttpHeaders() const; - std::string ToQueryString(); + std::string ToQueryString() const; - operator bool() const { return !map_.empty(); } + explicit operator bool() const { return !map_.empty(); } - bool Contains(std::string_view key); + bool Contains(std::string_view key) const; - std::list Get(std::string_view key); + std::list Get(std::string_view key) const; - std::string GetFront(std::string_view key); + std::string GetFront(std::string_view key) const; - std::list Keys(); + std::list Keys() const; void GetCanonicalHeaders(std::string& signed_headers, - std::string& canonical_headers); + std::string& canonical_headers) const; - std::string GetCanonicalQueryString(); + std::string GetCanonicalQueryString() const; }; // class Multimap /** @@ -200,21 +227,13 @@ class Multimap { */ struct CharBuffer : std::streambuf { CharBuffer(char* buf, size_t size) { this->setg(buf, buf, buf + size); } + virtual ~CharBuffer(); - pos_type seekoff(off_type off, std::ios_base::seekdir dir, - std::ios_base::openmode which = std::ios_base::in) override { - if (dir == std::ios_base::cur) - gbump(off); - else if (dir == std::ios_base::end) - setg(eback(), egptr() + off, egptr()); - else if (dir == std::ios_base::beg) - setg(eback(), eback() + off, egptr()); - return gptr() - eback(); - } + virtual pos_type seekpos(pos_type sp, std::ios_base::openmode which) override; - pos_type seekpos(pos_type sp, std::ios_base::openmode which) override { - return seekoff(sp - pos_type(off_type(0)), std::ios_base::beg, which); - } + virtual pos_type seekoff( + off_type off, std::ios_base::seekdir dir, + std::ios_base::openmode which = std::ios_base::in) override; }; // struct CharBuffer } // namespace utils } // namespace minio diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 17d46916..b7bcadbe 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -list(APPEND SRCS args.cc baseclient.cc client.cc http.cc request.cc response.cc select.cc signer.cc types.cc utils.cc) +list(APPEND SRCS args.cc baseclient.cc client.cc credentials.cc http.cc providers.cc request.cc response.cc select.cc signer.cc sse.cc types.cc utils.cc) add_library(miniocpp STATIC ${SRCS}) target_link_libraries(miniocpp ${requiredlibs}) diff --git a/src/args.cc b/src/args.cc index fcbfdbf0..47634ddf 100644 --- a/src/args.cc +++ b/src/args.cc @@ -15,12 +15,17 @@ #include "args.h" -minio::error::Error minio::s3::BucketArgs::Validate() { +#include +#include + +minio::error::Error minio::s3::BucketArgs::Validate() const { return utils::CheckBucketName(bucket); } -minio::error::Error minio::s3::ObjectArgs::Validate() { - if (error::Error err = BucketArgs::Validate()) return err; +minio::error::Error minio::s3::ObjectArgs::Validate() const { + if (error::Error err = BucketArgs::Validate()) { + return err; + } if (!utils::CheckNonEmptyString(object)) { return error::Error("object name cannot be empty"); } @@ -28,101 +33,120 @@ minio::error::Error minio::s3::ObjectArgs::Validate() { return error::SUCCESS; } -minio::utils::Multimap minio::s3::ObjectWriteArgs::Headers() { - utils::Multimap headers; - headers.AddAll(extra_headers); - headers.AddAll(headers); - headers.AddAll(user_metadata); +minio::utils::Multimap minio::s3::ObjectWriteArgs::Headers() const { + utils::Multimap result_headers; + result_headers.AddAll(extra_headers); + result_headers.AddAll(headers); + result_headers.AddAll(user_metadata); - if (sse != NULL) headers.AddAll(sse->Headers()); + if (sse != nullptr) { + result_headers.AddAll(sse->Headers()); + } std::string tagging; for (auto& [key, value] : tags) { std::string tag = curlpp::escape(key) + "=" + curlpp::escape(value); - if (!tagging.empty()) tagging += "&"; + if (!tagging.empty()) { + tagging += "&"; + } tagging += tag; } - if (!tagging.empty()) headers.Add("x-amz-tagging", tagging); - - if (retention != NULL) { - headers.Add("x-amz-object-lock-mode", - RetentionModeToString(retention->mode)); - headers.Add("x-amz-object-lock-retain-until-date", - retention->retain_until_date.ToISO8601UTC()); + if (!tagging.empty()) { + result_headers.Add("x-amz-tagging", tagging); + } + if (retention != nullptr) { + result_headers.Add("x-amz-object-lock-mode", + RetentionModeToString(retention->mode)); + result_headers.Add("x-amz-object-lock-retain-until-date", + retention->retain_until_date.ToISO8601UTC()); } - if (legal_hold) headers.Add("x-amz-object-lock-legal-hold", "ON"); - - return headers; + if (legal_hold) { + result_headers.Add("x-amz-object-lock-legal-hold", "ON"); + } + return result_headers; } -minio::utils::Multimap minio::s3::ObjectConditionalReadArgs::Headers() { +minio::utils::Multimap minio::s3::ObjectConditionalReadArgs::Headers() const { size_t* off = offset; size_t* len = length; size_t zero = 0; - if (len != NULL && off == NULL) { + if (len != nullptr && off == nullptr) { off = &zero; } std::string range; - if (off != NULL) { + if (off != nullptr) { range = "bytes=" + std::to_string(*off) + "-"; - if (len != NULL) { + if (len != nullptr) { range += std::to_string(*off + *len - 1); } } - utils::Multimap headers; - if (!range.empty()) headers.Add("Range", range); - if (!match_etag.empty()) headers.Add("if-match", match_etag); - if (!not_match_etag.empty()) headers.Add("if-none-match", not_match_etag); + utils::Multimap result_headers; + if (!range.empty()) { + result_headers.Add("Range", range); + } + if (!match_etag.empty()) { + result_headers.Add("if-match", match_etag); + } + if (!not_match_etag.empty()) { + result_headers.Add("if-none-match", not_match_etag); + } if (modified_since) { - headers.Add("if-modified-since", modified_since.ToHttpHeaderValue()); + result_headers.Add("if-modified-since", modified_since.ToHttpHeaderValue()); } if (unmodified_since) { - headers.Add("if-unmodified-since", unmodified_since.ToHttpHeaderValue()); + result_headers.Add("if-unmodified-since", + unmodified_since.ToHttpHeaderValue()); } - if (ssec != NULL) headers.AddAll(ssec->Headers()); - - return headers; + if (ssec != nullptr) { + result_headers.AddAll(ssec->Headers()); + } + return result_headers; } -minio::utils::Multimap minio::s3::ObjectConditionalReadArgs::CopyHeaders() { - utils::Multimap headers; +minio::utils::Multimap minio::s3::ObjectConditionalReadArgs::CopyHeaders() + const { + utils::Multimap result_headers; std::string copy_source = curlpp::escape("/" + bucket + "/" + object); if (!version_id.empty()) { copy_source += "?versionId=" + curlpp::escape(version_id); } - headers.Add("x-amz-copy-source", copy_source); + result_headers.Add("x-amz-copy-source", copy_source); - if (ssec != NULL) headers.AddAll(ssec->CopyHeaders()); + if (ssec != nullptr) { + result_headers.AddAll(ssec->CopyHeaders()); + } if (!match_etag.empty()) { - headers.Add("x-amz-copy-source-if-match", match_etag); + result_headers.Add("x-amz-copy-source-if-match", match_etag); } if (!not_match_etag.empty()) { - headers.Add("x-amz-copy-source-if-none-match", not_match_etag); + result_headers.Add("x-amz-copy-source-if-none-match", not_match_etag); } if (modified_since) { - headers.Add("x-amz-copy-source-if-modified-since", - modified_since.ToHttpHeaderValue()); + result_headers.Add("x-amz-copy-source-if-modified-since", + modified_since.ToHttpHeaderValue()); } if (unmodified_since) { - headers.Add("x-amz-copy-source-if-unmodified-since", - unmodified_since.ToHttpHeaderValue()); + result_headers.Add("x-amz-copy-source-if-unmodified-since", + unmodified_since.ToHttpHeaderValue()); } - return headers; + return result_headers; } -minio::error::Error minio::s3::MakeBucketArgs::Validate() { +minio::error::Error minio::s3::MakeBucketArgs::Validate() const { return utils::CheckBucketName(bucket, true); } -minio::error::Error minio::s3::AbortMultipartUploadArgs::Validate() { - if (error::Error err = ObjectArgs::Validate()) return err; +minio::error::Error minio::s3::AbortMultipartUploadArgs::Validate() const { + if (error::Error err = ObjectArgs::Validate()) { + return err; + } if (!utils::CheckNonEmptyString(upload_id)) { return error::Error("upload ID cannot be empty"); } @@ -130,8 +154,10 @@ minio::error::Error minio::s3::AbortMultipartUploadArgs::Validate() { return error::SUCCESS; } -minio::error::Error minio::s3::CompleteMultipartUploadArgs::Validate() { - if (error::Error err = ObjectArgs::Validate()) return err; +minio::error::Error minio::s3::CompleteMultipartUploadArgs::Validate() const { + if (error::Error err = ObjectArgs::Validate()) { + return err; + } if (!utils::CheckNonEmptyString(upload_id)) { return error::Error("upload ID cannot be empty"); } @@ -139,8 +165,10 @@ minio::error::Error minio::s3::CompleteMultipartUploadArgs::Validate() { return error::SUCCESS; } -minio::error::Error minio::s3::UploadPartArgs::Validate() { - if (error::Error err = ObjectArgs::Validate()) return err; +minio::error::Error minio::s3::UploadPartArgs::Validate() const { + if (error::Error err = ObjectArgs::Validate()) { + return err; + } if (!utils::CheckNonEmptyString(upload_id)) { return error::Error("upload ID cannot be empty"); } @@ -151,8 +179,10 @@ minio::error::Error minio::s3::UploadPartArgs::Validate() { return error::SUCCESS; } -minio::error::Error minio::s3::UploadPartCopyArgs::Validate() { - if (error::Error err = ObjectArgs::Validate()) return err; +minio::error::Error minio::s3::UploadPartCopyArgs::Validate() const { + if (error::Error err = ObjectArgs::Validate()) { + return err; + } if (!utils::CheckNonEmptyString(upload_id)) { return error::Error("upload ID cannot be empty"); } @@ -163,8 +193,10 @@ minio::error::Error minio::s3::UploadPartCopyArgs::Validate() { return error::SUCCESS; } -minio::error::Error minio::s3::DownloadObjectArgs::Validate() { - if (error::Error err = ObjectReadArgs::Validate()) return err; +minio::error::Error minio::s3::DownloadObjectArgs::Validate() const { + if (error::Error err = ObjectReadArgs::Validate()) { + return err; + } if (!utils::CheckNonEmptyString(filename)) { return error::Error("filename cannot be empty"); } @@ -176,9 +208,11 @@ minio::error::Error minio::s3::DownloadObjectArgs::Validate() { return error::SUCCESS; } -minio::error::Error minio::s3::GetObjectArgs::Validate() { - if (error::Error err = ObjectConditionalReadArgs::Validate()) return err; - if (datafunc == NULL) { +minio::error::Error minio::s3::GetObjectArgs::Validate() const { + if (error::Error err = ObjectConditionalReadArgs::Validate()) { + return err; + } + if (datafunc == nullptr) { return error::Error("data callback must be set"); } @@ -244,18 +278,23 @@ minio::error::Error minio::s3::PutObjectArgs::Validate() { return utils::CalcPartInfo(object_size, part_size, part_count); } -minio::error::Error minio::s3::CopyObjectArgs::Validate() { - if (error::Error err = ObjectArgs::Validate()) return err; - if (error::Error err = source.Validate()) return err; - - if (source.offset != NULL || source.length != NULL) { - if (metadata_directive != NULL && *metadata_directive == Directive::kCopy) { +minio::error::Error minio::s3::CopyObjectArgs::Validate() const { + if (error::Error err = ObjectArgs::Validate()) { + return err; + } + if (error::Error err = source.Validate()) { + return err; + } + if (source.offset != nullptr || source.length != nullptr) { + if (metadata_directive != nullptr && + *metadata_directive == Directive::kCopy) { return error::Error( "COPY metadata directive is not applicable to source object with " "range"); } - if (tagging_directive != NULL && *tagging_directive == Directive::kCopy) { + if (tagging_directive != nullptr && + *tagging_directive == Directive::kCopy) { return error::Error( "COPY tagging directive is not applicable to source object with " "range"); @@ -265,19 +304,21 @@ minio::error::Error minio::s3::CopyObjectArgs::Validate() { return error::SUCCESS; } -minio::error::Error minio::s3::ComposeSource::BuildHeaders(size_t object_size, - std::string& etag) { +minio::error::Error minio::s3::ComposeSource::BuildHeaders( + size_t object_size, const std::string& etag) { std::string msg = "source " + bucket + "/" + object; - if (!version_id.empty()) msg += "?versionId=" + version_id; + if (!version_id.empty()) { + msg += "?versionId=" + version_id; + } msg += ": "; - if (offset != NULL && *offset >= object_size) { + if (offset != nullptr && *offset >= object_size) { return error::Error(msg + "offset " + std::to_string(*offset) + " is beyond object size " + std::to_string(object_size)); } - if (length != NULL) { + if (length != nullptr) { if (*length > object_size) { return error::Error(msg + "length " + std::to_string(*length) + " is beyond object size " + @@ -285,7 +326,7 @@ minio::error::Error minio::s3::ComposeSource::BuildHeaders(size_t object_size, } size_t off = 0; - if (offset != NULL) off = *offset; + if (offset != nullptr) off = *offset; if ((off + *length) > object_size) { return error::Error( msg + "compose size " + std::to_string(off + *length) + @@ -293,7 +334,7 @@ minio::error::Error minio::s3::ComposeSource::BuildHeaders(size_t object_size, } } - object_size_ = object_size; + object_size_ = static_cast(object_size); headers_ = CopyHeaders(); if (!headers_.Contains("x-amz-copy-source-if-match")) { headers_.Add("x-amz-copy-source-if-match", etag); @@ -302,7 +343,7 @@ minio::error::Error minio::s3::ComposeSource::BuildHeaders(size_t object_size, return error::SUCCESS; } -size_t minio::s3::ComposeSource::ObjectSize() { +size_t minio::s3::ComposeSource::ObjectSize() const { if (object_size_ == -1) { std::cerr << "ABORT: ComposeSource::BuildHeaders() must be called prior to " "this method invocation. This shoud not happen." @@ -313,7 +354,7 @@ size_t minio::s3::ComposeSource::ObjectSize() { return object_size_; } -minio::utils::Multimap minio::s3::ComposeSource::Headers() { +minio::utils::Multimap minio::s3::ComposeSource::Headers() const { if (!headers_) { std::cerr << "ABORT: ComposeSource::BuildHeaders() must be called prior to " "this method invocation. This shoud not happen." @@ -324,10 +365,13 @@ minio::utils::Multimap minio::s3::ComposeSource::Headers() { return headers_; } -minio::error::Error minio::s3::ComposeObjectArgs::Validate() { - if (error::Error err = ObjectArgs::Validate()) return err; - if (sources.empty()) return error::Error("compose sources cannot be empty"); - +minio::error::Error minio::s3::ComposeObjectArgs::Validate() const { + if (error::Error err = ObjectArgs::Validate()) { + return err; + } + if (sources.empty()) { + return error::Error("compose sources cannot be empty"); + } int i = 1; for (auto& source : sources) { if (error::Error err = source.Validate()) { @@ -340,8 +384,9 @@ minio::error::Error minio::s3::ComposeObjectArgs::Validate() { } minio::error::Error minio::s3::UploadObjectArgs::Validate() { - if (error::Error err = ObjectArgs::Validate()) return err; - + if (error::Error err = ObjectArgs::Validate()) { + return err; + } if (!utils::CheckNonEmptyString(filename)) { return error::Error("filename cannot be empty"); } @@ -352,51 +397,59 @@ minio::error::Error minio::s3::UploadObjectArgs::Validate() { std::filesystem::path file_path = filename; size_t obj_size = std::filesystem::file_size(file_path); - object_size = obj_size; + object_size = static_cast(obj_size); return utils::CalcPartInfo(object_size, part_size, part_count); } -minio::error::Error minio::s3::RemoveObjectsArgs::Validate() { - if (error::Error err = BucketArgs::Validate()) return err; - if (func == NULL) { +minio::error::Error minio::s3::RemoveObjectsArgs::Validate() const { + if (error::Error err = BucketArgs::Validate()) { + return err; + } + if (func == nullptr) { return error::Error("delete object function must be set"); } return error::SUCCESS; } -minio::error::Error minio::s3::SelectObjectContentArgs::Validate() { - if (error::Error err = ObjectReadArgs::Validate()) return err; - +minio::error::Error minio::s3::SelectObjectContentArgs::Validate() const { + if (error::Error err = ObjectReadArgs::Validate()) { + return err; + } if (!utils::CheckNonEmptyString(request.expr)) { return error::Error("SQL expression must not be empty"); } - if (!((request.csv_input != NULL) ^ (request.json_input != NULL) ^ - (request.parquet_input != NULL))) { + if (!((request.csv_input != nullptr) ^ (request.json_input != nullptr) ^ + (request.parquet_input != nullptr))) { return error::Error( "One of CSV, JSON or Parquet input serialization must be set"); } - if (!((request.csv_output != NULL) ^ (request.json_output != NULL))) { + if (!((request.csv_output != nullptr) ^ (request.json_output != nullptr))) { return error::Error("One of CSV or JSON output serialization must be set"); } - if (resultfunc == NULL) return error::Error("result function must be set"); - + if (resultfunc == nullptr) { + return error::Error("result function must be set"); + } return error::SUCCESS; } -minio::error::Error minio::s3::ListenBucketNotificationArgs::Validate() { - if (error::Error err = BucketArgs::Validate()) return err; - if (func == NULL) error::Error("notification records function must be set"); - +minio::error::Error minio::s3::ListenBucketNotificationArgs::Validate() const { + if (error::Error err = BucketArgs::Validate()) { + return err; + } + if (func == nullptr) { + error::Error("notification records function must be set"); + } return error::SUCCESS; } -minio::error::Error minio::s3::SetBucketPolicyArgs::Validate() { - if (error::Error err = BucketArgs::Validate()) return err; - +minio::error::Error minio::s3::SetBucketPolicyArgs::Validate() const { + if (error::Error err = BucketArgs::Validate()) { + return err; + } if (!utils::CheckNonEmptyString(policy)) { return error::Error("bucket policy cannot be empty"); } @@ -404,9 +457,10 @@ minio::error::Error minio::s3::SetBucketPolicyArgs::Validate() { return error::SUCCESS; } -minio::error::Error minio::s3::SetBucketEncryptionArgs::Validate() { - if (error::Error err = BucketArgs::Validate()) return err; - +minio::error::Error minio::s3::SetBucketEncryptionArgs::Validate() const { + if (error::Error err = BucketArgs::Validate()) { + return err; + } if (!config) { return error::Error("bucket encryption configuration cannot be empty"); } @@ -414,16 +468,20 @@ minio::error::Error minio::s3::SetBucketEncryptionArgs::Validate() { return error::SUCCESS; } -minio::error::Error minio::s3::SetBucketVersioningArgs::Validate() { - if (error::Error err = BucketArgs::Validate()) return err; - if (!status) return error::Error("versioning status must be set"); - +minio::error::Error minio::s3::SetBucketVersioningArgs::Validate() const { + if (error::Error err = BucketArgs::Validate()) { + return err; + } + if (!status) { + return error::Error("versioning status must be set"); + } return error::SUCCESS; } -minio::error::Error minio::s3::SetBucketTagsArgs::Validate() { - if (error::Error err = BucketArgs::Validate()) return err; - +minio::error::Error minio::s3::SetBucketTagsArgs::Validate() const { + if (error::Error err = BucketArgs::Validate()) { + return err; + } if (tags.size() > 50) { return error::Error("too many bucket tags; allowed = 50, found = " + std::to_string(tags.size())); @@ -442,14 +500,17 @@ minio::error::Error minio::s3::SetBucketTagsArgs::Validate() { return error::SUCCESS; } -minio::error::Error minio::s3::SetObjectLockConfigArgs::Validate() { - if (error::Error err = BucketArgs::Validate()) return err; +minio::error::Error minio::s3::SetObjectLockConfigArgs::Validate() const { + if (error::Error err = BucketArgs::Validate()) { + return err; + } return config.Validate(); } -minio::error::Error minio::s3::SetObjectTagsArgs::Validate() { - if (error::Error err = ObjectArgs::Validate()) return err; - +minio::error::Error minio::s3::SetObjectTagsArgs::Validate() const { + if (error::Error err = ObjectArgs::Validate()) { + return err; + } if (tags.size() > 10) { return error::Error("too many object tags; allowed = 10, found = " + std::to_string(tags.size())); @@ -468,8 +529,10 @@ minio::error::Error minio::s3::SetObjectTagsArgs::Validate() { return error::SUCCESS; } -minio::error::Error minio::s3::SetObjectRetentionArgs::Validate() { - if (error::Error err = ObjectArgs::Validate()) return err; +minio::error::Error minio::s3::SetObjectRetentionArgs::Validate() const { + if (error::Error err = ObjectArgs::Validate()) { + return err; + } if (IsRetentionModeValid(retention_mode)) { return error::Error("valid retention mode must be set"); } @@ -480,8 +543,10 @@ minio::error::Error minio::s3::SetObjectRetentionArgs::Validate() { return error::SUCCESS; } -minio::error::Error minio::s3::GetPresignedObjectUrlArgs::Validate() { - if (error::Error err = ObjectArgs::Validate()) return err; +minio::error::Error minio::s3::GetPresignedObjectUrlArgs::Validate() const { + if (error::Error err = ObjectArgs::Validate()) { + return err; + } if (method < http::Method::kGet || method > http::Method::kDelete) { return error::Error("valid HTTP method must be provided"); } @@ -492,3 +557,149 @@ minio::error::Error minio::s3::GetPresignedObjectUrlArgs::Validate() { return error::SUCCESS; } + +minio::error::Error minio::s3::PostPolicy::AddEqualsCondition( + std::string element, std::string value) { + if (element.empty()) { + return error::Error("condition element cannot be empty"); + } + + element = trimDollar(element); + if (element == "success_action_redirect" || element == "redirect" || + element == "content-length-range") { + return error::Error(element + " is unsupported for equals condition"); + } + + if (isReservedElement(element)) { + return error::Error(element + " cannot be set"); + } + + conditions_[eq_][element] = std::move(value); + return error::SUCCESS; +} + +minio::error::Error minio::s3::PostPolicy::RemoveEqualsCondition( + std::string element) { + if (element.empty()) { + return error::Error("condition element cannot be empty"); + } + conditions_[eq_].erase(element); + return error::SUCCESS; +} + +minio::error::Error minio::s3::PostPolicy::AddStartsWithCondition( + std::string element, std::string value) { + if (element.empty()) { + return error::Error("condition element cannot be empty"); + } + + element = trimDollar(element); + if (element == "success_action_status" || element == "content-length-range" || + (utils::StartsWith(element, "x-amz-") && + utils::StartsWith(element, "x-amz-meta-"))) { + return error::Error(element + " is unsupported for starts-with condition"); + } + + if (isReservedElement(element)) { + return error::Error(element + " cannot be set"); + } + + conditions_[starts_with_][element] = value; + return error::SUCCESS; +} + +minio::error::Error minio::s3::PostPolicy::RemoveStartsWithCondition( + std::string element) { + if (element.empty()) { + return error::Error("condition element cannot be empty"); + } + conditions_[starts_with_].erase(element); + return error::SUCCESS; +} + +minio::error::Error minio::s3::PostPolicy::AddContentLengthRangeCondition( + size_t lower_limit, size_t upper_limit) { + if (lower_limit > upper_limit) { + return error::Error("lower limit cannot be greater than upper limit"); + } + lower_limit_ = Integer(static_cast(lower_limit)); + upper_limit_ = Integer(static_cast(upper_limit)); + return error::SUCCESS; +} + +void minio::s3::PostPolicy::RemoveContentLengthRangeCondition() { + lower_limit_ = Integer(); + upper_limit_ = Integer(); +} + +minio::error::Error minio::s3::PostPolicy::FormData( + std::map& data, std::string access_key, + std::string secret_key, std::string session_token, std::string region) { + if (region.empty()) { + return error::Error("region cannot be empty"); + } + if (conditions_[eq_]["key"].empty() && + conditions_[starts_with_]["key"].empty()) { + return error::Error("key condition must be set"); + } + + nlohmann::json policy; + policy["expiration"] = expiration_.ToISO8601UTC(); + + nlohmann::json conditions = nlohmann::json::array(); + conditions.push_back({eq_, "$bucket", bucket}); + for (auto& [cond_key, cond] : conditions_) { + for (auto& [key, value] : cond) { + conditions.push_back({cond_key, "$" + key, value}); + } + } + if (lower_limit_ && upper_limit_) { + conditions.push_back( + {"content-length-range", lower_limit_.Get(), upper_limit_.Get()}); + } + utils::Time date = utils::Time::Now(); + std::string credential = getCredentialString(access_key, date, region); + std::string amz_date = date.ToAmzDate(); + conditions.push_back({eq_, "$x-amz-algorithm", algorithm_}); + conditions.push_back({eq_, "$x-amz-credential", credential}); + if (!session_token.empty()) { + conditions.push_back({eq_, "$x-amz-security-token", session_token}); + } + conditions.push_back({eq_, "$x-amz-date", amz_date}); + policy["conditions"] = conditions; + + std::string encoded_policy = utils::Base64Encode(policy.dump()); + std::string signature = + signer::PostPresignV4(encoded_policy, secret_key, date, region); + + data["x-amz-algorithm"] = algorithm_; + data["x-amz-credential"] = credential; + data["x-amz-date"] = amz_date; + data["policy"] = encoded_policy; + data["x-amz-signature"] = signature; + if (!session_token.empty()) { + data["x-amz-security-token"] = session_token; + } + + return error::SUCCESS; +} + +std::string minio::s3::PostPolicy::trimDollar(std::string value) { + if (value.front() == '$') { + value.erase(0, 1); + } + return value; +} + +std::string minio::s3::PostPolicy::getCredentialString(std::string access_key, + utils::Time date, + std::string region) { + return access_key + "/" + date.ToSignerDate() + "/" + region + + "/s3/aws4_request"; +} + +bool minio::s3::PostPolicy::isReservedElement(std::string element) { + return element == "bucket" || element == "x-amz-algorithm" || + element == "x-amz-credential" || element == "x-amz-date" || + element == "policy" || element == "x-amz-signature"; +} diff --git a/src/baseclient.cc b/src/baseclient.cc index 7dd8cb6e..de0f5e97 100644 --- a/src/baseclient.cc +++ b/src/baseclient.cc @@ -16,8 +16,8 @@ #include "baseclient.h" minio::utils::Multimap minio::s3::GetCommonListObjectsQueryParams( - std::string& delimiter, std::string& encoding_type, unsigned int max_keys, - std::string& prefix) { + const std::string& delimiter, const std::string& encoding_type, + unsigned int max_keys, const std::string& prefix) { utils::Multimap query_params; query_params.Add("delimiter", delimiter); query_params.Add("max-keys", std::to_string(max_keys > 0 ? max_keys : 1000)); @@ -26,15 +26,13 @@ minio::utils::Multimap minio::s3::GetCommonListObjectsQueryParams( return query_params; } -minio::s3::BaseClient::BaseClient(BaseUrl& base_url, creds::Provider* provider) - : base_url_(base_url) { +minio::s3::BaseClient::BaseClient(BaseUrl base_url, creds::Provider* provider) + : base_url_(std::move(base_url)), provider_(provider) { if (!base_url_) { - std::cerr << "valid base url must be provided; " - << base_url_.Error().String() << std::endl; + std::cerr << "valid base url must be provided; " << base_url_.Error() + << std::endl; std::terminate(); } - - this->provider_ = provider; } minio::error::Error minio::s3::BaseClient::SetAppInfo( @@ -50,8 +48,8 @@ minio::error::Error minio::s3::BaseClient::SetAppInfo( void minio::s3::BaseClient::HandleRedirectResponse( std::string& code, std::string& message, int status_code, - http::Method method, utils::Multimap headers, std::string& bucket_name, - bool retry) { + http::Method method, const utils::Multimap& headers, + const std::string& bucket_name, bool retry) { switch (status_code) { case 301: code = "PermanentRedirect"; @@ -66,12 +64,12 @@ void minio::s3::BaseClient::HandleRedirectResponse( message = "Bad request"; break; default: - code = ""; - message = ""; + code.clear(); + message.clear(); break; } - std::string region = headers.GetFront("x-amz-bucket-region"); + const std::string region = headers.GetFront("x-amz-bucket-region"); if (!message.empty() && !region.empty()) { message += "; use region " + region; @@ -80,13 +78,13 @@ void minio::s3::BaseClient::HandleRedirectResponse( if (retry && !region.empty() && method == http::Method::kHead && !bucket_name.empty() && !region_map_[bucket_name].empty()) { code = "RetryHead"; - message = ""; + message.clear(); } } minio::s3::Response minio::s3::BaseClient::GetErrorResponse( http::Response resp, std::string_view resource, http::Method method, - std::string& bucket_name, std::string& object_name) { + const std::string& bucket_name, const std::string& object_name) { if (!resp.error.empty()) return error::Error(resp.error); if (!resp.body.empty()) { @@ -212,7 +210,7 @@ minio::s3::Response minio::s3::BaseClient::Execute(Request& req) { } minio::s3::GetRegionResponse minio::s3::BaseClient::GetRegion( - std::string& bucket_name, std::string& region) { + const std::string& bucket_name, const std::string& region) { std::string base_region = base_url_.region; if (!region.empty()) { if (!base_region.empty() && base_region != region) { @@ -225,7 +223,8 @@ minio::s3::GetRegionResponse minio::s3::BaseClient::GetRegion( if (!base_region.empty()) return base_region; - if (bucket_name.empty() || provider_ == NULL) return std::string("us-east-1"); + if (bucket_name.empty() || provider_ == nullptr) + return std::string("us-east-1"); std::string stored_region = region_map_[bucket_name]; if (!stored_region.empty()) return stored_region; @@ -283,7 +282,8 @@ minio::s3::BucketExistsResponse minio::s3::BaseClient::BucketExists( if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { region = resp.region; } else { - return (resp.code == "NoSuchBucket") ? false : resp; + return (resp.code == "NoSuchBucket") ? BucketExistsResponse(false) + : BucketExistsResponse(resp); } Request req(http::Method::kHead, region, base_url_, args.extra_headers, @@ -292,7 +292,8 @@ minio::s3::BucketExistsResponse minio::s3::BaseClient::BucketExists( if (Response resp = Execute(req)) { return true; } else { - return (resp.code == "NoSuchBucket") ? false : resp; + return (resp.code == "NoSuchBucket") ? BucketExistsResponse(false) + : BucketExistsResponse(resp); } } @@ -763,7 +764,7 @@ minio::s3::GetObjectResponse minio::s3::BaseClient::GetObject( GetObjectArgs args) { if (error::Error err = args.Validate()) return err; - if (args.ssec != NULL && !base_url_.https) { + if (args.ssec != nullptr && !base_url_.https) { return error::Error( "SSE-C operation must be performed over a secure connection"); } @@ -786,7 +787,7 @@ minio::s3::GetObjectResponse minio::s3::BaseClient::GetObject( req.userdata = args.userdata; req.progressfunc = args.progressfunc; req.progress_userdata = args.progress_userdata; - if (args.ssec != NULL) req.headers.AddAll(args.ssec->Headers()); + if (args.ssec != nullptr) req.headers.AddAll(args.ssec->Headers()); return Execute(req); } @@ -820,7 +821,6 @@ minio::s3::BaseClient::GetObjectLockConfig(GetObjectLockConfigArgs args) { if (!rule) return config; auto text = rule.node().select_node("DefaultRetention/Mode/text()"); - RetentionMode* mode = new RetentionMode; config.retention_mode = StringToRetentionMode(text.node().value()); if (rule.node().select_node("DefaultRetention/Days")) { @@ -927,7 +927,7 @@ minio::s3::BaseClient::GetPresignedObjectUrl(GetPresignedObjectUrlArgs args) { std::terminate(); } - if (provider_ != NULL) { + if (provider_ != nullptr) { creds::Credentials creds = provider_->Fetch(); if (!creds.session_token.empty()) { query_params.Add("X-Amz-Security-Token", creds.session_token); @@ -952,7 +952,7 @@ minio::s3::BaseClient::GetPresignedPostFormData(PostPolicy policy) { return error::Error("valid policy must be provided"); } - if (provider_ == NULL) { + if (provider_ == nullptr) { return error::Error( "Anonymous access does not require presigned post form-data"); } @@ -1322,7 +1322,7 @@ minio::s3::SelectObjectContentResponse minio::s3::BaseClient::SelectObjectContent(SelectObjectContentArgs args) { if (error::Error err = args.Validate()) return err; - if (args.ssec != NULL && !base_url_.https) { + if (args.ssec != nullptr && !base_url_.https) { return error::Error( "SSE-C operation must be performed over a secure connection"); } @@ -1668,7 +1668,7 @@ minio::s3::StatObjectResponse minio::s3::BaseClient::StatObject( StatObjectArgs args) { if (error::Error err = args.Validate()) return err; - if (args.ssec != NULL && !base_url_.https) { + if (args.ssec != nullptr && !base_url_.https) { return error::Error( "SSE-C operation must be performed over a secure connection"); } diff --git a/src/client.cc b/src/client.cc index ba765b1e..373984ee 100644 --- a/src/client.cc +++ b/src/client.cc @@ -15,16 +15,21 @@ #include "client.h" -minio::s3::ListObjectsResult::ListObjectsResult(error::Error err) { - this->failed_ = true; - this->resp_.contents.push_back(Item(err)); +minio::s3::ListObjectsResult::ListObjectsResult(error::Error err) + : failed_(true) { + this->resp_.contents.push_back(Item(std::move(err))); this->itr_ = resp_.contents.begin(); } -minio::s3::ListObjectsResult::ListObjectsResult(Client* client, - ListObjectsArgs args) { - this->client_ = client; - this->args_ = args; +minio::s3::ListObjectsResult::ListObjectsResult(Client* const client, + const ListObjectsArgs& args) + : client_(client), args_(args) { + Populate(); +} + +minio::s3::ListObjectsResult::ListObjectsResult(Client* const client, + ListObjectsArgs&& args) + : client_(client), args_(std::move(args)) { Populate(); } @@ -74,10 +79,15 @@ minio::s3::RemoveObjectsResult::RemoveObjectsResult(error::Error err) { itr_ = resp_.errors.begin(); } -minio::s3::RemoveObjectsResult::RemoveObjectsResult(Client* client, - RemoveObjectsArgs args) { - client_ = client; - args_ = args; +minio::s3::RemoveObjectsResult::RemoveObjectsResult( + Client* const client, const RemoveObjectsArgs& args) + : client_(client), args_(args) { + Populate(); +} + +minio::s3::RemoveObjectsResult::RemoveObjectsResult(Client* const client, + RemoveObjectsArgs&& args) + : client_(client), args_(args) { Populate(); } @@ -107,15 +117,15 @@ void minio::s3::RemoveObjectsResult::Populate() { } } -minio::s3::Client::Client(BaseUrl& base_url, creds::Provider* provider) +minio::s3::Client::Client(BaseUrl& base_url, creds::Provider* const provider) : BaseClient(base_url, provider) {} minio::s3::StatObjectResponse minio::s3::Client::CalculatePartCount( size_t& part_count, std::list sources) { size_t object_size = 0; - int i = 0; + size_t i = 0; for (auto& source : sources) { - if (source.ssec != NULL && !base_url_.https) { + if (source.ssec != nullptr && !base_url_.https) { std::string msg = "source " + source.bucket + "/" + source.object; if (!source.version_id.empty()) msg += "?versionId=" + source.version_id; msg += ": SSE-C operation must be performed over a secure connection"; @@ -133,9 +143,9 @@ minio::s3::StatObjectResponse minio::s3::Client::CalculatePartCount( size = resp.size; if (error::Error err = source.BuildHeaders(size, etag)) return err; - if (source.length != NULL) { + if (source.length != nullptr) { size = *source.length; - } else if (source.offset != NULL) { + } else if (source.offset != nullptr) { size -= *source.offset; } @@ -200,7 +210,7 @@ minio::s3::ComposeObjectResponse minio::s3::Client::ComposeObject( } ComposeSource& source = args.sources.front(); - if (part_count == 1 && source.offset == NULL && source.length == NULL) { + if (part_count == 1 && source.offset == nullptr && source.length == nullptr) { CopyObjectArgs coargs; coargs.extra_headers = args.extra_headers; coargs.extra_query_params = args.extra_query_params; @@ -231,7 +241,7 @@ minio::s3::ComposeObjectResponse minio::s3::Client::ComposeObject( unsigned int part_number = 0; utils::Multimap ssecheaders; - if (args.sse != NULL) { + if (args.sse != nullptr) { if (SseCustomerKey* ssec = dynamic_cast(args.sse)) { ssecheaders = ssec->Headers(); } @@ -240,14 +250,14 @@ minio::s3::ComposeObjectResponse minio::s3::Client::ComposeObject( std::list parts; for (auto& source : args.sources) { size_t size = source.ObjectSize(); - if (source.length != NULL) { + if (source.length != nullptr) { size = *source.length; - } else if (source.offset != NULL) { + } else if (source.offset != nullptr) { size -= *source.offset; } size_t offset = 0; - if (source.offset != NULL) offset = *source.offset; + if (source.offset != nullptr) offset = *source.offset; utils::Multimap headers; headers.AddAll(source.Headers()); @@ -255,11 +265,11 @@ minio::s3::ComposeObjectResponse minio::s3::Client::ComposeObject( if (size <= utils::kMaxPartSize) { part_number++; - if (source.length != NULL) { + if (source.length != nullptr) { headers.Add("x-amz-copy-source-range", "bytes=" + std::to_string(offset) + "-" + std::to_string(offset + *source.length - 1)); - } else if (source.offset != NULL) { + } else if (source.offset != nullptr) { headers.Add("x-amz-copy-source-range", "bytes=" + std::to_string(offset) + "-" + std::to_string(offset + size - 1)); @@ -316,7 +326,7 @@ minio::s3::ComposeObjectResponse minio::s3::Client::ComposeObject( } minio::s3::PutObjectResponse minio::s3::Client::PutObject( - PutObjectArgs& args, std::string& upload_id, char* buf) { + PutObjectArgs args, std::string& upload_id, char* buf) { utils::Multimap headers = args.Headers(); if (!headers.Contains("Content-Type")) { if (args.content_type.empty()) { @@ -428,7 +438,7 @@ minio::s3::PutObjectResponse minio::s3::Client::PutObject( up_args.upload_id = upload_id; up_args.part_number = part_number; up_args.data = data; - if (args.progressfunc != NULL) { + if (args.progressfunc != nullptr) { up_args.progressfunc = [&object_size = object_size, &uploaded_bytes = uploaded_bytes, &upload_speed = upload_speed, &progressfunc = args.progressfunc, @@ -444,23 +454,23 @@ minio::s3::PutObjectResponse minio::s3::Client::PutObject( } http::ProgressFunctionArgs actual_args; - actual_args.upload_total_bytes = object_size; + actual_args.upload_total_bytes = static_cast(object_size); actual_args.uploaded_bytes = uploaded_bytes + args.uploaded_bytes; actual_args.userdata = progress_userdata; progressfunc(actual_args); }; } - if (args.sse != NULL) { + if (args.sse != nullptr) { if (SseCustomerKey* ssec = dynamic_cast(args.sse)) { up_args.headers = ssec->Headers(); } } if (UploadPartResponse resp = UploadPart(up_args)) { - if (args.progressfunc != NULL) { - uploaded_bytes += data.length(); + if (args.progressfunc != nullptr) { + uploaded_bytes += static_cast(data.length()); http::ProgressFunctionArgs actual_args; - actual_args.upload_total_bytes = object_size; + actual_args.upload_total_bytes = static_cast(object_size); actual_args.uploaded_bytes = uploaded_bytes; actual_args.userdata = args.progress_userdata; args.progressfunc(actual_args); @@ -478,7 +488,7 @@ minio::s3::PutObjectResponse minio::s3::Client::PutObject( cmu_args.upload_id = upload_id; cmu_args.parts = parts; CompleteMultipartUploadResponse resp = CompleteMultipartUpload(cmu_args); - if (resp && args.progressfunc != NULL) { + if (resp && args.progressfunc != nullptr) { http::ProgressFunctionArgs actual_args; actual_args.upload_speed = upload_speed; actual_args.userdata = args.progress_userdata; @@ -491,7 +501,7 @@ minio::s3::ComposeObjectResponse minio::s3::Client::ComposeObject( ComposeObjectArgs args) { if (error::Error err = args.Validate()) return err; - if (args.sse != NULL && args.sse->TlsRequired() && !base_url_.https) { + if (args.sse != nullptr && args.sse->TlsRequired() && !base_url_.https) { return error::Error( "SSE operation must be performed over a secure connection"); } @@ -514,12 +524,12 @@ minio::s3::CopyObjectResponse minio::s3::Client::CopyObject( CopyObjectArgs args) { if (error::Error err = args.Validate()) return err; - if (args.sse != NULL && args.sse->TlsRequired() && !base_url_.https) { + if (args.sse != nullptr && args.sse->TlsRequired() && !base_url_.https) { return error::Error( "SSE operation must be performed over a secure connection"); } - if (args.source.ssec != NULL && !base_url_.https) { + if (args.source.ssec != nullptr && !base_url_.https) { return error::Error( "SSE-C operation must be performed over a secure connection"); } @@ -533,16 +543,16 @@ minio::s3::CopyObjectResponse minio::s3::Client::CopyObject( size = resp.size; } - if (args.source.offset != NULL || args.source.length != NULL || + if (args.source.offset != nullptr || args.source.length != nullptr || size > utils::kMaxPartSize) { - if (args.metadata_directive != NULL && + if (args.metadata_directive != nullptr && *args.metadata_directive == Directive::kCopy) { return error::Error( "COPY metadata directive is not applicable to source object size " "greater than 5 GiB"); } - if (args.tagging_directive != NULL && + if (args.tagging_directive != nullptr && *args.tagging_directive == Directive::kCopy) { return error::Error( "COPY tagging directive is not applicable to source object size " @@ -578,11 +588,11 @@ minio::s3::CopyObjectResponse minio::s3::Client::CopyObject( utils::Multimap headers; headers.AddAll(args.extra_headers); headers.AddAll(args.Headers()); - if (args.metadata_directive != NULL) { + if (args.metadata_directive != nullptr) { headers.Add("x-amz-metadata-directive", DirectiveToString(*args.metadata_directive)); } - if (args.tagging_directive != NULL) { + if (args.tagging_directive != nullptr) { headers.Add("x-amz-tagging-directive", DirectiveToString(*args.tagging_directive)); } @@ -615,13 +625,12 @@ minio::s3::DownloadObjectResponse minio::s3::Client::DownloadObject( DownloadObjectArgs args) { if (error::Error err = args.Validate()) return err; - if (args.ssec != NULL && !base_url_.https) { + if (args.ssec != nullptr && !base_url_.https) { return error::Error( "SSE-C operation must be performed over a secure connection"); } std::string etag; - size_t size; { StatObjectArgs soargs; soargs.bucket = args.bucket; @@ -632,7 +641,6 @@ minio::s3::DownloadObjectResponse minio::s3::Client::DownloadObject( StatObjectResponse resp = StatObject(soargs); if (!resp) return resp; etag = resp.etag; - size = resp.size; } std::string temp_filename = @@ -672,13 +680,13 @@ minio::s3::DownloadObjectResponse minio::s3::Client::DownloadObject( minio::s3::ListObjectsResult minio::s3::Client::ListObjects( ListObjectsArgs args) { if (error::Error err = args.Validate()) return err; - return ListObjectsResult(this, args); + return ListObjectsResult(this, std::move(args)); } minio::s3::PutObjectResponse minio::s3::Client::PutObject(PutObjectArgs args) { if (error::Error err = args.Validate()) return err; - if (args.sse != NULL && args.sse->TlsRequired() && !base_url_.https) { + if (args.sse != nullptr && args.sse->TlsRequired() && !base_url_.https) { return error::Error( "SSE operation must be performed over a secure connection"); } @@ -691,9 +699,9 @@ minio::s3::PutObjectResponse minio::s3::Client::PutObject(PutObjectArgs args) { if (!resp && !upload_id.empty()) { AbortMultipartUploadArgs amu_args; - amu_args.bucket = args.bucket; - amu_args.region = args.region; - amu_args.object = args.object; + amu_args.bucket = std::move(args.bucket); + amu_args.region = std::move(args.region); + amu_args.object = std::move(args.object); amu_args.upload_id = upload_id; AbortMultipartUpload(amu_args); } @@ -715,20 +723,20 @@ minio::s3::UploadObjectResponse minio::s3::Client::UploadObject( } PutObjectArgs po_args(file, args.object_size, 0); - po_args.extra_headers = args.extra_headers; - po_args.extra_query_params = args.extra_query_params; - po_args.bucket = args.bucket; - po_args.region = args.region; - po_args.object = args.object; - po_args.headers = args.headers; - po_args.user_metadata = args.user_metadata; - po_args.sse = args.sse; - po_args.tags = args.tags; - po_args.retention = args.retention; - po_args.legal_hold = args.legal_hold; - po_args.content_type = args.content_type; - - PutObjectResponse resp = PutObject(po_args); + po_args.extra_headers = std::move(args.extra_headers); + po_args.extra_query_params = std::move(args.extra_query_params); + po_args.bucket = std::move(args.bucket); + po_args.region = std::move(args.region); + po_args.object = std::move(args.object); + po_args.headers = std::move(args.headers); + po_args.user_metadata = std::move(args.user_metadata); + po_args.sse = std::move(args.sse); + po_args.tags = std::move(args.tags); + po_args.retention = std::move(args.retention); + po_args.legal_hold = std::move(args.legal_hold); + po_args.content_type = std::move(args.content_type); + + PutObjectResponse resp = PutObject(std::move(po_args)); file.close(); return resp; } @@ -736,5 +744,5 @@ minio::s3::UploadObjectResponse minio::s3::Client::UploadObject( minio::s3::RemoveObjectsResult minio::s3::Client::RemoveObjects( RemoveObjectsArgs args) { if (error::Error err = args.Validate()) return err; - return RemoveObjectsResult(this, args); + return RemoveObjectsResult(this, std::move(args)); } diff --git a/src/credentials.cc b/src/credentials.cc new file mode 100644 index 00000000..9db4fe27 --- /dev/null +++ b/src/credentials.cc @@ -0,0 +1,49 @@ +// MinIO C++ Library for Amazon S3 Compatible Cloud Storage +// Copyright 2022 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. + +#include "credentials.h" + +#include + +bool minio::creds::expired(const utils::Time& expiration) { + if (!expiration) return false; + utils::Time now = utils::Time::Now(); + now.Add(10); + return expiration < now; +} + +minio::creds::Credentials minio::creds::Credentials::ParseXML( + std::string_view data, const std::string& root) { + pugi::xml_document xdoc; + pugi::xml_parse_result result = xdoc.load_string(data.data()); + if (!result) return Credentials{error::Error("unable to parse XML")}; + + auto credentials = xdoc.select_node((root + "/Credentials").c_str()); + + auto text = credentials.node().select_node("AccessKeyId/text()"); + std::string access_key = text.node().value(); + + text = credentials.node().select_node("SecretAccessKey/text()"); + std::string secret_key = text.node().value(); + + text = credentials.node().select_node("SessionToken/text()"); + std::string session_token = text.node().value(); + + text = credentials.node().select_node("Expiration/text()"); + auto expiration = utils::Time::FromISO8601UTC(text.node().value()); + + return Credentials{error::SUCCESS, access_key, secret_key, session_token, + expiration}; +} diff --git a/src/http.cc b/src/http.cc index b6951da3..c4647dd7 100644 --- a/src/http.cc +++ b/src/http.cc @@ -17,6 +17,97 @@ #include +std::string minio::http::Url::String() const { + if (host.empty()) return {}; + + std::string url = (https ? "https://" : "http://") + host; + if (port) url += ":" + std::to_string(port); + if (!path.empty()) { + if (path.front() != '/') url += '/'; + url += path; + } + if (!query_string.empty()) url += "?" + query_string; + + return url; +} + +std::string minio::http::Url::HostHeaderValue() const { + if (!port) { + return host; + } + return host + ":" + std::to_string(port); +} + +minio::http::Url minio::http::Url::Parse(std::string value) { + std::string scheme; + size_t pos = value.find("://"); + if (pos != std::string::npos) { + scheme = value.substr(0, pos); + value.erase(0, pos + 3); + } + scheme = utils::ToLower(scheme); + + if (!scheme.empty() && scheme != "http" && scheme != "https") return Url{}; + + bool https = (scheme.empty() || scheme == "https"); + + std::string host; + std::string path; + std::string query_string; + pos = value.find("/"); + if (pos != std::string::npos) { + host = value.substr(0, pos); + value.erase(0, pos + 1); + + pos = value.find("?"); + if (pos != std::string::npos) { + path = value.substr(0, pos); + value.erase(0, pos + 1); + query_string = value; + } else { + path = value; + } + } else { + pos = value.find("?"); + if (pos != std::string::npos) { + host = value.substr(0, pos); + value.erase(0, pos + 1); + query_string = value; + } else { + host = value; + } + } + + if (host.empty()) return Url{}; + + unsigned int port = 0; + struct sockaddr_in6 dst; + if (inet_pton(AF_INET6, host.c_str(), &(dst.sin6_addr)) <= 0) { + if (host.front() != '[' || host.back() != ']') { + std::stringstream ss(host); + std::string portstr; + while (std::getline(ss, portstr, ':')) { + } + + if (!portstr.empty()) { + try { + port = std::stoi(portstr); + host = host.substr(0, host.rfind(":" + portstr)); + } catch (const std::invalid_argument&) { + port = 0; + } + } + } + } else { + host = "[" + host + "]"; + } + + if (!https && port == 80) port = 0; + if (https && port == 443) port = 0; + + return Url{https, host, port, path, query_string}; +} + minio::error::Error minio::http::Response::ReadStatusCode() { size_t pos = response_.find("\r\n"); if (pos == std::string::npos) { @@ -76,6 +167,15 @@ minio::error::Error minio::http::Response::ReadStatusCode() { return error::SUCCESS; } +minio::error::Error minio::http::Response::Error() const { + if (!error.empty()) return error::Error(error); + if (status_code && (status_code < 200 || status_code > 299)) { + return error::Error("failed with HTTP status code " + + std::to_string(status_code)); + } + return error::SUCCESS; +} + minio::error::Error minio::http::Response::ReadHeaders() { size_t pos = response_.find("\r\n\r\n"); if (pos == std::string::npos) { @@ -111,10 +211,10 @@ minio::error::Error minio::http::Response::ReadHeaders() { return error::SUCCESS; } -size_t minio::http::Response::ResponseCallback(curlpp::Multi *requests, - curlpp::Easy *request, - char *buffer, size_t size, - size_t length) { +size_t minio::http::Response::ResponseCallback(curlpp::Multi* const requests, + curlpp::Easy* const request, + const char* const buffer, + size_t size, size_t length) { size_t realsize = size * length; // If error occurred previously, just cancel the request. @@ -124,7 +224,7 @@ size_t minio::http::Response::ResponseCallback(curlpp::Multi *requests, } if (!status_code_read_ || !headers_read_) { - response_ += std::string(buffer, length); + response_.append(buffer, length); } if (!status_code_read_) { @@ -147,7 +247,7 @@ size_t minio::http::Response::ResponseCallback(curlpp::Multi *requests, if (!headers_read_ || response_.empty()) return realsize; // If data function is set and the request is successful, send data. - if (datafunc != NULL && status_code >= 200 && status_code <= 299) { + if (datafunc != nullptr && status_code >= 200 && status_code <= 299) { DataFunctionArgs args{request, this, response_, userdata}; if (!datafunc(args)) requests->remove(request); } else { @@ -158,11 +258,11 @@ size_t minio::http::Response::ResponseCallback(curlpp::Multi *requests, } // If data function is set and the request is successful, send data. - if (datafunc != NULL && status_code >= 200 && status_code <= 299) { + if (datafunc != nullptr && status_code >= 200 && status_code <= 299) { DataFunctionArgs args{request, this, std::string(buffer, length), userdata}; if (!datafunc(args)) requests->remove(request); } else { - body += std::string(buffer, length); + body.append(buffer, length); } return realsize; @@ -206,7 +306,7 @@ minio::http::Response minio::http::Request::execute() { } } - utils::CharBuffer charbuf((char *)body.data(), body.size()); + utils::CharBuffer charbuf((char*)body.data(), body.size()); std::istream body_stream(&charbuf); switch (method) { @@ -222,7 +322,8 @@ minio::http::Response minio::http::Request::execute() { headers.Add("Content-Length", std::to_string(body.size())); } request.setOpt(new curlpp::Options::ReadStream(&body_stream)); - request.setOpt(new curlpp::Options::InfileSize(body.size())); + request.setOpt( + new curlpp::Options::InfileSize(static_cast(body.size()))); request.setOpt(new curlpp::Options::Upload(true)); break; } @@ -255,7 +356,7 @@ minio::http::Response minio::http::Request::execute() { progressfunc(args); return CURL_PROGRESSFUNC_CONTINUE; }; - if (progressfunc != NULL) { + if (progressfunc != nullptr) { request.setOpt(new curlpp::options::NoProgress(false)); request.setOpt(new curlpp::options::ProgressFunction(progress)); } @@ -278,7 +379,7 @@ minio::http::Response minio::http::Request::execute() { requests.fdset(&fdread, &fdwrite, &fdexcep, &maxfd); - if (select(maxfd + 1, &fdread, &fdwrite, &fdexcep, NULL) < 0) { + if (select(maxfd + 1, &fdread, &fdwrite, &fdexcep, nullptr) < 0) { std::cerr << "select() failed; this should not happen" << std::endl; std::terminate(); } @@ -286,7 +387,7 @@ minio::http::Response minio::http::Request::execute() { } } - if (progressfunc != NULL) { + if (progressfunc != nullptr) { ProgressFunctionArgs args; args.userdata = progress_userdata; curlpp::infos::SpeedUpload::get(request, args.upload_speed); @@ -297,16 +398,14 @@ minio::http::Response minio::http::Request::execute() { return response; } -minio::http::Response minio::http::Request::Execute() { - try { - return execute(); - } catch (curlpp::LogicError &e) { - Response response; - response.error = std::string("curlpp::LogicError: ") + e.what(); - return response; - } catch (curlpp::RuntimeError &e) { - Response response; - response.error = std::string("curlpp::RuntimeError: ") + e.what(); - return response; - } +minio::http::Response minio::http::Request::Execute() try { + return execute(); +} catch (curlpp::LogicError& e) { + Response response; + response.error = std::string("curlpp::LogicError: ") + e.what(); + return response; +} catch (curlpp::RuntimeError& e) { + Response response; + response.error = std::string("curlpp::RuntimeError: ") + e.what(); + return response; } diff --git a/src/providers.cc b/src/providers.cc new file mode 100644 index 00000000..32fb8a85 --- /dev/null +++ b/src/providers.cc @@ -0,0 +1,536 @@ +// MinIO C++ Library for Amazon S3 Compatible Cloud Storage +// Copyright 2022 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. + +#ifdef _WIN32 +#define _WINSOCK_DEPRECATED_NO_WARNINGS +#endif + +#include "providers.h" + +#include + +#include +#include + +#include "signer.h" +#include "utils.h" + +#ifndef _WIN32 +#include +#include +#include +#endif + +minio::error::Error minio::creds::checkLoopbackHost(const std::string& host) { + struct addrinfo hints = {}; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + int status; + struct addrinfo* res = nullptr; + if ((status = getaddrinfo(host.c_str(), nullptr, &hints, &res)) != 0) { + return error::Error(std::string("getaddrinfo: ") + gai_strerror(status)); + } + + for (struct addrinfo* ai = res; ai != nullptr; ai = ai->ai_next) { + std::string ip(inet_ntoa(((struct sockaddr_in*)ai->ai_addr)->sin_addr)); + if (!utils::StartsWith(ip, "127.")) { + return error::Error(host + " is not loopback only host"); + } + } + + freeaddrinfo(res); // free the linked list + + return error::SUCCESS; +} + +minio::creds::Provider::~Provider() {} + +minio::creds::ChainedProvider::~ChainedProvider() {} + +minio::creds::Credentials minio::creds::ChainedProvider::Fetch() { + if (err_) return Credentials{err_}; + + if (creds_) return creds_; + + if (provider_ != nullptr) { + creds_ = provider_->Fetch(); + if (creds_) return creds_; + } + + for (auto provider : providers_) { + provider_ = provider; + creds_ = provider_->Fetch(); + if (creds_) return creds_; + } + + return Credentials{error::Error("All providers fail to fetch credentials")}; +} + +minio::creds::StaticProvider::StaticProvider(std::string access_key, + std::string secret_key, + std::string session_token) { + this->creds_ = Credentials{error::SUCCESS, std::move(access_key), + std::move(secret_key), std::move(session_token)}; +} + +minio::creds::StaticProvider::~StaticProvider() {} + +minio::creds::Credentials minio::creds::StaticProvider::Fetch() { + return creds_; +} + +minio::creds::EnvAwsProvider::EnvAwsProvider() { + std::string access_key; + std::string secret_key; + std::string session_token; + + if (!utils::GetEnv(access_key, "AWS_ACCESS_KEY_ID")) { + utils::GetEnv(access_key, "AWS_ACCESS_KEY"); + } + if (!utils::GetEnv(secret_key, "AWS_SECRET_ACCESS_KEY")) { + utils::GetEnv(secret_key, "AWS_SECRET_KEY"); + } + utils::GetEnv(session_token, "AWS_SESSION_TOKEN"); + + this->creds_ = + Credentials{error::SUCCESS, access_key, secret_key, session_token}; +} + +minio::creds::EnvAwsProvider::~EnvAwsProvider() {} + +minio::creds::Credentials minio::creds::EnvAwsProvider::Fetch() { + return creds_; +} + +minio::creds::EnvMinioProvider::EnvMinioProvider() { + std::string access_key; + std::string secret_key; + + utils::GetEnv(access_key, "MINIO_ACCESS_KEY"); + utils::GetEnv(secret_key, "MINIO_SECRET_KEY"); + this->creds_ = Credentials{error::SUCCESS, access_key, secret_key}; +} + +minio::creds::EnvMinioProvider::~EnvMinioProvider() {} + +minio::creds::Credentials minio::creds::EnvMinioProvider::Fetch() { + return creds_; +} + +minio::creds::AwsConfigProvider::AwsConfigProvider(std::string filename, + std::string profile) { + if (filename.empty()) { + if (!utils::GetEnv(filename, "AWS_SHARED_CREDENTIALS_FILE")) { + filename = utils::GetHomeDir() + "/aws/credentials"; + } + } + + if (profile.empty()) { + if (!utils::GetEnv(profile, "AWS_PROFILE")) profile = "default"; + } + + INIReader reader(filename); + if (reader.ParseError() < 0) { + this->creds_ = Credentials{error::Error("unable to read " + filename)}; + } else { + this->creds_ = Credentials{error::SUCCESS, + reader.Get(profile, "aws_access_key_id", ""), + reader.Get(profile, "aws_secret_access_key", ""), + reader.Get(profile, "aws_session_token", "")}; + } +} + +minio::creds::AwsConfigProvider::~AwsConfigProvider() {} + +minio::creds::Credentials minio::creds::AwsConfigProvider::Fetch() { + return creds_; +} + +minio::creds::MinioClientConfigProvider::MinioClientConfigProvider( + std::string filename, std::string alias) { + if (filename.empty()) filename = utils::GetHomeDir() + "/.mc/config.json"; + + if (alias.empty()) { + if (!utils::GetEnv(alias, "MINIO_ALIAS")) alias = "s3"; + } + + std::ifstream ifs(filename); + nlohmann::json json = nlohmann::json::parse(ifs); + ifs.close(); + + nlohmann::json aliases; + if (json.contains("hosts")) { + aliases = json["hosts"]; + } else if (json.contains("aliases")) { + aliases = json["aliases"]; + } else { + this->creds_ = + Credentials{error::Error("invalid configuration in file " + filename)}; + return; + } + + if (!aliases.contains(alias)) { + this->creds_ = Credentials{error::Error( + "alias " + alias + " not found in MinIO client configuration file " + + filename)}; + return; + } + + this->creds_ = Credentials{error::SUCCESS, aliases[alias]["accessKey"], + aliases[alias]["secretKey"]}; +} + +minio::creds::MinioClientConfigProvider::~MinioClientConfigProvider() {} + +minio::creds::Credentials minio::creds::MinioClientConfigProvider::Fetch() { + return creds_; +} + +minio::creds::AssumeRoleProvider::AssumeRoleProvider( + http::Url sts_endpoint, std::string access_key, std::string secret_key, + unsigned int duration_seconds, std::string policy, std::string region, + std::string role_arn, std::string role_session_name, + std::string external_id) { + this->sts_endpoint_ = sts_endpoint; + this->access_key_ = access_key; + this->secret_key_ = secret_key; + this->region_ = region; + + if (duration_seconds < DEFAULT_DURATION_SECONDS) { + duration_seconds = DEFAULT_DURATION_SECONDS; + } + + utils::Multimap map; + map.Add("Action", "AssumeRole"); + map.Add("Version", "2011-06-15"); + map.Add("DurationSeconds", std::to_string(duration_seconds)); + if (!role_arn.empty()) map.Add("RoleArn", role_arn); + if (!role_session_name.empty()) { + map.Add("RoleSessionName", role_session_name); + } + if (!policy.empty()) map.Add("Policy", policy); + if (!external_id.empty()) map.Add("ExternalId", external_id); + + this->body_ = map.ToQueryString(); + this->content_sha256_ = utils::Sha256Hash(body_); +} + +minio::creds::AssumeRoleProvider::~AssumeRoleProvider() {} + +minio::creds::Credentials minio::creds::AssumeRoleProvider::Fetch() { + if (err_) return Credentials{err_}; + + if (creds_) return creds_; + + utils::Time date = utils::Time::Now(); + utils::Multimap headers; + headers.Add("Content-Type", "application/x-www-form-urlencoded"); + headers.Add("Host", sts_endpoint_.host); + headers.Add("X-Amz-Date", date.ToAmzDate()); + + http::Method method = http::Method::kPost; + signer::SignV4STS(method, sts_endpoint_.path, region_, headers, + utils::Multimap(), access_key_, secret_key_, + content_sha256_, date); + + http::Request req(method, sts_endpoint_); + req.headers = headers; + req.body = body_; + http::Response resp = req.Execute(); + if (!resp) { + creds_ = Credentials{resp.Error()}; + } else { + creds_ = Credentials::ParseXML(resp.body, "AssumeRoleResult"); + } + + return creds_; +} + +minio::creds::WebIdentityClientGrantsProvider::WebIdentityClientGrantsProvider( + JwtFunction jwtfunc, http::Url sts_endpoint, unsigned int duration_seconds, + std::string policy, std::string role_arn, std::string role_session_name) { + this->jwtfunc_ = jwtfunc; + this->sts_endpoint_ = sts_endpoint; + this->duration_seconds_ = duration_seconds; + this->policy_ = policy; + this->role_arn_ = role_arn; + this->role_session_name_ = role_session_name; +} + +minio::creds::WebIdentityClientGrantsProvider:: + ~WebIdentityClientGrantsProvider() {} + +unsigned int minio::creds::WebIdentityClientGrantsProvider::getDurationSeconds( + unsigned int expiry) const { + if (duration_seconds_) expiry = duration_seconds_; + if (expiry > MAX_DURATION_SECONDS) return MAX_DURATION_SECONDS; + if (expiry == 0) return expiry; + if (expiry < MIN_DURATION_SECONDS) return MIN_DURATION_SECONDS; + return expiry; +} + +minio::creds::Credentials +minio::creds::WebIdentityClientGrantsProvider::Fetch() { + if (creds_) return creds_; + + Jwt jwt = jwtfunc_(); + + utils::Multimap map; + map.Add("Version", "2011-06-15"); + unsigned int duration_seconds = getDurationSeconds(jwt.expiry); + if (duration_seconds) { + map.Add("DurationSeconds", std::to_string(duration_seconds)); + } + if (!policy_.empty()) map.Add("Policy", policy_); + + if (IsWebIdentity()) { + map.Add("Action", "AssumeRoleWithWebIdentity"); + map.Add("WebIdentityToken", jwt.token); + if (!role_arn_.empty()) { + map.Add("RoleArn", role_arn_); + if (!role_session_name_.empty()) { + map.Add("RoleSessionName", role_session_name_); + } else { + map.Add("RoleSessionName", utils::Time::Now().ToISO8601UTC()); + } + } + } else { + map.Add("Action", "AssumeRoleWithClientGrants"); + map.Add("Token", jwt.token); + } + + http::Url url = sts_endpoint_; + url.query_string = map.ToQueryString(); + http::Request req(http::Method::kPost, url); + http::Response resp = req.Execute(); + if (!resp) { + creds_ = Credentials{resp.Error()}; + } else { + creds_ = Credentials::ParseXML( + resp.body, IsWebIdentity() ? "AssumeRoleWithWebIdentityResult" + : "AssumeRoleWithClientGrantsResult"); + } + return creds_; +} + +minio::creds::ClientGrantsProvider::ClientGrantsProvider( + JwtFunction jwtfunc, http::Url sts_endpoint, unsigned int duration_seconds, + std::string policy, std::string role_arn, std::string role_session_name) + : WebIdentityClientGrantsProvider(jwtfunc, sts_endpoint, duration_seconds, + policy, role_arn, role_session_name) {} + +minio::creds::ClientGrantsProvider::~ClientGrantsProvider() {} + +bool minio::creds::ClientGrantsProvider::IsWebIdentity() const { return false; } + +minio::creds::WebIdentityProvider::WebIdentityProvider( + JwtFunction jwtfunc, http::Url sts_endpoint, unsigned int duration_seconds, + std::string policy, std::string role_arn, std::string role_session_name) + : WebIdentityClientGrantsProvider(jwtfunc, sts_endpoint, duration_seconds, + policy, role_arn, role_session_name) {} + +minio::creds::WebIdentityProvider::~WebIdentityProvider() {} + +bool minio::creds::WebIdentityProvider::IsWebIdentity() const { return true; } + +minio::creds::IamAwsProvider::IamAwsProvider(http::Url custom_endpoint) { + this->custom_endpoint_ = custom_endpoint; + utils::GetEnv(this->token_file_, "AWS_WEB_IDENTITY_TOKEN_FILE"); + utils::GetEnv(this->aws_region_, "AWS_REGION"); + utils::GetEnv(this->role_arn_, "AWS_ROLE_ARN"); + utils::GetEnv(this->role_session_name_, "AWS_ROLE_SESSION_NAME"); + utils::GetEnv(this->relative_uri_, "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"); + if (!this->relative_uri_.empty() && this->relative_uri_.front() != '/') { + this->relative_uri_ = "/" + this->relative_uri_; + } + utils::GetEnv(this->full_uri_, "AWS_CONTAINER_CREDENTIALS_FULL_URI"); +} + +minio::creds::IamAwsProvider::~IamAwsProvider() {} + +minio::creds::Credentials minio::creds::IamAwsProvider::Fetch() { + if (creds_) return creds_; + + http::Url url = custom_endpoint_; + if (!token_file_.empty()) { + if (!url) { + url.https = true; + url.host = "sts.amazonaws.com"; + if (!aws_region_.empty()) { + url.host = "sts." + aws_region_ + ".amazonaws.com"; + } + } + + WebIdentityProvider provider = WebIdentityProvider( + [&token_file = token_file_]() -> Jwt { + std::ifstream ifs(token_file); + nlohmann::json json = nlohmann::json::parse(ifs); + ifs.close(); + return Jwt{json["access_token"], json["expires_in"]}; + }, + url, 0, "", role_arn_, role_session_name_); + creds_ = provider.Fetch(); + return creds_; + } + + if (!relative_uri_.empty()) { + if (!url) { + url.https = true; + url.host = "169.254.170.2"; + url.path = relative_uri_; + } + } else if (!full_uri_.empty()) { + if (!url) url = http::Url::Parse(full_uri_); + if (error::Error err = checkLoopbackHost(url.host)) { + creds_ = Credentials{err}; + return creds_; + } + } else { + if (!url) { + url.https = true; + url.host = "169.254.169.254"; + url.path = "/latest/meta-data/iam/security-credentials/"; + } + + std::string role_name; + if (error::Error err = getRoleName(role_name, url)) { + creds_ = Credentials{err}; + return creds_; + } + + url.path += "/" + role_name; + } + + creds_ = fetch(url); + return creds_; +} + +minio::creds::Credentials minio::creds::IamAwsProvider::fetch(http::Url url) { + http::Request req(http::Method::kGet, url); + http::Response resp = req.Execute(); + if (!resp) return Credentials{resp.Error()}; + + nlohmann::json json = nlohmann::json::parse(resp.body); + std::string code = json.value("Code", "Success"); + if (code != "Success") { + return Credentials{error::Error(url.String() + " failed with code " + code + + " and message " + + json.value("Message", ""))}; + } + + std::string expiration = json["Expiration"]; + return Credentials{error::SUCCESS, json["AccessKeyId"], + json["SecretAccessKey"], json["Token"], + utils::Time::FromISO8601UTC(expiration.c_str())}; +} + +minio::error::Error minio::creds::IamAwsProvider::getRoleName( + std::string& role_name, http::Url url) const { + http::Request req(http::Method::kGet, url); + http::Response resp = req.Execute(); + if (!resp) return resp.Error(); + + std::list role_names; + std::string lines = resp.body; + size_t pos; + while ((pos = lines.find("\n")) != std::string::npos) { + role_names.push_back(lines.substr(0, pos)); + lines.erase(0, pos + 1); + } + if (!lines.empty()) role_names.push_back(lines); + + if (role_names.empty()) { + return error::Error(std::string("no IAM roles attached to EC2 service ") + + url.String()); + } + + role_name = utils::Trim(role_names.front(), '\r'); + return error::SUCCESS; +} + +minio::creds::LdapIdentityProvider::LdapIdentityProvider( + http::Url sts_endpoint, std::string ldap_username, + std::string ldap_password) { + this->sts_endpoint_ = sts_endpoint; + utils::Multimap map; + map.Add("Action", "AssumeRoleWithLDAPIdentity"); + map.Add("Version", "2011-06-15"); + map.Add("LDAPUsername", ldap_username); + map.Add("LDAPPassword", ldap_password); + this->sts_endpoint_.query_string = map.ToQueryString(); +} + +minio::creds::LdapIdentityProvider::~LdapIdentityProvider() {} + +minio::creds::Credentials minio::creds::LdapIdentityProvider::Fetch() { + if (creds_) return creds_; + + http::Request req(http::Method::kPost, sts_endpoint_); + http::Response resp = req.Execute(); + if (!resp) return Credentials{resp.Error()}; + + creds_ = Credentials::ParseXML(resp.body, "AssumeRoleWithLDAPIdentityResult"); + return creds_; +} + +minio::creds::CertificateIdentityProvider::CertificateIdentityProvider( + http::Url sts_endpoint, std::string key_file, std::string cert_file, + std::string ssl_cert_file, unsigned int duration_seconds) { + if (!sts_endpoint.https) { + this->err_ = error::Error("sts endpoint scheme must be HTTPS"); + return; + } + + if (key_file.empty() || cert_file.empty()) { + this->err_ = error::Error("client key and certificate must be provided"); + return; + } + + unsigned int expiry = duration_seconds; + if (duration_seconds < DEFAULT_DURATION_SECONDS) { + expiry = DEFAULT_DURATION_SECONDS; + } + + utils::Multimap map; + map.Add("Action", "AssumeRoleWithCertificate"); + map.Add("Version", "2011-06-15"); + map.Add("DurationSeconds", std::to_string(expiry)); + + sts_endpoint_ = sts_endpoint; + sts_endpoint_.query_string = map.ToQueryString(); + key_file_ = key_file; + cert_file_ = cert_file; + ssl_cert_file_ = ssl_cert_file; +} + +minio::creds::CertificateIdentityProvider::~CertificateIdentityProvider() {} + +minio::creds::Credentials minio::creds::CertificateIdentityProvider::Fetch() { + if (err_) return Credentials{err_}; + + if (creds_) return creds_; + + http::Request req(http::Method::kPost, sts_endpoint_); + req.ssl_cert_file = ssl_cert_file_; + req.key_file = key_file_; + req.cert_file = cert_file_; + + http::Response resp = req.Execute(); + if (!resp) return Credentials{resp.Error()}; + + creds_ = Credentials::ParseXML(resp.body, "AssumeRoleWithCertificateResult"); + return creds_; +} diff --git a/src/request.cc b/src/request.cc index adb71886..704f411b 100644 --- a/src/request.cc +++ b/src/request.cc @@ -18,7 +18,7 @@ #define EMPTY_SHA256 \ "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" -bool minio::s3::awsRegexMatch(std::string_view value, std::regex regex) { +bool minio::s3::awsRegexMatch(std::string_view value, const std::regex& regex) { if (!std::regex_search(value.data(), regex)) return false; std::stringstream str_stream(value.data()); @@ -30,7 +30,7 @@ bool minio::s3::awsRegexMatch(std::string_view value, std::regex regex) { return true; } -minio::error::Error minio::s3::getAwsInfo(std::string host, bool https, +minio::error::Error minio::s3::getAwsInfo(const std::string& host, bool https, std::string& region, std::string& aws_s3_prefix, std::string& aws_domain_suffix, @@ -89,25 +89,41 @@ minio::error::Error minio::s3::getAwsInfo(std::string host, bool https, return error::SUCCESS; } -minio::s3::BaseUrl::BaseUrl(std::string host, bool https, std::string region) { - http::Url url = http::Url::Parse(host); +std::string minio::s3::extractRegion(const std::string& host) { + std::stringstream str_stream(host); + std::string token; + std::vector tokens; + while (std::getline(str_stream, token, '.')) tokens.push_back(token); + + token = tokens[1]; + + // If token is "dualstack", then region might be in next token. + if (token == "dualstack") token = tokens[2]; + + // If token is equal to "amazonaws", region is not passed in the host. + if (token == "amazonaws") return {}; + + // Return token as region. + return token; +} + +minio::s3::BaseUrl::BaseUrl(std::string host, bool https, std::string region) + : https(https), region(std::move(region)) { + const http::Url url = http::Url::Parse(host); if (!url.path.empty() || !url.query_string.empty()) { this->err_ = error::Error( "host value must contain only hostname and optional port number"); return; } - this->https = https; this->host = url.host; this->port = url.port; - if (!region.empty() && !awsRegexMatch(region, REGION_REGEX)) { - this->err_ = error::Error("invalid region " + region); + if (!this->region.empty() && !awsRegexMatch(this->region, REGION_REGEX)) { + this->err_ = error::Error("invalid region " + this->region); return; } - this->region = region; - if (error::Error err = getAwsInfo(this->host, this->https, this->region, this->aws_s3_prefix, this->aws_domain_suffix, this->dualstack)) { @@ -118,10 +134,9 @@ minio::s3::BaseUrl::BaseUrl(std::string host, bool https, std::string region) { utils::EndsWith(this->host, "aliyuncs.com"); } -minio::error::Error minio::s3::BaseUrl::BuildAwsUrl(http::Url& url, - std::string bucket_name, - bool enforce_path_style, - std::string region) { +minio::error::Error minio::s3::BaseUrl::BuildAwsUrl( + http::Url& url, const std::string& bucket_name, bool enforce_path_style, + const std::string& region) { std::string host = this->aws_s3_prefix + this->aws_domain_suffix; if (host == "s3-external-1.amazonaws.com" || host == "s3-us-gov-west-1.amazonaws.com" || @@ -152,7 +167,7 @@ minio::error::Error minio::s3::BaseUrl::BuildAwsUrl(http::Url& url, } void minio::s3::BaseUrl::BuildListBucketsUrl(http::Url& url, - std::string region) { + const std::string& region) { if (this->aws_domain_suffix.empty()) return; std::string host = this->aws_s3_prefix + this->aws_domain_suffix; @@ -174,12 +189,10 @@ void minio::s3::BaseUrl::BuildListBucketsUrl(http::Url& url, url.host = s3_prefix + region + "." + domain_suffix; } -minio::error::Error minio::s3::BaseUrl::BuildUrl(http::Url& url, - http::Method method, - std::string region, - utils::Multimap query_params, - std::string bucket_name, - std::string object_name) { +minio::error::Error minio::s3::BaseUrl::BuildUrl( + http::Url& url, http::Method method, const std::string& region, + const utils::Multimap& query_params, const std::string& bucket_name, + const std::string& object_name) { if (err_) return err_; if (bucket_name.empty() && !object_name.empty()) { @@ -234,15 +247,14 @@ minio::error::Error minio::s3::BaseUrl::BuildUrl(http::Url& url, minio::s3::Request::Request(http::Method method, std::string region, BaseUrl& baseurl, utils::Multimap extra_headers, utils::Multimap extra_query_params) - : base_url(baseurl) { - this->method = method; - this->region = region; - this->headers = extra_headers; - this->query_params = extra_query_params; -} + : method(method), + region(std::move(region)), + base_url(baseurl), + headers(std::move(extra_headers)), + query_params(std::move(extra_query_params)) {} void minio::s3::Request::BuildHeaders(http::Url& url, - creds::Provider* provider) { + creds::Provider* const provider) { headers.Add("Host", url.HostHeaderValue()); headers.Add("User-Agent", user_agent); @@ -256,14 +268,14 @@ void minio::s3::Request::BuildHeaders(http::Url& url, if (!headers.Contains("Content-Type")) { headers.Add("Content-Type", "application/octet-stream"); } - if (provider != NULL) { + if (provider != nullptr) { sha256 = utils::Sha256Hash(body); } else if (!md5sum_added) { md5sum = utils::Md5sumHash(body); } break; default: - if (provider != NULL) sha256 = EMPTY_SHA256; + if (provider != nullptr) sha256 = EMPTY_SHA256; } if (!md5sum.empty()) headers.Add("Content-MD5", md5sum); @@ -272,7 +284,7 @@ void minio::s3::Request::BuildHeaders(http::Url& url, date = utils::Time::Now(); headers.Add("x-amz-date", date.ToAmzDate()); - if (provider != NULL) { + if (provider != nullptr) { creds::Credentials creds = provider->Fetch(); if (!creds.session_token.empty()) { headers.Add("X-Amz-Security-Token", creds.session_token); @@ -284,7 +296,7 @@ void minio::s3::Request::BuildHeaders(http::Url& url, } minio::http::Request minio::s3::Request::ToHttpRequest( - creds::Provider* provider) { + creds::Provider* const provider) { http::Url url; if (error::Error err = base_url.BuildUrl(url, method, region, query_params, bucket_name, object_name)) { diff --git a/src/response.cc b/src/response.cc index 821d83f7..5cf1295b 100644 --- a/src/response.cc +++ b/src/response.cc @@ -15,6 +15,20 @@ #include "response.h" +minio::s3::Response::Response() {} + +minio::s3::Response::~Response() {} + +minio::error::Error minio::s3::Response::Error() const { + if (err_) return err_; + if (!code.empty()) return error::Error(code + ": " + message); + if (status_code && (status_code < 200 || status_code > 299)) { + return error::Error("failed with HTTP status code " + + std::to_string(status_code)); + } + return error::SUCCESS; +} + minio::s3::Response minio::s3::Response::ParseXML(std::string_view data, int status_code, utils::Multimap headers) { @@ -552,6 +566,7 @@ minio::s3::GetBucketReplicationResponse::ParseXML(std::string_view data) { if (filter.node().select_node("And/Tag")) { auto tags = root.node().select_nodes("And/Tag"); for (auto& tag : tags) { + (void)tag; text = filter.node().select_node("Key/text()"); std::string key = text.node().value(); @@ -668,6 +683,7 @@ minio::s3::GetBucketLifecycleResponse::ParseXML(std::string_view data) { if (filter.node().select_node("And/Tag")) { auto tags = root.node().select_nodes("And/Tag"); for (auto& tag : tags) { + (void)tag; text = filter.node().select_node("Key/text()"); std::string key = text.node().value(); diff --git a/src/select.cc b/src/select.cc index 8e5f74e1..40d3f219 100644 --- a/src/select.cc +++ b/src/select.cc @@ -16,16 +16,16 @@ #include "select.h" void minio::s3::SelectHandler::Reset() { - prelude_ = ""; + prelude_.clear(); prelude_read_ = false; - prelude_crc_ = ""; + prelude_crc_.clear(); prelude_crc_read_ = false; - data_ = ""; + data_.clear(); data_read_ = false; - message_crc_ = ""; + message_crc_.clear(); message_crc_read_ = false; } @@ -95,7 +95,7 @@ minio::error::Error minio::s3::SelectHandler::DecodeHeader( return error::SUCCESS; } -bool minio::s3::SelectHandler::process(http::DataFunctionArgs args, +bool minio::s3::SelectHandler::process(const http::DataFunctionArgs& /* args */, bool& cont) { if (!prelude_read_ && !ReadPrelude()) return true; @@ -154,7 +154,7 @@ bool minio::s3::SelectHandler::process(http::DataFunctionArgs args, return false; } - long payload_length = total_length_ - header_length - 16; + long payload_length = static_cast(total_length_ - header_length - 16); if (headers[":event-type"] == "Cont" || payload_length < 1) { Reset(); return true; @@ -213,7 +213,8 @@ bool minio::s3::SelectHandler::process(http::DataFunctionArgs args, return false; } -bool minio::s3::SelectHandler::DataFunction(http::DataFunctionArgs args) { +bool minio::s3::SelectHandler::DataFunction( + const http::DataFunctionArgs& args) { if (done_) return false; response_ += args.datachunk; diff --git a/src/signer.cc b/src/signer.cc index 96ddde58..36d442ff 100644 --- a/src/signer.cc +++ b/src/signer.cc @@ -17,16 +17,17 @@ const char* SIGN_V4_ALGORITHM = "AWS4-HMAC-SHA256"; -std::string minio::signer::GetScope(utils::Time& time, std::string& region, - std::string& service_name) { +std::string minio::signer::GetScope(const utils::Time& time, + const std::string& region, + const std::string& service_name) { return time.ToSignerDate() + "/" + region + "/" + service_name + "/aws4_request"; } std::string minio::signer::GetCanonicalRequestHash( - std::string& method, std::string& uri, std::string& query_string, - std::string& headers, std::string& signed_headers, - std::string& content_sha256) { + const std::string& method, const std::string& uri, + const std::string& query_string, const std::string& headers, + const std::string& signed_headers, const std::string& content_sha256) { // CanonicalRequest = // HTTPRequestMethod + '\n' + // CanonicalURI + '\n' + @@ -41,8 +42,8 @@ std::string minio::signer::GetCanonicalRequestHash( } std::string minio::signer::GetStringToSign( - utils::Time& date, std::string& scope, - std::string& canonical_request_hash) { + const utils::Time& date, const std::string& scope, + const std::string& canonical_request_hash) { return "AWS4-HMAC-SHA256\n" + date.ToAmzDate() + "\n" + scope + "\n" + canonical_request_hash; } @@ -59,8 +60,8 @@ std::string minio::signer::HmacHash(std::string_view key, return std::string{reinterpret_cast(hash.data()), hash_len}; } -std::string minio::signer::GetSigningKey(std::string& secret_key, - utils::Time& date, +std::string minio::signer::GetSigningKey(const std::string& secret_key, + const utils::Time& date, std::string_view region, std::string_view service_name) { std::string date_key = HmacHash("AWS4" + secret_key, date.ToSignerDate()); @@ -74,26 +75,27 @@ std::string minio::signer::GetSignature(std::string_view signing_key, std::string hash = HmacHash(signing_key, string_to_sign); std::string signature; char buf[3]; - for (int i = 0; i < hash.size(); ++i) { + for (std::size_t i = 0, n_size = hash.size(); i < n_size; ++i) { snprintf(buf, 3, "%02x", (unsigned char)hash[i]); signature += buf; } return signature; } -std::string minio::signer::GetAuthorization(std::string& access_key, - std::string& scope, - std::string& signed_headers, - std::string& signature) { +std::string minio::signer::GetAuthorization(const std::string& access_key, + const std::string& scope, + const std::string& signed_headers, + const std::string& signature) { return "AWS4-HMAC-SHA256 Credential=" + access_key + "/" + scope + ", " + "SignedHeaders=" + signed_headers + ", " + "Signature=" + signature; } -minio::utils::Multimap& minio::signer::SignV4( - std::string& service_name, http::Method& method, std::string& uri, - std::string& region, utils::Multimap& headers, - utils::Multimap& query_params, std::string& access_key, - std::string& secret_key, std::string& content_sha256, utils::Time& date) { +minio::utils::Multimap minio::signer::SignV4( + const std::string& service_name, http::Method method, + const std::string& uri, const std::string& region, utils::Multimap& headers, + utils::Multimap query_params, const std::string& access_key, + const std::string& secret_key, const std::string& content_sha256, + const utils::Time& date) { std::string scope = GetScope(date, region, service_name); std::string signed_headers; @@ -122,30 +124,33 @@ minio::utils::Multimap& minio::signer::SignV4( return headers; } -minio::utils::Multimap& minio::signer::SignV4S3( - http::Method method, std::string& uri, std::string& region, +minio::utils::Multimap minio::signer::SignV4S3( + http::Method method, const std::string& uri, const std::string& region, utils::Multimap& headers, utils::Multimap query_params, - std::string& access_key, std::string& secret_key, - std::string& content_sha256, utils::Time& date) { + const std::string& access_key, const std::string& secret_key, + const std::string& content_sha256, const utils::Time& date) { std::string service_name = "s3"; - return SignV4(service_name, method, uri, region, headers, query_params, - access_key, secret_key, content_sha256, date); + return SignV4(service_name, method, uri, region, headers, + std::move(query_params), access_key, secret_key, content_sha256, + date); } -minio::utils::Multimap& minio::signer::SignV4STS( - http::Method method, std::string& uri, std::string& region, +minio::utils::Multimap minio::signer::SignV4STS( + http::Method method, const std::string& uri, const std::string& region, utils::Multimap& headers, utils::Multimap query_params, - std::string& access_key, std::string& secret_key, - std::string& content_sha256, utils::Time& date) { + const std::string& access_key, const std::string& secret_key, + const std::string& content_sha256, const utils::Time& date) { std::string service_name = "sts"; - return SignV4(service_name, method, uri, region, headers, query_params, - access_key, secret_key, content_sha256, date); + return SignV4(service_name, method, uri, region, headers, + std::move(query_params), access_key, secret_key, content_sha256, + date); } -minio::utils::Multimap& minio::signer::PresignV4( - http::Method method, std::string& host, std::string& uri, - std::string& region, utils::Multimap& query_params, std::string& access_key, - std::string& secret_key, utils::Time& date, unsigned int expires) { +minio::utils::Multimap minio::signer::PresignV4( + http::Method method, const std::string& host, const std::string& uri, + const std::string& region, utils::Multimap query_params, + const std::string& access_key, const std::string& secret_key, + const utils::Time& date, unsigned int expires) { std::string service_name = "s3"; std::string scope = GetScope(date, region, service_name); std::string canonical_headers = "host:" + host; @@ -172,10 +177,10 @@ minio::utils::Multimap& minio::signer::PresignV4( return query_params; } -std::string minio::signer::PostPresignV4(std::string string_to_sign, - std::string& secret_key, - utils::Time& date, - std::string& region) { +std::string minio::signer::PostPresignV4(const std::string& string_to_sign, + const std::string& secret_key, + const utils::Time& date, + const std::string& region) { std::string service_name = "s3"; std::string signing_key = GetSigningKey(secret_key, date, region, service_name); diff --git a/src/sse.cc b/src/sse.cc new file mode 100644 index 00000000..c47377f7 --- /dev/null +++ b/src/sse.cc @@ -0,0 +1,69 @@ +// MinIO C++ Library for Amazon S3 Compatible Cloud Storage +// Copyright 2022 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. + +#include "sse.h" + +minio::s3::Sse::Sse() {} + +minio::s3::Sse::~Sse() {} + +minio::utils::Multimap minio::s3::Sse::Headers() const { return headers_; } + +minio::utils::Multimap minio::s3::Sse::CopyHeaders() const { + return copy_headers_; +} + +minio::s3::SseCustomerKey::SseCustomerKey(std::string_view key) { + std::string b64key = utils::Base64Encode(key); + std::string md5key = utils::Md5sumHash(key); + + this->headers_.Add("X-Amz-Server-Side-Encryption-Customer-Algorithm", + "AES256"); + this->headers_.Add("X-Amz-Server-Side-Encryption-Customer-Key", b64key); + this->headers_.Add("X-Amz-Server-Side-Encryption-Customer-Key-MD5", md5key); + + this->copy_headers_.Add( + "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Algorithm", "AES256"); + this->copy_headers_.Add( + "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key", b64key); + this->copy_headers_.Add( + "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key-MD5", md5key); +} + +minio::s3::SseCustomerKey::~SseCustomerKey() {} + +bool minio::s3::SseCustomerKey::TlsRequired() const { return true; } + +minio::s3::SseKms::SseKms(std::string_view key, std::string_view context) { + this->headers_.Add("X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id", + std::string(key)); + this->headers_.Add("X-Amz-Server-Side-Encryption", "aws:kms"); + if (!context.empty()) { + this->headers_.Add("X-Amz-Server-Side-Encryption-Context", + utils::Base64Encode(context)); + } +} + +minio::s3::SseKms::~SseKms() {} + +bool minio::s3::SseKms::TlsRequired() const { return true; } + +minio::s3::SseS3::SseS3() { + this->headers_.Add("X-Amz-Server-Side-Encryption", "AES256"); +} + +minio::s3::SseS3::~SseS3() {} + +bool minio::s3::SseS3::TlsRequired() const { return false; } diff --git a/src/types.cc b/src/types.cc index 940c6061..e8048b93 100644 --- a/src/types.cc +++ b/src/types.cc @@ -16,7 +16,7 @@ #include "types.h" minio::s3::RetentionMode minio::s3::StringToRetentionMode( - std::string_view str) throw() { + std::string_view str) noexcept { if (str == "GOVERNANCE") return RetentionMode::kGovernance; if (str == "COMPLIANCE") return RetentionMode::kCompliance; @@ -28,7 +28,7 @@ minio::s3::RetentionMode minio::s3::StringToRetentionMode( } minio::s3::LegalHold minio::s3::StringToLegalHold( - std::string_view str) throw() { + std::string_view str) noexcept { if (str == "ON") return LegalHold::kOn; if (str == "OFF") return LegalHold::kOff; @@ -40,7 +40,7 @@ minio::s3::LegalHold minio::s3::StringToLegalHold( } minio::s3::Directive minio::s3::StringToDirective( - std::string_view str) throw() { + std::string_view str) noexcept { if (str == "COPY") return Directive::kCopy; if (str == "REPLACE") return Directive::kReplace; @@ -50,7 +50,7 @@ minio::s3::Directive minio::s3::StringToDirective( return Directive::kCopy; // never reaches here. } -std::string minio::s3::SelectRequest::ToXML() { +std::string minio::s3::SelectRequest::ToXML() const { std::stringstream ss; ss << ""; @@ -59,8 +59,8 @@ std::string minio::s3::SelectRequest::ToXML() { ss << ""; - if (csv_input != NULL) { - if (csv_input->compression_type != NULL) { + if (csv_input != nullptr) { + if (csv_input->compression_type != nullptr) { ss << "" << CompressionTypeToString(*csv_input->compression_type) << ""; @@ -77,7 +77,7 @@ std::string minio::s3::SelectRequest::ToXML() { ss << "" << csv_input->field_delimiter << ""; } - if (csv_input->file_header_info != NULL) { + if (csv_input->file_header_info != nullptr) { ss << "" << FileHeaderInfoToString(*csv_input->file_header_info) << ""; @@ -93,27 +93,27 @@ std::string minio::s3::SelectRequest::ToXML() { ss << ""; } - if (json_input != NULL) { - if (json_input->compression_type != NULL) { + if (json_input != nullptr) { + if (json_input->compression_type != nullptr) { ss << "" << CompressionTypeToString(*json_input->compression_type) << ""; } ss << ""; - if (json_input->json_type != NULL) { + if (json_input->json_type != nullptr) { ss << "" << JsonTypeToString(*json_input->json_type) << ""; } ss << ""; } - if (parquet_input != NULL) ss << ""; + if (parquet_input != nullptr) ss << ""; ss << ""; ss << ""; - if (csv_output != NULL) { + if (csv_output != nullptr) { ss << ""; if (csv_output->field_delimiter) { ss << "" << csv_output->field_delimiter @@ -127,7 +127,7 @@ std::string minio::s3::SelectRequest::ToXML() { ss << "" << csv_output->quote_escape_character << ""; } - if (csv_output->quote_fields != NULL) { + if (csv_output->quote_fields != nullptr) { ss << "" << QuoteFieldsToString(*csv_output->quote_fields) << ""; } @@ -138,7 +138,7 @@ std::string minio::s3::SelectRequest::ToXML() { ss << ""; } - if (json_output != NULL) { + if (json_output != nullptr) { ss << ""; if (json_output->record_delimiter) { ss << "" << json_output->record_delimiter @@ -152,12 +152,12 @@ std::string minio::s3::SelectRequest::ToXML() { if (request_progress) { ss << "true"; } - if (scan_start_range != NULL || scan_end_range != NULL) { + if (scan_start_range != nullptr || scan_end_range != nullptr) { ss << ""; - if (scan_start_range != NULL) { + if (scan_start_range != nullptr) { ss << "" << *scan_start_range << ""; } - if (scan_end_range != NULL) { + if (scan_end_range != nullptr) { ss << "" << *scan_end_range << ""; } ss << ""; @@ -234,7 +234,7 @@ minio::s3::NotificationRecord minio::s3::NotificationRecord::ParseJSON( return record; } -std::string minio::s3::NotificationConfig::ToXML() { +std::string minio::s3::NotificationConfig::ToXML() const { std::stringstream ss; ss << ""; @@ -309,7 +309,7 @@ std::string minio::s3::NotificationConfig::ToXML() { return ss.str(); } -std::string minio::s3::ReplicationConfig::ToXML() { +std::string minio::s3::ReplicationConfig::ToXML() const { auto status_xml = [](bool status) -> std::string { std::stringstream ss; ss << "" << (status ? "Enabled" : "Disabled") << ""; @@ -455,7 +455,7 @@ std::string minio::s3::ReplicationConfig::ToXML() { return ss.str(); } -minio::error::Error minio::s3::LifecycleRule::Validate() { +minio::error::Error minio::s3::LifecycleRule::Validate() const { if (!abort_incomplete_multipart_upload_days_after_initiation && !expiration_date && !expiration_days && !expiration_expired_object_delete_marker && @@ -492,7 +492,7 @@ minio::error::Error minio::s3::LifecycleRule::Validate() { return error::SUCCESS; } -std::string minio::s3::LifecycleConfig::ToXML() { +std::string minio::s3::LifecycleConfig::ToXML() const { std::stringstream ss; ss << ""; @@ -502,8 +502,7 @@ std::string minio::s3::LifecycleConfig::ToXML() { if (rule.abort_incomplete_multipart_upload_days_after_initiation) { ss << "" - << std::to_string( - rule.abort_incomplete_multipart_upload_days_after_initiation) + << rule.abort_incomplete_multipart_upload_days_after_initiation << ""; } @@ -514,11 +513,11 @@ std::string minio::s3::LifecycleConfig::ToXML() { ss << "" << rule.expiration_date.ToISO8601UTC() << ""; } if (rule.expiration_days) { - ss << "" << std::to_string(rule.expiration_days) << ""; + ss << "" << rule.expiration_days << ""; } if (rule.expiration_expired_object_delete_marker) { ss << "" - << utils::BoolToString(rule.expiration_expired_object_delete_marker) + << rule.expiration_expired_object_delete_marker << ""; } ss << ""; @@ -584,7 +583,7 @@ std::string minio::s3::LifecycleConfig::ToXML() { ss << "" << rule.transition_date.ToISO8601UTC() << ""; } if (rule.transition_days) { - ss << "" << std::to_string(rule.transition_days) << ""; + ss << "" << rule.transition_days << ""; } if (!rule.transition_storage_class.empty()) { ss << "" << rule.transition_storage_class @@ -601,9 +600,10 @@ std::string minio::s3::LifecycleConfig::ToXML() { return ss.str(); } -minio::error::Error minio::s3::ObjectLockConfig::Validate() { +minio::error::Error minio::s3::ObjectLockConfig::Validate() const { if (IsRetentionModeValid(retention_mode)) { - if (!(retention_duration_days ^ retention_duration_years)) { + if (!(static_cast(retention_duration_days) ^ + static_cast(retention_duration_years))) { return error::Error( "retention mode must be provided with retention duration days or " "years"); @@ -616,3 +616,16 @@ minio::error::Error minio::s3::ObjectLockConfig::Validate() { return error::SUCCESS; } + +minio::s3::SseConfig minio::s3::SseConfig::S3() { + SseConfig config; + config.sse_algorithm = "AES256"; + return config; +} + +minio::s3::SseConfig minio::s3::SseConfig::Kms(std::string masterkeyid) { + SseConfig config; + config.sse_algorithm = "aws:kms"; + config.kms_master_key_id = masterkeyid; + return config; +} diff --git a/src/utils.cc b/src/utils.cc index 54e9a3a9..53182e7a 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -13,8 +13,14 @@ // See the License for the specific language governing permissions and // limitations under the License. +#ifdef _WIN32 +#define _CRT_SECURE_NO_WARNINGS +#endif + #include "utils.h" +#include + const std::string WEEK_DAYS[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; const std::string MONTHS[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", @@ -60,7 +66,7 @@ std::string minio::utils::GetHomeDir() { #endif } -std::string minio::utils::Printable(std::string s) { +std::string minio::utils::Printable(const std::string& s) { std::stringstream ss; for (auto& ch : s) { if (ch < 33 || ch > 126) { @@ -75,7 +81,8 @@ std::string minio::utils::Printable(std::string s) { } unsigned long minio::utils::CRC32(std::string_view str) { - return crc32(0, (const unsigned char*)str.data(), str.size()); + return crc32(0, reinterpret_cast(str.data()), + static_cast(str.size())); } unsigned int minio::utils::Int(std::string_view str) { @@ -83,7 +90,7 @@ unsigned int minio::utils::Int(std::string_view str) { return data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; } -bool minio::utils::StringToBool(std::string str) { +bool minio::utils::StringToBool(const std::string& str) { std::string s = ToLower(str); if (s == "false") return false; if (s == "true") return true; @@ -96,7 +103,7 @@ bool minio::utils::StringToBool(std::string str) { } std::string minio::utils::Trim(std::string_view str, char ch) { - int start, len; + std::size_t start, len; for (start = 0; start < str.size() && str[start] == ch; start++) ; for (len = str.size() - start; len > 0 && str[start + len - 1] == ch; len--) @@ -108,8 +115,8 @@ bool minio::utils::CheckNonEmptyString(std::string_view str) { return !str.empty() && Trim(str) == str; } -std::string minio::utils::ToLower(std::string str) { - std::string s = str; +std::string minio::utils::ToLower(const std::string& str) { + std::string s(str); std::transform(s.begin(), s.end(), s.begin(), ::tolower); return s; } @@ -132,8 +139,8 @@ bool minio::utils::Contains(std::string_view str, std::string_view substr) { return str.find(substr) != std::string::npos; } -std::string minio::utils::Join(std::list values, - std::string delimiter) { +std::string minio::utils::Join(const std::list& values, + const std::string& delimiter) { std::string result; for (const auto& value : values) { if (!result.empty()) result += delimiter; @@ -142,8 +149,8 @@ std::string minio::utils::Join(std::list values, return result; } -std::string minio::utils::Join(std::vector values, - std::string delimiter) { +std::string minio::utils::Join(const std::vector& values, + const std::string& delimiter) { std::string result; for (const auto& value : values) { if (!result.empty()) result += delimiter; @@ -152,7 +159,7 @@ std::string minio::utils::Join(std::vector values, return result; } -std::string minio::utils::EncodePath(std::string& path) { +std::string minio::utils::EncodePath(const std::string& path) { std::stringstream str_stream(path); std::string token; std::string out; @@ -171,12 +178,12 @@ std::string minio::utils::EncodePath(std::string& path) { std::string minio::utils::Sha256Hash(std::string_view str) { EVP_MD_CTX* ctx = EVP_MD_CTX_create(); - if (ctx == NULL) { + if (ctx == nullptr) { std::cerr << "failed to create EVP_MD_CTX" << std::endl; std::terminate(); } - if (1 != EVP_DigestInit_ex(ctx, EVP_sha256(), NULL)) { + if (1 != EVP_DigestInit_ex(ctx, EVP_sha256(), nullptr)) { std::cerr << "failed to init SHA-256 digest" << std::endl; std::terminate(); } @@ -188,7 +195,7 @@ std::string minio::utils::Sha256Hash(std::string_view str) { unsigned int length = EVP_MD_size(EVP_sha256()); unsigned char* digest = (unsigned char*)OPENSSL_malloc(length); - if (digest == NULL) { + if (digest == nullptr) { std::cerr << "failed to allocate memory for hash value" << std::endl; std::terminate(); } @@ -203,7 +210,7 @@ std::string minio::utils::Sha256Hash(std::string_view str) { std::string hash; char buf[3]; - for (int i = 0; i < length; ++i) { + for (unsigned int i = 0; i < length; ++i) { snprintf(buf, 3, "%02x", digest[i]); hash += buf; } @@ -218,7 +225,7 @@ std::string minio::utils::Base64Encode(std::string_view str) { auto base64 = BIO_new(BIO_f_base64()); base64 = BIO_push(base64, base64_memory); - BIO_write(base64, str.data(), str.size()); + BIO_write(base64, str.data(), static_cast(str.size())); BIO_flush(base64); BUF_MEM* buf_mem{}; @@ -232,12 +239,12 @@ std::string minio::utils::Base64Encode(std::string_view str) { std::string minio::utils::Md5sumHash(std::string_view str) { EVP_MD_CTX* ctx = EVP_MD_CTX_create(); - if (ctx == NULL) { + if (ctx == nullptr) { std::cerr << "failed to create EVP_MD_CTX" << std::endl; std::terminate(); } - if (1 != EVP_DigestInit_ex(ctx, EVP_md5(), NULL)) { + if (1 != EVP_DigestInit_ex(ctx, EVP_md5(), nullptr)) { std::cerr << "failed to init MD5 digest" << std::endl; std::terminate(); } @@ -249,7 +256,7 @@ std::string minio::utils::Md5sumHash(std::string_view str) { unsigned int length = EVP_MD_size(EVP_md5()); unsigned char* digest = (unsigned char*)OPENSSL_malloc(length); - if (digest == NULL) { + if (digest == nullptr) { std::cerr << "failed to allocate memory for hash value" << std::endl; std::terminate(); } @@ -262,7 +269,7 @@ std::string minio::utils::Md5sumHash(std::string_view str) { EVP_MD_CTX_destroy(ctx); - std::string hash = std::string((const char*)digest, length); + std::string hash(reinterpret_cast(digest), length); OPENSSL_free(digest); return minio::utils::Base64Encode(hash); @@ -274,32 +281,37 @@ std::string minio::utils::FormatTime(const std::tm* time, const char* format) { return std::string(buf); } -std::tm* minio::utils::Time::ToUTC() { +std::tm* minio::utils::Time::ToUTC() const { std::tm* t = new std::tm; const time_t secs = tv_.tv_sec; *t = utc_ ? *std::localtime(&secs) : *std::gmtime(&secs); return t; } -std::string minio::utils::Time::ToSignerDate() { - std::tm* utc = ToUTC(); - std::string result = FormatTime(utc, "%Y%m%d"); - delete utc; +minio::utils::Time minio::utils::Time::Now() { + auto usec = std::chrono::system_clock::now().time_since_epoch() / + std::chrono::microseconds(1); + return Time(static_cast(usec / 1000000), + static_cast(usec % 1000000), false); +} + +std::string minio::utils::Time::ToSignerDate() const { + std::unique_ptr utc(ToUTC()); + std::string result = FormatTime(utc.get(), "%Y%m%d"); return result; } -std::string minio::utils::Time::ToAmzDate() { - std::tm* utc = ToUTC(); - std::string result = FormatTime(utc, "%Y%m%dT%H%M%SZ"); - delete utc; +std::string minio::utils::Time::ToAmzDate() const { + std::unique_ptr utc(ToUTC()); + std::string result = FormatTime(utc.get(), "%Y%m%dT%H%M%SZ"); return result; } -std::string minio::utils::Time::ToHttpHeaderValue() { - std::tm* utc = ToUTC(); +std::string minio::utils::Time::ToHttpHeaderValue() const { + std::unique_ptr utc(ToUTC()); std::stringstream ss; - ss << WEEK_DAYS[utc->tm_wday] << ", " << FormatTime(utc, "%d ") - << MONTHS[utc->tm_mon] << FormatTime(utc, " %Y %H:%M:%S GMT"); + ss << WEEK_DAYS[utc->tm_wday] << ", " << FormatTime(utc.get(), "%d ") + << MONTHS[utc->tm_mon] << FormatTime(utc.get(), " %Y %H:%M:%S GMT"); return ss.str(); } @@ -316,7 +328,7 @@ minio::utils::Time minio::utils::Time::FromHttpHeaderValue(const char* value) { auto week_day = pos - std::begin(WEEK_DAYS); // Parse day. - std::tm day{0}; + std::tm day{}; strptime(s.substr(5, 2).c_str(), "%d", &day); if (s.at(7) != ' ') return Time(); @@ -326,10 +338,10 @@ minio::utils::Time minio::utils::Time::FromHttpHeaderValue(const char* value) { auto month = pos - std::begin(MONTHS); // Parse rest of values. - std::tm ltm{0}; + std::tm ltm{}; strptime(s.substr(11).c_str(), " %Y %H:%M:%S GMT", <m); ltm.tm_mday = day.tm_mday; - ltm.tm_mon = month; + ltm.tm_mon = static_cast(month); // Validate week day. std::time_t time = std::mktime(<m); @@ -339,19 +351,19 @@ minio::utils::Time minio::utils::Time::FromHttpHeaderValue(const char* value) { return Time(std::mktime(t), 0, true); } -std::string minio::utils::Time::ToISO8601UTC() { +std::string minio::utils::Time::ToISO8601UTC() const { char buf[64]; snprintf(buf, 64, "%03ld", (long int)tv_.tv_usec); std::string usec_str(buf); if (usec_str.size() > 3) usec_str = usec_str.substr(0, 3); - std::tm* utc = ToUTC(); - std::string result = FormatTime(utc, "%Y-%m-%dT%H:%M:%S.") + usec_str + "Z"; - delete utc; + std::unique_ptr utc(ToUTC()); + std::string result = + FormatTime(utc.get(), "%Y-%m-%dT%H:%M:%S.") + usec_str + "Z"; return result; } minio::utils::Time minio::utils::Time::FromISO8601UTC(const char* value) { - std::tm t{0}; + std::tm t{}; char* rv = strptime(value, "%Y-%m-%dT%H:%M:%S", &t); unsigned long ul = 0; sscanf(rv, ".%lu", &ul); @@ -360,9 +372,19 @@ minio::utils::Time minio::utils::Time::FromISO8601UTC(const char* value) { return Time(time, tv_usec, true); } +int minio::utils::Time::Compare(const Time& rhs) const { + if (tv_.tv_sec != rhs.tv_.tv_sec) { + return (tv_.tv_sec < rhs.tv_.tv_sec) ? -1 : 1; + } + if (tv_.tv_usec != rhs.tv_.tv_usec) { + return (tv_.tv_usec < rhs.tv_.tv_usec) ? -1 : 1; + } + return 0; +} + void minio::utils::Multimap::Add(std::string key, std::string value) { - map_[key].insert(value); - keys_[ToLower(key)].insert(key); + map_[key].insert(std::move(value)); + keys_[ToLower(key)].insert(std::move(key)); } void minio::utils::Multimap::AddAll(const Multimap& headers) { @@ -373,7 +395,7 @@ void minio::utils::Multimap::AddAll(const Multimap& headers) { } } -std::list minio::utils::Multimap::ToHttpHeaders() { +std::list minio::utils::Multimap::ToHttpHeaders() const { std::list headers; for (auto& [key, values] : map_) { for (auto& value : values) { @@ -383,7 +405,7 @@ std::list minio::utils::Multimap::ToHttpHeaders() { return headers; } -std::string minio::utils::Multimap::ToQueryString() { +std::string minio::utils::Multimap::ToQueryString() const { std::string query_string; for (auto& [key, values] : map_) { for (auto& value : values) { @@ -395,33 +417,36 @@ std::string minio::utils::Multimap::ToQueryString() { return query_string; } -bool minio::utils::Multimap::Contains(std::string_view key) { +bool minio::utils::Multimap::Contains(std::string_view key) const { return keys_.find(ToLower(std::string(key))) != keys_.end(); } -std::list minio::utils::Multimap::Get(std::string_view key) { +std::list minio::utils::Multimap::Get(std::string_view key) const { std::list result; - std::set keys = keys_[ToLower(std::string(key))]; - for (auto& key : keys) { - std::set values = map_[key]; - result.insert(result.end(), values.begin(), values.end()); + + if (const auto i = keys_.find(ToLower(std::string(key))); i != keys_.cend()) { + for (auto& k : i->second) { + if (const auto j = map_.find(k); j != map_.cend()) { + result.insert(result.end(), j->second.begin(), j->second.cend()); + } + } } return result; } -std::string minio::utils::Multimap::GetFront(std::string_view key) { +std::string minio::utils::Multimap::GetFront(std::string_view key) const { std::list values = Get(key); - return (values.size() > 0) ? values.front() : ""; + return (values.size() > 0) ? values.front() : std::string(); } -std::list minio::utils::Multimap::Keys() { +std::list minio::utils::Multimap::Keys() const { std::list keys; for (const auto& [key, _] : keys_) keys.push_back(key); return keys; } void minio::utils::Multimap::GetCanonicalHeaders( - std::string& signed_headers, std::string& canonical_headers) { + std::string& signed_headers, std::string& canonical_headers) const { std::vector signed_headerslist; std::map map; @@ -454,17 +479,20 @@ void minio::utils::Multimap::GetCanonicalHeaders( canonical_headers = utils::Join(canonical_headerslist, "\n"); } -std::string minio::utils::Multimap::GetCanonicalQueryString() { +std::string minio::utils::Multimap::GetCanonicalQueryString() const { std::vector keys; - for (auto& [key, _] : map_) keys.push_back(key); - std::sort(keys.begin(), keys.end()); + for (auto& [key, _] : map_) { + keys.push_back(key); + } + std::sort(keys.begin(), keys.end()); std::vector values; + for (auto& key : keys) { - auto vals = map_[key]; - for (auto& value : vals) { - std::string s = curlpp::escape(key) + "=" + curlpp::escape(value); - values.push_back(s); + if (const auto i = map_.find(key); i != map_.cend()) { + for (auto& value : i->second) { + values.push_back(curlpp::escape(key) + "=" + curlpp::escape(value)); + } } } @@ -531,7 +559,7 @@ minio::error::Error minio::utils::CalcPartInfo(long object_size, } if (object_size >= 0) { - if (object_size > kMaxObjectSize) { + if (static_cast(object_size) > kMaxObjectSize) { return error::Error("object size " + std::to_string(object_size) + " is not supported; maximum allowed 5TiB"); } @@ -551,9 +579,9 @@ minio::error::Error minio::utils::CalcPartInfo(long object_size, part_size = (size_t)std::ceil(psize / kMinPartSize) * kMinPartSize; } - if (part_size > object_size) part_size = object_size; - part_count = - part_size > 0 ? (long)std::ceil((double)object_size / part_size) : 1; + if (static_cast(part_size) > object_size) part_size = object_size; + part_count = static_cast( + (part_size > 0) ? ((object_size + part_size - 1) / part_size) : 1); if (part_count > kMaxMultipartCount) { return error::Error( "object size " + std::to_string(object_size) + " and part size " + @@ -563,3 +591,22 @@ minio::error::Error minio::utils::CalcPartInfo(long object_size, return error::SUCCESS; } + +minio::utils::CharBuffer::~CharBuffer() {} + +std::streambuf::pos_type minio::utils::CharBuffer::seekpos( + pos_type sp, std::ios_base::openmode which) { + return seekoff(sp - pos_type(off_type(0)), std::ios_base::beg, which); +} + +std::streambuf::pos_type minio::utils::CharBuffer::seekoff( + off_type off, std::ios_base::seekdir dir, + std::ios_base::openmode /* which */) { + if (dir == std::ios_base::cur) + gbump(static_cast(off)); + else if (dir == std::ios_base::end) + setg(eback(), egptr() + off, egptr()); + else if (dir == std::ios_base::beg) + setg(eback(), eback() + off, egptr()); + return gptr() - eback(); +} diff --git a/tests/tests.cc b/tests/tests.cc index 8bf97dcb..dcef9eb5 100644 --- a/tests/tests.cc +++ b/tests/tests.cc @@ -201,11 +201,11 @@ class Tests { throw std::runtime_error("BucketExists(): expected: true; got: false"); } RemoveBucket(bucket_name); - } catch (const MakeBucketError& err) { - throw err; - } catch (const std::runtime_error& err) { + } catch (const MakeBucketError&) { + throw; + } catch (const std::runtime_error&) { RemoveBucket(bucket_name); - throw err; + throw; } } @@ -225,7 +225,7 @@ class Tests { throw std::runtime_error("ListBuckets(): " + resp.Error().String()); } - int c = 0; + std::size_t c = 0; for (auto& bucket : resp.buckets) { if (std::find(bucket_names.begin(), bucket_names.end(), bucket.name) != bucket_names.end()) { @@ -238,9 +238,9 @@ class Tests { "; got: " + std::to_string(c)); } for (auto& bucket_name : bucket_names) RemoveBucket(bucket_name); - } catch (const std::runtime_error& err) { + } catch (const std::runtime_error&) { for (auto& bucket_name : bucket_names) RemoveBucket(bucket_name); - throw err; + throw; } } @@ -251,7 +251,7 @@ class Tests { std::string data = "StatObject()"; std::stringstream ss(data); - minio::s3::PutObjectArgs args(ss, data.length(), 0); + minio::s3::PutObjectArgs args(ss, static_cast(data.length()), 0); args.bucket = bucket_name_; args.object = object_name; minio::s3::PutObjectResponse resp = client_.PutObject(args); @@ -272,9 +272,9 @@ class Tests { "; got: " + std::to_string(resp.size)); } RemoveObject(bucket_name_, object_name); - } catch (const std::runtime_error& err) { + } catch (const std::runtime_error&) { RemoveObject(bucket_name_, object_name); - throw err; + throw; } } @@ -284,7 +284,7 @@ class Tests { std::string object_name = RandObjectName(); std::string data = "RemoveObject()"; std::stringstream ss(data); - minio::s3::PutObjectArgs args(ss, data.length(), 0); + minio::s3::PutObjectArgs args(ss, static_cast(data.length()), 0); args.bucket = bucket_name_; args.object = object_name; minio::s3::PutObjectResponse resp = client_.PutObject(args); @@ -301,7 +301,7 @@ class Tests { std::string data = "DownloadObject()"; std::stringstream ss(data); - minio::s3::PutObjectArgs args(ss, data.length(), 0); + minio::s3::PutObjectArgs args(ss, static_cast(data.length()), 0); args.bucket = bucket_name_; args.object = object_name; minio::s3::PutObjectResponse resp = client_.PutObject(args); @@ -334,9 +334,9 @@ class Tests { } std::filesystem::remove(filename); RemoveObject(bucket_name_, object_name); - } catch (const std::runtime_error& err) { + } catch (const std::runtime_error&) { RemoveObject(bucket_name_, object_name); - throw err; + throw; } } @@ -347,7 +347,7 @@ class Tests { std::string data = "GetObject()"; std::stringstream ss(data); - minio::s3::PutObjectArgs args(ss, data.length(), 0); + minio::s3::PutObjectArgs args(ss, static_cast(data.length()), 0); args.bucket = bucket_name_; args.object = object_name; minio::s3::PutObjectResponse resp = client_.PutObject(args); @@ -374,9 +374,9 @@ class Tests { "; got: " + content); } RemoveObject(bucket_name_, object_name); - } catch (const std::runtime_error& err) { + } catch (const std::runtime_error&) { RemoveObject(bucket_name_, object_name); - throw err; + throw; } } @@ -398,7 +398,7 @@ class Tests { object_names.push_back(object_name); } - int c = 0; + std::size_t c = 0; minio::s3::ListObjectsArgs args; args.bucket = bucket_name_; minio::s3::ListObjectsResult result = client_.ListObjects(args); @@ -419,9 +419,9 @@ class Tests { "; got: " + std::to_string(c)); } RemoveObjects(object_names); - } catch (const std::runtime_error& err) { + } catch (const std::runtime_error&) { RemoveObjects(object_names); - throw err; + throw; } } @@ -436,7 +436,9 @@ class Tests { std::string object_name = RandObjectName(); std::string data = "PutObject()"; std::stringstream ss(data); - minio::s3::PutObjectArgs args(ss, data.length(), 0); + minio::s3::PutObjectArgs args( + ss, static_cast(data.length()), + 0); // PWTODO: PutObjectArgs should accept size_t instead of long args.bucket = bucket_name_; args.object = object_name; minio::s3::PutObjectResponse resp = client_.PutObject(args); @@ -450,7 +452,7 @@ class Tests { std::string object_name = RandObjectName(); size_t size = 13930573; RandCharStream stream(size); - minio::s3::PutObjectArgs args(stream, size, 0); + minio::s3::PutObjectArgs args(stream, static_cast(size), 0); args.bucket = bucket_name_; args.object = object_name; minio::s3::PutObjectResponse resp = client_.PutObject(args); @@ -469,7 +471,7 @@ class Tests { std::string src_object_name = RandObjectName(); std::string data = "CopyObject()"; std::stringstream ss(data); - minio::s3::PutObjectArgs args(ss, data.length(), 0); + minio::s3::PutObjectArgs args(ss, static_cast(data.length()), 0); args.bucket = bucket_name_; args.object = src_object_name; minio::s3::PutObjectResponse resp = client_.PutObject(args); @@ -491,10 +493,10 @@ class Tests { } RemoveObject(bucket_name_, src_object_name); RemoveObject(bucket_name_, object_name); - } catch (const std::runtime_error& err) { + } catch (const std::runtime_error&) { RemoveObject(bucket_name_, src_object_name); RemoveObject(bucket_name_, object_name); - throw err; + throw; } } @@ -536,9 +538,9 @@ class Tests { object_names.push_back(object_name); } RemoveObjects(object_names); - } catch (const std::runtime_error& err) { + } catch (const std::runtime_error&) { RemoveObjects(object_names); - throw err; + throw; } } @@ -554,7 +556,7 @@ class Tests { "1996,Jeep,Grand Cherokee,\"MUST SELL!\n" "air, moon roof, loaded\",4799.00\n"; std::stringstream ss("Year,Make,Model,Description,Price\n" + data); - minio::s3::PutObjectArgs args(ss, ss.str().length(), 0); + minio::s3::PutObjectArgs args(ss, static_cast(ss.str().length()), 0); args.bucket = bucket_name_; args.object = object_name; minio::s3::PutObjectResponse resp = client_.PutObject(args); @@ -595,9 +597,9 @@ class Tests { throw std::runtime_error("expected: " + data + ", got: " + records); } RemoveObject(bucket_name_, object_name); - } catch (const std::runtime_error& err) { + } catch (const std::runtime_error&) { RemoveObject(bucket_name_, object_name); - throw err; + throw; } } @@ -628,7 +630,7 @@ class Tests { try { std::string data = "ListenBucketNotification()"; std::stringstream ss(data); - minio::s3::PutObjectArgs args(ss, data.length(), 0); + minio::s3::PutObjectArgs args(ss, static_cast(data.length()), 0); args.bucket = bucket_name_; args.object = object_name; minio::s3::PutObjectResponse resp = client_.PutObject(args); @@ -664,14 +666,14 @@ class Tests { } RemoveObject(bucket_name_, object_name); - } catch (const std::runtime_error& err) { + } catch (const std::runtime_error&) { RemoveObject(bucket_name_, object_name); - throw err; + throw; } } }; // class Tests -int main(int argc, char* argv[]) { +int main(int /*argc*/, char* /*argv*/[]) { std::string host; if (!minio::utils::GetEnv(host, "SERVER_ENDPOINT")) { std::cerr << "SERVER_ENDPOINT environment variable must be set"