diff --git a/Makefile b/Makefile index 93bea014..33c00f75 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ CFLAGS += -DMG_ENABLE_OPENSSL=1 -I$(OPENSSL)/include LDFLAGS ?= -L$(OPENSSL)/lib -lssl -lcrypto endif -all: mg_prefix unpacked test test++ arm examples vc98 vc2017 mingw mingw++ linux linux++ fuzz +all: mg_prefix unamalgamated unpacked test test++ arm examples vc98 vc2017 mingw mingw++ linux linux++ fuzz examples: @for X in $(EXAMPLES); do $(MAKE) -C $$X example || break; done @@ -125,7 +125,7 @@ mongoose.c: Makefile $(wildcard src/*) (cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@ mongoose.h: $(HDRS) Makefile - (cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/config.h src/str.h src/log.h src/timer.h src/util.h src/fs.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h | sed -e 's,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@ + (cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/config.h src/str.h src/log.h src/timer.h src/fs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h | sed -e 's,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@ clean: rm -rf $(PROG) *.o *.dSYM unit_test* ut fuzzer *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb slow-unit* _CL_* infer-out data.txt crash-* test/packed_fs.c pack diff --git a/docs/README.md b/docs/README.md index 0bfa0d58..ac46ff80 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1177,7 +1177,7 @@ void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { ```c int mg_http_upload(struct mg_connection *c, struct mg_http_message *hm, - const char *dir); + struct mg_fs *fs, const char *dir); ``` Handle file upload. See [file upload example](https://github.com/cesanta/mongoose/tree/master/examples/file-uploads/). @@ -1212,6 +1212,7 @@ The expected usage of this API function follows: Parameters: - `c` - Connection to use - `hm` - POST message, containing parameters described above +- `fs` - Filesystem to use - `dir` - Path to directory Return value: Request body length or negative value on error @@ -1223,7 +1224,7 @@ Usage example: 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; - mg_http_upload(c, hm, "."); // Upload to current folder + mg_http_upload(c, hm, &mg_fs_posix, "."); // Upload to current folder } ``` @@ -1852,6 +1853,7 @@ struct mg_tls_opts { const char *certkey; // Certificate key const char *ciphers; // Cipher list struct mg_str srvname; // If not empty, enables server name verification + struct mg_fs *fs; // FS API for reading certificate files }; ``` @@ -2840,7 +2842,7 @@ mg_base64_decode("Q2VzYW50YQ==", 12, buf); // buf is now "Cesanta" ### mg\_file\_read() ```c -char *mg_file_read(const char *path, size_t *sizep); +char *mg_file_read(struct mg_fs *fs, const char *path, size_t *sizep); ``` Read file contents into a nul-terminated malloc-ed string. It is a caller's @@ -2848,6 +2850,7 @@ responsibility to free() a returned pointer. If `sizep` is not NULL, it will return a file size in bytes. Return `NULL` on error. Parameters: +- `fs` - Filesystem to use - `path` - Path to file to read - `sizep` - Pointer to `size_t` to receive file size @@ -2857,7 +2860,7 @@ Usage example: ```c size_t file_size; -char* data = mg_file_read("myfile.txt", &file_size); +char* data = mg_file_read(&mg_fs_posix, "myfile.txt", &file_size); if (data != NULL) { // `data` is now pointer to information readen from file and `file_size` is it size. } @@ -2867,12 +2870,13 @@ free(data); ### mg\_file\_write() ```c -bool mg_file_write(const char *path, const void *buf, size_t len); +bool mg_file_write(struct mg_fs *fs, const char *path, const void *buf, size_t len); ``` Write data to a file. The write is atomic, i.e. data gets written to a temporary file first, then `rename()-ed` to a destination file name. Parameters: +- `fs` - Filesystem to use - `path` - Path to file - `buf` - Data to write - `len` - Data length @@ -2883,7 +2887,7 @@ Usage example: ```c char data[] = "Hello, world!"; -if(mg_file_write("my_file.txt", data, sizeof(data) - 1)) { +if(mg_file_write(&mg_fs_posix, "my_file.txt", data, sizeof(data) - 1)) { // File contains "Hello, world!" string } ``` @@ -2891,7 +2895,7 @@ if(mg_file_write("my_file.txt", data, sizeof(data) - 1)) { ### mg\_file\_printf() ```c -int mg_file_printf(const char *path, const char *fmt, ...); +bool mg_file_printf(struct mg_fs *fs, const char *path, const char *fmt, ...); ``` Write into a file `path` using `printf()` semantics. @@ -2899,13 +2903,14 @@ This function prints data to a temporary in-memory buffer first, then calls `mg_file_write()`. Parameters: +- `fs` - Filesystem to use - `path`- path to file - `fmt` - Format string in `printf()` semantics Return value: `true` on success, `false` otherwise ```c -if (mg_file_printf("my_file.txt", "Hello, %s!", "world") { +if (mg_file_printf(&mg_fs_posix, "my_file.txt", "Hello, %s!", "world") { // File contains "Hello, world!" string } ``` diff --git a/examples/complete/main.c b/examples/complete/main.c index d0c1f866..6a287a9f 100644 --- a/examples/complete/main.c +++ b/examples/complete/main.c @@ -147,7 +147,7 @@ static void broadcast_mjpeg_frame(struct mg_mgr *mgr) { static size_t i; const char *path = files[i++ % nfiles]; size_t size = 0; - char *data = mg_file_read(path, &size); // Read next file + char *data = mg_file_read(&mg_fs_posix, path, &size); // Read next file struct mg_connection *c; for (c = mgr->conns; c != NULL; c = c->next) { if (c->label[0] != 'S') continue; // Skip non-stream connections diff --git a/examples/esp32/main/main.c b/examples/esp32/main/main.c index a47e47a4..2cba9ff4 100644 --- a/examples/esp32/main/main.c +++ b/examples/esp32/main/main.c @@ -40,7 +40,7 @@ void app_main(void) { .base_path = FS_ROOT, .max_files = 20, .format_if_mount_failed = true}; int res = esp_vfs_spiffs_register(&conf); LOG(res == ESP_OK ? LL_INFO : LL_ERROR, ("FS %s, %d", conf.base_path, res)); - mg_file_printf(FS_ROOT "/hello.txt", "%s", "hello from ESP"); + mg_file_printf(&mg_fs_posix, FS_ROOT "/hello.txt", "%s", "hello from ESP"); // Setup wifi. This function is implemented in wifi.c // It blocks until connected to the configured WiFi network diff --git a/examples/video-stream/main.c b/examples/video-stream/main.c index e98f2f44..9c6be6fa 100644 --- a/examples/video-stream/main.c +++ b/examples/video-stream/main.c @@ -33,7 +33,7 @@ static void broadcast_mjpeg_frame(struct mg_mgr *mgr) { static size_t i; const char *path = files[i++ % nfiles]; size_t size = 0; - char *data = mg_file_read(path, &size); // Read next file + char *data = mg_file_read(&mg_fs_posix, path, &size); // Read next file struct mg_connection *c; for (c = mgr->conns; c != NULL; c = c->next) { if (c->label[0] != 'S') continue; // Skip non-stream connections diff --git a/mongoose.c b/mongoose.c index 9a72b650..dfef6f8e 100644 --- a/mongoose.c +++ b/mongoose.c @@ -413,6 +413,7 @@ void mg_error(struct mg_connection *c, const char *fmt, ...) { #endif + struct mg_fd *mg_fs_open(struct mg_fs *fs, const char *path, int flags) { struct mg_fd *fd = (struct mg_fd *) calloc(1, sizeof(*fd)); if (fd != NULL) { @@ -433,6 +434,59 @@ void mg_fs_close(struct mg_fd *fd) { } } +char *mg_file_read(struct mg_fs *fs, const char *path, size_t *sizep) { + struct mg_fd *fd; + char *data = NULL; + size_t size = 0; + fs->stat(path, &size, NULL); + if ((fd = mg_fs_open(fs, path, MG_FS_READ)) != NULL) { + data = (char *) calloc(1, size + 1); + if (data != NULL) { + if (fs->read(fd->fd, data, size) != size) { + free(data); + data = NULL; + } else { + data[size] = '\0'; + if (sizep != NULL) *sizep = size; + } + } + mg_fs_close(fd); + } + return data; +} + +bool mg_file_write(struct mg_fs *fs, const char *path, const void *buf, + size_t len) { + bool result = false; + struct mg_fd *fd; + char tmp[MG_PATH_MAX]; + snprintf(tmp, sizeof(tmp), "%s..%d", path, rand()); + if ((fd = mg_fs_open(fs, tmp, MG_FS_WRITE)) != NULL) { + result = fs->write(fd->fd, buf, len) == len; + mg_fs_close(fd); + if (result) { + fs->remove(path); + fs->rename(tmp, path); + } else { + fs->remove(tmp); + } + } + return result; +} + +bool mg_file_printf(struct mg_fs *fs, const char *path, const char *fmt, ...) { + char tmp[256], *buf = tmp; + bool result; + int len; + va_list ap; + va_start(ap, fmt); + len = mg_vasprintf(&buf, sizeof(tmp), fmt, ap); + va_end(ap); + result = mg_file_write(fs, path, buf, len > 0 ? (size_t) len : 0); + if (buf != tmp) free(buf); + return result; +} + #ifdef MG_ENABLE_LINES #line 1 "src/fs_fat.c" #endif @@ -475,10 +529,8 @@ static void ff_list(const char *dir, void (*fn)(const char *, void *), static void *ff_open(const char *path, int flags) { FIL f; - const char mode = flags == (MG_FS_READ | MG_FS_WRITE) ? FA_READ | FA_WRITE - : flags & MG_FS_READ ? FA_READ - : flags & MG_FS_WRITE ? FA_WRITE - : 0; + unsigned char mode = + flags == MG_FS_READ ? FA_READ : FA_READ | FA_WRITE | FA_OPEN_APPEND; if (f_open(&f, path, mode) == 0) { FIL *fp = calloc(1, sizeof(*fp)); *fp = f; @@ -512,8 +564,16 @@ static size_t ff_seek(void *fp, size_t offset) { return offset; } -struct mg_fs mg_fs_fat = {ff_stat, ff_list, ff_open, ff_close, - ff_read, ff_write, ff_seek}; +static bool ff_rename(const char *from, const char *to) { + return ff_rename(from, to) == FR_OK; +} + +static bool ff_remove(const char *path) { + return ff_remove(path) == 0; +} + +struct mg_fs mg_fs_fat = {ff_stat, ff_list, ff_open, ff_close, ff_read, + ff_write, ff_seek, ff_rename, ff_remove}; #endif #ifdef MG_ENABLE_LINES @@ -614,9 +674,19 @@ static size_t packed_seek(void *fd, size_t offset) { return fp->pos; } -struct mg_fs mg_fs_packed = {packed_stat, packed_list, packed_open, - packed_close, packed_read, packed_write, - packed_seek}; +static bool packed_rename(const char *from, const char *to) { + (void) from, (void) to; + return false; +} + +static bool packed_remove(const char *path) { + (void) path; + return false; +} + +struct mg_fs mg_fs_packed = {packed_stat, packed_list, packed_open, + packed_close, packed_read, packed_write, + packed_seek, packed_rename, packed_remove}; #ifdef MG_ENABLE_LINES #line 1 "src/fs_posix.c" @@ -779,10 +849,7 @@ static void p_list(const char *dir, void (*fn)(const char *, void *), } static void *p_open(const char *path, int flags) { - const char *mode = flags == (MG_FS_READ | MG_FS_WRITE) ? "r+b" - : flags & MG_FS_READ ? "rb" - : flags & MG_FS_WRITE ? "wb" - : ""; + const char *mode = flags == MG_FS_READ ? "rb" : "a+b"; #ifdef _WIN32 wchar_t b1[PATH_MAX], b2[10]; MultiByteToWideChar(CP_UTF8, 0, path, -1, b1, sizeof(b1) / sizeof(b1[0])); @@ -794,7 +861,7 @@ static void *p_open(const char *path, int flags) { } static void p_close(void *fp) { - if (fp != NULL) fclose((FILE *) fp); + fclose((FILE *) fp); } static size_t p_read(void *fp, void *buf, size_t len) { @@ -816,6 +883,14 @@ static size_t p_seek(void *fp, size_t offset) { return (size_t) ftell((FILE *) fp); } +static bool p_rename(const char *from, const char *to) { + return rename(from, to) == 0; +} + +static bool p_remove(const char *path) { + return remove(path) == 0; +} + #else static int p_stat(const char *path, size_t *size, time_t *mtime) { @@ -851,10 +926,18 @@ static size_t p_seek(void *fd, size_t offset) { (void) fd, (void) offset; return (size_t) ~0; } +static bool p_rename(const char *from, const char *to) { + (void) from, (void) to; + return false; +} +static bool p_remove(const char *path) { + (void) path; + return false; +} #endif -struct mg_fs mg_fs_posix = {p_stat, p_list, p_open, p_close, - p_read, p_write, p_seek}; +struct mg_fs mg_fs_posix = {p_stat, p_list, p_open, p_close, p_read, + p_write, p_seek, p_rename, p_remove}; #ifdef MG_ENABLE_LINES #line 1 "src/http.c" @@ -1748,9 +1831,8 @@ void mg_http_delete_chunk(struct mg_connection *c, struct mg_http_message *hm) { c->recv.len -= ch.len; } -#if MG_ENABLE_FILE int mg_http_upload(struct mg_connection *c, struct mg_http_message *hm, - const char *dir) { + struct mg_fs *fs, const char *dir) { char offset[40] = "", name[200] = "", path[256]; mg_http_get_var(&hm->query, "offset", offset, sizeof(offset)); mg_http_get_var(&hm->query, "name", name, sizeof(name)); @@ -1758,23 +1840,23 @@ int mg_http_upload(struct mg_connection *c, struct mg_http_message *hm, mg_http_reply(c, 400, "", "%s", "name required"); return -1; } else { - FILE *fp; + struct mg_fd *fd; long oft = strtol(offset, NULL, 0); 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 ((fp = fopen(path, oft == 0 ? "wb" : "ab")) == NULL) { - mg_http_reply(c, 400, "", "fopen(%s): %d", path, errno); + if (oft == 0) fs->remove(path); + if ((fd = mg_fs_open(fs, path, MG_FS_WRITE)) == NULL) { + mg_http_reply(c, 400, "", "open(%s): %d", path, errno); return -2; } else { - fwrite(hm->body.ptr, 1, hm->body.len, fp); - fclose(fp); + fs->write(fd->fd, hm->body.ptr, hm->body.len); + mg_fs_close(fd); mg_http_reply(c, 200, "", ""); return (int) hm->body.len; } } } -#endif static void http_cb(struct mg_connection *c, int ev, void *evd, void *fnd) { if (ev == MG_EV_READ || ev == MG_EV_CLOSE) { @@ -3840,11 +3922,55 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) { #endif + #if MG_ENABLE_MBEDTLS + +#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000 +#define MGRNG , rng_get, NULL +#else +#define MGRNG +#endif + +void mg_tls_free(struct mg_connection *c) { + struct mg_tls *tls = (struct mg_tls *) c->tls; + if (tls != NULL) { + free(tls->cafile); + mbedtls_ssl_free(&tls->ssl); + mbedtls_pk_free(&tls->pk); + mbedtls_x509_crt_free(&tls->ca); + mbedtls_x509_crl_free(&tls->crl); + mbedtls_x509_crt_free(&tls->cert); + mbedtls_ssl_config_free(&tls->conf); + free(tls); + c->tls = NULL; + } +} + +static bool mg_wouldblock(int n) { + return n < 0 && + (errno == EINPROGRESS || errno == EAGAIN || errno == EWOULDBLOCK); +} + +static int mg_net_send(void *ctx, const unsigned char *buf, size_t len) { + int fd = *(int *) ctx; + int n = (int) send(fd, buf, len, 0); + if (n > 0) return n; + if (mg_wouldblock(n)) return MBEDTLS_ERR_SSL_WANT_WRITE; + return MBEDTLS_ERR_NET_SEND_FAILED; +} + +static int mg_net_recv(void *ctx, unsigned char *buf, size_t len) { + int fd = *(int *) ctx; + int n = (int) recv(fd, buf, len, 0); + if (n > 0) return n; + if (mg_wouldblock(n)) return MBEDTLS_ERR_SSL_WANT_READ; + return MBEDTLS_ERR_NET_RECV_FAILED; +} + void mg_tls_handshake(struct mg_connection *c) { struct mg_tls *tls = (struct mg_tls *) c->tls; int rc; - mbedtls_ssl_set_bio(&tls->ssl, &c->fd, mbedtls_net_send, mbedtls_net_recv, 0); + mbedtls_ssl_set_bio(&tls->ssl, &c->fd, mg_net_send, mg_net_recv, 0); rc = mbedtls_ssl_handshake(&tls->ssl); if (rc == 0) { // Success LOG(LL_DEBUG, ("%lu success", c->id)); @@ -3880,27 +4006,23 @@ static int rng_get(void *p_rng, unsigned char *buf, size_t len) { } #endif +static struct mg_str mg_loadfile(struct mg_fs *fs, const char *path) { + size_t n = 0; + if (path[0] == '-') return mg_str(path); + char *p = mg_file_read(fs, path, &n); + return mg_str_n(p, n); +} + void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) { + struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs; struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls)); int rc = 0; - const char *ca = opts->ca == NULL ? "-" - : opts->ca[0] == '-' ? "(emb)" - : opts->ca; - const char *crl = opts->crl == NULL ? "-" - : opts->crl[0] == '-' ? "(emb)" - : opts->crl; - const char *cert = opts->cert == NULL ? "-" - : opts->cert[0] == '-' ? "(emb)" - : opts->cert; - const char *certkey = opts->certkey == NULL ? "-" - : opts->certkey[0] == '-' ? "(emb)" - : opts->certkey; - if (tls == NULL) { + c->tls = tls; + if (c->tls == NULL) { mg_error(c, "TLS OOM"); goto fail; } - LOG(LL_DEBUG, ("%lu Setting TLS, CA: %s, CRL: %s, cert: %s, key: %s", c->id, - ca, crl, cert, certkey)); + LOG(LL_DEBUG, ("%lu Setting TLS", c->id)); mbedtls_ssl_init(&tls->ssl); mbedtls_ssl_config_init(&tls->conf); mbedtls_x509_crt_init(&tls->ca); @@ -3908,9 +4030,6 @@ void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) { mbedtls_x509_crt_init(&tls->cert); mbedtls_pk_init(&tls->pk); mbedtls_ssl_conf_dbg(&tls->conf, debug_cb, c); - //#if !defined(ESP_PLATFORM) - // mbedtls_debug_set_threshold(5); - //#endif if ((rc = mbedtls_ssl_config_defaults( &tls->conf, c->is_client ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER, @@ -3921,15 +4040,13 @@ void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) { mbedtls_ssl_conf_rng(&tls->conf, mbed_rng, c); if (opts->ca == NULL || strcmp(opts->ca, "*") == 0) { mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE); - } - if (opts->ca != NULL && opts->ca[0] != '\0') { + } else if (opts->ca != NULL && opts->ca[0] != '\0') { if (opts->crl != NULL && opts->crl[0] != '\0') { - rc = opts->crl[0] == '-' - ? mbedtls_x509_crl_parse(&tls->crl, (uint8_t *) opts->crl, - strlen(opts->crl) + 1) - : mbedtls_x509_crl_parse_file(&tls->crl, opts->crl); + struct mg_str s = mg_loadfile(fs, opts->crl); + rc = mbedtls_x509_crl_parse(&tls->crl, (uint8_t *) s.ptr, s.len + 1); + if (opts->crl[0] != '-') free((char *) s.ptr); if (rc != 0) { - mg_error(c, "parse(%s) err %#x", crl, -rc); + mg_error(c, "parse(%s) err %#x", opts->crl, -rc); goto fail; } } @@ -3941,12 +4058,12 @@ void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) { goto fail; } #else - rc = opts->ca[0] == '-' - ? mbedtls_x509_crt_parse(&tls->ca, (uint8_t *) opts->ca, - strlen(opts->ca) + 1) - : mbedtls_x509_crt_parse_file(&tls->ca, opts->ca); + struct mg_str s = mg_loadfile(fs, opts->ca); + rc = mbedtls_x509_crt_parse(&tls->ca, (uint8_t *) s.ptr, s.len + 1); + if (opts->ca[0] != '-') free((char *) s.ptr); + LOG(LL_INFO, ("%s %d", opts->ca, (int) s.len)); if (rc != 0) { - mg_error(c, "parse(%s) err %#x", ca, -rc); + mg_error(c, "parse(%s) err %#x", opts->ca, -rc); goto fail; } mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->ca, &tls->crl); @@ -3961,24 +4078,20 @@ void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) { mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED); } if (opts->cert != NULL && opts->cert[0] != '\0') { - const char *key = opts->certkey; - if (key == NULL) { - key = opts->cert; - certkey = cert; - } - rc = opts->cert[0] == '-' - ? mbedtls_x509_crt_parse(&tls->cert, (uint8_t *) opts->cert, - strlen(opts->cert) + 1) - : mbedtls_x509_crt_parse_file(&tls->cert, opts->cert); + struct mg_str s = mg_loadfile(fs, opts->cert); + const char *key = opts->certkey == NULL ? opts->cert : opts->certkey; + rc = mbedtls_x509_crt_parse(&tls->cert, (uint8_t *) s.ptr, s.len + 1); + if (opts->cert[0] != '-') free((char *) s.ptr); if (rc != 0) { - mg_error(c, "parse(%s) err %#x", cert, -rc); + mg_error(c, "parse(%s) err %#x", opts->cert, -rc); goto fail; } - rc = key[0] == '-' ? mbedtls_pk_parse_key(&tls->pk, (uint8_t *) key, - strlen(key) + 1, NULL, 0 RNG) - : mbedtls_pk_parse_keyfile(&tls->pk, key, NULL RNG); + s = mg_loadfile(fs, key); + rc = mbedtls_pk_parse_key(&tls->pk, (uint8_t *) s.ptr, s.len + 1, NULL, + 0 MGRNG); + if (key[0] != '-') free((char *) s.ptr); if (rc != 0) { - mg_error(c, "tls key(%s) %#x", certkey, -rc); + mg_error(c, "tls key(%s) %#x", key, -rc); goto fail; } rc = mbedtls_ssl_conf_own_cert(&tls->conf, &tls->cert, &tls->pk); @@ -3999,8 +4112,7 @@ void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) { } return; fail: - c->is_closing = 1; - free(tls); + mg_tls_free(c); } long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) { @@ -4014,20 +4126,6 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) { long n = mbedtls_ssl_write(&tls->ssl, (unsigned char *) buf, len); return n == 0 ? -1 : n == MBEDTLS_ERR_SSL_WANT_WRITE ? 0 : n; } - -void mg_tls_free(struct mg_connection *c) { - struct mg_tls *tls = (struct mg_tls *) c->tls; - if (tls == NULL) return; - free(tls->cafile); - mbedtls_ssl_free(&tls->ssl); - mbedtls_pk_free(&tls->pk); - mbedtls_x509_crt_free(&tls->ca); - mbedtls_x509_crl_free(&tls->crl); - mbedtls_x509_crt_free(&tls->cert); - mbedtls_ssl_config_free(&tls->conf); - free(tls); - c->tls = NULL; -} #endif #ifdef MG_ENABLE_LINES @@ -4279,63 +4377,6 @@ struct mg_str mg_url_pass(const char *url) { #include #endif -#if MG_ENABLE_FILE -char *mg_file_read(const char *path, size_t *sizep) { - FILE *fp; - char *data = NULL; - size_t size = 0; - if ((fp = fopen(path, "rb")) != NULL) { - fseek(fp, 0, SEEK_END); - size = (size_t) ftell(fp); - rewind(fp); - data = (char *) calloc(1, size + 1); - if (data != NULL) { - if (fread(data, 1, size, fp) != size) { - free(data); - data = NULL; - } else { - data[size] = '\0'; - if (sizep != NULL) *sizep = size; - } - } - fclose(fp); - } - return data; -} - -bool mg_file_write(const char *path, const void *buf, size_t len) { - bool result = false; - FILE *fp; - char tmp[MG_PATH_MAX]; - snprintf(tmp, sizeof(tmp), "%s.%d", path, rand()); - fp = fopen(tmp, "wb"); - if (fp != NULL) { - result = fwrite(buf, 1, len, fp) == len; - fclose(fp); - if (result) { - remove(path); - rename(tmp, path); - } else { - remove(tmp); - } - } - return result; -} - -bool mg_file_printf(const char *path, const char *fmt, ...) { - char tmp[256], *buf = tmp; - bool result; - int len; - va_list ap; - va_start(ap, fmt); - len = mg_vasprintf(&buf, sizeof(tmp), fmt, ap); - va_end(ap); - result = mg_file_write(path, buf, len > 0 ? (size_t) len : 0); - if (buf != tmp) free(buf); - return result; -} -#endif - #if MG_ENABLE_CUSTOM_RANDOM #else void mg_random(void *buf, size_t len) { diff --git a/mongoose.h b/mongoose.h index 7f9de745..421ffb88 100644 --- a/mongoose.h +++ b/mongoose.h @@ -610,10 +610,44 @@ void mg_timer_poll(int64_t current_time_ms); +enum { MG_FS_READ = 1, MG_FS_WRITE = 2, MG_FS_DIR = 4 }; + +// Filesystem API functions +// stat() returns MG_FS_* flags and populates file size and modification time +// list() calls fn() for every directory entry, allowing to list a directory +struct mg_fs { + int (*stat)(const char *path, size_t *size, time_t *mtime); + void (*list)(const char *path, void (*fn)(const char *, void *), void *); + void *(*open)(const char *path, int flags); // Open file + void (*close)(void *fd); // Close file + size_t (*read)(void *fd, void *buf, size_t len); // Read file + size_t (*write)(void *fd, const void *buf, size_t len); // Write file + size_t (*seek)(void *fd, size_t offset); // Set file position + bool (*rename)(const char *from, const char *to); // Rename + bool (*remove)(const char *path); // Delete file +}; + +// File descriptor +struct mg_fd { + void *fd; + struct mg_fs *fs; +}; + +struct mg_fd *mg_fs_open(struct mg_fs *fs, const char *path, int flags); +void mg_fs_close(struct mg_fd *fd); +char *mg_file_read(struct mg_fs *fs, const char *path, size_t *size); +bool mg_file_write(struct mg_fs *fs, const char *path, const void *, size_t); +bool mg_file_printf(struct mg_fs *fs, const char *path, const char *fmt, ...); + +extern struct mg_fs mg_fs_posix; // POSIX open/close/read/write/seek +extern struct mg_fs mg_fs_packed; // Packed FS, see examples/complete +extern struct mg_fs mg_fs_fat; // FAT FS + + + + + -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); bool mg_globmatch(const char *pattern, size_t plen, const char *s, size_t n); bool mg_commalist(struct mg_str *s, struct mg_str *k, struct mg_str *v); @@ -676,37 +710,6 @@ int64_t mg_millis(void); - - -enum { MG_FS_READ = 1, MG_FS_WRITE = 2, MG_FS_DIR = 4 }; - -// Filesystem API functions -// stat() returns MG_FS_* flags and populates file size and modification time -// list() calls fn() for every directory entry, allowing to list a directory -struct mg_fs { - int (*stat)(const char *path, size_t *size, time_t *mtime); - void (*list)(const char *path, void (*fn)(const char *, void *), void *); - void *(*open)(const char *path, int flags); // Open file - void (*close)(void *fd); // Close file - size_t (*read)(void *fd, void *buf, size_t len); // Read file - size_t (*write)(void *fd, const void *buf, size_t len); // Write file - size_t (*seek)(void *fd, size_t offset); // Set file position -}; - -// File descriptor -struct mg_fd { - void *fd; - struct mg_fs *fs; -}; -struct mg_fd *mg_fs_open(struct mg_fs *fs, const char *path, int flags); -void mg_fs_close(struct mg_fd *fd); - -extern struct mg_fs mg_fs_posix; // POSIX open/close/read/write/seek -extern struct mg_fs mg_fs_packed; // Packed FS, see examples/complete -extern struct mg_fs mg_fs_fat; // FAT FS - - - unsigned short mg_url_port(const char *url); int mg_url_is_ssl(const char *url); struct mg_str mg_url_host(const char *url); @@ -930,7 +933,7 @@ size_t mg_url_encode(const char *s, size_t n, char *buf, size_t len); void mg_http_creds(struct mg_http_message *, char *, size_t, char *, size_t); bool mg_http_match_uri(const struct mg_http_message *, const char *glob); int mg_http_upload(struct mg_connection *, struct mg_http_message *hm, - const char *dir); + struct mg_fs *fs, const char *dir); void mg_http_bauth(struct mg_connection *, const char *user, const char *pass); struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v); size_t mg_http_next_multipart(struct mg_str, size_t, struct mg_http_part *); @@ -951,6 +954,7 @@ struct mg_tls_opts { const char *certkey; // Certificate key const char *ciphers; // Cipher list struct mg_str srvname; // If not empty, enables server name verification + struct mg_fs *fs; // FS API for reading certificate files }; void mg_tls_init(struct mg_connection *, struct mg_tls_opts *); @@ -966,18 +970,9 @@ void mg_tls_handshake(struct mg_connection *); #include +#include #include -#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000 -#define RNG , rng_get, NULL -#else -#define RNG -#endif - -// Different versions have those in different files, so declare here -EXTERN_C int mbedtls_net_recv(void *, unsigned char *, size_t); -EXTERN_C int mbedtls_net_send(void *, const unsigned char *, size_t); - struct mg_tls { char *cafile; // CA certificate path mbedtls_x509_crt ca; // Parsed CA certificate diff --git a/src/fs.c b/src/fs.c index 349c0928..514cd618 100644 --- a/src/fs.c +++ b/src/fs.c @@ -1,4 +1,5 @@ #include "fs.h" +#include "util.h" struct mg_fd *mg_fs_open(struct mg_fs *fs, const char *path, int flags) { struct mg_fd *fd = (struct mg_fd *) calloc(1, sizeof(*fd)); @@ -19,3 +20,56 @@ void mg_fs_close(struct mg_fd *fd) { free(fd); } } + +char *mg_file_read(struct mg_fs *fs, const char *path, size_t *sizep) { + struct mg_fd *fd; + char *data = NULL; + size_t size = 0; + fs->stat(path, &size, NULL); + if ((fd = mg_fs_open(fs, path, MG_FS_READ)) != NULL) { + data = (char *) calloc(1, size + 1); + if (data != NULL) { + if (fs->read(fd->fd, data, size) != size) { + free(data); + data = NULL; + } else { + data[size] = '\0'; + if (sizep != NULL) *sizep = size; + } + } + mg_fs_close(fd); + } + return data; +} + +bool mg_file_write(struct mg_fs *fs, const char *path, const void *buf, + size_t len) { + bool result = false; + struct mg_fd *fd; + char tmp[MG_PATH_MAX]; + snprintf(tmp, sizeof(tmp), "%s..%d", path, rand()); + if ((fd = mg_fs_open(fs, tmp, MG_FS_WRITE)) != NULL) { + result = fs->write(fd->fd, buf, len) == len; + mg_fs_close(fd); + if (result) { + fs->remove(path); + fs->rename(tmp, path); + } else { + fs->remove(tmp); + } + } + return result; +} + +bool mg_file_printf(struct mg_fs *fs, const char *path, const char *fmt, ...) { + char tmp[256], *buf = tmp; + bool result; + int len; + va_list ap; + va_start(ap, fmt); + len = mg_vasprintf(&buf, sizeof(tmp), fmt, ap); + va_end(ap); + result = mg_file_write(fs, path, buf, len > 0 ? (size_t) len : 0); + if (buf != tmp) free(buf); + return result; +} diff --git a/src/fs.h b/src/fs.h index a05f9438..d10db8bb 100644 --- a/src/fs.h +++ b/src/fs.h @@ -16,6 +16,8 @@ struct mg_fs { size_t (*read)(void *fd, void *buf, size_t len); // Read file size_t (*write)(void *fd, const void *buf, size_t len); // Write file size_t (*seek)(void *fd, size_t offset); // Set file position + bool (*rename)(const char *from, const char *to); // Rename + bool (*remove)(const char *path); // Delete file }; // File descriptor @@ -23,8 +25,12 @@ struct mg_fd { void *fd; struct mg_fs *fs; }; + struct mg_fd *mg_fs_open(struct mg_fs *fs, const char *path, int flags); void mg_fs_close(struct mg_fd *fd); +char *mg_file_read(struct mg_fs *fs, const char *path, size_t *size); +bool mg_file_write(struct mg_fs *fs, const char *path, const void *, size_t); +bool mg_file_printf(struct mg_fs *fs, const char *path, const char *fmt, ...); extern struct mg_fs mg_fs_posix; // POSIX open/close/read/write/seek extern struct mg_fs mg_fs_packed; // Packed FS, see examples/complete diff --git a/src/fs_fat.c b/src/fs_fat.c index eaf6e464..6d5dd463 100644 --- a/src/fs_fat.c +++ b/src/fs_fat.c @@ -37,10 +37,8 @@ static void ff_list(const char *dir, void (*fn)(const char *, void *), static void *ff_open(const char *path, int flags) { FIL f; - const char mode = flags == (MG_FS_READ | MG_FS_WRITE) ? FA_READ | FA_WRITE - : flags & MG_FS_READ ? FA_READ - : flags & MG_FS_WRITE ? FA_WRITE - : 0; + unsigned char mode = + flags == MG_FS_READ ? FA_READ : FA_READ | FA_WRITE | FA_OPEN_APPEND; if (f_open(&f, path, mode) == 0) { FIL *fp = calloc(1, sizeof(*fp)); *fp = f; @@ -74,6 +72,14 @@ static size_t ff_seek(void *fp, size_t offset) { return offset; } -struct mg_fs mg_fs_fat = {ff_stat, ff_list, ff_open, ff_close, - ff_read, ff_write, ff_seek}; +static bool ff_rename(const char *from, const char *to) { + return ff_rename(from, to) == FR_OK; +} + +static bool ff_remove(const char *path) { + return ff_remove(path) == 0; +} + +struct mg_fs mg_fs_fat = {ff_stat, ff_list, ff_open, ff_close, ff_read, + ff_write, ff_seek, ff_rename, ff_remove}; #endif diff --git a/src/fs_packed.c b/src/fs_packed.c index 9b8e6080..ba69e265 100644 --- a/src/fs_packed.c +++ b/src/fs_packed.c @@ -93,6 +93,16 @@ static size_t packed_seek(void *fd, size_t offset) { return fp->pos; } -struct mg_fs mg_fs_packed = {packed_stat, packed_list, packed_open, - packed_close, packed_read, packed_write, - packed_seek}; +static bool packed_rename(const char *from, const char *to) { + (void) from, (void) to; + return false; +} + +static bool packed_remove(const char *path) { + (void) path; + return false; +} + +struct mg_fs mg_fs_packed = {packed_stat, packed_list, packed_open, + packed_close, packed_read, packed_write, + packed_seek, packed_rename, packed_remove}; diff --git a/src/fs_posix.c b/src/fs_posix.c index 628d2ace..f91d7976 100644 --- a/src/fs_posix.c +++ b/src/fs_posix.c @@ -156,10 +156,7 @@ static void p_list(const char *dir, void (*fn)(const char *, void *), } static void *p_open(const char *path, int flags) { - const char *mode = flags == (MG_FS_READ | MG_FS_WRITE) ? "r+b" - : flags & MG_FS_READ ? "rb" - : flags & MG_FS_WRITE ? "wb" - : ""; + const char *mode = flags == MG_FS_READ ? "rb" : "a+b"; #ifdef _WIN32 wchar_t b1[PATH_MAX], b2[10]; MultiByteToWideChar(CP_UTF8, 0, path, -1, b1, sizeof(b1) / sizeof(b1[0])); @@ -171,7 +168,7 @@ static void *p_open(const char *path, int flags) { } static void p_close(void *fp) { - if (fp != NULL) fclose((FILE *) fp); + fclose((FILE *) fp); } static size_t p_read(void *fp, void *buf, size_t len) { @@ -193,6 +190,14 @@ static size_t p_seek(void *fp, size_t offset) { return (size_t) ftell((FILE *) fp); } +static bool p_rename(const char *from, const char *to) { + return rename(from, to) == 0; +} + +static bool p_remove(const char *path) { + return remove(path) == 0; +} + #else static int p_stat(const char *path, size_t *size, time_t *mtime) { @@ -228,7 +233,15 @@ static size_t p_seek(void *fd, size_t offset) { (void) fd, (void) offset; return (size_t) ~0; } +static bool p_rename(const char *from, const char *to) { + (void) from, (void) to; + return false; +} +static bool p_remove(const char *path) { + (void) path; + return false; +} #endif -struct mg_fs mg_fs_posix = {p_stat, p_list, p_open, p_close, - p_read, p_write, p_seek}; +struct mg_fs mg_fs_posix = {p_stat, p_list, p_open, p_close, p_read, + p_write, p_seek, p_rename, p_remove}; diff --git a/src/http.c b/src/http.c index c16ea13c..a9276828 100644 --- a/src/http.c +++ b/src/http.c @@ -887,9 +887,8 @@ void mg_http_delete_chunk(struct mg_connection *c, struct mg_http_message *hm) { c->recv.len -= ch.len; } -#if MG_ENABLE_FILE int mg_http_upload(struct mg_connection *c, struct mg_http_message *hm, - const char *dir) { + struct mg_fs *fs, const char *dir) { char offset[40] = "", name[200] = "", path[256]; mg_http_get_var(&hm->query, "offset", offset, sizeof(offset)); mg_http_get_var(&hm->query, "name", name, sizeof(name)); @@ -897,23 +896,23 @@ int mg_http_upload(struct mg_connection *c, struct mg_http_message *hm, mg_http_reply(c, 400, "", "%s", "name required"); return -1; } else { - FILE *fp; + struct mg_fd *fd; long oft = strtol(offset, NULL, 0); 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 ((fp = fopen(path, oft == 0 ? "wb" : "ab")) == NULL) { - mg_http_reply(c, 400, "", "fopen(%s): %d", path, errno); + if (oft == 0) fs->remove(path); + if ((fd = mg_fs_open(fs, path, MG_FS_WRITE)) == NULL) { + mg_http_reply(c, 400, "", "open(%s): %d", path, errno); return -2; } else { - fwrite(hm->body.ptr, 1, hm->body.len, fp); - fclose(fp); + fs->write(fd->fd, hm->body.ptr, hm->body.len); + mg_fs_close(fd); mg_http_reply(c, 200, "", ""); return (int) hm->body.len; } } } -#endif static void http_cb(struct mg_connection *c, int ev, void *evd, void *fnd) { if (ev == MG_EV_READ || ev == MG_EV_CLOSE) { diff --git a/src/http.h b/src/http.h index 8b7ecc6c..05952cdd 100644 --- a/src/http.h +++ b/src/http.h @@ -58,7 +58,7 @@ size_t mg_url_encode(const char *s, size_t n, char *buf, size_t len); void mg_http_creds(struct mg_http_message *, char *, size_t, char *, size_t); bool mg_http_match_uri(const struct mg_http_message *, const char *glob); int mg_http_upload(struct mg_connection *, struct mg_http_message *hm, - const char *dir); + struct mg_fs *fs, const char *dir); void mg_http_bauth(struct mg_connection *, const char *user, const char *pass); struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v); size_t mg_http_next_multipart(struct mg_str, size_t, struct mg_http_part *); diff --git a/src/tls.h b/src/tls.h index 704c366e..77f112e4 100644 --- a/src/tls.h +++ b/src/tls.h @@ -11,6 +11,7 @@ struct mg_tls_opts { const char *certkey; // Certificate key const char *ciphers; // Cipher list struct mg_str srvname; // If not empty, enables server name verification + struct mg_fs *fs; // FS API for reading certificate files }; void mg_tls_init(struct mg_connection *, struct mg_tls_opts *); diff --git a/src/tls_mbed.c b/src/tls_mbed.c index f1dc8b3c..0f86829b 100644 --- a/src/tls_mbed.c +++ b/src/tls_mbed.c @@ -1,10 +1,54 @@ +#include "fs.h" #include "tls.h" #if MG_ENABLE_MBEDTLS + +#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000 +#define MGRNG , rng_get, NULL +#else +#define MGRNG +#endif + +void mg_tls_free(struct mg_connection *c) { + struct mg_tls *tls = (struct mg_tls *) c->tls; + if (tls != NULL) { + free(tls->cafile); + mbedtls_ssl_free(&tls->ssl); + mbedtls_pk_free(&tls->pk); + mbedtls_x509_crt_free(&tls->ca); + mbedtls_x509_crl_free(&tls->crl); + mbedtls_x509_crt_free(&tls->cert); + mbedtls_ssl_config_free(&tls->conf); + free(tls); + c->tls = NULL; + } +} + +static bool mg_wouldblock(int n) { + return n < 0 && + (errno == EINPROGRESS || errno == EAGAIN || errno == EWOULDBLOCK); +} + +static int mg_net_send(void *ctx, const unsigned char *buf, size_t len) { + int fd = *(int *) ctx; + int n = (int) send(fd, buf, len, 0); + if (n > 0) return n; + if (mg_wouldblock(n)) return MBEDTLS_ERR_SSL_WANT_WRITE; + return MBEDTLS_ERR_NET_SEND_FAILED; +} + +static int mg_net_recv(void *ctx, unsigned char *buf, size_t len) { + int fd = *(int *) ctx; + int n = (int) recv(fd, buf, len, 0); + if (n > 0) return n; + if (mg_wouldblock(n)) return MBEDTLS_ERR_SSL_WANT_READ; + return MBEDTLS_ERR_NET_RECV_FAILED; +} + void mg_tls_handshake(struct mg_connection *c) { struct mg_tls *tls = (struct mg_tls *) c->tls; int rc; - mbedtls_ssl_set_bio(&tls->ssl, &c->fd, mbedtls_net_send, mbedtls_net_recv, 0); + mbedtls_ssl_set_bio(&tls->ssl, &c->fd, mg_net_send, mg_net_recv, 0); rc = mbedtls_ssl_handshake(&tls->ssl); if (rc == 0) { // Success LOG(LL_DEBUG, ("%lu success", c->id)); @@ -40,27 +84,23 @@ static int rng_get(void *p_rng, unsigned char *buf, size_t len) { } #endif +static struct mg_str mg_loadfile(struct mg_fs *fs, const char *path) { + size_t n = 0; + if (path[0] == '-') return mg_str(path); + char *p = mg_file_read(fs, path, &n); + return mg_str_n(p, n); +} + void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) { + struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs; struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls)); int rc = 0; - const char *ca = opts->ca == NULL ? "-" - : opts->ca[0] == '-' ? "(emb)" - : opts->ca; - const char *crl = opts->crl == NULL ? "-" - : opts->crl[0] == '-' ? "(emb)" - : opts->crl; - const char *cert = opts->cert == NULL ? "-" - : opts->cert[0] == '-' ? "(emb)" - : opts->cert; - const char *certkey = opts->certkey == NULL ? "-" - : opts->certkey[0] == '-' ? "(emb)" - : opts->certkey; - if (tls == NULL) { + c->tls = tls; + if (c->tls == NULL) { mg_error(c, "TLS OOM"); goto fail; } - LOG(LL_DEBUG, ("%lu Setting TLS, CA: %s, CRL: %s, cert: %s, key: %s", c->id, - ca, crl, cert, certkey)); + LOG(LL_DEBUG, ("%lu Setting TLS", c->id)); mbedtls_ssl_init(&tls->ssl); mbedtls_ssl_config_init(&tls->conf); mbedtls_x509_crt_init(&tls->ca); @@ -68,9 +108,6 @@ void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) { mbedtls_x509_crt_init(&tls->cert); mbedtls_pk_init(&tls->pk); mbedtls_ssl_conf_dbg(&tls->conf, debug_cb, c); - //#if !defined(ESP_PLATFORM) - // mbedtls_debug_set_threshold(5); - //#endif if ((rc = mbedtls_ssl_config_defaults( &tls->conf, c->is_client ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER, @@ -81,15 +118,13 @@ void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) { mbedtls_ssl_conf_rng(&tls->conf, mbed_rng, c); if (opts->ca == NULL || strcmp(opts->ca, "*") == 0) { mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE); - } - if (opts->ca != NULL && opts->ca[0] != '\0') { + } else if (opts->ca != NULL && opts->ca[0] != '\0') { if (opts->crl != NULL && opts->crl[0] != '\0') { - rc = opts->crl[0] == '-' - ? mbedtls_x509_crl_parse(&tls->crl, (uint8_t *) opts->crl, - strlen(opts->crl) + 1) - : mbedtls_x509_crl_parse_file(&tls->crl, opts->crl); + struct mg_str s = mg_loadfile(fs, opts->crl); + rc = mbedtls_x509_crl_parse(&tls->crl, (uint8_t *) s.ptr, s.len + 1); + if (opts->crl[0] != '-') free((char *) s.ptr); if (rc != 0) { - mg_error(c, "parse(%s) err %#x", crl, -rc); + mg_error(c, "parse(%s) err %#x", opts->crl, -rc); goto fail; } } @@ -101,12 +136,12 @@ void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) { goto fail; } #else - rc = opts->ca[0] == '-' - ? mbedtls_x509_crt_parse(&tls->ca, (uint8_t *) opts->ca, - strlen(opts->ca) + 1) - : mbedtls_x509_crt_parse_file(&tls->ca, opts->ca); + struct mg_str s = mg_loadfile(fs, opts->ca); + rc = mbedtls_x509_crt_parse(&tls->ca, (uint8_t *) s.ptr, s.len + 1); + if (opts->ca[0] != '-') free((char *) s.ptr); + LOG(LL_INFO, ("%s %d", opts->ca, (int) s.len)); if (rc != 0) { - mg_error(c, "parse(%s) err %#x", ca, -rc); + mg_error(c, "parse(%s) err %#x", opts->ca, -rc); goto fail; } mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->ca, &tls->crl); @@ -121,24 +156,20 @@ void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) { mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED); } if (opts->cert != NULL && opts->cert[0] != '\0') { - const char *key = opts->certkey; - if (key == NULL) { - key = opts->cert; - certkey = cert; - } - rc = opts->cert[0] == '-' - ? mbedtls_x509_crt_parse(&tls->cert, (uint8_t *) opts->cert, - strlen(opts->cert) + 1) - : mbedtls_x509_crt_parse_file(&tls->cert, opts->cert); + struct mg_str s = mg_loadfile(fs, opts->cert); + const char *key = opts->certkey == NULL ? opts->cert : opts->certkey; + rc = mbedtls_x509_crt_parse(&tls->cert, (uint8_t *) s.ptr, s.len + 1); + if (opts->cert[0] != '-') free((char *) s.ptr); if (rc != 0) { - mg_error(c, "parse(%s) err %#x", cert, -rc); + mg_error(c, "parse(%s) err %#x", opts->cert, -rc); goto fail; } - rc = key[0] == '-' ? mbedtls_pk_parse_key(&tls->pk, (uint8_t *) key, - strlen(key) + 1, NULL, 0 RNG) - : mbedtls_pk_parse_keyfile(&tls->pk, key, NULL RNG); + s = mg_loadfile(fs, key); + rc = mbedtls_pk_parse_key(&tls->pk, (uint8_t *) s.ptr, s.len + 1, NULL, + 0 MGRNG); + if (key[0] != '-') free((char *) s.ptr); if (rc != 0) { - mg_error(c, "tls key(%s) %#x", certkey, -rc); + mg_error(c, "tls key(%s) %#x", key, -rc); goto fail; } rc = mbedtls_ssl_conf_own_cert(&tls->conf, &tls->cert, &tls->pk); @@ -159,8 +190,7 @@ void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) { } return; fail: - c->is_closing = 1; - free(tls); + mg_tls_free(c); } long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) { @@ -174,18 +204,4 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) { long n = mbedtls_ssl_write(&tls->ssl, (unsigned char *) buf, len); return n == 0 ? -1 : n == MBEDTLS_ERR_SSL_WANT_WRITE ? 0 : n; } - -void mg_tls_free(struct mg_connection *c) { - struct mg_tls *tls = (struct mg_tls *) c->tls; - if (tls == NULL) return; - free(tls->cafile); - mbedtls_ssl_free(&tls->ssl); - mbedtls_pk_free(&tls->pk); - mbedtls_x509_crt_free(&tls->ca); - mbedtls_x509_crl_free(&tls->crl); - mbedtls_x509_crt_free(&tls->cert); - mbedtls_ssl_config_free(&tls->conf); - free(tls); - c->tls = NULL; -} #endif diff --git a/src/tls_mbed.h b/src/tls_mbed.h index f1e7a228..9b02a464 100644 --- a/src/tls_mbed.h +++ b/src/tls_mbed.h @@ -6,18 +6,9 @@ #include "util.h" #include +#include #include -#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000 -#define RNG , rng_get, NULL -#else -#define RNG -#endif - -// Different versions have those in different files, so declare here -EXTERN_C int mbedtls_net_recv(void *, unsigned char *, size_t); -EXTERN_C int mbedtls_net_send(void *, const unsigned char *, size_t); - struct mg_tls { char *cafile; // CA certificate path mbedtls_x509_crt ca; // Parsed CA certificate diff --git a/src/util.c b/src/util.c index 8981a5a6..5f47815c 100644 --- a/src/util.c +++ b/src/util.c @@ -4,63 +4,6 @@ #include #endif -#if MG_ENABLE_FILE -char *mg_file_read(const char *path, size_t *sizep) { - FILE *fp; - char *data = NULL; - size_t size = 0; - if ((fp = fopen(path, "rb")) != NULL) { - fseek(fp, 0, SEEK_END); - size = (size_t) ftell(fp); - rewind(fp); - data = (char *) calloc(1, size + 1); - if (data != NULL) { - if (fread(data, 1, size, fp) != size) { - free(data); - data = NULL; - } else { - data[size] = '\0'; - if (sizep != NULL) *sizep = size; - } - } - fclose(fp); - } - return data; -} - -bool mg_file_write(const char *path, const void *buf, size_t len) { - bool result = false; - FILE *fp; - char tmp[MG_PATH_MAX]; - snprintf(tmp, sizeof(tmp), "%s.%d", path, rand()); - fp = fopen(tmp, "wb"); - if (fp != NULL) { - result = fwrite(buf, 1, len, fp) == len; - fclose(fp); - if (result) { - remove(path); - rename(tmp, path); - } else { - remove(tmp); - } - } - return result; -} - -bool mg_file_printf(const char *path, const char *fmt, ...) { - char tmp[256], *buf = tmp; - bool result; - int len; - va_list ap; - va_start(ap, fmt); - len = mg_vasprintf(&buf, sizeof(tmp), fmt, ap); - va_end(ap); - result = mg_file_write(path, buf, len > 0 ? (size_t) len : 0); - if (buf != tmp) free(buf); - return result; -} -#endif - #if MG_ENABLE_CUSTOM_RANDOM #else void mg_random(void *buf, size_t len) { diff --git a/src/util.h b/src/util.h index 7e99c6b7..570b86ae 100644 --- a/src/util.h +++ b/src/util.h @@ -4,9 +4,6 @@ #include "config.h" #include "str.h" -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); bool mg_globmatch(const char *pattern, size_t plen, const char *s, size_t n); bool mg_commalist(struct mg_str *s, struct mg_str *k, struct mg_str *v); diff --git a/test/unit_test.c b/test/unit_test.c index e366bbc3..cd8db87d 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -380,7 +380,7 @@ static void eh1(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { mg_http_creds(hm, user, sizeof(user), pass, sizeof(pass)); mg_http_reply(c, 200, "", "[%s]:[%s]", user, pass); } else if (mg_http_match_uri(hm, "/upload")) { - mg_http_upload(c, hm, "."); + mg_http_upload(c, hm, &mg_fs_posix, "."); } else if (mg_http_match_uri(hm, "/test/")) { struct mg_http_serve_opts sopts; memset(&sopts, 0, sizeof(sopts)); @@ -416,9 +416,9 @@ struct fetch_data { }; static void fcb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { + struct fetch_data *fd = (struct fetch_data *) fn_data; if (ev == MG_EV_HTTP_MSG) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; - struct fetch_data *fd = (struct fetch_data *) fn_data; snprintf(fd->buf, FETCH_BUF_SIZE, "%.*s", (int) hm->message.len, hm->message.ptr); fd->code = atoi(hm->uri.ptr); @@ -448,6 +448,7 @@ static int fetch(struct mg_mgr *mgr, char *buf, const char *url, opts.srvname = host; } mg_tls_init(c, &opts); + if (c->tls == NULL) fd.closed = 1; // c->is_hexdumping = 1; } va_start(ap, fmt); @@ -617,7 +618,7 @@ static void test_http_server(void) { ASSERT(cmpbody(buf, "Invalid web root [/BAAADDD!]\n") == 0); { - char *data = mg_file_read("./test/data/ca.pem", NULL); + char *data = mg_file_read(&mg_fs_posix, "./test/data/ca.pem", NULL); ASSERT(fetch(&mgr, buf, url, "GET /ca.pem HTTP/1.0\r\n\n") == 200); ASSERT(cmpbody(buf, data) == 0); free(data); @@ -678,7 +679,7 @@ static void test_http_server(void) { // Test upload char *p; remove("uploaded.txt"); - ASSERT((p = mg_file_read("uploaded.txt", NULL)) == NULL); + ASSERT((p = mg_file_read(&mg_fs_posix, "uploaded.txt", NULL)) == NULL); ASSERT(fetch(&mgr, buf, url, "POST /upload HTTP/1.0\n" "Content-Length: 1\n\nx") == 400); @@ -691,7 +692,7 @@ static void test_http_server(void) { "POST /upload?name=uploaded.txt&offset=5 HTTP/1.0\r\n" "Content-Length: 6\r\n" "\r\n\nworld") == 200); - ASSERT((p = mg_file_read("uploaded.txt", NULL)) != NULL); + ASSERT((p = mg_file_read(&mg_fs_posix, "uploaded.txt", NULL)) != NULL); ASSERT(strcmp(p, "hello\nworld") == 0); free(p); remove("uploaded.txt"); @@ -701,12 +702,12 @@ static void test_http_server(void) { // Test upload directory traversal char *p; remove("uploaded.txt"); - ASSERT((p = mg_file_read("uploaded.txt", NULL)) == NULL); + ASSERT((p = mg_file_read(&mg_fs_posix, "uploaded.txt", NULL)) == NULL); ASSERT(fetch(&mgr, buf, url, "POST /upload?name=../uploaded.txt HTTP/1.0\r\n" "Content-Length: 5\r\n" "\r\nhello") == 200); - ASSERT((p = mg_file_read("uploaded.txt", NULL)) != NULL); + ASSERT((p = mg_file_read(&mg_fs_posix, "uploaded.txt", NULL)) != NULL); ASSERT(strcmp(p, "hello") == 0); free(p); remove("uploaded.txt"); @@ -1213,8 +1214,9 @@ static void test_util(void) { ASSERT(s != NULL); free(s); memset(&a, 0, sizeof(a)); - ASSERT(mg_file_printf("data.txt", "%s", "hi") == true); - ASSERT((p = mg_file_read("data.txt", NULL)) != NULL); + ASSERT(mg_file_printf(&mg_fs_posix, "data.txt", "%s", "hi") == true); + if (system("ls -l") != 0) (void) 0; + ASSERT((p = mg_file_read(&mg_fs_posix, "data.txt", NULL)) != NULL); ASSERT(strcmp(p, "hi") == 0); free(p); remove("data.txt"); @@ -1462,7 +1464,8 @@ 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] = "", *data = mg_file_read("Makefile", NULL); + char buf[FETCH_BUF_SIZE] = "", + *data = mg_file_read(&mg_fs_posix, "Makefile", NULL); mg_mgr_init(&mgr); mg_http_listen(&mgr, url, eh7, NULL); @@ -1472,7 +1475,7 @@ static void test_packed(void) { free(data); // Load file deeper in the FS tree directly - data = mg_file_read("src/ssi.h", NULL); + data = mg_file_read(&mg_fs_posix, "src/ssi.h", NULL); ASSERT(fetch(&mgr, buf, url, "GET /src/ssi.h HTTP/1.0\n\n") == 200); ASSERT(cmpbody(buf, data) == 0); free(data);