From f64c86d23f08ac7e425f62bf47d58d88cca25c33 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Thu, 10 Feb 2022 11:56:55 +0000 Subject: [PATCH] Use mg_snprintf() --- examples/file-upload/main.c | 3 +- mongoose.c | 481 ++++++++++++++++++++++-------------- mongoose.h | 55 +---- src/arch_azurertos.h | 8 - src/arch_freertos_lwip.h | 11 - src/arch_freertos_tcp.h | 2 - src/arch_unix.h | 2 - src/arch_win32.h | 13 - src/dns.c | 1 - src/fs.c | 2 +- src/fs_fat.c | 38 ++- src/fs_packed.c | 3 +- src/http.c | 60 ++--- src/log.c | 15 +- src/mqtt.c | 2 +- src/net.c | 12 +- src/ssi.c | 4 +- src/str.c | 219 ++++++++++++++++ src/str.h | 11 + src/util.c | 125 ---------- src/util.h | 8 - test/unit_test.c | 42 +++- 22 files changed, 659 insertions(+), 458 deletions(-) diff --git a/examples/file-upload/main.c b/examples/file-upload/main.c index dbd6c35b..69768902 100644 --- a/examples/file-upload/main.c +++ b/examples/file-upload/main.c @@ -4,8 +4,7 @@ // Streaming upload example. Demonstrates how to use chunked encoding // to send large payload in smaller chunks. To test, use curl utility: // -// curl http://localhost:8000/upload \ -// --data-binary @my_large_file.txt -H 'Transfer-Encoding: chunked' +// curl http://localhost:8000/upload?name=a.txt --data-binary @large_file.txt #include "mongoose.h" diff --git a/mongoose.c b/mongoose.c index 73d7dd38..d01b72af 100644 --- a/mongoose.c +++ b/mongoose.c @@ -341,7 +341,6 @@ static void mg_sendnsreq(struct mg_connection *c, struct mg_str *name, int ms, dnsc->c = mg_connect(c->mgr, dnsc->url, NULL, NULL); if (dnsc->c != NULL) { dnsc->c->pfn = dns_cb; - // snprintf(dnsc->c->label, sizeof(dnsc->c->label), "%s", "DNS"); // dnsc->c->is_hexdumping = 1; } } @@ -456,7 +455,7 @@ bool mg_file_write(struct mg_fs *fs, const char *path, const void *buf, bool result = false; struct mg_fd *fd; char tmp[MG_PATH_MAX]; - snprintf(tmp, sizeof(tmp), "%s..%d", path, rand()); + mg_snprintf(tmp, sizeof(tmp), "%s..%d", path, rand()); if ((fd = mg_fs_open(fs, tmp, MG_FS_WRITE)) != NULL) { result = fs->wr(fd->fd, buf, len) == len; mg_fs_close(fd); @@ -491,6 +490,42 @@ bool mg_file_printf(struct mg_fs *fs, const char *path, const char *fmt, ...) { #if MG_ENABLE_FATFS #include +static int mg_days_from_epoch(int y, int m, int d) { + y -= m <= 2; + int era = y / 400; + int yoe = y - era * 400; + int doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1; + int doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; + return era * 146097 + doe - 719468; +} + +static time_t mg_timegm(struct tm const *t) { + int year = t->tm_year + 1900; + int month = t->tm_mon; // 0-11 + if (month > 11) { + year += month / 12; + month %= 12; + } else if (month < 0) { + int years_diff = (11 - month) / 12; + year -= years_diff; + month += 12 * years_diff; + } + int x = mg_days_from_epoch(year, month + 1, t->tm_mday); + return 60 * (60 * (24L * x + t->tm_hour) + t->tm_min) + t->tm_sec; +} + +static time_t ff_time_to_epoch(uint16_t fdate, uint16_t ftime) { + struct tm tm; + memset(&tm, 0, sizeof(struct tm)); + tm.tm_sec = (ftime << 1) & 0x3e; + tm.tm_min = ((ftime >> 5) & 0x3f); + tm.tm_hour = ((ftime >> 11) & 0x1f); + tm.tm_mday = (fdate & 0x1f); + tm.tm_mon = ((fdate >> 5) & 0x0f) - 1; + tm.tm_year = ((fdate >> 9) & 0x7f) + 80; + return mg_timegm(&tm); +} + static int ff_stat(const char *path, size_t *size, time_t *mtime) { FILINFO fi; if (path[0] == '\0' || strcmp(path, MG_FATFS_ROOT) == 0) { @@ -499,7 +534,7 @@ static int ff_stat(const char *path, size_t *size, time_t *mtime) { return MG_FS_DIR; } else if (f_stat(path, &fi) == 0) { if (size) *size = (size_t) fi.fsize; - if (mtime) *mtime = (fi.fdate << 16) | fi.ftime; + if (mtime) *mtime = ff_time_to_epoch(fi.fdate, fi.ftime); return MG_FS_READ | MG_FS_WRITE | ((fi.fattrib & AM_DIR) ? MG_FS_DIR : 0); } else { return 0; @@ -582,6 +617,7 @@ struct mg_fs mg_fs_fat = {ff_stat, ff_list, ff_open, ff_close, ff_read, #endif + struct packed_file { const char *data; size_t size; @@ -629,7 +665,7 @@ static void packed_list(const char *dir, void (*fn)(const char *, void *), begin = &path[n + 1]; end = strchr(begin, '/'); if (end == NULL) end = begin + strlen(begin); - snprintf(buf, sizeof(buf), "%.*s", (int) (end - begin), begin); + mg_snprintf(buf, sizeof(buf), "%.*s", (int) (end - begin), begin); buf[sizeof(buf) - 1] = '\0'; // If this entry has been already listed, skip // NOTE: we're assuming that file list is sorted alphabetically @@ -1324,8 +1360,7 @@ static void restore_http_cb(struct mg_connection *c) { char *mg_http_etag(char *buf, size_t len, size_t size, time_t mtime); char *mg_http_etag(char *buf, size_t len, size_t size, time_t mtime) { - snprintf(buf, len, "\"%lx." MG_INT64_FMT "\"", (unsigned long) mtime, - (int64_t) size); + mg_snprintf(buf, len, "\"%lld.%lld\"", (int64_t) mtime, (int64_t) size); return buf; } @@ -1446,7 +1481,7 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm, mg_printf(c, "HTTP/1.1 304 Not Modified\r\nContent-Length: 0\r\n\r\n"); } else { int n, status = 200; - char range[100] = ""; + char range[100] = "", tmp[50]; int64_t r1 = 0, r2 = 0, cl = (int64_t) size; struct mg_str mime = guess_content_type(mg_str(path), opts->mime_types); @@ -1458,24 +1493,24 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm, if (r1 > r2 || r2 >= cl) { status = 416; cl = 0; - snprintf(range, sizeof(range), - "Content-Range: bytes */" MG_INT64_FMT "\r\n", (int64_t) size); + mg_snprintf(range, sizeof(range), "Content-Range: bytes */%lld\r\n", + (int64_t) size); } else { status = 206; cl = r2 - r1 + 1; - snprintf(range, sizeof(range), - "Content-Range: bytes " MG_INT64_FMT "-" MG_INT64_FMT - "/" MG_INT64_FMT "\r\n", - r1, r1 + cl - 1, (int64_t) size); + mg_snprintf(range, sizeof(range), + "Content-Range: bytes %lld-%lld/%lld\r\n", r1, r1 + cl - 1, + (int64_t) size); fs->sk(fd->fd, (size_t) r1); } } - + mg_snprintf(tmp, sizeof(tmp), "Content-Length: %lld\r\n", cl); + LOG(LL_INFO, ("TMP: [%s]", tmp)); mg_printf(c, "HTTP/1.1 %d %s\r\nContent-Type: %.*s\r\n" - "Etag: %s\r\nContent-Length: " MG_INT64_FMT "\r\n%s%s\r\n", + "Etag: %s\r\n%s%s%s\r\n", status, mg_http_status_code_str(status), (int) mime.len, mime.ptr, - etag, cl, range, opts->extra_headers ? opts->extra_headers : ""); + etag, tmp, range, opts->extra_headers ? opts->extra_headers : ""); if (mg_vcasecmp(&hm->method, "HEAD") == 0) { c->is_draining = 1; mg_fs_close(fd); @@ -1498,29 +1533,23 @@ static void printdirentry(const char *name, void *userdata) { struct mg_fs *fs = d->opts->fs == NULL ? &mg_fs_posix : d->opts->fs; size_t size = 0; time_t t = 0; - char path[MG_PATH_MAX], sz[64], mod[64]; + char path[MG_PATH_MAX], sz[40], mod[40]; int flags, n = 0; // LOG(LL_DEBUG, ("[%s] [%s]", d->dir, name)); - if (snprintf(path, sizeof(path), "%s%c%s", d->dir, '/', name) < 0) { + if (mg_snprintf(path, sizeof(path), "%s%c%s", d->dir, '/', name) > + sizeof(path)) { LOG(LL_ERROR, ("%s truncated", name)); } else if ((flags = fs->st(path, &size, &t)) == 0) { LOG(LL_ERROR, ("%lu stat(%s): %d", d->c->id, path, errno)); } else { const char *slash = flags & MG_FS_DIR ? "/" : ""; - struct tm tm; if (flags & MG_FS_DIR) { - snprintf(sz, sizeof(sz), "%s", "[DIR]"); - } else if (size < 1024) { - snprintf(sz, sizeof(sz), "%d", (int) size); - } else if (size < 0x100000) { - snprintf(sz, sizeof(sz), "%.1fk", (double) size / 1024.0); - } else if (size < 0x40000000) { - snprintf(sz, sizeof(sz), "%.1fM", (double) size / 1048576); + mg_snprintf(sz, sizeof(sz), "%s", "[DIR]"); } else { - snprintf(sz, sizeof(sz), "%.1fG", (double) size / 1073741824); + mg_snprintf(sz, sizeof(sz), "%llx", (uint64_t) size); } - strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime_r(&t, &tm)); + mg_snprintf(mod, sizeof(mod), "%lx", (unsigned long) t); n = (int) mg_url_encode(name, strlen(name), path, sizeof(path)); mg_printf(d->c, " %s%s" @@ -1588,8 +1617,7 @@ static void listdir(struct mg_connection *c, struct mg_http_message *hm, "
" "
Mongoose v.%s
\n", MG_VERSION); - n = (size_t) snprintf(tmp, sizeof(tmp), "%lu", - (unsigned long) (c->send.len - off)); + n = mg_snprintf(tmp, sizeof(tmp), "%lu", (unsigned long) (c->send.len - off)); if (n > sizeof(tmp)) n = 0; memcpy(c->send.buf + off - 10, tmp, n); // Set content length } @@ -1620,7 +1648,7 @@ static int uri_to_path2(struct mg_connection *c, struct mg_http_message *hm, char *path, size_t path_size) { int flags = 0, tmp; // Append URI to the root_dir, and sanitize it - size_t n = (size_t) snprintf(path, path_size, "%.*s", (int) dir.len, dir.ptr); + size_t n = mg_snprintf(path, path_size, "%.*s", (int) dir.len, dir.ptr); if (n > path_size) n = path_size; path[path_size - 1] = '\0'; if ((fs->st(path, NULL, NULL) & MG_FS_DIR) == 0) { @@ -1649,9 +1677,9 @@ static int uri_to_path2(struct mg_connection *c, struct mg_http_message *hm, (int) hm->uri.len, hm->uri.ptr); flags = 0; } else if (flags & MG_FS_DIR) { - if (((snprintf(path + n, path_size - n, "/" MG_HTTP_INDEX) > 0 && + if (((mg_snprintf(path + n, path_size - n, "/" MG_HTTP_INDEX) > 0 && (tmp = fs->st(path, NULL, NULL)) != 0) || - (snprintf(path + n, path_size - n, "/index.shtml") > 0 && + (mg_snprintf(path + n, path_size - n, "/index.shtml") > 0 && (tmp = fs->st(path, NULL, NULL)) != 0))) { flags = tmp; } else { @@ -1723,14 +1751,14 @@ void mg_http_creds(struct mg_http_message *hm, char *user, size_t userlen, int n = mg_base64_decode(v->ptr + 6, (int) v->len - 6, buf); const char *p = (const char *) memchr(buf, ':', n > 0 ? (size_t) n : 0); if (p != NULL) { - snprintf(user, userlen, "%.*s", (int) (p - buf), buf); - snprintf(pass, passlen, "%.*s", n - (int) (p - buf) - 1, p + 1); + mg_snprintf(user, userlen, "%.*s", (int) (p - buf), buf); + mg_snprintf(pass, passlen, "%.*s", n - (int) (p - buf) - 1, p + 1); } } else if (v != NULL && v->len > 7 && memcmp(v->ptr, "Bearer ", 7) == 0) { - snprintf(pass, passlen, "%.*s", (int) v->len - 7, v->ptr + 7); + mg_snprintf(pass, passlen, "%.*s", (int) v->len - 7, v->ptr + 7); } else if ((v = mg_http_get_header(hm, "Cookie")) != NULL) { struct mg_str t = mg_http_get_header_var(*v, mg_str_n("access_token", 12)); - if (t.len > 0) snprintf(pass, passlen, "%.*s", (int) t.len, t.ptr); + if (t.len > 0) mg_snprintf(pass, passlen, "%.*s", (int) t.len, t.ptr); } else { mg_http_get_var(&hm->query, "access_token", pass, passlen); } @@ -1845,7 +1873,7 @@ int mg_http_upload(struct mg_connection *c, struct mg_http_message *hm, } else { struct mg_fd *fd; long oft = strtol(offset, NULL, 0); - snprintf(path, sizeof(path), "%s%c%s", dir, MG_DIRSEP, name); + mg_snprintf(path, sizeof(path), "%s%c%s", dir, MG_DIRSEP, name); remove_double_dots(path); LOG(LL_DEBUG, ("%d bytes @ %ld [%s]", (int) hm->body.len, oft, path)); if (oft == 0) fs->rm(path); @@ -2034,16 +2062,11 @@ bool mg_log_prefix(int level, const char *file, int line, const char *fname) { } if (level <= max) { - char timebuf[21], buf[50] = ""; - time_t t = time(NULL); - struct tm tmp, *tm = gmtime_r(&t, &tmp); - int n; - (void) tmp; - strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm); - n = snprintf(buf, sizeof(buf), "%s %d %s:%d:%s", timebuf, level, p, line, - fname); - if (n < 0 || n > (int) sizeof(buf) - 2) n = sizeof(buf) - 2; - while (n < (int) sizeof(buf) - 1) buf[n++] = ' '; + char buf[40]; + size_t n = mg_snprintf(buf, sizeof(buf), "%llx %d %s:%d:%s", mg_millis(), + level, p, line, fname); + if (n > sizeof(buf) - 2) n = sizeof(buf) - 2; + while (n < sizeof(buf) - 1) buf[n++] = ' '; s_fn(buf, sizeof(buf) - 1, s_fn_param); return true; } else { @@ -2410,7 +2433,7 @@ int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m) { if (len_len >= 4) return MQTT_MALFORMED; } end = p + n; - if (lc & 0x80 || end > buf + len) return MQTT_INCOMPLETE; + if ((lc & 0x80) || (end > buf + len)) return MQTT_INCOMPLETE; m->dgram.len = (size_t) (end - buf); switch (m->cmd) { @@ -2582,21 +2605,21 @@ char *mg_straddr(struct mg_addr *a, char *buf, size_t len) { char tmp[30]; const char *fmt = a->is_ip6 ? "[%s]:%d" : "%s:%d"; mg_ntoa(a, tmp, sizeof(tmp)); - snprintf(buf, len, fmt, tmp, (int) mg_ntohs(a->port)); + mg_snprintf(buf, len, fmt, tmp, (int) mg_ntohs(a->port)); return buf; } char *mg_ntoa(const struct mg_addr *addr, char *buf, size_t len) { if (addr->is_ip6) { uint16_t *p = (uint16_t *) addr->ip6; - snprintf(buf, len, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx", mg_htons(p[0]), - mg_htons(p[1]), mg_htons(p[2]), mg_htons(p[3]), mg_htons(p[4]), - mg_htons(p[5]), mg_htons(p[6]), mg_htons(p[7])); + mg_snprintf(buf, len, "%x:%x:%x:%x:%x:%x:%x:%x", mg_htons(p[0]), + mg_htons(p[1]), mg_htons(p[2]), mg_htons(p[3]), mg_htons(p[4]), + mg_htons(p[5]), mg_htons(p[6]), mg_htons(p[7])); } else { uint8_t p[4]; memcpy(p, &addr->ip, sizeof(p)); - snprintf(buf, len, "%d.%d.%d.%d", (int) p[0], (int) p[1], (int) p[2], - (int) p[3]); + mg_snprintf(buf, len, "%d.%d.%d.%d", (int) p[0], (int) p[1], (int) p[2], + (int) p[3]); } return buf; } @@ -3713,7 +3736,7 @@ static char *mg_ssi(const char *path, const char *root, int depth) { char tmp[MG_PATH_MAX + BUFSIZ + 10], *p = (char *) path + strlen(path), *data; while (p > path && p[-1] != MG_DIRSEP && p[-1] != '/') p--; - snprintf(tmp, sizeof(tmp), "%.*s%s", (int) (p - path), path, arg); + mg_snprintf(tmp, sizeof(tmp), "%.*s%s", (int) (p - path), path, arg); if (depth < MG_MAX_SSI_DEPTH && (data = mg_ssi(tmp, root, depth + 1)) != NULL) { mg_iobuf_add(&b, b.len, data, strlen(data), align); @@ -3723,7 +3746,7 @@ static char *mg_ssi(const char *path, const char *root, int depth) { } } else if (sscanf(buf, "