From 56412193e710666258a5fe4fa7d1a542b142ce5d Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Thu, 30 Jun 2022 20:27:43 +0100 Subject: [PATCH] Add mg_remove_double_dots(), hide mg_http_upload() --- docs/README.md | 70 +++++++++++++++----------------------------------- mongoose.c | 46 ++++++++++++++++----------------- mongoose.h | 1 + src/http.c | 24 ++--------------- src/str.c | 22 +++++++++++++++- src/str.h | 1 + 6 files changed, 69 insertions(+), 95 deletions(-) diff --git a/docs/README.md b/docs/README.md index 4f5e39f2..e967020d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1337,55 +1337,6 @@ A diagram below shows how `mg_http_next_multipart()` in action: Function mg_http_next_multipart() - -### mg\_http\_upload() - -```c - -int mg_http_upload(struct mg_connection *c, struct mg_http_message *hm, - struct mg_fs *fs, const char *dir); -``` - -This is a helper utility function that is used to upload large files by small -chunks. - -Append HTTP POST data to a file in a specified directory. A file name and -file offset are specified by the query string parameters: -`POST /upload?name=firmware.bin&offset=2048 HTTP/1.1`. If the offset is 0, then the -file is truncated. It is a client's responsibility to divide a file into a -smaller chunks and send a sequence of POST requests that will be handled by -this function. - -Parameters: -- `c`- a connection -- `hm` - a parsed HTTP message -- `fs` - a filesystem where to write a file, e.g. `&mg_fs_posix` -- `dir` - a directory name where a file should be stored - -Return value: number of bytes written - -Usage example: - -```c -static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { - if (ev == MG_EV_HTTP_MSG) { - struct mg_http_message *hm = (struct mg_http_message *) ev_data; - if (mg_http_match_uri(hm, "/upload")) { - mg_http_upload(c, hm, &mg_fs_posix, "/tmp"); - } else { - struct mg_http_serve_opts opts = {.root_dir = "."}; // Serve - mg_http_serve_dir(c, ev_data, &opts); // static content - } - } -} - -``` - -See [app.js](https://github.com/cesanta/mongoose/blob/7.5/examples/file-upload/web_root/app.js) -for the example Javascript HTML page code that takes a file and -sends it by small chunks. - - ## Websocket ### struct mg\_ws\_message @@ -2536,6 +2487,27 @@ char *buf[sizeof(data)/2]; unsigned long val = mg_unhex(data, sizeof(data) - 1); // val is now 123 ``` +### mg\_remove\_double\_dots() + +```c +char *mg_remove_double_dots(char *s); +``` + +Modify string `s` in place by removing double dots from it. Used to +sanitize file names or URIs received from the network. + +Parameters: +- `s` - String to sanitise + +Return value: the `s` pointer + +Usage example: + +```c +char data[] = "../../a.txt"; +mg_remove_double_dots(data); // data is /a.txt +``` + ### mg\_snprintf(), mg\_vsnprintf() ```c size_t mg_snprintf(char *buf, size_t len, const char *fmt, ...); diff --git a/mongoose.c b/mongoose.c index ada49653..56767eec 100644 --- a/mongoose.c +++ b/mongoose.c @@ -2036,26 +2036,6 @@ static void listdir(struct mg_connection *c, struct mg_http_message *hm, memcpy(c->send.buf + off - 12, tmp, n); // Set content length } -static void remove_double_dots(char *s) { - char *p = s; - while (*s != '\0') { - *p++ = *s++; - if (s[-1] == '/' || s[-1] == '\\') { - while (s[0] != '\0') { - if (s[0] == '/' || s[0] == '\\') { - s++; - } else if (s[0] == '.' && s[1] == '.' && - (s[2] == '/' || s[2] == '\\')) { - s += 2; - } else { - break; - } - } - } - } - *p = '\0'; -} - // Resolve requested file into `path` and return its fs->st() result static int uri_to_path2(struct mg_connection *c, struct mg_http_message *hm, struct mg_fs *fs, struct mg_str url, struct mg_str dir, @@ -2069,7 +2049,7 @@ static int uri_to_path2(struct mg_connection *c, struct mg_http_message *hm, mg_url_decode(hm->uri.ptr + url.len, hm->uri.len - url.len, path + n, path_size - n, 0); path[path_size - 1] = '\0'; // Double-check - remove_double_dots(path); + mg_remove_double_dots(path); n = strlen(path); while (n > 1 && path[n - 1] == '/') path[--n] = 0; // Trim trailing slashes flags = mg_vcmp(&hm->uri, "/") == 0 ? MG_FS_DIR : fs->st(path, NULL, NULL); @@ -2288,7 +2268,7 @@ int mg_http_upload(struct mg_connection *c, struct mg_http_message *hm, struct mg_fd *fd; long oft = strtol(offset, NULL, 0); mg_snprintf(path, sizeof(path), "%s%c%s", dir, MG_DIRSEP, name); - remove_double_dots(path); + mg_remove_double_dots(path); MG_DEBUG(("%d bytes @ %ld [%s]", (int) hm->body.len, oft, path)); if (oft == 0) fs->rm(path); if ((fd = mg_fs_open(fs, path, MG_FS_WRITE)) == NULL) { @@ -4788,7 +4768,6 @@ void mg_unhex(const char *buf, size_t len, unsigned char *to) { } } - uint64_t mg_tou64(struct mg_str str) { uint64_t result = 0; size_t i = 0; @@ -4815,6 +4794,27 @@ int64_t mg_to64(struct mg_str str) { return result * neg; } +char *mg_remove_double_dots(char *s) { + char *p = s; + while (*s != '\0') { + *p++ = *s++; + if (s[-1] == '/' || s[-1] == '\\') { + while (s[0] != '\0') { + if (s[0] == '/' || s[0] == '\\') { + s++; + } else if (s[0] == '.' && s[1] == '.' && + (s[2] == '/' || s[2] == '\\')) { + s += 2; + } else { + break; + } + } + } + } + *p = '\0'; + return s; +} + #ifdef MG_ENABLE_LINES #line 1 "src/timer.c" #endif diff --git a/mongoose.h b/mongoose.h index 9c0382d7..12d23fd4 100644 --- a/mongoose.h +++ b/mongoose.h @@ -725,6 +725,7 @@ uint64_t mg_tou64(struct mg_str str); size_t mg_lld(char *buf, int64_t val, bool is_signed, bool is_hex); double mg_atod(const char *buf, int len, int *numlen); size_t mg_dtoa(char *buf, size_t len, double d, int width); +char *mg_remove_double_dots(char *s); typedef void (*mg_pc_t)(char, void *); // Custom putchar typedef size_t (*mg_pm_t)(mg_pc_t, void *, va_list *); // %M printer diff --git a/src/http.c b/src/http.c index 04bc07cb..17f6f802 100644 --- a/src/http.c +++ b/src/http.c @@ -621,26 +621,6 @@ static void listdir(struct mg_connection *c, struct mg_http_message *hm, memcpy(c->send.buf + off - 12, tmp, n); // Set content length } -static void remove_double_dots(char *s) { - char *p = s; - while (*s != '\0') { - *p++ = *s++; - if (s[-1] == '/' || s[-1] == '\\') { - while (s[0] != '\0') { - if (s[0] == '/' || s[0] == '\\') { - s++; - } else if (s[0] == '.' && s[1] == '.' && - (s[2] == '/' || s[2] == '\\')) { - s += 2; - } else { - break; - } - } - } - } - *p = '\0'; -} - // Resolve requested file into `path` and return its fs->st() result static int uri_to_path2(struct mg_connection *c, struct mg_http_message *hm, struct mg_fs *fs, struct mg_str url, struct mg_str dir, @@ -654,7 +634,7 @@ static int uri_to_path2(struct mg_connection *c, struct mg_http_message *hm, mg_url_decode(hm->uri.ptr + url.len, hm->uri.len - url.len, path + n, path_size - n, 0); path[path_size - 1] = '\0'; // Double-check - remove_double_dots(path); + mg_remove_double_dots(path); n = strlen(path); while (n > 1 && path[n - 1] == '/') path[--n] = 0; // Trim trailing slashes flags = mg_vcmp(&hm->uri, "/") == 0 ? MG_FS_DIR : fs->st(path, NULL, NULL); @@ -873,7 +853,7 @@ int mg_http_upload(struct mg_connection *c, struct mg_http_message *hm, struct mg_fd *fd; long oft = strtol(offset, NULL, 0); mg_snprintf(path, sizeof(path), "%s%c%s", dir, MG_DIRSEP, name); - remove_double_dots(path); + mg_remove_double_dots(path); MG_DEBUG(("%d bytes @ %ld [%s]", (int) hm->body.len, oft, path)); if (oft == 0) fs->rm(path); if ((fd = mg_fs_open(fs, path, MG_FS_WRITE)) == NULL) { diff --git a/src/str.c b/src/str.c index e072bc9d..80bcec2f 100644 --- a/src/str.c +++ b/src/str.c @@ -196,7 +196,6 @@ void mg_unhex(const char *buf, size_t len, unsigned char *to) { } } - uint64_t mg_tou64(struct mg_str str) { uint64_t result = 0; size_t i = 0; @@ -222,3 +221,24 @@ int64_t mg_to64(struct mg_str str) { } return result * neg; } + +char *mg_remove_double_dots(char *s) { + char *p = s; + while (*s != '\0') { + *p++ = *s++; + if (s[-1] == '/' || s[-1] == '\\') { + while (s[0] != '\0') { + if (s[0] == '/' || s[0] == '\\') { + s++; + } else if (s[0] == '.' && s[1] == '.' && + (s[2] == '/' || s[2] == '\\')) { + s += 2; + } else { + break; + } + } + } + } + *p = '\0'; + return s; +} diff --git a/src/str.h b/src/str.h index 71b89343..38c455dd 100644 --- a/src/str.h +++ b/src/str.h @@ -40,6 +40,7 @@ uint64_t mg_tou64(struct mg_str str); size_t mg_lld(char *buf, int64_t val, bool is_signed, bool is_hex); double mg_atod(const char *buf, int len, int *numlen); size_t mg_dtoa(char *buf, size_t len, double d, int width); +char *mg_remove_double_dots(char *s); typedef void (*mg_pc_t)(char, void *); // Custom putchar typedef size_t (*mg_pm_t)(mg_pc_t, void *, va_list *); // %M printer