diff --git a/cmake/lws_config_private.h.in b/cmake/lws_config_private.h.in index 1578aea33..a3235818d 100644 --- a/cmake/lws_config_private.h.in +++ b/cmake/lws_config_private.h.in @@ -119,4 +119,4 @@ /* Define if the inline keyword doesn't exist. */ #cmakedefine inline ${inline} - +#cmakedefine LWS_WITH_ZLIB diff --git a/contrib/abi/libwebsockets.json b/contrib/abi/libwebsockets.json index c72fda88e..1357afa97 100644 --- a/contrib/abi/libwebsockets.json +++ b/contrib/abi/libwebsockets.json @@ -14,6 +14,156 @@ "ABIView": "Off", "ABIDiff": "Off" }, + { + "Number": "3.0.0", + "Installed": "installed/libwebsockets/3.0.0", + "Source": "src/libwebsockets/3.0.0/libwebsockets-3.0.0.tar.gz", + "Changelog": "changelog", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off" + }, + { + "Number": "2.4.2", + "Installed": "installed/libwebsockets/2.4.2", + "Source": "src/libwebsockets/2.4.2/libwebsockets-2.4.2.tar.gz", + "Changelog": "changelog", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off" + }, + { + "Number": "2.4.1", + "Installed": "installed/libwebsockets/2.4.1", + "Source": "src/libwebsockets/2.4.1/libwebsockets-2.4.1.tar.gz", + "Changelog": "changelog", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off" + }, + { + "Number": "2.4.0", + "Installed": "installed/libwebsockets/2.4.0", + "Source": "src/libwebsockets/2.4.0/libwebsockets-2.4.0.tar.gz", + "Changelog": "changelog", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off" + }, + { + "Number": "2.3.0", + "Installed": "installed/libwebsockets/2.3.0", + "Source": "src/libwebsockets/2.3.0/libwebsockets-2.3.0.tar.gz", + "Changelog": "changelog", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off" + }, + { + "Number": "2.2.2", + "Installed": "installed/libwebsockets/2.2.2", + "Source": "src/libwebsockets/2.2.2/libwebsockets-2.2.2.tar.gz", + "Changelog": "changelog", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off" + }, + { + "Number": "2.2.1", + "Installed": "installed/libwebsockets/2.2.1", + "Source": "src/libwebsockets/2.2.1/libwebsockets-2.2.1.tar.gz", + "Changelog": "changelog", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off" + }, + { + "Number": "2.2.0", + "Installed": "installed/libwebsockets/2.2.0", + "Source": "src/libwebsockets/2.2.0/libwebsockets-2.2.0.tar.gz", + "Changelog": "changelog", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off" + }, + { + "Number": "2.1.1", + "Installed": "installed/libwebsockets/2.1.1", + "Source": "src/libwebsockets/2.1.1/libwebsockets-2.1.1.tar.gz", + "Changelog": "changelog", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off" + }, + { + "Number": "2.1.0", + "Installed": "installed/libwebsockets/2.1.0", + "Source": "src/libwebsockets/2.1.0/libwebsockets-2.1.0.tar.gz", + "Changelog": "changelog", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off" + }, + { + "Number": "1.7.9", + "Installed": "installed/libwebsockets/1.7.9", + "Source": "src/libwebsockets/1.7.9/libwebsockets-1.7.9.tar.gz", + "Changelog": "changelog", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off" + }, + { + "Number": "1.7.8", + "Installed": "installed/libwebsockets/1.7.8", + "Source": "src/libwebsockets/1.7.8/libwebsockets-1.7.8.tar.gz", + "Changelog": "changelog", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off" + }, + { + "Number": "1.7.7", + "Installed": "installed/libwebsockets/1.7.7", + "Source": "src/libwebsockets/1.7.7/libwebsockets-1.7.7.tar.gz", + "Changelog": "changelog", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off" + }, + { + "Number": "1.7.6", + "Installed": "installed/libwebsockets/1.7.6", + "Source": "src/libwebsockets/1.7.6/libwebsockets-1.7.6.tar.gz", + "Changelog": "changelog", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off" + }, + { + "Number": "1.7.5", + "Installed": "installed/libwebsockets/1.7.5", + "Source": "src/libwebsockets/1.7.5/libwebsockets-1.7.5.tar.gz", + "Changelog": "changelog", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off" + }, { "Number": "1.7.4", "Installed": "installed/libwebsockets/1.7.4", diff --git a/lib/core/context.c b/lib/core/context.c index 37927249d..b7caa7966 100644 --- a/lib/core/context.c +++ b/lib/core/context.c @@ -346,7 +346,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason, struct lws_cgi_args *args; #endif #if defined(LWS_WITH_CGI) || defined(LWS_WITH_HTTP_PROXY) - char buf[512]; + char buf[128]; int n; #endif @@ -387,6 +387,9 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason, ~LWS_CB_REASON_AUX_BF__CGI_HEADERS; else wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__CGI; + + if (wsi->http.cgi && wsi->http.cgi->cgi_transaction_over) + return -1; break; } @@ -537,16 +540,125 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason, case LWS_CALLBACK_CGI_STDIN_DATA: /* POST body for stdin */ args = (struct lws_cgi_args *)in; args->data[args->len] = '\0'; + if (!args->stdwsi[LWS_STDIN]) + return -1; n = lws_get_socket_fd(args->stdwsi[LWS_STDIN]); if (n < 0) return -1; + +#if defined(LWS_WITH_ZLIB) + if (wsi->http.cgi->gzip_inflate) { + /* gzip handling */ + + if (!wsi->http.cgi->gzip_init) { + lwsl_err("inflating gzip\n"); + + memset(&wsi->http.cgi->inflate, 0, sizeof(wsi->http.cgi->inflate)); + + if (inflateInit2(&wsi->http.cgi->inflate, 16 + 15) != Z_OK) { + lwsl_err("%s: iniflateInit failed\n", __func__); + return -1; + } + + wsi->http.cgi->gzip_init = 1; + } + + wsi->http.cgi->inflate.next_in = args->data; + wsi->http.cgi->inflate.avail_in = args->len; + + do { + + wsi->http.cgi->inflate.next_out = wsi->http.cgi->inflate_buf; + wsi->http.cgi->inflate.avail_out = sizeof(wsi->http.cgi->inflate_buf); + + n = inflate(&wsi->http.cgi->inflate, Z_SYNC_FLUSH); + lwsl_err("inflate: %d\n", n); + switch (n) { + case Z_NEED_DICT: + case Z_STREAM_ERROR: + case Z_DATA_ERROR: + case Z_MEM_ERROR: + inflateEnd(&wsi->http.cgi->inflate); + wsi->http.cgi->gzip_init = 0; + lwsl_err("zlib error inflate %d\n", n); + return -1; + } + + if (wsi->http.cgi->inflate.avail_out != sizeof(wsi->http.cgi->inflate_buf)) { + int written; + +// lwsl_hexdump_notice(wsi->http.cgi->inflate_buf, + // sizeof(wsi->http.cgi->inflate_buf) - wsi->http.cgi->inflate.avail_out); + + written = write(args->stdwsi[LWS_STDIN]->desc.filefd, wsi->http.cgi->inflate_buf, + sizeof(wsi->http.cgi->inflate_buf) - wsi->http.cgi->inflate.avail_out); + + if (written != (int)(sizeof(wsi->http.cgi->inflate_buf) - wsi->http.cgi->inflate.avail_out)) { + lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA: " + "sent %d only %d went", n, args->len); + } + lwsl_err("send inflated on fd %d says %d\n", args->stdwsi[LWS_STDIN]->desc.filefd, written); + + if (n == Z_STREAM_END) { + lwsl_err("gzip inflate end\n"); + inflateEnd(&wsi->http.cgi->inflate); + wsi->http.cgi->gzip_init = 0; + + //compatible_close(args->stdwsi[LWS_STDIN]->desc.filefd); + //args->stdwsi[LWS_STDIN]->desc.filefd = -1; + break; + } + + } else + break; + + if (wsi->http.cgi->inflate.avail_out) + break; + + } while (1); + + return args->len; + } +#endif /* WITH_ZLIB */ + n = write(n, args->data, args->len); +// lwsl_hexdump_notice(args->data, args->len); if (n < args->len) lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA: " "sent %d only %d went", n, args->len); + + if (wsi->http.cgi->post_in_expected && args->stdwsi[LWS_STDIN] && + args->stdwsi[LWS_STDIN]->desc.filefd > 0) { + wsi->http.cgi->post_in_expected -= n; + if (!wsi->http.cgi->post_in_expected) { + struct lws *siwsi = args->stdwsi[LWS_STDIN]; + + lwsl_debug("%s: expected POST in end: " + "closing stdin wsi %p, fd %d\n", + __func__, siwsi, siwsi->desc.sockfd); + + __remove_wsi_socket_from_fds(siwsi); + lwsi_set_state(siwsi, LRS_DEAD_SOCKET); + siwsi->socket_is_permanently_unusable = 1; + lws_remove_child_from_any_parent(siwsi); + if (wsi->context->event_loop_ops-> + close_handle_manually) { + wsi->context->event_loop_ops-> + close_handle_manually(siwsi); + siwsi->told_event_loop_closed = 1; + } else { + compatible_close(siwsi->desc.sockfd); + __lws_free_wsi(siwsi); + } + wsi->http.cgi->pipe_fds[LWS_STDIN][1] = -1; + + args->stdwsi[LWS_STDIN] = NULL; + } + } + return n; -#endif -#endif +#endif /* WITH_CGI */ +#endif /* ROLE_ H1 / H2 */ case LWS_CALLBACK_SSL_INFO: si = in; diff --git a/lib/core/libwebsockets.c b/lib/core/libwebsockets.c index 56870b72a..868c65aba 100644 --- a/lib/core/libwebsockets.c +++ b/lib/core/libwebsockets.c @@ -434,7 +434,7 @@ lws_timed_callback_vh_protocol(struct lws_vhost *vh, const struct lws_protocols return 0; } -static void +void lws_remove_child_from_any_parent(struct lws *wsi) { struct lws **pwsi; @@ -856,6 +856,7 @@ __lws_close_free_wsi_final(struct lws *wsi) int n; if (lws_socket_is_valid(wsi->desc.sockfd) && !lws_ssl_close(wsi)) { + lwsl_debug("%s: wsi %p: fd %d\n", __func__, wsi, wsi->desc.sockfd); n = compatible_close(wsi->desc.sockfd); if (n) lwsl_debug("closing: close ret %d\n", LWS_ERRNO); diff --git a/lib/core/private.h b/lib/core/private.h index 778520f7c..f9353d9c7 100644 --- a/lib/core/private.h +++ b/lib/core/private.h @@ -1756,6 +1756,8 @@ lws_context_destroy2(struct lws_context *context); int lws_role_call_client_bind(struct lws *wsi, const struct lws_client_connect_info *i); +void +lws_remove_child_from_any_parent(struct lws *wsi); #ifdef __cplusplus }; diff --git a/lib/event-libs/libuv/libuv.c b/lib/event-libs/libuv/libuv.c index b04cf556f..502dd1886 100644 --- a/lib/event-libs/libuv/libuv.c +++ b/lib/event-libs/libuv/libuv.c @@ -315,7 +315,7 @@ static void lws_libuv_closewsi_m(uv_handle_t* handle) { lws_sockfd_type sockfd = (lws_sockfd_type)(lws_intptr_t)handle->data; - + lwsl_debug("%s: sockfd %d\n", __func__, sockfd); compatible_close(sockfd); } diff --git a/lib/roles/cgi/cgi-server.c b/lib/roles/cgi/cgi-server.c index 8ccf73955..d607e1767 100644 --- a/lib/roles/cgi/cgi-server.c +++ b/lib/roles/cgi/cgi-server.c @@ -195,6 +195,13 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len sum += lws_snprintf(sum, sumend - sum, "%s ", exec_array[0]); + if (0) { + char *pct = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_ENCODING); + + if (pct && !strcmp(pct, "gzip")) + wsi->http.cgi->gzip_inflate = 1; + } + /* prepare his CGI env */ n = 0; @@ -327,10 +334,31 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len if (script_uri_path_len >= 0 && lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT)) { env_array[n++] = p; - p += lws_snprintf(p, end - p, "USER_AGENT=%s", + p += lws_snprintf(p, end - p, "HTTP_USER_AGENT=%s", lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_USER_AGENT)); p++; } + if (script_uri_path_len >= 0 && + lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_ENCODING)) { + env_array[n++] = p; + p += lws_snprintf(p, end - p, "HTTP_CONTENT_ENCODING=%s", + lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_ENCODING)); + p++; + } + if (script_uri_path_len >= 0 && + lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_ACCEPT)) { + env_array[n++] = p; + p += lws_snprintf(p, end - p, "HTTP_ACCEPT=%s", + lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_ACCEPT)); + p++; + } + if (script_uri_path_len >= 0 && + lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING)) { + env_array[n++] = p; + p += lws_snprintf(p, end - p, "HTTP_ACCEPT_ENCODING=%s", + lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING)); + p++; + } if (script_uri_path_len >= 0 && uritok == WSI_TOKEN_POST_URI) { if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE)) { @@ -339,14 +367,21 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE)); p++; } - if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) { + if (!wsi->http.cgi->gzip_inflate && + lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) { env_array[n++] = p; p += lws_snprintf(p, end - p, "CONTENT_LENGTH=%s", lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)); p++; } + + if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) + wsi->http.cgi->post_in_expected = + atoll(lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)); } + + env_array[n++] = "PATH=/bin:/usr/bin:/usr/local/bin:/var/www/cgi-bin"; env_array[n++] = p; @@ -356,6 +391,10 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len env_array[n++] = p; p += lws_snprintf(p, end - p, "%s=%s", mp_cgienv->name, mp_cgienv->value); + if (!strcmp(mp_cgienv->name, "GIT_PROJECT_ROOT")) { + wsi->http.cgi->implied_chunked = 1; + wsi->http.cgi->explicitly_chunked = 1; + } lwsl_info(" Applying mount-specific cgi env '%s'\n", env_array[n - 1]); p++; @@ -367,7 +406,7 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len #if 0 for (m = 0; m < n; m++) - lwsl_info(" %s\n", env_array[m]); + lwsl_notice(" %s\n", env_array[m]); #endif /* @@ -399,9 +438,10 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len if (cgi->pid) { /* we are the parent process */ wsi->context->count_cgi_spawned++; - lwsl_debug("%s: cgi %p spawned PID %d\n", __func__, + lwsl_info("%s: cgi %p spawned PID %d\n", __func__, cgi, cgi->pid); + /* close: stdin:r, stdout:w, stderr:w */ for (n = 0; n < 3; n++) close(cgi->pipe_fds[n][!(n == 0)]); @@ -430,7 +470,8 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len lwsl_err("%s: stdin dup2 failed\n", __func__); goto bail3; } - close(cgi->pipe_fds[n][!(n == 0)]); + close(cgi->pipe_fds[n][0]); + close(cgi->pipe_fds[n][1]); } #if !defined(LWS_HAVE_VFORK) || !defined(LWS_HAVE_EXECVPE) @@ -454,14 +495,14 @@ bail3: __remove_wsi_socket_from_fds(wsi->http.cgi->stdwsi[n]); bail2: for (n = 0; n < 3; n++) - if (wsi->http.cgi->stdwsi[n]) + if (wsi->http.cgi->stdwsi[n] > 0) __lws_free_wsi(cgi->stdwsi[n]); bail1: for (n = 0; n < 3; n++) { - if (cgi->pipe_fds[n][0]) + if (cgi->pipe_fds[n][0] > 0) close(cgi->pipe_fds[n][0]); - if (cgi->pipe_fds[n][1]) + if (cgi->pipe_fds[n][1] > 0) close(cgi->pipe_fds[n][1]); } @@ -479,6 +520,7 @@ static const char * const significant_hdr[SIGNIFICANT_HDR_COUNT] = { "location: ", "status: ", "transfer-encoding: chunked", + "content-encoding: gzip", }; enum header_recode { @@ -620,6 +662,9 @@ post_hpack_recode: return -1; } +// lwsl_hexdump_notice(wsi->http.cgi->headers_pos, +// wsi->http.cgi->headers_end - wsi->http.cgi->headers_pos); + wsi->hdr_state = LHCS_DUMP_HEADERS; wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI_HEADERS; lws_callback_on_writable(wsi); @@ -764,7 +809,7 @@ post_hpack_recode: !significant_hdr[SIGNIFICANT_HDR_TRANSFER_ENCODING] [wsi->http.cgi->match[ SIGNIFICANT_HDR_TRANSFER_ENCODING]]) { - lwsl_debug("cgi produced chunked\n"); + lwsl_info("cgi produced chunked\n"); wsi->http.cgi->explicitly_chunked = 1; } @@ -775,7 +820,6 @@ post_hpack_recode: lwsl_debug("CGI: Location hdr seen\n"); wsi->http.cgi->response_code = 302; } - break; case LCHS_LF1: *wsi->http.cgi->headers_pos++ = c; @@ -836,10 +880,25 @@ agin: /* payload processing */ - m = !wsi->http.cgi->explicitly_chunked && !wsi->http.cgi->content_length; + m = !wsi->http.cgi->implied_chunked && !wsi->http2_substream && !wsi->http.cgi->explicitly_chunked && !wsi->http.cgi->content_length; n = lws_get_socket_fd(wsi->http.cgi->stdwsi[LWS_STDOUT]); if (n < 0) return -1; + if (m) { + uint8_t term[LWS_PRE + 6]; + + lwsl_info("%s: zero chunk\n", __func__); + + memcpy(term + LWS_PRE, (uint8_t *)"0\x0d\x0a\x0d\x0a", 5); + + if (lws_write(wsi, term + LWS_PRE, 5, LWS_WRITE_HTTP_FINAL) != 5) + return -1; + + wsi->http.cgi->cgi_transaction_over = 1; + + return 0; + } + n = read(n, start, sizeof(buf) - LWS_PRE - (m ? LWS_HTTP_CHUNK_HDR_SIZE : 0)); @@ -848,6 +907,7 @@ agin: return -1; } if (n > 0) { + if (!wsi->http2_substream && m) { char chdr[LWS_HTTP_CHUNK_HDR_SIZE]; m = lws_snprintf(chdr, LWS_HTTP_CHUNK_HDR_SIZE - 3, @@ -860,6 +920,7 @@ agin: cmd = LWS_WRITE_HTTP; if (wsi->http.cgi->content_length_seen + n == wsi->http.cgi->content_length) cmd = LWS_WRITE_HTTP_FINAL; + m = lws_write(wsi, (unsigned char *)start, n, cmd); //lwsl_notice("write %d\n", m); if (m < 0) { diff --git a/lib/roles/cgi/ops-cgi.c b/lib/roles/cgi/ops-cgi.c index 0a3cc5cbb..e60487b16 100644 --- a/lib/roles/cgi/ops-cgi.c +++ b/lib/roles/cgi/ops-cgi.c @@ -75,6 +75,22 @@ rops_periodic_checks_cgi(struct lws_context *context, int tsi, time_t now) return 0; } +static int +rops_destroy_role_cgi(struct lws *wsi) +{ +#if defined(LWS_WITH_ZLIB) + if (!wsi->http.cgi) + return 0; + if (!wsi->http.cgi->gzip_init) + return 0; + + inflateEnd(&wsi->http.cgi->inflate); + wsi->http.cgi->gzip_init = 0; +#endif + + return 0; +} + struct lws_role_ops role_ops_cgi = { /* role name */ "cgi", /* alpn id */ NULL, @@ -95,7 +111,7 @@ struct lws_role_ops role_ops_cgi = { /* close_via_role_protocol */ NULL, /* close_role */ NULL, /* close_kill_connection */ NULL, - /* destroy_role */ NULL, + /* destroy_role */ rops_destroy_role_cgi, /* adoption_bind */ NULL, /* client_bind */ NULL, /* writeable cb clnt, srv */ { 0, 0 }, diff --git a/lib/roles/cgi/private.h b/lib/roles/cgi/private.h index b964ce03f..b49f54504 100644 --- a/lib/roles/cgi/private.h +++ b/lib/roles/cgi/private.h @@ -21,6 +21,10 @@ * This is included from core/private.h if LWS_ROLE_WS */ +#if defined(LWS_WITH_ZLIB) +#include +#endif + extern struct lws_role_ops role_ops_cgi; #define lwsi_role_cgi(wsi) (wsi->role_ops == &role_ops_cgi) @@ -28,10 +32,11 @@ extern struct lws_role_ops role_ops_cgi; #define LWS_HTTP_CHUNK_HDR_SIZE 16 enum { - SIGNIFICANT_HDR_CONTENT_LENGTH, + SIGNIFICANT_HDR_CONTENT_LENGTH, /* numeric */ SIGNIFICANT_HDR_LOCATION, - SIGNIFICANT_HDR_STATUS, + SIGNIFICANT_HDR_STATUS, /* numeric */ SIGNIFICANT_HDR_TRANSFER_ENCODING, + SIGNIFICANT_HDR_CONTENT_ENCODING_GZIP, SIGNIFICANT_HDR_COUNT }; @@ -51,7 +56,12 @@ struct lws_cgi { unsigned char *headers_end; char summary[128]; +#if defined(LWS_WITH_ZLIB) + z_stream inflate; + uint8_t inflate_buf[1024]; +#endif + lws_filepos_t post_in_expected; lws_filepos_t content_length; lws_filepos_t content_length_seen; @@ -64,6 +74,10 @@ struct lws_cgi { unsigned char being_closed:1; unsigned char explicitly_chunked:1; + unsigned char cgi_transaction_over:1; + unsigned char implied_chunked:1; + unsigned char gzip_inflate:1; + unsigned char gzip_init:1; unsigned char chunked_grace; }; diff --git a/lib/roles/http/server/server.c b/lib/roles/http/server/server.c index c5e0b88a9..07e925f4a 100644 --- a/lib/roles/http/server/server.c +++ b/lib/roles/http/server/server.c @@ -1652,7 +1652,7 @@ lws_http_transaction_completed(struct lws *wsi) return 1; if (wsi->http.connection_type != HTTP_CONNECTION_KEEP_ALIVE) { - lwsl_notice("%s: %p: close connection\n", __func__, wsi); + lwsl_info("%s: %p: close connection\n", __func__, wsi); return 1; } diff --git a/minimal-examples/http-server/README.md b/minimal-examples/http-server/README.md index db5579b2f..44f868db8 100644 --- a/minimal-examples/http-server/README.md +++ b/minimal-examples/http-server/README.md @@ -10,6 +10,7 @@ minimal-http-server-form-post-file|Process a multipart POST form with file trans minimal-http-server-form-post|Process a POST form (no file transfer) minimal-http-server-mimetypes|Shows how to add support for additional mimetypes at runtime minimal-http-server-multivhost|Same as minimal-http-server but three different vhosts +minimal-http-server-proxy|Reverse Proxy minimal-http-server-smp|Multiple service threads minimal-http-server-sse-ring|Server Side Events with ringbuffer and threaded event sources minimal-http-server-sse|Simple Server Side Events