oss_multipart.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. #include "aos_log.h"
  2. #include "aos_define.h"
  3. #include "aos_util.h"
  4. #include "aos_string.h"
  5. #include "aos_status.h"
  6. #include "oss_auth.h"
  7. #include "oss_util.h"
  8. #include "oss_xml.h"
  9. #include "oss_api.h"
  10. aos_status_t *oss_init_multipart_upload(const oss_request_options_t *options,
  11. const aos_string_t *bucket,
  12. const aos_string_t *object,
  13. aos_string_t *upload_id,
  14. aos_table_t *headers,
  15. aos_table_t **resp_headers)
  16. {
  17. int res = AOSE_OK;
  18. aos_status_t *s = NULL;
  19. aos_http_request_t *req = NULL;
  20. aos_http_response_t *resp = NULL;
  21. aos_table_t *query_params = NULL;
  22. //init query_params
  23. query_params = aos_table_create_if_null(options, query_params, 1);
  24. apr_table_add(query_params, OSS_UPLOADS, "");
  25. //init headers
  26. headers = aos_table_create_if_null(options, headers, 1);
  27. set_content_type(NULL, object->data, headers);
  28. oss_init_object_request(options, bucket, object, HTTP_POST,
  29. &req, query_params, headers, NULL, 0, &resp);
  30. s = oss_process_request(options, req, resp);
  31. oss_fill_read_response_header(resp, resp_headers);
  32. if (!aos_status_is_ok(s)) {
  33. return s;
  34. }
  35. res = oss_upload_id_parse_from_body(options->pool, &resp->body, upload_id);
  36. if (res != AOSE_OK) {
  37. aos_xml_error_status_set(s, res);
  38. }
  39. return s;
  40. }
  41. aos_status_t *oss_abort_multipart_upload(const oss_request_options_t *options,
  42. const aos_string_t *bucket,
  43. const aos_string_t *object,
  44. aos_string_t *upload_id,
  45. aos_table_t **resp_headers)
  46. {
  47. aos_status_t *s = NULL;
  48. aos_http_request_t *req = NULL;
  49. aos_http_response_t *resp = NULL;
  50. aos_table_t *query_params = NULL;
  51. aos_table_t *headers = NULL;
  52. //init query_params
  53. query_params = aos_table_create_if_null(options, query_params, 1);
  54. apr_table_add(query_params, OSS_UPLOAD_ID, upload_id->data);
  55. //init headers
  56. headers = aos_table_create_if_null(options, headers, 0);
  57. oss_init_object_request(options, bucket, object, HTTP_DELETE,
  58. &req, query_params, headers, NULL, 0, &resp);
  59. s = oss_process_request(options, req, resp);
  60. oss_fill_read_response_header(resp, resp_headers);
  61. return s;
  62. }
  63. aos_status_t *oss_list_upload_part(const oss_request_options_t *options,
  64. const aos_string_t *bucket,
  65. const aos_string_t *object,
  66. const aos_string_t *upload_id,
  67. oss_list_upload_part_params_t *params,
  68. aos_table_t **resp_headers)
  69. {
  70. int res = AOSE_OK;
  71. aos_status_t *s = NULL;
  72. aos_http_request_t *req = NULL;
  73. aos_http_response_t *resp = NULL;
  74. aos_table_t *query_params = NULL;
  75. aos_table_t *headers = NULL;
  76. //init query_params
  77. query_params = aos_table_create_if_null(options, query_params, 3);
  78. apr_table_add(query_params, OSS_UPLOAD_ID, upload_id->data);
  79. aos_table_add_int(query_params, OSS_MAX_PARTS, params->max_ret);
  80. apr_table_add(query_params, OSS_PART_NUMBER_MARKER,
  81. params->part_number_marker.data);
  82. //init headers
  83. headers = aos_table_create_if_null(options, headers, 0);
  84. oss_init_object_request(options, bucket, object, HTTP_GET,
  85. &req, query_params, headers, NULL, 0, &resp);
  86. s = oss_process_request(options, req, resp);
  87. oss_fill_read_response_header(resp, resp_headers);
  88. if (!aos_status_is_ok(s)) {
  89. return s;
  90. }
  91. res = oss_list_parts_parse_from_body(options->pool, &resp->body,
  92. &params->part_list, &params->next_part_number_marker,
  93. &params->truncated);
  94. if (res != AOSE_OK) {
  95. aos_xml_error_status_set(s, res);
  96. }
  97. return s;
  98. }
  99. aos_status_t *oss_list_multipart_upload(const oss_request_options_t *options,
  100. const aos_string_t *bucket,
  101. oss_list_multipart_upload_params_t *params,
  102. aos_table_t **resp_headers)
  103. {
  104. int res = AOSE_OK;
  105. aos_status_t *s = NULL;
  106. aos_http_request_t *req = NULL;
  107. aos_http_response_t *resp = NULL;
  108. aos_table_t *query_params = NULL;
  109. aos_table_t *headers = NULL;
  110. //init query_params
  111. query_params = aos_table_create_if_null(options, query_params, 6);
  112. apr_table_add(query_params, OSS_UPLOADS, "");
  113. apr_table_add(query_params, OSS_PREFIX, params->prefix.data);
  114. apr_table_add(query_params, OSS_DELIMITER, params->delimiter.data);
  115. apr_table_add(query_params, OSS_KEY_MARKER, params->key_marker.data);
  116. apr_table_add(query_params, OSS_UPLOAD_ID_MARKER, params->upload_id_marker.data);
  117. aos_table_add_int(query_params, OSS_MAX_UPLOADS, params->max_ret);
  118. //init headers
  119. headers = aos_table_create_if_null(options, headers, 0);
  120. oss_init_bucket_request(options, bucket, HTTP_GET, &req,
  121. query_params, headers, &resp);
  122. s = oss_process_request(options, req, resp);
  123. oss_fill_read_response_header(resp, resp_headers);
  124. if (!aos_status_is_ok(s)) {
  125. return s;
  126. }
  127. res = oss_list_multipart_uploads_parse_from_body(options->pool, &resp->body,
  128. &params->upload_list, &params->next_key_marker,
  129. &params->next_upload_id_marker, &params->truncated);
  130. if (res != AOSE_OK) {
  131. aos_xml_error_status_set(s, res);
  132. }
  133. return s;
  134. }
  135. aos_status_t *oss_complete_multipart_upload(const oss_request_options_t *options,
  136. const aos_string_t *bucket,
  137. const aos_string_t *object,
  138. const aos_string_t *upload_id,
  139. aos_list_t *part_list,
  140. aos_table_t *headers,
  141. aos_table_t **resp_headers)
  142. {
  143. return oss_do_complete_multipart_upload(options, bucket, object, upload_id, part_list,
  144. headers, NULL, resp_headers, NULL);
  145. }
  146. aos_status_t *oss_do_complete_multipart_upload(const oss_request_options_t *options,
  147. const aos_string_t *bucket,
  148. const aos_string_t *object,
  149. const aos_string_t *upload_id,
  150. aos_list_t *part_list,
  151. aos_table_t *headers,
  152. aos_table_t *params,
  153. aos_table_t **resp_headers,
  154. aos_list_t *resp_body)
  155. {
  156. aos_status_t *s = NULL;
  157. aos_http_request_t *req = NULL;
  158. aos_http_response_t *resp = NULL;
  159. apr_table_t *query_params = NULL;
  160. aos_list_t body;
  161. //init query_params
  162. query_params = aos_table_create_if_null(options, params, 1);
  163. apr_table_add(query_params, OSS_UPLOAD_ID, upload_id->data);
  164. //init headers
  165. headers = aos_table_create_if_null(options, headers, 1);
  166. apr_table_set(headers, OSS_CONTENT_TYPE, OSS_MULTIPART_CONTENT_TYPE);
  167. oss_init_object_request(options, bucket, object, HTTP_POST,
  168. &req, query_params, headers, NULL, 0, &resp);
  169. build_complete_multipart_upload_body(options->pool, part_list, &body);
  170. oss_write_request_body_from_buffer(&body, req);
  171. s = oss_process_request(options, req, resp);
  172. oss_fill_read_response_header(resp, resp_headers);
  173. oss_fill_read_response_body(resp, resp_body);
  174. return s;
  175. }
  176. aos_status_t *oss_upload_part_from_buffer(const oss_request_options_t *options,
  177. const aos_string_t *bucket,
  178. const aos_string_t *object,
  179. const aos_string_t *upload_id,
  180. int part_num,
  181. aos_list_t *buffer,
  182. aos_table_t **resp_headers)
  183. {
  184. return oss_do_upload_part_from_buffer(options, bucket, object, upload_id, part_num,
  185. buffer, NULL, NULL, NULL, resp_headers, NULL);
  186. }
  187. aos_status_t *oss_do_upload_part_from_buffer(const oss_request_options_t *options,
  188. const aos_string_t *bucket,
  189. const aos_string_t *object,
  190. const aos_string_t *upload_id,
  191. int part_num,
  192. aos_list_t *buffer,
  193. oss_progress_callback progress_callback,
  194. aos_table_t *headers,
  195. aos_table_t *params,
  196. aos_table_t **resp_headers,
  197. aos_list_t *resp_body)
  198. {
  199. aos_status_t *s = NULL;
  200. aos_http_request_t *req = NULL;
  201. aos_http_response_t *resp = NULL;
  202. aos_table_t *query_params = NULL;
  203. //init query_params
  204. query_params = aos_table_create_if_null(options, params, 2);
  205. apr_table_add(query_params, OSS_UPLOAD_ID, upload_id->data);
  206. aos_table_add_int(query_params, OSS_PARTNUMBER, part_num);
  207. //init headers
  208. headers = aos_table_create_if_null(options, headers, 0);
  209. oss_init_object_request(options, bucket, object, HTTP_PUT, &req, query_params,
  210. headers, progress_callback, 0, &resp);
  211. oss_write_request_body_from_buffer(buffer, req);
  212. s = oss_process_request(options, req, resp);
  213. oss_fill_read_response_header(resp, resp_headers);
  214. oss_fill_read_response_body(resp, resp_body);
  215. if (is_enable_crc(options) && has_crc_in_response(resp)) {
  216. oss_check_crc_consistent(req->crc64, resp->headers, s);
  217. }
  218. return s;
  219. }
  220. aos_status_t *oss_upload_part_from_file(const oss_request_options_t *options,
  221. const aos_string_t *bucket,
  222. const aos_string_t *object,
  223. const aos_string_t *upload_id,
  224. int part_num,
  225. oss_upload_file_t *upload_file,
  226. aos_table_t **resp_headers)
  227. {
  228. return oss_do_upload_part_from_file(options, bucket, object, upload_id, part_num,
  229. upload_file, NULL, NULL, NULL, resp_headers, NULL);
  230. }
  231. aos_status_t *oss_do_upload_part_from_file(const oss_request_options_t *options,
  232. const aos_string_t *bucket,
  233. const aos_string_t *object,
  234. const aos_string_t *upload_id,
  235. int part_num,
  236. oss_upload_file_t *upload_file,
  237. oss_progress_callback progress_callback,
  238. aos_table_t *headers,
  239. aos_table_t *params,
  240. aos_table_t **resp_headers,
  241. aos_list_t *resp_body)
  242. {
  243. aos_status_t *s = NULL;
  244. aos_http_request_t *req = NULL;
  245. aos_http_response_t *resp = NULL;
  246. aos_table_t *query_params = NULL;
  247. int res = AOSE_OK;
  248. s = aos_status_create(options->pool);
  249. //init query_params
  250. query_params = aos_table_create_if_null(options, params, 2);
  251. apr_table_add(query_params, OSS_UPLOAD_ID, upload_id->data);
  252. aos_table_add_int(query_params, OSS_PARTNUMBER, part_num);
  253. //init headers
  254. headers = aos_table_create_if_null(options, headers, 0);
  255. oss_init_object_request(options, bucket, object, HTTP_PUT, &req,
  256. query_params, headers, progress_callback, 0, &resp);
  257. res = oss_write_request_body_from_upload_file(options->pool, upload_file, req);
  258. if (res != AOSE_OK) {
  259. aos_file_error_status_set(s, res);
  260. return s;
  261. }
  262. s = oss_process_request(options, req, resp);
  263. oss_fill_read_response_header(resp, resp_headers);
  264. oss_fill_read_response_body(resp, resp_body);
  265. if (is_enable_crc(options) && has_crc_in_response(resp)) {
  266. oss_check_crc_consistent(req->crc64, resp->headers, s);
  267. }
  268. return s;
  269. }
  270. aos_status_t *oss_upload_part_copy(const oss_request_options_t *options,
  271. oss_upload_part_copy_params_t *params,
  272. aos_table_t *headers,
  273. aos_table_t **resp_headers)
  274. {
  275. aos_status_t *s = NULL;
  276. aos_http_request_t *req = NULL;
  277. aos_http_response_t *resp = NULL;
  278. aos_table_t *query_params = NULL;
  279. char *copy_source = NULL;
  280. char *copy_source_range = NULL;
  281. s = aos_status_create(options->pool);
  282. //init query_params
  283. query_params = aos_table_create_if_null(options, query_params, 2);
  284. apr_table_add(query_params, OSS_UPLOAD_ID, params->upload_id.data);
  285. aos_table_add_int(query_params, OSS_PARTNUMBER, params->part_num);
  286. //init headers
  287. headers = aos_table_create_if_null(options, headers, 2);
  288. copy_source = apr_psprintf(options->pool, "/%.*s/%.*s",
  289. params->source_bucket.len, params->source_bucket.data,
  290. params->source_object.len, params->source_object.data);
  291. apr_table_add(headers, OSS_COPY_SOURCE, copy_source);
  292. copy_source_range = apr_psprintf(options->pool,
  293. "bytes=%" APR_INT64_T_FMT "-%" APR_INT64_T_FMT,
  294. params->range_start, params->range_end);
  295. apr_table_add(headers, OSS_COPY_SOURCE_RANGE, copy_source_range);
  296. oss_init_object_request(options, &params->dest_bucket, &params->dest_object,
  297. HTTP_PUT, &req, query_params, headers, NULL, 0, &resp);
  298. s = oss_process_request(options, req, resp);
  299. oss_fill_read_response_header(resp, resp_headers);
  300. return s;
  301. }
  302. aos_status_t *oss_get_sorted_uploaded_part(oss_request_options_t *options,
  303. const aos_string_t *bucket,
  304. const aos_string_t *object,
  305. const aos_string_t *upload_id,
  306. aos_list_t *complete_part_list,
  307. int *part_count)
  308. {
  309. aos_pool_t *subpool = NULL;
  310. aos_pool_t *parent_pool = NULL;
  311. aos_status_t *s = NULL;
  312. aos_status_t *ret = NULL;
  313. oss_upload_part_t *part_arr = NULL;
  314. int part_index = 0;
  315. int index = 0;
  316. int uploaded_part_count = 0;
  317. oss_list_upload_part_params_t *params = NULL;
  318. oss_list_part_content_t *part_content = NULL;
  319. oss_complete_part_content_t *complete_content = NULL;
  320. aos_table_t *list_part_resp_headers = NULL;
  321. char *part_num_str = NULL;
  322. parent_pool = options->pool;
  323. part_arr = aos_palloc(parent_pool, OSS_MAX_PART_NUM * sizeof(oss_upload_part_t *));
  324. params = oss_create_list_upload_part_params(parent_pool);
  325. while (params->truncated) {
  326. aos_pool_create(&subpool, parent_pool);
  327. options->pool = subpool;
  328. s = oss_list_upload_part(options, bucket, object,
  329. upload_id, params, &list_part_resp_headers);
  330. if (!aos_status_is_ok(s)) {
  331. ret = aos_status_dup(parent_pool, s);
  332. aos_pool_destroy(subpool);
  333. options->pool = parent_pool;
  334. return ret;
  335. }
  336. if (!params->truncated) {
  337. ret = aos_status_dup(parent_pool, s);
  338. }
  339. aos_list_for_each_entry(oss_list_part_content_t, part_content, &params->part_list, node) {
  340. oss_upload_part_t upload_part;
  341. upload_part.etag = part_content->etag.data;
  342. upload_part.part_num = atoi(part_content->part_number.data);
  343. part_arr[part_index++] = upload_part;
  344. uploaded_part_count++;
  345. }
  346. aos_list_init(&params->part_list);
  347. if (params->next_part_number_marker.data != NULL) {
  348. aos_str_set(&params->part_number_marker,
  349. params->next_part_number_marker.data);
  350. }
  351. //sort multipart upload part content
  352. qsort(part_arr, uploaded_part_count, sizeof(part_arr[0]), part_sort_cmp);
  353. for (index = 0; index < part_index; ++index) {
  354. complete_content = oss_create_complete_part_content(parent_pool);
  355. part_num_str = apr_psprintf(parent_pool, "%d", part_arr[index].part_num);
  356. aos_str_set(&complete_content->part_number, part_num_str);
  357. aos_str_set(&complete_content->etag, part_arr[index].etag);
  358. aos_list_add_tail(&complete_content->node, complete_part_list);
  359. }
  360. part_index = 0;
  361. aos_pool_destroy(subpool);
  362. }
  363. *part_count = uploaded_part_count;
  364. options->pool = parent_pool;
  365. return ret;
  366. }
  367. aos_status_t *oss_upload_file(oss_request_options_t *options,
  368. const aos_string_t *bucket,
  369. const aos_string_t *object,
  370. aos_string_t *upload_id,
  371. aos_string_t *filepath,
  372. int64_t part_size,
  373. aos_table_t *headers)
  374. {
  375. aos_pool_t *subpool = NULL;
  376. aos_pool_t *parent_pool = NULL;
  377. int64_t start_pos;
  378. int64_t end_pos;
  379. int part_num;
  380. int part_count = 0;
  381. int res = AOSE_OK;
  382. aos_status_t *s = NULL;
  383. aos_status_t *ret = NULL;
  384. aos_file_buf_t *fb = NULL;
  385. oss_upload_file_t *upload_file = NULL;
  386. aos_table_t *upload_part_resp_headers = NULL;
  387. char *part_num_str = NULL;
  388. char *etag = NULL;
  389. aos_list_t complete_part_list;
  390. oss_complete_part_content_t *complete_content = NULL;
  391. aos_table_t *complete_resp_headers = NULL;
  392. aos_list_init(&complete_part_list);
  393. parent_pool = options->pool;
  394. //get upload_id and uploaded part
  395. aos_pool_create(&subpool, options->pool);
  396. options->pool = subpool;
  397. if (NULL == upload_id->data) {
  398. aos_table_t *init_multipart_headers = NULL;
  399. aos_table_t *init_multipart_resp_headers = NULL;
  400. init_multipart_headers = aos_table_make(subpool, 0);
  401. s = oss_init_multipart_upload(options, bucket, object,
  402. upload_id, init_multipart_headers, &init_multipart_resp_headers);
  403. if (!aos_status_is_ok(s)) {
  404. ret = aos_status_dup(parent_pool, s);
  405. aos_pool_destroy(subpool);
  406. options->pool = parent_pool;
  407. return ret;
  408. }
  409. } else {
  410. s = oss_get_sorted_uploaded_part(options, bucket, object, upload_id,
  411. &complete_part_list, &part_count);
  412. if (!aos_status_is_ok(s)) {
  413. ret = aos_status_dup(parent_pool, s);
  414. aos_pool_destroy(subpool);
  415. options->pool = parent_pool;
  416. return ret;
  417. }
  418. }
  419. aos_pool_destroy(subpool);
  420. //get part size
  421. fb = aos_create_file_buf(parent_pool);
  422. res = aos_open_file_for_read(parent_pool, filepath->data, fb);
  423. if (res != AOSE_OK) {
  424. s = aos_status_create(parent_pool);
  425. aos_file_error_status_set(s, res);
  426. options->pool = parent_pool;
  427. return s;
  428. }
  429. oss_get_part_size(fb->file_last, &part_size);
  430. //upload part from file
  431. upload_file = oss_create_upload_file(parent_pool);
  432. aos_str_set(&upload_file->filename, filepath->data);
  433. start_pos = part_size * part_count;
  434. end_pos = start_pos + part_size;
  435. part_num = part_count + 1;
  436. while (1) {
  437. aos_pool_create(&subpool, parent_pool);
  438. options->pool = subpool;
  439. upload_file->file_pos = start_pos;
  440. upload_file->file_last = end_pos;
  441. s = oss_upload_part_from_file(options, bucket, object, upload_id,
  442. part_num, upload_file, &upload_part_resp_headers);
  443. if (!aos_status_is_ok(s)) {
  444. ret = aos_status_dup(parent_pool, s);
  445. aos_pool_destroy(subpool);
  446. options->pool = parent_pool;
  447. return ret;
  448. }
  449. complete_content = oss_create_complete_part_content(parent_pool);
  450. part_num_str = apr_psprintf(parent_pool, "%d", part_num);
  451. aos_str_set(&complete_content->part_number, part_num_str);
  452. etag = apr_pstrdup(parent_pool,
  453. (char*)apr_table_get(upload_part_resp_headers, "ETag"));
  454. aos_str_set(&complete_content->etag, etag);
  455. aos_list_add_tail(&complete_content->node, &complete_part_list);
  456. aos_pool_destroy(subpool);
  457. if (end_pos >= fb->file_last) {
  458. break;
  459. }
  460. start_pos += part_size;
  461. end_pos += part_size;
  462. if (end_pos > fb->file_last)
  463. end_pos = fb->file_last;
  464. part_num += 1;
  465. }
  466. //complete multipart
  467. aos_pool_create(&subpool, parent_pool);
  468. options->pool = subpool;
  469. headers = aos_table_create_if_null(options, headers, 0);
  470. s = oss_complete_multipart_upload(options, bucket, object, upload_id,
  471. &complete_part_list, headers, &complete_resp_headers);
  472. ret = aos_status_dup(parent_pool, s);
  473. aos_pool_destroy(subpool);
  474. options->pool = parent_pool;
  475. return ret;
  476. }