also remove patches incorporated upstream into lighttpd 1.4.60 Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com>lilik-openwrt-22.03
@ -0,0 +1,34 @@ | |||||
From cf4dfbe15ef8ead3a7eda974af7d804d447f00db Mon Sep 17 00:00:00 2001 | |||||
From: Glenn Strauss <gstrauss@gluelogic.com> | |||||
Date: Mon, 4 Oct 2021 09:51:22 -0400 | |||||
Subject: [PATCH] [core] define __BEGIN_DECLS, __END_DECLS if needed | |||||
--- | |||||
src/first.h | 16 ++++++++++++++++ | |||||
1 file changed, 16 insertions(+) | |||||
--- a/src/first.h | |||||
+++ b/src/first.h | |||||
@@ -39,6 +39,22 @@ | |||||
#include <sys/types.h> | |||||
#include <stddef.h> | |||||
+#ifndef __BEGIN_DECLS | |||||
+#ifdef __cplusplus | |||||
+#define __BEGIN_DECLS extern "C" { | |||||
+#else | |||||
+#define __BEGIN_DECLS | |||||
+#endif | |||||
+#endif | |||||
+ | |||||
+#ifndef __END_DECLS | |||||
+#ifdef __cplusplus | |||||
+#define __END_DECLS } | |||||
+#else | |||||
+#define __END_DECLS | |||||
+#endif | |||||
+#endif | |||||
+ | |||||
#if defined HAVE_STDINT_H | |||||
# include <stdint.h> | |||||
#elif defined HAVE_INTTYPES_H |
@ -1,24 +0,0 @@ | |||||
From a737572aa4b7a50fd9ac3f54245e40fd5cd2609d Mon Sep 17 00:00:00 2001 | |||||
From: Glenn Strauss <gstrauss@gluelogic.com> | |||||
Date: Wed, 3 Feb 2021 00:35:34 -0500 | |||||
Subject: [PATCH] [meson] add with_zstd to meson_options.txt | |||||
Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com> | |||||
--- | |||||
meson_options.txt | 5 +++++ | |||||
1 file changed, 5 insertions(+) | |||||
--- a/meson_options.txt | |||||
+++ b/meson_options.txt | |||||
@@ -148,6 +148,11 @@ option('with_zlib', | |||||
value: true, | |||||
description: 'with deflate-support for mod_deflate [default: on]', | |||||
) | |||||
+option('with_zstd', | |||||
+ type: 'boolean', | |||||
+ value: false, | |||||
+ description: 'with zstd-support for mod_deflate [default: off]', | |||||
+) | |||||
option('build_extra_warnings', | |||||
type: 'boolean', |
@ -1,31 +0,0 @@ | |||||
From 1ca25d4e2cfeb83c844ad52b9c94eac218c71379 Mon Sep 17 00:00:00 2001 | |||||
From: Glenn Strauss <gstrauss@gluelogic.com> | |||||
Date: Thu, 4 Feb 2021 00:22:12 -0500 | |||||
Subject: [PATCH] [core] 101 upgrade fails if Content-Length incl (fixes #3063) | |||||
(thx daimh) | |||||
commit 903024d7 in lighttpd 1.4.57 fixed issue #3046 but in the process | |||||
broke HTTP/1.1 101 Switching Protocols which included Content-Length: 0 | |||||
in the response headers. Content-Length response header is permitted | |||||
by the RFCs, but not necessary with HTTP status 101 Switching Protocols. | |||||
x-ref: | |||||
"websocket proxy fails if 101 Switching Protocols from backend includes Content-Length" | |||||
https://redmine.lighttpd.net/issues/3063 | |||||
Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com> | |||||
--- | |||||
src/http-header-glue.c | 1 + | |||||
1 file changed, 1 insertion(+) | |||||
--- a/src/http-header-glue.c | |||||
+++ b/src/http-header-glue.c | |||||
@@ -961,6 +961,7 @@ void http_response_upgrade_read_body_unk | |||||
(FDEVENT_STREAM_RESPONSE_BUFMIN | FDEVENT_STREAM_RESPONSE); | |||||
r->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_POLLIN; | |||||
r->reqbody_length = -2; | |||||
+ r->resp_body_scratchpad = -1; | |||||
r->keep_alive = 0; | |||||
} | |||||
@ -1,143 +0,0 @@ | |||||
From 4a600dabd5e2799bf0c3048859ee4f00808b7d89 Mon Sep 17 00:00:00 2001 | |||||
From: Glenn Strauss <gstrauss@gluelogic.com> | |||||
Date: Sat, 6 Feb 2021 08:29:41 -0500 | |||||
Subject: [PATCH] [mod_auth] close HTTP/2 connection after bad pass | |||||
mitigation slows down brute force password attacks | |||||
x-ref: | |||||
"Possible feature: authentication brute force hardening" | |||||
https://redmine.lighttpd.net/boards/3/topics/8885 | |||||
Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com> | |||||
--- | |||||
src/connections.c | 22 +++++++++++++++++++++- | |||||
src/mod_accesslog.c | 2 +- | |||||
src/mod_auth.c | 6 +++--- | |||||
src/reqpool.c | 1 + | |||||
src/request.h | 2 +- | |||||
src/response.c | 4 ++-- | |||||
6 files changed, 29 insertions(+), 8 deletions(-) | |||||
--- a/src/connections.c | |||||
+++ b/src/connections.c | |||||
@@ -228,7 +228,7 @@ static void connection_handle_response_e | |||||
} | |||||
} | |||||
- if (r->keep_alive) { | |||||
+ if (r->keep_alive > 0) { | |||||
request_reset(r); | |||||
config_reset_config(r); | |||||
con->is_readable = 1; /* potentially trigger optimistic read */ | |||||
@@ -1265,6 +1265,19 @@ connection_set_fdevent_interest (request | |||||
} | |||||
+__attribute_cold__ | |||||
+static void | |||||
+connection_request_end_h2 (request_st * const h2r, connection * const con) | |||||
+{ | |||||
+ if (h2r->keep_alive >= 0) { | |||||
+ h2r->keep_alive = -1; | |||||
+ h2_send_goaway(con, H2_E_NO_ERROR); | |||||
+ } | |||||
+ else /*(abort connection upon second request to close h2 connection)*/ | |||||
+ h2_send_goaway(con, H2_E_ENHANCE_YOUR_CALM); | |||||
+} | |||||
+ | |||||
+ | |||||
static void | |||||
connection_state_machine_h2 (request_st * const h2r, connection * const con) | |||||
{ | |||||
@@ -1359,8 +1372,15 @@ connection_state_machine_h2 (request_st | |||||
&& !chunkqueue_is_empty(con->read_queue)) | |||||
resched |= 1; | |||||
h2_send_end_stream(r, con); | |||||
+ const int alive = r->keep_alive; | |||||
h2_retire_stream(r, con);/*r invalidated;removed from h2c->r[]*/ | |||||
--i;/* adjust loop i; h2c->rused was modified to retire r */ | |||||
+ /*(special-case: allow *stream* to set r->keep_alive = -1 to | |||||
+ * trigger goaway on h2 connection, e.g. after mod_auth failure | |||||
+ * in attempt to mitigate brute force attacks by forcing a | |||||
+ * reconnect and (somewhat) slowing down retries)*/ | |||||
+ if (alive < 0) | |||||
+ connection_request_end_h2(h2r, con); | |||||
} | |||||
} | |||||
} | |||||
--- a/src/mod_accesslog.c | |||||
+++ b/src/mod_accesslog.c | |||||
@@ -1108,7 +1108,7 @@ static int log_access_record (const requ | |||||
break; | |||||
case FORMAT_CONNECTION_STATUS: | |||||
if (r->state == CON_STATE_RESPONSE_END) { | |||||
- if (0 == r->keep_alive) { | |||||
+ if (r->keep_alive <= 0) { | |||||
buffer_append_string_len(b, CONST_STR_LEN("-")); | |||||
} else { | |||||
buffer_append_string_len(b, CONST_STR_LEN("+")); | |||||
--- a/src/mod_auth.c | |||||
+++ b/src/mod_auth.c | |||||
@@ -828,7 +828,7 @@ static handler_t mod_auth_check_basic(re | |||||
log_error(r->conf.errh, __FILE__, __LINE__, | |||||
"password doesn't match for %s username: %s IP: %s", | |||||
r->uri.path.ptr, username->ptr, r->con->dst_addr_buf->ptr); | |||||
- r->keep_alive = 0; /*(disable keep-alive if bad password)*/ | |||||
+ r->keep_alive = -1; /*(disable keep-alive if bad password)*/ | |||||
rc = HANDLER_UNSET; | |||||
break; | |||||
} | |||||
@@ -1461,7 +1461,7 @@ static handler_t mod_auth_check_digest(r | |||||
return HANDLER_FINISHED; | |||||
case HANDLER_ERROR: | |||||
default: | |||||
- r->keep_alive = 0; /*(disable keep-alive if unknown user)*/ | |||||
+ r->keep_alive = -1; /*(disable keep-alive if unknown user)*/ | |||||
buffer_free(b); | |||||
return mod_auth_send_401_unauthorized_digest(r, require, 0); | |||||
} | |||||
@@ -1482,7 +1482,7 @@ static handler_t mod_auth_check_digest(r | |||||
log_error(r->conf.errh, __FILE__, __LINE__, | |||||
"digest: auth failed for %s: wrong password, IP: %s", | |||||
username, r->con->dst_addr_buf->ptr); | |||||
- r->keep_alive = 0; /*(disable keep-alive if bad password)*/ | |||||
+ r->keep_alive = -1; /*(disable keep-alive if bad password)*/ | |||||
buffer_free(b); | |||||
return mod_auth_send_401_unauthorized_digest(r, require, 0); | |||||
--- a/src/reqpool.c | |||||
+++ b/src/reqpool.c | |||||
@@ -58,6 +58,7 @@ request_reset (request_st * const r) | |||||
http_response_reset(r); | |||||
r->loops_per_request = 0; | |||||
+ r->keep_alive = 0; | |||||
r->h2state = 0; /* H2_STATE_IDLE */ | |||||
r->h2id = 0; | |||||
--- a/src/request.h | |||||
+++ b/src/request.h | |||||
@@ -175,7 +175,7 @@ struct request_st { | |||||
char resp_header_repeated; | |||||
char loops_per_request; /* catch endless loops in a single request */ | |||||
- char keep_alive; /* only request.c can enable it, all other just disable */ | |||||
+ int8_t keep_alive; /* only request.c can enable it, all other just disable */ | |||||
char async_callback; | |||||
buffer *tmp_buf; /* shared; same as srv->tmp_buf */ | |||||
--- a/src/response.c | |||||
+++ b/src/response.c | |||||
@@ -103,9 +103,9 @@ http_response_write_header (request_st * | |||||
if (light_btst(r->resp_htags, HTTP_HEADER_UPGRADE) | |||||
&& r->http_version == HTTP_VERSION_1_1) { | |||||
http_header_response_set(r, HTTP_HEADER_CONNECTION, CONST_STR_LEN("Connection"), CONST_STR_LEN("upgrade")); | |||||
- } else if (0 == r->keep_alive) { | |||||
+ } else if (r->keep_alive <= 0) { | |||||
http_header_response_set(r, HTTP_HEADER_CONNECTION, CONST_STR_LEN("Connection"), CONST_STR_LEN("close")); | |||||
- } else if (r->http_version == HTTP_VERSION_1_0) {/*(&& r->keep_alive != 0)*/ | |||||
+ } else if (r->http_version == HTTP_VERSION_1_0) {/*(&& r->keep_alive > 0)*/ | |||||
http_header_response_set(r, HTTP_HEADER_CONNECTION, CONST_STR_LEN("Connection"), CONST_STR_LEN("keep-alive")); | |||||
} | |||||
@ -1,45 +0,0 @@ | |||||
From aa81834bc3ff47aa5cc66b6763678d3cf47a3d54 Mon Sep 17 00:00:00 2001 | |||||
From: Glenn Strauss <gstrauss@gluelogic.com> | |||||
Date: Fri, 12 Mar 2021 20:03:38 -0500 | |||||
Subject: [PATCH] [mod_openssl] skip cert chain build if self-issued | |||||
If cert is self-issued, then do not attempt to build certificate chain. | |||||
(Attempting to build certificate chain when chain is not provided, but | |||||
ssl.ca-file is specified, is provided as backward compatible behavior | |||||
from lighttpd versions prior to lighttpd 1.4.56) | |||||
Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com> | |||||
--- | |||||
src/mod_openssl.c | 6 +++++- | |||||
1 file changed, 5 insertions(+), 1 deletion(-) | |||||
--- a/src/mod_openssl.c | |||||
+++ b/src/mod_openssl.c | |||||
@@ -103,6 +103,7 @@ typedef struct { | |||||
time_t ssl_stapling_loadts; | |||||
time_t ssl_stapling_nextts; | |||||
char must_staple; | |||||
+ char self_issued; | |||||
} plugin_cert; | |||||
typedef struct { | |||||
@@ -1081,7 +1082,7 @@ mod_openssl_cert_cb (SSL *ssl, void *arg | |||||
#if !defined(BORINGSSL_API_VERSION) \ | |||||
&& !defined(LIBRESSL_VERSION_NUMBER) | |||||
/* (missing SSL_set1_chain_cert_store() and SSL_build_cert_chain()) */ | |||||
- else if (hctx->conf.ssl_ca_file) { | |||||
+ else if (hctx->conf.ssl_ca_file && !pc->self_issued) { | |||||
/* preserve legacy behavior whereby openssl will reuse CAs trusted for | |||||
* certificate verification (set by SSL_CTX_load_verify_locations() in | |||||
* SSL_CTX) in order to build certificate chain for server certificate | |||||
@@ -1671,6 +1672,9 @@ network_openssl_load_pemfile (server *sr | |||||
#else | |||||
pc->must_staple = 0; | |||||
#endif | |||||
+ pc->self_issued = | |||||
+ (0 == X509_NAME_cmp(X509_get_subject_name(ssl_pemfile_x509), | |||||
+ X509_get_issuer_name(ssl_pemfile_x509))); | |||||
if (!buffer_string_is_empty(pc->ssl_stapling_file)) { | |||||
#ifndef OPENSSL_NO_OCSP |
@ -1,27 +0,0 @@ | |||||
From c41ebea4bb220c8fe252f472eec836c691734690 Mon Sep 17 00:00:00 2001 | |||||
From: Glenn Strauss <gstrauss@gluelogic.com> | |||||
Date: Fri, 2 Apr 2021 01:01:02 -0400 | |||||
Subject: [PATCH] [build] fix zstd option in meson (fixes #3076) | |||||
(thx KimonHoffmann) | |||||
x-ref: | |||||
"Fix zstd dependency handling in meson build" | |||||
https://redmine.lighttpd.net/issues/3076 | |||||
Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com> | |||||
--- | |||||
src/meson.build | 2 +- | |||||
1 file changed, 1 insertion(+), 1 deletion(-) | |||||
--- a/src/meson.build | |||||
+++ b/src/meson.build | |||||
@@ -685,7 +685,7 @@ endif | |||||
libzstd = [] | |||||
if get_option('with_zstd') | |||||
- libz = dependency('zstd', required: false) | |||||
+ libzstd = dependency('zstd', required: false) | |||||
if libzstd.found() | |||||
libzstd = [ libzstd ] | |||||
else |
@ -1,56 +0,0 @@ | |||||
From 3392e8fb11de35778cad1fb112e6eb5916aa7de0 Mon Sep 17 00:00:00 2001 | |||||
From: Glenn Strauss <gstrauss@gluelogic.com> | |||||
Date: Tue, 20 Apr 2021 22:04:56 -0400 | |||||
Subject: [PATCH] [core] update ls-hpack | |||||
LiteSpeed ls-hpack v2.3.0 | |||||
Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com> | |||||
--- | |||||
src/ls-hpack/README.md | 2 +- | |||||
src/ls-hpack/lshpack.c | 4 +++- | |||||
src/ls-hpack/lshpack.h | 6 +++--- | |||||
3 files changed, 7 insertions(+), 5 deletions(-) | |||||
--- a/src/ls-hpack/lshpack.c | |||||
+++ b/src/ls-hpack/lshpack.c | |||||
@@ -1,7 +1,7 @@ | |||||
/* | |||||
MIT License | |||||
-Copyright (c) 2018 LiteSpeed Technologies Inc | |||||
+Copyright (c) 2018 - 2021 LiteSpeed Technologies Inc | |||||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
of this software and associated documentation files (the "Software"), to deal | |||||
@@ -1549,6 +1549,8 @@ lshpack_dec_push_entry (struct lshpack_d | |||||
#endif | |||||
memcpy(DTE_NAME(entry), lsxpack_header_get_name(xhdr), name_len); | |||||
memcpy(DTE_VALUE(entry), lsxpack_header_get_value(xhdr), val_len); | |||||
+ | |||||
+ hdec_remove_overflow_entries(dec); | |||||
return 0; | |||||
} | |||||
--- a/src/ls-hpack/lshpack.h | |||||
+++ b/src/ls-hpack/lshpack.h | |||||
@@ -1,7 +1,7 @@ | |||||
/* | |||||
MIT License | |||||
-Copyright (c) 2018 - 2020 LiteSpeed Technologies Inc | |||||
+Copyright (c) 2018 - 2021 LiteSpeed Technologies Inc | |||||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
of this software and associated documentation files (the "Software"), to deal | |||||
@@ -34,8 +34,8 @@ extern "C" { | |||||
#include "lsxpack_header.h" | |||||
#define LSHPACK_MAJOR_VERSION 2 | |||||
-#define LSHPACK_MINOR_VERSION 2 | |||||
-#define LSHPACK_PATCH_VERSION 1 | |||||
+#define LSHPACK_MINOR_VERSION 3 | |||||
+#define LSHPACK_PATCH_VERSION 0 | |||||
#define lshpack_strlen_t lsxpack_strlen_t | |||||
#define LSHPACK_MAX_STRLEN LSXPACK_MAX_STRLEN |
@ -1,145 +0,0 @@ | |||||
From 81d18a8e359685c169cfd30e6a1574b98aedbaeb Mon Sep 17 00:00:00 2001 | |||||
From: Glenn Strauss <gstrauss@gluelogic.com> | |||||
Date: Thu, 22 Apr 2021 01:11:47 -0400 | |||||
Subject: [PATCH] [core] discard some HTTP/2 DATA after response (fixes #3078) | |||||
(thx oldium) | |||||
improve handling of HTTP/2 DATA frames received | |||||
a short time after sending response | |||||
x-ref: | |||||
"POST request DATA part for non-existing URI closes HTTP/2 connection prematurely" | |||||
https://redmine.lighttpd.net/issues/3078 | |||||
Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com> | |||||
--- | |||||
src/h2.c | 64 ++++++++++++++++++++++++++++++++++++++++++-------------- | |||||
src/h2.h | 1 + | |||||
2 files changed, 49 insertions(+), 16 deletions(-) | |||||
--- a/src/h2.c | |||||
+++ b/src/h2.c | |||||
@@ -272,10 +272,23 @@ h2_send_rst_stream_id (uint32_t h2id, co | |||||
__attribute_cold__ | |||||
static void | |||||
-h2_send_rst_stream (request_st * const r, connection * const con, const request_h2error_t e) | |||||
+h2_send_rst_stream_state (request_st * const r, h2con * const h2c) | |||||
{ | |||||
+ if (r->h2state != H2_STATE_HALF_CLOSED_REMOTE | |||||
+ && r->h2state != H2_STATE_CLOSED) { | |||||
+ /* set timestamp for comparison; not tracking individual stream ids */ | |||||
+ h2c->half_closed_ts = log_epoch_secs; | |||||
+ } | |||||
r->state = CON_STATE_ERROR; | |||||
r->h2state = H2_STATE_CLOSED; | |||||
+} | |||||
+ | |||||
+ | |||||
+__attribute_cold__ | |||||
+static void | |||||
+h2_send_rst_stream (request_st * const r, connection * const con, const request_h2error_t e) | |||||
+{ | |||||
+ h2_send_rst_stream_state(r, con->h2);/*(sets r->h2state = H2_STATE_CLOSED)*/ | |||||
h2_send_rst_stream_id(r->h2id, con, e); | |||||
} | |||||
@@ -289,13 +302,10 @@ h2_send_goaway_rst_stream (connection * | |||||
for (uint32_t i = 0, rused = h2c->rused; i < rused; ++i) { | |||||
request_st * const r = h2c->r[i]; | |||||
if (r->h2state == H2_STATE_CLOSED) continue; | |||||
+ h2_send_rst_stream_state(r, h2c);/*(sets r->h2state = H2_STATE_CLOSED)*/ | |||||
/*(XXX: might consider always sending RST_STREAM)*/ | |||||
- if (!sent_goaway) { | |||||
- r->state = CON_STATE_ERROR; | |||||
- r->h2state = H2_STATE_CLOSED; | |||||
- } | |||||
- else /*(also sets r->h2state = H2_STATE_CLOSED)*/ | |||||
- h2_send_rst_stream(r, con, H2_E_PROTOCOL_ERROR); | |||||
+ if (sent_goaway) | |||||
+ h2_send_rst_stream_id(r->h2id, con, H2_E_PROTOCOL_ERROR); | |||||
} | |||||
} | |||||
@@ -780,14 +790,27 @@ h2_recv_data (connection * const con, co | |||||
} | |||||
chunkqueue * const cq = con->read_queue; | |||||
if (NULL == r) { | |||||
- /* XXX: TODO: might need to keep a list of recently retired streams | |||||
- * for a few seconds so that if we send RST_STREAM, then we ignore | |||||
- * further DATA and do not send connection error, though recv windows | |||||
- * still must be updated. */ | |||||
- if (h2c->h2_cid < id || (!h2c->sent_goaway && 0 != alen)) | |||||
- h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR); | |||||
+ /* simplistic heuristic to discard additional DATA from recently-closed | |||||
+ * streams (or half-closed (local)), where recently-closed here is | |||||
+ * within 2-3 seconds of any (other) stream being half-closed (local) | |||||
+ * or reset before that (other) stream received END_STREAM from peer. | |||||
+ * (e.g. clients might fire off POST request followed by DATA, | |||||
+ * and a response might be sent before processing DATA frames) | |||||
+ * (id <= h2c->h2_cid) already checked above, else H2_E_PROTOCOL_ERROR | |||||
+ * If the above conditions do not hold, then send GOAWAY to attempt to | |||||
+ * reduce the chance of becoming an infinite data sink for misbehaving | |||||
+ * clients, though remaining streams are still handled before the | |||||
+ * connection is closed. */ | |||||
chunkqueue_mark_written(cq, 9+len); | |||||
- return 0; | |||||
+ if (h2c->half_closed_ts + 2 >= log_epoch_secs) { | |||||
+ h2_send_window_update(con, 0, len); /*(h2r->h2_rwin)*/ | |||||
+ return 1; | |||||
+ } | |||||
+ else { | |||||
+ if (!h2c->sent_goaway && 0 != alen) | |||||
+ h2_send_goaway_e(con, H2_E_NO_ERROR); | |||||
+ return 0; | |||||
+ } | |||||
} | |||||
if (r->h2state == H2_STATE_CLOSED | |||||
@@ -808,7 +831,7 @@ h2_recv_data (connection * const con, co | |||||
} | |||||
} | |||||
/*(allow h2r->h2_rwin to dip below 0 so that entire frame is processed)*/ | |||||
- /*(undeflow will not occur (with reasonable SETTINGS_MAX_FRAME_SIZE used) | |||||
+ /*(underflow will not occur (with reasonable SETTINGS_MAX_FRAME_SIZE used) | |||||
* since windows updated elsewhere and data is streamed to temp files if | |||||
* not FDEVENT_STREAM_REQUEST_BUFMIN)*/ | |||||
/*r->h2_rwin -= (int32_t)len;*/ | |||||
@@ -2347,16 +2370,25 @@ h2_send_end_stream_data (request_st * co | |||||
} }; | |||||
dataframe.u[2] = htonl(r->h2id); | |||||
- r->h2state = H2_STATE_CLOSED; | |||||
/*(ignore window updates when sending 0-length DATA frame with END_STREAM)*/ | |||||
chunkqueue_append_mem(con->write_queue, /*(+3 to skip over align pad)*/ | |||||
(const char *)dataframe.c+3, sizeof(dataframe)-3); | |||||
+ | |||||
+ if (r->h2state != H2_STATE_HALF_CLOSED_REMOTE) { | |||||
+ /* set timestamp for comparison; not tracking individual stream ids */ | |||||
+ h2con * const h2c = con->h2; | |||||
+ h2c->half_closed_ts = log_epoch_secs; | |||||
+ /* indicate to peer that no more DATA should be sent from peer */ | |||||
+ h2_send_rst_stream_id(r->h2id, con, H2_E_NO_ERROR); | |||||
+ } | |||||
+ r->h2state = H2_STATE_CLOSED; | |||||
} | |||||
void | |||||
h2_send_end_stream (request_st * const r, connection * const con) | |||||
{ | |||||
+ if (r->h2state == H2_STATE_CLOSED) return; | |||||
if (r->state != CON_STATE_ERROR && r->resp_body_finished) { | |||||
/* CON_STATE_RESPONSE_END */ | |||||
if (r->gw_dechunk && r->gw_dechunk->done | |||||
--- a/src/h2.h | |||||
+++ b/src/h2.h | |||||
@@ -92,6 +92,7 @@ struct h2con { | |||||
uint32_t s_max_header_list_size; /* SETTINGS_MAX_HEADER_LIST_SIZE */ | |||||
struct lshpack_dec decoder; | |||||
struct lshpack_enc encoder; | |||||
+ time_t half_closed_ts; | |||||
}; | |||||
void h2_send_goaway (connection *con, request_h2error_t e); |