args.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. // MinIO C++ Library for Amazon S3 Compatible Cloud Storage
  2. // Copyright 2022 MinIO, Inc.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. #ifndef _MINIO_S3_ARGS_H
  16. #define _MINIO_S3_ARGS_H
  17. #include "http.h"
  18. #include "signer.h"
  19. #include "sse.h"
  20. #include "types.h"
  21. #include <filesystem>
  22. #include <nlohmann/json.hpp>
  23. namespace minio {
  24. namespace s3 {
  25. struct BaseArgs {
  26. utils::Multimap extra_headers;
  27. utils::Multimap extra_query_params;
  28. }; // struct BaseArgs
  29. struct BucketArgs : public BaseArgs {
  30. std::string bucket;
  31. std::string region;
  32. error::Error Validate();
  33. }; // struct BucketArgs
  34. struct ObjectArgs : public BucketArgs {
  35. std::string object;
  36. error::Error Validate();
  37. }; // struct ObjectArgs
  38. struct ObjectWriteArgs : public ObjectArgs {
  39. utils::Multimap headers;
  40. utils::Multimap user_metadata;
  41. Sse *sse = NULL;
  42. std::map<std::string, std::string> tags;
  43. Retention *retention = NULL;
  44. bool legal_hold = false;
  45. utils::Multimap Headers();
  46. }; // struct ObjectWriteArgs
  47. struct ObjectVersionArgs : public ObjectArgs {
  48. std::string version_id;
  49. }; // struct ObjectVersionArgs
  50. struct ObjectReadArgs : public ObjectVersionArgs {
  51. SseCustomerKey *ssec = NULL;
  52. }; // struct ObjectReadArgs
  53. struct ObjectConditionalReadArgs : public ObjectReadArgs {
  54. size_t *offset = NULL;
  55. size_t *length = NULL;
  56. std::string match_etag;
  57. std::string not_match_etag;
  58. utils::Time modified_since;
  59. utils::Time unmodified_since;
  60. utils::Multimap Headers();
  61. utils::Multimap CopyHeaders();
  62. }; // struct ObjectConditionalReadArgs
  63. struct MakeBucketArgs : public BucketArgs {
  64. bool object_lock = false;
  65. error::Error Validate();
  66. }; // struct MakeBucketArgs
  67. using ListBucketsArgs = BaseArgs;
  68. using BucketExistsArgs = BucketArgs;
  69. using RemoveBucketArgs = BucketArgs;
  70. struct AbortMultipartUploadArgs : public ObjectArgs {
  71. std::string upload_id;
  72. error::Error Validate();
  73. }; // struct AbortMultipartUploadArgs
  74. struct CompleteMultipartUploadArgs : public ObjectArgs {
  75. std::string upload_id;
  76. std::list<Part> parts;
  77. error::Error Validate();
  78. }; // struct CompleteMultipartUploadArgs
  79. struct CreateMultipartUploadArgs : public ObjectArgs {
  80. utils::Multimap headers;
  81. }; // struct CreateMultipartUploadArgs
  82. struct PutObjectBaseArgs : public ObjectWriteArgs {
  83. long object_size = -1;
  84. size_t part_size = 0;
  85. long part_count = 0;
  86. std::string content_type;
  87. }; // struct PutObjectBaseArgs
  88. struct PutObjectApiArgs : public PutObjectBaseArgs {
  89. std::string_view data;
  90. utils::Multimap query_params;
  91. http::ProgressFunction progressfunc = NULL;
  92. void *progress_userdata = NULL;
  93. }; // struct PutObjectApiArgs
  94. struct UploadPartArgs : public ObjectWriteArgs {
  95. std::string upload_id;
  96. unsigned int part_number;
  97. std::string_view data;
  98. http::ProgressFunction progressfunc = NULL;
  99. void *progress_userdata = NULL;
  100. error::Error Validate();
  101. }; // struct UploadPartArgs
  102. struct UploadPartCopyArgs : public ObjectWriteArgs {
  103. std::string upload_id;
  104. unsigned int part_number;
  105. utils::Multimap headers;
  106. error::Error Validate();
  107. }; // struct UploadPartCopyArgs
  108. using StatObjectArgs = ObjectConditionalReadArgs;
  109. using RemoveObjectArgs = ObjectVersionArgs;
  110. struct DownloadObjectArgs : public ObjectReadArgs {
  111. std::string filename;
  112. bool overwrite;
  113. http::ProgressFunction progressfunc = NULL;
  114. void *progress_userdata = NULL;
  115. error::Error Validate();
  116. }; // struct DownloadObjectArgs
  117. struct GetObjectArgs : public ObjectConditionalReadArgs {
  118. http::DataFunction datafunc;
  119. void *userdata = NULL;
  120. http::ProgressFunction progressfunc = NULL;
  121. void *progress_userdata = NULL;
  122. error::Error Validate();
  123. }; // struct GetObjectArgs
  124. struct ListObjectsArgs : public BucketArgs {
  125. std::string delimiter;
  126. bool use_url_encoding_type = true;
  127. std::string marker; // only for ListObjectsV1.
  128. std::string start_after; // only for ListObjectsV2.
  129. std::string key_marker; // only for GetObjectVersions.
  130. unsigned int max_keys = 1000;
  131. std::string prefix;
  132. std::string continuation_token; // only for ListObjectsV2.
  133. bool fetch_owner = false; // only for ListObjectsV2.
  134. std::string version_id_marker; // only for GetObjectVersions.
  135. bool include_user_metadata = false; // MinIO extension for ListObjectsV2.
  136. bool recursive = false;
  137. bool use_api_v1 = false;
  138. bool include_versions = false;
  139. }; // struct ListObjectsArgs
  140. struct ListObjectsCommonArgs : public BucketArgs {
  141. std::string delimiter;
  142. std::string encoding_type;
  143. unsigned int max_keys = 1000;
  144. std::string prefix;
  145. }; // struct ListObjectsCommonArgs
  146. struct ListObjectsV1Args : public ListObjectsCommonArgs {
  147. std::string marker;
  148. ListObjectsV1Args();
  149. ListObjectsV1Args(ListObjectsArgs args);
  150. }; // struct ListObjectsV1Args
  151. struct ListObjectsV2Args : public ListObjectsCommonArgs {
  152. std::string start_after;
  153. std::string continuation_token;
  154. bool fetch_owner;
  155. bool include_user_metadata;
  156. ListObjectsV2Args();
  157. ListObjectsV2Args(ListObjectsArgs args);
  158. }; // struct ListObjectsV2Args
  159. struct ListObjectVersionsArgs : public ListObjectsCommonArgs {
  160. std::string key_marker;
  161. std::string version_id_marker;
  162. ListObjectVersionsArgs();
  163. ListObjectVersionsArgs(ListObjectsArgs args);
  164. }; // struct ListObjectVersionsArgs
  165. struct PutObjectArgs : public PutObjectBaseArgs {
  166. std::istream &stream;
  167. http::ProgressFunction progressfunc = NULL;
  168. void *progress_userdata = NULL;
  169. PutObjectArgs(std::istream &stream, long object_size, long part_size);
  170. error::Error Validate();
  171. }; // struct PutObjectArgs
  172. using CopySource = ObjectConditionalReadArgs;
  173. struct CopyObjectArgs : public ObjectWriteArgs {
  174. CopySource source;
  175. Directive *metadata_directive = NULL;
  176. Directive *tagging_directive = NULL;
  177. error::Error Validate();
  178. }; // struct CopyObjectArgs
  179. struct ComposeSource : public ObjectConditionalReadArgs {
  180. error::Error BuildHeaders(size_t object_size, std::string &etag);
  181. size_t ObjectSize();
  182. utils::Multimap Headers();
  183. private:
  184. long object_size_ = -1;
  185. utils::Multimap headers_;
  186. }; // struct ComposeSource
  187. struct ComposeObjectArgs : public ObjectWriteArgs {
  188. std::list<ComposeSource> sources;
  189. error::Error Validate();
  190. }; // struct ComposeObjectArgs
  191. struct UploadObjectArgs : public PutObjectBaseArgs {
  192. std::string filename;
  193. http::ProgressFunction progressfunc = NULL;
  194. void *progress_userdata = NULL;
  195. error::Error Validate();
  196. }; // struct UploadObjectArgs
  197. struct RemoveObjectsApiArgs : public BucketArgs {
  198. bool bypass_governance_mode = false;
  199. bool quiet = true;
  200. std::list<DeleteObject> objects;
  201. }; // struct RemoveObjectsApiArgs
  202. using DeleteObjectFunction = std::function<bool(DeleteObject &)>;
  203. struct RemoveObjectsArgs : public BucketArgs {
  204. bool bypass_governance_mode = false;
  205. DeleteObjectFunction func = NULL;
  206. error::Error Validate();
  207. }; // struct RemoveObjectsArgs
  208. struct SelectObjectContentArgs : public ObjectReadArgs {
  209. SelectRequest &request;
  210. SelectResultFunction resultfunc = NULL;
  211. SelectObjectContentArgs(SelectRequest &req, SelectResultFunction func)
  212. : request(req), resultfunc(func) {}
  213. error::Error Validate();
  214. }; // struct SelectObjectContentArgs
  215. struct ListenBucketNotificationArgs : public BucketArgs {
  216. std::string prefix;
  217. std::string suffix;
  218. std::list<std::string> events;
  219. NotificationRecordsFunction func = NULL;
  220. error::Error Validate();
  221. }; // struct ListenBucketNotificationArgs
  222. using DeleteBucketPolicyArgs = BucketArgs;
  223. using GetBucketPolicyArgs = BucketArgs;
  224. struct SetBucketPolicyArgs : public BucketArgs {
  225. std::string policy;
  226. error::Error Validate();
  227. }; // struct SetBucketPolicy
  228. using DeleteBucketNotificationArgs = BucketArgs;
  229. using GetBucketNotificationArgs = BucketArgs;
  230. struct SetBucketNotificationArgs : public BucketArgs {
  231. NotificationConfig &config;
  232. SetBucketNotificationArgs(NotificationConfig &configvalue)
  233. : config(configvalue) {}
  234. }; // struct SetBucketNotification
  235. using DeleteBucketEncryptionArgs = BucketArgs;
  236. using GetBucketEncryptionArgs = BucketArgs;
  237. struct SetBucketEncryptionArgs : public BucketArgs {
  238. SseConfig &config;
  239. SetBucketEncryptionArgs(SseConfig &sseconfig) : config(sseconfig) {}
  240. error::Error Validate();
  241. }; // struct SetBucketEncryption
  242. using GetBucketVersioningArgs = BucketArgs;
  243. struct SetBucketVersioningArgs : public BucketArgs {
  244. Boolean status;
  245. Boolean mfa_delete;
  246. error::Error Validate();
  247. }; // struct SetBucketVersioning
  248. using DeleteBucketReplicationArgs = BucketArgs;
  249. using GetBucketReplicationArgs = BucketArgs;
  250. struct SetBucketReplicationArgs : public BucketArgs {
  251. ReplicationConfig &config;
  252. SetBucketReplicationArgs(ReplicationConfig &value) : config(value) {}
  253. }; // struct SetBucketReplication
  254. using DeleteBucketLifecycleArgs = BucketArgs;
  255. using GetBucketLifecycleArgs = BucketArgs;
  256. struct SetBucketLifecycleArgs : public BucketArgs {
  257. LifecycleConfig &config;
  258. SetBucketLifecycleArgs(LifecycleConfig &value) : config(value) {}
  259. }; // struct SetBucketLifecycle
  260. using DeleteBucketTagsArgs = BucketArgs;
  261. using GetBucketTagsArgs = BucketArgs;
  262. struct SetBucketTagsArgs : public BucketArgs {
  263. std::map<std::string, std::string> tags;
  264. error::Error Validate();
  265. }; // struct SetBucketTags
  266. using DeleteObjectLockConfigArgs = BucketArgs;
  267. using GetObjectLockConfigArgs = BucketArgs;
  268. struct SetObjectLockConfigArgs : public BucketArgs {
  269. ObjectLockConfig config;
  270. error::Error Validate();
  271. }; // struct SetObjectLockConfig
  272. using DeleteObjectTagsArgs = ObjectVersionArgs;
  273. using GetObjectTagsArgs = ObjectVersionArgs;
  274. struct SetObjectTagsArgs : public ObjectVersionArgs {
  275. std::map<std::string, std::string> tags;
  276. error::Error Validate();
  277. }; // struct SetObjectTags
  278. using EnableObjectLegalHoldArgs = ObjectVersionArgs;
  279. using DisableObjectLegalHoldArgs = ObjectVersionArgs;
  280. using IsObjectLegalHoldEnabledArgs = ObjectVersionArgs;
  281. using GetObjectRetentionArgs = ObjectVersionArgs;
  282. struct SetObjectRetentionArgs : public ObjectVersionArgs {
  283. RetentionMode retention_mode;
  284. utils::Time retain_until_date;
  285. error::Error Validate();
  286. }; // struct SetObjectRetention
  287. inline constexpr unsigned int kDefaultExpirySeconds =
  288. (60 * 60 * 24 * 7); // 7 days
  289. struct GetPresignedObjectUrlArgs : public ObjectVersionArgs {
  290. http::Method method;
  291. unsigned int expiry_seconds = kDefaultExpirySeconds;
  292. utils::Time request_time;
  293. error::Error Validate();
  294. }; // struct GetPresignedObjectUrlArgs
  295. struct PostPolicy {
  296. std::string bucket;
  297. std::string region;
  298. PostPolicy(std::string bucket, utils::Time expiration) {
  299. this->bucket = bucket;
  300. this->expiration_ = expiration;
  301. }
  302. operator bool() const { return !bucket.empty() && !expiration_; }
  303. error::Error AddEqualsCondition(std::string element, std::string value) {
  304. if (element.empty()) {
  305. return error::Error("condition element cannot be empty");
  306. }
  307. element = trimDollar(element);
  308. if (element == "success_action_redirect" || element == "redirect" ||
  309. element == "content-length-range") {
  310. return error::Error(element + " is unsupported for equals condition");
  311. }
  312. if (isReservedElement(element)) {
  313. return error::Error(element + " cannot be set");
  314. }
  315. conditions_[eq_][element] = value;
  316. return error::SUCCESS;
  317. }
  318. error::Error RemoveEqualsCondition(std::string element) {
  319. if (element.empty()) {
  320. return error::Error("condition element cannot be empty");
  321. }
  322. conditions_[eq_].erase(element);
  323. return error::SUCCESS;
  324. }
  325. error::Error AddStartsWithCondition(std::string element, std::string value) {
  326. if (element.empty()) {
  327. return error::Error("condition element cannot be empty");
  328. }
  329. element = trimDollar(element);
  330. if (element == "success_action_status" ||
  331. element == "content-length-range" ||
  332. (utils::StartsWith(element, "x-amz-") &&
  333. utils::StartsWith(element, "x-amz-meta-"))) {
  334. return error::Error(element +
  335. " is unsupported for starts-with condition");
  336. }
  337. if (isReservedElement(element)) {
  338. return error::Error(element + " cannot be set");
  339. }
  340. conditions_[starts_with_][element] = value;
  341. return error::SUCCESS;
  342. }
  343. error::Error RemoveStartsWithCondition(std::string element) {
  344. if (element.empty()) {
  345. return error::Error("condition element cannot be empty");
  346. }
  347. conditions_[starts_with_].erase(element);
  348. return error::SUCCESS;
  349. }
  350. error::Error AddContentLengthRangeCondition(size_t lower_limit,
  351. size_t upper_limit) {
  352. if (lower_limit > upper_limit) {
  353. return error::Error("lower limit cannot be greater than upper limit");
  354. }
  355. lower_limit_ = Integer(lower_limit);
  356. upper_limit_ = Integer(upper_limit);
  357. return error::SUCCESS;
  358. }
  359. void RemoveContentLengthRangeCondition() {
  360. lower_limit_ = Integer();
  361. upper_limit_ = Integer();
  362. }
  363. error::Error FormData(std::map<std::string, std::string> &data,
  364. std::string access_key, std::string secret_key,
  365. std::string session_token, std::string region) {
  366. if (region.empty()) return error::Error("region cannot be empty");
  367. if (conditions_[eq_]["key"].empty() &&
  368. conditions_[starts_with_]["key"].empty()) {
  369. return error::Error("key condition must be set");
  370. }
  371. nlohmann::json policy;
  372. policy["expiration"] = expiration_.ToISO8601UTC();
  373. nlohmann::json conditions = nlohmann::json::array();
  374. conditions.push_back({eq_, "$bucket", bucket});
  375. for (auto &[cond_key, cond] : conditions_) {
  376. for (auto &[key, value] : cond) {
  377. conditions.push_back({cond_key, "$" + key, value});
  378. }
  379. }
  380. if (lower_limit_ && upper_limit_) {
  381. conditions.push_back(
  382. {"content-length-range", lower_limit_.Get(), upper_limit_.Get()});
  383. }
  384. utils::Time date = utils::Time::Now();
  385. std::string credential = getCredentialString(access_key, date, region);
  386. std::string amz_date = date.ToAmzDate();
  387. conditions.push_back({eq_, "$x-amz-algorithm", algorithm_});
  388. conditions.push_back({eq_, "$x-amz-credential", credential});
  389. if (!session_token.empty()) {
  390. conditions.push_back({eq_, "$x-amz-security-token", session_token});
  391. }
  392. conditions.push_back({eq_, "$x-amz-date", amz_date});
  393. policy["conditions"] = conditions;
  394. std::string encoded_policy = utils::Base64Encode(policy.dump());
  395. std::string signature =
  396. signer::PostPresignV4(encoded_policy, secret_key, date, region);
  397. data["x-amz-algorithm"] = algorithm_;
  398. data["x-amz-credential"] = credential;
  399. data["x-amz-date"] = amz_date;
  400. data["policy"] = encoded_policy;
  401. data["x-amz-signature"] = signature;
  402. if (!session_token.empty()) {
  403. data["x-amz-security-token"] = session_token;
  404. }
  405. return error::SUCCESS;
  406. }
  407. private:
  408. static constexpr const char *eq_ = "eq";
  409. static constexpr const char *starts_with_ = "starts-with";
  410. static constexpr const char *algorithm_ = "AWS4-HMAC-SHA256";
  411. utils::Time expiration_;
  412. std::map<std::string, std::map<std::string, std::string>> conditions_;
  413. Integer lower_limit_;
  414. Integer upper_limit_;
  415. static std::string trimDollar(std::string value) {
  416. if (value.front() == '$') value.erase(0, 1);
  417. return value;
  418. }
  419. static std::string getCredentialString(std::string access_key,
  420. utils::Time date, std::string region) {
  421. return access_key + "/" + date.ToSignerDate() + "/" + region +
  422. "/s3/aws4_request";
  423. }
  424. static bool isReservedElement(std::string element) {
  425. return element == "bucket" || element == "x-amz-algorithm" ||
  426. element == "x-amz-credential" || element == "x-amz-date" ||
  427. element == "policy" || element == "x-amz-signature";
  428. }
  429. }; // struct PostPolicy
  430. } // namespace s3
  431. } // namespace minio
  432. #endif // #ifndef __MINIO_S3_ARGS_H