From 3a46055e521356f313c691f78551fbcff51ce2b1 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Fri, 30 Jul 2021 13:19:20 +0100 Subject: [PATCH] Better packed test --- Makefile | 39 ++++++++++++++------------ docs/README.md | 24 ++++++++++++++++ examples/complete/Makefile | 6 ++-- examples/complete/main.c | 3 +- examples/esp32/Makefile | 2 +- mongoose.c | 44 ++++++++++++++++++++++++------ mongoose.h | 23 ++++++---------- src/config.h | 8 ++++++ src/fs_packed.c | 39 ++++++++++++++++++++------ src/http.c | 2 +- src/util.c | 3 ++ src/util.h | 15 +--------- {examples/complete => test}/pack.c | 19 +++++++++---- test/unit_test.c | 14 ++++++---- 14 files changed, 161 insertions(+), 80 deletions(-) rename {examples/complete => test}/pack.c (79%) diff --git a/Makefile b/Makefile index 69c781e2..cf1c8a85 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ SRCS = mongoose.c test/unit_test.c test/packed_fs.c HDRS = $(wildcard src/*.h) -DEFS ?= -DMG_MAX_HTTP_HEADERS=5 -DMG_ENABLE_LINES +DEFS ?= -DMG_MAX_HTTP_HEADERS=5 -DMG_ENABLE_LINES -DMG_ENABLE_PACKED_FS=1 WARN ?= -W -Wall -Werror -Wshadow -Wdouble-promotion -fno-common -Wconversion OPTS ?= -O3 -g3 INCS ?= -Isrc -I. @@ -27,14 +27,14 @@ CFLAGS += -DMG_ENABLE_OPENSSL=1 -I$(OPENSSL)/include LDFLAGS ?= -L$(OPENSSL)/lib -lssl -lcrypto endif -all: mg_prefix test test++ arm examples vc98 vc2017 mingw mingw++ linux linux++ fuzz +all: mg_prefix unpacked test test++ arm examples vc98 vc2017 mingw mingw++ linux linux++ fuzz examples: @for X in $(EXAMPLES); do $(MAKE) -C $$X example || break; done -test/packed_fs.c: - $(CC) $(CFLAGS) examples/complete/pack.c -o pack - ./pack Makefile > $@ +test/packed_fs.c: Makefile src/fs.h src/ssi.h test/fuzz.c test/data/a.txt + $(CC) $(CFLAGS) test/pack.c -o pack + ./pack $? > $@ # Check that all external (exported) symbols have "mg_" prefix mg_prefix: mongoose.c mongoose.h @@ -49,8 +49,11 @@ test++: test unamalgamated: $(HDRS) Makefile $(CC) src/*.c test/unit_test.c $(CFLAGS) $(LDFLAGS) -g -o unit_test +unpacked: + $(CC) -I. mongoose.c test/unit_test.c -o unit_test + fuzzer: mongoose.c mongoose.h Makefile test/fuzz.c - clang mongoose.c test/fuzz.c $(CFLAGS) -DMG_ENABLE_LINES -DMG_ENABLE_LOG=0 -fsanitize=fuzzer,signed-integer-overflow,address $(LDFLAGS) -g -o $@ + clang mongoose.c test/fuzz.c $(WARN) $(INCS) -DMG_ENABLE_LINES -DMG_ENABLE_LOG=0 -fsanitize=fuzzer,signed-integer-overflow,address -g -o $@ fuzz: fuzzer $(RUN) ./fuzzer @@ -72,33 +75,33 @@ infer: infer run -- cc test/unit_test.c -c -W -Wall -Werror -Isrc -I. -O2 -DMG_ENABLE_MBEDTLS=1 -DMG_ENABLE_LINES -I/usr/local/Cellar/mbedtls/2.23.0/include -DMG_ENABLE_IPV6=1 -g -o /dev/null arm: mongoose.h $(SRCS) - $(DOCKER) mdashnet/armgcc arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb $(SRCS) test/mongoose_custom.c -Itest -DMG_ARCH=MG_ARCH_CUSTOM $(OPTS) $(WARN) $(INCS) -DMG_MAX_HTTP_HEADERS=5 -DMG_ENABLE_LINES=1 -o unit_test -nostartfiles --specs nosys.specs -e 0 + $(DOCKER) mdashnet/armgcc arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb $(SRCS) test/mongoose_custom.c -Itest -DMG_ARCH=MG_ARCH_CUSTOM $(OPTS) $(WARN) $(INCS) $(DEFS) -o unit_test -nostartfiles --specs nosys.specs -e 0 riscv: mongoose.h $(SRCS) - $(DOCKER) mdashnet/riscv riscv-none-elf-gcc -march=rv32imc -mabi=ilp32 $(SRCS) test/mongoose_custom.c -Itest -DMG_ARCH=MG_ARCH_CUSTOM $(OPTS) $(WARN) $(INCS) -DMG_MAX_HTTP_HEADERS=5 -DMG_ENABLE_LINES=1 -o unit_test + $(DOCKER) mdashnet/riscv riscv-none-elf-gcc -march=rv32imc -mabi=ilp32 $(SRCS) test/mongoose_custom.c -Itest -DMG_ARCH=MG_ARCH_CUSTOM $(OPTS) $(WARN) $(INCS) $(DEFS) -o unit_test #vc98: VCFLAGS += -DMG_ENABLE_IPV6=1 -vc98: Makefile mongoose.c mongoose.h test/unit_test.c - $(DOCKER) mdashnet/vc98 wine cl mongoose.c test/unit_test.c $(VCFLAGS) ws2_32.lib /Fe$@.exe +vc98: Makefile mongoose.h $(SRCS) + $(DOCKER) mdashnet/vc98 wine cl $(SRCS) $(VCFLAGS) ws2_32.lib /Fe$@.exe $(DOCKER) mdashnet/vc98 wine $@.exe #vc2017: VCFLAGS += -DMG_ENABLE_IPV6=1 -vc2017: Makefile mongoose.c mongoose.h test/unit_test.c - $(DOCKER) mdashnet/vc2017 wine64 cl mongoose.c test/unit_test.c $(VCFLAGS) ws2_32.lib /Fe$@.exe +vc2017: Makefile mongoose.h $(SRCS) + $(DOCKER) mdashnet/vc2017 wine64 cl $(SRCS) $(VCFLAGS) ws2_32.lib /Fe$@.exe $(DOCKER) mdashnet/vc2017 wine64 $@.exe -mingw: Makefile mongoose.c mongoose.h test/unit_test.c - $(DOCKER) mdashnet/mingw i686-w64-mingw32-gcc mongoose.c test/unit_test.c -W -Wall -Werror -I. $(DEFS) -lwsock32 -o test.exe +mingw: Makefile mongoose.h $(SRCS) + $(DOCKER) mdashnet/mingw i686-w64-mingw32-gcc $(SRCS) -W -Wall -Werror -I. $(DEFS) -lwsock32 -o test.exe $(DOCKER) mdashnet/vc98 wine test.exe -mingw++: Makefile mongoose.c mongoose.h test/unit_test.c - $(DOCKER) mdashnet/mingw i686-w64-mingw32-g++ mongoose.c test/unit_test.c -W -Wall -Werror -I. $(DEFS) -lwsock32 -o test.exe +mingw++: Makefile mongoose.h $(SRCS) + $(DOCKER) mdashnet/mingw i686-w64-mingw32-g++ $(SRCS) -W -Wall -Werror -I. $(DEFS) -lwsock32 -o test.exe # Note: for some reason, a binary built with mingw g++, fails to run #linux: CFLAGS += -DMG_ENABLE_IPV6=$(IPV6) linux: CFLAGS += -fsanitize=address,undefined -linux: Makefile mongoose.c mongoose.h test/unit_test.c - $(DOCKER) mdashnet/cc2 gcc mongoose.c test/unit_test.c $(CFLAGS) $(LDFLAGS) -o unit_test_gcc +linux: Makefile mongoose.h $(SRCS) + $(DOCKER) mdashnet/cc2 gcc $(SRCS) $(CFLAGS) $(LDFLAGS) -o unit_test_gcc $(DOCKER) mdashnet/cc2 ./unit_test_gcc linux++: CC = g++ diff --git a/docs/README.md b/docs/README.md index 4a28d501..f6dc17b6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -243,6 +243,8 @@ Here is a list of build constants and their default values: |MG_ENABLE_SOCKETPAIR | 0 | Enable `mg_socketpair()` for multi-threading | |MG_ENABLE_SSI | 1 | Enable serving SSI files by `mg_http_serve_dir()` | |MG_ENABLE_DIRLIST | 0 | Enable directory listing | +|MG_ENABLE_CUSTOM_RANDOM | 0 | Provide custom RNG function `mg_random()` | +|MG_ENABLE_PACKED_FS | 0 | Enable embedded FS support | |MG_IO_SIZE | 2048 | Granularity of the send/recv IO buffer growth | |MG_MAX_RECV_BUF_SIZE | (3 * 1024 * 1024) | Maximum recv buffer size | |MG_MAX_HTTP_HEADERS | 40 | Maximum number of HTTP headers | @@ -755,6 +757,28 @@ parameter. - `headers` - extra headers, default NULL. If not NULL, must end with `\r\n` - `fmt` - a format string for the HTTP body, in a printf semantics +Example - send a simple JSON respose: + ```c + mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{\"result\": %d}", 123); + ``` + +Example - send JSON response using [mjson](https://github.com/cesanta/mjson) library: + ```c + char *json = NULL; + mjson_printf(mjson_print_dynamic_buf, &json, "{%Q:%d}", "name", 123); + mg_http_reply(c, 200, "Content-Type: application/json\r\n", "%s", json); + free(json); + ``` + +Example - send a 302 redirect: + ```c + mg_http_reply(c, 302, "Location: /\r\n", ""); + ``` + +Example - send error: + ```c + mg_http_reply(c, 403, "", "%s", "Not Authorised\n"); + ``` ### mg\_http\_get\_header() diff --git a/examples/complete/Makefile b/examples/complete/Makefile index c55f8a58..0994721b 100644 --- a/examples/complete/Makefile +++ b/examples/complete/Makefile @@ -1,20 +1,20 @@ PROG ?= example SOURCES ?= ../../mongoose.c main.c mjson.c packed_fs.c -CFLAGS ?= -I../.. $(EXTRA) +CFLAGS ?= -I../.. -DMG_ENABLE_PACKED_FS=1 $(EXTRA) FILES_TO_EMBED ?= $(wildcard web_root/*.js) $(wildcard web_root/*.css) $(wildcard web_root/*.html) $(wildcard web_root/images/*.png) $(wildcard images/*.jpg) all: $(PROG) $(RUN) ./$(PROG) $(PROG): - $(CC) pack.c -o pack + $(CC) ../../test/pack.c -o pack ./pack $(FILES_TO_EMBED) > packed_fs.c $(CC) -W -Wall -Wextra -Os -g3 $(CFLAGS) -o $(PROG) $(SOURCES) ROOT ?= $(realpath $(CURDIR)/../..) DOCKER ?= docker run -it --rm -e Tmp=. -e WINEDEBUG=-all -v $(ROOT):$(ROOT) -w $(CURDIR) mdashnet/vc98 wine windows: - $(DOCKER) cl.exe /nologo $(CFLAGS) pack.c /Fepack.exe + $(DOCKER) cl.exe /nologo $(CFLAGS) ../../test/pack.c /Fepack.exe $(DOCKER) cmd /c 'pack.exe $(FILES_TO_EMBED) > packed_fs.c' $(DOCKER) cl.exe /nologo /O2 $(CFLAGS) $(SOURCES) ws2_32.lib /Fe$(PROG).exe $(DOCKER) $(PROG).exe diff --git a/examples/complete/main.c b/examples/complete/main.c index 23f76ea8..d0c1f866 100644 --- a/examples/complete/main.c +++ b/examples/complete/main.c @@ -119,7 +119,8 @@ static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { "Pragma: no-cache\r\nExpires: Thu, 01 Dec 1994 16:00:00 GMT\r\n" "Content-Type: multipart/x-mixed-replace; boundary=--foo\r\n\r\n"); } else if (mg_http_match_uri(hm, "/api/log/static")) { - struct mg_http_serve_opts opts = {.root_dir = NULL}; + struct mg_http_serve_opts opts; + memset(&opts, 0, sizeof(opts)); mg_http_serve_file(c, hm, "log.txt", &opts); } else if (mg_http_match_uri(hm, "/api/log/live")) { c->label[0] = 'L'; // Mark that connection as live log listener diff --git a/examples/esp32/Makefile b/examples/esp32/Makefile index d4fc6aa2..3fc92995 100644 --- a/examples/esp32/Makefile +++ b/examples/esp32/Makefile @@ -15,4 +15,4 @@ flash: cd build && $(ESPTOOL) --chip esp32 -p $(COMPORT) -b 460800 --before=default_reset --after=hard_reset write_flash --flash_mode dio --flash_freq 40m --flash_size 2MB 0x8000 partition_table/partition-table.bin 0x1000 bootloader/bootloader.bin 0x100000 mongoose-esp32-example.bin clean: - rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb mongoose mongoose_* mongoose.* build sdkconfig build + rm -rf build diff --git a/mongoose.c b/mongoose.c index 9d0f75f3..bfd023af 100644 --- a/mongoose.c +++ b/mongoose.c @@ -417,32 +417,55 @@ struct packed_file { size_t pos; }; -const char *mg_unpack(const char *, size_t *) WEAK; -const char *mg_unpack(const char *path, size_t *size) { - (void) path, (void) size; +const char *mg_unpack(const char *path, size_t *size, time_t *mtime); +const char *mg_unlist(size_t no); +#if MG_ENABLE_PACKED_FS +#else +const char *mg_unpack(const char *path, size_t *size, time_t *mtime) { + (void) path, (void) size, (void) mtime; return NULL; } +const char *mg_unlist(size_t no) { + (void) no; + return NULL; +} +#endif static char *packed_realpath(const char *path, char *resolved_path) { if (resolved_path == NULL) resolved_path = (char *) malloc(strlen(path) + 1); + while (*path == '.' || *path == '/') path++; strcpy(resolved_path, path); return resolved_path; } +static int is_dir_prefix(const char *prefix, size_t n, const char *path) { + return n < strlen(path) && memcmp(prefix, path, n) == 0 && + (n == 0 || path[n] == MG_DIRSEP); +} + static int packed_stat(const char *path, size_t *size, time_t *mtime) { - const char *data = mg_unpack(path, size); - if (mtime) *mtime = 0; - return data == NULL ? MG_FS_DIR : MG_FS_READ; + const char *p; + size_t i, n = strlen(path); + if (mg_unpack(path, size, mtime)) return MG_FS_READ; // Regular file + // Scan all files. If `path` is a dir prefix for any of them, it's a dir + for (i = 0; (p = mg_unlist(i)) != NULL; i++) { + if (is_dir_prefix(path, n, p)) return MG_FS_DIR; + } + return 0; } static void packed_list(const char *path, void (*fn)(const char *, void *), void *userdata) { - (void) path, (void) fn, (void) userdata; + const char *p; + size_t i, n = strlen(path); + for (i = 0; (p = mg_unlist(i)) != NULL; i++) { + if (is_dir_prefix(path, n, p)) fn(&p[n], userdata); + } } static struct mg_fd *packed_open(const char *path, int flags) { size_t size = 0; - const char *data = mg_unpack(path, &size); + const char *data = mg_unpack(path, &size, NULL); struct packed_file *fp = NULL; struct mg_fd *fd = NULL; if (data == NULL) return NULL; @@ -1332,7 +1355,7 @@ static void printdirentry(const char *name, void *userdata) { char path[MG_PATH_MAX], sz[64], mod[64]; int flags, n = 0; - if (snprintf(path, sizeof(path), "%s%c%s", d->dir, MG_DIRSEP, name) < 0) { + if (snprintf(path, sizeof(path), "%s%c%s", d->dir, '/', name) < 0) { LOG(LL_ERROR, ("%s truncated", name)); } else if ((flags = fs->stat(path, &size, &mtime)) == 0) { LOG(LL_ERROR, ("%lu stat(%s): %d", d->c->id, path, errno)); @@ -4155,6 +4178,8 @@ bool mg_file_printf(const char *path, const char *fmt, ...) { return result; } +#if MG_ENABLE_CUSTOM_RANDOM +#else void mg_random(void *buf, size_t len) { bool done = false; unsigned char *p = (unsigned char *) buf; @@ -4173,6 +4198,7 @@ void mg_random(void *buf, size_t len) { while (len--) *p++ = (unsigned char) (rand() & 255); } } +#endif bool mg_globmatch(const char *s1, size_t n1, const char *s2, size_t n2) { size_t i = 0, j = 0, ni = 0, nj = 0; diff --git a/mongoose.h b/mongoose.h index eb4d3607..f1dc0577 100644 --- a/mongoose.h +++ b/mongoose.h @@ -66,6 +66,14 @@ extern "C" { #define MG_ENABLE_SOCKETPAIR 0 #endif +#ifndef MG_ENABLE_CUSTOM_RANDOM +#define MG_ENABLE_CUSTOM_RANDOM 0 +#endif + +#ifndef MG_ENABLE_PACKED_FS +#define MG_ENABLE_PACKED_FS 0 +#endif + // Granularity of the send/recv IO buffer growth #ifndef MG_IO_SIZE #define MG_IO_SIZE 2048 @@ -517,23 +525,10 @@ void mg_timer_poll(unsigned long uptime_ms); -// WEAK symbol makes it possible to define a "default" function implementation, -// which could be overridden by the user who can define a function with the -// same name without linking conflict -#if !defined(WEAK) -#if (defined(__GNUC__) || defined(__clang__) || \ - defined(__TI_COMPILER_VERSION__)) && \ - !defined(_WIN32) && !defined(__CYGWIN__) -#define WEAK __attribute__((weak)) -#else -#define WEAK -#endif -#endif - char *mg_file_read(const char *path, size_t *size); bool mg_file_write(const char *path, const void *buf, size_t len); bool mg_file_printf(const char *path, const char *fmt, ...); -void mg_random(void *buf, size_t len) WEAK; +void mg_random(void *buf, size_t len); bool mg_globmatch(const char *pattern, size_t plen, const char *s, size_t n); bool mg_next_comma_entry(struct mg_str *s, struct mg_str *k, struct mg_str *v); uint16_t mg_ntohs(uint16_t net); diff --git a/src/config.h b/src/config.h index fdb418fd..d1f52ed4 100644 --- a/src/config.h +++ b/src/config.h @@ -41,6 +41,14 @@ #define MG_ENABLE_SOCKETPAIR 0 #endif +#ifndef MG_ENABLE_CUSTOM_RANDOM +#define MG_ENABLE_CUSTOM_RANDOM 0 +#endif + +#ifndef MG_ENABLE_PACKED_FS +#define MG_ENABLE_PACKED_FS 0 +#endif + // Granularity of the send/recv IO buffer growth #ifndef MG_IO_SIZE #define MG_IO_SIZE 2048 diff --git a/src/fs_packed.c b/src/fs_packed.c index 638ef45e..9d4c8d79 100644 --- a/src/fs_packed.c +++ b/src/fs_packed.c @@ -6,32 +6,55 @@ struct packed_file { size_t pos; }; -const char *mg_unpack(const char *, size_t *) WEAK; -const char *mg_unpack(const char *path, size_t *size) { - (void) path, (void) size; +const char *mg_unpack(const char *path, size_t *size, time_t *mtime); +const char *mg_unlist(size_t no); +#if MG_ENABLE_PACKED_FS +#else +const char *mg_unpack(const char *path, size_t *size, time_t *mtime) { + (void) path, (void) size, (void) mtime; return NULL; } +const char *mg_unlist(size_t no) { + (void) no; + return NULL; +} +#endif static char *packed_realpath(const char *path, char *resolved_path) { if (resolved_path == NULL) resolved_path = (char *) malloc(strlen(path) + 1); + while (*path == '.' || *path == '/') path++; strcpy(resolved_path, path); return resolved_path; } +static int is_dir_prefix(const char *prefix, size_t n, const char *path) { + return n < strlen(path) && memcmp(prefix, path, n) == 0 && + (n == 0 || path[n] == MG_DIRSEP); +} + static int packed_stat(const char *path, size_t *size, time_t *mtime) { - const char *data = mg_unpack(path, size); - if (mtime) *mtime = 0; - return data == NULL ? MG_FS_DIR : MG_FS_READ; + const char *p; + size_t i, n = strlen(path); + if (mg_unpack(path, size, mtime)) return MG_FS_READ; // Regular file + // Scan all files. If `path` is a dir prefix for any of them, it's a dir + for (i = 0; (p = mg_unlist(i)) != NULL; i++) { + if (is_dir_prefix(path, n, p)) return MG_FS_DIR; + } + return 0; } static void packed_list(const char *path, void (*fn)(const char *, void *), void *userdata) { - (void) path, (void) fn, (void) userdata; + const char *p; + size_t i, n = strlen(path); + for (i = 0; (p = mg_unlist(i)) != NULL; i++) { + if (is_dir_prefix(path, n, p)) fn(&p[n], userdata); + } } static struct mg_fd *packed_open(const char *path, int flags) { size_t size = 0; - const char *data = mg_unpack(path, &size); + const char *data = mg_unpack(path, &size, NULL); struct packed_file *fp = NULL; struct mg_fd *fd = NULL; if (data == NULL) return NULL; diff --git a/src/http.c b/src/http.c index 19097fb2..a2b732dd 100644 --- a/src/http.c +++ b/src/http.c @@ -596,7 +596,7 @@ static void printdirentry(const char *name, void *userdata) { char path[MG_PATH_MAX], sz[64], mod[64]; int flags, n = 0; - if (snprintf(path, sizeof(path), "%s%c%s", d->dir, MG_DIRSEP, name) < 0) { + if (snprintf(path, sizeof(path), "%s%c%s", d->dir, '/', name) < 0) { LOG(LL_ERROR, ("%s truncated", name)); } else if ((flags = fs->stat(path, &size, &mtime)) == 0) { LOG(LL_ERROR, ("%lu stat(%s): %d", d->c->id, path, errno)); diff --git a/src/util.c b/src/util.c index 93faa6c9..def70bfb 100644 --- a/src/util.c +++ b/src/util.c @@ -57,6 +57,8 @@ bool mg_file_printf(const char *path, const char *fmt, ...) { return result; } +#if MG_ENABLE_CUSTOM_RANDOM +#else void mg_random(void *buf, size_t len) { bool done = false; unsigned char *p = (unsigned char *) buf; @@ -75,6 +77,7 @@ void mg_random(void *buf, size_t len) { while (len--) *p++ = (unsigned char) (rand() & 255); } } +#endif bool mg_globmatch(const char *s1, size_t n1, const char *s2, size_t n2) { size_t i = 0, j = 0, ni = 0, nj = 0; diff --git a/src/util.h b/src/util.h index ee2eb483..e232aec0 100644 --- a/src/util.h +++ b/src/util.h @@ -3,23 +3,10 @@ #include "arch.h" #include "str.h" -// WEAK symbol makes it possible to define a "default" function implementation, -// which could be overridden by the user who can define a function with the -// same name without linking conflict -#if !defined(WEAK) -#if (defined(__GNUC__) || defined(__clang__) || \ - defined(__TI_COMPILER_VERSION__)) && \ - !defined(_WIN32) && !defined(__CYGWIN__) -#define WEAK __attribute__((weak)) -#else -#define WEAK -#endif -#endif - char *mg_file_read(const char *path, size_t *size); bool mg_file_write(const char *path, const void *buf, size_t len); bool mg_file_printf(const char *path, const char *fmt, ...); -void mg_random(void *buf, size_t len) WEAK; +void mg_random(void *buf, size_t len); bool mg_globmatch(const char *pattern, size_t plen, const char *s, size_t n); bool mg_next_comma_entry(struct mg_str *s, struct mg_str *k, struct mg_str *v); uint16_t mg_ntohs(uint16_t net); diff --git a/examples/complete/pack.c b/test/pack.c similarity index 79% rename from examples/complete/pack.c rename to test/pack.c index 46775491..1a6216de 100644 --- a/examples/complete/pack.c +++ b/test/pack.c @@ -20,13 +20,18 @@ #include #include +#include static const char *code = - "const char *mg_unpack(const char *name, size_t *size) {\n" + "const char *mg_unlist(size_t no) {\n" + " return packed_files[no].name;\n" + "}\n" + "const char *mg_unpack(const char *name, size_t *size, time_t *mtime) {\n" " const struct packed_file *p;\n" " for (p = packed_files; p->name != NULL; p++) {\n" " if (strcmp(p->name, name) != 0) continue;\n" " if (size != NULL) *size = p->size - 1;\n" + " if (mtime != NULL) *mtime = p->mtime;\n" " return (const char *) p->data;\n" " }\n" " return NULL;\n" @@ -37,12 +42,13 @@ int main(int argc, char *argv[]) { printf("%s", "#include \n"); printf("%s", "#include \n"); + printf("%s", "#include \n"); printf("%s", "\n"); for (i = 1; i < argc; i++) { - FILE *fp = fopen(argv[i], "rb"); char ascii[12]; - if (fp == NULL) exit(EXIT_FAILURE); + FILE *fp = fopen(argv[i], "rb"); + if (fp == NULL) printf("Cannot open %s\n", argv[i]), exit(EXIT_FAILURE); printf("static const unsigned char v%d[] = {\n", i); for (j = 0; (ch = fgetc(fp)) != EOF; j++) { @@ -64,12 +70,15 @@ int main(int argc, char *argv[]) { printf("%s", " const char *name;\n"); printf("%s", " const unsigned char *data;\n"); printf("%s", " size_t size;\n"); + printf("%s", " time_t mtime;\n"); printf("%s", "} packed_files[] = {\n"); for (i = 1; i < argc; i++) { - printf(" {\"%s\", v%d, sizeof(v%d) },\n", argv[i], i, i); + struct stat st; + stat(argv[i], &st); + printf(" {\"%s\", v%d, sizeof(v%d), %lu},\n", argv[i], i, i, st.st_mtime); } - printf("%s", " {NULL, NULL, 0}\n"); + printf("%s", " {NULL, NULL, 0, 0}\n"); printf("%s", "};\n\n"); printf("%s", code); diff --git a/test/unit_test.c b/test/unit_test.c index 75f3d93d..1cdb821d 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -1368,19 +1368,22 @@ static void eh7(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { static void test_packed(void) { struct mg_mgr mgr; const char *url = "http://127.0.0.1:12351"; - char buf[FETCH_BUF_SIZE] = ""; + char buf[FETCH_BUF_SIZE] = "", *data = mg_file_read("Makefile", NULL); mg_mgr_init(&mgr); mg_http_listen(&mgr, url, eh7, NULL); - // ASSERT(fetch(&mgr, buf, url, "GET /packed/ HTTP/1.0\n\n") == 404); - // fetch(&mgr, buf, url, "GET / HTTP/1.0\n\n"); - fetch(&mgr, buf, url, "GET /Makefile HTTP/1.0\n\n"); - printf("--------\n%s\n", buf); + ASSERT(fetch(&mgr, buf, url, "GET /Makefile HTTP/1.0\n\n") == 200); + ASSERT(cmpbody(buf, data) == 0); + free(data); + ASSERT(fetch(&mgr, buf, url, "GET / HTTP/1.0\n\n") == 200); + // printf("--------\n%s\n", buf); + // exit(0); mg_mgr_free(&mgr); ASSERT(mgr.conns == NULL); } int main(void) { mg_log_set("3"); + test_packed(); test_crc32(); test_multipart(); test_http_chunked(); @@ -1403,7 +1406,6 @@ int main(void) { test_http_no_content_length(); test_http_pipeline(); test_http_range(); - test_packed(); test_mqtt(); printf("SUCCESS. Total tests: %d\n", s_num_tests); return EXIT_SUCCESS;