diff --git a/mongoose.c b/mongoose.c index 2481b9c8..588e847f 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1578,7 +1578,7 @@ void mg_dash_ev_handler(struct mg_connection *c, int ev, void *ev_data) { // The response has been send in EV_HDRS path, so we're not reponding // anything but clearing the marker for the next request. d->marker = 0; - c->is_resp = 0; + c->pfn_data = NULL; // Response done } else if (ev == MG_EV_HTTP_MSG && d->marker == '\0') { struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_dash_user *u = mg_dash_authenticate(c, hm, dash); @@ -3848,7 +3848,7 @@ static void mg_http_vprintf_chunk(struct mg_connection *c, const char *fmt, if (c->send.len >= len + 10) { mg_snprintf((char *) c->send.buf + len, 9, "%08lx", c->send.len - len - 10); c->send.buf[len + 8] = '\r'; - if (c->send.len == len + 10) c->is_resp = 0; // Last chunk, reset marker + if (c->send.len == len + 10) c->pfn_data = NULL; // Last chunk, done } if (!mg_send(c, "\r\n", 2)) mg_error(c, "OOM"); } @@ -3863,7 +3863,7 @@ void mg_http_printf_chunk(struct mg_connection *c, const char *fmt, ...) { void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len) { mg_printf(c, "%lx\r\n", (unsigned long) len); if (!mg_send(c, buf, len) || !mg_send(c, "\r\n", 2)) mg_error(c, "OOM"); - if (len == 0) c->is_resp = 0; + if (len == 0) c->pfn_data = NULL; // Last chunk, response done } // clang-format off @@ -3952,15 +3952,14 @@ void mg_http_reply(struct mg_connection *c, int code, const char *headers, (unsigned long) (c->send.len - len)); c->send.buf[len - 15 + n] = ' '; // Change ending 0 to space } - c->is_resp = 0; + c->pfn_data = NULL; // Response done } static void http_cb(struct mg_connection *, int, void *); static void restore_http_cb(struct mg_connection *c) { mg_fs_close((struct mg_fd *) c->pfn_data); - c->pfn_data = NULL; + c->pfn_data = NULL; // Response done c->pfn = http_cb; - c->is_resp = 0; } char *mg_http_etag(char *buf, size_t len, size_t size, time_t mtime); @@ -4148,7 +4147,7 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm, etag, (uint64_t) cl, gzip ? "Content-Encoding: gzip\r\n" : "", range, hdrs); if (mg_strcasecmp(hm->method, mg_str("HEAD")) == 0 || c->is_closing) { - c->is_resp = 0; + c->pfn_data = NULL; // Response done mg_fs_close(fd); } else { // start serving static content only if not closing, see #3354 // Track to-be-sent content length at the end of c->data, aligned @@ -4217,7 +4216,7 @@ static void listdir(struct mg_connection *c, struct mg_http_message *hm, n = mg_snprintf(tmp, sizeof(tmp), "%lu", (unsigned long) (c->send.len - off)); if (n > sizeof(tmp)) n = 0; memcpy(c->send.buf + off - 12, tmp, n); // Set content length - c->is_resp = 0; // Mark response end + c->pfn_data = NULL; // Response done } // Map requested URI to the file path (buf,len). Use root directory r. @@ -4271,7 +4270,7 @@ static int uri_to_file_status(struct mg_connection *c, "Content-Length: 0\r\n" "\r\n", (int) hm->uri.len, hm->uri.buf); - c->is_resp = 0; + c->pfn_data = NULL; // Response done flags = -1; } else if (flags & MG_FS_DIR) { if (((mg_snprintf(path + n, path_size - n, "/" MG_HTTP_INDEX) > 0 && @@ -4616,7 +4615,9 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) { c->recv.len > 0)) { // see #2796 struct mg_http_message hm; size_t ofs = 0; // Parsing offset - while (c->is_resp == 0 && ofs < c->recv.len) { + // c->pfn_data is the "response generation in progress" marker. While it + // is set, don't parse the next pipelined request, to keep responses in order + while (c->pfn_data == NULL && ofs < c->recv.len) { const char *buf = (char *) c->recv.buf + ofs; int n = mg_http_parse(buf, c->recv.len - ofs, &hm); struct mg_str *te; // Transfer - encoding header @@ -4709,9 +4710,9 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) { ofs += (size_t) n + hm.body.len; } - if (c->is_accepted) c->is_resp = 1; // Start generating response - mg_call(c, MG_EV_HTTP_MSG, &hm); // User handler can clear is_resp - if (c->is_accepted && !c->is_resp) { + if (c->is_accepted) c->pfn_data = c; // Response started + mg_call(c, MG_EV_HTTP_MSG, &hm); // Handler sets pfn_data NULL when done + if (c->is_accepted && c->pfn_data == NULL) { struct mg_str *cc = mg_http_get_header(&hm, "Connection"); if (cc != NULL && mg_strcasecmp(*cc, mg_str("close")) == 0) { c->is_draining = 1; // honor "Connection: close" @@ -15268,13 +15269,8 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) { for (c = mgr->conns; c != NULL; c = tmp) { long flush = 0; - bool is_resp = c->is_resp; tmp = c->next; mg_call(c, MG_EV_POLL, &now); - if (is_resp && !c->is_resp) { - long n = 0; - mg_call(c, MG_EV_READ, &n); - } MG_VERBOSE(("%lu %c%c %c%c%c%c%c %lu %lu", c->id, c->is_readable ? 'r' : '-', c->is_writable ? 'w' : '-', c->is_tls ? 'T' : 't', c->is_connecting ? 'C' : 'c', @@ -27021,7 +27017,7 @@ void mg_ws_upgrade(struct mg_connection *c, struct mg_http_message *hm, ws_handshake(c, wskey, wsproto, fmt, &ap); va_end(ap); c->is_websocket = 1; - c->is_resp = 0; + c->pfn_data = NULL; // HTTP response done; mg_ws_cb uses it as an offset mg_call(c, MG_EV_WS_OPEN, hm); } } diff --git a/mongoose.h b/mongoose.h index fe1646a7..1219fd20 100644 --- a/mongoose.h +++ b/mongoose.h @@ -2488,7 +2488,6 @@ struct mg_connection { unsigned is_closing : 1; // Close and free immediately on next poll unsigned is_full : 1; // Pause incoming reads until cleared unsigned is_tls_throttled : 1; // TLS write was throttled; retry pending - unsigned is_resp : 1; // HTTP: response is still being generated unsigned is_readable : 1; // Socket is ready to read (epoll/select) unsigned is_writable : 1; // Socket is ready to write (epoll/select) }; diff --git a/src/dash.c b/src/dash.c index 57b1ecd0..f7ceb756 100644 --- a/src/dash.c +++ b/src/dash.c @@ -603,7 +603,7 @@ void mg_dash_ev_handler(struct mg_connection *c, int ev, void *ev_data) { // The response has been send in EV_HDRS path, so we're not reponding // anything but clearing the marker for the next request. d->marker = 0; - c->is_resp = 0; + c->pfn_data = NULL; // Response done } else if (ev == MG_EV_HTTP_MSG && d->marker == '\0') { struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_dash_user *u = mg_dash_authenticate(c, hm, dash); diff --git a/src/http.c b/src/http.c index ad58c3f8..96368993 100644 --- a/src/http.c +++ b/src/http.c @@ -358,7 +358,7 @@ static void mg_http_vprintf_chunk(struct mg_connection *c, const char *fmt, if (c->send.len >= len + 10) { mg_snprintf((char *) c->send.buf + len, 9, "%08lx", c->send.len - len - 10); c->send.buf[len + 8] = '\r'; - if (c->send.len == len + 10) c->is_resp = 0; // Last chunk, reset marker + if (c->send.len == len + 10) c->pfn_data = NULL; // Last chunk, done } if (!mg_send(c, "\r\n", 2)) mg_error(c, "OOM"); } @@ -373,7 +373,7 @@ void mg_http_printf_chunk(struct mg_connection *c, const char *fmt, ...) { void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len) { mg_printf(c, "%lx\r\n", (unsigned long) len); if (!mg_send(c, buf, len) || !mg_send(c, "\r\n", 2)) mg_error(c, "OOM"); - if (len == 0) c->is_resp = 0; + if (len == 0) c->pfn_data = NULL; // Last chunk, response done } // clang-format off @@ -462,15 +462,14 @@ void mg_http_reply(struct mg_connection *c, int code, const char *headers, (unsigned long) (c->send.len - len)); c->send.buf[len - 15 + n] = ' '; // Change ending 0 to space } - c->is_resp = 0; + c->pfn_data = NULL; // Response done } static void http_cb(struct mg_connection *, int, void *); static void restore_http_cb(struct mg_connection *c) { mg_fs_close((struct mg_fd *) c->pfn_data); - c->pfn_data = NULL; + c->pfn_data = NULL; // Response done c->pfn = http_cb; - c->is_resp = 0; } char *mg_http_etag(char *buf, size_t len, size_t size, time_t mtime); @@ -658,7 +657,7 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm, etag, (uint64_t) cl, gzip ? "Content-Encoding: gzip\r\n" : "", range, hdrs); if (mg_strcasecmp(hm->method, mg_str("HEAD")) == 0 || c->is_closing) { - c->is_resp = 0; + c->pfn_data = NULL; // Response done mg_fs_close(fd); } else { // start serving static content only if not closing, see #3354 // Track to-be-sent content length at the end of c->data, aligned @@ -727,7 +726,7 @@ static void listdir(struct mg_connection *c, struct mg_http_message *hm, n = mg_snprintf(tmp, sizeof(tmp), "%lu", (unsigned long) (c->send.len - off)); if (n > sizeof(tmp)) n = 0; memcpy(c->send.buf + off - 12, tmp, n); // Set content length - c->is_resp = 0; // Mark response end + c->pfn_data = NULL; // Response done } // Map requested URI to the file path (buf,len). Use root directory r. @@ -781,7 +780,7 @@ static int uri_to_file_status(struct mg_connection *c, "Content-Length: 0\r\n" "\r\n", (int) hm->uri.len, hm->uri.buf); - c->is_resp = 0; + c->pfn_data = NULL; // Response done flags = -1; } else if (flags & MG_FS_DIR) { if (((mg_snprintf(path + n, path_size - n, "/" MG_HTTP_INDEX) > 0 && @@ -1126,7 +1125,9 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) { c->recv.len > 0)) { // see #2796 struct mg_http_message hm; size_t ofs = 0; // Parsing offset - while (c->is_resp == 0 && ofs < c->recv.len) { + // c->pfn_data is the "response generation in progress" marker. While it + // is set, don't parse the next pipelined request, to keep responses in order + while (c->pfn_data == NULL && ofs < c->recv.len) { const char *buf = (char *) c->recv.buf + ofs; int n = mg_http_parse(buf, c->recv.len - ofs, &hm); struct mg_str *te; // Transfer - encoding header @@ -1219,9 +1220,9 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) { ofs += (size_t) n + hm.body.len; } - if (c->is_accepted) c->is_resp = 1; // Start generating response - mg_call(c, MG_EV_HTTP_MSG, &hm); // User handler can clear is_resp - if (c->is_accepted && !c->is_resp) { + if (c->is_accepted) c->pfn_data = c; // Response started + mg_call(c, MG_EV_HTTP_MSG, &hm); // Handler sets pfn_data NULL when done + if (c->is_accepted && c->pfn_data == NULL) { struct mg_str *cc = mg_http_get_header(&hm, "Connection"); if (cc != NULL && mg_strcasecmp(*cc, mg_str("close")) == 0) { c->is_draining = 1; // honor "Connection: close" diff --git a/src/net.h b/src/net.h index 5ba7a71b..ad823641 100644 --- a/src/net.h +++ b/src/net.h @@ -95,7 +95,6 @@ struct mg_connection { unsigned is_closing : 1; // Close and free immediately on next poll unsigned is_full : 1; // Pause incoming reads until cleared unsigned is_tls_throttled : 1; // TLS write was throttled; retry pending - unsigned is_resp : 1; // HTTP: response is still being generated unsigned is_readable : 1; // Socket is ready to read (epoll/select) unsigned is_writable : 1; // Socket is ready to write (epoll/select) }; diff --git a/src/sock.c b/src/sock.c index 28c3cc6c..23f3cb2d 100644 --- a/src/sock.c +++ b/src/sock.c @@ -772,13 +772,8 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) { for (c = mgr->conns; c != NULL; c = tmp) { long flush = 0; - bool is_resp = c->is_resp; tmp = c->next; mg_call(c, MG_EV_POLL, &now); - if (is_resp && !c->is_resp) { - long n = 0; - mg_call(c, MG_EV_READ, &n); - } MG_VERBOSE(("%lu %c%c %c%c%c%c%c %lu %lu", c->id, c->is_readable ? 'r' : '-', c->is_writable ? 'w' : '-', c->is_tls ? 'T' : 't', c->is_connecting ? 'C' : 'c', diff --git a/src/ws.c b/src/ws.c index 2a2da30f..5f1a4a1d 100644 --- a/src/ws.c +++ b/src/ws.c @@ -287,7 +287,7 @@ void mg_ws_upgrade(struct mg_connection *c, struct mg_http_message *hm, ws_handshake(c, wskey, wsproto, fmt, &ap); va_end(ap); c->is_websocket = 1; - c->is_resp = 0; + c->pfn_data = NULL; // HTTP response done; mg_ws_cb uses it as an offset mg_call(c, MG_EV_WS_OPEN, hm); } } diff --git a/test/unit_test.c b/test/unit_test.c index b5de3da6..705e413f 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -3351,7 +3351,7 @@ static void eY(struct mg_connection *c, int ev, void *ev_data) { c->data[0]++; if (c->data[0] == 10) mg_send(c, "a", 1); if (c->data[0] == 12) mg_send(c, "bc", 2); - if (c->data[0] == 30) mg_send(c, "d", 1), c->is_resp = 0, c->data[0] = 0; + if (c->data[0] == 30) mg_send(c, "d", 1), c->pfn_data = NULL, c->data[0] = 0; } (void) ev_data; } diff --git a/tutorials/http/http-reverse-proxy/main.c b/tutorials/http/http-reverse-proxy/main.c index 196b1c83..04f01b51 100644 --- a/tutorials/http/http-reverse-proxy/main.c +++ b/tutorials/http/http-reverse-proxy/main.c @@ -65,7 +65,7 @@ static void fn(struct mg_connection *c, int ev, void *ev_data) { } c->fn_data = c2; forward_request(hm, c2); - c->is_resp = 0; // process further msgs in keep-alive connection + c->pfn_data = NULL; // process further msgs in keep-alive connection c2->is_hexdumping = 1; } } else if (ev == MG_EV_CLOSE) {