[core] refuse excess h2 streams at con start (fixes #3093)

refuse excess h2 streams up to stream id 199 within 1-2 seconds of
establishing connection.  This attempts to more gracefully handle
excessively agressive browsers sending too many new requests *before*
processing the initial SETTINGS frame sent by the server.

lighttpd HTTP/2 support limits SETTINGS_MAX_CONCURRENT_STREAMS to 8
and communicates this in the initial SETTINGS sent by the server.

x-ref:
  "Chrome 92, HTTP/2, fcgi, mutiple puts no response"
  https://redmine.lighttpd.net/issues/3093
  "POST request DATA part for non-existing URI closes HTTP/2 connection prematurely"
  https://redmine.lighttpd.net/issues/3078
personal/stbuehler/tests-path
Glenn Strauss 2021-08-12 05:05:20 -04:00
parent aa1027ba24
commit c82ca970fb
1 changed files with 26 additions and 17 deletions

View File

@ -407,6 +407,30 @@ h2_send_goaway_e (connection * const con, const request_h2error_t e)
}
__attribute_cold__
static int
h2_send_refused_stream (uint32_t h2id, connection * const con)
{
h2con * const h2c = con->h2;
if (0 == h2c->sent_settings /*(see h2_recv_settings() comments)*/
|| (h2id < 200 && log_monotonic_secs - con->connection_start < 2)) {
/* too many active streams; refuse new stream */
h2c->h2_cid = h2id;
h2_send_rst_stream_id(h2id, con, H2_E_REFUSED_STREAM);
return 1;
}
else {
/* alternative: stop processing frames and defer processing this
* HEADERS frame until num active streams drops below limit.
* lighttpd sends SETTINGS_MAX_CONCURRENT_STREAMS <limit> with
* server Connection Preface, so a well-behaved client will
* adjust after it sends its initial requests.
* (e.g. h2load -n 100 -m 100 sends 100 requests upon connect)*/
return -1;
}
}
static int
h2_recv_goaway (connection * const con, const uint8_t * const s, uint32_t len)
{
@ -1315,23 +1339,8 @@ h2_recv_headers (connection * const con, uint8_t * const s, uint32_t flen)
int trailers = 0;
if (id > h2c->h2_cid) {
if (h2c->rused == sizeof(h2c->r)/sizeof(*h2c->r)) {
if (0 == h2c->sent_settings) { /*(see h2_recv_settings() comments)*/
/* too many active streams; refuse new stream */
h2c->h2_cid = id;
h2_send_rst_stream_id(id, con, H2_E_REFUSED_STREAM);
return 1;
}
else {
/* alternative: stop processing frames and defer processing this
* HEADERS frame until num active streams drops below limit.
* lighttpd sends SETTINGS_MAX_CONCURRENT_STREAMS <limit> with
* server Connection Preface, so a well-behaved client will
* adjust after it sends its initial requests.
* (e.g. h2load -n 100 -m 100 sends 100 requests upon connect)*/
return -1;
}
}
if (h2c->rused == sizeof(h2c->r)/sizeof(*h2c->r))
return h2_send_refused_stream(id, con);
/* Note: MUST process HPACK decode even if already sent GOAWAY.
* This is necessary since there may be active streams not in
* H2_STATE_HALF_CLOSED_REMOTE, e.g. H2_STATE_OPEN, still possibly