summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGES15
-rw-r--r--modules/http2/config2.m41
-rw-r--r--modules/http2/h2.h6
-rw-r--r--modules/http2/h2_config.c36
-rw-r--r--modules/http2/h2_config.h2
-rw-r--r--modules/http2/h2_conn_io.c15
-rw-r--r--modules/http2/h2_mplx.c206
-rw-r--r--modules/http2/h2_mplx.h29
-rw-r--r--modules/http2/h2_ngn_shed.c392
-rw-r--r--modules/http2/h2_ngn_shed.h79
-rw-r--r--modules/http2/h2_proxy_session.c47
-rw-r--r--modules/http2/h2_proxy_session.h3
-rw-r--r--modules/http2/h2_request.c2
-rw-r--r--modules/http2/h2_session.c46
-rw-r--r--modules/http2/h2_session.h2
-rw-r--r--modules/http2/h2_stream.c2
-rw-r--r--modules/http2/h2_task.c73
-rw-r--r--modules/http2/h2_task.h10
-rw-r--r--modules/http2/h2_version.h4
-rw-r--r--modules/http2/mod_http2.c24
-rw-r--r--modules/http2/mod_http2.h46
-rw-r--r--modules/http2/mod_proxy_http2.c342
22 files changed, 200 insertions, 1182 deletions
diff --git a/CHANGES b/CHANGES
index 4dd26ea533..9991922735 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,21 @@
-*- coding: utf-8 -*-
Changes with Apache 2.5.1
+ *) mod_http2: new configuration directive: ```H2Padding numbits``` to control
+ padding of HTTP/2 payload frames. 'numbits' is a number from 0-8,
+ controlling the range of padding bytes added to a frame. The actual number
+ added is chosen randomly per frame. This applies to HEADERS, DATA and PUSH_PROMISE
+ frames equally. The default continues to be 0, e.g. no padding. [Stefan Eissing]
+
+ *) mod_http2: ripping out all the h2_req_engine internal features now that mod_proxy_http2
+ has no more need for it. Optional functions are still declared but no longer implemented.
+ While previous mod_proxy_http2 will work with this, it is recommeneded to run the matching
+ versions of both modules. [Stefan Eissing]
+
+ *) mod_proxy_http2: changed mod_proxy_http2 implementation and fixed several bugs which
+ resolve PR63170. The proxy module does now a single h2 request on the (reused)
+ connection and returns. [Stefan Eissing]
+
*) mod_http2/mod_proxy_http2: proxy_http2 checks correct master connection aborted status
to trigger immediate shutdown of backend connections. This is now always signalled
by mod_http2 when the the session is being released.
diff --git a/modules/http2/config2.m4 b/modules/http2/config2.m4
index e8cefe37f0..5f49adf1cb 100644
--- a/modules/http2/config2.m4
+++ b/modules/http2/config2.m4
@@ -31,7 +31,6 @@ h2_from_h1.lo dnl
h2_h2.lo dnl
h2_headers.lo dnl
h2_mplx.lo dnl
-h2_ngn_shed.lo dnl
h2_push.lo dnl
h2_request.lo dnl
h2_session.lo dnl
diff --git a/modules/http2/h2.h b/modules/http2/h2.h
index 786c84b2d2..e057d66e0c 100644
--- a/modules/http2/h2.h
+++ b/modules/http2/h2.h
@@ -48,12 +48,12 @@ extern const char *H2_MAGIC_TOKEN;
#define H2_HEADER_PATH_LEN 5
#define H2_CRLF "\r\n"
-/* Max data size to write so it fits inside a TLS record */
-#define H2_DATA_CHUNK_SIZE ((16*1024) - 100 - 9)
-
/* Size of the frame header itself in HTTP/2 */
#define H2_FRAME_HDR_LEN 9
+/* Max data size to write so it fits inside a TLS record */
+#define H2_DATA_CHUNK_SIZE ((16*1024) - 100 - H2_FRAME_HDR_LEN)
+
/* Maximum number of padding bytes in a frame, rfc7540 */
#define H2_MAX_PADLEN 256
/* Initial default window size, RFC 7540 ch. 6.5.2 */
diff --git a/modules/http2/h2_config.c b/modules/http2/h2_config.c
index 7edd2eeaaf..fede8cc255 100644
--- a/modules/http2/h2_config.c
+++ b/modules/http2/h2_config.c
@@ -76,6 +76,8 @@ typedef struct h2_config {
int copy_files; /* if files shall be copied vs setaside on output */
apr_array_header_t *push_list;/* list of h2_push_res configurations */
int early_hints; /* support status code 103 */
+ int padding_bits;
+ int padding_always;
} h2_config;
typedef struct h2_dir_config {
@@ -111,6 +113,8 @@ static h2_config defconf = {
0, /* copy files across threads */
NULL, /* push list */
0, /* early hints, http status 103 */
+ 0, /* padding bits */
+ 1, /* padding always */
};
static h2_dir_config defdconf = {
@@ -153,6 +157,8 @@ void *h2_config_create_svr(apr_pool_t *pool, server_rec *s)
conf->copy_files = DEF_VAL;
conf->push_list = NULL;
conf->early_hints = DEF_VAL;
+ conf->padding_bits = DEF_VAL;
+ conf->padding_always = DEF_VAL;
return conf;
}
@@ -194,6 +200,8 @@ static void *h2_config_merge(apr_pool_t *pool, void *basev, void *addv)
n->push_list = add->push_list? add->push_list : base->push_list;
}
n->early_hints = H2_CONFIG_GET(add, base, early_hints);
+ n->padding_bits = H2_CONFIG_GET(add, base, padding_bits);
+ n->padding_always = H2_CONFIG_GET(add, base, padding_always);
return n;
}
@@ -275,6 +283,10 @@ static apr_int64_t h2_srv_config_geti64(const h2_config *conf, h2_config_var_t v
return H2_CONFIG_GET(conf, &defconf, copy_files);
case H2_CONF_EARLY_HINTS:
return H2_CONFIG_GET(conf, &defconf, early_hints);
+ case H2_CONF_PADDING_BITS:
+ return H2_CONFIG_GET(conf, &defconf, padding_bits);
+ case H2_CONF_PADDING_ALWAYS:
+ return H2_CONFIG_GET(conf, &defconf, padding_always);
default:
return DEF_VAL;
}
@@ -334,6 +346,12 @@ static void h2_srv_config_seti(h2_config *conf, h2_config_var_t var, int val)
case H2_CONF_EARLY_HINTS:
H2_CONFIG_SET(conf, early_hints, val);
break;
+ case H2_CONF_PADDING_BITS:
+ H2_CONFIG_SET(conf, padding_bits, val);
+ break;
+ case H2_CONF_PADDING_ALWAYS:
+ H2_CONFIG_SET(conf, padding_always, val);
+ break;
default:
break;
}
@@ -873,6 +891,22 @@ static const char *h2_conf_set_early_hints(cmd_parms *cmd,
return NULL;
}
+static const char *h2_conf_set_padding(cmd_parms *cmd, void *dirconf, const char *value)
+{
+ int val;
+
+ val = (int)apr_atoi64(value);
+ if (val < 0) {
+ return "number of bits must be >= 0";
+ }
+ if (val > 8) {
+ return "number of bits must be <= 8";
+ }
+ CONFIG_CMD_SET(cmd, dirconf, H2_CONF_PADDING_BITS, val);
+ return NULL;
+}
+
+
void h2_get_num_workers(server_rec *s, int *minw, int *maxw)
{
int threads_per_child = 0;
@@ -941,6 +975,8 @@ const command_rec h2_cmds[] = {
OR_FILEINFO|OR_AUTHCFG, "add a resource to be pushed in this location/on this server."),
AP_INIT_TAKE1("H2EarlyHints", h2_conf_set_early_hints, NULL,
RSRC_CONF, "on to enable interim status 103 responses"),
+ AP_INIT_TAKE1("H2Padding", h2_conf_set_padding, NULL,
+ RSRC_CONF, "set payload padding"),
AP_END_CMD
};
diff --git a/modules/http2/h2_config.h b/modules/http2/h2_config.h
index 307ed43c27..e940c8a715 100644
--- a/modules/http2/h2_config.h
+++ b/modules/http2/h2_config.h
@@ -42,6 +42,8 @@ typedef enum {
H2_CONF_PUSH_DIARY_SIZE,
H2_CONF_COPY_FILES,
H2_CONF_EARLY_HINTS,
+ H2_CONF_PADDING_BITS,
+ H2_CONF_PADDING_ALWAYS,
} h2_config_var_t;
struct apr_hash_t;
diff --git a/modules/http2/h2_conn_io.c b/modules/http2/h2_conn_io.c
index f94710f5bb..68c15d13e4 100644
--- a/modules/http2/h2_conn_io.c
+++ b/modules/http2/h2_conn_io.c
@@ -40,12 +40,17 @@
* ~= 1300 bytes */
#define WRITE_SIZE_INITIAL 1300
-/* Calculated like this: max TLS record size 16*1024
- * - 40 (IP) - 20 (TCP) - 40 (TCP options)
- * - TLS overhead (60-100)
- * which seems to create less TCP packets overall
+/* The maximum we'd like to write in one chunk is
+ * the max size of a TLS record. When pushing
+ * many frames down the h2 connection, this might
+ * align differently because of headers and other
+ * frames or simply as not sufficient data is
+ * in a response body.
+ * However keeping frames at or below this limit
+ * should make optimizations at the layer that writes
+ * to TLS easier.
*/
-#define WRITE_SIZE_MAX (TLS_DATA_MAX - 100)
+#define WRITE_SIZE_MAX (TLS_DATA_MAX)
#define BUF_REMAIN ((apr_size_t)(bmax-off))
diff --git a/modules/http2/h2_mplx.c b/modules/http2/h2_mplx.c
index aad7beaa97..81b063ad44 100644
--- a/modules/http2/h2_mplx.c
+++ b/modules/http2/h2_mplx.c
@@ -40,7 +40,6 @@
#include "h2_ctx.h"
#include "h2_h2.h"
#include "h2_mplx.h"
-#include "h2_ngn_shed.h"
#include "h2_request.h"
#include "h2_stream.h"
#include "h2_session.h"
@@ -83,12 +82,6 @@ static void check_data_for(h2_mplx *m, h2_stream *stream, int lock);
static void stream_output_consumed(void *ctx,
h2_bucket_beam *beam, apr_off_t length)
{
- h2_stream *stream = ctx;
- h2_task *task = stream->task;
-
- if (length > 0 && task && task->assigned) {
- h2_req_engine_out_consumed(task->assigned, task->c, length);
- }
}
static void stream_input_ev(void *ctx, h2_bucket_beam *beam)
@@ -136,7 +129,6 @@ static void stream_cleanup(h2_mplx *m, h2_stream *stream)
}
else if (stream->task) {
stream->task->c->aborted = 1;
- apr_thread_cond_broadcast(m->task_thawed);
}
}
@@ -198,12 +190,6 @@ h2_mplx *h2_mplx_create(conn_rec *c, server_rec *s, apr_pool_t *parent,
return NULL;
}
- status = apr_thread_cond_create(&m->task_thawed, m->pool);
- if (status != APR_SUCCESS) {
- apr_pool_destroy(m->pool);
- return NULL;
- }
-
m->max_streams = h2_config_sgeti(s, H2_CONF_MAX_STREAMS);
m->stream_max_mem = h2_config_sgeti(s, H2_CONF_STREAM_MAX_MEM);
@@ -226,10 +212,6 @@ h2_mplx *h2_mplx_create(conn_rec *c, server_rec *s, apr_pool_t *parent,
m->limit_change_interval = apr_time_from_msec(100);
m->spare_slaves = apr_array_make(m->pool, 10, sizeof(conn_rec*));
-
- m->ngn_shed = h2_ngn_shed_create(m->pool, m->c, m->max_streams,
- m->stream_max_mem);
- h2_ngn_shed_set_ctx(m->ngn_shed , m);
}
return m;
}
@@ -387,10 +369,10 @@ static int report_stream_iter(void *ctx, void *val) {
if (task) {
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, m->c, /* NO APLOGNO */
H2_STRM_MSG(stream, "->03198: %s %s %s"
- "[started=%d/done=%d/frozen=%d]"),
+ "[started=%d/done=%d]"),
task->request->method, task->request->authority,
task->request->path, task->worker_started,
- task->worker_done, task->frozen);
+ task->worker_done);
}
else {
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, m->c, /* NO APLOGNO */
@@ -452,9 +434,7 @@ void h2_mplx_release_and_join(h2_mplx *m, apr_thread_cond_t *wait)
/* until empty */
}
- /* 2. terminate ngn_shed, no more streams
- * should be scheduled or in the active set */
- h2_ngn_shed_abort(m->ngn_shed);
+ /* 2. no more streams should be scheduled or in the active set */
ap_assert(h2_ihash_empty(m->streams));
ap_assert(h2_iq_empty(m->q));
@@ -478,10 +458,6 @@ void h2_mplx_release_and_join(h2_mplx *m, apr_thread_cond_t *wait)
ap_assert(m->tasks_active == 0);
m->join_wait = NULL;
- /* 4. close the h2_req_enginge shed */
- h2_ngn_shed_destroy(m->ngn_shed);
- m->ngn_shed = NULL;
-
/* 4. With all workers done, all streams should be in spurge */
if (!h2_ihash_empty(m->shold)) {
ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, m->c, APLOGNO(03516)
@@ -787,49 +763,14 @@ apr_status_t h2_mplx_pop_task(h2_mplx *m, h2_task **ptask)
return rv;
}
-static void task_done(h2_mplx *m, h2_task *task, h2_req_engine *ngn)
+static void task_done(h2_mplx *m, h2_task *task)
{
h2_stream *stream;
- if (task->frozen) {
- /* this task was handed over to an engine for processing
- * and the original worker has finished. That means the
- * engine may start processing now. */
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
- "h2_mplx(%ld): task(%s) done (frozen)", m->id, task->id);
- h2_task_thaw(task);
- apr_thread_cond_broadcast(m->task_thawed);
- return;
- }
-
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
"h2_mplx(%ld): task(%s) done", m->id, task->id);
out_close(m, task);
- if (ngn) {
- apr_off_t bytes = 0;
- h2_beam_send(task->output.beam, NULL, APR_NONBLOCK_READ);
- bytes += h2_beam_get_buffered(task->output.beam);
- if (bytes > 0) {
- /* we need to report consumed and current buffered output
- * to the engine. The request will be streamed out or cancelled,
- * no more data is coming from it and the engine should update
- * its calculations before we destroy this information. */
- h2_req_engine_out_consumed(ngn, task->c, bytes);
- }
- }
-
- if (task->engine) {
- if (!m->aborted && !task->c->aborted
- && !h2_req_engine_is_shutdown(task->engine)) {
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, m->c, APLOGNO(10022)
- "h2_mplx(%ld): task(%s) has not-shutdown "
- "engine(%s)", m->id, task->id,
- h2_req_engine_get_id(task->engine));
- }
- h2_ngn_shed_done_ngn(m->ngn_shed, task->engine);
- }
-
task->worker_done = 1;
task->done_at = apr_time_now();
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
@@ -906,7 +847,7 @@ void h2_mplx_task_done(h2_mplx *m, h2_task *task, h2_task **ptask)
{
H2_MPLX_ENTER_ALWAYS(m);
- task_done(m, task, NULL);
+ task_done(m, task);
--m->tasks_active;
if (m->join_wait) {
@@ -1100,143 +1041,6 @@ apr_status_t h2_mplx_idle(h2_mplx *m)
}
/*******************************************************************************
- * HTTP/2 request engines
- ******************************************************************************/
-
-typedef struct {
- h2_mplx * m;
- h2_req_engine *ngn;
- int streams_updated;
-} ngn_update_ctx;
-
-static int ngn_update_window(void *ctx, void *val)
-{
- ngn_update_ctx *uctx = ctx;
- h2_stream *stream = val;
- if (stream->task && stream->task->assigned == uctx->ngn
- && output_consumed_signal(uctx->m, stream->task)) {
- ++uctx->streams_updated;
- }
- return 1;
-}
-
-static apr_status_t ngn_out_update_windows(h2_mplx *m, h2_req_engine *ngn)
-{
- ngn_update_ctx ctx;
-
- ctx.m = m;
- ctx.ngn = ngn;
- ctx.streams_updated = 0;
- h2_ihash_iter(m->streams, ngn_update_window, &ctx);
-
- return ctx.streams_updated? APR_SUCCESS : APR_EAGAIN;
-}
-
-apr_status_t h2_mplx_req_engine_push(const char *ngn_type,
- request_rec *r,
- http2_req_engine_init *einit)
-{
- apr_status_t status;
- h2_mplx *m;
- h2_task *task;
- h2_stream *stream;
-
- task = h2_ctx_get_task(r->connection);
- if (!task) {
- return APR_ECONNABORTED;
- }
- m = task->mplx;
-
- H2_MPLX_ENTER(m);
-
- stream = h2_ihash_get(m->streams, task->stream_id);
- if (stream) {
- status = h2_ngn_shed_push_request(m->ngn_shed, ngn_type, r, einit);
- }
- else {
- status = APR_ECONNABORTED;
- }
-
- H2_MPLX_LEAVE(m);
- return status;
-}
-
-apr_status_t h2_mplx_req_engine_pull(h2_req_engine *ngn,
- apr_read_type_e block,
- int capacity,
- request_rec **pr)
-{
- h2_ngn_shed *shed = h2_ngn_shed_get_shed(ngn);
- h2_mplx *m = h2_ngn_shed_get_ctx(shed);
- apr_status_t status;
- int want_shutdown;
-
- H2_MPLX_ENTER(m);
-
- want_shutdown = (block == APR_BLOCK_READ);
-
- /* Take this opportunity to update output consummation
- * for this engine */
- ngn_out_update_windows(m, ngn);
-
- if (want_shutdown && !h2_iq_empty(m->q)) {
- /* For a blocking read, check first if requests are to be
- * had and, if not, wait a short while before doing the
- * blocking, and if unsuccessful, terminating read.
- */
- status = h2_ngn_shed_pull_request(shed, ngn, capacity, 1, pr);
- if (APR_STATUS_IS_EAGAIN(status)) {
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
- "h2_mplx(%ld): start block engine pull", m->id);
- apr_thread_cond_timedwait(m->task_thawed, m->lock,
- apr_time_from_msec(20));
- status = h2_ngn_shed_pull_request(shed, ngn, capacity, 1, pr);
- }
- }
- else {
- status = h2_ngn_shed_pull_request(shed, ngn, capacity,
- want_shutdown, pr);
- }
-
- H2_MPLX_LEAVE(m);
- return status;
-}
-
-void h2_mplx_req_engine_done(h2_req_engine *ngn, conn_rec *r_conn,
- apr_status_t status)
-{
- h2_task *task = h2_ctx_get_task(r_conn);
-
- if (task) {
- h2_mplx *m = task->mplx;
- h2_stream *stream;
- int task_hosting_engine = (task->engine != NULL);
-
- H2_MPLX_ENTER_ALWAYS(m);
-
- stream = h2_ihash_get(m->streams, task->stream_id);
-
- ngn_out_update_windows(m, ngn);
- h2_ngn_shed_done_task(m->ngn_shed, ngn, task);
-
- if (status != APR_SUCCESS && stream
- && h2_task_can_redo(task)
- && !h2_ihash_get(m->sredo, stream->id)) {
- ap_log_cerror(APLOG_MARK, APLOG_INFO, status, m->c,
- "h2_mplx(%ld): task %s added to redo", m->id, task->id);
- h2_ihash_add(m->sredo, stream);
- }
-
- /* cannot report that until hosted engine returns */
- if (!task_hosting_engine) {
- task_done(m, task, ngn);
- }
-
- H2_MPLX_LEAVE(m);
- }
-}
-
-/*******************************************************************************
* mplx master events dispatching
******************************************************************************/
diff --git a/modules/http2/h2_mplx.h b/modules/http2/h2_mplx.h
index b5db224a27..575ccaf430 100644
--- a/modules/http2/h2_mplx.h
+++ b/modules/http2/h2_mplx.h
@@ -47,8 +47,6 @@ struct h2_request;
struct apr_thread_cond_t;
struct h2_workers;
struct h2_iqueue;
-struct h2_ngn_shed;
-struct h2_req_engine;
#include <apr_queue.h>
@@ -86,7 +84,6 @@ struct h2_mplx {
apr_thread_mutex_t *lock;
struct apr_thread_cond_t *added_output;
- struct apr_thread_cond_t *task_thawed;
struct apr_thread_cond_t *join_wait;
apr_size_t stream_max_mem;
@@ -95,8 +92,6 @@ struct h2_mplx {
apr_array_header_t *spare_slaves; /* spare slave connections */
struct h2_workers *workers;
-
- struct h2_ngn_shed *ngn_shed;
};
@@ -302,28 +297,4 @@ APR_RING_INSERT_TAIL((b), ap__b, h2_mplx, link); \
*/
apr_status_t h2_mplx_idle(h2_mplx *m);
-/*******************************************************************************
- * h2_req_engine handling
- ******************************************************************************/
-
-typedef void h2_output_consumed(void *ctx, conn_rec *c, apr_off_t consumed);
-typedef apr_status_t h2_mplx_req_engine_init(struct h2_req_engine *engine,
- const char *id,
- const char *type,
- apr_pool_t *pool,
- apr_size_t req_buffer_size,
- request_rec *r,
- h2_output_consumed **pconsumed,
- void **pbaton);
-
-apr_status_t h2_mplx_req_engine_push(const char *ngn_type,
- request_rec *r,
- h2_mplx_req_engine_init *einit);
-apr_status_t h2_mplx_req_engine_pull(struct h2_req_engine *ngn,
- apr_read_type_e block,
- int capacity,
- request_rec **pr);
-void h2_mplx_req_engine_done(struct h2_req_engine *ngn, conn_rec *r_conn,
- apr_status_t status);
-
#endif /* defined(__mod_h2__h2_mplx__) */
diff --git a/modules/http2/h2_ngn_shed.c b/modules/http2/h2_ngn_shed.c
deleted file mode 100644
index 39582592ce..0000000000
--- a/modules/http2/h2_ngn_shed.c
+++ /dev/null
@@ -1,392 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <assert.h>
-#include <stddef.h>
-#include <stdlib.h>
-
-#include <apr_thread_mutex.h>
-#include <apr_thread_cond.h>
-#include <apr_strings.h>
-#include <apr_time.h>
-
-#include <httpd.h>
-#include <http_core.h>
-#include <http_log.h>
-
-#include "mod_http2.h"
-
-#include "h2_private.h"
-#include "h2.h"
-#include "h2_config.h"
-#include "h2_conn.h"
-#include "h2_ctx.h"
-#include "h2_h2.h"
-#include "h2_mplx.h"
-#include "h2_request.h"
-#include "h2_task.h"
-#include "h2_util.h"
-#include "h2_ngn_shed.h"
-
-
-typedef struct h2_ngn_entry h2_ngn_entry;
-struct h2_ngn_entry {
- APR_RING_ENTRY(h2_ngn_entry) link;
- h2_task *task;
- request_rec *r;
-};
-
-#define H2_NGN_ENTRY_NEXT(e) APR_RING_NEXT((e), link)
-#define H2_NGN_ENTRY_PREV(e) APR_RING_PREV((e), link)
-#define H2_NGN_ENTRY_REMOVE(e) APR_RING_REMOVE((e), link)
-
-#define H2_REQ_ENTRIES_SENTINEL(b) APR_RING_SENTINEL((b), h2_ngn_entry, link)
-#define H2_REQ_ENTRIES_EMPTY(b) APR_RING_EMPTY((b), h2_ngn_entry, link)
-#define H2_REQ_ENTRIES_FIRST(b) APR_RING_FIRST(b)
-#define H2_REQ_ENTRIES_LAST(b) APR_RING_LAST(b)
-
-#define H2_REQ_ENTRIES_INSERT_HEAD(b, e) do { \
-h2_ngn_entry *ap__b = (e); \
-APR_RING_INSERT_HEAD((b), ap__b, h2_ngn_entry, link); \
-} while (0)
-
-#define H2_REQ_ENTRIES_INSERT_TAIL(b, e) do { \
-h2_ngn_entry *ap__b = (e); \
-APR_RING_INSERT_TAIL((b), ap__b, h2_ngn_entry, link); \
-} while (0)
-
-struct h2_req_engine {
- const char *id; /* identifier */
- const char *type; /* name of the engine type */
- apr_pool_t *pool; /* pool for engine specific allocations */
- conn_rec *c; /* connection this engine is assigned to */
- h2_task *task; /* the task this engine is based on, running in */
- h2_ngn_shed *shed;
-
- unsigned int shutdown : 1; /* engine is being shut down */
- unsigned int done : 1; /* engine has finished */
-
- APR_RING_HEAD(h2_req_entries, h2_ngn_entry) entries;
- int capacity; /* maximum concurrent requests */
- int no_assigned; /* # of assigned requests */
- int no_live; /* # of live */
- int no_finished; /* # of finished */
-
- h2_output_consumed *out_consumed;
- void *out_consumed_ctx;
-};
-
-const char *h2_req_engine_get_id(h2_req_engine *engine)
-{
- return engine->id;
-}
-
-int h2_req_engine_is_shutdown(h2_req_engine *engine)
-{
- return engine->shutdown;
-}
-
-void h2_req_engine_out_consumed(h2_req_engine *engine, conn_rec *c,
- apr_off_t bytes)
-{
- if (engine->out_consumed) {
- engine->out_consumed(engine->out_consumed_ctx, c, bytes);
- }
-}
-
-h2_ngn_shed *h2_ngn_shed_create(apr_pool_t *pool, conn_rec *c,
- int default_capacity,
- apr_size_t req_buffer_size)
-{
- h2_ngn_shed *shed;
-
- shed = apr_pcalloc(pool, sizeof(*shed));
- shed->c = c;
- shed->pool = pool;
- shed->default_capacity = default_capacity;
- shed->req_buffer_size = req_buffer_size;
- shed->ngns = apr_hash_make(pool);
-
- return shed;
-}
-
-void h2_ngn_shed_set_ctx(h2_ngn_shed *shed, void *user_ctx)
-{
- shed->user_ctx = user_ctx;
-}
-
-void *h2_ngn_shed_get_ctx(h2_ngn_shed *shed)
-{
- return shed->user_ctx;
-}
-
-h2_ngn_shed *h2_ngn_shed_get_shed(h2_req_engine *ngn)
-{
- return ngn->shed;
-}
-
-void h2_ngn_shed_abort(h2_ngn_shed *shed)
-{
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, shed->c, APLOGNO(03394)
- "h2_ngn_shed(%ld): abort", shed->c->id);
- shed->aborted = 1;
-}
-
-static void ngn_add_task(h2_req_engine *ngn, h2_task *task, request_rec *r)
-{
- h2_ngn_entry *entry = apr_pcalloc(task->pool, sizeof(*entry));
- APR_RING_ELEM_INIT(entry, link);
- entry->task = task;
- entry->r = r;
- H2_REQ_ENTRIES_INSERT_TAIL(&ngn->entries, entry);
- ngn->no_assigned++;
-}
-
-
-apr_status_t h2_ngn_shed_push_request(h2_ngn_shed *shed, const char *ngn_type,
- request_rec *r,
- http2_req_engine_init *einit)
-{
- h2_req_engine *ngn;
- h2_task *task = h2_ctx_get_task(r->connection);
-
- ap_assert(task);
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, shed->c,
- "h2_ngn_shed(%ld): PUSHing request (task=%s)", shed->c->id,
- task->id);
- if (task->request->serialize) {
- /* Max compatibility, deny processing of this */
- return APR_EOF;
- }
-
- if (task->assigned) {
- --task->assigned->no_assigned;
- --task->assigned->no_live;
- task->assigned = NULL;
- }
-
- if (task->engine) {
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, task->c,
- "h2_ngn_shed(%ld): push task(%s) hosting engine %s "
- "already with %d tasks",
- shed->c->id, task->id, task->engine->id,
- task->engine->no_assigned);
- task->assigned = task->engine;
- ngn_add_task(task->engine, task, r);
- return APR_SUCCESS;
- }
-
- ngn = apr_hash_get(shed->ngns, ngn_type, APR_HASH_KEY_STRING);
- if (ngn && !ngn->shutdown) {
- /* this task will be processed in another thread,
- * freeze any I/O for the time being. */
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, task->c,
- "h2_ngn_shed(%ld): pushing request %s to %s",
- shed->c->id, task->id, ngn->id);
- if (!h2_task_has_thawed(task)) {
- h2_task_freeze(task);
- }
- ngn_add_task(ngn, task, r);
- return APR_SUCCESS;
- }
-
- /* no existing engine or being shut down, start a new one */
- if (einit) {
- apr_status_t status;
- apr_pool_t *pool = task->pool;
- h2_req_engine *newngn;
-
- newngn = apr_pcalloc(pool, sizeof(*ngn));
- newngn->pool = pool;
- newngn->id = apr_psprintf(pool, "ngn-%s", task->id);
- newngn->type = apr_pstrdup(pool, ngn_type);
- newngn->c = task->c;
- newngn->shed = shed;
- newngn->capacity = shed->default_capacity;
- newngn->no_assigned = 1;
- newngn->no_live = 1;
- APR_RING_INIT(&newngn->entries, h2_ngn_entry, link);
-
- status = einit(newngn, newngn->id, newngn->type, newngn->pool,
- shed->req_buffer_size, r,
- &newngn->out_consumed, &newngn->out_consumed_ctx);
-
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, task->c, APLOGNO(03395)
- "h2_ngn_shed(%ld): create engine %s (%s)",
- shed->c->id, newngn->id, newngn->type);
- if (status == APR_SUCCESS) {
- newngn->task = task;
- task->engine = newngn;
- task->assigned = newngn;
- apr_hash_set(shed->ngns, newngn->type, APR_HASH_KEY_STRING, newngn);
- }
- return status;
- }
- return APR_EOF;
-}
-
-static h2_ngn_entry *pop_detached(h2_req_engine *ngn)
-{
- h2_ngn_entry *entry;
- for (entry = H2_REQ_ENTRIES_FIRST(&ngn->entries);
- entry != H2_REQ_ENTRIES_SENTINEL(&ngn->entries);
- entry = H2_NGN_ENTRY_NEXT(entry)) {
- if (h2_task_has_thawed(entry->task)
- || (entry->task->engine == ngn)) {
- /* The task hosting this engine can always be pulled by it.
- * For other task, they need to become detached, e.g. no longer
- * assigned to another worker. */
- H2_NGN_ENTRY_REMOVE(entry);
- return entry;
- }
- }
- return NULL;
-}
-
-apr_status_t h2_ngn_shed_pull_request(h2_ngn_shed *shed,
- h2_req_engine *ngn,
- int capacity,
- int want_shutdown,
- request_rec **pr)
-{
- h2_ngn_entry *entry;
-
- ap_assert(ngn);
- *pr = NULL;
- ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, shed->c, APLOGNO(03396)
- "h2_ngn_shed(%ld): pull task for engine %s, shutdown=%d",
- shed->c->id, ngn->id, want_shutdown);
- if (shed->aborted) {
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, shed->c, APLOGNO(03397)
- "h2_ngn_shed(%ld): abort while pulling requests %s",
- shed->c->id, ngn->id);
- ngn->shutdown = 1;
- return APR_ECONNABORTED;
- }
-
- ngn->capacity = capacity;
- if (H2_REQ_ENTRIES_EMPTY(&ngn->entries)) {
- if (want_shutdown) {
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, shed->c,
- "h2_ngn_shed(%ld): empty queue, shutdown engine %s",
- shed->c->id, ngn->id);
- ngn->shutdown = 1;
- }
- return ngn->shutdown? APR_EOF : APR_EAGAIN;
- }
-
- if ((entry = pop_detached(ngn))) {
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, entry->task->c, APLOGNO(03398)
- "h2_ngn_shed(%ld): pulled request %s for engine %s",
- shed->c->id, entry->task->id, ngn->id);
- ngn->no_live++;
- *pr = entry->r;
- entry->task->assigned = ngn;
- /* task will now run in ngn's own thread. Modules like lua
- * seem to require the correct thread set in the conn_rec.
- * See PR 59542. */
- if (entry->task->c && ngn->c) {
- entry->task->c->current_thread = ngn->c->current_thread;
- }
- if (entry->task->engine == ngn) {
- /* If an engine pushes its own base task, and then pulls
- * it back to itself again, it needs to be thawed.
- */
- h2_task_thaw(entry->task);
- }
- return APR_SUCCESS;
- }
-
- if (1) {
- entry = H2_REQ_ENTRIES_FIRST(&ngn->entries);
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, shed->c, APLOGNO(03399)
- "h2_ngn_shed(%ld): pull task, nothing, first task %s",
- shed->c->id, entry->task->id);
- }
- return APR_EAGAIN;
-}
-
-static apr_status_t ngn_done_task(h2_ngn_shed *shed, h2_req_engine *ngn,
- h2_task *task, int waslive, int aborted)
-{
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, shed->c, APLOGNO(03400)
- "h2_ngn_shed(%ld): task %s %s by %s",
- shed->c->id, task->id, aborted? "aborted":"done", ngn->id);
- ngn->no_finished++;
- if (waslive) ngn->no_live--;
- ngn->no_assigned--;
- task->assigned = NULL;
-
- return APR_SUCCESS;
-}
-
-apr_status_t h2_ngn_shed_done_task(h2_ngn_shed *shed,
- struct h2_req_engine *ngn, h2_task *task)
-{
- return ngn_done_task(shed, ngn, task, 1, 0);
-}
-
-void h2_ngn_shed_done_ngn(h2_ngn_shed *shed, struct h2_req_engine *ngn)
-{
- if (ngn->done) {
- return;
- }
-
- if (!shed->aborted && !H2_REQ_ENTRIES_EMPTY(&ngn->entries)) {
- h2_ngn_entry *entry;
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, shed->c,
- "h2_ngn_shed(%ld): exit engine %s (%s), "
- "has still requests queued, shutdown=%d,"
- "assigned=%ld, live=%ld, finished=%ld",
- shed->c->id, ngn->id, ngn->type,
- ngn->shutdown,
- (long)ngn->no_assigned, (long)ngn->no_live,
- (long)ngn->no_finished);
- for (entry = H2_REQ_ENTRIES_FIRST(&ngn->entries);
- entry != H2_REQ_ENTRIES_SENTINEL(&ngn->entries);
- entry = H2_NGN_ENTRY_NEXT(entry)) {
- h2_task *task = entry->task;
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, shed->c,
- "h2_ngn_shed(%ld): engine %s has queued task %s, "
- "frozen=%d, aborting",
- shed->c->id, ngn->id, task->id, task->frozen);
- ngn_done_task(shed, ngn, task, 0, 1);
- task->engine = task->assigned = NULL;
- }
- }
- if (!shed->aborted && (ngn->no_assigned > 1 || ngn->no_live > 1)) {
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, shed->c,
- "h2_ngn_shed(%ld): exit engine %s (%s), "
- "assigned=%ld, live=%ld, finished=%ld",
- shed->c->id, ngn->id, ngn->type,
- (long)ngn->no_assigned, (long)ngn->no_live,
- (long)ngn->no_finished);
- }
- else {
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, shed->c,
- "h2_ngn_shed(%ld): exit engine %s",
- shed->c->id, ngn->id);
- }
-
- apr_hash_set(shed->ngns, ngn->type, APR_HASH_KEY_STRING, NULL);
- ngn->done = 1;
-}
-
-void h2_ngn_shed_destroy(h2_ngn_shed *shed)
-{
- ap_assert(apr_hash_count(shed->ngns) == 0);
-}
-
diff --git a/modules/http2/h2_ngn_shed.h b/modules/http2/h2_ngn_shed.h
deleted file mode 100644
index 7764c1897f..0000000000
--- a/modules/http2/h2_ngn_shed.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef h2_req_shed_h
-#define h2_req_shed_h
-
-struct h2_req_engine;
-struct h2_task;
-
-typedef struct h2_ngn_shed h2_ngn_shed;
-struct h2_ngn_shed {
- conn_rec *c;
- apr_pool_t *pool;
- apr_hash_t *ngns;
- void *user_ctx;
-
- unsigned int aborted : 1;
-
- int default_capacity;
- apr_size_t req_buffer_size; /* preferred buffer size for responses */
-};
-
-const char *h2_req_engine_get_id(h2_req_engine *engine);
-int h2_req_engine_is_shutdown(h2_req_engine *engine);
-
-void h2_req_engine_out_consumed(h2_req_engine *engine, conn_rec *c,
- apr_off_t bytes);
-
-typedef apr_status_t h2_shed_ngn_init(h2_req_engine *engine,
- const char *id,
- const char *type,
- apr_pool_t *pool,
- apr_size_t req_buffer_size,
- request_rec *r,
- h2_output_consumed **pconsumed,
- void **pbaton);
-
-h2_ngn_shed *h2_ngn_shed_create(apr_pool_t *pool, conn_rec *c,
- int default_capactiy,
- apr_size_t req_buffer_size);
-
-void h2_ngn_shed_destroy(h2_ngn_shed *shed);
-
-void h2_ngn_shed_set_ctx(h2_ngn_shed *shed, void *user_ctx);
-void *h2_ngn_shed_get_ctx(h2_ngn_shed *shed);
-
-h2_ngn_shed *h2_ngn_shed_get_shed(struct h2_req_engine *ngn);
-
-void h2_ngn_shed_abort(h2_ngn_shed *shed);
-
-apr_status_t h2_ngn_shed_push_request(h2_ngn_shed *shed, const char *ngn_type,
- request_rec *r,
- h2_shed_ngn_init *init_cb);
-
-apr_status_t h2_ngn_shed_pull_request(h2_ngn_shed *shed, h2_req_engine *pub_ngn,
- int capacity,
- int want_shutdown, request_rec **pr);
-
-apr_status_t h2_ngn_shed_done_task(h2_ngn_shed *shed,
- struct h2_req_engine *ngn,
- struct h2_task *task);
-
-void h2_ngn_shed_done_ngn(h2_ngn_shed *shed, struct h2_req_engine *ngn);
-
-
-#endif /* h2_req_shed_h */
diff --git a/modules/http2/h2_proxy_session.c b/modules/http2/h2_proxy_session.c
index b024c8c256..961f5e40b6 100644
--- a/modules/http2/h2_proxy_session.c
+++ b/modules/http2/h2_proxy_session.c
@@ -429,12 +429,6 @@ static int stream_response_data(nghttp2_session *ngh2, uint8_t flags,
stream_id, NGHTTP2_STREAM_CLOSED);
return NGHTTP2_ERR_STREAM_CLOSING;
}
- if (stream->standalone) {
- nghttp2_session_consume(ngh2, stream_id, len);
- ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, stream->r,
- "h2_proxy_session(%s): stream %d, win_update %d bytes",
- session->id, stream_id, (int)len);
- }
return 0;
}
@@ -641,7 +635,7 @@ h2_proxy_session *h2_proxy_session_setup(const char *id, proxy_conn_rec *p_conn,
nghttp2_option_new(&option);
nghttp2_option_set_peer_max_concurrent_streams(option, 100);
- nghttp2_option_set_no_auto_window_update(option, 1);
+ nghttp2_option_set_no_auto_window_update(option, 0);
nghttp2_session_client_new2(&session->ngh2, cbs, session, option);
@@ -1545,42 +1539,3 @@ typedef struct {
int updated;
} win_update_ctx;
-static int win_update_iter(void *udata, void *val)
-{
- win_update_ctx *ctx = udata;
- h2_proxy_stream *stream = val;
-
- if (stream->r && stream->r->connection == ctx->c) {
- ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, ctx->session->c,
- "h2_proxy_session(%s-%d): win_update %ld bytes",
- ctx->session->id, (int)stream->id, (long)ctx->bytes);
- nghttp2_session_consume(ctx->session->ngh2, stream->id, ctx->bytes);
- ctx->updated = 1;
- return 0;
- }
- return 1;
-}
-
-
-void h2_proxy_session_update_window(h2_proxy_session *session,
- conn_rec *c, apr_off_t bytes)
-{
- if (!h2_proxy_ihash_empty(session->streams)) {
- win_update_ctx ctx;
- ctx.session = session;
- ctx.c = c;
- ctx.bytes = bytes;
- ctx.updated = 0;
- h2_proxy_ihash_iter(session->streams, win_update_iter, &ctx);
-
- if (!ctx.updated) {
- /* could not find the stream any more, possibly closed, update
- * the connection window at least */
- ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c,
- "h2_proxy_session(%s): win_update conn %ld bytes",
- session->id, (long)bytes);
- nghttp2_session_consume_connection(session->ngh2, (size_t)bytes);
- }
- }
-}
-
diff --git a/modules/http2/h2_proxy_session.h b/modules/http2/h2_proxy_session.h
index ecebb6155f..1d0750b0c2 100644
--- a/modules/http2/h2_proxy_session.h
+++ b/modules/http2/h2_proxy_session.h
@@ -120,9 +120,6 @@ void h2_proxy_session_cancel_all(h2_proxy_session *s);
void h2_proxy_session_cleanup(h2_proxy_session *s, h2_proxy_request_done *done);
-void h2_proxy_session_update_window(h2_proxy_session *s,
- conn_rec *c, apr_off_t bytes);
-
#define H2_PROXY_REQ_URL_NOTE "h2-proxy-req-url"
#endif /* h2_proxy_session_h */
diff --git a/modules/http2/h2_request.c b/modules/http2/h2_request.c
index 5893c8b267..d3341bb4da 100644
--- a/modules/http2/h2_request.c
+++ b/modules/http2/h2_request.c
@@ -282,7 +282,7 @@ request_rec *h2_request_create_rec(const h2_request *req, conn_rec *c)
/* Time to populate r with the data we have. */
r->request_time = req->request_time;
- r->method = apr_pstrdup(r->pool, req->method);
+ r->method = req->method;
/* Provide quick information about the request method as soon as known */
r->method_number = ap_method_number_of(r->method);
if (r->method_number == M_GET && r->method[0] == 'H') {
diff --git a/modules/http2/h2_session.c b/modules/http2/h2_session.c
index 2eda330de6..1fceabc112 100644
--- a/modules/http2/h2_session.c
+++ b/modules/http2/h2_session.c
@@ -495,9 +495,7 @@ static int on_send_data_cb(nghttp2_session *ngh2,
return NGHTTP2_ERR_WOULDBLOCK;
}
- if (frame->data.padlen > H2_MAX_PADLEN) {
- return NGHTTP2_ERR_PROTO;
- }
+ ap_assert(frame->data.padlen <= (H2_MAX_PADLEN+1));
padlen = (unsigned char)frame->data.padlen;
stream = get_stream(session, stream_id);
@@ -513,8 +511,9 @@ static int on_send_data_cb(nghttp2_session *ngh2,
H2_STRM_MSG(stream, "send_data_cb for %ld bytes"),
(long)length);
- status = h2_conn_io_write(&session->io, (const char *)framehd, 9);
+ status = h2_conn_io_write(&session->io, (const char *)framehd, H2_FRAME_HDR_LEN);
if (padlen && status == APR_SUCCESS) {
+ --padlen;
status = h2_conn_io_write(&session->io, (const char *)&padlen, 1);
}
@@ -622,6 +621,39 @@ static int on_invalid_header_cb(nghttp2_session *ngh2,
}
#endif
+static ssize_t select_padding_cb(nghttp2_session *ngh2,
+ const nghttp2_frame *frame,
+ size_t max_payloadlen, void *user_data)
+{
+ h2_session *session = user_data;
+ ssize_t frame_len = frame->hd.length + H2_FRAME_HDR_LEN; /* the total length without padding */
+ ssize_t padded_len = frame_len;
+
+ /* Determine # of padding bytes to append to frame. Unless session->padding_always
+ * the number my be capped by the ui.write_size that currently applies.
+ */
+ if (session->padding_max) {
+ int n = ap_random_pick(0, session->padding_max);
+ padded_len = H2MIN(max_payloadlen + H2_FRAME_HDR_LEN, frame_len + n);
+ }
+
+ if (padded_len != frame_len) {
+ if (!session->padding_always && session->io.write_size
+ && (padded_len > session->io.write_size)
+ && (frame_len <= session->io.write_size)) {
+ padded_len = session->io.write_size;
+ }
+ if (APLOGctrace2(session->c)) {
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c,
+ "select padding from [%d, %d]: %d (frame length: 0x%04x, write size: %d)",
+ (int)frame_len, (int)max_payloadlen+H2_FRAME_HDR_LEN,
+ (int)(padded_len - frame_len), (int)padded_len, (int)session->io.write_size);
+ }
+ return padded_len - H2_FRAME_HDR_LEN;
+ }
+ return frame->hd.length;
+}
+
#define NGH2_SET_CALLBACK(callbacks, name, fn)\
nghttp2_session_callbacks_set_##name##_callback(callbacks, fn)
@@ -647,6 +679,7 @@ static apr_status_t init_callbacks(conn_rec *c, nghttp2_session_callbacks **pcb)
#ifdef H2_NG2_INVALID_HEADER_CB
NGH2_SET_CALLBACK(*pcb, on_invalid_header, on_invalid_header_cb);
#endif
+ NGH2_SET_CALLBACK(*pcb, select_padding, select_padding_cb);
return APR_SUCCESS;
}
@@ -862,6 +895,11 @@ apr_status_t h2_session_create(h2_session **psession, conn_rec *c, request_rec *
ap_add_input_filter("H2_IN", session->cin, r, c);
h2_conn_io_init(&session->io, c, s);
+ session->padding_max = h2_config_sgeti(s, H2_CONF_PADDING_BITS);
+ if (session->padding_max) {
+ session->padding_max = (0x01 << session->padding_max) - 1;
+ }
+ session->padding_always = h2_config_sgeti(s, H2_CONF_PADDING_ALWAYS);
session->bbtmp = apr_brigade_create(session->pool, c->bucket_alloc);
status = init_callbacks(c, &callbacks);
diff --git a/modules/http2/h2_session.h b/modules/http2/h2_session.h
index 764da8a21d..cd08fc2429 100644
--- a/modules/http2/h2_session.h
+++ b/modules/http2/h2_session.h
@@ -85,6 +85,8 @@ typedef struct h2_session {
struct h2_workers *workers; /* for executing stream tasks */
struct h2_filter_cin *cin; /* connection input filter context */
h2_conn_io io; /* io on httpd conn filters */
+ int padding_max; /* max number of padding bytes */
+ int padding_always; /* padding has precedence over I/O optimizations */
struct nghttp2_session *ngh2; /* the nghttp2 session (internal use) */
h2_session_state state; /* state session is in */
diff --git a/modules/http2/h2_stream.c b/modules/http2/h2_stream.c
index 3cef6bae05..9b7d2c5655 100644
--- a/modules/http2/h2_stream.c
+++ b/modules/http2/h2_stream.c
@@ -854,7 +854,7 @@ apr_status_t h2_stream_out_prepare(h2_stream *stream, apr_off_t *plen,
* is requested. But we can reduce the size in case the master
* connection operates in smaller chunks. (TSL warmup) */
if (stream->session->io.write_size > 0) {
- max_chunk = stream->session->io.write_size - 9; /* header bits */
+ max_chunk = stream->session->io.write_size - H2_FRAME_HDR_LEN;
}
requested = (*plen > 0)? H2MIN(*plen, max_chunk) : max_chunk;
diff --git a/modules/http2/h2_task.c b/modules/http2/h2_task.c
index 77bcb20d8c..8d3dc6fde8 100644
--- a/modules/http2/h2_task.c
+++ b/modules/http2/h2_task.c
@@ -97,7 +97,7 @@ static apr_status_t send_out(h2_task *task, apr_bucket_brigade* bb, int block)
apr_brigade_length(bb, 0, &written);
H2_TASK_OUT_LOG(APLOG_TRACE2, task, bb, "h2_task send_out");
h2_beam_log(task->output.beam, task->c, APLOG_TRACE2, "send_out(before)");
- /* engines send unblocking */
+
status = h2_beam_send(task->output.beam, bb,
block? APR_BLOCK_READ : APR_NONBLOCK_READ);
h2_beam_log(task->output.beam, task->c, APLOG_TRACE2, "send_out(after)");
@@ -133,26 +133,9 @@ static apr_status_t slave_out(h2_task *task, ap_filter_t* f,
apr_status_t rv = APR_SUCCESS;
int flush = 0, blocking;
- if (task->frozen) {
- h2_util_bb_log(task->c, task->stream_id, APLOG_TRACE2,
- "frozen task output write, ignored", bb);
- while (!APR_BRIGADE_EMPTY(bb)) {
- b = APR_BRIGADE_FIRST(bb);
- if (AP_BUCKET_IS_EOR(b)) {
- APR_BUCKET_REMOVE(b);
- task->eor = b;
- }
- else {
- apr_bucket_delete(b);
- }
- }
- return APR_SUCCESS;
- }
-
send:
- /* we send block once we opened the output, so someone is there
- * reading it *and* the task is not assigned to a h2_req_engine */
- blocking = (!task->assigned && task->output.opened);
+ /* we send block once we opened the output, so someone is there reading it */
+ blocking = task->output.opened;
for (b = APR_BRIGADE_FIRST(bb);
b != APR_BRIGADE_SENTINEL(bb);
b = APR_BUCKET_NEXT(b)) {
@@ -632,18 +615,9 @@ apr_status_t h2_task_do(h2_task *task, apr_thread_t *thread, int worker_id)
task->c->current_thread = thread;
ap_run_process_connection(c);
- if (task->frozen) {
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
- "h2_task(%s): process_conn returned frozen task",
- task->id);
- /* cleanup delayed */
- return APR_EAGAIN;
- }
- else {
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
- "h2_task(%s): processing done", task->id);
- return output_finish(task);
- }
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
+ "h2_task(%s): processing done", task->id);
+ return output_finish(task);
}
static apr_status_t h2_task_process_request(h2_task *task, conn_rec *c)
@@ -681,14 +655,8 @@ static apr_status_t h2_task_process_request(h2_task *task, conn_rec *c)
ap_process_request(r);
- if (task->frozen) {
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
- "h2_task(%s): process_request frozen", task->id);
- }
- else {
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
- "h2_task(%s): process_request done", task->id);
- }
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
+ "h2_task(%s): process_request done", task->id);
/* After the call to ap_process_request, the
* request pool may have been deleted. We set
@@ -740,28 +708,3 @@ static int h2_task_process_conn(conn_rec* c)
return DECLINED;
}
-apr_status_t h2_task_freeze(h2_task *task)
-{
- if (!task->frozen) {
- task->frozen = 1;
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, task->c, APLOGNO(03406)
- "h2_task(%s), frozen", task->id);
- }
- return APR_SUCCESS;
-}
-
-apr_status_t h2_task_thaw(h2_task *task)
-{
- if (task->frozen) {
- task->frozen = 0;
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, task->c, APLOGNO(03407)
- "h2_task(%s), thawed", task->id);
- }
- task->thawed = 1;
- return APR_SUCCESS;
-}
-
-int h2_task_has_thawed(h2_task *task)
-{
- return task->thawed;
-}
diff --git a/modules/http2/h2_task.h b/modules/http2/h2_task.h
index 2624b11118..4121d0fd69 100644
--- a/modules/http2/h2_task.h
+++ b/modules/http2/h2_task.h
@@ -42,7 +42,6 @@ struct h2_bucket_beam;
struct h2_conn;
struct h2_mplx;
struct h2_task;
-struct h2_req_engine;
struct h2_request;
struct h2_response_parser;
struct h2_stream;
@@ -80,8 +79,6 @@ struct h2_task {
struct h2_mplx *mplx;
unsigned int filters_set : 1;
- unsigned int frozen : 1;
- unsigned int thawed : 1;
unsigned int worker_started : 1; /* h2_worker started processing */
int worker_done; /* h2_worker finished */
@@ -90,9 +87,6 @@ struct h2_task {
apr_time_t started_at; /* when processing started */
apr_time_t done_at; /* when processing was done */
apr_bucket *eor;
-
- struct h2_req_engine *engine; /* engine hosted by this task */
- struct h2_req_engine *assigned; /* engine that task has been assigned to */
};
h2_task *h2_task_create(conn_rec *slave, int stream_id,
@@ -122,8 +116,4 @@ apr_status_t h2_task_init(apr_pool_t *pool, server_rec *s);
extern APR_OPTIONAL_FN_TYPE(ap_logio_add_bytes_in) *h2_task_logio_add_bytes_in;
extern APR_OPTIONAL_FN_TYPE(ap_logio_add_bytes_out) *h2_task_logio_add_bytes_out;
-apr_status_t h2_task_freeze(h2_task *task);
-apr_status_t h2_task_thaw(h2_task *task);
-int h2_task_has_thawed(h2_task *task);
-
#endif /* defined(__mod_h2__h2_task__) */
diff --git a/modules/http2/h2_version.h b/modules/http2/h2_version.h
index 5260c2258c..286e98f1ce 100644
--- a/modules/http2/h2_version.h
+++ b/modules/http2/h2_version.h
@@ -27,7 +27,7 @@
* @macro
* Version number of the http2 module as c string
*/
-#define MOD_HTTP2_VERSION "1.12.6-DEV"
+#define MOD_HTTP2_VERSION "1.14.1-git"
/**
* @macro
@@ -35,7 +35,7 @@
* 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 0x010c06
+#define MOD_HTTP2_VERSION_NUM 0x010e01
#endif /* mod_h2_h2_version_h */
diff --git a/modules/http2/mod_http2.c b/modules/http2/mod_http2.c
index 1bcccd28c4..5664f39aa1 100644
--- a/modules/http2/mod_http2.c
+++ b/modules/http2/mod_http2.c
@@ -172,27 +172,6 @@ static char *http2_var_lookup(apr_pool_t *, server_rec *,
conn_rec *, request_rec *, char *name);
static int http2_is_h2(conn_rec *);
-static apr_status_t http2_req_engine_push(const char *ngn_type,
- request_rec *r,
- http2_req_engine_init *einit)
-{
- return h2_mplx_req_engine_push(ngn_type, r, einit);
-}
-
-static apr_status_t http2_req_engine_pull(h2_req_engine *ngn,
- apr_read_type_e block,
- int capacity,
- request_rec **pr)
-{
- return h2_mplx_req_engine_pull(ngn, block, (apr_uint32_t)capacity, pr);
-}
-
-static void http2_req_engine_done(h2_req_engine *ngn, conn_rec *r_conn,
- apr_status_t status)
-{
- h2_mplx_req_engine_done(ngn, r_conn, status);
-}
-
static void http2_get_num_workers(server_rec *s, int *minw, int *maxw)
{
h2_get_num_workers(s, minw, maxw);
@@ -220,9 +199,6 @@ static void h2_hooks(apr_pool_t *pool)
APR_REGISTER_OPTIONAL_FN(http2_is_h2);
APR_REGISTER_OPTIONAL_FN(http2_var_lookup);
- APR_REGISTER_OPTIONAL_FN(http2_req_engine_push);
- APR_REGISTER_OPTIONAL_FN(http2_req_engine_pull);
- APR_REGISTER_OPTIONAL_FN(http2_req_engine_done);
APR_REGISTER_OPTIONAL_FN(http2_get_num_workers);
ap_log_perror(APLOG_MARK, APLOG_TRACE1, 0, pool, "installing hooks");
diff --git a/modules/http2/mod_http2.h b/modules/http2/mod_http2.h
index 7a1b49a455..ba5e6dd121 100644
--- a/modules/http2/mod_http2.h
+++ b/modules/http2/mod_http2.h
@@ -30,22 +30,20 @@ APR_DECLARE_OPTIONAL_FN(int,
/*******************************************************************************
- * HTTP/2 request engines
+ * START HTTP/2 request engines (DEPRECATED)
******************************************************************************/
+
+/* The following functions were introduced for the experimental mod_proxy_http2
+ * support, but have been abandoned since.
+ * They are still declared here for backward compatibiliy, in case someone
+ * tries to build an old mod_proxy_http2 against it, but will disappear
+ * completely sometime in the future.
+ */
struct apr_thread_cond_t;
-
typedef struct h2_req_engine h2_req_engine;
-
typedef void http2_output_consumed(void *ctx, conn_rec *c, apr_off_t consumed);
-/**
- * Initialize a h2_req_engine. The structure will be passed in but
- * only the name and master are set. The function should initialize
- * all fields.
- * @param engine the allocated, partially filled structure
- * @param r the first request to process, or NULL
- */
typedef apr_status_t http2_req_engine_init(h2_req_engine *engine,
const char *id,
const char *type,
@@ -55,35 +53,11 @@ typedef apr_status_t http2_req_engine_init(h2_req_engine *engine,
http2_output_consumed **pconsumed,
void **pbaton);
-/**
- * Push a request to an engine with the specified name for further processing.
- * If no such engine is available, einit is not NULL, einit is called
- * with a new engine record and the caller is responsible for running the
- * new engine instance.
- * @param engine_type the type of the engine to add the request to
- * @param r the request to push to an engine for processing
- * @param einit an optional initialization callback for a new engine
- * of the requested type, should no instance be available.
- * By passing a non-NULL callback, the caller is willing
- * to init and run a new engine itself.
- * @return APR_SUCCESS iff slave was successfully added to an engine
- */
APR_DECLARE_OPTIONAL_FN(apr_status_t,
http2_req_engine_push, (const char *engine_type,
request_rec *r,
http2_req_engine_init *einit));
-/**
- * Get a new request for processing in this engine.
- * @param engine the engine which is done processing the slave
- * @param block if call should block waiting for request to come
- * @param capacity how many parallel requests are acceptable
- * @param pr the request that needs processing or NULL
- * @return APR_SUCCESS if new request was assigned
- * APR_EAGAIN if no new request is available
- * APR_EOF if engine may shut down, as no more request will be scheduled
- * APR_ECONNABORTED if the engine needs to shut down immediately
- */
APR_DECLARE_OPTIONAL_FN(apr_status_t,
http2_req_engine_pull, (h2_req_engine *engine,
apr_read_type_e block,
@@ -98,4 +72,8 @@ APR_DECLARE_OPTIONAL_FN(void,
http2_get_num_workers, (server_rec *s,
int *minw, int *max));
+/*******************************************************************************
+ * END HTTP/2 request engines (DEPRECATED)
+ ******************************************************************************/
+
#endif
diff --git a/modules/http2/mod_proxy_http2.c b/modules/http2/mod_proxy_http2.c
index 15418ded58..95336f7576 100644
--- a/modules/http2/mod_proxy_http2.c
+++ b/modules/http2/mod_proxy_http2.c
@@ -47,20 +47,12 @@ AP_DECLARE_MODULE(proxy_http2) = {
/* Optional functions from mod_http2 */
static int (*is_h2)(conn_rec *c);
-static apr_status_t (*req_engine_push)(const char *name, request_rec *r,
- http2_req_engine_init *einit);
-static apr_status_t (*req_engine_pull)(h2_req_engine *engine,
- apr_read_type_e block,
- int capacity,
- request_rec **pr);
-static void (*req_engine_done)(h2_req_engine *engine, conn_rec *r_conn,
- apr_status_t status);
-
+
typedef struct h2_proxy_ctx {
+ const char *id;
conn_rec *master;
conn_rec *owner;
apr_pool_t *pool;
- request_rec *rbase;
server_rec *server;
const char *proxy_func;
char server_portstr[32];
@@ -68,19 +60,16 @@ typedef struct h2_proxy_ctx {
proxy_worker *worker;
proxy_server_conf *conf;
- h2_req_engine *engine;
- const char *engine_id;
- const char *engine_type;
- apr_pool_t *engine_pool;
apr_size_t req_buffer_size;
- h2_proxy_fifo *requests;
int capacity;
- unsigned standalone : 1;
unsigned is_ssl : 1;
unsigned flushall : 1;
- apr_status_t r_status; /* status of our first request work */
+ request_rec *r; /* the request processed in this ctx */
+ apr_status_t r_status; /* status of request work */
+ int r_done; /* request was processed, not necessarily successfully */
+ int r_may_retry; /* request may be retried */
h2_proxy_session *session; /* current http2 session against backend */
} h2_proxy_ctx;
@@ -106,16 +95,6 @@ static int h2_proxy_post_config(apr_pool_t *p, apr_pool_t *plog,
MOD_HTTP2_VERSION, ngh2? ngh2->version_str : "unknown");
is_h2 = APR_RETRIEVE_OPTIONAL_FN(http2_is_h2);
- req_engine_push = APR_RETRIEVE_OPTIONAL_FN(http2_req_engine_push);
- req_engine_pull = APR_RETRIEVE_OPTIONAL_FN(http2_req_engine_pull);
- req_engine_done = APR_RETRIEVE_OPTIONAL_FN(http2_req_engine_done);
-
- /* we need all of them */
- if (!req_engine_push || !req_engine_pull || !req_engine_done) {
- req_engine_push = NULL;
- req_engine_pull = NULL;
- req_engine_done = NULL;
- }
return status;
}
@@ -206,45 +185,6 @@ static int proxy_http2_canon(request_rec *r, char *url)
return OK;
}
-static void out_consumed(void *baton, conn_rec *c, apr_off_t bytes)
-{
- h2_proxy_ctx *ctx = baton;
-
- if (ctx->session) {
- h2_proxy_session_update_window(ctx->session, c, bytes);
- }
-}
-
-static apr_status_t proxy_engine_init(h2_req_engine *engine,
- const char *id,
- const char *type,
- apr_pool_t *pool,
- apr_size_t req_buffer_size,
- request_rec *r,
- http2_output_consumed **pconsumed,
- void **pctx)
-{
- h2_proxy_ctx *ctx = ap_get_module_config(r->connection->conn_config,
- &proxy_http2_module);
- if (!ctx) {
- ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(03368)
- "h2_proxy_session, engine init, no ctx found");
- return APR_ENOTIMPL;
- }
-
- ctx->pool = pool;
- ctx->engine = engine;
- ctx->engine_id = id;
- ctx->engine_type = type;
- ctx->engine_pool = pool;
- ctx->req_buffer_size = req_buffer_size;
- ctx->capacity = H2MIN(100, h2_proxy_fifo_capacity(ctx->requests));
-
- *pconsumed = out_consumed;
- *pctx = ctx;
- return APR_SUCCESS;
-}
-
static apr_status_t add_request(h2_proxy_session *session, request_rec *r)
{
h2_proxy_ctx *ctx = session->user_data;
@@ -254,7 +194,7 @@ static apr_status_t add_request(h2_proxy_session *session, request_rec *r)
url = apr_table_get(r->notes, H2_PROXY_REQ_URL_NOTE);
apr_table_setn(r->notes, "proxy-source-port", apr_psprintf(r->pool, "%hu",
ctx->p_conn->connection->local_addr->port));
- status = h2_proxy_session_submit(session, url, r, ctx->standalone);
+ status = h2_proxy_session_submit(session, url, r, 1);
if (status != APR_SUCCESS) {
ap_log_cerror(APLOG_MARK, APLOG_ERR, status, r->connection, APLOGNO(03351)
"pass request body failed to %pI (%s) from %s (%s)",
@@ -268,43 +208,15 @@ static apr_status_t add_request(h2_proxy_session *session, request_rec *r)
static void request_done(h2_proxy_ctx *ctx, request_rec *r,
apr_status_t status, int touched)
{
- const char *task_id = apr_table_get(r->connection->notes, H2_TASK_ID_NOTE);
-
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, r->connection,
- "h2_proxy_session(%s): request done %s, touched=%d",
- ctx->engine_id, task_id, touched);
- if (status != APR_SUCCESS) {
- if (!touched) {
- /* untouched request, need rescheduling */
- status = h2_proxy_fifo_push(ctx->requests, r);
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, r->connection,
- APLOGNO(03369)
- "h2_proxy_session(%s): rescheduled request %s",
- ctx->engine_id, task_id);
- return;
- }
- else {
- const char *uri;
- uri = apr_uri_unparse(r->pool, &r->parsed_uri, 0);
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, r->connection,
- APLOGNO(03471) "h2_proxy_session(%s): request %s -> %s "
- "not complete, cannot repeat",
- ctx->engine_id, task_id, uri);
- }
- }
-
- if (r == ctx->rbase) {
+ if (r == ctx->r) {
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, r->connection,
+ "h2_proxy_session(%s): request done, touched=%d",
+ ctx->id, touched);
+ ctx->r_done = 1;
+ if (touched) ctx->r_may_retry = 0;
ctx->r_status = ((status == APR_SUCCESS)? APR_SUCCESS
: HTTP_SERVICE_UNAVAILABLE);
}
-
- if (req_engine_done && ctx->engine) {
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, r->connection,
- APLOGNO(03370)
- "h2_proxy_session(%s): finished request %s",
- ctx->engine_id, task_id);
- req_engine_done(ctx->engine, r->connection, status);
- }
}
static void session_req_done(h2_proxy_session *session, request_rec *r,
@@ -313,43 +225,15 @@ static void session_req_done(h2_proxy_session *session, request_rec *r,
request_done(session->user_data, r, status, touched);
}
-static apr_status_t next_request(h2_proxy_ctx *ctx, int before_leave)
-{
- if (h2_proxy_fifo_count(ctx->requests) > 0) {
- return APR_SUCCESS;
- }
- else if (req_engine_pull && ctx->engine) {
- apr_status_t status;
- request_rec *r = NULL;
-
- status = req_engine_pull(ctx->engine, before_leave?
- APR_BLOCK_READ: APR_NONBLOCK_READ,
- ctx->capacity, &r);
- if (status == APR_SUCCESS && r) {
- ap_log_cerror(APLOG_MARK, APLOG_TRACE3, status, ctx->owner,
- "h2_proxy_engine(%s): pulled request (%s) %s",
- ctx->engine_id,
- before_leave? "before leave" : "regular",
- r->the_request);
- h2_proxy_fifo_push(ctx->requests, r);
- }
- return APR_STATUS_IS_EAGAIN(status)? APR_SUCCESS : status;
- }
- return APR_EOF;
-}
-
-static apr_status_t proxy_engine_run(h2_proxy_ctx *ctx) {
+static apr_status_t ctx_run(h2_proxy_ctx *ctx) {
apr_status_t status = OK;
int h2_front;
- request_rec *r;
/* Step Four: Send the Request in a new HTTP/2 stream and
* loop until we got the response or encounter errors.
*/
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctx->owner,
- "eng(%s): setup session", ctx->engine_id);
h2_front = is_h2? is_h2(ctx->owner) : 0;
- ctx->session = h2_proxy_session_setup(ctx->engine_id, ctx->p_conn, ctx->conf,
+ ctx->session = h2_proxy_session_setup(ctx->id, ctx->p_conn, ctx->conf,
h2_front, 30,
h2_proxy_log2((int)ctx->req_buffer_size),
session_req_done);
@@ -360,45 +244,20 @@ static apr_status_t proxy_engine_run(h2_proxy_ctx *ctx) {
}
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->owner, APLOGNO(03373)
- "eng(%s): run session %s", ctx->engine_id, ctx->session->id);
+ "eng(%s): run session %s", ctx->id, ctx->session->id);
ctx->session->user_data = ctx;
- while (1) {
- if (ctx->master->aborted) {
- status = APR_ECONNABORTED;
- goto out;
- }
-
- if (APR_SUCCESS == h2_proxy_fifo_try_pull(ctx->requests, (void**)&r)) {
- add_request(ctx->session, r);
- }
+ ctx->r_done = 0;
+ add_request(ctx->session, ctx->r);
+
+ while (!ctx->master->aborted && !ctx->r_done) {
+
status = h2_proxy_session_process(ctx->session);
-
- if (status == APR_SUCCESS) {
- /* ongoing processing, check if we have room to handle more streams,
- * maybe the remote side changed their limit */
- if (ctx->session->remote_max_concurrent > 0
- && ctx->session->remote_max_concurrent != ctx->capacity) {
- ctx->capacity = H2MIN((int)ctx->session->remote_max_concurrent,
- h2_proxy_fifo_capacity(ctx->requests));
- }
- /* try to pull more request, if our capacity allows it */
- if (APR_ECONNABORTED == next_request(ctx, 0)) {
- status = APR_ECONNABORTED;
- goto out;
- }
- /* If we have no ongoing streams and nothing in our queue, we
- * terminate processing and return to our caller. */
- if ((h2_proxy_fifo_count(ctx->requests) == 0)
- && h2_proxy_ihash_empty(ctx->session->streams)) {
- goto out;
- }
- }
- else {
+ if (status != APR_SUCCESS) {
/* Encountered an error during session processing */
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, ctx->owner,
APLOGNO(03375) "eng(%s): end of session %s",
- ctx->engine_id, ctx->session->id);
+ ctx->id, ctx->session->id);
/* Any open stream of that session needs to
* a) be reopened on the new session iff safe to do so
* b) reported as done (failed) otherwise
@@ -409,12 +268,11 @@ static apr_status_t proxy_engine_run(h2_proxy_ctx *ctx) {
}
out:
- if (APR_ECONNABORTED == status) {
+ if (ctx->master->aborted) {
/* master connection gone */
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, ctx->owner,
- APLOGNO(03374) "eng(%s): master connection gone", ctx->engine_id);
- /* give notice that we're leaving and cancel all ongoing streams. */
- next_request(ctx, 1);
+ APLOGNO(03374) "eng(%s): master connection gone", ctx->id);
+ /* cancel all ongoing requests */
h2_proxy_session_cancel_all(ctx->session);
h2_proxy_session_process(ctx->session);
if (!ctx->master->aborted) {
@@ -427,49 +285,6 @@ out:
return status;
}
-static apr_status_t push_request_somewhere(h2_proxy_ctx *ctx, request_rec *r)
-{
- conn_rec *c = ctx->owner;
- const char *engine_type, *hostname;
-
- hostname = (ctx->p_conn->ssl_hostname?
- ctx->p_conn->ssl_hostname : ctx->p_conn->hostname);
- engine_type = apr_psprintf(ctx->pool, "proxy_http2 %s%s", hostname,
- ctx->server_portstr);
-
- if (c->master && req_engine_push && r && is_h2 && is_h2(c)) {
- /* If we are have req_engine capabilities, push the handling of this
- * request (e.g. slave connection) to a proxy_http2 engine which
- * uses the same backend. We may be called to create an engine
- * ourself. */
- if (req_engine_push(engine_type, r, proxy_engine_init) == APR_SUCCESS) {
- if (ctx->engine == NULL) {
- /* request has been assigned to an engine in another thread */
- return SUSPENDED;
- }
- }
- }
-
- if (!ctx->engine) {
- /* No engine was available or has been initialized, handle this
- * request just by ourself. */
- ctx->engine_id = apr_psprintf(ctx->pool, "eng-proxy-%ld", c->id);
- ctx->engine_type = engine_type;
- ctx->engine_pool = ctx->pool;
- ctx->req_buffer_size = (32*1024);
- ctx->standalone = 1;
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
- "h2_proxy_http2(%ld): setup standalone engine for type %s",
- c->id, engine_type);
- }
- else {
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
- "H2: hosting engine %s", ctx->engine_id);
- }
-
- return h2_proxy_fifo_push(ctx->requests, r);
-}
-
static int proxy_http2_handler(request_rec *r,
proxy_worker *worker,
proxy_server_conf *conf,
@@ -477,7 +292,7 @@ static int proxy_http2_handler(request_rec *r,
const char *proxyname,
apr_port_t proxyport)
{
- const char *proxy_func;
+ const char *proxy_func, *task_id;
char *locurl = url, *u;
apr_size_t slen;
int is_ssl = 0;
@@ -509,34 +324,35 @@ static int proxy_http2_handler(request_rec *r,
default:
return DECLINED;
}
+
+ task_id = apr_table_get(r->connection->notes, H2_TASK_ID_NOTE);
ctx = apr_pcalloc(r->pool, sizeof(*ctx));
- ctx->master = r->connection->master? r->connection->master : r->connection;
- ctx->owner = r->connection;
- ctx->pool = r->pool;
- ctx->rbase = r;
- ctx->server = r->server;
+ ctx->master = r->connection->master? r->connection->master : r->connection;
+ ctx->id = task_id? task_id : apr_psprintf(r->pool, "%ld", (long)ctx->master->id);
+ ctx->owner = r->connection;
+ ctx->pool = r->pool;
+ ctx->server = r->server;
ctx->proxy_func = proxy_func;
- ctx->is_ssl = is_ssl;
- ctx->worker = worker;
- ctx->conf = conf;
- ctx->flushall = apr_table_get(r->subprocess_env, "proxy-flushall")? 1 : 0;
- ctx->r_status = HTTP_SERVICE_UNAVAILABLE;
-
- h2_proxy_fifo_set_create(&ctx->requests, ctx->pool, 100);
+ ctx->is_ssl = is_ssl;
+ ctx->worker = worker;
+ ctx->conf = conf;
+ ctx->flushall = apr_table_get(r->subprocess_env, "proxy-flushall")? 1 : 0;
+ ctx->req_buffer_size = (32*1024);
+ ctx->r = r;
+ ctx->r_status = status = HTTP_SERVICE_UNAVAILABLE;
+ ctx->r_done = 0;
+ ctx->r_may_retry = 1;
ap_set_module_config(ctx->owner->conn_config, &proxy_http2_module, ctx);
/* scheme says, this is for us. */
- apr_table_setn(ctx->rbase->notes, H2_PROXY_REQ_URL_NOTE, url);
- ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, ctx->rbase,
+ apr_table_setn(ctx->r->notes, H2_PROXY_REQ_URL_NOTE, url);
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, ctx->r,
"H2: serving URL %s", url);
run_connect:
- if (ctx->master->aborted) {
- ctx->r_status = APR_ECONNABORTED;
- goto cleanup;
- }
+ if (ctx->master->aborted) goto cleanup;
/* Get a proxy_conn_rec from the worker, might be a new one, might
* be one still open from another request, or it might fail if the
@@ -551,7 +367,7 @@ run_connect:
/* Step One: Determine the URL to connect to (might be a proxy),
* initialize the backend accordingly and determine the server
* port string we can expect in responses. */
- if ((status = ap_proxy_determine_connection(ctx->pool, ctx->rbase, conf, worker,
+ if ((status = ap_proxy_determine_connection(ctx->pool, ctx->r, conf, worker,
ctx->p_conn, &uri, &locurl,
proxyname, proxyport,
ctx->server_portstr,
@@ -559,17 +375,6 @@ run_connect:
goto cleanup;
}
- /* If we are not already hosting an engine, try to push the request
- * to an already existing engine or host a new engine here. */
- if (r && !ctx->engine) {
- ctx->r_status = push_request_somewhere(ctx, r);
- r = NULL;
- if (ctx->r_status == SUSPENDED) {
- /* request was pushed to another thread, leave processing here */
- goto cleanup;
- }
- }
-
/* Step Two: Make the Connection (or check that an already existing
* socket is still usable). On success, we have a socket connected to
* backend->hostname. */
@@ -578,19 +383,19 @@ run_connect:
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->owner, APLOGNO(03352)
"H2: failed to make connection to backend: %s",
ctx->p_conn->hostname);
- goto reconnect;
+ goto cleanup;
}
/* Step Three: Create conn_rec for the socket we have open now. */
if (!ctx->p_conn->connection) {
- status = ap_proxy_connection_create_ex(ctx->proxy_func,
- ctx->p_conn, ctx->rbase);
+ status = ap_proxy_connection_create_ex(ctx->proxy_func, ctx->p_conn, ctx->r);
if (status != OK) {
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, ctx->owner, APLOGNO(03353)
"setup new connection: is_ssl=%d %s %s %s",
ctx->p_conn->is_ssl, ctx->p_conn->ssl_hostname,
locurl, ctx->p_conn->hostname);
- goto reconnect;
+ ctx->r_status = status;
+ goto cleanup;
}
if (!ctx->p_conn->data && ctx->is_ssl) {
@@ -600,7 +405,7 @@ run_connect:
apr_table_setn(ctx->p_conn->connection->notes,
"proxy-request-alpn-protos", "h2");
if (ctx->p_conn->ssl_hostname) {
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, ctx->owner,
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctx->owner,
"set SNI to %s for (%s)",
ctx->p_conn->ssl_hostname,
ctx->p_conn->hostname);
@@ -610,33 +415,11 @@ run_connect:
}
}
-run_session:
- if (ctx->owner->aborted) {
- ctx->r_status = APR_ECONNABORTED;
- goto cleanup;
- }
-
- status = proxy_engine_run(ctx);
- if (status == APR_SUCCESS) {
- /* session and connection still ok */
- if (next_request(ctx, 1) == APR_SUCCESS) {
- /* more requests, run again */
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->owner, APLOGNO(03376)
- "run_session, again");
- goto run_session;
- }
- /* done */
- ctx->engine = NULL;
- }
-
-reconnect:
- if (ctx->master->aborted) {
- ctx->r_status = APR_ECONNABORTED;
- goto cleanup;
- }
+ if (ctx->master->aborted) goto cleanup;
+ status = ctx_run(ctx);
- if (next_request(ctx, 1) == APR_SUCCESS) {
- /* Still more to do, tear down old conn and start over */
+ if (ctx->r_status != APR_SUCCESS && ctx->r_may_retry && !ctx->master->aborted) {
+ /* Not successfully processed, but may retry, tear down old conn and start over */
if (ctx->p_conn) {
ctx->p_conn->close = 1;
#if AP_MODULE_MAGIC_AT_LEAST(20140207, 2)
@@ -646,12 +429,12 @@ reconnect:
ctx->p_conn = NULL;
}
++reconnects;
- if (reconnects < 5 && !ctx->master->aborted) {
+ if (reconnects < 5) {
goto run_connect;
}
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->owner, APLOGNO(10023)
- "giving up after %d reconnects, %d requests todo",
- reconnects, h2_proxy_fifo_count(ctx->requests));
+ "giving up after %d reconnects, request-done=%d",
+ reconnects, ctx->r_done);
}
cleanup:
@@ -661,17 +444,12 @@ cleanup:
ctx->p_conn->close = 1;
}
#if AP_MODULE_MAGIC_AT_LEAST(20140207, 2)
- proxy_run_detach_backend(ctx->rbase, ctx->p_conn);
+ proxy_run_detach_backend(ctx->r, ctx->p_conn);
#endif
ap_proxy_release_connection(ctx->proxy_func, ctx->p_conn, ctx->server);
ctx->p_conn = NULL;
}
- /* Any requests we still have need to fail */
- while (APR_SUCCESS == h2_proxy_fifo_try_pull(ctx->requests, (void**)&r)) {
- request_done(ctx, r, HTTP_SERVICE_UNAVAILABLE, 1);
- }
-
ap_set_module_config(ctx->owner->conn_config, &proxy_http2_module, NULL);
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, ctx->owner,
APLOGNO(03377) "leaving handler");