Better packed test

This commit is contained in:
Sergey Lyubka 2021-07-30 13:19:20 +01:00
parent 2af5d07467
commit 3a46055e52
14 changed files with 161 additions and 80 deletions

View File

@ -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++

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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));

View File

@ -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;

View File

@ -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);

View File

@ -20,13 +20,18 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
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 <stddef.h>\n");
printf("%s", "#include <string.h>\n");
printf("%s", "#include <time.h>\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);

View File

@ -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;