Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

H2 backports 2.4.58 #364

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions changes-entries/h2_early_hints_and_fixes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
*) mod_http2: v2.0.15 with the following fixes and improvements
- New directive 'H2EarlyHint name value' to add headers to a response,
picked up already when a "103 Early Hints" response is sent. 'name' and
'value' must comply to the HTTP field restrictions.
This directive can be repeated several times and header fields of the
same names add. Sending a 'Link' header with 'preload' relation will
also cause a HTTP/2 PUSH if enabled and supported by the client.
- Fixed an issue where requests were not logged and accounted in a timely
fashion when the connection returns to "keepalive" handling, e.g. when
the request served was the last outstanding one.
This led to late appearance in access logs with wrong duration times
reported.
- Accurately report the bytes sent for a request in the '%O' Log format.
This addresses #203, a long outstanding issue where mod_h2 has reported
numbers over-eagerly from internal buffering and not what has actually
been placed on the connection.
The numbers are now the same with and without H2CopyFiles enabled.
[Stefan Eissing]
4 changes: 4 additions & 0 deletions changes-entries/h2_flush_fix.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*) mod_http2: fixed a bug in flushing pending data on an already closed
connection that could lead to a busy loop, preventing the HTTP/2 session
to close down successfully. Fixed PR 66624.
[Stefan Eissing]
7 changes: 7 additions & 0 deletions changes-entries/h2_max_data_frame_len.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
*) mod_http2: new directive 'H2MaxDataFrameLen n' to limit the maximum
amount of response body bytes put into a single HTTP/2 DATA frame.
Setting this to 0 places no limit (but the max size allowed by the
protocol is observed).
The module, by default, tries to use the maximum size possible, which is
somewhat around 16KB. This sets the maximum. When less response data is
available, smaller frames will be sent.
6 changes: 6 additions & 0 deletions changes-entries/h2_pr66646.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*) mod_http2: fixed a bug that could lead to a crash in main connection
output handling. This occured only when the last request on a HTTP/2
connection had been processed and the session decided to shut down.
This could lead to an attempt to send a final GOAWAY while the previous
write was still in progress. See PR 66646.
[Stefan Eissing]
13 changes: 13 additions & 0 deletions changes-entries/h2_v2.0.18.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
* mod_proxy_http2: fixed using the wrong "bucket_alloc" from the backend
connection when sending data on the frontend one. This caused crashes
or infinite loops in rare situations.
* mod_proxy_http2: fixed a bug in retry/response handling that could lead
to wrong status codes or HTTP messages send at the end of response bodies
exceeding the announced content-length.
* mod_proxy_http2: fix retry handling to not leak temporary errors.
On detecting that that an existing connection was shutdown by the other
side, a 503 response leaked even though the request was retried on a
fresh connection.
* mod_http2: fixed a bug that did cleanup of consumed and pending buckets in
the wrong order when a bucket_beam was destroyed.
[Stefan Eissing]
78 changes: 78 additions & 0 deletions docs/manual/mod/mod_http2.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1002,4 +1002,82 @@ H2TLSCoolDownSecs 0
</usage>
</directivesynopsis>

<directivesynopsis>
<name>H2StreamTimeout</name>
<description>Maximum time waiting when sending/receiving data to stream processing</description>
<syntax>H2StreamTimeout <var>time-interval</var>[s]</syntax>
<default>Value of <directive module="core">Timeout</directive></default>
<contextlist>
<context>server config</context>
<context>virtual host</context>
<context>directory</context>
</contextlist>
<compatibility>Available in version 2.5.1 and later.</compatibility>

<usage>
<p>
<directive>H2StreamTimeout</directive> specifies the maximum time that
a stream being processed will wait for its data to be sent/received.
</p>
</usage>
</directivesynopsis>

<directivesynopsis>
<name>H2MaxDataFrameLen</name>
<description>Maximum bytes inside a single HTTP/2 DATA frame</description>
<syntax>H2MaxDataFrameLen <em>n</em></syntax>
<default>H2MaxDataFrameLen 0</default>
<contextlist>
<context>server config</context>
<context>virtual host</context>
</contextlist>
<compatibility>Available in version 2.5.1 and later.</compatibility>

<usage>
<p>
<directive>H2MaxDataFrameLen</directive> limits the maximum
amount of response body bytes placed into a single HTTP/2 DATA
frame. Setting this to 0 places no limit (but the max size
allowed by the protocol is observed).
</p><p>
The module, by default, tries to use the maximum size possible,
which is somewhat around 16KB. This sets the maximum. When less
response data is availble, smaller frames will be sent.
</p>
</usage>
</directivesynopsis>

<directivesynopsis>
<name>H2EarlyHint</name>
<description>Add a response header to be picked up in 103 Early Hints</description>
<syntax>H2EarlyHint <em>name</em> <em>value</em></syntax>
<contextlist>
<context>server config</context>
<context>virtual host</context>
<context>directory</context>
<context>.htaccess</context>
</contextlist>
<compatibility>Available in version 2.5.1 and later.</compatibility>

<usage>
<p>
<directive>H2EarlyHint</directive> allows adding a response
header before the real request processing is started. Such headers
are picked up for "103 Early Hints" intermediate responses. The main
purpose is to send "preload" information to client browsers.
</p><p>
<em>name</em> and <em>value</em> must be valid HTTP header fields
or will lead to failed responses. <directive>H2EarlyHints</directive>
must still be enabled to allow 103 intermediate responses to be sent.
This directive can be repeated several times and header fields of the
same names add.
</p>
<example><title>Example</title>
<highlight language="config">
H2EarlyHint Link "&lt;/my.css&gt;;rel=preload;as=style"
</highlight>
</example>
</usage>
</directivesynopsis>

