From e89be2e944ac1dd4d95c65d32b1194fab33ae54d Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov <rojer@cesanta.com> Date: Tue, 10 Apr 2018 02:34:35 +0100 Subject: [PATCH] Add mg_url_encode_opt() CL: Add `mg_url_encode_opt()` - a parametrized version of `mg_url_encode()` PUBLISHED_FROM=17fa57a7a5325b51b6e3aef3855eac4e82c35782 --- docs/c-api/mg_util.h/mg_url_encode.md | 5 +--- mongoose.c | 16 +++++++++--- mongoose.h | 17 ++++++++++++- src/mg_util.c | 16 +++++++++--- src/mg_util.h | 9 ++++++- test/unit_test.c | 36 ++++++++++++++++++++++++--- 6 files changed, 81 insertions(+), 18 deletions(-) diff --git a/docs/c-api/mg_util.h/mg_url_encode.md b/docs/c-api/mg_util.h/mg_url_encode.md index 105ce9473..176ac5f7a 100644 --- a/docs/c-api/mg_util.h/mg_url_encode.md +++ b/docs/c-api/mg_util.h/mg_url_encode.md @@ -6,8 +6,5 @@ signature: | struct mg_str mg_url_encode(const struct mg_str src); --- -URL-escape the specified string. -All non-printable characters are escaped, plus `._-$,;~()/`. -Input need not be NUL-terminated, but the returned string is. -Returned string is heap-allocated and must be free()'d. +Same as `mg_url_encode_opt(src, "._-$,;~()/", 0)`. diff --git a/mongoose.c b/mongoose.c index 534009b74..1eb690e71 100644 --- a/mongoose.c +++ b/mongoose.c @@ -10444,17 +10444,21 @@ void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass, mbuf_append(buf, header_suffix, strlen(header_suffix)); } -struct mg_str mg_url_encode(const struct mg_str src) { - static const char *dont_escape = "._-$,;~()/"; - static const char *hex = "0123456789abcdef"; +struct mg_str mg_url_encode_opt(const struct mg_str src, + const struct mg_str safe, unsigned int flags) { + const char *hex = + (flags & MG_URL_ENCODE_F_UPPERCASE_HEX ? "0123456789ABCDEF" + : "0123456789abcdef"); size_t i = 0; struct mbuf mb; mbuf_init(&mb, src.len); for (i = 0; i < src.len; i++) { const unsigned char c = *((const unsigned char *) src.p + i); - if (isalnum(c) || strchr(dont_escape, c) != NULL) { + if (isalnum(c) || mg_strchr(safe, c) != NULL) { mbuf_append(&mb, &c, 1); + } else if (c == ' ' && (flags & MG_URL_ENCODE_F_SPACE_AS_PLUS)) { + mbuf_append(&mb, "+", 1); } else { mbuf_append(&mb, "%", 1); mbuf_append(&mb, &hex[c >> 4], 1); @@ -10465,6 +10469,10 @@ struct mg_str mg_url_encode(const struct mg_str src) { mbuf_trim(&mb); return mg_mk_str_n(mb.buf, mb.len - 1); } + +struct mg_str mg_url_encode(const struct mg_str src) { + return mg_url_encode_opt(src, mg_mk_str("._-$,;~()/"), 0); +} #ifdef MG_MODULE_LINES #line 1 "mongoose/src/mg_mqtt.c" #endif diff --git a/mongoose.h b/mongoose.h index 080642c3b..a02d96466 100644 --- a/mongoose.h +++ b/mongoose.h @@ -2314,6 +2314,14 @@ void cs_base64_finish(struct cs_base64_ctx *ctx); void cs_base64_encode(const unsigned char *src, int src_len, char *dst); void cs_fprint_base64(FILE *f, const unsigned char *src, int src_len); + +/* + * Decodes a base64 string `s` length `len` into `dst`. + * `dst` must have enough space to hold the result. + * `*dec_len` will contain the resulting length of the string in `dst` + * while return value will return number of processed bytes in `src`. + * Return value == len indicates successful processing of all the data. + */ int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len); #ifdef __cplusplus @@ -4501,10 +4509,17 @@ void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass, /* * URL-escape the specified string. - * All non-printable characters are escaped, plus `._-$,;~()/`. + * All characters acept letters, numbers and characters listed in + * `safe` are escaped. If `hex_upper`is true, `A-F` are used for hex digits. * Input need not be NUL-terminated, but the returned string is. * Returned string is heap-allocated and must be free()'d. */ +#define MG_URL_ENCODE_F_SPACE_AS_PLUS (1 << 0) +#define MG_URL_ENCODE_F_UPPERCASE_HEX (1 << 1) +struct mg_str mg_url_encode_opt(const struct mg_str src, + const struct mg_str safe, unsigned int flags); + +/* Same as `mg_url_encode_opt(src, "._-$,;~()/", 0)`. */ struct mg_str mg_url_encode(const struct mg_str src); #ifdef __cplusplus diff --git a/src/mg_util.c b/src/mg_util.c index 95246a8db..cfbd87e5a 100644 --- a/src/mg_util.c +++ b/src/mg_util.c @@ -313,17 +313,21 @@ void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass, mbuf_append(buf, header_suffix, strlen(header_suffix)); } -struct mg_str mg_url_encode(const struct mg_str src) { - static const char *dont_escape = "._-$,;~()/"; - static const char *hex = "0123456789abcdef"; +struct mg_str mg_url_encode_opt(const struct mg_str src, + const struct mg_str safe, unsigned int flags) { + const char *hex = + (flags & MG_URL_ENCODE_F_UPPERCASE_HEX ? "0123456789ABCDEF" + : "0123456789abcdef"); size_t i = 0; struct mbuf mb; mbuf_init(&mb, src.len); for (i = 0; i < src.len; i++) { const unsigned char c = *((const unsigned char *) src.p + i); - if (isalnum(c) || strchr(dont_escape, c) != NULL) { + if (isalnum(c) || mg_strchr(safe, c) != NULL) { mbuf_append(&mb, &c, 1); + } else if (c == ' ' && (flags & MG_URL_ENCODE_F_SPACE_AS_PLUS)) { + mbuf_append(&mb, "+", 1); } else { mbuf_append(&mb, "%", 1); mbuf_append(&mb, &hex[c >> 4], 1); @@ -334,3 +338,7 @@ struct mg_str mg_url_encode(const struct mg_str src) { mbuf_trim(&mb); return mg_mk_str_n(mb.buf, mb.len - 1); } + +struct mg_str mg_url_encode(const struct mg_str src) { + return mg_url_encode_opt(src, mg_mk_str("._-$,;~()/"), 0); +} diff --git a/src/mg_util.h b/src/mg_util.h index e6f2e4813..8ddeb770f 100644 --- a/src/mg_util.h +++ b/src/mg_util.h @@ -196,10 +196,17 @@ void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass, /* * URL-escape the specified string. - * All non-printable characters are escaped, plus `._-$,;~()/`. + * All characters acept letters, numbers and characters listed in + * `safe` are escaped. If `hex_upper`is true, `A-F` are used for hex digits. * Input need not be NUL-terminated, but the returned string is. * Returned string is heap-allocated and must be free()'d. */ +#define MG_URL_ENCODE_F_SPACE_AS_PLUS (1 << 0) +#define MG_URL_ENCODE_F_UPPERCASE_HEX (1 << 1) +struct mg_str mg_url_encode_opt(const struct mg_str src, + const struct mg_str safe, unsigned int flags); + +/* Same as `mg_url_encode_opt(src, "._-$,;~()/", 0)`. */ struct mg_str mg_url_encode(const struct mg_str src); #ifdef __cplusplus diff --git a/test/unit_test.c b/test/unit_test.c index f496b27c5..485403595 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -928,10 +928,38 @@ static const char *test_mg_uri_to_local_path(void) { static const char *test_mg_url_encode(void) { const struct mg_str encode_me = MG_MK_STR("I'm a.little_tea-pot,here's$my;spout~oink(oink)oink/!"); - struct mg_str encoded = mg_url_encode(encode_me); - ASSERT_MG_STREQ( - encoded, "I%27m%20a.little_tea-pot,here%27s$my;spout~oink(oink)oink/%21"); - free((void *) encoded.p); + { + struct mg_str encoded = mg_url_encode(encode_me); + ASSERT_MG_STREQ( + encoded, + "I%27m%20a.little_tea-pot,here%27s$my;spout~oink(oink)oink/%21"); + free((void *) encoded.p); + } + { + struct mg_str encoded = mg_url_encode_opt(encode_me, mg_mk_str(NULL), 0); + ASSERT_MG_STREQ(encoded, + "I%27m%20a%2elittle%5ftea%2dpot%2chere%27s%24my%3bspout%" + "7eoink%28oink%29oink%2f%21"); + free((void *) encoded.p); + } + { + struct mg_str encoded = mg_url_encode_opt(encode_me, mg_mk_str(" /!"), + MG_URL_ENCODE_F_UPPERCASE_HEX); + ASSERT_MG_STREQ(encoded, + "I%27m " + "a%2Elittle%5Ftea%2Dpot%2Chere%27s%24my%3Bspout%7Eoink%" + "28oink%29oink/!"); + free((void *) encoded.p); + } + { + struct mg_str encoded = mg_url_encode_opt( + encode_me, mg_mk_str("/!"), + MG_URL_ENCODE_F_SPACE_AS_PLUS | MG_URL_ENCODE_F_UPPERCASE_HEX); + ASSERT_MG_STREQ(encoded, + "I%27m+a%2Elittle%5Ftea%2Dpot%2Chere%27s%24my%3Bspout%" + "7Eoink%28oink%29oink/!"); + free((void *) encoded.p); + } return NULL; } -- GitLab