From 185bee5366b26db3788d1486bb15e9b46f344771 Mon Sep 17 00:00:00 2001 From: Dirk Engling Date: Sat, 24 Oct 2026 05:48:37 +0200 Subject: Add a url escaper next to the scanner --- scan_urlencoded_query.c | 28 +++++++++++++++++++++++++++- scan_urlencoded_query.h | 8 ++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/scan_urlencoded_query.c b/scan_urlencoded_query.c index 50aced3..cf0c5b1 100644 --- a/scan_urlencoded_query.c +++ b/scan_urlencoded_query.c @@ -20,7 +20,7 @@ */ /* This matrix holds for each ascii character the information, - whether it is a non-terminating character for on of the three + whether it is a non-terminating character for one of the three scan states we are in, that is 'path', 'param' and 'value' from /path?param=value¶m=value, it is encoded in bit 0, 1 and 2 respectively @@ -159,3 +159,29 @@ ssize_t scan_fixed_int(char *data, size_t len, int *tmp) { *tmp = -*tmp; return len; } + +size_t fmt_urlencoded(char *dest, const uint8_t *src, size_t len) { + static const char safe[] = "$/.=~-_"; + static const char hexdigit[] = "0123456789abcdef"; + size_t written = 0, i; + + for (i = 0; i < len; ++i) { + uint8_t c = src[i]; + + /* strchr would find the terminator, so a zero byte never counts as safe */ + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c && strchr(safe, c))) { + if (dest) + dest[written] = (char)c; + ++written; + } else { + if (dest) { + dest[written] = '%'; + dest[written + 1] = hexdigit[c >> 4]; + dest[written + 2] = hexdigit[c & 15]; + } + written += 3; + } + } + + return written; +} diff --git a/scan_urlencoded_query.h b/scan_urlencoded_query.h index 74246e7..6f12c03 100644 --- a/scan_urlencoded_query.h +++ b/scan_urlencoded_query.h @@ -6,6 +6,8 @@ #ifndef SCAN_URLENCODED_QUERY_H__ #define SCAN_URLENCODED_QUERY_H__ +#include +#include #include typedef struct { @@ -52,4 +54,10 @@ void scan_urlencoded_skipvalue(char **string); */ ssize_t scan_fixed_int(char *data, size_t len, int *number); +/* The other direction: percent encode len bytes from src into dest and return + how many characters were written, or how many would be needed when dest is + NULL. dest needs room for three times len. + */ +size_t fmt_urlencoded(char *dest, const uint8_t *src, size_t len); + #endif -- cgit v1.3