</modulesynopsis>
25 changes: 24 additions & 1 deletion modules/http2/h2_bucket_beam.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#include <httpd.h>
#include <http_protocol.h>
#include <http_request.h>
#include <http_log.h>

#include "h2_private.h"
Expand Down Expand Up @@ -156,6 +157,23 @@ static void purge_consumed_buckets(h2_bucket_beam *beam)
* from sender thread only */
while (!H2_BLIST_EMPTY(&beam->buckets_consumed)) {
b = H2_BLIST_FIRST(&beam->buckets_consumed);
if(AP_BUCKET_IS_EOR(b)) {
APR_BUCKET_REMOVE(b);
H2_BLIST_INSERT_TAIL(&beam->buckets_eor, b);
}
else {
apr_bucket_delete(b);
}
}
}

static void purge_eor_buckets(h2_bucket_beam *beam)
{
apr_bucket *b;
/* delete all sender buckets in purge brigade, needs to be called
* from sender thread only */
while (!H2_BLIST_EMPTY(&beam->buckets_eor)) {
b = H2_BLIST_FIRST(&beam->buckets_eor);
apr_bucket_delete(b);
}
}
Expand Down Expand Up @@ -254,15 +272,16 @@ static void beam_shutdown(h2_bucket_beam *beam, apr_shutdown_how_e how)

/* shutdown sender (or both)? */
if (how != APR_SHUTDOWN_READ) {
h2_blist_cleanup(&beam->buckets_to_send);
purge_consumed_buckets(beam);
h2_blist_cleanup(&beam->buckets_to_send);
}
}

static apr_status_t beam_cleanup(void *data)
{
h2_bucket_beam *beam = data;
beam_shutdown(beam, APR_SHUTDOWN_READWRITE);
purge_eor_buckets(beam);
beam->pool = NULL; /* the pool is clearing now */
return APR_SUCCESS;
}
Expand Down Expand Up @@ -295,6 +314,7 @@ apr_status_t h2_beam_create(h2_bucket_beam **pbeam, conn_rec *from,

H2_BLIST_INIT(&beam->buckets_to_send);
H2_BLIST_INIT(&beam->buckets_consumed);
H2_BLIST_INIT(&beam->buckets_eor);
beam->tx_mem_limits = 1;
beam->max_buf_size = max_buf_size;
beam->timeout = timeout;
Expand Down Expand Up @@ -565,6 +585,9 @@ apr_status_t h2_beam_send(h2_bucket_beam *beam, conn_rec *from,
rv = APR_ECONNABORTED;
}
H2_BEAM_LOG(beam, from, APLOG_TRACE2, rv, "end send", sender_bb);
if(rv != APR_SUCCESS && !APR_STATUS_IS_EAGAIN(rv) && sender_bb != NULL) {
apr_brigade_cleanup(sender_bb);
}
apr_thread_mutex_unlock(beam->lock);
return rv;
}
Expand Down
1 change: 1 addition & 0 deletions modules/http2/h2_bucket_beam.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ struct h2_bucket_beam {
apr_pool_t *pool;
h2_blist buckets_to_send;
h2_blist buckets_consumed;
h2_blist buckets_eor;

apr_size_t max_buf_size;
apr_interval_time_t timeout;
Expand Down
28 changes: 21 additions & 7 deletions modules/http2/h2_c1_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,9 +260,22 @@ static apr_status_t read_to_scratch(h2_c1_io *io, apr_bucket *b)
static apr_status_t pass_output(h2_c1_io *io, int flush)
{
conn_rec *c = io->session->c1;
apr_off_t bblen;
apr_off_t bblen = 0;
apr_status_t rv;


if (io->is_passing) {
/* recursive call, may be triggered by an H2EOS bucket
* being destroyed and triggering sending more data? */
AP_DEBUG_ASSERT(0);
ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(10456)
"h2_c1_io(%ld): recursive call of h2_c1_io_pass. "
"Denied to prevent output corruption. This "
"points to a bug in the HTTP/2 implementation.",
c->id);
return APR_EGENERAL;
}
io->is_passing = 1;

append_scratch(io);
if (flush) {
if (!APR_BUCKET_IS_FLUSH(APR_BRIGADE_LAST(io->output))) {
Expand All @@ -271,17 +284,16 @@ static apr_status_t pass_output(h2_c1_io *io, int flush)
}
}
if (APR_BRIGADE_EMPTY(io->output)) {
return APR_SUCCESS;
rv = APR_SUCCESS;
goto cleanup;
}

io->unflushed = !APR_BUCKET_IS_FLUSH(APR_BRIGADE_LAST(io->output));
apr_brigade_length(io->output, 0, &bblen);
C1_IO_BB_LOG(c, 0, APLOG_TRACE2, "out", io->output);

rv = ap_pass_brigade(c->output_filters, io->output);
if (APR_SUCCESS != rv) goto cleanup;

io->buffered_len = 0;
io->bytes_written += (apr_size_t)bblen;

if (io->write_size < WRITE_SIZE_MAX
Expand Down Expand Up @@ -309,6 +321,8 @@ static apr_status_t pass_output(h2_c1_io *io, int flush)
c->id, (long)bblen);
}
apr_brigade_cleanup(io->output);
io->buffered_len = 0;
io->is_passing = 0;
return rv;
}

Expand Down
3 changes: 2 additions & 1 deletion modules/http2/h2_c1_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ typedef struct {
apr_off_t buffered_len;
apr_off_t flush_threshold;
unsigned int is_flushed : 1;

unsigned int is_passing : 1;

char *scratch;
apr_size_t ssize;
apr_size_t slen;
Expand Down
Loading