Changes with Apache 2.4.21
+ *) mod_http2: fixed a write after free when streams/connections
+ were aborted before tasks returned. [Stefan Eissing]
+
*) mod_ssl: Correct the interaction between SSLProxyCheckPeerCN and newer
SSLProxyCheckPeerName directives since release 2.4.5, such that disabling
either disables both, and that enabling either triggers the new, more
h2_stream **pstream = data;
if (*pstream) {
- /*
- * If bucket_destroy is called after us, this prevents
- * bucket_destroy from trying to destroy the pool again.
- */
+ /* If bucket_destroy is called after us, this prevents
+ * bucket_destroy from trying to destroy the stream again. */
*pstream = NULL;
}
return APR_SUCCESS;
if (apr_bucket_shared_destroy(h)) {
h2_stream *stream = h->stream;
+ if (stream && stream->pool) {
+ apr_pool_cleanup_kill(stream->pool, &h->stream, bucket_cleanup);
+ }
+ apr_bucket_free(h);
if (stream) {
h2_stream_eos_destroy(stream);
}
- apr_bucket_free(h);
}
}
h2_ihash_remove(m->spurge, stream->id);
h2_stream_destroy(stream);
if (task) {
- task_destroy(m, task, 1);
+ task_destroy(m, task, 0);
}
return 0;
}
ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, m->c,
"h2_task(%s): destroy", task->id);
/* cleanup any buffered input */
- status = h2_task_shutdown(task, 0);
- if (status != APR_SUCCESS){
- ap_log_cerror(APLOG_MARK, APLOG_WARNING, status, m->c, APLOGNO(03385)
- "h2_task(%s): shutdown", task->id);
+ if (task->input.beam) {
+ status = h2_beam_shutdown(task->input.beam, APR_NONBLOCK_READ);
+ if (status != APR_SUCCESS){
+ ap_log_cerror(APLOG_MARK, APLOG_WARNING, status, m->c, APLOGNO(03385)
+ "h2_task(%s): input shutdown", task->id);
+ }
}
if (called_from_master) {
if (rst_error) {
h2_task_rst(task, rst_error);
}
- /* FIXME: this should work, but does not
h2_ihash_add(m->shold, stream);
- return;*/
- task->input.beam = NULL;
+ return;
}
else {
/* already finished */
if (task->c) {
task->c->aborted = 1;
}
+ if (task->input.beam) {
+ h2_beam_abort(task->input.beam);
+ }
+ if (task->output.beam) {
+ h2_beam_abort(task->output.beam);
+ }
return 1;
}
AP_DEBUG_ASSERT(h2_ihash_empty(m->shold));
if (!h2_ihash_empty(m->spurge)) {
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
- "h2_mplx(%ld): release_join %d streams to purge",
+ "h2_mplx(%ld): 3. release_join %d streams to purge",
m->id, (int)h2_ihash_count(m->spurge));
purge_streams(m);
}
* parent pool / allocator) */
h2_ihash_remove(m->shold, stream->id);
h2_ihash_add(m->spurge, stream);
+ task_destroy(m, task, 0);
}
else {
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
void h2_stream_eos_destroy(h2_stream *stream)
{
h2_session_stream_done(stream->session, stream);
- /* stream is gone */
+ /* stream possibly destroyed */
}
apr_pool_t *h2_stream_detach_pool(h2_stream *stream)
{
apr_status_t status = APR_SUCCESS;
apr_bucket_brigade *bb = task->input.bb;
- apr_table_t *t = task->request->trailers;
+ apr_table_t *t = task->request? task->request->trailers : NULL;
if (task->input.chunked) {
task->input.tmp = apr_brigade_split_ex(bb, b, task->input.tmp);
{
apr_status_t status = APR_SUCCESS;
apr_bucket_brigade *bb = task->input.bb;
- apr_table_t *t = task->request->trailers;
+ apr_table_t *t = task->request? task->request->trailers : NULL;
if (task->input.chunked) {
if (t && !apr_is_empty_table(t)) {
return ap_get_brigade(f->c->input_filters, bb, mode, block, readbytes);
}
- if (f->c->aborted) {
+ if (f->c->aborted || !task->request) {
return APR_ECONNABORTED;
}
if (!task->input.bb) {
if (!task->input.eos_written) {
input_append_eos(task, f->r);
+ return APR_SUCCESS;
}
return APR_EOF;
}
}
}
- while (APR_BRIGADE_EMPTY(task->input.bb)) {
- if (task->input.eos_written) {
- return APR_EOF;
- }
-
+ while (APR_BRIGADE_EMPTY(task->input.bb) && !task->input.eos) {
/* Get more input data for our request. */
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, f->c,
"h2_task(%s): get more data from mplx, block=%d, "
status = APR_EOF;
}
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, f->c,
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, f->c,
"h2_task(%s): read returned", task->id);
if (APR_STATUS_IS_EAGAIN(status)
&& (mode == AP_MODE_GETLINE || block == APR_BLOCK_READ)) {
* upload 100k test on test-ser.example.org hangs */
status = APR_SUCCESS;
}
- else if (APR_STATUS_IS_EOF(status) && !task->input.eos_written) {
+ else if (APR_STATUS_IS_EOF(status)) {
task->input.eos = 1;
}
else if (status != APR_SUCCESS) {
}
}
- if (!task->input.eos_written && task->input.eos) {
- input_append_eos(task, f->r);
+ if (task->input.eos) {
+ if (!task->input.eos_written) {
+ input_append_eos(task, f->r);
+ }
+ if (APR_BRIGADE_EMPTY(task->input.bb)) {
+ return APR_EOF;
+ }
}
h2_util_bb_log(f->c, task->stream_id, APLOG_TRACE2,
}
}
-apr_status_t h2_task_shutdown(h2_task *task, int block)
-{
- if (task->output.beam) {
- apr_status_t status;
- status = h2_beam_shutdown(task->output.beam, APR_NONBLOCK_READ);
- if (block && status == APR_EAGAIN) {
- ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, task->c,
- "h2_task(%s): output shutdown waiting", task->id);
- status = h2_beam_shutdown(task->output.beam, APR_BLOCK_READ);
- ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, task->c,
- "h2_task(%s): output shutdown done", task->id);
- }
- return status;
- }
- return APR_SUCCESS;
-}
-
/*******************************************************************************
* Register various hooks
*/
*/
void h2_task_rst(h2_task *task, int error);
-/**
- * Shuts all input/output down. Clears any buckets buffered and closes.
- */
-apr_status_t h2_task_shutdown(h2_task *task, int block);
-
void h2_task_register_hooks(void);
/*
* One time, post config intialization.
* @macro
* Version number of the http2 module as c string
*/
-#define MOD_HTTP2_VERSION "1.5.6"
+#define MOD_HTTP2_VERSION "1.5.7"
/**
* @macro
* release. This is a 24 bit number with 8 bits for major number, 8 bits
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
*/
-#define MOD_HTTP2_VERSION_NUM 0x010506
+#define MOD_HTTP2_VERSION_NUM 0x010507
#endif /* mod_h2_h2_version_h */