s3_request_messages.c 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include "aws/s3/private/s3_request_messages.h"
  6. #include "aws/s3/private/s3_checksums.h"
  7. #include "aws/s3/private/s3_client_impl.h"
  8. #include "aws/s3/private/s3_meta_request_impl.h"
  9. #include "aws/s3/private/s3_util.h"
  10. #include <aws/cal/hash.h>
  11. #include <aws/common/byte_buf.h>
  12. #include <aws/common/encoding.h>
  13. #include <aws/common/string.h>
  14. #include <aws/http/request_response.h>
  15. #include <aws/io/stream.h>
  16. #include <aws/io/uri.h>
  17. #include <aws/s3/s3.h>
  18. #include <inttypes.h>
  19. const struct aws_byte_cursor g_s3_create_multipart_upload_excluded_headers[] = {
  20. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Length"),
  21. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-MD5"),
  22. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-copy-source"),
  23. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-copy-source-range"),
  24. };
  25. const size_t g_s3_create_multipart_upload_excluded_headers_count =
  26. AWS_ARRAY_SIZE(g_s3_create_multipart_upload_excluded_headers);
  27. const struct aws_byte_cursor g_s3_upload_part_excluded_headers[] = {
  28. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-acl"),
  29. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Cache-Control"),
  30. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Disposition"),
  31. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Encoding"),
  32. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Language"),
  33. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Length"),
  34. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-MD5"),
  35. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Type"),
  36. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Expires"),
  37. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-full-control"),
  38. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-read"),
  39. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-read-acp"),
  40. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-write-acp"),
  41. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption"),
  42. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-storage-class"),
  43. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-website-redirect-location"),
  44. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-aws-kms-key-id"),
  45. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-context"),
  46. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-bucket-key-enabled"),
  47. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-tagging"),
  48. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-object-lock-mode"),
  49. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-object-lock-retain-until-date"),
  50. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-object-lock-legal-hold"),
  51. };
  52. const size_t g_s3_upload_part_excluded_headers_count = AWS_ARRAY_SIZE(g_s3_upload_part_excluded_headers);
  53. const struct aws_byte_cursor g_s3_complete_multipart_upload_excluded_headers[] = {
  54. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-acl"),
  55. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Cache-Control"),
  56. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Disposition"),
  57. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Encoding"),
  58. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Language"),
  59. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Length"),
  60. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-MD5"),
  61. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Type"),
  62. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Expires"),
  63. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-full-control"),
  64. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-read"),
  65. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-read-acp"),
  66. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-write-acp"),
  67. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption"),
  68. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-storage-class"),
  69. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-website-redirect-location"),
  70. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-customer-algorithm"),
  71. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-customer-key"),
  72. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-customer-key-MD5"),
  73. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-aws-kms-key-id"),
  74. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-context"),
  75. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-bucket-key-enabled"),
  76. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-tagging"),
  77. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-object-lock-mode"),
  78. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-object-lock-retain-until-date"),
  79. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-object-lock-legal-hold"),
  80. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-copy-source"),
  81. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-copy-source-range"),
  82. };
  83. const size_t g_s3_complete_multipart_upload_excluded_headers_count =
  84. AWS_ARRAY_SIZE(g_s3_complete_multipart_upload_excluded_headers);
  85. /* The server-side encryption (SSE) is needed only when the object was created using a checksum algorithm for complete
  86. * multipart upload. */
  87. const struct aws_byte_cursor g_s3_complete_multipart_upload_with_checksum_excluded_headers[] = {
  88. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-acl"),
  89. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Cache-Control"),
  90. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Disposition"),
  91. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Encoding"),
  92. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Language"),
  93. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Length"),
  94. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-MD5"),
  95. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Type"),
  96. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Expires"),
  97. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-full-control"),
  98. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-read"),
  99. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-read-acp"),
  100. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-write-acp"),
  101. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption"),
  102. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-storage-class"),
  103. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-website-redirect-location"),
  104. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-aws-kms-key-id"),
  105. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-context"),
  106. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-bucket-key-enabled"),
  107. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-tagging"),
  108. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-object-lock-mode"),
  109. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-object-lock-retain-until-date"),
  110. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-object-lock-legal-hold"),
  111. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-copy-source"),
  112. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-copy-source-range"),
  113. };
  114. const struct aws_byte_cursor g_s3_list_parts_excluded_headers[] = {
  115. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-acl"),
  116. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Cache-Control"),
  117. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Disposition"),
  118. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Encoding"),
  119. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Language"),
  120. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Length"),
  121. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-MD5"),
  122. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Type"),
  123. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Expires"),
  124. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-full-control"),
  125. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-read"),
  126. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-read-acp"),
  127. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-write-acp"),
  128. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption"),
  129. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-storage-class"),
  130. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-website-redirect-location"),
  131. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-customer-algorithm"),
  132. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-customer-key"),
  133. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-customer-key-MD5"),
  134. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-aws-kms-key-id"),
  135. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-context"),
  136. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-bucket-key-enabled"),
  137. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-tagging"),
  138. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-object-lock-mode"),
  139. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-object-lock-retain-until-date"),
  140. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-object-lock-legal-hold"),
  141. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-copy-source"),
  142. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-copy-source-range"),
  143. };
  144. const size_t g_s3_list_parts_excluded_headers_count = AWS_ARRAY_SIZE(g_s3_list_parts_excluded_headers);
  145. const struct aws_byte_cursor g_s3_list_parts_with_checksum_excluded_headers[] = {
  146. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-acl"),
  147. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Cache-Control"),
  148. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Disposition"),
  149. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Encoding"),
  150. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Language"),
  151. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Length"),
  152. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-MD5"),
  153. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Type"),
  154. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Expires"),
  155. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-full-control"),
  156. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-read"),
  157. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-read-acp"),
  158. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-write-acp"),
  159. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption"),
  160. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-storage-class"),
  161. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-website-redirect-location"),
  162. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-aws-kms-key-id"),
  163. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-context"),
  164. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-bucket-key-enabled"),
  165. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-tagging"),
  166. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-object-lock-mode"),
  167. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-object-lock-retain-until-date"),
  168. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-object-lock-legal-hold"),
  169. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-copy-source"),
  170. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-copy-source-range"),
  171. };
  172. const size_t g_s3_list_parts_with_checksum_excluded_headers_count =
  173. AWS_ARRAY_SIZE(g_s3_list_parts_with_checksum_excluded_headers);
  174. const struct aws_byte_cursor g_s3_abort_multipart_upload_excluded_headers[] = {
  175. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-acl"),
  176. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Cache-Control"),
  177. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Disposition"),
  178. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Encoding"),
  179. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Language"),
  180. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Length"),
  181. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-MD5"),
  182. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Type"),
  183. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Expires"),
  184. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-full-control"),
  185. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-read"),
  186. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-read-acp"),
  187. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-write-acp"),
  188. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption"),
  189. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-storage-class"),
  190. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-website-redirect-location"),
  191. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-customer-algorithm"),
  192. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-customer-key"),
  193. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-customer-key-MD5"),
  194. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-aws-kms-key-id"),
  195. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-context"),
  196. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-bucket-key-enabled"),
  197. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-tagging"),
  198. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-object-lock-mode"),
  199. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-object-lock-retain-until-date"),
  200. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-object-lock-legal-hold"),
  201. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-copy-source"),
  202. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-copy-source-range"),
  203. };
  204. static const struct aws_byte_cursor s_x_amz_meta_prefix = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-meta-");
  205. const size_t g_s3_abort_multipart_upload_excluded_headers_count =
  206. AWS_ARRAY_SIZE(g_s3_abort_multipart_upload_excluded_headers);
  207. static void s_s3_message_util_add_range_header(
  208. uint64_t part_range_start,
  209. uint64_t part_range_end,
  210. struct aws_http_message *out_message);
  211. /* Create a new get object request from an existing get object request. Currently just adds an optional ranged header.
  212. */
  213. struct aws_http_message *aws_s3_ranged_get_object_message_new(
  214. struct aws_allocator *allocator,
  215. struct aws_http_message *base_message,
  216. uint64_t range_start,
  217. uint64_t range_end) {
  218. AWS_PRECONDITION(allocator);
  219. AWS_PRECONDITION(base_message);
  220. struct aws_http_message *message =
  221. aws_s3_message_util_copy_http_message_no_body_all_headers(allocator, base_message);
  222. if (message == NULL) {
  223. return NULL;
  224. }
  225. s_s3_message_util_add_range_header(range_start, range_end, message);
  226. return message;
  227. }
  228. /* Creates a create-multipart-upload request from a given put objet request. */
  229. struct aws_http_message *aws_s3_create_multipart_upload_message_new(
  230. struct aws_allocator *allocator,
  231. struct aws_http_message *base_message,
  232. enum aws_s3_checksum_algorithm algorithm) {
  233. AWS_PRECONDITION(allocator);
  234. /* For multipart upload, some headers should ONLY be in the initial create-multipart request.
  235. * Headers such as:
  236. * - SSE related headers
  237. * - user metadata (prefixed "x-amz-meta-") headers */
  238. struct aws_http_message *message = aws_s3_message_util_copy_http_message_no_body_filter_headers(
  239. allocator,
  240. base_message,
  241. g_s3_create_multipart_upload_excluded_headers,
  242. AWS_ARRAY_SIZE(g_s3_create_multipart_upload_excluded_headers),
  243. false /*exclude_x_amz_meta*/);
  244. if (message == NULL) {
  245. return NULL;
  246. }
  247. if (aws_s3_message_util_set_multipart_request_path(allocator, NULL, 0, true, message)) {
  248. goto error_clean_up;
  249. }
  250. struct aws_http_headers *headers = aws_http_message_get_headers(message);
  251. if (headers == NULL) {
  252. goto error_clean_up;
  253. }
  254. if (aws_http_headers_erase(headers, g_content_md5_header_name)) {
  255. if (aws_last_error_or_unknown() != AWS_ERROR_HTTP_HEADER_NOT_FOUND) {
  256. goto error_clean_up;
  257. }
  258. }
  259. if (algorithm) {
  260. if (aws_http_headers_set(
  261. headers,
  262. g_create_mpu_checksum_header_name,
  263. *aws_get_create_mpu_header_name_from_algorithm(algorithm))) {
  264. goto error_clean_up;
  265. }
  266. }
  267. aws_http_message_set_request_method(message, g_post_method);
  268. aws_http_message_set_body_stream(message, NULL);
  269. return message;
  270. error_clean_up:
  271. aws_http_message_release(message);
  272. return NULL;
  273. }
  274. /* Create a new put object request from an existing put object request. Currently just optionally adds part information
  275. * for a multipart upload. */
  276. struct aws_http_message *aws_s3_upload_part_message_new(
  277. struct aws_allocator *allocator,
  278. struct aws_http_message *base_message,
  279. struct aws_byte_buf *buffer,
  280. uint32_t part_number,
  281. const struct aws_string *upload_id,
  282. bool should_compute_content_md5,
  283. const struct checksum_config *checksum_config,
  284. struct aws_byte_buf *encoded_checksum_output) {
  285. AWS_PRECONDITION(allocator);
  286. AWS_PRECONDITION(base_message);
  287. AWS_PRECONDITION(part_number > 0);
  288. AWS_PRECONDITION(buffer);
  289. struct aws_http_message *message = aws_s3_message_util_copy_http_message_no_body_filter_headers(
  290. allocator,
  291. base_message,
  292. g_s3_upload_part_excluded_headers,
  293. AWS_ARRAY_SIZE(g_s3_upload_part_excluded_headers),
  294. true /*exclude_x_amz_meta*/);
  295. if (message == NULL) {
  296. return NULL;
  297. }
  298. if (aws_s3_message_util_set_multipart_request_path(allocator, upload_id, part_number, false, message)) {
  299. goto error_clean_up;
  300. }
  301. if (aws_s3_message_util_assign_body(allocator, buffer, message, checksum_config, encoded_checksum_output) == NULL) {
  302. goto error_clean_up;
  303. }
  304. if (should_compute_content_md5) {
  305. if (!checksum_config || checksum_config->location == AWS_SCL_NONE) {
  306. /* MD5 will be skiped if flexible checksum used */
  307. if (aws_s3_message_util_add_content_md5_header(allocator, buffer, message)) {
  308. goto error_clean_up;
  309. }
  310. }
  311. }
  312. return message;
  313. error_clean_up:
  314. aws_http_message_release(message);
  315. return NULL;
  316. }
  317. struct aws_http_message *aws_s3_upload_part_copy_message_new(
  318. struct aws_allocator *allocator,
  319. struct aws_http_message *base_message,
  320. struct aws_byte_buf *buffer,
  321. uint32_t part_number,
  322. uint64_t range_start,
  323. uint64_t range_end,
  324. const struct aws_string *upload_id,
  325. bool should_compute_content_md5) {
  326. AWS_PRECONDITION(allocator);
  327. AWS_PRECONDITION(base_message);
  328. AWS_PRECONDITION(part_number > 0);
  329. struct aws_http_message *message = aws_s3_message_util_copy_http_message_no_body_filter_headers(
  330. allocator,
  331. base_message,
  332. g_s3_upload_part_excluded_headers,
  333. AWS_ARRAY_SIZE(g_s3_upload_part_excluded_headers),
  334. true /*exclude_x_amz_meta*/);
  335. if (message == NULL) {
  336. goto error_clean_up;
  337. }
  338. if (aws_s3_message_util_set_multipart_request_path(allocator, upload_id, part_number, false, message)) {
  339. goto error_clean_up;
  340. }
  341. if (buffer != NULL) {
  342. /* part copy does not have a ChecksumAlgorithm member, it will use the same algorithm as the create
  343. * multipart upload request specifies */
  344. if (aws_s3_message_util_assign_body(
  345. allocator, buffer, message, NULL /* checksum_config */, NULL /* out_checksum */) == NULL) {
  346. goto error_clean_up;
  347. }
  348. if (should_compute_content_md5) {
  349. if (aws_s3_message_util_add_content_md5_header(allocator, buffer, message)) {
  350. goto error_clean_up;
  351. }
  352. }
  353. }
  354. char source_range[1024];
  355. snprintf(source_range, sizeof(source_range), "bytes=%" PRIu64 "-%" PRIu64, range_start, range_end);
  356. struct aws_http_header source_range_header = {
  357. .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-copy-source-range"),
  358. .value = aws_byte_cursor_from_c_str(source_range),
  359. };
  360. struct aws_http_headers *headers = aws_http_message_get_headers(message);
  361. aws_http_headers_add_header(headers, &source_range_header);
  362. return message;
  363. error_clean_up:
  364. if (message != NULL) {
  365. aws_http_message_release(message);
  366. message = NULL;
  367. }
  368. return NULL;
  369. }
  370. /* Creates a HEAD GetObject request to get the size of the specified object. */
  371. struct aws_http_message *aws_s3_get_object_size_message_new(
  372. struct aws_allocator *allocator,
  373. struct aws_http_message *base_message,
  374. struct aws_byte_cursor source_bucket,
  375. struct aws_byte_cursor source_key) {
  376. (void)base_message;
  377. AWS_PRECONDITION(allocator);
  378. struct aws_http_message *message = aws_http_message_new_request(allocator);
  379. if (message == NULL) {
  380. return NULL;
  381. }
  382. const struct aws_byte_cursor head_operation = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("HEAD");
  383. if (aws_http_message_set_request_method(message, head_operation)) {
  384. goto error_clean_up;
  385. }
  386. char destination_path[1024];
  387. snprintf(destination_path, sizeof(destination_path), "/%.*s", (int)source_key.len, source_key.ptr);
  388. /* TODO: url encode */
  389. if (aws_http_message_set_request_path(message, aws_byte_cursor_from_c_str(destination_path))) {
  390. goto error_clean_up;
  391. }
  392. char host_header_value[1024];
  393. /* TODO: Fix the hard-coded host name. */
  394. snprintf(
  395. host_header_value,
  396. sizeof(host_header_value),
  397. "%.*s.s3.us-west-2.amazonaws.com",
  398. (int)source_bucket.len,
  399. source_bucket.ptr);
  400. struct aws_http_header host_header = {
  401. .name = g_host_header_name,
  402. .value = aws_byte_cursor_from_c_str(host_header_value),
  403. };
  404. aws_http_message_add_header(message, host_header);
  405. aws_http_message_set_body_stream(message, NULL);
  406. return message;
  407. error_clean_up:
  408. if (message != NULL) {
  409. aws_http_message_release(message);
  410. message = NULL;
  411. }
  412. return NULL;
  413. }
  414. /* Creates a HEAD GetObject sub-request to get the size of the source object of a Copy meta request. */
  415. struct aws_http_message *aws_s3_get_source_object_size_message_new(
  416. struct aws_allocator *allocator,
  417. struct aws_http_message *base_message) {
  418. AWS_PRECONDITION(allocator);
  419. struct aws_http_message *message = NULL;
  420. /* find the x-amz-copy-source header */
  421. struct aws_http_headers *headers = aws_http_message_get_headers(base_message);
  422. struct aws_byte_cursor source_bucket;
  423. AWS_ZERO_STRUCT(source_bucket);
  424. const struct aws_byte_cursor copy_source_header = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-copy-source");
  425. if (aws_http_headers_get(headers, copy_source_header, &source_bucket) != AWS_OP_SUCCESS) {
  426. AWS_LOGF_ERROR(AWS_LS_S3_GENERAL, "CopyRequest is missing the x-amz-copy-source header");
  427. return NULL;
  428. }
  429. if (source_bucket.len > 1 && source_bucket.ptr[0] == '/') {
  430. /* skip the leading slash */
  431. aws_byte_cursor_advance(&source_bucket, 1);
  432. }
  433. /* as we skipped the optional leading slash, from this point source format is always {bucket}/{key}. split them.
  434. */
  435. struct aws_byte_cursor source_key = source_bucket;
  436. while (source_key.len > 0) {
  437. if (*source_key.ptr == '/') {
  438. source_bucket.len = source_key.ptr - source_bucket.ptr;
  439. aws_byte_cursor_advance(&source_key, 1); /* skip the / between bucket and key */
  440. break;
  441. }
  442. aws_byte_cursor_advance(&source_key, 1);
  443. }
  444. if (source_bucket.len == 0 || source_key.len == 0) {
  445. AWS_LOGF_ERROR(
  446. AWS_LS_S3_GENERAL,
  447. "The CopyRequest x-amz-copy-source header must contain the bucket and object key separated by a slash");
  448. goto error_cleanup;
  449. }
  450. message = aws_s3_get_object_size_message_new(allocator, base_message, source_bucket, source_key);
  451. error_cleanup:
  452. return message;
  453. }
  454. static const struct aws_byte_cursor s_complete_payload_begin = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(
  455. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  456. "<CompleteMultipartUpload xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">\n");
  457. static const struct aws_byte_cursor s_complete_payload_end =
  458. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("</CompleteMultipartUpload>");
  459. static const struct aws_byte_cursor s_part_section_string_0 = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(" <Part>\n"
  460. " <ETag>");
  461. static const struct aws_byte_cursor s_part_section_string_1 =
  462. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("</ETag>\n"
  463. " <PartNumber>");
  464. static const struct aws_byte_cursor s_close_part_number_tag = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("</PartNumber>\n");
  465. static const struct aws_byte_cursor s_close_part_tag = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(" </Part>\n");
  466. static const struct aws_byte_cursor s_open_start_bracket = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(" <");
  467. static const struct aws_byte_cursor s_open_end_bracket = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("</");
  468. static const struct aws_byte_cursor s_close_bracket = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(">");
  469. static const struct aws_byte_cursor s_close_bracket_new_line = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(">\n");
  470. /* Create a complete-multipart message, which includes an XML payload of all completed parts. */
  471. struct aws_http_message *aws_s3_complete_multipart_message_new(
  472. struct aws_allocator *allocator,
  473. struct aws_http_message *base_message,
  474. struct aws_byte_buf *body_buffer,
  475. const struct aws_string *upload_id,
  476. const struct aws_array_list *etags,
  477. struct aws_byte_buf *checksums,
  478. enum aws_s3_checksum_algorithm algorithm) {
  479. AWS_PRECONDITION(allocator);
  480. AWS_PRECONDITION(base_message);
  481. AWS_PRECONDITION(body_buffer);
  482. AWS_PRECONDITION(upload_id);
  483. AWS_PRECONDITION(etags);
  484. const struct aws_byte_cursor *mpu_algorithm_checksum_name = aws_get_complete_mpu_name_from_algorithm(algorithm);
  485. struct aws_http_message *message = NULL;
  486. if (algorithm == AWS_SCA_NONE) {
  487. /* We don't need to worry about the pre-calculated checksum from user as for multipart upload, only way to
  488. * calculate checksum is from client. */
  489. message = aws_s3_message_util_copy_http_message_no_body_filter_headers(
  490. allocator,
  491. base_message,
  492. g_s3_complete_multipart_upload_excluded_headers,
  493. AWS_ARRAY_SIZE(g_s3_complete_multipart_upload_excluded_headers),
  494. true /*exclude_x_amz_meta*/);
  495. } else {
  496. message = aws_s3_message_util_copy_http_message_no_body_filter_headers(
  497. allocator,
  498. base_message,
  499. g_s3_complete_multipart_upload_with_checksum_excluded_headers,
  500. AWS_ARRAY_SIZE(g_s3_complete_multipart_upload_with_checksum_excluded_headers),
  501. true /*exclude_x_amz_meta*/);
  502. }
  503. struct aws_http_headers *headers = NULL;
  504. if (message == NULL) {
  505. goto error_clean_up;
  506. }
  507. if (aws_s3_message_util_set_multipart_request_path(allocator, upload_id, 0, false, message)) {
  508. goto error_clean_up;
  509. }
  510. aws_http_message_set_request_method(message, g_post_method);
  511. headers = aws_http_message_get_headers(message);
  512. if (headers == NULL) {
  513. goto error_clean_up;
  514. }
  515. /* Create XML payload with all of the etags of finished parts */
  516. {
  517. aws_byte_buf_reset(body_buffer, false);
  518. if (aws_byte_buf_append_dynamic(body_buffer, &s_complete_payload_begin)) {
  519. goto error_clean_up;
  520. }
  521. for (size_t etag_index = 0; etag_index < aws_array_list_length(etags); ++etag_index) {
  522. struct aws_string *etag = NULL;
  523. aws_array_list_get_at(etags, &etag, etag_index);
  524. AWS_FATAL_ASSERT(etag != NULL);
  525. if (aws_byte_buf_append_dynamic(body_buffer, &s_part_section_string_0)) {
  526. goto error_clean_up;
  527. }
  528. struct aws_byte_cursor etag_byte_cursor = aws_byte_cursor_from_string(etag);
  529. if (aws_byte_buf_append_dynamic(body_buffer, &etag_byte_cursor)) {
  530. goto error_clean_up;
  531. }
  532. if (aws_byte_buf_append_dynamic(body_buffer, &s_part_section_string_1)) {
  533. goto error_clean_up;
  534. }
  535. char part_number_buffer[32] = "";
  536. int part_number = (int)(etag_index + 1);
  537. int part_number_num_char = snprintf(part_number_buffer, sizeof(part_number_buffer), "%d", part_number);
  538. struct aws_byte_cursor part_number_byte_cursor =
  539. aws_byte_cursor_from_array(part_number_buffer, part_number_num_char);
  540. if (aws_byte_buf_append_dynamic(body_buffer, &part_number_byte_cursor)) {
  541. goto error_clean_up;
  542. }
  543. if (aws_byte_buf_append_dynamic(body_buffer, &s_close_part_number_tag)) {
  544. goto error_clean_up;
  545. }
  546. if (mpu_algorithm_checksum_name) {
  547. struct aws_byte_cursor checksum = aws_byte_cursor_from_buf(&checksums[etag_index]);
  548. if (aws_byte_buf_append_dynamic(body_buffer, &s_open_start_bracket)) {
  549. goto error_clean_up;
  550. }
  551. if (aws_byte_buf_append_dynamic(body_buffer, mpu_algorithm_checksum_name)) {
  552. goto error_clean_up;
  553. }
  554. if (aws_byte_buf_append_dynamic(body_buffer, &s_close_bracket)) {
  555. goto error_clean_up;
  556. }
  557. if (aws_byte_buf_append_dynamic(body_buffer, &checksum)) {
  558. goto error_clean_up;
  559. }
  560. if (aws_byte_buf_append_dynamic(body_buffer, &s_open_end_bracket)) {
  561. goto error_clean_up;
  562. }
  563. if (aws_byte_buf_append_dynamic(body_buffer, mpu_algorithm_checksum_name)) {
  564. goto error_clean_up;
  565. }
  566. if (aws_byte_buf_append_dynamic(body_buffer, &s_close_bracket_new_line)) {
  567. goto error_clean_up;
  568. }
  569. }
  570. if (aws_byte_buf_append_dynamic(body_buffer, &s_close_part_tag)) {
  571. goto error_clean_up;
  572. }
  573. }
  574. if (aws_byte_buf_append_dynamic(body_buffer, &s_complete_payload_end)) {
  575. goto error_clean_up;
  576. }
  577. aws_s3_message_util_assign_body(
  578. allocator, body_buffer, message, NULL /* checksum_config */, NULL /* out_checksum */);
  579. }
  580. return message;
  581. error_clean_up:
  582. AWS_LOGF_ERROR(AWS_LS_S3_GENERAL, "Could not create complete multipart message");
  583. if (message != NULL) {
  584. aws_http_message_release(message);
  585. message = NULL;
  586. }
  587. return NULL;
  588. }
  589. struct aws_http_message *aws_s3_abort_multipart_upload_message_new(
  590. struct aws_allocator *allocator,
  591. struct aws_http_message *base_message,
  592. const struct aws_string *upload_id) {
  593. struct aws_http_message *message = aws_s3_message_util_copy_http_message_no_body_filter_headers(
  594. allocator,
  595. base_message,
  596. g_s3_abort_multipart_upload_excluded_headers,
  597. AWS_ARRAY_SIZE(g_s3_abort_multipart_upload_excluded_headers),
  598. true /*exclude_x_amz_meta*/);
  599. if (aws_s3_message_util_set_multipart_request_path(allocator, upload_id, 0, false, message)) {
  600. goto error_clean_up;
  601. }
  602. aws_http_message_set_request_method(message, g_delete_method);
  603. return message;
  604. error_clean_up:
  605. AWS_LOGF_ERROR(AWS_LS_S3_GENERAL, "Could not create abort multipart upload message");
  606. if (message != NULL) {
  607. aws_http_message_release(message);
  608. message = NULL;
  609. }
  610. return NULL;
  611. }
  612. /* Assign a buffer to an HTTP message, creating a stream and setting the content-length header */
  613. struct aws_input_stream *aws_s3_message_util_assign_body(
  614. struct aws_allocator *allocator,
  615. struct aws_byte_buf *byte_buf,
  616. struct aws_http_message *out_message,
  617. const struct checksum_config *checksum_config,
  618. struct aws_byte_buf *out_checksum) {
  619. AWS_PRECONDITION(allocator);
  620. AWS_PRECONDITION(out_message);
  621. AWS_PRECONDITION(byte_buf);
  622. struct aws_byte_cursor buffer_byte_cursor = aws_byte_cursor_from_buf(byte_buf);
  623. struct aws_http_headers *headers = aws_http_message_get_headers(out_message);
  624. if (headers == NULL) {
  625. return NULL;
  626. }
  627. struct aws_input_stream *input_stream = aws_input_stream_new_from_cursor(allocator, &buffer_byte_cursor);
  628. if (input_stream == NULL) {
  629. goto error_clean_up;
  630. }
  631. if (checksum_config) {
  632. if (checksum_config->location == AWS_SCL_TRAILER) {
  633. /* aws-chunked encode the payload and add related headers */
  634. /* set Content-Encoding header. TODO: the aws-chunked should be appended to the existing content encoding.
  635. */
  636. if (aws_http_headers_set(headers, g_content_encoding_header_name, g_content_encoding_header_aws_chunked)) {
  637. goto error_clean_up;
  638. }
  639. /* set x-amz-trailer header */
  640. if (aws_http_headers_set(
  641. headers,
  642. g_trailer_header_name,
  643. *aws_get_http_header_name_from_algorithm(checksum_config->checksum_algorithm))) {
  644. goto error_clean_up;
  645. }
  646. /* set x-amz-decoded-content-length header */
  647. char decoded_content_length_buffer[64] = "";
  648. snprintf(
  649. decoded_content_length_buffer,
  650. sizeof(decoded_content_length_buffer),
  651. "%" PRIu64,
  652. (uint64_t)buffer_byte_cursor.len);
  653. struct aws_byte_cursor decode_content_length_cursor =
  654. aws_byte_cursor_from_array(decoded_content_length_buffer, strlen(decoded_content_length_buffer));
  655. if (aws_http_headers_set(headers, g_decoded_content_length_header_name, decode_content_length_cursor)) {
  656. goto error_clean_up;
  657. }
  658. /* set input stream to chunk stream */
  659. struct aws_input_stream *chunk_stream =
  660. aws_chunk_stream_new(allocator, input_stream, checksum_config->checksum_algorithm, out_checksum);
  661. if (!chunk_stream) {
  662. goto error_clean_up;
  663. }
  664. aws_input_stream_release(input_stream);
  665. input_stream = chunk_stream;
  666. }
  667. }
  668. int64_t stream_length = 0;
  669. if (aws_input_stream_get_length(input_stream, &stream_length)) {
  670. goto error_clean_up;
  671. }
  672. char content_length_buffer[64] = "";
  673. snprintf(content_length_buffer, sizeof(content_length_buffer), "%" PRIu64, (uint64_t)stream_length);
  674. struct aws_byte_cursor content_length_cursor =
  675. aws_byte_cursor_from_array(content_length_buffer, strlen(content_length_buffer));
  676. if (aws_http_headers_set(headers, g_content_length_header_name, content_length_cursor)) {
  677. goto error_clean_up;
  678. }
  679. aws_http_message_set_body_stream(out_message, input_stream);
  680. /* Let the message take the full ownership */
  681. aws_input_stream_release(input_stream);
  682. return input_stream;
  683. error_clean_up:
  684. AWS_LOGF_ERROR(AWS_LS_S3_CLIENT, "Failed to assign body for s3 request http message, from body buffer .");
  685. aws_input_stream_release(input_stream);
  686. return NULL;
  687. }
  688. bool aws_s3_message_util_check_checksum_header(struct aws_http_message *message) {
  689. struct aws_http_headers *headers = aws_http_message_get_headers(message);
  690. for (int algorithm = AWS_SCA_INIT; algorithm <= AWS_SCA_END; algorithm++) {
  691. const struct aws_byte_cursor *algorithm_header_name = aws_get_http_header_name_from_algorithm(algorithm);
  692. if (aws_http_headers_has(headers, *algorithm_header_name)) {
  693. return true;
  694. }
  695. }
  696. return false;
  697. }
  698. /* Add a content-md5 header. */
  699. int aws_s3_message_util_add_content_md5_header(
  700. struct aws_allocator *allocator,
  701. struct aws_byte_buf *input_buf,
  702. struct aws_http_message *out_message) {
  703. AWS_PRECONDITION(out_message);
  704. /* Compute MD5 */
  705. struct aws_byte_cursor md5_input = aws_byte_cursor_from_buf(input_buf);
  706. uint8_t md5_output[AWS_MD5_LEN];
  707. struct aws_byte_buf md5_output_buf = aws_byte_buf_from_empty_array(md5_output, sizeof(md5_output));
  708. if (aws_md5_compute(allocator, &md5_input, &md5_output_buf, 0)) {
  709. return AWS_OP_ERR;
  710. }
  711. /* Compute Base64 encoding of MD5 */
  712. struct aws_byte_cursor base64_input = aws_byte_cursor_from_buf(&md5_output_buf);
  713. size_t base64_output_size = 0;
  714. if (aws_base64_compute_encoded_len(md5_output_buf.len, &base64_output_size)) {
  715. return AWS_OP_ERR;
  716. }
  717. struct aws_byte_buf base64_output_buf;
  718. if (aws_byte_buf_init(&base64_output_buf, allocator, base64_output_size)) {
  719. return AWS_OP_ERR;
  720. }
  721. if (aws_base64_encode(&base64_input, &base64_output_buf)) {
  722. goto error_clean_up;
  723. }
  724. struct aws_http_headers *headers = aws_http_message_get_headers(out_message);
  725. if (aws_http_headers_set(headers, g_content_md5_header_name, aws_byte_cursor_from_buf(&base64_output_buf))) {
  726. goto error_clean_up;
  727. }
  728. aws_byte_buf_clean_up(&base64_output_buf);
  729. return AWS_OP_SUCCESS;
  730. error_clean_up:
  731. aws_byte_buf_clean_up(&base64_output_buf);
  732. return AWS_OP_ERR;
  733. }
  734. /* Copy an existing HTTP message's headers, method, and path. */
  735. struct aws_http_message *aws_s3_message_util_copy_http_message_no_body_all_headers(
  736. struct aws_allocator *allocator,
  737. struct aws_http_message *base_message) {
  738. return aws_s3_message_util_copy_http_message_no_body_filter_headers(allocator, base_message, NULL, 0, false);
  739. }
  740. struct aws_http_message *aws_s3_message_util_copy_http_message_no_body_filter_headers(
  741. struct aws_allocator *allocator,
  742. struct aws_http_message *base_message,
  743. const struct aws_byte_cursor *excluded_header_array,
  744. size_t excluded_header_array_size,
  745. bool exclude_x_amz_meta) {
  746. AWS_PRECONDITION(allocator);
  747. AWS_PRECONDITION(base_message);
  748. struct aws_http_message *message = aws_http_message_new_request(allocator);
  749. AWS_ASSERT(message);
  750. struct aws_byte_cursor request_method;
  751. if (aws_http_message_get_request_method(base_message, &request_method)) {
  752. AWS_LOGF_ERROR(AWS_LS_S3_CLIENT, "Failed to get request method.");
  753. goto error_clean_up;
  754. }
  755. if (aws_http_message_set_request_method(message, request_method)) {
  756. goto error_clean_up;
  757. }
  758. struct aws_byte_cursor request_path;
  759. if (aws_http_message_get_request_path(base_message, &request_path)) {
  760. AWS_LOGF_ERROR(AWS_LS_S3_CLIENT, "Failed to get request path.");
  761. goto error_clean_up;
  762. }
  763. if (aws_http_message_set_request_path(message, request_path)) {
  764. goto error_clean_up;
  765. }
  766. aws_s3_message_util_copy_headers(
  767. base_message, message, excluded_header_array, excluded_header_array_size, exclude_x_amz_meta);
  768. return message;
  769. error_clean_up:
  770. aws_http_message_release(message);
  771. return NULL;
  772. }
  773. /* Copy message and retain all headers, but replace body with one that reads directly from a filepath. */
  774. struct aws_http_message *aws_s3_message_util_copy_http_message_filepath_body_all_headers(
  775. struct aws_allocator *allocator,
  776. struct aws_http_message *base_message,
  777. struct aws_byte_cursor filepath) {
  778. bool success = false;
  779. struct aws_string *filepath_str = NULL;
  780. struct aws_input_stream *body_stream = NULL;
  781. struct aws_http_message *message = NULL;
  782. /* Copy message and retain all headers */
  783. message = aws_s3_message_util_copy_http_message_no_body_filter_headers(
  784. allocator,
  785. base_message,
  786. NULL /*excluded_header_array*/,
  787. 0 /*excluded_header_array_size*/,
  788. false /*exclude_x_amz_meta*/);
  789. if (!message) {
  790. goto clean_up;
  791. }
  792. /* Create body-stream that reads from file */
  793. filepath_str = aws_string_new_from_cursor(allocator, &filepath);
  794. body_stream = aws_input_stream_new_from_file(allocator, aws_string_c_str(filepath_str));
  795. if (!body_stream) {
  796. goto clean_up;
  797. }
  798. aws_http_message_set_body_stream(message, body_stream);
  799. success = true;
  800. clean_up:
  801. aws_string_destroy(filepath_str);
  802. aws_input_stream_release(body_stream);
  803. if (success) {
  804. return message;
  805. } else {
  806. aws_http_message_release(message);
  807. return NULL;
  808. }
  809. }
  810. void aws_s3_message_util_copy_headers(
  811. struct aws_http_message *source_message,
  812. struct aws_http_message *dest_message,
  813. const struct aws_byte_cursor *excluded_header_array,
  814. size_t excluded_header_array_size,
  815. bool exclude_x_amz_meta) {
  816. size_t num_headers = aws_http_message_get_header_count(source_message);
  817. for (size_t header_index = 0; header_index < num_headers; ++header_index) {
  818. struct aws_http_header header;
  819. int error = aws_http_message_get_header(source_message, &header, header_index);
  820. if (excluded_header_array && excluded_header_array_size > 0) {
  821. bool exclude_header = false;
  822. for (size_t exclude_index = 0; exclude_index < excluded_header_array_size; ++exclude_index) {
  823. if (aws_byte_cursor_eq_ignore_case(&header.name, &excluded_header_array[exclude_index])) {
  824. exclude_header = true;
  825. break;
  826. }
  827. }
  828. if (exclude_header) {
  829. continue;
  830. }
  831. }
  832. if (exclude_x_amz_meta) {
  833. if (aws_byte_cursor_starts_with_ignore_case(&header.name, &s_x_amz_meta_prefix)) {
  834. continue;
  835. }
  836. }
  837. error |= aws_http_message_add_header(dest_message, header);
  838. (void)error;
  839. AWS_ASSERT(!error);
  840. }
  841. }
  842. /* Add a range header.*/
  843. static void s_s3_message_util_add_range_header(
  844. uint64_t part_range_start,
  845. uint64_t part_range_end,
  846. struct aws_http_message *out_message) {
  847. AWS_PRECONDITION(out_message);
  848. /* ((2^64)-1 = 20 characters; 2*20 + length-of("bytes=-") < 128) */
  849. char range_value_buffer[128] = "";
  850. snprintf(
  851. range_value_buffer, sizeof(range_value_buffer), "bytes=%" PRIu64 "-%" PRIu64, part_range_start, part_range_end);
  852. struct aws_http_header range_header;
  853. AWS_ZERO_STRUCT(range_header);
  854. range_header.name = g_range_header_name;
  855. range_header.value = aws_byte_cursor_from_c_str(range_value_buffer);
  856. struct aws_http_headers *headers = aws_http_message_get_headers(out_message);
  857. AWS_ASSERT(headers != NULL);
  858. int erase_result = aws_http_headers_erase(headers, range_header.name);
  859. AWS_ASSERT(erase_result == AWS_OP_SUCCESS || aws_last_error() == AWS_ERROR_HTTP_HEADER_NOT_FOUND);
  860. /* Only failed when the header has invalid name, which is impossible here. */
  861. erase_result = aws_http_message_add_header(out_message, range_header);
  862. AWS_ASSERT(erase_result == AWS_OP_SUCCESS);
  863. (void)erase_result;
  864. }
  865. /* Handle setting up the multipart request path for a message. */
  866. int aws_s3_message_util_set_multipart_request_path(
  867. struct aws_allocator *allocator,
  868. const struct aws_string *upload_id,
  869. uint32_t part_number,
  870. bool append_uploads_suffix,
  871. struct aws_http_message *message) {
  872. const struct aws_byte_cursor question_mark = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("?");
  873. const struct aws_byte_cursor ampersand = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("&");
  874. const struct aws_byte_cursor uploads_suffix = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("uploads");
  875. const struct aws_byte_cursor part_number_arg = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("partNumber=");
  876. const struct aws_byte_cursor upload_id_arg = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("uploadId=");
  877. struct aws_byte_buf request_path_buf;
  878. struct aws_byte_cursor request_path;
  879. if (aws_http_message_get_request_path(message, &request_path)) {
  880. return AWS_OP_ERR;
  881. }
  882. if (aws_byte_buf_init(&request_path_buf, allocator, request_path.len)) {
  883. return AWS_OP_ERR;
  884. }
  885. if (aws_byte_buf_append_dynamic(&request_path_buf, &request_path)) {
  886. goto error_clean_up;
  887. }
  888. bool has_existing_query_parameters = false;
  889. for (size_t i = 0; i < request_path.len; ++i) {
  890. if (request_path.ptr[i] == '?') {
  891. has_existing_query_parameters = true;
  892. break;
  893. }
  894. }
  895. if (part_number > 0) {
  896. if (aws_byte_buf_append_dynamic(
  897. &request_path_buf, has_existing_query_parameters ? &ampersand : &question_mark)) {
  898. goto error_clean_up;
  899. }
  900. if (aws_byte_buf_append_dynamic(&request_path_buf, &part_number_arg)) {
  901. goto error_clean_up;
  902. }
  903. char part_number_buffer[32] = "";
  904. snprintf(part_number_buffer, sizeof(part_number_buffer), "%d", part_number);
  905. struct aws_byte_cursor part_number_cursor =
  906. aws_byte_cursor_from_array(part_number_buffer, strlen(part_number_buffer));
  907. if (aws_byte_buf_append_dynamic(&request_path_buf, &part_number_cursor)) {
  908. goto error_clean_up;
  909. }
  910. has_existing_query_parameters = true;
  911. }
  912. if (upload_id != NULL) {
  913. struct aws_byte_cursor upload_id_cursor = aws_byte_cursor_from_string(upload_id);
  914. if (aws_byte_buf_append_dynamic(
  915. &request_path_buf, has_existing_query_parameters ? &ampersand : &question_mark)) {
  916. goto error_clean_up;
  917. }
  918. if (aws_byte_buf_append_dynamic(&request_path_buf, &upload_id_arg)) {
  919. goto error_clean_up;
  920. }
  921. if (aws_byte_buf_append_dynamic(&request_path_buf, &upload_id_cursor)) {
  922. goto error_clean_up;
  923. }
  924. has_existing_query_parameters = true;
  925. }
  926. if (append_uploads_suffix) {
  927. if (aws_byte_buf_append_dynamic(
  928. &request_path_buf, has_existing_query_parameters ? &ampersand : &question_mark)) {
  929. goto error_clean_up;
  930. }
  931. if (aws_byte_buf_append_dynamic(&request_path_buf, &uploads_suffix)) {
  932. goto error_clean_up;
  933. }
  934. has_existing_query_parameters = true;
  935. }
  936. struct aws_byte_cursor new_request_path = aws_byte_cursor_from_buf(&request_path_buf);
  937. if (aws_http_message_set_request_path(message, new_request_path)) {
  938. goto error_clean_up;
  939. }
  940. aws_byte_buf_clean_up(&request_path_buf);
  941. return AWS_OP_SUCCESS;
  942. error_clean_up:
  943. aws_byte_buf_clean_up(&request_path_buf);
  944. return AWS_OP_ERR;
  945. }