sigv4_http_request.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/auth/private/sigv4_http_request.h>
  6. #include <aws/auth/credentials.h>
  7. #include <aws/auth/signable.h>
  8. #include <aws/auth/signing.h>
  9. #include <aws/auth/signing_result.h>
  10. #include <aws/common/condition_variable.h>
  11. #include <aws/common/mutex.h>
  12. #include <aws/common/string.h>
  13. #include <aws/http/request_response.h>
  14. #include <aws/io/uri.h>
  15. #if defined(_MSC_VER)
  16. # pragma warning(disable : 4204)
  17. #endif /* _MSC_VER */
  18. #define DEFAULT_QUERY_PARAM_COUNT 10
  19. /*
  20. * Uses the signing result to rebuild the request's URI. If the signing was not done via
  21. * query params, then this ends up doing nothing.
  22. */
  23. static int s_build_request_uri(
  24. struct aws_allocator *allocator,
  25. struct aws_http_message *request,
  26. const struct aws_signing_result *signing_result) {
  27. /* first let's see if we need to do anything at all */
  28. struct aws_array_list *result_param_list = NULL;
  29. aws_signing_result_get_property_list(
  30. signing_result, g_aws_http_query_params_property_list_name, &result_param_list);
  31. if (result_param_list == NULL) {
  32. return AWS_OP_SUCCESS;
  33. }
  34. /*
  35. * There are query params to apply. Use the following algorithm:
  36. *
  37. * (1) Take the old uri and parse it into a URI structure
  38. * (2) Make a new URI builder and add the old URI's components to it
  39. * (3) Add the signing query params to the builder
  40. * (4) Use the builder to make a new URI
  41. */
  42. int result = AWS_OP_ERR;
  43. size_t signed_query_param_count = aws_array_list_length(result_param_list);
  44. struct aws_uri old_uri;
  45. AWS_ZERO_STRUCT(old_uri);
  46. struct aws_uri new_uri;
  47. AWS_ZERO_STRUCT(new_uri);
  48. struct aws_uri_builder_options new_uri_builder;
  49. AWS_ZERO_STRUCT(new_uri_builder);
  50. struct aws_array_list query_params;
  51. AWS_ZERO_STRUCT(query_params);
  52. struct aws_byte_cursor old_path;
  53. aws_http_message_get_request_path(request, &old_path);
  54. /* start with the old uri and parse it */
  55. if (aws_uri_init_parse(&old_uri, allocator, &old_path)) {
  56. goto done;
  57. }
  58. /* pull out the old query params */
  59. if (aws_array_list_init_dynamic(
  60. &query_params, allocator, DEFAULT_QUERY_PARAM_COUNT, sizeof(struct aws_uri_param))) {
  61. goto done;
  62. }
  63. if (aws_uri_query_string_params(&old_uri, &query_params)) {
  64. goto done;
  65. }
  66. /* initialize a builder for the new uri matching the old uri */
  67. new_uri_builder.host_name = old_uri.host_name;
  68. new_uri_builder.path = old_uri.path;
  69. new_uri_builder.port = old_uri.port;
  70. new_uri_builder.scheme = old_uri.scheme;
  71. new_uri_builder.query_params = &query_params;
  72. /* and now add any signing query params */
  73. for (size_t i = 0; i < signed_query_param_count; ++i) {
  74. struct aws_signing_result_property source_param;
  75. if (aws_array_list_get_at(result_param_list, &source_param, i)) {
  76. goto done;
  77. }
  78. struct aws_uri_param signed_param;
  79. signed_param.key = aws_byte_cursor_from_string(source_param.name);
  80. signed_param.value = aws_byte_cursor_from_string(source_param.value);
  81. aws_array_list_push_back(&query_params, &signed_param);
  82. }
  83. /* create the new uri */
  84. if (aws_uri_init_from_builder_options(&new_uri, allocator, &new_uri_builder)) {
  85. goto done;
  86. }
  87. /* copy the full string */
  88. struct aws_byte_cursor new_uri_cursor = aws_byte_cursor_from_buf(&new_uri.uri_str);
  89. if (aws_http_message_set_request_path(request, new_uri_cursor)) {
  90. goto done;
  91. }
  92. result = AWS_OP_SUCCESS;
  93. done:
  94. aws_array_list_clean_up(&query_params);
  95. aws_uri_clean_up(&new_uri);
  96. aws_uri_clean_up(&old_uri);
  97. return result;
  98. }
  99. /*
  100. * Takes a mutable http request and adds all the additional query params and/or headers generated by the
  101. * signing process.
  102. */
  103. int aws_apply_signing_result_to_http_request(
  104. struct aws_http_message *request,
  105. struct aws_allocator *allocator,
  106. const struct aws_signing_result *result) {
  107. /* uri/query params */
  108. if (s_build_request_uri(allocator, request, result)) {
  109. return AWS_OP_ERR;
  110. }
  111. /* headers */
  112. size_t signing_header_count = 0;
  113. struct aws_array_list *result_header_list = NULL;
  114. aws_signing_result_get_property_list(result, g_aws_http_headers_property_list_name, &result_header_list);
  115. if (result_header_list != NULL) {
  116. signing_header_count = aws_array_list_length(result_header_list);
  117. }
  118. for (size_t i = 0; i < signing_header_count; ++i) {
  119. struct aws_signing_result_property source_header;
  120. AWS_ZERO_STRUCT(source_header);
  121. if (aws_array_list_get_at(result_header_list, &source_header, i)) {
  122. return AWS_OP_ERR;
  123. }
  124. if (source_header.name == NULL || source_header.value == NULL) {
  125. return AWS_OP_ERR;
  126. }
  127. struct aws_http_header dest_header = {
  128. .name = aws_byte_cursor_from_string(source_header.name),
  129. .value = aws_byte_cursor_from_string(source_header.value),
  130. };
  131. aws_http_message_add_header(request, dest_header);
  132. }
  133. return AWS_OP_SUCCESS;
  134. }