Loading CHANGES +11 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,17 @@ Changes with Apache 2.4.21 *) mod_http2: Fix async write issue that led to selection of wrong timeout vs. keepalive timeout selection for idle sessions. [Stefan Eissing] *) mod_http2: checking LimitRequestLine, LimitRequestFields and LimitRequestFieldSize configurated values for incoming streams. Returning HTTP status 431 for too long/many headers fields and 414 for a too long pseudo header. [Stefan Eissing] *) mod_http2: tracking conn_rec->current_thread on slave connections, so that mod_lua finds the correct one. Fixes PR 59542. [Stefan Eissing] *) mod_proxy_http2: new experimental http2 proxy module for h2: and h2c: proxy urls. Part of the httpd mod_proxy framework, common settings apply. Requests from the same HTTP/2 frontend connection against the same backend Loading modules/http2/NWGNUmod_http2 +1 −0 Original line number Diff line number Diff line Loading @@ -355,6 +355,7 @@ $(OBJDIR)/mod_http2.imp : NWGNUmod_http2 @echo $(DL)GEN $@$(DL) @echo $(DL) (HTTP2)$(DL) > $@ @echo $(DL) http2_module,$(DL) >> $@ @echo $(DL) h2_casecmpstrn,$(DL) >> $@ @echo $(DL) h2_ihash_add,$(DL) >> $@ @echo $(DL) h2_ihash_clear,$(DL) >> $@ @echo $(DL) h2_ihash_count,$(DL) >> $@ Loading modules/http2/h2_from_h1.c +13 −8 Original line number Diff line number Diff line Loading @@ -291,7 +291,8 @@ static void fix_vary(request_rec *r) } } static void set_basic_http_header(request_rec *r, apr_table_t *headers) void h2_from_h1_set_basic_http_header(apr_table_t *headers, request_rec *r, apr_pool_t *pool) { char *date = NULL; const char *proxy_date = NULL; Loading @@ -302,7 +303,7 @@ static void set_basic_http_header(request_rec *r, apr_table_t *headers) * keep the set-by-proxy server and date headers, otherwise * generate a new server header / date header */ if (r->proxyreq != PROXYREQ_NONE) { if (r && r->proxyreq != PROXYREQ_NONE) { proxy_date = apr_table_get(r->headers_out, "Date"); if (!proxy_date) { /* Loading @@ -310,27 +311,31 @@ static void set_basic_http_header(request_rec *r, apr_table_t *headers) * our own Date header and pass it over to proxy_date later to * avoid a compiler warning. */ date = apr_palloc(r->pool, APR_RFC822_DATE_LEN); date = apr_palloc(pool, APR_RFC822_DATE_LEN); ap_recent_rfc822_date(date, r->request_time); } server = apr_table_get(r->headers_out, "Server"); } else { date = apr_palloc(r->pool, APR_RFC822_DATE_LEN); ap_recent_rfc822_date(date, r->request_time); date = apr_palloc(pool, APR_RFC822_DATE_LEN); ap_recent_rfc822_date(date, r? r->request_time : apr_time_now()); } apr_table_setn(headers, "Date", proxy_date ? proxy_date : date ); if (r) { apr_table_unset(r->headers_out, "Date"); } if (!server && *us) { server = us; } if (server) { apr_table_setn(headers, "Server", server); if (r) { apr_table_unset(r->headers_out, "Server"); } } } static int copy_header(void *ctx, const char *name, const char *value) { Loading Loading @@ -445,7 +450,7 @@ static h2_response *create_response(h2_from_h1 *from_h1, request_rec *r) headers = apr_table_make(r->pool, 10); set_basic_http_header(r, headers); h2_from_h1_set_basic_http_header(headers, r, r->pool); if (r->status == HTTP_NOT_MODIFIED) { apr_table_do((int (*)(void *, const char *, const char *)) copy_header, (void *) headers, r->headers_out, Loading modules/http2/h2_from_h1.h +3 −0 Original line number Diff line number Diff line Loading @@ -69,4 +69,7 @@ apr_status_t h2_response_output_filter(ap_filter_t *f, apr_bucket_brigade *bb); apr_status_t h2_response_trailers_filter(ap_filter_t *f, apr_bucket_brigade *bb); void h2_from_h1_set_basic_http_header(apr_table_t *headers, request_rec *r, apr_pool_t *pool); #endif /* defined(__mod_h2__h2_from_h1__) */ modules/http2/h2_mplx.c +22 −40 Original line number Diff line number Diff line Loading @@ -282,11 +282,11 @@ h2_mplx *h2_mplx_create(conn_rec *c, apr_pool_t *parent, m->stream_max_mem = h2_config_geti(conf, H2_CONF_STREAM_MAX_MEM); m->streams = h2_ihash_create(m->pool, offsetof(h2_stream,id)); m->sready = h2_ihash_create(m->pool, offsetof(h2_stream,id)); m->shold = h2_ihash_create(m->pool, offsetof(h2_stream,id)); m->spurge = h2_ihash_create(m->pool, offsetof(h2_stream,id)); m->q = h2_iq_create(m->pool, m->max_streams); m->tasks = h2_ihash_create(m->pool, offsetof(h2_task,stream_id)); m->ready_tasks = h2_ihash_create(m->pool, offsetof(h2_task,stream_id)); m->stream_timeout = stream_timeout; m->workers = workers; Loading Loading @@ -373,7 +373,6 @@ static void task_destroy(h2_mplx *m, h2_task *task, int called_from_master) && !task->rst_error); h2_ihash_remove(m->tasks, task->stream_id); h2_ihash_remove(m->ready_tasks, task->stream_id); if (m->redo_tasks) { h2_ihash_remove(m->redo_tasks, task->stream_id); } Loading Loading @@ -428,7 +427,7 @@ static void stream_done(h2_mplx *m, h2_stream *stream, int rst_error) * stream destruction until the task is done. */ h2_iq_remove(m->q, stream->id); h2_ihash_remove(m->ready_tasks, stream->id); h2_ihash_remove(m->sready, stream->id); h2_ihash_remove(m->streams, stream->id); if (stream->input) { m->tx_handles_reserved += h2_beam_get_files_beamed(stream->input); Loading Loading @@ -657,11 +656,10 @@ apr_status_t h2_mplx_in_update_windows(h2_mplx *m) return status; } static int task_iter_first(void *ctx, void *val) static int stream_iter_first(void *ctx, void *val) { task_iter_ctx *tctx = ctx; h2_task *task = val; tctx->task = task; h2_stream **pstream = ctx; *pstream = val; return 0; } Loading @@ -673,17 +671,11 @@ h2_stream *h2_mplx_next_submit(h2_mplx *m) AP_DEBUG_ASSERT(m); if ((status = enter_mutex(m, &acquired)) == APR_SUCCESS) { task_iter_ctx ctx; ctx.m = m; ctx.task = NULL; h2_ihash_iter(m->ready_tasks, task_iter_first, &ctx); if (ctx.task && !m->aborted) { h2_task *task = ctx.task; h2_ihash_remove(m->ready_tasks, task->stream_id); stream = h2_ihash_get(m->streams, task->stream_id); if (stream && task) { h2_ihash_iter(m->sready, stream_iter_first, &stream); if (stream) { h2_task *task = h2_ihash_get(m->tasks, stream->id); h2_ihash_remove(m->sready, stream->id); if (task) { task->submitted = 1; if (task->rst_error) { h2_stream_rst(stream, task->rst_error); Loading @@ -694,24 +686,11 @@ h2_stream *h2_mplx_next_submit(h2_mplx *m) task->output.beam); } } else if (task) { /* We have the io ready, but the stream has gone away, maybe * reset by the client. Should no longer happen since such * streams should clear io's from the ready queue. */ ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, m->c, APLOGNO(03347) "h2_mplx(%s): stream for response closed, " "resetting io to close request processing", task->id); h2_task_rst(task, H2_ERR_STREAM_CLOSED); if (!task->worker_started || task->worker_done) { task_destroy(m, task, 1); } else { /* hang around until the h2_task is done, but * shutdown output */ h2_task_shutdown(task, 0); } /* We have the stream ready without a task. This happens * when we fail streams early. A response should already * be present. */ AP_DEBUG_ASSERT(stream->response || stream->rst_error); } } leave_mutex(m, acquired); Loading Loading @@ -744,7 +723,7 @@ static apr_status_t out_open(h2_mplx *m, int stream_id, h2_response *response) h2_beam_mutex_set(task->output.beam, beam_enter, task->cond, m); } h2_ihash_add(m->ready_tasks, task); h2_ihash_add(m->sready, stream); if (response && response->http_status < 300) { /* we might see some file buckets in the output, see * if we have enough handles reserved. */ Loading Loading @@ -788,10 +767,9 @@ static apr_status_t out_close(h2_mplx *m, h2_task *task) if (!task->response && !task->rst_error) { /* In case a close comes before a response was created, * insert an error one so that our streams can properly * reset. * insert an error one so that our streams can properly reset. */ h2_response *r = h2_response_die(task->stream_id, APR_EGENERAL, h2_response *r = h2_response_die(task->stream_id, 500, task->request, m->pool); status = out_open(m, task->stream_id, r); ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, m->c, Loading Loading @@ -876,6 +854,10 @@ apr_status_t h2_mplx_process(h2_mplx *m, struct h2_stream *stream, if (m->aborted) { status = APR_ECONNABORTED; } else if (stream->response) { /* already have a respone, schedule for submit */ h2_ihash_add(m->sready, stream); } else { h2_beam_create(&stream->input, stream->pool, stream->id, "input", 0); Loading Loading
CHANGES +11 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,17 @@ Changes with Apache 2.4.21 *) mod_http2: Fix async write issue that led to selection of wrong timeout vs. keepalive timeout selection for idle sessions. [Stefan Eissing] *) mod_http2: checking LimitRequestLine, LimitRequestFields and LimitRequestFieldSize configurated values for incoming streams. Returning HTTP status 431 for too long/many headers fields and 414 for a too long pseudo header. [Stefan Eissing] *) mod_http2: tracking conn_rec->current_thread on slave connections, so that mod_lua finds the correct one. Fixes PR 59542. [Stefan Eissing] *) mod_proxy_http2: new experimental http2 proxy module for h2: and h2c: proxy urls. Part of the httpd mod_proxy framework, common settings apply. Requests from the same HTTP/2 frontend connection against the same backend Loading
modules/http2/NWGNUmod_http2 +1 −0 Original line number Diff line number Diff line Loading @@ -355,6 +355,7 @@ $(OBJDIR)/mod_http2.imp : NWGNUmod_http2 @echo $(DL)GEN $@$(DL) @echo $(DL) (HTTP2)$(DL) > $@ @echo $(DL) http2_module,$(DL) >> $@ @echo $(DL) h2_casecmpstrn,$(DL) >> $@ @echo $(DL) h2_ihash_add,$(DL) >> $@ @echo $(DL) h2_ihash_clear,$(DL) >> $@ @echo $(DL) h2_ihash_count,$(DL) >> $@ Loading
modules/http2/h2_from_h1.c +13 −8 Original line number Diff line number Diff line Loading @@ -291,7 +291,8 @@ static void fix_vary(request_rec *r) } } static void set_basic_http_header(request_rec *r, apr_table_t *headers) void h2_from_h1_set_basic_http_header(apr_table_t *headers, request_rec *r, apr_pool_t *pool) { char *date = NULL; const char *proxy_date = NULL; Loading @@ -302,7 +303,7 @@ static void set_basic_http_header(request_rec *r, apr_table_t *headers) * keep the set-by-proxy server and date headers, otherwise * generate a new server header / date header */ if (r->proxyreq != PROXYREQ_NONE) { if (r && r->proxyreq != PROXYREQ_NONE) { proxy_date = apr_table_get(r->headers_out, "Date"); if (!proxy_date) { /* Loading @@ -310,27 +311,31 @@ static void set_basic_http_header(request_rec *r, apr_table_t *headers) * our own Date header and pass it over to proxy_date later to * avoid a compiler warning. */ date = apr_palloc(r->pool, APR_RFC822_DATE_LEN); date = apr_palloc(pool, APR_RFC822_DATE_LEN); ap_recent_rfc822_date(date, r->request_time); } server = apr_table_get(r->headers_out, "Server"); } else { date = apr_palloc(r->pool, APR_RFC822_DATE_LEN); ap_recent_rfc822_date(date, r->request_time); date = apr_palloc(pool, APR_RFC822_DATE_LEN); ap_recent_rfc822_date(date, r? r->request_time : apr_time_now()); } apr_table_setn(headers, "Date", proxy_date ? proxy_date : date ); if (r) { apr_table_unset(r->headers_out, "Date"); } if (!server && *us) { server = us; } if (server) { apr_table_setn(headers, "Server", server); if (r) { apr_table_unset(r->headers_out, "Server"); } } } static int copy_header(void *ctx, const char *name, const char *value) { Loading Loading @@ -445,7 +450,7 @@ static h2_response *create_response(h2_from_h1 *from_h1, request_rec *r) headers = apr_table_make(r->pool, 10); set_basic_http_header(r, headers); h2_from_h1_set_basic_http_header(headers, r, r->pool); if (r->status == HTTP_NOT_MODIFIED) { apr_table_do((int (*)(void *, const char *, const char *)) copy_header, (void *) headers, r->headers_out, Loading
modules/http2/h2_from_h1.h +3 −0 Original line number Diff line number Diff line Loading @@ -69,4 +69,7 @@ apr_status_t h2_response_output_filter(ap_filter_t *f, apr_bucket_brigade *bb); apr_status_t h2_response_trailers_filter(ap_filter_t *f, apr_bucket_brigade *bb); void h2_from_h1_set_basic_http_header(apr_table_t *headers, request_rec *r, apr_pool_t *pool); #endif /* defined(__mod_h2__h2_from_h1__) */
modules/http2/h2_mplx.c +22 −40 Original line number Diff line number Diff line Loading @@ -282,11 +282,11 @@ h2_mplx *h2_mplx_create(conn_rec *c, apr_pool_t *parent, m->stream_max_mem = h2_config_geti(conf, H2_CONF_STREAM_MAX_MEM); m->streams = h2_ihash_create(m->pool, offsetof(h2_stream,id)); m->sready = h2_ihash_create(m->pool, offsetof(h2_stream,id)); m->shold = h2_ihash_create(m->pool, offsetof(h2_stream,id)); m->spurge = h2_ihash_create(m->pool, offsetof(h2_stream,id)); m->q = h2_iq_create(m->pool, m->max_streams); m->tasks = h2_ihash_create(m->pool, offsetof(h2_task,stream_id)); m->ready_tasks = h2_ihash_create(m->pool, offsetof(h2_task,stream_id)); m->stream_timeout = stream_timeout; m->workers = workers; Loading Loading @@ -373,7 +373,6 @@ static void task_destroy(h2_mplx *m, h2_task *task, int called_from_master) && !task->rst_error); h2_ihash_remove(m->tasks, task->stream_id); h2_ihash_remove(m->ready_tasks, task->stream_id); if (m->redo_tasks) { h2_ihash_remove(m->redo_tasks, task->stream_id); } Loading Loading @@ -428,7 +427,7 @@ static void stream_done(h2_mplx *m, h2_stream *stream, int rst_error) * stream destruction until the task is done. */ h2_iq_remove(m->q, stream->id); h2_ihash_remove(m->ready_tasks, stream->id); h2_ihash_remove(m->sready, stream->id); h2_ihash_remove(m->streams, stream->id); if (stream->input) { m->tx_handles_reserved += h2_beam_get_files_beamed(stream->input); Loading Loading @@ -657,11 +656,10 @@ apr_status_t h2_mplx_in_update_windows(h2_mplx *m) return status; } static int task_iter_first(void *ctx, void *val) static int stream_iter_first(void *ctx, void *val) { task_iter_ctx *tctx = ctx; h2_task *task = val; tctx->task = task; h2_stream **pstream = ctx; *pstream = val; return 0; } Loading @@ -673,17 +671,11 @@ h2_stream *h2_mplx_next_submit(h2_mplx *m) AP_DEBUG_ASSERT(m); if ((status = enter_mutex(m, &acquired)) == APR_SUCCESS) { task_iter_ctx ctx; ctx.m = m; ctx.task = NULL; h2_ihash_iter(m->ready_tasks, task_iter_first, &ctx); if (ctx.task && !m->aborted) { h2_task *task = ctx.task; h2_ihash_remove(m->ready_tasks, task->stream_id); stream = h2_ihash_get(m->streams, task->stream_id); if (stream && task) { h2_ihash_iter(m->sready, stream_iter_first, &stream); if (stream) { h2_task *task = h2_ihash_get(m->tasks, stream->id); h2_ihash_remove(m->sready, stream->id); if (task) { task->submitted = 1; if (task->rst_error) { h2_stream_rst(stream, task->rst_error); Loading @@ -694,24 +686,11 @@ h2_stream *h2_mplx_next_submit(h2_mplx *m) task->output.beam); } } else if (task) { /* We have the io ready, but the stream has gone away, maybe * reset by the client. Should no longer happen since such * streams should clear io's from the ready queue. */ ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, m->c, APLOGNO(03347) "h2_mplx(%s): stream for response closed, " "resetting io to close request processing", task->id); h2_task_rst(task, H2_ERR_STREAM_CLOSED); if (!task->worker_started || task->worker_done) { task_destroy(m, task, 1); } else { /* hang around until the h2_task is done, but * shutdown output */ h2_task_shutdown(task, 0); } /* We have the stream ready without a task. This happens * when we fail streams early. A response should already * be present. */ AP_DEBUG_ASSERT(stream->response || stream->rst_error); } } leave_mutex(m, acquired); Loading Loading @@ -744,7 +723,7 @@ static apr_status_t out_open(h2_mplx *m, int stream_id, h2_response *response) h2_beam_mutex_set(task->output.beam, beam_enter, task->cond, m); } h2_ihash_add(m->ready_tasks, task); h2_ihash_add(m->sready, stream); if (response && response->http_status < 300) { /* we might see some file buckets in the output, see * if we have enough handles reserved. */ Loading Loading @@ -788,10 +767,9 @@ static apr_status_t out_close(h2_mplx *m, h2_task *task) if (!task->response && !task->rst_error) { /* In case a close comes before a response was created, * insert an error one so that our streams can properly * reset. * insert an error one so that our streams can properly reset. */ h2_response *r = h2_response_die(task->stream_id, APR_EGENERAL, h2_response *r = h2_response_die(task->stream_id, 500, task->request, m->pool); status = out_open(m, task->stream_id, r); ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, m->c, Loading Loading @@ -876,6 +854,10 @@ apr_status_t h2_mplx_process(h2_mplx *m, struct h2_stream *stream, if (m->aborted) { status = APR_ECONNABORTED; } else if (stream->response) { /* already have a respone, schedule for submit */ h2_ihash_add(m->sready, stream); } else { h2_beam_create(&stream->input, stream->pool, stream->id, "input", 0); Loading