diff --git a/examples/file-transfer/server.c b/examples/file-transfer/server.c index 6287901c..69d625bc 100644 --- a/examples/file-transfer/server.c +++ b/examples/file-transfer/server.c @@ -42,7 +42,7 @@ static void cb(struct mg_connection *c, int ev, void *ev_data) { mg_fs_close(fd); mg_http_reply(c, 200, "", "ok\n"); } - } else if(c->is_resp == 0) { + } else if (c->is_resp == 0) { struct mg_http_message hm; int n = mg_http_parse((char *) c->recv.buf, c->recv.len, &hm); if (n < 0) mg_error(c, "Bad response"); @@ -71,9 +71,9 @@ static void cb(struct mg_connection *c, int ev, void *ev_data) { } else { MG_DEBUG(("Got request, chunk len %lu", c->recv.len - n)); if ((fd = mg_fs_open(&mg_fs_posix, fpath, MG_FS_WRITE)) == NULL) { - mg_http_reply(c, 400, "", "open failed: %d", errno); + mg_http_reply(c, 400, "", "open failed: %d\n", errno); c->is_draining = 1; // Tell mongoose to close this connection - } else { + } else { c->fn_data = fd; c->recv.len -= n; // remove headers data[0] = hm.body.len; @@ -88,7 +88,7 @@ static void cb(struct mg_connection *c, int ev, void *ev_data) { } } } - c->is_resp = 1; // ignore the rest of the body + c->is_resp = 1; // ignore the rest of the body } else { struct mg_http_serve_opts opts = {0}; opts.root_dir = s_root_dir; @@ -159,7 +159,9 @@ int main(int argc, char *argv[]) { signal(SIGTERM, signal_handler); mg_log_set(s_debug_level); mg_mgr_init(&mgr); - if (mg_http_listen(&mgr, s_listening_address, cb, NULL) == NULL) { + // use mg_listen instead of mg_http_listen to be able to override the parser + // and shape buffering + if (mg_listen(&mgr, s_listening_address, cb, NULL) == NULL) { MG_ERROR(("Cannot listen on %s.", s_listening_address)); exit(EXIT_FAILURE); } diff --git a/examples/file-upload-single-post/main.c b/examples/file-upload-single-post/main.c index b9bd6423..c3be1382 100644 --- a/examples/file-upload-single-post/main.c +++ b/examples/file-upload-single-post/main.c @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Cesanta Software Limited +// Copyright (c) 2020-2024 Cesanta Software Limited // All rights reserved // // Streaming upload example. Demonstrates how to use MG_EV_READ events @@ -11,7 +11,7 @@ // HTTP request handler function. It implements the following endpoints: // /upload - Saves the next file chunk // all other URI - serves web_root/ directory -static void cb(struct mg_connection *c, int ev, void *ev_data) { +static void fn(struct mg_connection *c, int ev, void *ev_data) { if (ev == MG_EV_READ) { // Parse the incoming data ourselves. If we can parse the request, // store two size_t variables in the c->data: expected len and recv len. @@ -46,7 +46,7 @@ int main(void) { mg_mgr_init(&mgr); mg_log_set(MG_LL_DEBUG); // Set debug log level - mg_http_listen(&mgr, "http://localhost:8000", cb, NULL); + mg_listen(&mgr, "http://localhost:8000", fn, NULL); for (;;) mg_mgr_poll(&mgr, 50); mg_mgr_free(&mgr); diff --git a/examples/http-streaming-client/main.c b/examples/http-streaming-client/main.c index de4c9082..b0c180f2 100644 --- a/examples/http-streaming-client/main.c +++ b/examples/http-streaming-client/main.c @@ -27,53 +27,44 @@ static void fn(struct mg_connection *c, int ev, void *ev_data) { // Send request mg_printf(c, "GET %s HTTP/1.1\r\n" - "Connection: keep-alive\r\n" - "Keep-Alive: timeout=60\r\n" + "Connection: close\r\n" "Host: %.*s\r\n" "\r\n", mg_url_uri(s_url), (int) host.len, host.ptr); } else if (ev == MG_EV_READ) { - // Parse the incoming data ourselves. If we can parse the request, - // store two size_t variables in the c->data: expected len and recv len. - size_t *data = (size_t *) c->data; - if (data[0]) { // Already parsed, simply print received data - data[1] += c->recv.len; - fwrite(c->recv.buf, 1, c->recv.len, stdout); - c->recv.len = 0; // And cleanup the receive buffer. Streming! - if (data[1] >= data[0]) * (bool *) c->fn_data = true; - } else { + // c->data[0] holds a flag, whether we have parsed the request already + if (c->data[0] == 0) { struct mg_http_message hm; int n = mg_http_parse((char *) c->recv.buf, c->recv.len, &hm); if (n < 0) mg_error(c, "Bad response"); if (n > 0) { fwrite(c->recv.buf + n, 1, c->recv.len - n, stdout); // Print body - data[0] = n + hm.body.len; - data[1] = c->recv.len; c->recv.len = 0; // Cleanup receive buffer - if (data[1] >= data[0]) * (bool *) c->fn_data = true; + c->data[0] = 1; // Request parsed, set the flag } + } else { + fwrite(c->recv.buf, 1, c->recv.len, stdout); + c->recv.len = 0; // Cleanup the receive buffer } } else if (ev == MG_EV_CLOSE) { - *(bool *) c->fn_data = true; // tell event loop to stop + *(bool *) c->fn_data = true; // Done, tell event loop to stop } else if (ev == MG_EV_ERROR) { - *(bool *) c->fn_data = true; // Error, tell event loop to stop + *(bool *) c->fn_data = true; // Error, Tell event loop to stop } (void) ev_data; } int main(int argc, char *argv[]) { - struct mg_mgr mgr; // Event manager - bool done = false; // Event handler flips it to true - const char *log_level = getenv("V"); // Log level + struct mg_mgr mgr; // Event manager + bool done = false; // Event handler flips it to true - mg_mgr_init(&mgr); // Initialise event manager - if (log_level == NULL) log_level = "2"; // If not set, set to DEBUG - mg_log_set(atoi(log_level)); // Set to 0 to disable debug log - if (argc > 1) s_url = argv[1]; // Use URL from command line + mg_mgr_init(&mgr); // Initialise event manager + mg_log_set(MG_LL_INFO); // Set to 0 to disable debug log - mg_http_connect(&mgr, s_url, fn, &done); // Create client connection - while (!done) mg_mgr_poll(&mgr, 1000); // Infinite event loop - mg_mgr_free(&mgr); // Free resources + if (argc > 1) s_url = argv[1]; // Use URL from command line + mg_connect(&mgr, s_url, fn, &done); // Create client connection + while (!done) mg_mgr_poll(&mgr, 1000); // Infinite event loop + mg_mgr_free(&mgr); // Free resources return 0; } diff --git a/mongoose.c b/mongoose.c index 9e4303d2..25904dc5 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1345,11 +1345,9 @@ void mg_call(struct mg_connection *c, int ev, void *ev_data) { MG_PROF_ADD(c, names[ev]); } #endif - // Run user-defined handler first, in order to give it an ability - // to intercept processing (e.g. clean input buffer) before the - // protocol handler kicks in - if (c->fn != NULL) c->fn(c, ev, ev_data); + // Fire protocol handler first, user handler second. See #2559 if (c->pfn != NULL) c->pfn(c, ev, ev_data); + if (c->fn != NULL) c->fn(c, ev, ev_data); } void mg_error(struct mg_connection *c, const char *fmt, ...) { diff --git a/src/event.c b/src/event.c index e6217f40..8c0fa211 100644 --- a/src/event.c +++ b/src/event.c @@ -16,11 +16,9 @@ void mg_call(struct mg_connection *c, int ev, void *ev_data) { MG_PROF_ADD(c, names[ev]); } #endif - // Run user-defined handler first, in order to give it an ability - // to intercept processing (e.g. clean input buffer) before the - // protocol handler kicks in - if (c->fn != NULL) c->fn(c, ev, ev_data); + // Fire protocol handler first, user handler second. See #2559 if (c->pfn != NULL) c->pfn(c, ev, ev_data); + if (c->fn != NULL) c->fn(c, ev, ev_data); } void mg_error(struct mg_connection *c, const char *fmt, ...) { diff --git a/test/unit_test.c b/test/unit_test.c index dbc736ca..faceab48 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -1407,7 +1407,7 @@ static void test_http_no_content_length(void) { for (i = 0; i < 1000 && strchr(buf2, 'c') == NULL; i++) mg_mgr_poll(&mgr, 10); MG_INFO(("[%s] [%s]", buf1, buf2)); ASSERT(strcmp(buf1, "mc") == 0); - ASSERT(strcmp(buf2, "cm") == 0); // See #1475 + ASSERT(strcmp(buf2, "mc") == 0); mg_mgr_free(&mgr); ASSERT(mgr.conns == NULL); }