Skip to content

Commit 9a6fc98

Browse files
Switch to generic xml unescaping logic (#631)
1 parent 31c3351 commit 9a6fc98

10 files changed

Lines changed: 55 additions & 56 deletions

File tree

.github/workflows/ci.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ jobs:
4242
role-to-assume: ${{ env.CRT_CI_ROLE }}
4343
aws-region: ${{ env.AWS_DEFAULT_REGION }}
4444
- name: Checkout Sources
45-
uses: actions/checkout@v4
45+
uses: actions/checkout@v6
4646
# We can't use the `uses: docker://image` version yet, GitHub lacks authentication for actions -> packages
4747
- name: Build ${{ env.PACKAGE_NAME }}
4848
run: |
@@ -204,7 +204,7 @@ jobs:
204204
role-to-assume: ${{ env.CRT_CI_ROLE }}
205205
aws-region: ${{ env.AWS_DEFAULT_REGION }}
206206
- name: Checkout Sources
207-
uses: actions/checkout@v4
207+
uses: actions/checkout@v6
208208
- name: Build ${{ env.PACKAGE_NAME }} + consumers
209209
run: |
210210
python3 -m venv .venv
@@ -221,7 +221,7 @@ jobs:
221221
role-to-assume: ${{ env.CRT_CI_ROLE }}
222222
aws-region: ${{ env.AWS_DEFAULT_REGION }}
223223
- name: Checkout Sources
224-
uses: actions/checkout@v4
224+
uses: actions/checkout@v6
225225
- name: Build ${{ env.PACKAGE_NAME }} + consumers
226226
run: |
227227
python3 -m venv .venv

.github/workflows/clang-format.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99

1010
steps:
1111
- name: Checkout Sources
12-
uses: actions/checkout@v4
12+
uses: actions/checkout@v6
1313

1414
- name: clang-format lint
1515
run: |

.github/workflows/codecov.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
role-to-assume: ${{ env.CRT_CI_ROLE }}
2626
aws-region: ${{ env.AWS_DEFAULT_REGION }}
2727
- name: Checkout Sources
28-
uses: actions/checkout@v4
28+
uses: actions/checkout@v6
2929
- name: Build ${{ env.PACKAGE_NAME }} + consumers
3030
run: |
3131
python3 -c "from urllib.request import urlretrieve; urlretrieve('${{ env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION }}/builder.pyz?run=${{ env.RUN }}', 'builder')"

include/aws/s3/private/s3_util.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -236,11 +236,6 @@ int aws_xml_get_body_at_path(
236236
const char *path_name_array[],
237237
struct aws_byte_cursor *out_body);
238238

239-
/* replace " with escaped /"
240-
* Returns initialized aws_byte_buf */
241-
AWS_S3_API
242-
struct aws_byte_buf aws_replace_quote_entities(struct aws_allocator *allocator, struct aws_byte_cursor src);
243-
244239
/* strip quotes if string is enclosed in quotes. does not remove quotes if they only appear on either side of the string
245240
*/
246241
AWS_S3_API

source/s3_auto_ranged_put.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <aws/common/clock.h>
1414
#include <aws/common/encoding.h>
1515
#include <aws/common/string.h>
16+
#include <aws/common/xml_parser.h>
1617
#include <aws/io/stream.h>
1718

1819
/* TODO: better logging of steps */
@@ -1756,13 +1757,20 @@ static void s_s3_auto_ranged_put_request_finished(
17561757
aws_xml_get_body_at_path(meta_request->allocator, xml_doc, xml_path, &etag_header_value);
17571758

17581759
if (etag_header_value.len > 0) {
1759-
struct aws_byte_buf etag_header_value_byte_buf =
1760-
aws_replace_quote_entities(meta_request->allocator, etag_header_value);
1761-
1762-
aws_http_headers_set(
1763-
request->send_data.response_headers,
1764-
g_etag_header_name,
1765-
aws_byte_cursor_from_buf(&etag_header_value_byte_buf));
1760+
struct aws_byte_buf etag_header_value_byte_buf;
1761+
aws_byte_buf_init(&etag_header_value_byte_buf, meta_request->allocator, 20);
1762+
if (aws_byte_buf_append_unescaped_xml(
1763+
meta_request->allocator, etag_header_value, &etag_header_value_byte_buf)) {
1764+
AWS_LOGF_ERROR(
1765+
AWS_LS_S3_META_REQUEST, "Server returned unexpected etag format. skipping etag unescaping");
1766+
aws_http_headers_set(
1767+
request->send_data.response_headers, g_etag_header_name, etag_header_value);
1768+
} else {
1769+
aws_http_headers_set(
1770+
request->send_data.response_headers,
1771+
g_etag_header_name,
1772+
aws_byte_cursor_from_buf(&etag_header_value_byte_buf));
1773+
}
17661774

17671775
aws_byte_buf_clean_up(&etag_header_value_byte_buf);
17681776
}

source/s3_copy_object.c

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "aws/s3/private/s3_request_messages.h"
99
#include "aws/s3/private/s3_util.h"
1010
#include <aws/common/string.h>
11+
#include <aws/common/xml_parser.h>
1112

1213
/* Objects with size smaller than the constant below are bypassed as S3 CopyObject instead of multipart copy */
1314
static const size_t s_multipart_copy_minimum_object_size = GB_TO_BYTES(1);
@@ -569,7 +570,9 @@ static struct aws_string *s_etag_new_from_upload_part_copy_response(
569570
const char *xml_path[] = {"CopyPartResult", "ETag", NULL};
570571
aws_xml_get_body_at_path(allocator, xml_doc, xml_path, &etag_within_xml_quotes);
571572

572-
struct aws_byte_buf etag_within_quotes_byte_buf = aws_replace_quote_entities(allocator, etag_within_xml_quotes);
573+
struct aws_byte_buf etag_within_quotes_byte_buf;
574+
aws_byte_buf_init(&etag_within_quotes_byte_buf, allocator, 20);
575+
aws_byte_buf_append_unescaped_xml(allocator, etag_within_xml_quotes, &etag_within_quotes_byte_buf);
573576

574577
struct aws_string *stripped_etag =
575578
aws_strip_quotes(allocator, aws_byte_cursor_from_buf(&etag_within_quotes_byte_buf));
@@ -770,13 +773,20 @@ static void s_s3_copy_object_request_finished(
770773
const char *xml_path[] = {"CompleteMultipartUploadResult", "ETag", NULL};
771774
aws_xml_get_body_at_path(meta_request->allocator, xml_doc, xml_path, &etag_header_value);
772775
if (etag_header_value.len > 0) {
773-
struct aws_byte_buf etag_header_value_byte_buf =
774-
aws_replace_quote_entities(meta_request->allocator, etag_header_value);
775-
776-
aws_http_headers_set(
777-
request->send_data.response_headers,
778-
g_etag_header_name,
779-
aws_byte_cursor_from_buf(&etag_header_value_byte_buf));
776+
struct aws_byte_buf etag_header_value_byte_buf;
777+
aws_byte_buf_init(&etag_header_value_byte_buf, meta_request->allocator, 20);
778+
if (aws_byte_buf_append_unescaped_xml(
779+
meta_request->allocator, etag_header_value, &etag_header_value_byte_buf)) {
780+
AWS_LOGF_ERROR(
781+
AWS_LS_S3_META_REQUEST, "Server returned unexpected etag format. skipping etag unescaping");
782+
aws_http_headers_set(
783+
request->send_data.response_headers, g_etag_header_name, etag_header_value);
784+
} else {
785+
aws_http_headers_set(
786+
request->send_data.response_headers,
787+
g_etag_header_name,
788+
aws_byte_cursor_from_buf(&etag_header_value_byte_buf));
789+
}
780790

781791
aws_byte_buf_clean_up(&etag_header_value_byte_buf);
782792
}

source/s3_list_objects.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,13 @@ static int s_on_list_bucket_result_node_encountered(struct aws_xml_node *node, v
131131
fs_wrapper.fs_info.prefix = aws_byte_cursor_from_string(operation_data->prefix);
132132
}
133133

134-
struct aws_byte_buf trimmed_etag = aws_replace_quote_entities(fs_wrapper.allocator, fs_wrapper.fs_info.e_tag);
135-
fs_wrapper.fs_info.e_tag = aws_byte_cursor_from_buf(&trimmed_etag);
134+
struct aws_byte_buf trimmed_etag;
135+
aws_byte_buf_init(&trimmed_etag, fs_wrapper.allocator, 20);
136+
137+
if (aws_byte_buf_append_unescaped_xml(fs_wrapper.allocator, fs_wrapper.fs_info.e_tag, &trimmed_etag) ==
138+
AWS_OP_SUCCESS) {
139+
fs_wrapper.fs_info.e_tag = aws_byte_cursor_from_buf(&trimmed_etag);
140+
}
136141

137142
int ret_val = AWS_OP_SUCCESS;
138143
if (operation_data->on_object) {

source/s3_list_parts.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,13 @@ static int s_xml_on_ListPartsResult_child(struct aws_xml_node *node, void *user_
142142
return AWS_OP_ERR;
143143
}
144144

145-
struct aws_byte_buf trimmed_etag =
146-
aws_replace_quote_entities(result_wrapper.allocator, result_wrapper.part_info.e_tag);
147-
result_wrapper.part_info.e_tag = aws_byte_cursor_from_buf(&trimmed_etag);
145+
struct aws_byte_buf trimmed_etag;
146+
aws_byte_buf_init(&trimmed_etag, result_wrapper.allocator, 20);
147+
148+
if (aws_byte_buf_append_unescaped_xml(
149+
result_wrapper.allocator, result_wrapper.part_info.e_tag, &trimmed_etag) == AWS_OP_SUCCESS) {
150+
result_wrapper.part_info.e_tag = aws_byte_cursor_from_buf(&trimmed_etag);
151+
}
148152

149153
int ret_val = AWS_OP_SUCCESS;
150154
if (operation_data->on_part) {

source/s3_util.c

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -333,31 +333,6 @@ void aws_s3_init_default_signing_config(
333333
signing_config->signed_body_value = g_aws_signed_body_value_unsigned_payload;
334334
}
335335

336-
static struct aws_byte_cursor s_quote_entity_literal = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("&quot;");
337-
static struct aws_byte_cursor s_quote_literal = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("\"");
338-
339-
struct aws_byte_buf aws_replace_quote_entities(struct aws_allocator *allocator, struct aws_byte_cursor src) {
340-
struct aws_byte_buf out_buf;
341-
aws_byte_buf_init(&out_buf, allocator, src.len);
342-
343-
for (size_t i = 0; i < src.len; ++i) {
344-
size_t chars_remaining = src.len - i;
345-
346-
if (chars_remaining >= s_quote_entity_literal.len &&
347-
!strncmp((const char *)&src.ptr[i], (const char *)s_quote_entity_literal.ptr, s_quote_entity_literal.len)) {
348-
/* Append quote */
349-
aws_byte_buf_append(&out_buf, &s_quote_literal);
350-
i += s_quote_entity_literal.len - 1;
351-
} else {
352-
/* Append character */
353-
struct aws_byte_cursor character_cursor = aws_byte_cursor_from_array(&src.ptr[i], 1);
354-
aws_byte_buf_append(&out_buf, &character_cursor);
355-
}
356-
}
357-
358-
return out_buf;
359-
}
360-
361336
struct aws_string *aws_strip_quotes(struct aws_allocator *allocator, struct aws_byte_cursor in_cur) {
362337

363338
if (in_cur.len >= 2 && in_cur.ptr[0] == '"' && in_cur.ptr[in_cur.len - 1] == '"') {

tests/s3_util_tests.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,9 @@ static int s_test_s3_replace_quote_entities(struct aws_allocator *allocator, voi
133133
for (size_t i = 0; i < AWS_ARRAY_SIZE(test_cases); ++i) {
134134
struct test_case *test_case = &test_cases[i];
135135

136-
struct aws_byte_buf result_byte_buf = aws_replace_quote_entities(allocator, test_case->test_string);
136+
struct aws_byte_buf result_byte_buf;
137+
aws_byte_buf_init(&result_byte_buf, allocator, 20);
138+
ASSERT_SUCCESS(aws_byte_buf_append_unescaped_xml(allocator, test_case->test_string, &result_byte_buf));
137139

138140
struct aws_byte_cursor result_byte_cursor = aws_byte_cursor_from_buf(&result_byte_buf);
139141

0 commit comments

Comments
 (0)