mirror of
https://github.com/apache/httpd.git
synced 2025-08-08 15:02:10 +03:00
*) mod_http2: Configuration directoves H2Push and H2Upgrade can now be specified per
Location/Directory, e.g. disabling PUSH for a specific set of resources. [Stefan Eissing] *) mod_http2: HEAD requests to some module such as mod_cgid caused the stream to terminate improperly and cause a HTTP/2 PROTOCOL_ERROR. Fixes <https://github.com/icing/mod_h2/issues/167>. [Michael Kaufmann] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1852339 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
7
CHANGES
7
CHANGES
@@ -1,6 +1,13 @@
|
|||||||
-*- coding: utf-8 -*-
|
-*- coding: utf-8 -*-
|
||||||
Changes with Apache 2.5.1
|
Changes with Apache 2.5.1
|
||||||
|
|
||||||
|
*) mod_http2: Configuration directoves H2Push and H2Upgrade can now be specified per
|
||||||
|
Location/Directory, e.g. disabling PUSH for a specific set of resources. [Stefan Eissing]
|
||||||
|
|
||||||
|
*) mod_http2: HEAD requests to some module such as mod_cgid caused the stream to
|
||||||
|
terminate improperly and cause a HTTP/2 PROTOCOL_ERROR.
|
||||||
|
Fixes <https://github.com/icing/mod_h2/issues/167>. [Michael Kaufmann]
|
||||||
|
|
||||||
*) mod_ssl: give mod_md the chance to override certificate after ALPN protocol
|
*) mod_ssl: give mod_md the chance to override certificate after ALPN protocol
|
||||||
negotiation. [Stefan Eissing]
|
negotiation. [Stefan Eissing]
|
||||||
|
|
||||||
|
@@ -244,6 +244,8 @@ H2Direct on
|
|||||||
<contextlist>
|
<contextlist>
|
||||||
<context>server config</context>
|
<context>server config</context>
|
||||||
<context>virtual host</context>
|
<context>virtual host</context>
|
||||||
|
<context>directory</context>
|
||||||
|
<context>.htaccess</context>
|
||||||
</contextlist>
|
</contextlist>
|
||||||
<compatibility>Available in version 2.4.18 and later.</compatibility>
|
<compatibility>Available in version 2.4.18 and later.</compatibility>
|
||||||
|
|
||||||
@@ -269,7 +271,8 @@ H2Direct on
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Link headers in responses are either set by the application or
|
Link headers in responses are either set by the application or
|
||||||
can be configured via <module>mod_headers</module> as:
|
can be configured via <directive>H2PushResource</directive> or
|
||||||
|
using <module>mod_headers</module> as:
|
||||||
</p>
|
</p>
|
||||||
<example><title>mod_headers example</title>
|
<example><title>mod_headers example</title>
|
||||||
<highlight language="config">
|
<highlight language="config">
|
||||||
@@ -286,9 +289,10 @@ H2Direct on
|
|||||||
twice or more to one client. Use with care.
|
twice or more to one client. Use with care.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
HTTP/2 server pushes are enabled by default. This directive
|
HTTP/2 server pushes are enabled by default. On a server or virtual host,
|
||||||
allows it to be switch off on all resources of this server/virtual
|
you may enable/disable this feature for any connection to the host. In addition,
|
||||||
host.
|
you may disable PUSH for a set of resources in a Directory/Location. This controls
|
||||||
|
which resources may cause a PUSH, not which resources may be sent via PUSH.
|
||||||
</p>
|
</p>
|
||||||
<example><title>Example</title>
|
<example><title>Example</title>
|
||||||
<highlight language="config">
|
<highlight language="config">
|
||||||
@@ -480,6 +484,8 @@ H2PushPriority text/css interleaved # weight 256 default
|
|||||||
<contextlist>
|
<contextlist>
|
||||||
<context>server config</context>
|
<context>server config</context>
|
||||||
<context>virtual host</context>
|
<context>virtual host</context>
|
||||||
|
<context>directory</context>
|
||||||
|
<context>.htaccess</context>
|
||||||
</contextlist>
|
</contextlist>
|
||||||
|
|
||||||
<usage>
|
<usage>
|
||||||
|
@@ -162,5 +162,6 @@ typedef int h2_stream_pri_cmp(int stream_id1, int stream_id2, void *ctx);
|
|||||||
#define H2_FILTER_DEBUG_NOTE "http2-debug"
|
#define H2_FILTER_DEBUG_NOTE "http2-debug"
|
||||||
#define H2_HDR_CONFORMANCE "http2-hdr-conformance"
|
#define H2_HDR_CONFORMANCE "http2-hdr-conformance"
|
||||||
#define H2_HDR_CONFORMANCE_UNSAFE "unsafe"
|
#define H2_HDR_CONFORMANCE_UNSAFE "unsafe"
|
||||||
|
#define H2_PUSH_MODE_NOTE "http2-push-mode"
|
||||||
|
|
||||||
#endif /* defined(__mod_h2__h2__) */
|
#endif /* defined(__mod_h2__h2__) */
|
||||||
|
@@ -75,7 +75,7 @@ h2_alt_svc *h2_alt_svc_parse(const char *s, apr_pool_t *pool)
|
|||||||
|
|
||||||
static int h2_alt_svc_handler(request_rec *r)
|
static int h2_alt_svc_handler(request_rec *r)
|
||||||
{
|
{
|
||||||
const h2_config *cfg;
|
apr_array_header_t *alt_svcs;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (r->connection->keepalives > 0) {
|
if (r->connection->keepalives > 0) {
|
||||||
@@ -87,8 +87,8 @@ static int h2_alt_svc_handler(request_rec *r)
|
|||||||
return DECLINED;
|
return DECLINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg = h2_config_sget(r->server);
|
alt_svcs = h2_config_alt_svcs(r);
|
||||||
if (r->hostname && cfg && cfg->alt_svcs && cfg->alt_svcs->nelts > 0) {
|
if (r->hostname && alt_svcs && alt_svcs->nelts > 0) {
|
||||||
const char *alt_svc_used = apr_table_get(r->headers_in, "Alt-Svc-Used");
|
const char *alt_svc_used = apr_table_get(r->headers_in, "Alt-Svc-Used");
|
||||||
if (!alt_svc_used) {
|
if (!alt_svc_used) {
|
||||||
/* We have alt-svcs defined and client is not already using
|
/* We have alt-svcs defined and client is not already using
|
||||||
@@ -99,7 +99,7 @@ static int h2_alt_svc_handler(request_rec *r)
|
|||||||
const char *alt_svc = "";
|
const char *alt_svc = "";
|
||||||
const char *svc_ma = "";
|
const char *svc_ma = "";
|
||||||
int secure = h2_h2_is_tls(r->connection);
|
int secure = h2_h2_is_tls(r->connection);
|
||||||
int ma = h2_config_geti(cfg, H2_CONF_ALT_SVC_MAX_AGE);
|
int ma = h2_config_rgeti(r, H2_CONF_ALT_SVC_MAX_AGE);
|
||||||
if (ma >= 0) {
|
if (ma >= 0) {
|
||||||
svc_ma = apr_psprintf(r->pool, "; ma=%d", ma);
|
svc_ma = apr_psprintf(r->pool, "; ma=%d", ma);
|
||||||
}
|
}
|
||||||
@@ -107,8 +107,8 @@ static int h2_alt_svc_handler(request_rec *r)
|
|||||||
"h2_alt_svc: announce %s for %s:%d",
|
"h2_alt_svc: announce %s for %s:%d",
|
||||||
(secure? "secure" : "insecure"),
|
(secure? "secure" : "insecure"),
|
||||||
r->hostname, (int)r->server->port);
|
r->hostname, (int)r->server->port);
|
||||||
for (i = 0; i < cfg->alt_svcs->nelts; ++i) {
|
for (i = 0; i < alt_svcs->nelts; ++i) {
|
||||||
h2_alt_svc *as = h2_alt_svc_IDX(cfg->alt_svcs, i);
|
h2_alt_svc *as = h2_alt_svc_IDX(alt_svcs, i);
|
||||||
const char *ahost = as->host;
|
const char *ahost = as->host;
|
||||||
if (ahost && !apr_strnatcasecmp(ahost, r->hostname)) {
|
if (ahost && !apr_strnatcasecmp(ahost, r->hostname)) {
|
||||||
ahost = NULL;
|
ahost = NULL;
|
||||||
|
@@ -42,6 +42,53 @@
|
|||||||
#define H2_CONFIG_GET(a, b, n) \
|
#define H2_CONFIG_GET(a, b, n) \
|
||||||
(((a)->n == DEF_VAL)? (b) : (a))->n
|
(((a)->n == DEF_VAL)? (b) : (a))->n
|
||||||
|
|
||||||
|
#define H2_CONFIG_SET(a, n, v) \
|
||||||
|
((a)->n = v)
|
||||||
|
|
||||||
|
#define CONFIG_CMD_SET(cmd,dir,var,val) \
|
||||||
|
h2_config_seti(((cmd)->path? (dir) : NULL), h2_config_sget((cmd)->server), var, val)
|
||||||
|
|
||||||
|
#define CONFIG_CMD_SET64(cmd,dir,var,val) \
|
||||||
|
h2_config_seti64(((cmd)->path? (dir) : NULL), h2_config_sget((cmd)->server), var, val)
|
||||||
|
|
||||||
|
/* Apache httpd module configuration for h2. */
|
||||||
|
typedef struct h2_config {
|
||||||
|
const char *name;
|
||||||
|
int h2_max_streams; /* max concurrent # streams (http2) */
|
||||||
|
int h2_window_size; /* stream window size (http2) */
|
||||||
|
int min_workers; /* min # of worker threads/child */
|
||||||
|
int max_workers; /* max # of worker threads/child */
|
||||||
|
int max_worker_idle_secs; /* max # of idle seconds for worker */
|
||||||
|
int stream_max_mem_size; /* max # bytes held in memory/stream */
|
||||||
|
apr_array_header_t *alt_svcs; /* h2_alt_svc specs for this server */
|
||||||
|
int alt_svc_max_age; /* seconds clients can rely on alt-svc info*/
|
||||||
|
int serialize_headers; /* Use serialized HTTP/1.1 headers for
|
||||||
|
processing, better compatibility */
|
||||||
|
int h2_direct; /* if mod_h2 is active directly */
|
||||||
|
int modern_tls_only; /* Accept only modern TLS in HTTP/2 connections */
|
||||||
|
int h2_upgrade; /* Allow HTTP/1 upgrade to h2/h2c */
|
||||||
|
apr_int64_t tls_warmup_size; /* Amount of TLS data to send before going full write size */
|
||||||
|
int tls_cooldown_secs; /* Seconds of idle time before going back to small TLS records */
|
||||||
|
int h2_push; /* if HTTP/2 server push is enabled */
|
||||||
|
struct apr_hash_t *priorities;/* map of content-type to h2_priority records */
|
||||||
|
|
||||||
|
int push_diary_size; /* # of entries in push diary */
|
||||||
|
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 */
|
||||||
|
} h2_config;
|
||||||
|
|
||||||
|
typedef struct h2_dir_config {
|
||||||
|
const char *name;
|
||||||
|
apr_array_header_t *alt_svcs; /* h2_alt_svc specs for this server */
|
||||||
|
int alt_svc_max_age; /* seconds clients can rely on alt-svc info*/
|
||||||
|
int h2_upgrade; /* Allow HTTP/1 upgrade to h2/h2c */
|
||||||
|
int h2_push; /* if HTTP/2 server push is enabled */
|
||||||
|
apr_array_header_t *push_list;/* list of h2_push_res configurations */
|
||||||
|
int early_hints; /* support status code 103 */
|
||||||
|
} h2_dir_config;
|
||||||
|
|
||||||
|
|
||||||
static h2_config defconf = {
|
static h2_config defconf = {
|
||||||
"default",
|
"default",
|
||||||
100, /* max_streams */
|
100, /* max_streams */
|
||||||
@@ -66,17 +113,25 @@ static h2_config defconf = {
|
|||||||
0, /* early hints, http status 103 */
|
0, /* early hints, http status 103 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static h2_dir_config defdconf = {
|
||||||
|
"default",
|
||||||
|
NULL, /* no alt-svcs */
|
||||||
|
-1, /* alt-svc max age */
|
||||||
|
-1, /* HTTP/1 Upgrade support */
|
||||||
|
-1, /* HTTP/2 server push enabled */
|
||||||
|
NULL, /* push list */
|
||||||
|
-1, /* early hints, http status 103 */
|
||||||
|
};
|
||||||
|
|
||||||
void h2_config_init(apr_pool_t *pool)
|
void h2_config_init(apr_pool_t *pool)
|
||||||
{
|
{
|
||||||
(void)pool;
|
(void)pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *h2_config_create(apr_pool_t *pool,
|
void *h2_config_create_svr(apr_pool_t *pool, server_rec *s)
|
||||||
const char *prefix, const char *x)
|
|
||||||
{
|
{
|
||||||
h2_config *conf = (h2_config *)apr_pcalloc(pool, sizeof(h2_config));
|
h2_config *conf = (h2_config *)apr_pcalloc(pool, sizeof(h2_config));
|
||||||
const char *s = x? x : "unknown";
|
char *name = apr_pstrcat(pool, "srv[", s->defn_name, "]", NULL);
|
||||||
char *name = apr_pstrcat(pool, prefix, "[", s, "]", NULL);
|
|
||||||
|
|
||||||
conf->name = name;
|
conf->name = name;
|
||||||
conf->h2_max_streams = DEF_VAL;
|
conf->h2_max_streams = DEF_VAL;
|
||||||
@@ -101,16 +156,6 @@ static void *h2_config_create(apr_pool_t *pool,
|
|||||||
return conf;
|
return conf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *h2_config_create_svr(apr_pool_t *pool, server_rec *s)
|
|
||||||
{
|
|
||||||
return h2_config_create(pool, "srv", s->defn_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *h2_config_create_dir(apr_pool_t *pool, char *x)
|
|
||||||
{
|
|
||||||
return h2_config_create(pool, "dir", x);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *h2_config_merge(apr_pool_t *pool, void *basev, void *addv)
|
static void *h2_config_merge(apr_pool_t *pool, void *basev, void *addv)
|
||||||
{
|
{
|
||||||
h2_config *base = (h2_config *)basev;
|
h2_config *base = (h2_config *)basev;
|
||||||
@@ -152,22 +197,47 @@ static void *h2_config_merge(apr_pool_t *pool, void *basev, void *addv)
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *h2_config_merge_dir(apr_pool_t *pool, void *basev, void *addv)
|
|
||||||
{
|
|
||||||
return h2_config_merge(pool, basev, addv);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *h2_config_merge_svr(apr_pool_t *pool, void *basev, void *addv)
|
void *h2_config_merge_svr(apr_pool_t *pool, void *basev, void *addv)
|
||||||
{
|
{
|
||||||
return h2_config_merge(pool, basev, addv);
|
return h2_config_merge(pool, basev, addv);
|
||||||
}
|
}
|
||||||
|
|
||||||
int h2_config_geti(const h2_config *conf, h2_config_var_t var)
|
void *h2_config_create_dir(apr_pool_t *pool, char *x)
|
||||||
{
|
{
|
||||||
return (int)h2_config_geti64(conf, var);
|
h2_dir_config *conf = (h2_dir_config *)apr_pcalloc(pool, sizeof(h2_dir_config));
|
||||||
|
const char *s = x? x : "unknown";
|
||||||
|
char *name = apr_pstrcat(pool, "dir[", s, "]", NULL);
|
||||||
|
|
||||||
|
conf->name = name;
|
||||||
|
conf->alt_svc_max_age = DEF_VAL;
|
||||||
|
conf->h2_upgrade = DEF_VAL;
|
||||||
|
conf->h2_push = DEF_VAL;
|
||||||
|
conf->early_hints = DEF_VAL;
|
||||||
|
return conf;
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_int64_t h2_config_geti64(const h2_config *conf, h2_config_var_t var)
|
void *h2_config_merge_dir(apr_pool_t *pool, void *basev, void *addv)
|
||||||
|
{
|
||||||
|
h2_dir_config *base = (h2_dir_config *)basev;
|
||||||
|
h2_dir_config *add = (h2_dir_config *)addv;
|
||||||
|
h2_dir_config *n = (h2_dir_config *)apr_pcalloc(pool, sizeof(h2_dir_config));
|
||||||
|
|
||||||
|
n->name = apr_pstrcat(pool, "merged[", add->name, ", ", base->name, "]", NULL);
|
||||||
|
n->alt_svcs = add->alt_svcs? add->alt_svcs : base->alt_svcs;
|
||||||
|
n->alt_svc_max_age = H2_CONFIG_GET(add, base, alt_svc_max_age);
|
||||||
|
n->h2_upgrade = H2_CONFIG_GET(add, base, h2_upgrade);
|
||||||
|
n->h2_push = H2_CONFIG_GET(add, base, h2_push);
|
||||||
|
if (add->push_list && base->push_list) {
|
||||||
|
n->push_list = apr_array_append(pool, base->push_list, add->push_list);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
n->push_list = add->push_list? add->push_list : base->push_list;
|
||||||
|
}
|
||||||
|
n->early_hints = H2_CONFIG_GET(add, base, early_hints);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static apr_int64_t h2_srv_config_geti64(const h2_config *conf, h2_config_var_t var)
|
||||||
{
|
{
|
||||||
switch(var) {
|
switch(var) {
|
||||||
case H2_CONF_MAX_STREAMS:
|
case H2_CONF_MAX_STREAMS:
|
||||||
@@ -191,7 +261,8 @@ apr_int64_t h2_config_geti64(const h2_config *conf, h2_config_var_t var)
|
|||||||
case H2_CONF_UPGRADE:
|
case H2_CONF_UPGRADE:
|
||||||
return H2_CONFIG_GET(conf, &defconf, h2_upgrade);
|
return H2_CONFIG_GET(conf, &defconf, h2_upgrade);
|
||||||
case H2_CONF_DIRECT:
|
case H2_CONF_DIRECT:
|
||||||
return H2_CONFIG_GET(conf, &defconf, h2_direct);
|
return 1;
|
||||||
|
/*return H2_CONFIG_GET(conf, &defconf, h2_direct);*/
|
||||||
case H2_CONF_TLS_WARMUP_SIZE:
|
case H2_CONF_TLS_WARMUP_SIZE:
|
||||||
return H2_CONFIG_GET(conf, &defconf, tls_warmup_size);
|
return H2_CONFIG_GET(conf, &defconf, tls_warmup_size);
|
||||||
case H2_CONF_TLS_COOLDOWN_SECS:
|
case H2_CONF_TLS_COOLDOWN_SECS:
|
||||||
@@ -209,7 +280,78 @@ apr_int64_t h2_config_geti64(const h2_config *conf, h2_config_var_t var)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const h2_config *h2_config_sget(server_rec *s)
|
static void h2_srv_config_seti(h2_config *conf, h2_config_var_t var, int val)
|
||||||
|
{
|
||||||
|
switch(var) {
|
||||||
|
case H2_CONF_MAX_STREAMS:
|
||||||
|
H2_CONFIG_SET(conf, h2_max_streams, val);
|
||||||
|
break;
|
||||||
|
case H2_CONF_WIN_SIZE:
|
||||||
|
H2_CONFIG_SET(conf, h2_window_size, val);
|
||||||
|
break;
|
||||||
|
case H2_CONF_MIN_WORKERS:
|
||||||
|
H2_CONFIG_SET(conf, min_workers, val);
|
||||||
|
break;
|
||||||
|
case H2_CONF_MAX_WORKERS:
|
||||||
|
H2_CONFIG_SET(conf, max_workers, val);
|
||||||
|
break;
|
||||||
|
case H2_CONF_MAX_WORKER_IDLE_SECS:
|
||||||
|
H2_CONFIG_SET(conf, max_worker_idle_secs, val);
|
||||||
|
break;
|
||||||
|
case H2_CONF_STREAM_MAX_MEM:
|
||||||
|
H2_CONFIG_SET(conf, stream_max_mem_size, val);
|
||||||
|
break;
|
||||||
|
case H2_CONF_ALT_SVC_MAX_AGE:
|
||||||
|
H2_CONFIG_SET(conf, alt_svc_max_age, val);
|
||||||
|
break;
|
||||||
|
case H2_CONF_SER_HEADERS:
|
||||||
|
H2_CONFIG_SET(conf, serialize_headers, val);
|
||||||
|
break;
|
||||||
|
case H2_CONF_MODERN_TLS_ONLY:
|
||||||
|
H2_CONFIG_SET(conf, modern_tls_only, val);
|
||||||
|
break;
|
||||||
|
case H2_CONF_UPGRADE:
|
||||||
|
H2_CONFIG_SET(conf, h2_upgrade, val);
|
||||||
|
break;
|
||||||
|
case H2_CONF_DIRECT:
|
||||||
|
H2_CONFIG_SET(conf, h2_direct, val);
|
||||||
|
break;
|
||||||
|
case H2_CONF_TLS_WARMUP_SIZE:
|
||||||
|
H2_CONFIG_SET(conf, tls_warmup_size, val);
|
||||||
|
break;
|
||||||
|
case H2_CONF_TLS_COOLDOWN_SECS:
|
||||||
|
H2_CONFIG_SET(conf, tls_cooldown_secs, val);
|
||||||
|
break;
|
||||||
|
case H2_CONF_PUSH:
|
||||||
|
H2_CONFIG_SET(conf, h2_push, val);
|
||||||
|
break;
|
||||||
|
case H2_CONF_PUSH_DIARY_SIZE:
|
||||||
|
H2_CONFIG_SET(conf, push_diary_size, val);
|
||||||
|
break;
|
||||||
|
case H2_CONF_COPY_FILES:
|
||||||
|
H2_CONFIG_SET(conf, copy_files, val);
|
||||||
|
break;
|
||||||
|
case H2_CONF_EARLY_HINTS:
|
||||||
|
H2_CONFIG_SET(conf, early_hints, val);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void h2_srv_config_seti64(h2_config *conf, h2_config_var_t var, apr_int64_t val)
|
||||||
|
{
|
||||||
|
switch(var) {
|
||||||
|
case H2_CONF_TLS_WARMUP_SIZE:
|
||||||
|
H2_CONFIG_SET(conf, tls_warmup_size, val);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
h2_srv_config_seti(conf, var, (int)val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static h2_config *h2_config_sget(server_rec *s)
|
||||||
{
|
{
|
||||||
h2_config *cfg = (h2_config *)ap_get_module_config(s->module_config,
|
h2_config *cfg = (h2_config *)ap_get_module_config(s->module_config,
|
||||||
&http2_module);
|
&http2_module);
|
||||||
@@ -217,9 +359,162 @@ const h2_config *h2_config_sget(server_rec *s)
|
|||||||
return cfg;
|
return cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct h2_priority *h2_config_get_priority(const h2_config *conf,
|
static const h2_dir_config *h2_config_rget(request_rec *r)
|
||||||
const char *content_type)
|
|
||||||
{
|
{
|
||||||
|
h2_dir_config *cfg = (h2_dir_config *)ap_get_module_config(r->per_dir_config,
|
||||||
|
&http2_module);
|
||||||
|
ap_assert(cfg);
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static apr_int64_t h2_dir_config_geti64(const h2_dir_config *conf, h2_config_var_t var)
|
||||||
|
{
|
||||||
|
switch(var) {
|
||||||
|
case H2_CONF_ALT_SVC_MAX_AGE:
|
||||||
|
return H2_CONFIG_GET(conf, &defdconf, alt_svc_max_age);
|
||||||
|
case H2_CONF_UPGRADE:
|
||||||
|
return H2_CONFIG_GET(conf, &defdconf, h2_upgrade);
|
||||||
|
case H2_CONF_PUSH:
|
||||||
|
return H2_CONFIG_GET(conf, &defdconf, h2_push);
|
||||||
|
case H2_CONF_EARLY_HINTS:
|
||||||
|
return H2_CONFIG_GET(conf, &defdconf, early_hints);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return DEF_VAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void h2_config_seti(h2_dir_config *dconf, h2_config *conf, h2_config_var_t var, int val)
|
||||||
|
{
|
||||||
|
int set_srv = !dconf;
|
||||||
|
if (dconf) {
|
||||||
|
switch(var) {
|
||||||
|
case H2_CONF_ALT_SVC_MAX_AGE:
|
||||||
|
H2_CONFIG_SET(dconf, alt_svc_max_age, val);
|
||||||
|
break;
|
||||||
|
case H2_CONF_UPGRADE:
|
||||||
|
H2_CONFIG_SET(dconf, h2_upgrade, val);
|
||||||
|
break;
|
||||||
|
case H2_CONF_PUSH:
|
||||||
|
H2_CONFIG_SET(dconf, h2_push, val);
|
||||||
|
break;
|
||||||
|
case H2_CONF_EARLY_HINTS:
|
||||||
|
H2_CONFIG_SET(dconf, early_hints, val);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* not handled in dir_conf */
|
||||||
|
set_srv = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set_srv) {
|
||||||
|
h2_srv_config_seti(conf, var, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void h2_config_seti64(h2_dir_config *dconf, h2_config *conf, h2_config_var_t var, apr_int64_t val)
|
||||||
|
{
|
||||||
|
int set_srv = !dconf;
|
||||||
|
if (dconf) {
|
||||||
|
switch(var) {
|
||||||
|
default:
|
||||||
|
/* not handled in dir_conf */
|
||||||
|
set_srv = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set_srv) {
|
||||||
|
h2_srv_config_seti64(conf, var, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const h2_config *h2_config_get(conn_rec *c)
|
||||||
|
{
|
||||||
|
h2_ctx *ctx = h2_ctx_get(c, 0);
|
||||||
|
|
||||||
|
if (ctx) {
|
||||||
|
if (ctx->config) {
|
||||||
|
return ctx->config;
|
||||||
|
}
|
||||||
|
else if (ctx->server) {
|
||||||
|
ctx->config = h2_config_sget(ctx->server);
|
||||||
|
return ctx->config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return h2_config_sget(c->base_server);
|
||||||
|
}
|
||||||
|
|
||||||
|
int h2_config_cgeti(conn_rec *c, h2_config_var_t var)
|
||||||
|
{
|
||||||
|
return (int)h2_srv_config_geti64(h2_config_get(c), var);
|
||||||
|
}
|
||||||
|
|
||||||
|
apr_int64_t h2_config_cgeti64(conn_rec *c, h2_config_var_t var)
|
||||||
|
{
|
||||||
|
return h2_srv_config_geti64(h2_config_get(c), var);
|
||||||
|
}
|
||||||
|
|
||||||
|
int h2_config_sgeti(server_rec *s, h2_config_var_t var)
|
||||||
|
{
|
||||||
|
return (int)h2_srv_config_geti64(h2_config_sget(s), var);
|
||||||
|
}
|
||||||
|
|
||||||
|
apr_int64_t h2_config_sgeti64(server_rec *s, h2_config_var_t var)
|
||||||
|
{
|
||||||
|
return h2_srv_config_geti64(h2_config_sget(s), var);
|
||||||
|
}
|
||||||
|
|
||||||
|
int h2_config_geti(request_rec *r, server_rec *s, h2_config_var_t var)
|
||||||
|
{
|
||||||
|
return (int)h2_config_geti64(r, s, var);
|
||||||
|
}
|
||||||
|
|
||||||
|
apr_int64_t h2_config_geti64(request_rec *r, server_rec *s, h2_config_var_t var)
|
||||||
|
{
|
||||||
|
apr_int64_t mode = r? (int)h2_dir_config_geti64(h2_config_rget(r), var) : DEF_VAL;
|
||||||
|
return (mode != DEF_VAL)? mode : h2_config_sgeti64(s, var);
|
||||||
|
}
|
||||||
|
|
||||||
|
int h2_config_rgeti(request_rec *r, h2_config_var_t var)
|
||||||
|
{
|
||||||
|
return h2_config_geti(r, r->server, var);
|
||||||
|
}
|
||||||
|
|
||||||
|
apr_int64_t h2_config_rgeti64(request_rec *r, h2_config_var_t var)
|
||||||
|
{
|
||||||
|
return h2_config_geti64(r, r->server, var);
|
||||||
|
}
|
||||||
|
|
||||||
|
apr_array_header_t *h2_config_push_list(request_rec *r)
|
||||||
|
{
|
||||||
|
const h2_config *sconf;
|
||||||
|
const h2_dir_config *conf = h2_config_rget(r);
|
||||||
|
|
||||||
|
if (conf && conf->push_list) {
|
||||||
|
return conf->push_list;
|
||||||
|
}
|
||||||
|
sconf = h2_config_sget(r->server);
|
||||||
|
return sconf? sconf->push_list : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
apr_array_header_t *h2_config_alt_svcs(request_rec *r)
|
||||||
|
{
|
||||||
|
const h2_config *sconf;
|
||||||
|
const h2_dir_config *conf = h2_config_rget(r);
|
||||||
|
|
||||||
|
if (conf && conf->alt_svcs) {
|
||||||
|
return conf->alt_svcs;
|
||||||
|
}
|
||||||
|
sconf = h2_config_sget(r->server);
|
||||||
|
return sconf? sconf->alt_svcs : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct h2_priority *h2_cconfig_get_priority(conn_rec *c, const char *content_type)
|
||||||
|
{
|
||||||
|
const h2_config *conf = h2_config_get(c);
|
||||||
if (content_type && conf->priorities) {
|
if (content_type && conf->priorities) {
|
||||||
apr_ssize_t len = (apr_ssize_t)strcspn(content_type, "; \t");
|
apr_ssize_t len = (apr_ssize_t)strcspn(content_type, "; \t");
|
||||||
h2_priority *prio = apr_hash_get(conf->priorities, content_type, len);
|
h2_priority *prio = apr_hash_get(conf->priorities, content_type, len);
|
||||||
@@ -228,166 +523,156 @@ const struct h2_priority *h2_config_get_priority(const h2_config *conf,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *h2_conf_set_max_streams(cmd_parms *parms,
|
static const char *h2_conf_set_max_streams(cmd_parms *cmd,
|
||||||
void *arg, const char *value)
|
void *dirconf, const char *value)
|
||||||
{
|
{
|
||||||
h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
|
apr_int64_t ival = (int)apr_atoi64(value);
|
||||||
cfg->h2_max_streams = (int)apr_atoi64(value);
|
if (ival < 1) {
|
||||||
(void)arg;
|
|
||||||
if (cfg->h2_max_streams < 1) {
|
|
||||||
return "value must be > 0";
|
return "value must be > 0";
|
||||||
}
|
}
|
||||||
|
CONFIG_CMD_SET64(cmd, dirconf, H2_CONF_MAX_STREAMS, ival);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *h2_conf_set_window_size(cmd_parms *parms,
|
static const char *h2_conf_set_window_size(cmd_parms *cmd,
|
||||||
void *arg, const char *value)
|
void *dirconf, const char *value)
|
||||||
{
|
{
|
||||||
h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
|
int val = (int)apr_atoi64(value);
|
||||||
cfg->h2_window_size = (int)apr_atoi64(value);
|
if (val < 1024) {
|
||||||
(void)arg;
|
|
||||||
if (cfg->h2_window_size < 1024) {
|
|
||||||
return "value must be >= 1024";
|
return "value must be >= 1024";
|
||||||
}
|
}
|
||||||
|
CONFIG_CMD_SET(cmd, dirconf, H2_CONF_WIN_SIZE, val);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *h2_conf_set_min_workers(cmd_parms *parms,
|
static const char *h2_conf_set_min_workers(cmd_parms *cmd,
|
||||||
void *arg, const char *value)
|
void *dirconf, const char *value)
|
||||||
{
|
{
|
||||||
h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
|
int val = (int)apr_atoi64(value);
|
||||||
cfg->min_workers = (int)apr_atoi64(value);
|
if (val < 1) {
|
||||||
(void)arg;
|
|
||||||
if (cfg->min_workers < 1) {
|
|
||||||
return "value must be > 0";
|
return "value must be > 0";
|
||||||
}
|
}
|
||||||
|
CONFIG_CMD_SET(cmd, dirconf, H2_CONF_MIN_WORKERS, val);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *h2_conf_set_max_workers(cmd_parms *parms,
|
static const char *h2_conf_set_max_workers(cmd_parms *cmd,
|
||||||
void *arg, const char *value)
|
void *dirconf, const char *value)
|
||||||
{
|
{
|
||||||
h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
|
int val = (int)apr_atoi64(value);
|
||||||
cfg->max_workers = (int)apr_atoi64(value);
|
if (val < 1) {
|
||||||
(void)arg;
|
|
||||||
if (cfg->max_workers < 1) {
|
|
||||||
return "value must be > 0";
|
return "value must be > 0";
|
||||||
}
|
}
|
||||||
|
CONFIG_CMD_SET(cmd, dirconf, H2_CONF_MAX_WORKERS, val);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *h2_conf_set_max_worker_idle_secs(cmd_parms *parms,
|
static const char *h2_conf_set_max_worker_idle_secs(cmd_parms *cmd,
|
||||||
void *arg, const char *value)
|
void *dirconf, const char *value)
|
||||||
{
|
{
|
||||||
h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
|
int val = (int)apr_atoi64(value);
|
||||||
cfg->max_worker_idle_secs = (int)apr_atoi64(value);
|
if (val < 1) {
|
||||||
(void)arg;
|
|
||||||
if (cfg->max_worker_idle_secs < 1) {
|
|
||||||
return "value must be > 0";
|
return "value must be > 0";
|
||||||
}
|
}
|
||||||
|
CONFIG_CMD_SET(cmd, dirconf, H2_CONF_MAX_WORKER_IDLE_SECS, val);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *h2_conf_set_stream_max_mem_size(cmd_parms *parms,
|
static const char *h2_conf_set_stream_max_mem_size(cmd_parms *cmd,
|
||||||
void *arg, const char *value)
|
void *dirconf, const char *value)
|
||||||
{
|
{
|
||||||
h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
|
int val = (int)apr_atoi64(value);
|
||||||
|
if (val < 1024) {
|
||||||
|
|
||||||
cfg->stream_max_mem_size = (int)apr_atoi64(value);
|
|
||||||
(void)arg;
|
|
||||||
if (cfg->stream_max_mem_size < 1024) {
|
|
||||||
return "value must be >= 1024";
|
return "value must be >= 1024";
|
||||||
}
|
}
|
||||||
|
CONFIG_CMD_SET(cmd, dirconf, H2_CONF_STREAM_MAX_MEM, val);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *h2_add_alt_svc(cmd_parms *parms,
|
static const char *h2_add_alt_svc(cmd_parms *cmd,
|
||||||
void *arg, const char *value)
|
void *dirconf, const char *value)
|
||||||
{
|
{
|
||||||
if (value && *value) {
|
if (value && *value) {
|
||||||
h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
|
h2_alt_svc *as = h2_alt_svc_parse(value, cmd->pool);
|
||||||
h2_alt_svc *as = h2_alt_svc_parse(value, parms->pool);
|
|
||||||
if (!as) {
|
if (!as) {
|
||||||
return "unable to parse alt-svc specifier";
|
return "unable to parse alt-svc specifier";
|
||||||
}
|
}
|
||||||
if (!cfg->alt_svcs) {
|
|
||||||
cfg->alt_svcs = apr_array_make(parms->pool, 5, sizeof(h2_alt_svc*));
|
if (cmd->path) {
|
||||||
|
h2_dir_config *dcfg = (h2_dir_config *)dirconf;
|
||||||
|
if (!dcfg->alt_svcs) {
|
||||||
|
dcfg->alt_svcs = apr_array_make(cmd->pool, 5, sizeof(h2_alt_svc*));
|
||||||
|
}
|
||||||
|
APR_ARRAY_PUSH(dcfg->alt_svcs, h2_alt_svc*) = as;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
h2_config *cfg = (h2_config *)h2_config_sget(cmd->server);
|
||||||
|
if (!cfg->alt_svcs) {
|
||||||
|
cfg->alt_svcs = apr_array_make(cmd->pool, 5, sizeof(h2_alt_svc*));
|
||||||
|
}
|
||||||
|
APR_ARRAY_PUSH(cfg->alt_svcs, h2_alt_svc*) = as;
|
||||||
}
|
}
|
||||||
APR_ARRAY_PUSH(cfg->alt_svcs, h2_alt_svc*) = as;
|
|
||||||
}
|
}
|
||||||
(void)arg;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *h2_conf_set_alt_svc_max_age(cmd_parms *parms,
|
static const char *h2_conf_set_alt_svc_max_age(cmd_parms *cmd,
|
||||||
void *arg, const char *value)
|
void *dirconf, const char *value)
|
||||||
{
|
{
|
||||||
h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
|
int val = (int)apr_atoi64(value);
|
||||||
cfg->alt_svc_max_age = (int)apr_atoi64(value);
|
CONFIG_CMD_SET(cmd, dirconf, H2_CONF_ALT_SVC_MAX_AGE, val);
|
||||||
(void)arg;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *h2_conf_set_session_extra_files(cmd_parms *parms,
|
static const char *h2_conf_set_session_extra_files(cmd_parms *cmd,
|
||||||
void *arg, const char *value)
|
void *dirconf, const char *value)
|
||||||
{
|
{
|
||||||
/* deprecated, ignore */
|
/* deprecated, ignore */
|
||||||
(void)arg;
|
(void)dirconf;
|
||||||
(void)value;
|
(void)value;
|
||||||
ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, parms->pool, /* NO LOGNO */
|
ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, cmd->pool, /* NO LOGNO */
|
||||||
"H2SessionExtraFiles is obsolete and will be ignored");
|
"H2SessionExtraFiles is obsolete and will be ignored");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *h2_conf_set_serialize_headers(cmd_parms *parms,
|
static const char *h2_conf_set_serialize_headers(cmd_parms *cmd,
|
||||||
void *arg, const char *value)
|
void *dirconf, const char *value)
|
||||||
{
|
{
|
||||||
h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
|
|
||||||
if (!strcasecmp(value, "On")) {
|
if (!strcasecmp(value, "On")) {
|
||||||
cfg->serialize_headers = 1;
|
CONFIG_CMD_SET(cmd, dirconf, H2_CONF_SER_HEADERS, 1);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else if (!strcasecmp(value, "Off")) {
|
else if (!strcasecmp(value, "Off")) {
|
||||||
cfg->serialize_headers = 0;
|
CONFIG_CMD_SET(cmd, dirconf, H2_CONF_SER_HEADERS, 0);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)arg;
|
|
||||||
return "value must be On or Off";
|
return "value must be On or Off";
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *h2_conf_set_direct(cmd_parms *parms,
|
static const char *h2_conf_set_direct(cmd_parms *cmd,
|
||||||
void *arg, const char *value)
|
void *dirconf, const char *value)
|
||||||
{
|
{
|
||||||
h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
|
|
||||||
if (!strcasecmp(value, "On")) {
|
if (!strcasecmp(value, "On")) {
|
||||||
cfg->h2_direct = 1;
|
CONFIG_CMD_SET(cmd, dirconf, H2_CONF_DIRECT, 1);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else if (!strcasecmp(value, "Off")) {
|
else if (!strcasecmp(value, "Off")) {
|
||||||
cfg->h2_direct = 0;
|
CONFIG_CMD_SET(cmd, dirconf, H2_CONF_DIRECT, 0);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)arg;
|
|
||||||
return "value must be On or Off";
|
return "value must be On or Off";
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *h2_conf_set_push(cmd_parms *parms,
|
static const char *h2_conf_set_push(cmd_parms *cmd, void *dirconf, const char *value)
|
||||||
void *arg, const char *value)
|
|
||||||
{
|
{
|
||||||
h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
|
|
||||||
if (!strcasecmp(value, "On")) {
|
if (!strcasecmp(value, "On")) {
|
||||||
cfg->h2_push = 1;
|
CONFIG_CMD_SET(cmd, dirconf, H2_CONF_PUSH, 1);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else if (!strcasecmp(value, "Off")) {
|
else if (!strcasecmp(value, "Off")) {
|
||||||
cfg->h2_push = 0;
|
CONFIG_CMD_SET(cmd, dirconf, H2_CONF_PUSH, 0);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)arg;
|
|
||||||
return "value must be On or Off";
|
return "value must be On or Off";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -448,102 +733,88 @@ static const char *h2_conf_add_push_priority(cmd_parms *cmd, void *_cfg,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *h2_conf_set_modern_tls_only(cmd_parms *parms,
|
static const char *h2_conf_set_modern_tls_only(cmd_parms *cmd,
|
||||||
void *arg, const char *value)
|
void *dirconf, const char *value)
|
||||||
{
|
{
|
||||||
h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
|
|
||||||
if (!strcasecmp(value, "On")) {
|
if (!strcasecmp(value, "On")) {
|
||||||
cfg->modern_tls_only = 1;
|
CONFIG_CMD_SET(cmd, dirconf, H2_CONF_MODERN_TLS_ONLY, 1);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else if (!strcasecmp(value, "Off")) {
|
else if (!strcasecmp(value, "Off")) {
|
||||||
cfg->modern_tls_only = 0;
|
CONFIG_CMD_SET(cmd, dirconf, H2_CONF_MODERN_TLS_ONLY, 0);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)arg;
|
|
||||||
return "value must be On or Off";
|
return "value must be On or Off";
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *h2_conf_set_upgrade(cmd_parms *parms,
|
static const char *h2_conf_set_upgrade(cmd_parms *cmd,
|
||||||
void *arg, const char *value)
|
void *dirconf, const char *value)
|
||||||
{
|
{
|
||||||
h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
|
|
||||||
if (!strcasecmp(value, "On")) {
|
if (!strcasecmp(value, "On")) {
|
||||||
cfg->h2_upgrade = 1;
|
CONFIG_CMD_SET(cmd, dirconf, H2_CONF_UPGRADE, 1);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else if (!strcasecmp(value, "Off")) {
|
else if (!strcasecmp(value, "Off")) {
|
||||||
cfg->h2_upgrade = 0;
|
CONFIG_CMD_SET(cmd, dirconf, H2_CONF_UPGRADE, 0);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)arg;
|
|
||||||
return "value must be On or Off";
|
return "value must be On or Off";
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *h2_conf_set_tls_warmup_size(cmd_parms *parms,
|
static const char *h2_conf_set_tls_warmup_size(cmd_parms *cmd,
|
||||||
void *arg, const char *value)
|
void *dirconf, const char *value)
|
||||||
{
|
{
|
||||||
h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
|
apr_int64_t val = apr_atoi64(value);
|
||||||
cfg->tls_warmup_size = apr_atoi64(value);
|
CONFIG_CMD_SET64(cmd, dirconf, H2_CONF_TLS_WARMUP_SIZE, val);
|
||||||
(void)arg;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *h2_conf_set_tls_cooldown_secs(cmd_parms *parms,
|
static const char *h2_conf_set_tls_cooldown_secs(cmd_parms *cmd,
|
||||||
void *arg, const char *value)
|
void *dirconf, const char *value)
|
||||||
{
|
{
|
||||||
h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
|
apr_int64_t val = (int)apr_atoi64(value);
|
||||||
cfg->tls_cooldown_secs = (int)apr_atoi64(value);
|
CONFIG_CMD_SET64(cmd, dirconf, H2_CONF_TLS_COOLDOWN_SECS, val);
|
||||||
(void)arg;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *h2_conf_set_push_diary_size(cmd_parms *parms,
|
static const char *h2_conf_set_push_diary_size(cmd_parms *cmd,
|
||||||
void *arg, const char *value)
|
void *dirconf, const char *value)
|
||||||
{
|
{
|
||||||
h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
|
int val = (int)apr_atoi64(value);
|
||||||
(void)arg;
|
if (val < 0) {
|
||||||
cfg->push_diary_size = (int)apr_atoi64(value);
|
|
||||||
if (cfg->push_diary_size < 0) {
|
|
||||||
return "value must be >= 0";
|
return "value must be >= 0";
|
||||||
}
|
}
|
||||||
if (cfg->push_diary_size > 0 && (cfg->push_diary_size & (cfg->push_diary_size-1))) {
|
if (val > 0 && (val & (val-1))) {
|
||||||
return "value must a power of 2";
|
return "value must a power of 2";
|
||||||
}
|
}
|
||||||
if (cfg->push_diary_size > (1 << 15)) {
|
if (val > (1 << 15)) {
|
||||||
return "value must <= 65536";
|
return "value must <= 65536";
|
||||||
}
|
}
|
||||||
|
CONFIG_CMD_SET(cmd, dirconf, H2_CONF_PUSH_DIARY_SIZE, val);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *h2_conf_set_copy_files(cmd_parms *parms,
|
static const char *h2_conf_set_copy_files(cmd_parms *cmd,
|
||||||
void *arg, const char *value)
|
void *dirconf, const char *value)
|
||||||
{
|
{
|
||||||
h2_config *cfg = (h2_config *)arg;
|
|
||||||
|
|
||||||
(void)parms;
|
|
||||||
if (!strcasecmp(value, "On")) {
|
if (!strcasecmp(value, "On")) {
|
||||||
cfg->copy_files = 1;
|
CONFIG_CMD_SET(cmd, dirconf, H2_CONF_COPY_FILES, 1);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else if (!strcasecmp(value, "Off")) {
|
else if (!strcasecmp(value, "Off")) {
|
||||||
cfg->copy_files = 0;
|
CONFIG_CMD_SET(cmd, dirconf, H2_CONF_COPY_FILES, 0);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)arg;
|
|
||||||
return "value must be On or Off";
|
return "value must be On or Off";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_push(apr_pool_t *pool, h2_config *conf, h2_push_res *push)
|
static void add_push(apr_array_header_t **plist, apr_pool_t *pool, h2_push_res *push)
|
||||||
{
|
{
|
||||||
h2_push_res *new;
|
h2_push_res *new;
|
||||||
if (!conf->push_list) {
|
if (!*plist) {
|
||||||
conf->push_list = apr_array_make(pool, 10, sizeof(*push));
|
*plist = apr_array_make(pool, 10, sizeof(*push));
|
||||||
}
|
}
|
||||||
new = apr_array_push(conf->push_list);
|
new = apr_array_push(*plist);
|
||||||
new->uri_ref = push->uri_ref;
|
new->uri_ref = push->uri_ref;
|
||||||
new->critical = push->critical;
|
new->critical = push->critical;
|
||||||
}
|
}
|
||||||
@@ -552,8 +823,6 @@ static const char *h2_conf_add_push_res(cmd_parms *cmd, void *dirconf,
|
|||||||
const char *arg1, const char *arg2,
|
const char *arg1, const char *arg2,
|
||||||
const char *arg3)
|
const char *arg3)
|
||||||
{
|
{
|
||||||
h2_config *dconf = (h2_config*)dirconf ;
|
|
||||||
h2_config *sconf = (h2_config*)h2_config_sget(cmd->server);
|
|
||||||
h2_push_res push;
|
h2_push_res push;
|
||||||
const char *last = arg3;
|
const char *last = arg3;
|
||||||
|
|
||||||
@@ -578,42 +847,38 @@ static const char *h2_conf_add_push_res(cmd_parms *cmd, void *dirconf,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* server command? set both */
|
if (cmd->path) {
|
||||||
if (cmd->path == NULL) {
|
add_push(&(((h2_dir_config*)dirconf)->push_list), cmd->pool, &push);
|
||||||
add_push(cmd->pool, sconf, &push);
|
|
||||||
add_push(cmd->pool, dconf, &push);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
add_push(cmd->pool, dconf, &push);
|
add_push(&(h2_config_sget(cmd->server)->push_list), cmd->pool, &push);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *h2_conf_set_early_hints(cmd_parms *parms,
|
static const char *h2_conf_set_early_hints(cmd_parms *cmd,
|
||||||
void *arg, const char *value)
|
void *dirconf, const char *value)
|
||||||
{
|
{
|
||||||
h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
|
int val;
|
||||||
if (!strcasecmp(value, "On")) {
|
|
||||||
cfg->early_hints = 1;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else if (!strcasecmp(value, "Off")) {
|
|
||||||
cfg->early_hints = 0;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
(void)arg;
|
if (!strcasecmp(value, "On")) val = 1;
|
||||||
return "value must be On or Off";
|
else if (!strcasecmp(value, "Off")) val = 0;
|
||||||
|
else return "value must be On or Off";
|
||||||
|
|
||||||
|
CONFIG_CMD_SET(cmd, dirconf, H2_CONF_EARLY_HINTS, val);
|
||||||
|
if (cmd->path) {
|
||||||
|
ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, cmd->pool,
|
||||||
|
"H2EarlyHints = %d on path %s", val, cmd->path);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void h2_get_num_workers(server_rec *s, int *minw, int *maxw)
|
void h2_get_num_workers(server_rec *s, int *minw, int *maxw)
|
||||||
{
|
{
|
||||||
int threads_per_child = 0;
|
int threads_per_child = 0;
|
||||||
const h2_config *config = h2_config_sget(s);
|
|
||||||
|
|
||||||
*minw = h2_config_geti(config, H2_CONF_MIN_WORKERS);
|
*minw = h2_config_sgeti(s, H2_CONF_MIN_WORKERS);
|
||||||
*maxw = h2_config_geti(config, H2_CONF_MAX_WORKERS);
|
*maxw = h2_config_sgeti(s, H2_CONF_MAX_WORKERS);
|
||||||
ap_mpm_query(AP_MPMQ_MAX_THREADS, &threads_per_child);
|
ap_mpm_query(AP_MPMQ_MAX_THREADS, &threads_per_child);
|
||||||
|
|
||||||
if (*minw <= 0) {
|
if (*minw <= 0) {
|
||||||
@@ -655,7 +920,7 @@ const command_rec h2_cmds[] = {
|
|||||||
AP_INIT_TAKE1("H2ModernTLSOnly", h2_conf_set_modern_tls_only, NULL,
|
AP_INIT_TAKE1("H2ModernTLSOnly", h2_conf_set_modern_tls_only, NULL,
|
||||||
RSRC_CONF, "off to not impose RFC 7540 restrictions on TLS"),
|
RSRC_CONF, "off to not impose RFC 7540 restrictions on TLS"),
|
||||||
AP_INIT_TAKE1("H2Upgrade", h2_conf_set_upgrade, NULL,
|
AP_INIT_TAKE1("H2Upgrade", h2_conf_set_upgrade, NULL,
|
||||||
RSRC_CONF, "on to allow HTTP/1 Upgrades to h2/h2c"),
|
RSRC_CONF|OR_AUTHCFG, "on to allow HTTP/1 Upgrades to h2/h2c"),
|
||||||
AP_INIT_TAKE1("H2Direct", h2_conf_set_direct, NULL,
|
AP_INIT_TAKE1("H2Direct", h2_conf_set_direct, NULL,
|
||||||
RSRC_CONF, "on to enable direct HTTP/2 mode"),
|
RSRC_CONF, "on to enable direct HTTP/2 mode"),
|
||||||
AP_INIT_TAKE1("H2SessionExtraFiles", h2_conf_set_session_extra_files, NULL,
|
AP_INIT_TAKE1("H2SessionExtraFiles", h2_conf_set_session_extra_files, NULL,
|
||||||
@@ -665,7 +930,7 @@ const command_rec h2_cmds[] = {
|
|||||||
AP_INIT_TAKE1("H2TLSCoolDownSecs", h2_conf_set_tls_cooldown_secs, NULL,
|
AP_INIT_TAKE1("H2TLSCoolDownSecs", h2_conf_set_tls_cooldown_secs, NULL,
|
||||||
RSRC_CONF, "seconds of idle time on TLS before shrinking writes"),
|
RSRC_CONF, "seconds of idle time on TLS before shrinking writes"),
|
||||||
AP_INIT_TAKE1("H2Push", h2_conf_set_push, NULL,
|
AP_INIT_TAKE1("H2Push", h2_conf_set_push, NULL,
|
||||||
RSRC_CONF, "off to disable HTTP/2 server push"),
|
RSRC_CONF|OR_AUTHCFG, "off to disable HTTP/2 server push"),
|
||||||
AP_INIT_TAKE23("H2PushPriority", h2_conf_add_push_priority, NULL,
|
AP_INIT_TAKE23("H2PushPriority", h2_conf_add_push_priority, NULL,
|
||||||
RSRC_CONF, "define priority of PUSHed resources per content type"),
|
RSRC_CONF, "define priority of PUSHed resources per content type"),
|
||||||
AP_INIT_TAKE1("H2PushDiarySize", h2_conf_set_push_diary_size, NULL,
|
AP_INIT_TAKE1("H2PushDiarySize", h2_conf_set_push_diary_size, NULL,
|
||||||
@@ -673,33 +938,10 @@ const command_rec h2_cmds[] = {
|
|||||||
AP_INIT_TAKE1("H2CopyFiles", h2_conf_set_copy_files, NULL,
|
AP_INIT_TAKE1("H2CopyFiles", h2_conf_set_copy_files, NULL,
|
||||||
OR_FILEINFO, "on to perform copy of file data"),
|
OR_FILEINFO, "on to perform copy of file data"),
|
||||||
AP_INIT_TAKE123("H2PushResource", h2_conf_add_push_res, NULL,
|
AP_INIT_TAKE123("H2PushResource", h2_conf_add_push_res, NULL,
|
||||||
OR_FILEINFO, "add a resource to be pushed in this location/on this server."),
|
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,
|
AP_INIT_TAKE1("H2EarlyHints", h2_conf_set_early_hints, NULL,
|
||||||
RSRC_CONF, "on to enable interim status 103 responses"),
|
RSRC_CONF, "on to enable interim status 103 responses"),
|
||||||
AP_END_CMD
|
AP_END_CMD
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const h2_config *h2_config_rget(request_rec *r)
|
|
||||||
{
|
|
||||||
h2_config *cfg = (h2_config *)ap_get_module_config(r->per_dir_config,
|
|
||||||
&http2_module);
|
|
||||||
return cfg? cfg : h2_config_sget(r->server);
|
|
||||||
}
|
|
||||||
|
|
||||||
const h2_config *h2_config_get(conn_rec *c)
|
|
||||||
{
|
|
||||||
h2_ctx *ctx = h2_ctx_get(c, 0);
|
|
||||||
|
|
||||||
if (ctx) {
|
|
||||||
if (ctx->config) {
|
|
||||||
return ctx->config;
|
|
||||||
}
|
|
||||||
else if (ctx->server) {
|
|
||||||
ctx->config = h2_config_sget(ctx->server);
|
|
||||||
return ctx->config;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return h2_config_sget(c->base_server);
|
|
||||||
}
|
|
||||||
|
@@ -53,33 +53,6 @@ typedef struct h2_push_res {
|
|||||||
int critical;
|
int critical;
|
||||||
} h2_push_res;
|
} h2_push_res;
|
||||||
|
|
||||||
/* Apache httpd module configuration for h2. */
|
|
||||||
typedef struct h2_config {
|
|
||||||
const char *name;
|
|
||||||
int h2_max_streams; /* max concurrent # streams (http2) */
|
|
||||||
int h2_window_size; /* stream window size (http2) */
|
|
||||||
int min_workers; /* min # of worker threads/child */
|
|
||||||
int max_workers; /* max # of worker threads/child */
|
|
||||||
int max_worker_idle_secs; /* max # of idle seconds for worker */
|
|
||||||
int stream_max_mem_size; /* max # bytes held in memory/stream */
|
|
||||||
apr_array_header_t *alt_svcs; /* h2_alt_svc specs for this server */
|
|
||||||
int alt_svc_max_age; /* seconds clients can rely on alt-svc info*/
|
|
||||||
int serialize_headers; /* Use serialized HTTP/1.1 headers for
|
|
||||||
processing, better compatibility */
|
|
||||||
int h2_direct; /* if mod_h2 is active directly */
|
|
||||||
int modern_tls_only; /* Accept only modern TLS in HTTP/2 connections */
|
|
||||||
int h2_upgrade; /* Allow HTTP/1 upgrade to h2/h2c */
|
|
||||||
apr_int64_t tls_warmup_size; /* Amount of TLS data to send before going full write size */
|
|
||||||
int tls_cooldown_secs; /* Seconds of idle time before going back to small TLS records */
|
|
||||||
int h2_push; /* if HTTP/2 server push is enabled */
|
|
||||||
struct apr_hash_t *priorities;/* map of content-type to h2_priority records */
|
|
||||||
|
|
||||||
int push_diary_size; /* # of entries in push diary */
|
|
||||||
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 */
|
|
||||||
} h2_config;
|
|
||||||
|
|
||||||
|
|
||||||
void *h2_config_create_dir(apr_pool_t *pool, char *x);
|
void *h2_config_create_dir(apr_pool_t *pool, char *x);
|
||||||
void *h2_config_merge_dir(apr_pool_t *pool, void *basev, void *addv);
|
void *h2_config_merge_dir(apr_pool_t *pool, void *basev, void *addv);
|
||||||
@@ -88,19 +61,37 @@ void *h2_config_merge_svr(apr_pool_t *pool, void *basev, void *addv);
|
|||||||
|
|
||||||
extern const command_rec h2_cmds[];
|
extern const command_rec h2_cmds[];
|
||||||
|
|
||||||
const h2_config *h2_config_get(conn_rec *c);
|
int h2_config_geti(request_rec *r, server_rec *s, h2_config_var_t var);
|
||||||
const h2_config *h2_config_sget(server_rec *s);
|
apr_int64_t h2_config_geti64(request_rec *r, server_rec *s, h2_config_var_t var);
|
||||||
const h2_config *h2_config_rget(request_rec *r);
|
|
||||||
|
/**
|
||||||
|
* Get the configured value for variable <var> at the given connection.
|
||||||
|
*/
|
||||||
|
int h2_config_cgeti(conn_rec *c, h2_config_var_t var);
|
||||||
|
apr_int64_t h2_config_cgeti64(conn_rec *c, h2_config_var_t var);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the configured value for variable <var> at the given server.
|
||||||
|
*/
|
||||||
|
int h2_config_sgeti(server_rec *s, h2_config_var_t var);
|
||||||
|
apr_int64_t h2_config_sgeti64(server_rec *s, h2_config_var_t var);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the configured value for variable <var> at the given request,
|
||||||
|
* if configured for the request location.
|
||||||
|
* Fallback to request server config otherwise.
|
||||||
|
*/
|
||||||
|
int h2_config_rgeti(request_rec *r, h2_config_var_t var);
|
||||||
|
apr_int64_t h2_config_rgeti64(request_rec *r, h2_config_var_t var);
|
||||||
|
|
||||||
|
apr_array_header_t *h2_config_push_list(request_rec *r);
|
||||||
|
apr_array_header_t *h2_config_alt_svcs(request_rec *r);
|
||||||
|
|
||||||
int h2_config_geti(const h2_config *conf, h2_config_var_t var);
|
|
||||||
apr_int64_t h2_config_geti64(const h2_config *conf, h2_config_var_t var);
|
|
||||||
|
|
||||||
void h2_get_num_workers(server_rec *s, int *minw, int *maxw);
|
void h2_get_num_workers(server_rec *s, int *minw, int *maxw);
|
||||||
|
|
||||||
void h2_config_init(apr_pool_t *pool);
|
void h2_config_init(apr_pool_t *pool);
|
||||||
|
|
||||||
const struct h2_priority *h2_config_get_priority(const h2_config *conf,
|
const struct h2_priority *h2_cconfig_get_priority(conn_rec *c, const char *content_type);
|
||||||
const char *content_type);
|
|
||||||
|
|
||||||
#endif /* __mod_h2__h2_config_h__ */
|
#endif /* __mod_h2__h2_config_h__ */
|
||||||
|
|
||||||
|
@@ -110,7 +110,6 @@ static void check_modules(int force)
|
|||||||
|
|
||||||
apr_status_t h2_conn_child_init(apr_pool_t *pool, server_rec *s)
|
apr_status_t h2_conn_child_init(apr_pool_t *pool, server_rec *s)
|
||||||
{
|
{
|
||||||
const h2_config *config = h2_config_sget(s);
|
|
||||||
apr_status_t status = APR_SUCCESS;
|
apr_status_t status = APR_SUCCESS;
|
||||||
int minw, maxw;
|
int minw, maxw;
|
||||||
int max_threads_per_child = 0;
|
int max_threads_per_child = 0;
|
||||||
@@ -130,7 +129,7 @@ apr_status_t h2_conn_child_init(apr_pool_t *pool, server_rec *s)
|
|||||||
|
|
||||||
h2_get_num_workers(s, &minw, &maxw);
|
h2_get_num_workers(s, &minw, &maxw);
|
||||||
|
|
||||||
idle_secs = h2_config_geti(config, H2_CONF_MAX_WORKER_IDLE_SECS);
|
idle_secs = h2_config_sgeti(s, H2_CONF_MAX_WORKER_IDLE_SECS);
|
||||||
ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s,
|
ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s,
|
||||||
"h2_workers: min=%d max=%d, mthrpchild=%d, idle_secs=%d",
|
"h2_workers: min=%d max=%d, mthrpchild=%d, idle_secs=%d",
|
||||||
minw, maxw, max_threads_per_child, idle_secs);
|
minw, maxw, max_threads_per_child, idle_secs);
|
||||||
@@ -173,9 +172,10 @@ static module *h2_conn_mpm_module(void)
|
|||||||
return mpm_module;
|
return mpm_module;
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_status_t h2_conn_setup(h2_ctx *ctx, conn_rec *c, request_rec *r)
|
apr_status_t h2_conn_setup(conn_rec *c, request_rec *r, server_rec *s)
|
||||||
{
|
{
|
||||||
h2_session *session;
|
h2_session *session;
|
||||||
|
h2_ctx *ctx;
|
||||||
apr_status_t status;
|
apr_status_t status;
|
||||||
|
|
||||||
if (!workers) {
|
if (!workers) {
|
||||||
@@ -184,24 +184,19 @@ apr_status_t h2_conn_setup(h2_ctx *ctx, conn_rec *c, request_rec *r)
|
|||||||
return APR_EGENERAL;
|
return APR_EGENERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r) {
|
if (APR_SUCCESS == (status = h2_session_create(&session, c, r, s, workers))) {
|
||||||
status = h2_session_rcreate(&session, r, ctx, workers);
|
ctx = h2_ctx_get(c, 1);
|
||||||
}
|
|
||||||
else {
|
|
||||||
status = h2_session_create(&session, c, ctx, workers);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status == APR_SUCCESS) {
|
|
||||||
h2_ctx_session_set(ctx, session);
|
h2_ctx_session_set(ctx, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_status_t h2_conn_run(struct h2_ctx *ctx, conn_rec *c)
|
apr_status_t h2_conn_run(conn_rec *c)
|
||||||
{
|
{
|
||||||
apr_status_t status;
|
apr_status_t status;
|
||||||
int mpm_state = 0;
|
int mpm_state = 0;
|
||||||
h2_session *session = h2_ctx_session_get(ctx);
|
h2_session *session = h2_ctx_get_session(c);
|
||||||
|
|
||||||
ap_assert(session);
|
ap_assert(session);
|
||||||
do {
|
do {
|
||||||
@@ -250,7 +245,7 @@ apr_status_t h2_conn_run(struct h2_ctx *ctx, conn_rec *c)
|
|||||||
|
|
||||||
apr_status_t h2_conn_pre_close(struct h2_ctx *ctx, conn_rec *c)
|
apr_status_t h2_conn_pre_close(struct h2_ctx *ctx, conn_rec *c)
|
||||||
{
|
{
|
||||||
h2_session *session = h2_ctx_session_get(ctx);
|
h2_session *session = h2_ctx_get_session(c);
|
||||||
|
|
||||||
(void)c;
|
(void)c;
|
||||||
if (session) {
|
if (session) {
|
||||||
|
@@ -23,21 +23,21 @@ struct h2_task;
|
|||||||
/**
|
/**
|
||||||
* Setup the connection and our context for HTTP/2 processing
|
* Setup the connection and our context for HTTP/2 processing
|
||||||
*
|
*
|
||||||
* @param ctx the http2 context to setup
|
|
||||||
* @param c the connection HTTP/2 is starting on
|
* @param c the connection HTTP/2 is starting on
|
||||||
* @param r the upgrade request that still awaits an answer, optional
|
* @param r the upgrade request that still awaits an answer, optional
|
||||||
|
* @param s the server selected for this connection (can be != c->base_server)
|
||||||
*/
|
*/
|
||||||
apr_status_t h2_conn_setup(struct h2_ctx *ctx, conn_rec *c, request_rec *r);
|
apr_status_t h2_conn_setup(conn_rec *c, request_rec *r, server_rec *s);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run the HTTP/2 connection in synchronous fashion.
|
* Run the HTTP/2 connection in synchronous fashion.
|
||||||
* Return when the HTTP/2 session is done
|
* Return when the HTTP/2 session is done
|
||||||
* and the connection will close or a fatal error occurred.
|
* and the connection will close or a fatal error occurred.
|
||||||
*
|
*
|
||||||
* @param ctx the http2 context to run
|
* @param c the http2 connection to run
|
||||||
* @return APR_SUCCESS when session is done.
|
* @return APR_SUCCESS when session is done.
|
||||||
*/
|
*/
|
||||||
apr_status_t h2_conn_run(struct h2_ctx *ctx, conn_rec *c);
|
apr_status_t h2_conn_run(conn_rec *c);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The connection is about to close. If we have not send a GOAWAY
|
* The connection is about to close. If we have not send a GOAWAY
|
||||||
|
@@ -124,21 +124,20 @@ static void h2_conn_io_bb_log(conn_rec *c, int stream_id, int level,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c,
|
apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c, server_rec *s)
|
||||||
const h2_config *cfg)
|
|
||||||
{
|
{
|
||||||
io->c = c;
|
io->c = c;
|
||||||
io->output = apr_brigade_create(c->pool, c->bucket_alloc);
|
io->output = apr_brigade_create(c->pool, c->bucket_alloc);
|
||||||
io->is_tls = h2_h2_is_tls(c);
|
io->is_tls = h2_h2_is_tls(c);
|
||||||
io->buffer_output = io->is_tls;
|
io->buffer_output = io->is_tls;
|
||||||
io->flush_threshold = (apr_size_t)h2_config_geti64(cfg, H2_CONF_STREAM_MAX_MEM);
|
io->flush_threshold = (apr_size_t)h2_config_sgeti64(s, H2_CONF_STREAM_MAX_MEM);
|
||||||
|
|
||||||
if (io->is_tls) {
|
if (io->is_tls) {
|
||||||
/* This is what we start with,
|
/* This is what we start with,
|
||||||
* see https://issues.apache.org/jira/browse/TS-2503
|
* see https://issues.apache.org/jira/browse/TS-2503
|
||||||
*/
|
*/
|
||||||
io->warmup_size = h2_config_geti64(cfg, H2_CONF_TLS_WARMUP_SIZE);
|
io->warmup_size = h2_config_sgeti64(s, H2_CONF_TLS_WARMUP_SIZE);
|
||||||
io->cooldown_usecs = (h2_config_geti(cfg, H2_CONF_TLS_COOLDOWN_SECS)
|
io->cooldown_usecs = (h2_config_sgeti(s, H2_CONF_TLS_COOLDOWN_SECS)
|
||||||
* APR_USEC_PER_SEC);
|
* APR_USEC_PER_SEC);
|
||||||
io->write_size = (io->cooldown_usecs > 0?
|
io->write_size = (io->cooldown_usecs > 0?
|
||||||
WRITE_SIZE_INITIAL : WRITE_SIZE_MAX);
|
WRITE_SIZE_INITIAL : WRITE_SIZE_MAX);
|
||||||
|
@@ -48,8 +48,7 @@ typedef struct {
|
|||||||
apr_size_t slen;
|
apr_size_t slen;
|
||||||
} h2_conn_io;
|
} h2_conn_io;
|
||||||
|
|
||||||
apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c,
|
apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c, server_rec *s);
|
||||||
const struct h2_config *cfg);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append data to the buffered output.
|
* Append data to the buffered output.
|
||||||
|
@@ -29,8 +29,8 @@ static h2_ctx *h2_ctx_create(const conn_rec *c)
|
|||||||
{
|
{
|
||||||
h2_ctx *ctx = apr_pcalloc(c->pool, sizeof(h2_ctx));
|
h2_ctx *ctx = apr_pcalloc(c->pool, sizeof(h2_ctx));
|
||||||
ap_assert(ctx);
|
ap_assert(ctx);
|
||||||
|
h2_ctx_server_update(ctx, c->base_server);
|
||||||
ap_set_module_config(c->conn_config, &http2_module, ctx);
|
ap_set_module_config(c->conn_config, &http2_module, ctx);
|
||||||
h2_ctx_server_set(ctx, c->base_server);
|
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,8 +79,9 @@ h2_ctx *h2_ctx_protocol_set(h2_ctx *ctx, const char *proto)
|
|||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2_session *h2_ctx_session_get(h2_ctx *ctx)
|
h2_session *h2_ctx_get_session(conn_rec *c)
|
||||||
{
|
{
|
||||||
|
h2_ctx *ctx = h2_ctx_get(c, 0);
|
||||||
return ctx? ctx->session : NULL;
|
return ctx? ctx->session : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,33 +90,17 @@ void h2_ctx_session_set(h2_ctx *ctx, struct h2_session *session)
|
|||||||
ctx->session = session;
|
ctx->session = session;
|
||||||
}
|
}
|
||||||
|
|
||||||
server_rec *h2_ctx_server_get(h2_ctx *ctx)
|
h2_ctx *h2_ctx_server_update(h2_ctx *ctx, server_rec *s)
|
||||||
{
|
{
|
||||||
return ctx? ctx->server : NULL;
|
if (ctx->server != s) {
|
||||||
}
|
ctx->server = s;
|
||||||
|
}
|
||||||
h2_ctx *h2_ctx_server_set(h2_ctx *ctx, server_rec *s)
|
|
||||||
{
|
|
||||||
ctx->server = s;
|
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
int h2_ctx_is_task(h2_ctx *ctx)
|
h2_task *h2_ctx_get_task(conn_rec *c)
|
||||||
{
|
|
||||||
return ctx && ctx->task;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2_task *h2_ctx_get_task(h2_ctx *ctx)
|
|
||||||
{
|
{
|
||||||
|
h2_ctx *ctx = h2_ctx_get(c, 0);
|
||||||
return ctx? ctx->task : NULL;
|
return ctx? ctx->task : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2_task *h2_ctx_cget_task(conn_rec *c)
|
|
||||||
{
|
|
||||||
return h2_ctx_get_task(h2_ctx_get(c, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
h2_task *h2_ctx_rget_task(request_rec *r)
|
|
||||||
{
|
|
||||||
return h2_ctx_get_task(h2_ctx_rget(r));
|
|
||||||
}
|
|
||||||
|
@@ -56,12 +56,11 @@ h2_ctx *h2_ctx_create_for(const conn_rec *c, struct h2_task *task);
|
|||||||
*/
|
*/
|
||||||
h2_ctx *h2_ctx_protocol_set(h2_ctx *ctx, const char *proto);
|
h2_ctx *h2_ctx_protocol_set(h2_ctx *ctx, const char *proto);
|
||||||
|
|
||||||
/* Set the server_rec relevant for this context.
|
/* Update the server_rec relevant for this context. A server for
|
||||||
|
* a connection may change during SNI handling, for example.
|
||||||
*/
|
*/
|
||||||
h2_ctx *h2_ctx_server_set(h2_ctx *ctx, server_rec *s);
|
h2_ctx *h2_ctx_server_update(h2_ctx *ctx, server_rec *s);
|
||||||
server_rec *h2_ctx_server_get(h2_ctx *ctx);
|
|
||||||
|
|
||||||
struct h2_session *h2_ctx_session_get(h2_ctx *ctx);
|
|
||||||
void h2_ctx_session_set(h2_ctx *ctx, struct h2_session *session);
|
void h2_ctx_session_set(h2_ctx *ctx, struct h2_session *session);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,10 +68,8 @@ void h2_ctx_session_set(h2_ctx *ctx, struct h2_session *session);
|
|||||||
*/
|
*/
|
||||||
const char *h2_ctx_protocol_get(const conn_rec *c);
|
const char *h2_ctx_protocol_get(const conn_rec *c);
|
||||||
|
|
||||||
int h2_ctx_is_task(h2_ctx *ctx);
|
struct h2_session *h2_ctx_get_session(conn_rec *c);
|
||||||
|
struct h2_task *h2_ctx_get_task(conn_rec *c);
|
||||||
|
|
||||||
struct h2_task *h2_ctx_get_task(h2_ctx *ctx);
|
|
||||||
struct h2_task *h2_ctx_cget_task(conn_rec *c);
|
|
||||||
struct h2_task *h2_ctx_rget_task(request_rec *r);
|
|
||||||
|
|
||||||
#endif /* defined(__mod_h2__h2_ctx__) */
|
#endif /* defined(__mod_h2__h2_ctx__) */
|
||||||
|
@@ -313,8 +313,7 @@ static void add_settings(apr_bucket_brigade *bb, h2_session *s, int last)
|
|||||||
bbout(bb, " \"settings\": {\n");
|
bbout(bb, " \"settings\": {\n");
|
||||||
bbout(bb, " \"SETTINGS_MAX_CONCURRENT_STREAMS\": %d,\n", m->max_streams);
|
bbout(bb, " \"SETTINGS_MAX_CONCURRENT_STREAMS\": %d,\n", m->max_streams);
|
||||||
bbout(bb, " \"SETTINGS_MAX_FRAME_SIZE\": %d,\n", 16*1024);
|
bbout(bb, " \"SETTINGS_MAX_FRAME_SIZE\": %d,\n", 16*1024);
|
||||||
bbout(bb, " \"SETTINGS_INITIAL_WINDOW_SIZE\": %d,\n",
|
bbout(bb, " \"SETTINGS_INITIAL_WINDOW_SIZE\": %d,\n", h2_config_sgeti(s->s, H2_CONF_WIN_SIZE));
|
||||||
h2_config_geti(s->config, H2_CONF_WIN_SIZE));
|
|
||||||
bbout(bb, " \"SETTINGS_ENABLE_PUSH\": %d\n", h2_session_push_enabled(s));
|
bbout(bb, " \"SETTINGS_ENABLE_PUSH\": %d\n", h2_session_push_enabled(s));
|
||||||
bbout(bb, " }%s\n", last? "" : ",");
|
bbout(bb, " }%s\n", last? "" : ",");
|
||||||
}
|
}
|
||||||
@@ -496,7 +495,6 @@ static apr_status_t status_event(void *ctx, h2_bucket_event event,
|
|||||||
|
|
||||||
int h2_filter_h2_status_handler(request_rec *r)
|
int h2_filter_h2_status_handler(request_rec *r)
|
||||||
{
|
{
|
||||||
h2_ctx *ctx = h2_ctx_rget(r);
|
|
||||||
conn_rec *c = r->connection;
|
conn_rec *c = r->connection;
|
||||||
h2_task *task;
|
h2_task *task;
|
||||||
apr_bucket_brigade *bb;
|
apr_bucket_brigade *bb;
|
||||||
@@ -510,7 +508,7 @@ int h2_filter_h2_status_handler(request_rec *r)
|
|||||||
return DECLINED;
|
return DECLINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
task = ctx? h2_ctx_get_task(ctx) : NULL;
|
task = h2_ctx_get_task(r->connection);
|
||||||
if (task) {
|
if (task) {
|
||||||
|
|
||||||
if ((status = ap_discard_request_body(r)) != OK) {
|
if ((status = ap_discard_request_body(r)) != OK) {
|
||||||
|
@@ -594,9 +594,9 @@ apr_status_t h2_filter_headers_out(ap_filter_t *f, apr_bucket_brigade *bb)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r->header_only) {
|
if (r->header_only || AP_STATUS_IS_HEADER_ONLY(r->status)) {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
|
||||||
"h2_task(%s): header_only, cleanup output brigade",
|
"h2_task(%s): headers only, cleanup output brigade",
|
||||||
task->id);
|
task->id);
|
||||||
b = body_bucket? body_bucket : APR_BRIGADE_FIRST(bb);
|
b = body_bucket? body_bucket : APR_BRIGADE_FIRST(bb);
|
||||||
while (b != APR_BRIGADE_SENTINEL(bb)) {
|
while (b != APR_BRIGADE_SENTINEL(bb)) {
|
||||||
@@ -604,8 +604,10 @@ apr_status_t h2_filter_headers_out(ap_filter_t *f, apr_bucket_brigade *bb)
|
|||||||
if (APR_BUCKET_IS_EOS(b) || AP_BUCKET_IS_EOR(b)) {
|
if (APR_BUCKET_IS_EOS(b) || AP_BUCKET_IS_EOR(b)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
APR_BUCKET_REMOVE(b);
|
if (!H2_BUCKET_IS_HEADERS(b)) {
|
||||||
apr_bucket_destroy(b);
|
APR_BUCKET_REMOVE(b);
|
||||||
|
apr_bucket_destroy(b);
|
||||||
|
}
|
||||||
b = next;
|
b = next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -463,12 +463,11 @@ int h2_h2_is_tls(conn_rec *c)
|
|||||||
return opt_ssl_is_https && opt_ssl_is_https(c);
|
return opt_ssl_is_https && opt_ssl_is_https(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
int h2_is_acceptable_connection(conn_rec *c, int require_all)
|
int h2_is_acceptable_connection(conn_rec *c, request_rec *r, int require_all)
|
||||||
{
|
{
|
||||||
int is_tls = h2_h2_is_tls(c);
|
int is_tls = h2_h2_is_tls(c);
|
||||||
const h2_config *cfg = h2_config_get(c);
|
|
||||||
|
|
||||||
if (is_tls && h2_config_geti(cfg, H2_CONF_MODERN_TLS_ONLY) > 0) {
|
if (is_tls && h2_config_cgeti(c, H2_CONF_MODERN_TLS_ONLY) > 0) {
|
||||||
/* Check TLS connection for modern TLS parameters, as defined in
|
/* Check TLS connection for modern TLS parameters, as defined in
|
||||||
* RFC 7540 and https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
|
* RFC 7540 and https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
|
||||||
*/
|
*/
|
||||||
@@ -521,26 +520,22 @@ int h2_is_acceptable_connection(conn_rec *c, int require_all)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int h2_allows_h2_direct(conn_rec *c)
|
static int h2_allows_h2_direct(conn_rec *c)
|
||||||
{
|
{
|
||||||
const h2_config *cfg = h2_config_get(c);
|
|
||||||
int is_tls = h2_h2_is_tls(c);
|
int is_tls = h2_h2_is_tls(c);
|
||||||
const char *needed_protocol = is_tls? "h2" : "h2c";
|
const char *needed_protocol = is_tls? "h2" : "h2c";
|
||||||
int h2_direct = h2_config_geti(cfg, H2_CONF_DIRECT);
|
int h2_direct = h2_config_cgeti(c, H2_CONF_DIRECT);
|
||||||
|
|
||||||
if (h2_direct < 0) {
|
if (h2_direct < 0) {
|
||||||
h2_direct = is_tls? 0 : 1;
|
h2_direct = is_tls? 0 : 1;
|
||||||
}
|
}
|
||||||
return (h2_direct
|
return (h2_direct && ap_is_allowed_protocol(c, NULL, NULL, needed_protocol));
|
||||||
&& ap_is_allowed_protocol(c, NULL, NULL, needed_protocol));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int h2_allows_h2_upgrade(conn_rec *c)
|
int h2_allows_h2_upgrade(request_rec *r)
|
||||||
{
|
{
|
||||||
const h2_config *cfg = h2_config_get(c);
|
int h2_upgrade = h2_config_rgeti(r, H2_CONF_UPGRADE);
|
||||||
int h2_upgrade = h2_config_geti(cfg, H2_CONF_UPGRADE);
|
return h2_upgrade > 0 || (h2_upgrade < 0 && !h2_h2_is_tls(r->connection));
|
||||||
|
|
||||||
return h2_upgrade > 0 || (h2_upgrade < 0 && !h2_h2_is_tls(c));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@@ -581,14 +576,17 @@ int h2_h2_process_conn(conn_rec* c)
|
|||||||
{
|
{
|
||||||
apr_status_t status;
|
apr_status_t status;
|
||||||
h2_ctx *ctx;
|
h2_ctx *ctx;
|
||||||
|
server_rec *s;
|
||||||
|
|
||||||
if (c->master) {
|
if (c->master) {
|
||||||
return DECLINED;
|
return DECLINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = h2_ctx_get(c, 0);
|
ctx = h2_ctx_get(c, 0);
|
||||||
|
s = ctx? ctx->server : c->base_server;
|
||||||
|
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, process_conn");
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, process_conn");
|
||||||
if (h2_ctx_is_task(ctx)) {
|
if (ctx && ctx->task) {
|
||||||
/* our stream pseudo connection */
|
/* our stream pseudo connection */
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_h2, task, declined");
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_h2, task, declined");
|
||||||
return DECLINED;
|
return DECLINED;
|
||||||
@@ -601,19 +599,19 @@ int h2_h2_process_conn(conn_rec* c)
|
|||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, process_conn, "
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, process_conn, "
|
||||||
"new connection using protocol '%s', direct=%d, "
|
"new connection using protocol '%s', direct=%d, "
|
||||||
"tls acceptable=%d", proto, h2_allows_h2_direct(c),
|
"tls acceptable=%d", proto, h2_allows_h2_direct(c),
|
||||||
h2_is_acceptable_connection(c, 1));
|
h2_is_acceptable_connection(c, NULL, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(AP_PROTOCOL_HTTP1, proto)
|
if (!strcmp(AP_PROTOCOL_HTTP1, proto)
|
||||||
&& h2_allows_h2_direct(c)
|
&& h2_allows_h2_direct(c)
|
||||||
&& h2_is_acceptable_connection(c, 1)) {
|
&& h2_is_acceptable_connection(c, NULL, 1)) {
|
||||||
/* Fresh connection still is on http/1.1 and H2Direct is enabled.
|
/* Fresh connection still is on http/1.1 and H2Direct is enabled.
|
||||||
* Otherwise connection is in a fully acceptable state.
|
* Otherwise connection is in a fully acceptable state.
|
||||||
* -> peek at the first 24 incoming bytes
|
* -> peek at the first 24 incoming bytes
|
||||||
*/
|
*/
|
||||||
apr_bucket_brigade *temp;
|
apr_bucket_brigade *temp;
|
||||||
char *s = NULL;
|
char *peek = NULL;
|
||||||
apr_size_t slen;
|
apr_size_t peeklen;
|
||||||
|
|
||||||
temp = apr_brigade_create(c->pool, c->bucket_alloc);
|
temp = apr_brigade_create(c->pool, c->bucket_alloc);
|
||||||
status = ap_get_brigade(c->input_filters, temp,
|
status = ap_get_brigade(c->input_filters, temp,
|
||||||
@@ -626,8 +624,8 @@ int h2_h2_process_conn(conn_rec* c)
|
|||||||
return DECLINED;
|
return DECLINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_brigade_pflatten(temp, &s, &slen, c->pool);
|
apr_brigade_pflatten(temp, &peek, &peeklen, c->pool);
|
||||||
if ((slen >= 24) && !memcmp(H2_MAGIC_TOKEN, s, 24)) {
|
if ((peeklen >= 24) && !memcmp(H2_MAGIC_TOKEN, peek, 24)) {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
||||||
"h2_h2, direct mode detected");
|
"h2_h2, direct mode detected");
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
@@ -638,7 +636,7 @@ int h2_h2_process_conn(conn_rec* c)
|
|||||||
else if (APLOGctrace2(c)) {
|
else if (APLOGctrace2(c)) {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
|
||||||
"h2_h2, not detected in %d bytes(base64): %s",
|
"h2_h2, not detected in %d bytes(base64): %s",
|
||||||
(int)slen, h2_util_base64url_encode(s, slen, c->pool));
|
(int)peeklen, h2_util_base64url_encode(peek, peeklen, c->pool));
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_brigade_destroy(temp);
|
apr_brigade_destroy(temp);
|
||||||
@@ -647,15 +645,16 @@ int h2_h2_process_conn(conn_rec* c)
|
|||||||
|
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "process_conn");
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "process_conn");
|
||||||
if (!h2_ctx_session_get(ctx)) {
|
|
||||||
status = h2_conn_setup(ctx, c, NULL);
|
if (!h2_ctx_get_session(c)) {
|
||||||
|
status = h2_conn_setup(c, NULL, s);
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, c, "conn_setup");
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, c, "conn_setup");
|
||||||
if (status != APR_SUCCESS) {
|
if (status != APR_SUCCESS) {
|
||||||
h2_ctx_clear(c);
|
h2_ctx_clear(c);
|
||||||
return !OK;
|
return !OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
h2_conn_run(ctx, c);
|
h2_conn_run(c);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -684,16 +683,17 @@ static int h2_h2_pre_close_conn(conn_rec *c)
|
|||||||
|
|
||||||
static void check_push(request_rec *r, const char *tag)
|
static void check_push(request_rec *r, const char *tag)
|
||||||
{
|
{
|
||||||
const h2_config *conf = h2_config_rget(r);
|
apr_array_header_t *push_list = h2_config_push_list(r);
|
||||||
if (!r->expecting_100
|
|
||||||
&& conf && conf->push_list && conf->push_list->nelts > 0) {
|
if (!r->expecting_100 && push_list && push_list->nelts > 0) {
|
||||||
int i, old_status;
|
int i, old_status;
|
||||||
const char *old_line;
|
const char *old_line;
|
||||||
|
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
|
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
|
||||||
"%s, early announcing %d resources for push",
|
"%s, early announcing %d resources for push",
|
||||||
tag, conf->push_list->nelts);
|
tag, push_list->nelts);
|
||||||
for (i = 0; i < conf->push_list->nelts; ++i) {
|
for (i = 0; i < push_list->nelts; ++i) {
|
||||||
h2_push_res *push = &APR_ARRAY_IDX(conf->push_list, i, h2_push_res);
|
h2_push_res *push = &APR_ARRAY_IDX(push_list, i, h2_push_res);
|
||||||
apr_table_add(r->headers_out, "Link",
|
apr_table_add(r->headers_out, "Link",
|
||||||
apr_psprintf(r->pool, "<%s>; rel=preload%s",
|
apr_psprintf(r->pool, "<%s>; rel=preload%s",
|
||||||
push->uri_ref, push->critical? "; critical" : ""));
|
push->uri_ref, push->critical? "; critical" : ""));
|
||||||
@@ -712,8 +712,7 @@ static int h2_h2_post_read_req(request_rec *r)
|
|||||||
{
|
{
|
||||||
/* slave connection? */
|
/* slave connection? */
|
||||||
if (r->connection->master) {
|
if (r->connection->master) {
|
||||||
h2_ctx *ctx = h2_ctx_rget(r);
|
struct h2_task *task = h2_ctx_get_task(r->connection);
|
||||||
struct h2_task *task = h2_ctx_get_task(ctx);
|
|
||||||
/* This hook will get called twice on internal redirects. Take care
|
/* This hook will get called twice on internal redirects. Take care
|
||||||
* that we manipulate filters only once. */
|
* that we manipulate filters only once. */
|
||||||
if (task && !task->filters_set) {
|
if (task && !task->filters_set) {
|
||||||
@@ -746,12 +745,10 @@ static int h2_h2_late_fixups(request_rec *r)
|
|||||||
{
|
{
|
||||||
/* slave connection? */
|
/* slave connection? */
|
||||||
if (r->connection->master) {
|
if (r->connection->master) {
|
||||||
h2_ctx *ctx = h2_ctx_rget(r);
|
struct h2_task *task = h2_ctx_get_task(r->connection);
|
||||||
struct h2_task *task = h2_ctx_get_task(ctx);
|
|
||||||
if (task) {
|
if (task) {
|
||||||
/* check if we copy vs. setaside files in this location */
|
/* check if we copy vs. setaside files in this location */
|
||||||
task->output.copy_files = h2_config_geti(h2_config_rget(r),
|
task->output.copy_files = h2_config_rgeti(r, H2_CONF_COPY_FILES);
|
||||||
H2_CONF_COPY_FILES);
|
|
||||||
if (task->output.copy_files) {
|
if (task->output.copy_files) {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, task->c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, task->c,
|
||||||
"h2_slave_out(%s): copy_files on", task->id);
|
"h2_slave_out(%s): copy_files on", task->id);
|
||||||
|
@@ -57,23 +57,15 @@ void h2_h2_register_hooks(void);
|
|||||||
* the handshake is still ongoing.
|
* the handshake is still ongoing.
|
||||||
* @return != 0 iff connection requirements are met
|
* @return != 0 iff connection requirements are met
|
||||||
*/
|
*/
|
||||||
int h2_is_acceptable_connection(conn_rec *c, int require_all);
|
int h2_is_acceptable_connection(conn_rec *c, request_rec *r, int require_all);
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the "direct" HTTP/2 mode of protocol handling is enabled
|
|
||||||
* for the given connection.
|
|
||||||
* @param c the connection to check
|
|
||||||
* @return != 0 iff direct mode is enabled
|
|
||||||
*/
|
|
||||||
int h2_allows_h2_direct(conn_rec *c);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the "Upgrade" HTTP/1.1 mode of protocol switching is enabled
|
* Check if the "Upgrade" HTTP/1.1 mode of protocol switching is enabled
|
||||||
* for the given connection.
|
* for the given request.
|
||||||
* @param c the connection to check
|
* @param r the request to check
|
||||||
* @return != 0 iff Upgrade switching is enabled
|
* @return != 0 iff Upgrade switching is enabled
|
||||||
*/
|
*/
|
||||||
int h2_allows_h2_upgrade(conn_rec *c);
|
int h2_allows_h2_upgrade(request_rec *r);
|
||||||
|
|
||||||
|
|
||||||
#endif /* defined(__mod_h2__h2_h2__) */
|
#endif /* defined(__mod_h2__h2_h2__) */
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
#include "h2_private.h"
|
#include "h2_private.h"
|
||||||
#include "h2_h2.h"
|
#include "h2_h2.h"
|
||||||
|
#include "h2_config.h"
|
||||||
#include "h2_util.h"
|
#include "h2_util.h"
|
||||||
#include "h2_request.h"
|
#include "h2_request.h"
|
||||||
#include "h2_headers.h"
|
#include "h2_headers.h"
|
||||||
@@ -141,8 +142,10 @@ h2_headers *h2_headers_rcreate(request_rec *r, int status,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_unsafe(r->server)) {
|
if (is_unsafe(r->server)) {
|
||||||
apr_table_setn(headers->notes, H2_HDR_CONFORMANCE,
|
apr_table_setn(headers->notes, H2_HDR_CONFORMANCE, H2_HDR_CONFORMANCE_UNSAFE);
|
||||||
H2_HDR_CONFORMANCE_UNSAFE);
|
}
|
||||||
|
if (h2_config_rgeti(r, H2_CONF_PUSH) == 0 && h2_config_sgeti(r->server, H2_CONF_PUSH) != 0) {
|
||||||
|
apr_table_setn(headers->notes, H2_PUSH_MODE_NOTE, "0");
|
||||||
}
|
}
|
||||||
return headers;
|
return headers;
|
||||||
}
|
}
|
||||||
|
@@ -151,25 +151,19 @@ static void stream_cleanup(h2_mplx *m, h2_stream *stream)
|
|||||||
* their HTTP/1 cousins, the separate allocator seems to work better
|
* their HTTP/1 cousins, the separate allocator seems to work better
|
||||||
* than protecting a shared h2_session one with an own lock.
|
* than protecting a shared h2_session one with an own lock.
|
||||||
*/
|
*/
|
||||||
h2_mplx *h2_mplx_create(conn_rec *c, apr_pool_t *parent,
|
h2_mplx *h2_mplx_create(conn_rec *c, server_rec *s, apr_pool_t *parent,
|
||||||
const h2_config *conf,
|
|
||||||
h2_workers *workers)
|
h2_workers *workers)
|
||||||
{
|
{
|
||||||
apr_status_t status = APR_SUCCESS;
|
apr_status_t status = APR_SUCCESS;
|
||||||
apr_allocator_t *allocator;
|
apr_allocator_t *allocator;
|
||||||
apr_thread_mutex_t *mutex;
|
apr_thread_mutex_t *mutex;
|
||||||
h2_mplx *m;
|
h2_mplx *m;
|
||||||
h2_ctx *ctx = h2_ctx_get(c, 0);
|
|
||||||
ap_assert(conf);
|
|
||||||
|
|
||||||
m = apr_pcalloc(parent, sizeof(h2_mplx));
|
m = apr_pcalloc(parent, sizeof(h2_mplx));
|
||||||
if (m) {
|
if (m) {
|
||||||
m->id = c->id;
|
m->id = c->id;
|
||||||
m->c = c;
|
m->c = c;
|
||||||
m->s = (ctx? h2_ctx_server_get(ctx) : NULL);
|
m->s = s;
|
||||||
if (!m->s) {
|
|
||||||
m->s = c->base_server;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We create a pool with its own allocator to be used for
|
/* We create a pool with its own allocator to be used for
|
||||||
* processing slave connections. This is the only way to have the
|
* processing slave connections. This is the only way to have the
|
||||||
@@ -210,8 +204,8 @@ h2_mplx *h2_mplx_create(conn_rec *c, apr_pool_t *parent,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
m->max_streams = h2_config_geti(conf, H2_CONF_MAX_STREAMS);
|
m->max_streams = h2_config_sgeti(s, H2_CONF_MAX_STREAMS);
|
||||||
m->stream_max_mem = h2_config_geti(conf, H2_CONF_STREAM_MAX_MEM);
|
m->stream_max_mem = h2_config_sgeti(s, H2_CONF_STREAM_MAX_MEM);
|
||||||
|
|
||||||
m->streams = h2_ihash_create(m->pool, offsetof(h2_stream,id));
|
m->streams = h2_ihash_create(m->pool, offsetof(h2_stream,id));
|
||||||
m->sredo = h2_ihash_create(m->pool, offsetof(h2_stream,id));
|
m->sredo = h2_ihash_create(m->pool, offsetof(h2_stream,id));
|
||||||
@@ -327,8 +321,7 @@ static int stream_destroy_iter(void *ctx, void *val)
|
|||||||
&& !task->rst_error);
|
&& !task->rst_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
task->c = NULL;
|
if (reuse_slave && slave->keepalive == AP_CONN_KEEPALIVE) {
|
||||||
if (reuse_slave) {
|
|
||||||
h2_beam_log(task->output.beam, m->c, APLOG_DEBUG,
|
h2_beam_log(task->output.beam, m->c, APLOG_DEBUG,
|
||||||
APLOGNO(03385) "h2_task_destroy, reuse slave");
|
APLOGNO(03385) "h2_task_destroy, reuse slave");
|
||||||
h2_task_destroy(task);
|
h2_task_destroy(task);
|
||||||
@@ -795,6 +788,8 @@ static void task_done(h2_mplx *m, h2_task *task, h2_req_engine *ngn)
|
|||||||
/* this task was handed over to an engine for processing
|
/* this task was handed over to an engine for processing
|
||||||
* and the original worker has finished. That means the
|
* and the original worker has finished. That means the
|
||||||
* engine may start processing now. */
|
* 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);
|
h2_task_thaw(task);
|
||||||
apr_thread_cond_broadcast(m->task_thawed);
|
apr_thread_cond_broadcast(m->task_thawed);
|
||||||
return;
|
return;
|
||||||
@@ -850,17 +845,23 @@ static void task_done(h2_mplx *m, h2_task *task, h2_req_engine *ngn)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ap_assert(task->done_done == 0);
|
||||||
|
|
||||||
stream = h2_ihash_get(m->streams, task->stream_id);
|
stream = h2_ihash_get(m->streams, task->stream_id);
|
||||||
if (stream) {
|
if (stream) {
|
||||||
/* stream not done yet. */
|
/* stream not done yet. */
|
||||||
if (!m->aborted && h2_ihash_get(m->sredo, stream->id)) {
|
if (!m->aborted && h2_ihash_get(m->sredo, stream->id)) {
|
||||||
/* reset and schedule again */
|
/* reset and schedule again */
|
||||||
|
task->worker_done = 0;
|
||||||
h2_task_redo(task);
|
h2_task_redo(task);
|
||||||
h2_ihash_remove(m->sredo, stream->id);
|
h2_ihash_remove(m->sredo, stream->id);
|
||||||
h2_iq_add(m->q, stream->id, NULL, NULL);
|
h2_iq_add(m->q, stream->id, NULL, NULL);
|
||||||
|
ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, m->c,
|
||||||
|
H2_STRM_MSG(stream, "redo, added to q"));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* stream not cleaned up, stay around */
|
/* stream not cleaned up, stay around */
|
||||||
|
task->done_done = 1;
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
|
||||||
H2_STRM_MSG(stream, "task_done, stream open"));
|
H2_STRM_MSG(stream, "task_done, stream open"));
|
||||||
if (stream->input) {
|
if (stream->input) {
|
||||||
@@ -873,6 +874,7 @@ static void task_done(h2_mplx *m, h2_task *task, h2_req_engine *ngn)
|
|||||||
}
|
}
|
||||||
else if ((stream = h2_ihash_get(m->shold, task->stream_id)) != NULL) {
|
else if ((stream = h2_ihash_get(m->shold, task->stream_id)) != NULL) {
|
||||||
/* stream is done, was just waiting for this. */
|
/* stream is done, was just waiting for this. */
|
||||||
|
task->done_done = 1;
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
|
||||||
H2_STRM_MSG(stream, "task_done, in hold"));
|
H2_STRM_MSG(stream, "task_done, in hold"));
|
||||||
if (stream->input) {
|
if (stream->input) {
|
||||||
@@ -1132,7 +1134,7 @@ apr_status_t h2_mplx_req_engine_push(const char *ngn_type,
|
|||||||
h2_task *task;
|
h2_task *task;
|
||||||
h2_stream *stream;
|
h2_stream *stream;
|
||||||
|
|
||||||
task = h2_ctx_rget_task(r);
|
task = h2_ctx_get_task(r->connection);
|
||||||
if (!task) {
|
if (!task) {
|
||||||
return APR_ECONNABORTED;
|
return APR_ECONNABORTED;
|
||||||
}
|
}
|
||||||
@@ -1196,11 +1198,12 @@ apr_status_t h2_mplx_req_engine_pull(h2_req_engine *ngn,
|
|||||||
void h2_mplx_req_engine_done(h2_req_engine *ngn, conn_rec *r_conn,
|
void h2_mplx_req_engine_done(h2_req_engine *ngn, conn_rec *r_conn,
|
||||||
apr_status_t status)
|
apr_status_t status)
|
||||||
{
|
{
|
||||||
h2_task *task = h2_ctx_cget_task(r_conn);
|
h2_task *task = h2_ctx_get_task(r_conn);
|
||||||
|
|
||||||
if (task) {
|
if (task) {
|
||||||
h2_mplx *m = task->mplx;
|
h2_mplx *m = task->mplx;
|
||||||
h2_stream *stream;
|
h2_stream *stream;
|
||||||
|
int task_hosting_engine = (task->engine != NULL);
|
||||||
|
|
||||||
H2_MPLX_ENTER_ALWAYS(m);
|
H2_MPLX_ENTER_ALWAYS(m);
|
||||||
|
|
||||||
@@ -1212,13 +1215,13 @@ void h2_mplx_req_engine_done(h2_req_engine *ngn, conn_rec *r_conn,
|
|||||||
if (status != APR_SUCCESS && stream
|
if (status != APR_SUCCESS && stream
|
||||||
&& h2_task_can_redo(task)
|
&& h2_task_can_redo(task)
|
||||||
&& !h2_ihash_get(m->sredo, stream->id)) {
|
&& !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);
|
h2_ihash_add(m->sredo, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (task->engine) {
|
/* cannot report that until hosted engine returns */
|
||||||
/* cannot report that as done until engine returns */
|
if (!task_hosting_engine) {
|
||||||
}
|
|
||||||
else {
|
|
||||||
task_done(m, task, ngn);
|
task_done(m, task, ngn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -111,8 +111,7 @@ apr_status_t h2_mplx_child_init(apr_pool_t *pool, server_rec *s);
|
|||||||
* Create the multiplexer for the given HTTP2 session.
|
* Create the multiplexer for the given HTTP2 session.
|
||||||
* Implicitly has reference count 1.
|
* Implicitly has reference count 1.
|
||||||
*/
|
*/
|
||||||
h2_mplx *h2_mplx_create(conn_rec *c, apr_pool_t *master,
|
h2_mplx *h2_mplx_create(conn_rec *c, server_rec *s, apr_pool_t *master,
|
||||||
const struct h2_config *conf,
|
|
||||||
struct h2_workers *workers);
|
struct h2_workers *workers);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -161,7 +161,7 @@ apr_status_t h2_ngn_shed_push_request(h2_ngn_shed *shed, const char *ngn_type,
|
|||||||
http2_req_engine_init *einit)
|
http2_req_engine_init *einit)
|
||||||
{
|
{
|
||||||
h2_req_engine *ngn;
|
h2_req_engine *ngn;
|
||||||
h2_task *task = h2_ctx_rget_task(r);
|
h2_task *task = h2_ctx_get_task(r->connection);
|
||||||
|
|
||||||
ap_assert(task);
|
ap_assert(task);
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, shed->c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, shed->c,
|
||||||
|
@@ -85,8 +85,7 @@ apr_status_t h2_request_rcreate(h2_request **preq, apr_pool_t *pool,
|
|||||||
req->path = path;
|
req->path = path;
|
||||||
req->headers = apr_table_make(pool, 10);
|
req->headers = apr_table_make(pool, 10);
|
||||||
if (r->server) {
|
if (r->server) {
|
||||||
req->serialize = h2_config_geti(h2_config_sget(r->server),
|
req->serialize = h2_config_rgeti(r, H2_CONF_SER_HEADERS);
|
||||||
H2_CONF_SER_HEADERS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
x.pool = pool;
|
x.pool = pool;
|
||||||
|
@@ -757,9 +757,8 @@ static apr_status_t session_pool_cleanup(void *data)
|
|||||||
{
|
{
|
||||||
conn_rec *c = data;
|
conn_rec *c = data;
|
||||||
h2_session *session;
|
h2_session *session;
|
||||||
h2_ctx *ctx = h2_ctx_get(c, 0);
|
|
||||||
|
|
||||||
if (ctx && (session = h2_ctx_session_get(ctx))) {
|
if ((session = h2_ctx_get_session(c))) {
|
||||||
/* if the session is still there, now is the last chance
|
/* if the session is still there, now is the last chance
|
||||||
* to perform cleanup. Normally, cleanup should have happened
|
* to perform cleanup. Normally, cleanup should have happened
|
||||||
* earlier in the connection pre_close. Main reason is that
|
* earlier in the connection pre_close. Main reason is that
|
||||||
@@ -775,11 +774,8 @@ static apr_status_t session_pool_cleanup(void *data)
|
|||||||
return APR_SUCCESS;
|
return APR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static apr_status_t h2_session_create_int(h2_session **psession,
|
apr_status_t h2_session_create(h2_session **psession, conn_rec *c, request_rec *r,
|
||||||
conn_rec *c,
|
server_rec *s, h2_workers *workers)
|
||||||
request_rec *r,
|
|
||||||
h2_ctx *ctx,
|
|
||||||
h2_workers *workers)
|
|
||||||
{
|
{
|
||||||
nghttp2_session_callbacks *callbacks = NULL;
|
nghttp2_session_callbacks *callbacks = NULL;
|
||||||
nghttp2_option *options = NULL;
|
nghttp2_option *options = NULL;
|
||||||
@@ -820,19 +816,16 @@ static apr_status_t h2_session_create_int(h2_session **psession,
|
|||||||
session->id = c->id;
|
session->id = c->id;
|
||||||
session->c = c;
|
session->c = c;
|
||||||
session->r = r;
|
session->r = r;
|
||||||
session->s = h2_ctx_server_get(ctx);
|
session->s = s;
|
||||||
session->pool = pool;
|
session->pool = pool;
|
||||||
session->config = h2_config_sget(session->s);
|
|
||||||
session->workers = workers;
|
session->workers = workers;
|
||||||
|
|
||||||
session->state = H2_SESSION_ST_INIT;
|
session->state = H2_SESSION_ST_INIT;
|
||||||
session->local.accepting = 1;
|
session->local.accepting = 1;
|
||||||
session->remote.accepting = 1;
|
session->remote.accepting = 1;
|
||||||
|
|
||||||
session->max_stream_count = h2_config_geti(session->config,
|
session->max_stream_count = h2_config_sgeti(s, H2_CONF_MAX_STREAMS);
|
||||||
H2_CONF_MAX_STREAMS);
|
session->max_stream_mem = h2_config_sgeti(s, H2_CONF_STREAM_MAX_MEM);
|
||||||
session->max_stream_mem = h2_config_geti(session->config,
|
|
||||||
H2_CONF_STREAM_MAX_MEM);
|
|
||||||
|
|
||||||
status = apr_thread_cond_create(&session->iowait, session->pool);
|
status = apr_thread_cond_create(&session->iowait, session->pool);
|
||||||
if (status != APR_SUCCESS) {
|
if (status != APR_SUCCESS) {
|
||||||
@@ -862,14 +855,13 @@ static apr_status_t h2_session_create_int(h2_session **psession,
|
|||||||
session->monitor->on_state_event = on_stream_state_event;
|
session->monitor->on_state_event = on_stream_state_event;
|
||||||
session->monitor->on_event = on_stream_event;
|
session->monitor->on_event = on_stream_event;
|
||||||
|
|
||||||
session->mplx = h2_mplx_create(c, session->pool, session->config,
|
session->mplx = h2_mplx_create(c, s, session->pool, workers);
|
||||||
workers);
|
|
||||||
|
|
||||||
/* connection input filter that feeds the session */
|
/* connection input filter that feeds the session */
|
||||||
session->cin = h2_filter_cin_create(session);
|
session->cin = h2_filter_cin_create(session);
|
||||||
ap_add_input_filter("H2_IN", session->cin, r, c);
|
ap_add_input_filter("H2_IN", session->cin, r, c);
|
||||||
|
|
||||||
h2_conn_io_init(&session->io, c, session->config);
|
h2_conn_io_init(&session->io, c, s);
|
||||||
session->bbtmp = apr_brigade_create(session->pool, c->bucket_alloc);
|
session->bbtmp = apr_brigade_create(session->pool, c->bucket_alloc);
|
||||||
|
|
||||||
status = init_callbacks(c, &callbacks);
|
status = init_callbacks(c, &callbacks);
|
||||||
@@ -888,8 +880,7 @@ static apr_status_t h2_session_create_int(h2_session **psession,
|
|||||||
apr_pool_destroy(pool);
|
apr_pool_destroy(pool);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
nghttp2_option_set_peer_max_concurrent_streams(
|
nghttp2_option_set_peer_max_concurrent_streams(options, (uint32_t)session->max_stream_count);
|
||||||
options, (uint32_t)session->max_stream_count);
|
|
||||||
/* We need to handle window updates ourself, otherwise we
|
/* We need to handle window updates ourself, otherwise we
|
||||||
* get flooded by nghttp2. */
|
* get flooded by nghttp2. */
|
||||||
nghttp2_option_set_no_auto_window_update(options, 1);
|
nghttp2_option_set_no_auto_window_update(options, 1);
|
||||||
@@ -907,7 +898,7 @@ static apr_status_t h2_session_create_int(h2_session **psession,
|
|||||||
return APR_ENOMEM;
|
return APR_ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
n = h2_config_geti(session->config, H2_CONF_PUSH_DIARY_SIZE);
|
n = h2_config_sgeti(s, H2_CONF_PUSH_DIARY_SIZE);
|
||||||
session->push_diary = h2_push_diary_create(session->pool, n);
|
session->push_diary = h2_push_diary_create(session->pool, n);
|
||||||
|
|
||||||
if (APLOGcdebug(c)) {
|
if (APLOGcdebug(c)) {
|
||||||
@@ -925,21 +916,10 @@ static apr_status_t h2_session_create_int(h2_session **psession,
|
|||||||
}
|
}
|
||||||
|
|
||||||
apr_pool_pre_cleanup_register(pool, c, session_pool_cleanup);
|
apr_pool_pre_cleanup_register(pool, c, session_pool_cleanup);
|
||||||
|
|
||||||
return APR_SUCCESS;
|
return APR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_status_t h2_session_create(h2_session **psession,
|
|
||||||
conn_rec *c, h2_ctx *ctx, h2_workers *workers)
|
|
||||||
{
|
|
||||||
return h2_session_create_int(psession, c, NULL, ctx, workers);
|
|
||||||
}
|
|
||||||
|
|
||||||
apr_status_t h2_session_rcreate(h2_session **psession,
|
|
||||||
request_rec *r, h2_ctx *ctx, h2_workers *workers)
|
|
||||||
{
|
|
||||||
return h2_session_create_int(psession, r->connection, r, ctx, workers);
|
|
||||||
}
|
|
||||||
|
|
||||||
static apr_status_t h2_session_start(h2_session *session, int *rv)
|
static apr_status_t h2_session_start(h2_session *session, int *rv)
|
||||||
{
|
{
|
||||||
apr_status_t status = APR_SUCCESS;
|
apr_status_t status = APR_SUCCESS;
|
||||||
@@ -1004,7 +984,7 @@ static apr_status_t h2_session_start(h2_session *session, int *rv)
|
|||||||
settings[slen].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
|
settings[slen].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
|
||||||
settings[slen].value = (uint32_t)session->max_stream_count;
|
settings[slen].value = (uint32_t)session->max_stream_count;
|
||||||
++slen;
|
++slen;
|
||||||
win_size = h2_config_geti(session->config, H2_CONF_WIN_SIZE);
|
win_size = h2_config_sgeti(session->s, H2_CONF_WIN_SIZE);
|
||||||
if (win_size != H2_INITIAL_WINDOW_SIZE) {
|
if (win_size != H2_INITIAL_WINDOW_SIZE) {
|
||||||
settings[slen].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
|
settings[slen].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
|
||||||
settings[slen].value = win_size;
|
settings[slen].value = win_size;
|
||||||
@@ -1280,7 +1260,7 @@ int h2_session_push_enabled(h2_session *session)
|
|||||||
{
|
{
|
||||||
/* iff we can and they can and want */
|
/* iff we can and they can and want */
|
||||||
return (session->remote.accepting /* remote GOAWAY received */
|
return (session->remote.accepting /* remote GOAWAY received */
|
||||||
&& h2_config_geti(session->config, H2_CONF_PUSH)
|
&& h2_config_sgeti(session->s, H2_CONF_PUSH)
|
||||||
&& nghttp2_session_get_remote_settings(session->ngh2,
|
&& nghttp2_session_get_remote_settings(session->ngh2,
|
||||||
NGHTTP2_SETTINGS_ENABLE_PUSH));
|
NGHTTP2_SETTINGS_ENABLE_PUSH));
|
||||||
}
|
}
|
||||||
@@ -1324,6 +1304,7 @@ static apr_status_t on_stream_headers(h2_session *session, h2_stream *stream,
|
|||||||
int eos)
|
int eos)
|
||||||
{
|
{
|
||||||
apr_status_t status = APR_SUCCESS;
|
apr_status_t status = APR_SUCCESS;
|
||||||
|
const char *s;
|
||||||
int rv = 0;
|
int rv = 0;
|
||||||
|
|
||||||
ap_assert(session);
|
ap_assert(session);
|
||||||
@@ -1391,8 +1372,12 @@ static apr_status_t on_stream_headers(h2_session *session, h2_stream *stream,
|
|||||||
&& (headers->status < 400)
|
&& (headers->status < 400)
|
||||||
&& (headers->status != 304)
|
&& (headers->status != 304)
|
||||||
&& h2_session_push_enabled(session)) {
|
&& h2_session_push_enabled(session)) {
|
||||||
|
/* PUSH is possibe and enabled on server, unless the request
|
||||||
h2_stream_submit_pushes(stream, headers);
|
* denies it, submit resources to push */
|
||||||
|
s = apr_table_get(headers->notes, H2_PUSH_MODE_NOTE);
|
||||||
|
if (!s || strcmp(s, "0")) {
|
||||||
|
h2_stream_submit_pushes(stream, headers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stream->pref_priority) {
|
if (!stream->pref_priority) {
|
||||||
@@ -1414,7 +1399,7 @@ static apr_status_t on_stream_headers(h2_session *session, h2_stream *stream,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (headers->status == 103
|
if (headers->status == 103
|
||||||
&& !h2_config_geti(session->config, H2_CONF_EARLY_HINTS)) {
|
&& !h2_config_sgeti(session->s, H2_CONF_EARLY_HINTS)) {
|
||||||
/* suppress sending this to the client, it might have triggered
|
/* suppress sending this to the client, it might have triggered
|
||||||
* pushes and served its purpose nevertheless */
|
* pushes and served its purpose nevertheless */
|
||||||
rv = 0;
|
rv = 0;
|
||||||
@@ -2089,7 +2074,7 @@ apr_status_t h2_session_process(h2_session *session, int async)
|
|||||||
switch (session->state) {
|
switch (session->state) {
|
||||||
case H2_SESSION_ST_INIT:
|
case H2_SESSION_ST_INIT:
|
||||||
ap_update_child_status_from_conn(c->sbh, SERVER_BUSY_READ, c);
|
ap_update_child_status_from_conn(c->sbh, SERVER_BUSY_READ, c);
|
||||||
if (!h2_is_acceptable_connection(c, 1)) {
|
if (!h2_is_acceptable_connection(c, session->r, 1)) {
|
||||||
update_child_status(session, SERVER_BUSY_READ,
|
update_child_status(session, SERVER_BUSY_READ,
|
||||||
"inadequate security");
|
"inadequate security");
|
||||||
h2_session_shutdown(session,
|
h2_session_shutdown(session,
|
||||||
|
@@ -80,7 +80,6 @@ typedef struct h2_session {
|
|||||||
request_rec *r; /* the request that started this in case
|
request_rec *r; /* the request that started this in case
|
||||||
* of 'h2c', NULL otherwise */
|
* of 'h2c', NULL otherwise */
|
||||||
server_rec *s; /* server/vhost we're starting on */
|
server_rec *s; /* server/vhost we're starting on */
|
||||||
const struct h2_config *config; /* Relevant config for this session */
|
|
||||||
apr_pool_t *pool; /* pool to use in session */
|
apr_pool_t *pool; /* pool to use in session */
|
||||||
struct h2_mplx *mplx; /* multiplexer for stream data */
|
struct h2_mplx *mplx; /* multiplexer for stream data */
|
||||||
struct h2_workers *workers; /* for executing stream tasks */
|
struct h2_workers *workers; /* for executing stream tasks */
|
||||||
@@ -142,27 +141,15 @@ const char *h2_session_state_str(h2_session_state state);
|
|||||||
* The session will apply the configured parameter.
|
* The session will apply the configured parameter.
|
||||||
* @param psession pointer receiving the created session on success or NULL
|
* @param psession pointer receiving the created session on success or NULL
|
||||||
* @param c the connection to work on
|
* @param c the connection to work on
|
||||||
|
* @param r optional request when protocol was upgraded
|
||||||
* @param cfg the module config to apply
|
* @param cfg the module config to apply
|
||||||
* @param workers the worker pool to use
|
* @param workers the worker pool to use
|
||||||
* @return the created session
|
* @return the created session
|
||||||
*/
|
*/
|
||||||
apr_status_t h2_session_create(h2_session **psession,
|
apr_status_t h2_session_create(h2_session **psession,
|
||||||
conn_rec *c, struct h2_ctx *ctx,
|
conn_rec *c, request_rec *r, server_rec *,
|
||||||
struct h2_workers *workers);
|
struct h2_workers *workers);
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new h2_session for the given request.
|
|
||||||
* The session will apply the configured parameter.
|
|
||||||
* @param psession pointer receiving the created session on success or NULL
|
|
||||||
* @param r the request that was upgraded
|
|
||||||
* @param cfg the module config to apply
|
|
||||||
* @param workers the worker pool to use
|
|
||||||
* @return the created session
|
|
||||||
*/
|
|
||||||
apr_status_t h2_session_rcreate(h2_session **psession,
|
|
||||||
request_rec *r, struct h2_ctx *ctx,
|
|
||||||
struct h2_workers *workers);
|
|
||||||
|
|
||||||
void h2_session_event(h2_session *session, h2_session_event_t ev,
|
void h2_session_event(h2_session *session, h2_session_event_t ev,
|
||||||
int err, const char *msg);
|
int err, const char *msg);
|
||||||
|
|
||||||
|
@@ -365,9 +365,8 @@ void h2_stream_dispatch(h2_stream *stream, h2_stream_event_t ev)
|
|||||||
static void set_policy_for(h2_stream *stream, h2_request *r)
|
static void set_policy_for(h2_stream *stream, h2_request *r)
|
||||||
{
|
{
|
||||||
int enabled = h2_session_push_enabled(stream->session);
|
int enabled = h2_session_push_enabled(stream->session);
|
||||||
stream->push_policy = h2_push_policy_determine(r->headers, stream->pool,
|
stream->push_policy = h2_push_policy_determine(r->headers, stream->pool, enabled);
|
||||||
enabled);
|
r->serialize = h2_config_sgeti(stream->session->s, H2_CONF_SER_HEADERS);
|
||||||
r->serialize = h2_config_geti(stream->session->config, H2_CONF_SER_HEADERS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_status_t h2_stream_send_frame(h2_stream *stream, int ftype, int flags, size_t frame_len)
|
apr_status_t h2_stream_send_frame(h2_stream *stream, int ftype, int flags, size_t frame_len)
|
||||||
@@ -987,7 +986,7 @@ const h2_priority *h2_stream_get_priority(h2_stream *stream,
|
|||||||
const char *ctype = apr_table_get(response->headers, "content-type");
|
const char *ctype = apr_table_get(response->headers, "content-type");
|
||||||
if (ctype) {
|
if (ctype) {
|
||||||
/* FIXME: Not good enough, config needs to come from request->server */
|
/* FIXME: Not good enough, config needs to come from request->server */
|
||||||
return h2_config_get_priority(stream->session->config, ctype);
|
return h2_cconfig_get_priority(stream->session->c, ctype);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@@ -55,7 +55,6 @@ static int h2_protocol_propose(conn_rec *c, request_rec *r,
|
|||||||
int is_tls = h2_h2_is_tls(c);
|
int is_tls = h2_h2_is_tls(c);
|
||||||
const char **protos = is_tls? h2_tls_protos : h2_clear_protos;
|
const char **protos = is_tls? h2_tls_protos : h2_clear_protos;
|
||||||
|
|
||||||
(void)s;
|
|
||||||
if (!h2_mpm_supported()) {
|
if (!h2_mpm_supported()) {
|
||||||
return DECLINED;
|
return DECLINED;
|
||||||
}
|
}
|
||||||
@@ -68,7 +67,7 @@ static int h2_protocol_propose(conn_rec *c, request_rec *r,
|
|||||||
return DECLINED;
|
return DECLINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!h2_is_acceptable_connection(c, 0)) {
|
if (!h2_is_acceptable_connection(c, r, 0)) {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(03084)
|
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(03084)
|
||||||
"protocol propose: connection requirements not met");
|
"protocol propose: connection requirements not met");
|
||||||
return DECLINED;
|
return DECLINED;
|
||||||
@@ -81,7 +80,7 @@ static int h2_protocol_propose(conn_rec *c, request_rec *r,
|
|||||||
*/
|
*/
|
||||||
const char *p;
|
const char *p;
|
||||||
|
|
||||||
if (!h2_allows_h2_upgrade(c)) {
|
if (!h2_allows_h2_upgrade(r)) {
|
||||||
return DECLINED;
|
return DECLINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +149,7 @@ static int h2_protocol_switch(conn_rec *c, request_rec *r, server_rec *s,
|
|||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
||||||
"switching protocol to '%s'", protocol);
|
"switching protocol to '%s'", protocol);
|
||||||
h2_ctx_protocol_set(ctx, protocol);
|
h2_ctx_protocol_set(ctx, protocol);
|
||||||
h2_ctx_server_set(ctx, s);
|
h2_ctx_server_update(ctx, s);
|
||||||
|
|
||||||
if (r != NULL) {
|
if (r != NULL) {
|
||||||
apr_status_t status;
|
apr_status_t status;
|
||||||
@@ -164,8 +163,8 @@ static int h2_protocol_switch(conn_rec *c, request_rec *r, server_rec *s,
|
|||||||
ap_remove_output_filter_byhandle(r->output_filters, "HTTP_HEADER");
|
ap_remove_output_filter_byhandle(r->output_filters, "HTTP_HEADER");
|
||||||
|
|
||||||
/* Ok, start an h2_conn on this one. */
|
/* Ok, start an h2_conn on this one. */
|
||||||
h2_ctx_server_set(ctx, r->server);
|
status = h2_conn_setup(c, r, s);
|
||||||
status = h2_conn_setup(ctx, r->connection, r);
|
|
||||||
if (status != APR_SUCCESS) {
|
if (status != APR_SUCCESS) {
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(03088)
|
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(03088)
|
||||||
"session setup");
|
"session setup");
|
||||||
@@ -173,7 +172,7 @@ static int h2_protocol_switch(conn_rec *c, request_rec *r, server_rec *s,
|
|||||||
return !OK;
|
return !OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2_conn_run(ctx, c);
|
h2_conn_run(c);
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
@@ -236,7 +236,7 @@ static apr_status_t h2_filter_slave_in(ap_filter_t* f,
|
|||||||
apr_size_t rmax = ((readbytes <= APR_SIZE_MAX)?
|
apr_size_t rmax = ((readbytes <= APR_SIZE_MAX)?
|
||||||
(apr_size_t)readbytes : APR_SIZE_MAX);
|
(apr_size_t)readbytes : APR_SIZE_MAX);
|
||||||
|
|
||||||
task = h2_ctx_cget_task(f->c);
|
task = h2_ctx_get_task(f->c);
|
||||||
ap_assert(task);
|
ap_assert(task);
|
||||||
|
|
||||||
if (trace1) {
|
if (trace1) {
|
||||||
@@ -379,7 +379,7 @@ static apr_status_t h2_filter_slave_in(ap_filter_t* f,
|
|||||||
static apr_status_t h2_filter_slave_output(ap_filter_t* filter,
|
static apr_status_t h2_filter_slave_output(ap_filter_t* filter,
|
||||||
apr_bucket_brigade* brigade)
|
apr_bucket_brigade* brigade)
|
||||||
{
|
{
|
||||||
h2_task *task = h2_ctx_cget_task(filter->c);
|
h2_task *task = h2_ctx_get_task(filter->c);
|
||||||
apr_status_t status;
|
apr_status_t status;
|
||||||
|
|
||||||
ap_assert(task);
|
ap_assert(task);
|
||||||
@@ -392,7 +392,7 @@ static apr_status_t h2_filter_slave_output(ap_filter_t* filter,
|
|||||||
|
|
||||||
static apr_status_t h2_filter_parse_h1(ap_filter_t* f, apr_bucket_brigade* bb)
|
static apr_status_t h2_filter_parse_h1(ap_filter_t* f, apr_bucket_brigade* bb)
|
||||||
{
|
{
|
||||||
h2_task *task = h2_ctx_cget_task(f->c);
|
h2_task *task = h2_ctx_get_task(f->c);
|
||||||
apr_status_t status;
|
apr_status_t status;
|
||||||
|
|
||||||
ap_assert(task);
|
ap_assert(task);
|
||||||
@@ -502,7 +502,7 @@ static int h2_task_pre_conn(conn_rec* c, void *arg)
|
|||||||
|
|
||||||
ctx = h2_ctx_get(c, 0);
|
ctx = h2_ctx_get(c, 0);
|
||||||
(void)arg;
|
(void)arg;
|
||||||
if (h2_ctx_is_task(ctx)) {
|
if (ctx->task) {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
|
||||||
"h2_slave(%s), pre_connection, adding filters", c->log_id);
|
"h2_slave(%s), pre_connection, adding filters", c->log_id);
|
||||||
ap_add_input_filter("H2_SLAVE_IN", NULL, NULL, c);
|
ap_add_input_filter("H2_SLAVE_IN", NULL, NULL, c);
|
||||||
@@ -545,6 +545,7 @@ h2_task *h2_task_create(conn_rec *slave, int stream_id,
|
|||||||
void h2_task_destroy(h2_task *task)
|
void h2_task_destroy(h2_task *task)
|
||||||
{
|
{
|
||||||
if (task->output.beam) {
|
if (task->output.beam) {
|
||||||
|
h2_beam_log(task->output.beam, task->c, APLOG_TRACE2, "task_destroy");
|
||||||
h2_beam_destroy(task->output.beam);
|
h2_beam_destroy(task->output.beam);
|
||||||
task->output.beam = NULL;
|
task->output.beam = NULL;
|
||||||
}
|
}
|
||||||
@@ -724,7 +725,7 @@ static int h2_task_process_conn(conn_rec* c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx = h2_ctx_get(c, 0);
|
ctx = h2_ctx_get(c, 0);
|
||||||
if (h2_ctx_is_task(ctx)) {
|
if (ctx->task) {
|
||||||
if (!ctx->task->request->serialize) {
|
if (!ctx->task->request->serialize) {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
||||||
"h2_h2, processing request directly");
|
"h2_h2, processing request directly");
|
||||||
|
@@ -83,7 +83,9 @@ struct h2_task {
|
|||||||
unsigned int frozen : 1;
|
unsigned int frozen : 1;
|
||||||
unsigned int thawed : 1;
|
unsigned int thawed : 1;
|
||||||
unsigned int worker_started : 1; /* h2_worker started processing */
|
unsigned int worker_started : 1; /* h2_worker started processing */
|
||||||
unsigned int worker_done : 1; /* h2_worker finished */
|
|
||||||
|
int worker_done; /* h2_worker finished */
|
||||||
|
int done_done; /* task_done has been handled */
|
||||||
|
|
||||||
apr_time_t started_at; /* when processing started */
|
apr_time_t started_at; /* when processing started */
|
||||||
apr_time_t done_at; /* when processing was done */
|
apr_time_t done_at; /* when processing was done */
|
||||||
|
@@ -27,7 +27,7 @@
|
|||||||
* @macro
|
* @macro
|
||||||
* Version number of the http2 module as c string
|
* Version number of the http2 module as c string
|
||||||
*/
|
*/
|
||||||
#define MOD_HTTP2_VERSION "1.12.0-DEV"
|
#define MOD_HTTP2_VERSION "1.12.2-DEV"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @macro
|
* @macro
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
* release. This is a 24 bit number with 8 bits for major number, 8 bits
|
* 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.
|
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
|
||||||
*/
|
*/
|
||||||
#define MOD_HTTP2_VERSION_NUM 0x010c00
|
#define MOD_HTTP2_VERSION_NUM 0x010c02
|
||||||
|
|
||||||
|
|
||||||
#endif /* mod_h2_h2_version_h */
|
#endif /* mod_h2_h2_version_h */
|
||||||
|
@@ -260,9 +260,8 @@ static const char *val_H2_PUSH(apr_pool_t *p, server_rec *s,
|
|||||||
{
|
{
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
if (r) {
|
if (r) {
|
||||||
h2_task *task = h2_ctx_get_task(ctx);
|
if (ctx->task) {
|
||||||
if (task) {
|
h2_stream *stream = h2_mplx_stream_get(ctx->task->mplx, ctx->task->stream_id);
|
||||||
h2_stream *stream = h2_mplx_stream_get(task->mplx, task->stream_id);
|
|
||||||
if (stream && stream->push_policy != H2_PUSH_NONE) {
|
if (stream && stream->push_policy != H2_PUSH_NONE) {
|
||||||
return "on";
|
return "on";
|
||||||
}
|
}
|
||||||
@@ -273,8 +272,7 @@ static const char *val_H2_PUSH(apr_pool_t *p, server_rec *s,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (s) {
|
else if (s) {
|
||||||
const h2_config *cfg = h2_config_sget(s);
|
if (h2_config_geti(r, s, H2_CONF_PUSH)) {
|
||||||
if (cfg && h2_config_geti(cfg, H2_CONF_PUSH)) {
|
|
||||||
return "on";
|
return "on";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -285,8 +283,7 @@ static const char *val_H2_PUSHED(apr_pool_t *p, server_rec *s,
|
|||||||
conn_rec *c, request_rec *r, h2_ctx *ctx)
|
conn_rec *c, request_rec *r, h2_ctx *ctx)
|
||||||
{
|
{
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
h2_task *task = h2_ctx_get_task(ctx);
|
if (ctx->task && !H2_STREAM_CLIENT_INITIATED(ctx->task->stream_id)) {
|
||||||
if (task && !H2_STREAM_CLIENT_INITIATED(task->stream_id)) {
|
|
||||||
return "PUSHED";
|
return "PUSHED";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,9 +294,8 @@ static const char *val_H2_PUSHED_ON(apr_pool_t *p, server_rec *s,
|
|||||||
conn_rec *c, request_rec *r, h2_ctx *ctx)
|
conn_rec *c, request_rec *r, h2_ctx *ctx)
|
||||||
{
|
{
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
h2_task *task = h2_ctx_get_task(ctx);
|
if (ctx->task && !H2_STREAM_CLIENT_INITIATED(ctx->task->stream_id)) {
|
||||||
if (task && !H2_STREAM_CLIENT_INITIATED(task->stream_id)) {
|
h2_stream *stream = h2_mplx_stream_get(ctx->task->mplx, ctx->task->stream_id);
|
||||||
h2_stream *stream = h2_mplx_stream_get(task->mplx, task->stream_id);
|
|
||||||
if (stream) {
|
if (stream) {
|
||||||
return apr_itoa(p, stream->initiated_on);
|
return apr_itoa(p, stream->initiated_on);
|
||||||
}
|
}
|
||||||
@@ -312,9 +308,8 @@ static const char *val_H2_STREAM_TAG(apr_pool_t *p, server_rec *s,
|
|||||||
conn_rec *c, request_rec *r, h2_ctx *ctx)
|
conn_rec *c, request_rec *r, h2_ctx *ctx)
|
||||||
{
|
{
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
h2_task *task = h2_ctx_get_task(ctx);
|
if (ctx->task) {
|
||||||
if (task) {
|
return ctx->task->id;
|
||||||
return task->id;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
@@ -366,7 +361,7 @@ static char *http2_var_lookup(apr_pool_t *p, server_rec *s,
|
|||||||
for (i = 0; i < H2_ALEN(H2_VARS); ++i) {
|
for (i = 0; i < H2_ALEN(H2_VARS); ++i) {
|
||||||
h2_var_def *vdef = &H2_VARS[i];
|
h2_var_def *vdef = &H2_VARS[i];
|
||||||
if (!strcmp(vdef->name, name)) {
|
if (!strcmp(vdef->name, name)) {
|
||||||
h2_ctx *ctx = (r? h2_ctx_rget(r) :
|
h2_ctx *ctx = (r? h2_ctx_get(c, 0) :
|
||||||
h2_ctx_get(c->master? c->master : c, 0));
|
h2_ctx_get(c->master? c->master : c, 0));
|
||||||
return (char *)vdef->lookup(p, s, c, r, ctx);
|
return (char *)vdef->lookup(p, s, c, r, ctx);
|
||||||
}
|
}
|
||||||
@@ -377,7 +372,7 @@ static char *http2_var_lookup(apr_pool_t *p, server_rec *s,
|
|||||||
static int h2_h2_fixups(request_rec *r)
|
static int h2_h2_fixups(request_rec *r)
|
||||||
{
|
{
|
||||||
if (r->connection->master) {
|
if (r->connection->master) {
|
||||||
h2_ctx *ctx = h2_ctx_rget(r);
|
h2_ctx *ctx = h2_ctx_get(r->connection, 0);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; ctx && i < H2_ALEN(H2_VARS); ++i) {
|
for (i = 0; ctx && i < H2_ALEN(H2_VARS); ++i) {
|
||||||
|
@@ -583,6 +583,14 @@ run_connect:
|
|||||||
*/
|
*/
|
||||||
apr_table_setn(ctx->p_conn->connection->notes,
|
apr_table_setn(ctx->p_conn->connection->notes,
|
||||||
"proxy-request-alpn-protos", "h2");
|
"proxy-request-alpn-protos", "h2");
|
||||||
|
if (ctx->p_conn->ssl_hostname) {
|
||||||
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, ctx->owner,
|
||||||
|
"set SNI to %s for (%s)",
|
||||||
|
ctx->p_conn->ssl_hostname,
|
||||||
|
ctx->p_conn->hostname);
|
||||||
|
apr_table_setn(ctx->p_conn->connection->notes,
|
||||||
|
"proxy-request-hostname", ctx->p_conn->ssl_hostname);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user