in source/aws_signing.c [463:557]
static int s_append_normalized_path(
const struct aws_byte_cursor *raw_path,
struct aws_allocator *allocator,
struct aws_byte_buf *dest) {
struct aws_array_list raw_split;
AWS_ZERO_STRUCT(raw_split);
struct aws_array_list normalized_split;
AWS_ZERO_STRUCT(normalized_split);
int result = AWS_OP_ERR;
if (aws_array_list_init_dynamic(
&raw_split, allocator, DEFAULT_PATH_COMPONENT_COUNT, sizeof(struct aws_byte_cursor))) {
goto cleanup;
}
if (aws_byte_cursor_split_on_char(raw_path, '/', &raw_split)) {
goto cleanup;
}
const size_t raw_split_count = aws_array_list_length(&raw_split);
if (aws_array_list_init_dynamic(&normalized_split, allocator, raw_split_count, sizeof(struct aws_byte_cursor))) {
goto cleanup;
}
/*
* Iterate the raw split to build a list of path components that make up the
* normalized path
*/
for (size_t i = 0; i < raw_split_count; ++i) {
struct aws_byte_cursor path_component;
AWS_ZERO_STRUCT(path_component);
if (aws_array_list_get_at(&raw_split, &path_component, i)) {
goto cleanup;
}
if (path_component.len == 0 || (path_component.len == 1 && *path_component.ptr == '.')) {
/* '.' and '' contribute nothing to a normalized path */
continue;
}
if (path_component.len == 2 && *path_component.ptr == '.' && *(path_component.ptr + 1) == '.') {
/* '..' causes us to remove the last valid path component */
aws_array_list_pop_back(&normalized_split);
} else {
aws_array_list_push_back(&normalized_split, &path_component);
}
}
/*
* Special case preserve whether or not the path ended with a '/'
*/
bool ends_with_slash = raw_path->len > 0 && raw_path->ptr[raw_path->len - 1] == '/';
/*
* Paths always start with a single '/'
*/
if (aws_byte_buf_append_byte_dynamic(dest, '/')) {
goto cleanup;
}
/*
* build the final normalized path from the normalized split by joining
* the components together with '/'
*/
const size_t normalized_split_count = aws_array_list_length(&normalized_split);
for (size_t i = 0; i < normalized_split_count; ++i) {
struct aws_byte_cursor normalized_path_component;
AWS_ZERO_STRUCT(normalized_path_component);
if (aws_array_list_get_at(&normalized_split, &normalized_path_component, i)) {
goto cleanup;
}
if (aws_byte_buf_append_dynamic(dest, &normalized_path_component)) {
goto cleanup;
}
if (i + 1 < normalized_split_count || ends_with_slash) {
if (aws_byte_buf_append_byte_dynamic(dest, '/')) {
goto cleanup;
}
}
}
result = AWS_OP_SUCCESS;
cleanup:
aws_array_list_clean_up(&raw_split);
aws_array_list_clean_up(&normalized_split);
return result;
}