libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

commit b566b9afd52b536d6d333e6df75788d766076064
parent 1b23b1eaae216f1f8c114582c9ad362df970ccf8
Author: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Date:   Tue, 18 Nov 2025 19:34:33 +0100

Further improved readability of URI normalisation function

Diffstat:
Msrc/mhd2/mhd_str.c | 175+++++++++++++++++++++++++++++++++++++++++--------------------------------------
1 file changed, 90 insertions(+), 85 deletions(-)

diff --git a/src/mhd2/mhd_str.c b/src/mhd2/mhd_str.c @@ -2400,6 +2400,7 @@ mhd_str_dec_norm_uri_path (size_t str_len, char c2; if (str_len == r + 1u) /* overflow-safe as 'str_len > r' */ { + /* The complete string is "." */ ++r; /* Skip "." */ break; /* At the edge, stop */ } @@ -2407,6 +2408,7 @@ mhd_str_dec_norm_uri_path (size_t str_len, c2 = str[r + 1u]; if ('/' == c2) { + /* Found "./" at the start of the string */ r += 2u; /* Skip "./" */ continue; } @@ -2421,6 +2423,7 @@ mhd_str_dec_norm_uri_path (size_t str_len, char c3; if (str_len == r + 2u) /* overflow-safe as 'str_len > r + 1 ' */ { + /* The complete string is ".." */ r += 2u; /* Skip ".." */ break; /* At the edge, stop */ } @@ -2428,6 +2431,7 @@ mhd_str_dec_norm_uri_path (size_t str_len, c3 = str[r + 2u]; if ('/' == c3) { + /* Found "../" at the start of the string */ r += 3u; /* Skip "../" */ continue; } @@ -2444,6 +2448,7 @@ mhd_str_dec_norm_uri_path (size_t str_len, } break; } + mhd_ASSUME (w <= r); /* Found first segment which is not "../" and is not "./" OR the end of the string */ for ((void) r; str_len > r && '/' != str[r]; ++r) @@ -2460,114 +2465,114 @@ mhd_str_dec_norm_uri_path (size_t str_len, mhd_ASSUME (w <= r); str[w++] = c; } + /* Found first '/' which is not skipped OR the end of the string */ - if (str_len > r) + while (str_len > r) { - /* Found first segment started with '/' */ - mhd_ASSUME ('/' == str[r]); - while (str_len > r) + char slash_chr = str[r]; + size_t seg_start = w; + mhd_ASSUME ('/' == slash_chr); + str[w++] = slash_chr; + ++r; + if (str_len > r) { - char slash_chr = str[r]; - size_t seg_start = w; - mhd_ASSUME ('/' == slash_chr); - str[w++] = slash_chr; - ++r; - if (str_len > r) + char c; + mhd_ASSUME (w <= r); + c = str[r]; + if ('/' == c) + continue; + if (('%' == c) && + pct_decode_no_slash (str_len, + str, + r, + &c)) + r += 2u; + if ('.' == c) { - char c; + char c2; + if (str_len == r + 1u) /* overflow-safe as 'str_len > r' */ + { + /* Found "/." at the end of the string */ + ++r; /* Skip ".", leave bare '/' */ + break; /* At the edge, stop */ + } mhd_ASSUME (w <= r); - c = str[r]; - if ('/' == c) - continue; - if (('%' == c) && + c2 = str[r + 1u]; + if ('/' == c2) + { + /* Found "/./" */ + w = seg_start; /* Rewind output to the '/' at the start of the segment */ + ++r; /* Skip "." */ + continue; /* Go to the next "/", which will be written again */ + } + if (('%' == c2) && pct_decode_no_slash (str_len, str, - r, - &c)) + r + 1u, + &c2)) r += 2u; - if ('.' == c) + if ('.' == c2) { - char c2; - if (str_len == r + 1u) /* overflow-safe as 'str_len > r' */ + char c3; + if (str_len == r + 2u) /* overflow-safe as 'str_len > r + 1 ' */ { - ++r; /* Skip ".", leave bare '/' */ - break; /* At the edge, stop */ + /* Found "/.." at the end of the string */ + w = seg_start; + if (0 < w) + do + { /* Rewind output to the start of prev segment */ + --w; + } while (0 < w && '/' != str[w]); + mhd_ASSUME (w < r); + str[w++] = '/'; /* Replace prev segment with '/' */ + r += 2u; /* Skip ".." */ + break; /* At the edge, stop */ } mhd_ASSUME (w <= r); - c2 = str[r + 1u]; - if ('/' == c2) + c3 = str[r + 2u]; + if ('/' == c3) { + /* Found "/../" */ w = seg_start; - ++r; /* Skip "." */ - continue; /* Go to the next "/", which will be written again */ - } - if (('%' == c2) && - pct_decode_no_slash (str_len, - str, - r + 1u, - &c2)) - r += 2u; - if ('.' == c2) - { - char c3; - if (str_len == r + 2u) /* overflow-safe as 'str_len > r + 1 ' */ - { - w = seg_start; - if (0 < w) - do - { /* Rewind output to the start of prev segment */ - --w; - } while (0 < w && '/' != str[w]); - mhd_ASSUME (w < r); - str[w++] = '/'; /* Replace prev segment with '/' */ - r += 2u; /* Skip ".." */ - break; /* At the edge, stop */ - } - mhd_ASSUME (w <= r); - c3 = str[r + 2u]; - if ('/' == c3) - { - w = seg_start; - if (0 < w) - do - { /* Rewind output to the start of prev segment */ - --w; - } while (0 < w && '/' != str[w]); - r += 2u; /* Skip ".."; put next '/' to the start of prev segment */ - continue; - } - /* Do not write 'c3' as it has not been percent-decoded */ + if (0 < w) + do + { /* Rewind output to the start of prev segment */ + --w; + } while (0 < w && '/' != str[w]); + r += 2u; /* Skip ".."; put next '/' to the start of prev segment */ + continue; } - str[w++] = c; - str[w++] = c2; - r += 2u; - } - else - { - str[w++] = c; - r += 1u; + /* Do not write 'c3' as it has not been percent-decoded */ } - mhd_assert (seg_start < w); + str[w++] = c; + str[w++] = c2; + r += 2u; } - for ((void) r; str_len > r && '/' != str[r]; ++r) + else { - /* Process the end of the segment */ - char c; - mhd_ASSUME (w <= r); - c = str[r]; - if (('%' == c) && - pct_decode_no_slash (str_len, - str, - r, - &c)) - r += 2u; - mhd_ASSUME (w <= r); str[w++] = c; + r += 1u; } + mhd_assert (seg_start < w); + } + for ((void) r; str_len > r && '/' != str[r]; ++r) + { + /* Process the end of the segment */ + char c; + mhd_ASSUME (w <= r); + c = str[r]; + if (('%' == c) && + pct_decode_no_slash (str_len, + str, + r, + &c)) + r += 2u; + mhd_ASSUME (w <= r); + str[w++] = c; } mhd_assert (0u != w); - mhd_assert ((r == str_len) || ('/' == str[w - 1u])); } + mhd_assert (r == str_len); if (str_len > w) str[w] = '\0';