From 0fba87c755a4dd23bfa5e538480db9d0e955793b Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Fri, 21 Jul 2017 14:02:06 +0200 Subject: [PATCH] Make mg_url_encode public Change the API to heap-allocate the string and get rid of a bunch of fat stack buffers. PUBLISHED_FROM=c793dc64a9a044a9769d92ea16859f5d704a2181 --- docs/c-api/util.h/intro.md | 1 + docs/c-api/util.h/mg_url_encode.md | 13 +++++++ mongoose.c | 59 ++++++++++++++++-------------- mongoose.h | 8 ++++ 4 files changed, 53 insertions(+), 28 deletions(-) create mode 100644 docs/c-api/util.h/mg_url_encode.md diff --git a/docs/c-api/util.h/intro.md b/docs/c-api/util.h/intro.md index d04619a1..73c4f792 100644 --- a/docs/c-api/util.h/intro.md +++ b/docs/c-api/util.h/intro.md @@ -22,6 +22,7 @@ items: - { name: mg_sock_to_str.md } - { name: mg_start_thread.md } - { name: mg_stat.md } + - { name: mg_url_encode.md } --- diff --git a/docs/c-api/util.h/mg_url_encode.md b/docs/c-api/util.h/mg_url_encode.md new file mode 100644 index 00000000..105ce947 --- /dev/null +++ b/docs/c-api/util.h/mg_url_encode.md @@ -0,0 +1,13 @@ +--- +title: "mg_url_encode()" +decl_name: "mg_url_encode" +symbol_kind: "func" +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. + diff --git a/mongoose.c b/mongoose.c index 3dfe789a..f3210df8 100644 --- a/mongoose.c +++ b/mongoose.c @@ -7033,28 +7033,6 @@ static int mg_http_is_authorized(struct http_message *hm, #endif #if MG_ENABLE_DIRECTORY_LISTING -static size_t mg_url_encode(const char *src, size_t s_len, char *dst, - size_t dst_len) { - static const char *dont_escape = "._-$,;~()/"; - static const char *hex = "0123456789abcdef"; - size_t i = 0, j = 0; - - for (i = j = 0; dst_len > 0 && i < s_len && j + 2 < dst_len - 1; i++, j++) { - if (isalnum(*(const unsigned char *) (src + i)) || - strchr(dont_escape, *(const unsigned char *) (src + i)) != NULL) { - dst[j] = src[i]; - } else if (j + 3 < dst_len) { - dst[j] = '%'; - dst[j + 1] = hex[(*(const unsigned char *) (src + i)) >> 4]; - dst[j + 2] = hex[(*(const unsigned char *) (src + i)) & 0xf]; - j += 2; - } - } - - dst[j] = '\0'; - return j; -} - static void mg_escape(const char *src, char *dst, size_t dst_len) { size_t n = 0; while (*src != '\0' && n + 5 < dst_len) { @@ -7070,10 +7048,11 @@ static void mg_escape(const char *src, char *dst, size_t dst_len) { static void mg_print_dir_entry(struct mg_connection *nc, const char *file_name, cs_stat_t *stp) { - char size[64], mod[64], href[MG_MAX_PATH * 3], path[MG_MAX_PATH]; + char size[64], mod[64], path[MG_MAX_PATH]; int64_t fsize = stp->st_size; int is_dir = S_ISDIR(stp->st_mode); const char *slash = is_dir ? "/" : ""; + struct mg_str href; if (is_dir) { snprintf(size, sizeof(size), "%s", "[DIRECTORY]"); @@ -7094,12 +7073,13 @@ static void mg_print_dir_entry(struct mg_connection *nc, const char *file_name, } strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&stp->st_mtime)); mg_escape(file_name, path, sizeof(path)); - mg_url_encode(file_name, strlen(file_name), href, sizeof(href)); + href = mg_url_encode(mg_mk_str(file_name)); mg_printf_http_chunk(nc, "%s%s" "%s%s\n", - href, slash, path, slash, mod, is_dir ? -1 : fsize, + href.p, slash, path, slash, mod, is_dir ? -1 : fsize, size); + free((void *) href.p); } static void mg_scan_directory(struct mg_connection *nc, const char *dir, @@ -8865,10 +8845,10 @@ static int mg_mkdir(const char *path, uint32_t mode) { static void mg_print_props(struct mg_connection *nc, const char *name, cs_stat_t *stp) { - char mtime[64], buf[MG_MAX_PATH * 3]; + char mtime[64]; time_t t = stp->st_mtime; /* store in local variable for NDK compile */ + struct mg_str name_esc = mg_url_encode(mg_mk_str(name)); mg_gmt_time_string(mtime, sizeof(mtime), &t); - mg_url_encode(name, strlen(name), buf, sizeof(buf)); mg_printf(nc, "" "%s" @@ -8882,8 +8862,9 @@ static void mg_print_props(struct mg_connection *nc, const char *name, "HTTP/1.1 200 OK" "" "\n", - buf, S_ISDIR(stp->st_mode) ? "" : "", + name_esc.p, S_ISDIR(stp->st_mode) ? "" : "", (int64_t) stp->st_size, mtime); + free((void *) name_esc.p); } MG_INTERNAL void mg_handle_propfind(struct mg_connection *nc, const char *path, @@ -9823,6 +9804,28 @@ void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass, cs_base64_finish(&ctx); 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"; + 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) { + mbuf_append(&mb, &c, 1); + } else { + mbuf_append(&mb, "%", 1); + mbuf_append(&mb, &hex[c >> 4], 1); + mbuf_append(&mb, &hex[c & 15], 1); + } + } + mbuf_append(&mb, "", 1); + mbuf_trim(&mb); + return mg_mk_str_n(mb.buf, mb.len - 1); +} #ifdef MG_MODULE_LINES #line 1 "mongoose/src/mqtt.c" #endif diff --git a/mongoose.h b/mongoose.h index 514b904e..66fbe857 100644 --- a/mongoose.h +++ b/mongoose.h @@ -4077,6 +4077,14 @@ void mg_mbuf_append_base64(struct mbuf *mbuf, const void *data, size_t len); void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass, struct mbuf *buf); +/* + * 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. + */ +struct mg_str mg_url_encode(const struct mg_str src); + #ifdef __cplusplus } #endif /* __cplusplus */