From 25e2a99d8e7ee6241e034556192bc792041fd0cf Mon Sep 17 00:00:00 2001 From: cpq Date: Thu, 22 Oct 2026 14:30:10 +0100 Subject: [PATCH] Make mg_http_ota_cb public, add /ota endpoints to MCU examples --- mongoose.c | 117 ++++++++++-------- mongoose.h | 30 ++--- src/dash.c | 21 +--- src/http.c | 76 +++++++----- src/http.h | 25 ++-- src/ota.c | 19 ++- src/ota.h | 5 +- test/unit_test.c | 114 ++++++++++++++++- tutorials/esp32/minimal/main/main.c | 5 + tutorials/micropython/esp32/mongoose/main.c | 7 +- tutorials/micropython/mongoose/main.c | 7 +- tutorials/nxp/frdm-imxrt1186/minimal/main.c | 5 + tutorials/nxp/frdm-mcxe247/minimal/main.c | 5 + tutorials/nxp/frdm-mcxn947/minimal/main.c | 5 + tutorials/nxp/frdm-mcxw71/minimal/main.c | 5 + tutorials/nxp/frdm-rw612/minimal/main.c | 5 + tutorials/nxp/rt1060-evkb/minimal/main.c | 5 + tutorials/nxp/rt1170-evkb/minimal/main.c | 5 + tutorials/rp/pico-rm2/main.c | 7 +- tutorials/rp/pico-rmii/main.c | 7 +- tutorials/rp/pico-rndis/main.c | 7 +- tutorials/rp/pico-w/main.c | 5 + tutorials/rp/w5500-evb-pico/main.c | 5 + tutorials/rp/w55rp20-evb-pico/main.c | 5 + tutorials/stm32/nucleo-c5a3zg/minimal/main.c | 5 + .../stm32/nucleo-f429zi/minimal-rndis/main.c | 7 +- tutorials/stm32/nucleo-f429zi/minimal/main.c | 5 + .../stm32/nucleo-f746zg/minimal-pppoe/main.c | 7 +- .../stm32/nucleo-f746zg/minimal-rndis/main.c | 7 +- tutorials/stm32/nucleo-f746zg/minimal/main.c | 5 + tutorials/stm32/nucleo-f756zg/minimal/main.c | 5 + .../stm32/nucleo-g031k8/minimal-w5500/main.c | 7 +- tutorials/stm32/nucleo-h563zi/minimal/main.c | 5 + .../nucleo-h723zg/cubemx/Core/Src/main.c | 7 +- .../minimal-bsd-baremetal/main.c | 7 +- .../nucleo-h723zg/minimal-bsd-freertos/main.c | 7 +- tutorials/stm32/nucleo-h723zg/minimal/main.c | 5 + tutorials/stm32/nucleo-h743zi/minimal/main.c | 5 + .../stm32/nucleo-n657x0-q/minimal/main.c | 5 + .../stm32/nucleo-u5a5zj-q/minimal/main.c | 5 + tutorials/stm32/portenta-h7/minimal/main.c | 5 + tutorials/stm32/stm32h573i-dk/minimal/main.c | 5 + .../stm32/stm32h747i-disco/minimal/main.c | 5 + .../main.c | 7 +- .../ch32v307-make-baremetal-builtin/main.c | 7 +- tutorials/zephyr/http-server/src/main.c | 5 + 46 files changed, 469 insertions(+), 156 deletions(-) diff --git a/mongoose.c b/mongoose.c index 220cef5a..349bd737 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1668,21 +1668,6 @@ static void mg_dash_handle_add(struct mg_connection *c, struct mg_dash *dash, } } -// Firmware upload callback for mg_http_stream_body(). Uses *p as a flag: -// non-NULL means an OTA session is open and must be closed by mg_ota_end() -static bool otacb(struct mg_http_message *hm, struct mg_str *data, void **p) { - if (hm != NULL) { // Start - if (!mg_ota_begin(hm->body.len)) return false; - *p = (void *) (ptrdiff_t) 1; - return true; - } else if (data != NULL) { // Next chunk - return mg_ota_write(data->buf, data->len); - } - if (*p == NULL) return false; // End. Begin failed, nothing to finish - *p = NULL; - return mg_ota_end(); -} - static void mg_serve_fs(struct mg_connection *c, struct mg_http_message *hm, struct mg_dash_user *u, bool stream) { struct mg_dash *dash = (struct mg_dash *) c->fn_data; @@ -1729,9 +1714,9 @@ void mg_dash_ev_handler(struct mg_connection *c, int ev, void *ev_data) { mg_serve_fs(c, hm, u, true); return; // Important - the serve_fs() call can invalidate hm } else if (mg_match(hm->uri, mg_str("/api/ota"), NULL)) { - // Authenticated above. If streaming started, the stream handler owns - // the connection and c->data, so skip the marker check below - if (mg_http_stream_body(c, hm, otacb, NULL)) return; + // Authenticated above. Streaming owns the connection and c->data. + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + return; } if (d->marker != '\0') mg_log_http_req(c, hm); } else if (ev == MG_EV_HTTP_MSG && d->marker != '\0') { @@ -4644,8 +4629,8 @@ void mg_http_serve_upload(struct mg_connection *c, struct mg_http_message *hm, fs->rm(path); // MG_FS_WRITE appends, not truncates: drop any old file if ((fd = mg_fs_open(fs, path, MG_FS_WRITE)) == NULL) { MG_ERROR(("Cannot open %s for upload", path)); - } else if (!mg_http_stream_body(c, hm, serve_upload_cb, fd)) { - mg_fs_close(fd); + } else { + mg_http_stream_body(c, hm, serve_upload_cb, fd); } } } @@ -4779,6 +4764,7 @@ struct mg_upload_state { size_t received; // Number of body bytes received so far void *user_data; // Passed to cb, free for cb to use bool failed; // Set when cb returned false + bool finished; // End callback has been called }; // Event handler installed by mg_http_stream_body(). Feeds the body to the @@ -4786,18 +4772,18 @@ struct mg_upload_state { // handler: the connection is closed after the reply. static void mg_stream_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_upload_state *us = (struct mg_upload_state *) c->data; - bool (*fn)(struct mg_http_message *, struct mg_str *, void **) = + bool (*fn)(struct mg_http_message *, struct mg_str *, void **) = (bool (*)(struct mg_http_message *, struct mg_str *, void **)) (ptrdiff_t) c->fn_data; (void) ev_data; if (ev == MG_EV_CLOSE || ev == MG_EV_ERROR) { - if (us->received < us->expected) { + if (!us->finished) { // Connection dropped mid-upload. Let cb clean up, e.g. call mg_ota_end() - us->received = us->expected; // MG_EV_ERROR is followed by MG_EV_CLOSE + us->finished = true; // MG_EV_ERROR is followed by MG_EV_CLOSE fn(NULL, NULL, &us->user_data); } - } else if (ev == MG_EV_READ && !c->is_draining) { - if (c->recv.len > 0 && us->received < us->expected) { + } else if (ev == MG_EV_READ && !c->is_draining && !us->finished) { + if (!us->failed && c->recv.len > 0 && us->received < us->expected) { // Got some uploaded data. Feed by 512-byte aligned chunks, for OTA size_t left = us->expected - us->received, r = c->recv.len; size_t aligned = r < left ? MG_ROUND_DOWN(r, 512) : left; @@ -4808,10 +4794,13 @@ static void mg_stream_handler(struct mg_connection *c, int ev, void *ev_data) { us->received += aligned; mg_iobuf_del(&c->recv, 0, aligned); // Shift the unprocessed tail } - if (us->received >= us->expected) { + if (!us->finished && (us->failed || us->received >= us->expected)) { // Finished upload. Always call cb, even after error, so it can clean up + us->finished = true; us->failed |= !fn(NULL, NULL, &us->user_data); - if (!c->is_client) { + if (c->is_client && us->failed) { + mg_error(c, "Body streaming failed"); + } else if (!c->is_client) { mg_http_reply(c, us->failed ? 500 : 200, NULL, "%zu %s\n", us->received, us->failed ? "fail" : "ok"); } @@ -4820,48 +4809,54 @@ static void mg_stream_handler(struct mg_connection *c, int ev, void *ev_data) { } } -bool mg_http_stream_body(struct mg_connection *c, struct mg_http_message *hm, +void mg_http_stream_body(struct mg_connection *c, struct mg_http_message *hm, bool (*cb)(struct mg_http_message *, struct mg_str *, - void **user_data), + void **), void *user_data) { struct mg_upload_state *us = (struct mg_upload_state *) c->data; - struct mg_str *te = mg_http_get_header(hm, "Transfer-Encoding"); - bool handled = false; + int code = 0; + size_t head_len = hm->head.len; // Catch upload requests early, without buffering whole body. Called on the // MG_EV_HTTP_HDRS event: we've received all HTTP headers but not necessarily // the full HTTP body - if (hm->body.len == (size_t) ~0 || - (te != NULL && mg_strcasecmp(*te, mg_str("chunked")) == 0)) { - // Unknown length or chunked, cannot stream. Leave it to the caller - } else if (!c->is_client && - mg_strcmp(hm->method, mg_str("POST")) != 0 && - mg_strcmp(hm->method, mg_str("PUT")) != 0) { - // Not an upload request. Leave it to the caller + if (!c->is_client && mg_strcmp(hm->method, mg_str("POST")) != 0 && + mg_strcmp(hm->method, mg_str("PUT")) != 0) { + code = 405; + } else if (mg_http_get_header(hm, "Transfer-Encoding") != NULL) { + code = 400; + } else if (hm->body.len == (size_t) ~0 || + (!c->is_client && mg_http_get_header(hm, "Content-Length") == NULL)) { + code = 411; } else if (sizeof(*us) > sizeof(c->data)) { - if (!c->is_client) { // Nobody to reply to on a client connection - c->pfn = NULL; - mg_http_reply(c, 500, NULL, "data too small\n"); - c->is_draining = 1; - cb(NULL, NULL, &user_data); // Let cb release user_data, start skipped - handled = true; + code = 500; + } + c->pfn = NULL; // Take ownership even when validation fails + if (code != 0) { + c->fn = NULL; + c->fn_data = NULL; + mg_iobuf_del(&c->recv, 0, c->recv.len); + cb(NULL, NULL, &user_data); // Release resources even if start was skipped + if (c->is_client) { + mg_error(c, "%s", mg_http_status_code_str(code)); + } else { + mg_http_reply(c, code, code == 405 ? "Allow: POST, PUT\r\n" : NULL, ""); } + c->is_draining = 1; } else { - c->pfn = NULL; // Silence HTTP protocol handler memset(us, 0, sizeof(*us)); us->expected = hm->body.len; // Store number of bytes we expect us->user_data = user_data; + c->fn = mg_stream_handler; + c->fn_data = (void *) (ptrdiff_t) cb; us->failed = !cb(hm, NULL, &us->user_data); // Call before deleting headers - if (mg_http_get_header(hm, "Expect") != NULL) { + if (!c->is_client && !us->failed && !us->finished && + mg_http_get_header(hm, "Expect") != NULL) { mg_http_reply(c, 100, NULL, ""); // If curl expects, we continue } - mg_iobuf_del(&c->recv, 0, hm->head.len); // Delete HTTP headers - c->fn = mg_stream_handler; // We own the connection from now - c->fn_data = (void *) (ptrdiff_t) cb; + mg_iobuf_del(&c->recv, 0, head_len); // Delete HTTP headers mg_call(c, MG_EV_READ, &c->recv.len); // Process the body bytes we have - handled = true; } - return handled; } static bool is_hex_digit(int c) { @@ -11429,9 +11424,7 @@ static void s_firmware_fn(struct mg_connection *c, int ev, void *ev_data) { (unsigned long) hm->body.len, (unsigned long) s_ota->size); } else { MG_DEBUG(("Beginning OTA (%lu bytes)", (unsigned long) s_ota->size)); - if (!mg_http_stream_body(c, hm, s_firmware_cb, NULL)) { - mg_error(c, "Cannot stream firmware"); - } + mg_http_stream_body(c, hm, s_firmware_cb, NULL); } } else if (ev == MG_EV_ERROR) { s_ota->fn((char *) ev_data); @@ -11464,6 +11457,21 @@ void mg_ota_url_check(struct mg_mgr *mgr, const char *json_url, } } +// Uses *p as a flag: non-NULL means an OTA session is open and must be +// closed by mg_ota_end() +bool mg_http_ota_cb(struct mg_http_message *hm, struct mg_str *data, void **p) { + if (hm != NULL) { // Start + if (!mg_ota_begin(hm->body.len)) return false; + *p = (void *) (ptrdiff_t) 1; + return true; + } else if (data != NULL) { // Next chunk + return mg_ota_write(data->buf, data->len); + } + if (*p == NULL) return false; // End. Begin failed, nothing to finish + *p = NULL; + return mg_ota_end(); +} + void mg_ota_poll(struct mg_mgr *mgr) { static uint64_t t = 5000; // Fire first time 5 sec after boot @@ -34937,6 +34945,7 @@ struct mg_tcpip_driver mg_tcpip_driver_stm32f = { #if MG_ENABLE_TCPIP && (MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_MCXN || \ MG_ENABLE_DRIVER_STM32N) +// STM32C: vendor modded single-queue Synopsys v5.4, same settings as STM32H // STM32H: vendor modded single-queue Synopsys v4.2 // STM32N: dual-queue GbE Synopsys v5.2 with no hash table option, 64-bit AXI // MCXNx4x: dual-queue Synopsys v5.2 with no hash table option diff --git a/mongoose.h b/mongoose.h index 1ed986e6..6ac3ed93 100644 --- a/mongoose.h +++ b/mongoose.h @@ -2724,29 +2724,32 @@ int mg_http_status(const struct mg_http_message *hm); // Streams a POST/PUT body to a callback as it arrives, without buffering it. // Call it from an MG_EV_HTTP_HDRS handler, after matching the request, e.g. -// with mg_match(). Returns true if it took over the connection, false if the -// request is not POST/PUT, is chunked, or has no Content-Length. +// with mg_match(). Always takes over the connection. Invalid requests receive +// an HTTP error; client-side failures call mg_error(). Replies and connection +// draining are handled internally, including callback failures. // // Callback upload_fn(hm, data, user_data) is called: // - at start: hm is set. Open the file, set *user_data. // - per chunk: data is set, 512 byte aligned except the last. Not called // again after a failure. -// - at end: both NULL. Always called once, also when the connection drops -// early, so release resources here. A truncated body looks like a complete -// one: validate before committing. -// Return true on success, false on error. +// - at end: both NULL. Always called exactly once, including validation +// failures before start and connections that drop early. Release resources +// here. A truncated body looks like a complete one: validate before +// committing. +// The callback returns true on success, false on error. A failure stops +// streaming immediately and calls the end callback before closing. // Example: -// if (ev == MG_EV_HTTP_HDRS && mg_match(hm->uri, mg_str("/fs/*"), NULL) { -// mg_http_stream_body(c, hm, upload, NULL)); +// if (ev == MG_EV_HTTP_HDRS && mg_match(hm->uri, mg_str("/fs/*"), NULL)) { +// mg_http_stream_body(c, hm, upload, NULL); // } // Full example: // tutorials/http/file-upload-single-post // Related APIs: // mg_http_listen(), mg_http_next_multipart() // Notes: -// After it returns true, this function hijacks the connection. Existing event -// handler not called, hm is invalid, c->data and c->fn_data are modified -bool mg_http_stream_body(struct mg_connection *c, struct mg_http_message *hm, +// The existing event handler is no longer called. hm is invalid after this +// call; c->data and c->fn_data are reserved for streaming state. +void mg_http_stream_body(struct mg_connection *c, struct mg_http_message *hm, bool (*upload_fn)(struct mg_http_message *, struct mg_str *, void **user_data), void *user_data); @@ -4220,9 +4223,8 @@ bool mg_ota_end(void); // ```c // if (ev == MG_EV_HTTP_HDRS) { // struct mg_http_message *hm = (struct mg_http_message *) ev_data; -// if (mg_match(hm->uri, mg_str("/ota"), NULL) && -// !mg_http_stream_body(c, hm, mg_http_ota_cb, NULL)) { -// mg_http_reply(c, 400, "", "POST firmware with Content-Length\n"); +// if (mg_match(hm->uri, mg_str("/ota"), NULL)) { +// mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); // } // } // ``` diff --git a/src/dash.c b/src/dash.c index f7ceb756..49baf988 100644 --- a/src/dash.c +++ b/src/dash.c @@ -533,21 +533,6 @@ static void mg_dash_handle_add(struct mg_connection *c, struct mg_dash *dash, } } -// Firmware upload callback for mg_http_stream_body(). Uses *p as a flag: -// non-NULL means an OTA session is open and must be closed by mg_ota_end() -static bool otacb(struct mg_http_message *hm, struct mg_str *data, void **p) { - if (hm != NULL) { // Start - if (!mg_ota_begin(hm->body.len)) return false; - *p = (void *) (ptrdiff_t) 1; - return true; - } else if (data != NULL) { // Next chunk - return mg_ota_write(data->buf, data->len); - } - if (*p == NULL) return false; // End. Begin failed, nothing to finish - *p = NULL; - return mg_ota_end(); -} - static void mg_serve_fs(struct mg_connection *c, struct mg_http_message *hm, struct mg_dash_user *u, bool stream) { struct mg_dash *dash = (struct mg_dash *) c->fn_data; @@ -594,9 +579,9 @@ void mg_dash_ev_handler(struct mg_connection *c, int ev, void *ev_data) { mg_serve_fs(c, hm, u, true); return; // Important - the serve_fs() call can invalidate hm } else if (mg_match(hm->uri, mg_str("/api/ota"), NULL)) { - // Authenticated above. If streaming started, the stream handler owns - // the connection and c->data, so skip the marker check below - if (mg_http_stream_body(c, hm, otacb, NULL)) return; + // Authenticated above. Streaming owns the connection and c->data. + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + return; } if (d->marker != '\0') mg_log_http_req(c, hm); } else if (ev == MG_EV_HTTP_MSG && d->marker != '\0') { diff --git a/src/http.c b/src/http.c index 96368993..b0e067b7 100644 --- a/src/http.c +++ b/src/http.c @@ -879,8 +879,8 @@ void mg_http_serve_upload(struct mg_connection *c, struct mg_http_message *hm, fs->rm(path); // MG_FS_WRITE appends, not truncates: drop any old file if ((fd = mg_fs_open(fs, path, MG_FS_WRITE)) == NULL) { MG_ERROR(("Cannot open %s for upload", path)); - } else if (!mg_http_stream_body(c, hm, serve_upload_cb, fd)) { - mg_fs_close(fd); + } else { + mg_http_stream_body(c, hm, serve_upload_cb, fd); } } } @@ -1014,6 +1014,7 @@ struct mg_upload_state { size_t received; // Number of body bytes received so far void *user_data; // Passed to cb, free for cb to use bool failed; // Set when cb returned false + bool finished; // End callback has been called }; // Event handler installed by mg_http_stream_body(). Feeds the body to the @@ -1021,18 +1022,18 @@ struct mg_upload_state { // handler: the connection is closed after the reply. static void mg_stream_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_upload_state *us = (struct mg_upload_state *) c->data; - bool (*fn)(struct mg_http_message *, struct mg_str *, void **) = + bool (*fn)(struct mg_http_message *, struct mg_str *, void **) = (bool (*)(struct mg_http_message *, struct mg_str *, void **)) (ptrdiff_t) c->fn_data; (void) ev_data; if (ev == MG_EV_CLOSE || ev == MG_EV_ERROR) { - if (us->received < us->expected) { + if (!us->finished) { // Connection dropped mid-upload. Let cb clean up, e.g. call mg_ota_end() - us->received = us->expected; // MG_EV_ERROR is followed by MG_EV_CLOSE + us->finished = true; // MG_EV_ERROR is followed by MG_EV_CLOSE fn(NULL, NULL, &us->user_data); } - } else if (ev == MG_EV_READ && !c->is_draining) { - if (c->recv.len > 0 && us->received < us->expected) { + } else if (ev == MG_EV_READ && !c->is_draining && !us->finished) { + if (!us->failed && c->recv.len > 0 && us->received < us->expected) { // Got some uploaded data. Feed by 512-byte aligned chunks, for OTA size_t left = us->expected - us->received, r = c->recv.len; size_t aligned = r < left ? MG_ROUND_DOWN(r, 512) : left; @@ -1043,10 +1044,13 @@ static void mg_stream_handler(struct mg_connection *c, int ev, void *ev_data) { us->received += aligned; mg_iobuf_del(&c->recv, 0, aligned); // Shift the unprocessed tail } - if (us->received >= us->expected) { + if (!us->finished && (us->failed || us->received >= us->expected)) { // Finished upload. Always call cb, even after error, so it can clean up + us->finished = true; us->failed |= !fn(NULL, NULL, &us->user_data); - if (!c->is_client) { + if (c->is_client && us->failed) { + mg_error(c, "Body streaming failed"); + } else if (!c->is_client) { mg_http_reply(c, us->failed ? 500 : 200, NULL, "%zu %s\n", us->received, us->failed ? "fail" : "ok"); } @@ -1055,48 +1059,54 @@ static void mg_stream_handler(struct mg_connection *c, int ev, void *ev_data) { } } -bool mg_http_stream_body(struct mg_connection *c, struct mg_http_message *hm, +void mg_http_stream_body(struct mg_connection *c, struct mg_http_message *hm, bool (*cb)(struct mg_http_message *, struct mg_str *, - void **user_data), + void **), void *user_data) { struct mg_upload_state *us = (struct mg_upload_state *) c->data; - struct mg_str *te = mg_http_get_header(hm, "Transfer-Encoding"); - bool handled = false; + int code = 0; + size_t head_len = hm->head.len; // Catch upload requests early, without buffering whole body. Called on the // MG_EV_HTTP_HDRS event: we've received all HTTP headers but not necessarily // the full HTTP body - if (hm->body.len == (size_t) ~0 || - (te != NULL && mg_strcasecmp(*te, mg_str("chunked")) == 0)) { - // Unknown length or chunked, cannot stream. Leave it to the caller - } else if (!c->is_client && - mg_strcmp(hm->method, mg_str("POST")) != 0 && - mg_strcmp(hm->method, mg_str("PUT")) != 0) { - // Not an upload request. Leave it to the caller + if (!c->is_client && mg_strcmp(hm->method, mg_str("POST")) != 0 && + mg_strcmp(hm->method, mg_str("PUT")) != 0) { + code = 405; + } else if (mg_http_get_header(hm, "Transfer-Encoding") != NULL) { + code = 400; + } else if (hm->body.len == (size_t) ~0 || + (!c->is_client && mg_http_get_header(hm, "Content-Length") == NULL)) { + code = 411; } else if (sizeof(*us) > sizeof(c->data)) { - if (!c->is_client) { // Nobody to reply to on a client connection - c->pfn = NULL; - mg_http_reply(c, 500, NULL, "data too small\n"); - c->is_draining = 1; - cb(NULL, NULL, &user_data); // Let cb release user_data, start skipped - handled = true; + code = 500; + } + c->pfn = NULL; // Take ownership even when validation fails + if (code != 0) { + c->fn = NULL; + c->fn_data = NULL; + mg_iobuf_del(&c->recv, 0, c->recv.len); + cb(NULL, NULL, &user_data); // Release resources even if start was skipped + if (c->is_client) { + mg_error(c, "%s", mg_http_status_code_str(code)); + } else { + mg_http_reply(c, code, code == 405 ? "Allow: POST, PUT\r\n" : NULL, ""); } + c->is_draining = 1; } else { - c->pfn = NULL; // Silence HTTP protocol handler memset(us, 0, sizeof(*us)); us->expected = hm->body.len; // Store number of bytes we expect us->user_data = user_data; + c->fn = mg_stream_handler; + c->fn_data = (void *) (ptrdiff_t) cb; us->failed = !cb(hm, NULL, &us->user_data); // Call before deleting headers - if (mg_http_get_header(hm, "Expect") != NULL) { + if (!c->is_client && !us->failed && !us->finished && + mg_http_get_header(hm, "Expect") != NULL) { mg_http_reply(c, 100, NULL, ""); // If curl expects, we continue } - mg_iobuf_del(&c->recv, 0, hm->head.len); // Delete HTTP headers - c->fn = mg_stream_handler; // We own the connection from now - c->fn_data = (void *) (ptrdiff_t) cb; + mg_iobuf_del(&c->recv, 0, head_len); // Delete HTTP headers mg_call(c, MG_EV_READ, &c->recv.len); // Process the body bytes we have - handled = true; } - return handled; } static bool is_hex_digit(int c) { diff --git a/src/http.h b/src/http.h index 302c6173..e6a991a8 100644 --- a/src/http.h +++ b/src/http.h @@ -205,29 +205,32 @@ int mg_http_status(const struct mg_http_message *hm); // Streams a POST/PUT body to a callback as it arrives, without buffering it. // Call it from an MG_EV_HTTP_HDRS handler, after matching the request, e.g. -// with mg_match(). Returns true if it took over the connection, false if the -// request is not POST/PUT, is chunked, or has no Content-Length. +// with mg_match(). Always takes over the connection. Invalid requests receive +// an HTTP error; client-side failures call mg_error(). Replies and connection +// draining are handled internally, including callback failures. // // Callback upload_fn(hm, data, user_data) is called: // - at start: hm is set. Open the file, set *user_data. // - per chunk: data is set, 512 byte aligned except the last. Not called // again after a failure. -// - at end: both NULL. Always called once, also when the connection drops -// early, so release resources here. A truncated body looks like a complete -// one: validate before committing. -// Return true on success, false on error. +// - at end: both NULL. Always called exactly once, including validation +// failures before start and connections that drop early. Release resources +// here. A truncated body looks like a complete one: validate before +// committing. +// The callback returns true on success, false on error. A failure stops +// streaming immediately and calls the end callback before closing. // Example: -// if (ev == MG_EV_HTTP_HDRS && mg_match(hm->uri, mg_str("/fs/*"), NULL) { -// mg_http_stream_body(c, hm, upload, NULL)); +// if (ev == MG_EV_HTTP_HDRS && mg_match(hm->uri, mg_str("/fs/*"), NULL)) { +// mg_http_stream_body(c, hm, upload, NULL); // } // Full example: // tutorials/http/file-upload-single-post // Related APIs: // mg_http_listen(), mg_http_next_multipart() // Notes: -// After it returns true, this function hijacks the connection. Existing event -// handler not called, hm is invalid, c->data and c->fn_data are modified -bool mg_http_stream_body(struct mg_connection *c, struct mg_http_message *hm, +// The existing event handler is no longer called. hm is invalid after this +// call; c->data and c->fn_data are reserved for streaming state. +void mg_http_stream_body(struct mg_connection *c, struct mg_http_message *hm, bool (*upload_fn)(struct mg_http_message *, struct mg_str *, void **user_data), void *user_data); diff --git a/src/ota.c b/src/ota.c index 65453345..b8be331d 100644 --- a/src/ota.c +++ b/src/ota.c @@ -208,9 +208,7 @@ static void s_firmware_fn(struct mg_connection *c, int ev, void *ev_data) { (unsigned long) hm->body.len, (unsigned long) s_ota->size); } else { MG_DEBUG(("Beginning OTA (%lu bytes)", (unsigned long) s_ota->size)); - if (!mg_http_stream_body(c, hm, s_firmware_cb, NULL)) { - mg_error(c, "Cannot stream firmware"); - } + mg_http_stream_body(c, hm, s_firmware_cb, NULL); } } else if (ev == MG_EV_ERROR) { s_ota->fn((char *) ev_data); @@ -243,6 +241,21 @@ void mg_ota_url_check(struct mg_mgr *mgr, const char *json_url, } } +// Uses *p as a flag: non-NULL means an OTA session is open and must be +// closed by mg_ota_end() +bool mg_http_ota_cb(struct mg_http_message *hm, struct mg_str *data, void **p) { + if (hm != NULL) { // Start + if (!mg_ota_begin(hm->body.len)) return false; + *p = (void *) (ptrdiff_t) 1; + return true; + } else if (data != NULL) { // Next chunk + return mg_ota_write(data->buf, data->len); + } + if (*p == NULL) return false; // End. Begin failed, nothing to finish + *p = NULL; + return mg_ota_end(); +} + void mg_ota_poll(struct mg_mgr *mgr) { static uint64_t t = 5000; // Fire first time 5 sec after boot diff --git a/src/ota.h b/src/ota.h index 333a6e3c..2c4ade50 100644 --- a/src/ota.h +++ b/src/ota.h @@ -80,9 +80,8 @@ bool mg_ota_end(void); // ```c // if (ev == MG_EV_HTTP_HDRS) { // struct mg_http_message *hm = (struct mg_http_message *) ev_data; -// if (mg_match(hm->uri, mg_str("/ota"), NULL) && -// !mg_http_stream_body(c, hm, mg_http_ota_cb, NULL)) { -// mg_http_reply(c, 400, "", "POST firmware with Content-Length\n"); +// if (mg_match(hm->uri, mg_str("/ota"), NULL)) { +// mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); // } // } // ``` diff --git a/test/unit_test.c b/test/unit_test.c index a444816c..22434439 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -3158,8 +3158,6 @@ static bool su_cb(struct mg_http_message *hm, struct mg_str *data, void **p) { static void su(struct mg_connection *c, int ev, void *ev_data) { if (ev == MG_EV_HTTP_HDRS) { mg_http_stream_body(c, (struct mg_http_message *) ev_data, su_cb, NULL); - } else if (ev == MG_EV_HTTP_MSG) { // Only for requests that were not streamed - mg_http_reply(c, 400, "", "not streamed\n"); } } @@ -3194,8 +3192,7 @@ static void cr(struct mg_connection *c, int ev, void *ev_data) { if (ev == MG_EV_CONNECT) { mg_printf(c, "GET / HTTP/1.0\r\n\r\n"); } else if (ev == MG_EV_HTTP_HDRS) { - ASSERT(mg_http_stream_body(c, (struct mg_http_message *) ev_data, cr_cb, - NULL)); + mg_http_stream_body(c, (struct mg_http_message *) ev_data, cr_cb, NULL); } } @@ -3208,12 +3205,103 @@ static void cs(struct mg_connection *c, int ev, void *ev_data) { (void) ev_data; } +struct stream_test_state { + int fail_at, starts, chunks, ends; +}; + +static bool stream_test_cb(struct mg_http_message *hm, struct mg_str *data, + void **p) { + struct stream_test_state *s = (struct stream_test_state *) *p; + ASSERT(s != NULL); + if (hm != NULL) { + s->starts++; + return s->fail_at != 1; + } else if (data != NULL) { + s->chunks++; + return s->fail_at != 2; + } + s->ends++; + *p = NULL; + return s->fail_at != 3; +} + +static void stream_test_original(struct mg_connection *c, int ev, void *data) { + (void) c, (void) ev, (void) data; + ASSERT(false); // Streaming must take ownership even when validation fails +} + +static void test_http_stream_errors(void) { + static const struct { + const char *request; + int client, fail_at, body_size, code, starts, chunks; + } cases[] = { + {"GET / HTTP/1.1\r\nContent-Length: 0\r\n\r\n", 0, 0, 0, 405, 0, 0}, + {"POST / HTTP/1.1\r\n\r\n", 0, 0, 0, 411, 0, 0}, + {"POST / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n", + 0, 0, 0, 400, 0, 0}, + {"POST / HTTP/1.1\r\nContent-Length: 3\r\n\r\nabc", 0, 0, 0, 200, 1, 1}, + {"PUT / HTTP/1.1\r\nContent-Length: 0\r\n\r\n", 0, 0, 0, 200, 1, 0}, + // Start failure must reply without waiting for the body or sending 100. + {"POST / HTTP/1.1\r\nContent-Length: 1000000\r\nExpect: 100-continue\r\n\r\n", + 0, 1, 0, 500, 1, 0}, + // Write failure must also reply before the announced body is complete. + {"POST / HTTP/1.1\r\nContent-Length: 1000000\r\n\r\n", + 0, 2, 512, 500, 1, 1}, + {"POST / HTTP/1.1\r\nContent-Length: 3\r\n\r\nabc", 0, 3, 0, 500, 1, 1}, + // Clients close on errors and never send an HTTP error response. + {"HTTP/1.1 200 OK\r\n\r\n", 1, 0, 0, 411, 0, 0}, + {"HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n", + 1, 0, 0, 400, 0, 0}, + {"HTTP/1.1 200 OK\r\nContent-Length: 1000000\r\n\r\n", + 1, 1, 0, 500, 1, 0}, + {"HTTP/1.1 200 OK\r\nContent-Length: 1000000\r\n\r\n", + 1, 2, 512, 500, 1, 1}, + {"HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nabc", 1, 3, 0, 500, 1, 1}, + {"HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nabc", 1, 0, 0, 200, 1, 1}, + {"HTTP/1.1 204 No Content\r\n\r\n", 1, 0, 0, 200, 1, 0}, + }; + size_t i; + for (i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) { + struct mg_connection c; + struct mg_http_message hm; + struct stream_test_state state = {0, 0, 0, 0}; + char body[512]; + memset(&c, 0, sizeof(c)); + memset(body, 'x', sizeof(body)); + state.fail_at = cases[i].fail_at; + c.is_client = cases[i].client != 0; + c.fn = c.pfn = stream_test_original; + mg_iobuf_add(&c.recv, 0, cases[i].request, strlen(cases[i].request)); + mg_iobuf_add(&c.recv, c.recv.len, body, (size_t) cases[i].body_size); + ASSERT(mg_http_parse((char *) c.recv.buf, c.recv.len, &hm) > 0); + mg_http_stream_body(&c, &hm, stream_test_cb, &state); + ASSERT(c.pfn == NULL && c.is_draining); + ASSERT(state.starts == cases[i].starts && state.chunks == cases[i].chunks); + ASSERT(state.ends == 1); + if (c.is_client) { + ASSERT(c.send.len == 0); + ASSERT(c.is_closing == (cases[i].code != 200)); + } else { + ASSERT(mg_http_parse((char *) c.send.buf, c.send.len, &hm) > 0); + ASSERT(mg_http_status(&hm) == cases[i].code); + ASSERT(hm.message.len == c.send.len); // Exactly one response + } + mg_call(&c, MG_EV_READ, NULL); + mg_error(&c, "stream cleanup test"); + mg_call(&c, MG_EV_CLOSE, NULL); + ASSERT(state.ends == 1); // Error followed by close must not clean up twice + mg_iobuf_free(&c.recv); + mg_iobuf_free(&c.send); + } +} + static void test_http_upload(void) { struct mg_mgr mgr; const char *url = "http://127.0.0.1:12352"; int i; const char *s = "ok (8 foo\nbar\n)\n"; + test_http_stream_errors(); mg_mgr_init(&mgr); mg_http_listen(&mgr, url, us, NULL); mg_http_connect(&mgr, url, uc, (void *) &s); @@ -3257,7 +3345,7 @@ static void test_http_upload(void) { ASSERT(mgr.conns == NULL); } - // mg_http_stream_body: chunked request is not streamed, caller replies "400" + // mg_http_stream_body: chunked request rejected with "400", cleanup still runs { char buf[FETCH_BUF_SIZE]; s_su_done = s_su_end = 0; @@ -3268,7 +3356,7 @@ static void test_http_upload(void) { "POST /su_chunked.txt HTTP/1.1\r\n" "Transfer-Encoding: chunked\r\n\r\n" "3\r\nfoo\r\n0\r\n\r\n") == 400); - ASSERT(s_su_done == 0 && s_su_end == 0); // The callback was never called + ASSERT(s_su_done == 1 && s_su_end == 1); // End called without start ASSERT(fopen("su_chunked.txt", "r") == NULL); mg_mgr_free(&mgr); ASSERT(mgr.conns == NULL); @@ -5010,6 +5098,20 @@ static void test_dash(void) { "Authorization: Basic YWRtaW46YWRtaW4=\n\n") == 200); ASSERT(cmpbody(buf, login_admin_expected) == 0); + // OTA uses streaming and enforces the dashboard's authentication. + ASSERT(fetch(&mgr, buf, url, + "POST /api/ota HTTP/1.0\nContent-Length: 1\n\nx") == 403); + ASSERT(fetch(&mgr, buf, url, + "GET /api/ota HTTP/1.0\nContent-Length: 0\n" + "Authorization: Basic YWRtaW46YWRtaW4=\n\n") == 405); + ASSERT(fetch(&mgr, buf, url, + "POST /ota HTTP/1.0\nContent-Length: 1\n" + "Authorization: Basic YWRtaW46YWRtaW4=\n\nx") == 404); + ASSERT(fetch(&mgr, buf, url, + "POST /api/ota HTTP/1.0\nContent-Length: 1\n" + "Authorization: Basic YWRtaW46YWRtaW4=\n\nx") == 200); + ASSERT(cmpbody(buf, "1 ok\n") == 0); + // set3 is admin-only ASSERT(fetch(&mgr, buf, url, "GET /api/get/set3 HTTP/1.0\n" diff --git a/tutorials/esp32/minimal/main/main.c b/tutorials/esp32/minimal/main/main.c index 6c525bb0..d7737e28 100644 --- a/tutorials/esp32/minimal/main/main.c +++ b/tutorials/esp32/minimal/main/main.c @@ -44,6 +44,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), .key = mg_str(TLS_KEY)}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; size_t total = heap_caps_get_total_size(MALLOC_CAP_DEFAULT); diff --git a/tutorials/micropython/esp32/mongoose/main.c b/tutorials/micropython/esp32/mongoose/main.c index fa2914a2..3406d1d4 100644 --- a/tutorials/micropython/esp32/mongoose/main.c +++ b/tutorials/micropython/esp32/mongoose/main.c @@ -9,7 +9,12 @@ static void t_fn(void *arg) { // Tick periodically } static void fn(struct mg_connection *c, int ev, void *ev_data) { - if (ev == MG_EV_HTTP_MSG) mg_http_reply(c, 200, "", "hi\n"); + if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } + } else if (ev == MG_EV_HTTP_MSG) mg_http_reply(c, 200, "", "hi\n"); (void) ev_data; } diff --git a/tutorials/micropython/mongoose/main.c b/tutorials/micropython/mongoose/main.c index c3c413f4..b02af34e 100644 --- a/tutorials/micropython/mongoose/main.c +++ b/tutorials/micropython/mongoose/main.c @@ -9,7 +9,12 @@ static void t_fn(void *arg) { // Tick periodically } static void fn(struct mg_connection *c, int ev, void *ev_data) { - if (ev == MG_EV_HTTP_MSG) mg_http_reply(c, 200, "", "hi\n"); + if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } + } else if (ev == MG_EV_HTTP_MSG) mg_http_reply(c, 200, "", "hi\n"); (void) ev_data; } diff --git a/tutorials/nxp/frdm-imxrt1186/minimal/main.c b/tutorials/nxp/frdm-imxrt1186/minimal/main.c index 43e8db2e..7e03bc0a 100644 --- a/tutorials/nxp/frdm-imxrt1186/minimal/main.c +++ b/tutorials/nxp/frdm-imxrt1186/minimal/main.c @@ -65,6 +65,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), .key = mg_str(TLS_KEY)}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { diff --git a/tutorials/nxp/frdm-mcxe247/minimal/main.c b/tutorials/nxp/frdm-mcxe247/minimal/main.c index 5ee99234..2c86a073 100644 --- a/tutorials/nxp/frdm-mcxe247/minimal/main.c +++ b/tutorials/nxp/frdm-mcxe247/minimal/main.c @@ -89,6 +89,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), .key = mg_str(TLS_KEY)}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { diff --git a/tutorials/nxp/frdm-mcxn947/minimal/main.c b/tutorials/nxp/frdm-mcxn947/minimal/main.c index 3124584c..751ad438 100644 --- a/tutorials/nxp/frdm-mcxn947/minimal/main.c +++ b/tutorials/nxp/frdm-mcxn947/minimal/main.c @@ -97,6 +97,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), .key = mg_str(TLS_KEY)}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { diff --git a/tutorials/nxp/frdm-mcxw71/minimal/main.c b/tutorials/nxp/frdm-mcxw71/minimal/main.c index 2cb7510e..f091d1d7 100644 --- a/tutorials/nxp/frdm-mcxw71/minimal/main.c +++ b/tutorials/nxp/frdm-mcxw71/minimal/main.c @@ -47,6 +47,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), .key = mg_str(TLS_KEY)}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { diff --git a/tutorials/nxp/frdm-rw612/minimal/main.c b/tutorials/nxp/frdm-rw612/minimal/main.c index 9a87e535..739f9a2f 100644 --- a/tutorials/nxp/frdm-rw612/minimal/main.c +++ b/tutorials/nxp/frdm-rw612/minimal/main.c @@ -65,6 +65,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), .key = mg_str(TLS_KEY)}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { diff --git a/tutorials/nxp/rt1060-evkb/minimal/main.c b/tutorials/nxp/rt1060-evkb/minimal/main.c index b4344d65..e840532e 100644 --- a/tutorials/nxp/rt1060-evkb/minimal/main.c +++ b/tutorials/nxp/rt1060-evkb/minimal/main.c @@ -61,6 +61,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), .key = mg_str(TLS_KEY)}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { diff --git a/tutorials/nxp/rt1170-evkb/minimal/main.c b/tutorials/nxp/rt1170-evkb/minimal/main.c index 5f38f234..02747fbf 100644 --- a/tutorials/nxp/rt1170-evkb/minimal/main.c +++ b/tutorials/nxp/rt1170-evkb/minimal/main.c @@ -65,6 +65,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), .key = mg_str(TLS_KEY)}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { diff --git a/tutorials/rp/pico-rm2/main.c b/tutorials/rp/pico-rm2/main.c index dd0eae9a..fe0a8c3f 100644 --- a/tutorials/rp/pico-rm2/main.c +++ b/tutorials/rp/pico-rm2/main.c @@ -5,7 +5,12 @@ #include "mongoose.h" static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { - if (ev == MG_EV_HTTP_MSG) { // New HTTP request received + if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } + } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received struct mg_http_message *hm = (struct mg_http_message *) ev_data; uint64_t tick = to_ms_since_boot(get_absolute_time()); if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { diff --git a/tutorials/rp/pico-rmii/main.c b/tutorials/rp/pico-rmii/main.c index 63d722b8..5f9d7729 100644 --- a/tutorials/rp/pico-rmii/main.c +++ b/tutorials/rp/pico-rmii/main.c @@ -33,7 +33,12 @@ static void driver_init(struct mg_mgr *mgr) { } static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { - if (ev == MG_EV_HTTP_MSG) { // New HTTP request received + if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } + } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received struct mg_http_message *hm = (struct mg_http_message *) ev_data; uint64_t tick = to_ms_since_boot(get_absolute_time()); if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { diff --git a/tutorials/rp/pico-rndis/main.c b/tutorials/rp/pico-rndis/main.c index 4f3ed2f1..a4bc37f6 100644 --- a/tutorials/rp/pico-rndis/main.c +++ b/tutorials/rp/pico-rndis/main.c @@ -58,7 +58,12 @@ static void driver_init(struct mg_mgr *mgr) { } static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { - if (ev == MG_EV_HTTP_MSG) { // New HTTP request received + if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } + } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received struct mg_http_message *hm = (struct mg_http_message *) ev_data; uint64_t tick = to_ms_since_boot(get_absolute_time()); if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { diff --git a/tutorials/rp/pico-w/main.c b/tutorials/rp/pico-w/main.c index ae9919ea..670b2d8e 100644 --- a/tutorials/rp/pico-w/main.c +++ b/tutorials/rp/pico-w/main.c @@ -39,6 +39,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), .key = mg_str(TLS_KEY)}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received struct mg_http_message *hm = (struct mg_http_message *) ev_data; uint64_t tick = to_ms_since_boot(get_absolute_time()); diff --git a/tutorials/rp/w5500-evb-pico/main.c b/tutorials/rp/w5500-evb-pico/main.c index 728caf0e..3f1ab143 100644 --- a/tutorials/rp/w5500-evb-pico/main.c +++ b/tutorials/rp/w5500-evb-pico/main.c @@ -82,6 +82,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), .key = mg_str(TLS_KEY)}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received struct mg_http_message *hm = (struct mg_http_message *) ev_data; uint64_t tick = to_ms_since_boot(get_absolute_time()); diff --git a/tutorials/rp/w55rp20-evb-pico/main.c b/tutorials/rp/w55rp20-evb-pico/main.c index 84886208..55b52438 100644 --- a/tutorials/rp/w55rp20-evb-pico/main.c +++ b/tutorials/rp/w55rp20-evb-pico/main.c @@ -195,6 +195,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), .key = mg_str(TLS_KEY)}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received struct mg_http_message *hm = (struct mg_http_message *) ev_data; uint64_t tick = to_ms_since_boot(get_absolute_time()); diff --git a/tutorials/stm32/nucleo-c5a3zg/minimal/main.c b/tutorials/stm32/nucleo-c5a3zg/minimal/main.c index 1264442a..557c233d 100644 --- a/tutorials/stm32/nucleo-c5a3zg/minimal/main.c +++ b/tutorials/stm32/nucleo-c5a3zg/minimal/main.c @@ -63,6 +63,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), .key = mg_str(TLS_KEY)}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { diff --git a/tutorials/stm32/nucleo-f429zi/minimal-rndis/main.c b/tutorials/stm32/nucleo-f429zi/minimal-rndis/main.c index e7cff967..7f7c78c4 100644 --- a/tutorials/stm32/nucleo-f429zi/minimal-rndis/main.c +++ b/tutorials/stm32/nucleo-f429zi/minimal-rndis/main.c @@ -66,7 +66,12 @@ static bool usb_poll(struct mg_tcpip_if *ifp, bool s1) { } static void fn(struct mg_connection *c, int ev, void *ev_data) { - if (ev == MG_EV_HTTP_MSG) { + if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } + } else if (ev == MG_EV_HTTP_MSG) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/debug"), NULL)) { int level = mg_json_get_long(hm->body, "$.level", MG_LL_DEBUG); diff --git a/tutorials/stm32/nucleo-f429zi/minimal/main.c b/tutorials/stm32/nucleo-f429zi/minimal/main.c index 34d521fb..a05c10a5 100644 --- a/tutorials/stm32/nucleo-f429zi/minimal/main.c +++ b/tutorials/stm32/nucleo-f429zi/minimal/main.c @@ -68,6 +68,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), .key = mg_str(TLS_KEY)}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { diff --git a/tutorials/stm32/nucleo-f746zg/minimal-pppoe/main.c b/tutorials/stm32/nucleo-f746zg/minimal-pppoe/main.c index c0dae9f8..b2968457 100644 --- a/tutorials/stm32/nucleo-f746zg/minimal-pppoe/main.c +++ b/tutorials/stm32/nucleo-f746zg/minimal-pppoe/main.c @@ -28,7 +28,12 @@ bool mg_random(void *buf, size_t len) { // Use on-board RNG static void fn(struct mg_connection *c, int ev, void *ev_data) { - if (ev == MG_EV_HTTP_MSG) { + if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } + } else if (ev == MG_EV_HTTP_MSG) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; (void) hm; mg_http_reply(c, 200, "", "hi\n"); diff --git a/tutorials/stm32/nucleo-f746zg/minimal-rndis/main.c b/tutorials/stm32/nucleo-f746zg/minimal-rndis/main.c index e7cff967..7f7c78c4 100644 --- a/tutorials/stm32/nucleo-f746zg/minimal-rndis/main.c +++ b/tutorials/stm32/nucleo-f746zg/minimal-rndis/main.c @@ -66,7 +66,12 @@ static bool usb_poll(struct mg_tcpip_if *ifp, bool s1) { } static void fn(struct mg_connection *c, int ev, void *ev_data) { - if (ev == MG_EV_HTTP_MSG) { + if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } + } else if (ev == MG_EV_HTTP_MSG) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/debug"), NULL)) { int level = mg_json_get_long(hm->body, "$.level", MG_LL_DEBUG); diff --git a/tutorials/stm32/nucleo-f746zg/minimal/main.c b/tutorials/stm32/nucleo-f746zg/minimal/main.c index a9af858a..1ff8a90a 100644 --- a/tutorials/stm32/nucleo-f746zg/minimal/main.c +++ b/tutorials/stm32/nucleo-f746zg/minimal/main.c @@ -68,6 +68,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), .key = mg_str(TLS_KEY)}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { diff --git a/tutorials/stm32/nucleo-f756zg/minimal/main.c b/tutorials/stm32/nucleo-f756zg/minimal/main.c index a9af858a..1ff8a90a 100644 --- a/tutorials/stm32/nucleo-f756zg/minimal/main.c +++ b/tutorials/stm32/nucleo-f756zg/minimal/main.c @@ -68,6 +68,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), .key = mg_str(TLS_KEY)}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { diff --git a/tutorials/stm32/nucleo-g031k8/minimal-w5500/main.c b/tutorials/stm32/nucleo-g031k8/minimal-w5500/main.c index fa3a7de3..06d6eeb3 100644 --- a/tutorials/stm32/nucleo-g031k8/minimal-w5500/main.c +++ b/tutorials/stm32/nucleo-g031k8/minimal-w5500/main.c @@ -47,7 +47,12 @@ static void timer_fn(void *arg) { static void fn(struct mg_connection *c, int ev, void *ev_data) { struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->fn_data; - if (ev == MG_EV_HTTP_MSG) { + if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } + } else if (ev == MG_EV_HTTP_MSG) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/hello"), NULL)) { // Request to /api/hello diff --git a/tutorials/stm32/nucleo-h563zi/minimal/main.c b/tutorials/stm32/nucleo-h563zi/minimal/main.c index 9afc5886..29dce9be 100644 --- a/tutorials/stm32/nucleo-h563zi/minimal/main.c +++ b/tutorials/stm32/nucleo-h563zi/minimal/main.c @@ -68,6 +68,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), .key = mg_str(TLS_KEY)}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { diff --git a/tutorials/stm32/nucleo-h723zg/cubemx/Core/Src/main.c b/tutorials/stm32/nucleo-h723zg/cubemx/Core/Src/main.c index 9498d2b8..28a133d0 100644 --- a/tutorials/stm32/nucleo-h723zg/cubemx/Core/Src/main.c +++ b/tutorials/stm32/nucleo-h723zg/cubemx/Core/Src/main.c @@ -89,7 +89,12 @@ static void log_fn(char ch, void *param) { } static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { - if (ev == MG_EV_HTTP_MSG) { + if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } + } else if (ev == MG_EV_HTTP_MSG) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { mg_http_reply(c, 200, "", "{%m:%lu}\n", MG_ESC("tick"), HAL_GetTick()); diff --git a/tutorials/stm32/nucleo-h723zg/minimal-bsd-baremetal/main.c b/tutorials/stm32/nucleo-h723zg/minimal-bsd-baremetal/main.c index 466726ef..97209b5b 100644 --- a/tutorials/stm32/nucleo-h723zg/minimal-bsd-baremetal/main.c +++ b/tutorials/stm32/nucleo-h723zg/minimal-bsd-baremetal/main.c @@ -44,7 +44,12 @@ bool mg_random(void *buf, size_t len) { } static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { - if (ev == MG_EV_HTTP_MSG) { + if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } + } else if (ev == MG_EV_HTTP_MSG) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick()); diff --git a/tutorials/stm32/nucleo-h723zg/minimal-bsd-freertos/main.c b/tutorials/stm32/nucleo-h723zg/minimal-bsd-freertos/main.c index 3ad55286..9e8f4ca8 100644 --- a/tutorials/stm32/nucleo-h723zg/minimal-bsd-freertos/main.c +++ b/tutorials/stm32/nucleo-h723zg/minimal-bsd-freertos/main.c @@ -43,7 +43,12 @@ bool mg_random(void *buf, size_t len) { } static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { - if (ev == MG_EV_HTTP_MSG) { + if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } + } else if (ev == MG_EV_HTTP_MSG) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick()); diff --git a/tutorials/stm32/nucleo-h723zg/minimal/main.c b/tutorials/stm32/nucleo-h723zg/minimal/main.c index d6a954f3..2021aa61 100644 --- a/tutorials/stm32/nucleo-h723zg/minimal/main.c +++ b/tutorials/stm32/nucleo-h723zg/minimal/main.c @@ -68,6 +68,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), .key = mg_str(TLS_KEY)}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { diff --git a/tutorials/stm32/nucleo-h743zi/minimal/main.c b/tutorials/stm32/nucleo-h743zi/minimal/main.c index bffe9198..0b1e2889 100644 --- a/tutorials/stm32/nucleo-h743zi/minimal/main.c +++ b/tutorials/stm32/nucleo-h743zi/minimal/main.c @@ -68,6 +68,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), .key = mg_str(TLS_KEY)}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { diff --git a/tutorials/stm32/nucleo-n657x0-q/minimal/main.c b/tutorials/stm32/nucleo-n657x0-q/minimal/main.c index 24ea16ac..9d1f4ff2 100644 --- a/tutorials/stm32/nucleo-n657x0-q/minimal/main.c +++ b/tutorials/stm32/nucleo-n657x0-q/minimal/main.c @@ -64,6 +64,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), .key = mg_str(TLS_KEY)}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { diff --git a/tutorials/stm32/nucleo-u5a5zj-q/minimal/main.c b/tutorials/stm32/nucleo-u5a5zj-q/minimal/main.c index 3bca52ab..06ed1880 100644 --- a/tutorials/stm32/nucleo-u5a5zj-q/minimal/main.c +++ b/tutorials/stm32/nucleo-u5a5zj-q/minimal/main.c @@ -60,6 +60,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), .key = mg_str(TLS_KEY)}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { diff --git a/tutorials/stm32/portenta-h7/minimal/main.c b/tutorials/stm32/portenta-h7/minimal/main.c index 62720f30..b6e08ecf 100644 --- a/tutorials/stm32/portenta-h7/minimal/main.c +++ b/tutorials/stm32/portenta-h7/minimal/main.c @@ -68,6 +68,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), .key = mg_str(TLS_KEY)}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { diff --git a/tutorials/stm32/stm32h573i-dk/minimal/main.c b/tutorials/stm32/stm32h573i-dk/minimal/main.c index ea1fde63..c1a9fa9b 100644 --- a/tutorials/stm32/stm32h573i-dk/minimal/main.c +++ b/tutorials/stm32/stm32h573i-dk/minimal/main.c @@ -68,6 +68,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), .key = mg_str(TLS_KEY)}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { diff --git a/tutorials/stm32/stm32h747i-disco/minimal/main.c b/tutorials/stm32/stm32h747i-disco/minimal/main.c index ecaeb215..02f62a88 100644 --- a/tutorials/stm32/stm32h747i-disco/minimal/main.c +++ b/tutorials/stm32/stm32h747i-disco/minimal/main.c @@ -68,6 +68,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), .key = mg_str(TLS_KEY)}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { diff --git a/tutorials/ti/ek-tm4c1294xl-make-baremetal-builtin-rndis/main.c b/tutorials/ti/ek-tm4c1294xl-make-baremetal-builtin-rndis/main.c index 1d6c7e1d..b4dd4d83 100644 --- a/tutorials/ti/ek-tm4c1294xl-make-baremetal-builtin-rndis/main.c +++ b/tutorials/ti/ek-tm4c1294xl-make-baremetal-builtin-rndis/main.c @@ -63,7 +63,12 @@ static bool usb_poll(struct mg_tcpip_if *ifp, bool s1) { } static void fn(struct mg_connection *c, int ev, void *ev_data) { - if (ev == MG_EV_HTTP_MSG) { + if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } + } else if (ev == MG_EV_HTTP_MSG) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (mg_match(hm->uri, mg_str("/api/debug"), NULL)) { int level = mg_json_get_long(hm->body, "$.level", MG_LL_DEBUG); diff --git a/tutorials/wch/ch32v307-make-baremetal-builtin/main.c b/tutorials/wch/ch32v307-make-baremetal-builtin/main.c index 887983f4..ee3038c8 100644 --- a/tutorials/wch/ch32v307-make-baremetal-builtin/main.c +++ b/tutorials/wch/ch32v307-make-baremetal-builtin/main.c @@ -30,7 +30,12 @@ static void timer_fn(void *arg) { // https://mongoose.ws/documentation/#2-minute-integration-guide static void fn(struct mg_connection *c, int ev, void *ev_data) { - if (ev == MG_EV_HTTP_MSG) { + if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } + } else if (ev == MG_EV_HTTP_MSG) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; mg_http_reply(c, 200, "", "ok %p\r\n", hm); } diff --git a/tutorials/zephyr/http-server/src/main.c b/tutorials/zephyr/http-server/src/main.c index d20ae76f..f993ca58 100644 --- a/tutorials/zephyr/http-server/src/main.c +++ b/tutorials/zephyr/http-server/src/main.c @@ -14,6 +14,11 @@ static void wcb(struct mg_connection *c, int ev, void *ev_data) { if (ev == MG_EV_ACCEPT && c->is_tls) { struct mg_tls_opts opts = {.cert = (char *) s_ssl_cert, .key = (char *) s_ssl_key}; mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_HDRS) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/ota"), NULL)) { + mg_http_stream_body(c, hm, mg_http_ota_cb, NULL); + } } else if (ev == MG_EV_HTTP_MSG) { struct mg_http_message *hm = ev_data; MG_INFO(("%.*s %.*s %ld", (int) hm->method.len, hm->method.buf,