static int h2_task_process_conn(conn_rec* c) { h2_ctx *ctx; if (!c->master) { return DECLINED; } ctx = h2_ctx_get(c, 0); if (h2_ctx_is_task(ctx)) { if (!ctx->task->request->serialize) { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, processing request directly"); h2_task_process_request(ctx->task, c); return DONE; } ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_task(%s), serialized handling", ctx->task->id); } else { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "slave_conn(%ld): has no task", c->id); } return DECLINED; }
int h2_h2_process_conn(conn_rec* c) { h2_ctx *ctx = h2_ctx_get(c, 0); if (ctx) { if (h2_ctx_is_task(c)) { // This should not happend, as we install our own filters // in h2_h2_pre_connection in such cases, so the normal // connection hooks get bypassed. return DECLINED; } else if (!h2_ctx_is_negotiated(c)) { // Let the client/server hellos fly and ALPN call us back. apr_bucket_brigade* temp_brigade = apr_brigade_create( c->pool, c->bucket_alloc); ap_get_brigade(c->input_filters, temp_brigade, AP_MODE_SPECULATIVE, APR_BLOCK_READ, 1); apr_brigade_destroy(temp_brigade); } check_sni_host(c); } ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_h2, connection, start"); if (h2_ctx_is_active(c)) { ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_h2, connection, h2 active"); return h2_conn_main(c); } ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_h2, connection, declined"); return DECLINED; }
static int h2_alt_svc_handler(request_rec *r) { h2_ctx *ctx; h2_config *cfg; int i; if (r->connection->keepalives > 0) { /* Only announce Alt-Svc on the first response */ return DECLINED; } ctx = h2_ctx_rget(r); if (h2_ctx_is_active(ctx) || h2_ctx_is_task(ctx)) { return DECLINED; } cfg = h2_config_rget(r); if (r->hostname && cfg && cfg->alt_svcs && cfg->alt_svcs->nelts > 0) { const char *alt_svc_used = apr_table_get(r->headers_in, "Alt-Svc-Used"); if (!alt_svc_used) { /* We have alt-svcs defined and client is not already using * one, announce the services that were configured and match. * The security of this connection determines if we allow * other host names or ports only. */ const char *alt_svc = ""; const char *svc_ma = ""; int secure = h2_h2_is_tls(r->connection); int ma = h2_config_geti(cfg, H2_CONF_ALT_SVC_MAX_AGE); if (ma >= 0) { svc_ma = apr_psprintf(r->pool, "; ma=%d", ma); } ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "h2_alt_svc: announce %s for %s:%d", (secure? "secure" : "insecure"), r->hostname, (int)r->server->port); for (i = 0; i < cfg->alt_svcs->nelts; ++i) { h2_alt_svc *as = h2_alt_svc_IDX(cfg->alt_svcs, i); const char *ahost = as->host; if (ahost && !apr_strnatcasecmp(ahost, r->hostname)) { ahost = NULL; } if (secure || !ahost) { alt_svc = apr_psprintf(r->pool, "%s%s%s=\"%s:%d\"%s", alt_svc, (*alt_svc? ", " : ""), as->alpn, ahost? ahost : "", as->port, svc_ma); } } if (*alt_svc) { apr_table_set(r->headers_out, "Alt-Svc", alt_svc); } } } return DECLINED; }
int h2_h2_pre_conn(conn_rec* c, void *arg) { ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_h2, pre_connection, start"); h2_ctx *ctx = h2_ctx_get(c, 0); if (!ctx) { ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_h2, pre_connection, no ctx"); /* We have not seen this one yet, are we active? */ h2_config *cfg = h2_config_get(c); if (!h2_config_geti(cfg, H2_CONF_ENABLED)) { ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_h2, pre_connection, h2 not enabled"); return DECLINED; } /* Are we using TLS on this connection? */ if (!h2_h2_is_tls(c)) { ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_h2, pre_connection, no TLS"); return DECLINED; } /* Does mod_ssl offer ALPN/NPN support? */ if (opt_ssl_register_alpn == NULL && opt_ssl_register_npn == NULL) { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "h2_h2, pre_connection, no ALPN/NPN support in mod_ssl"); return DECLINED; } ctx = h2_ctx_get(c, 1); if (opt_ssl_register_alpn) { opt_ssl_register_alpn(c, h2_h2_alpn_propose, h2_h2_alpn_negotiated); } if (opt_ssl_register_npn) { opt_ssl_register_npn(c, h2_h2_npn_advertise, h2_h2_npn_negotiated); } ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_h2, pre_connection, ALPN callback registered"); ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_h2, pre_connection, end"); } else if (h2_ctx_is_task(c)) { /* A connection that represents a http2 stream from another connection. */ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_h2, pre_connection, found stream task"); h2_task *task = h2_ctx_get_task(ctx); return h2_task_pre_conn(task, c); } return DECLINED; }
static int h2_h2_remove_timeout(conn_rec* c) { h2_ctx *ctx = h2_ctx_get(c); if (h2_ctx_is_active(ctx) && !h2_ctx_is_task(ctx)) { /* cleanup on master h2 connections */ ap_remove_input_filter_byhandle(c->input_filters, "reqtimeout"); } return DECLINED; }
int h2_h2_stream_pre_conn(conn_rec* c, void *arg) { h2_ctx *ctx = h2_ctx_get(c, 0); if (ctx && h2_ctx_is_task(c)) { /* This connection is a pseudo-connection used for a h2_task. * Since we read/write directly from it ourselves, we need * to disable a possible ssl connection filter. */ if (opt_ssl_engine_disable) { opt_ssl_engine_disable(c); } } return OK; }
static int h2_task_process_conn(conn_rec* c) { h2_ctx *ctx = h2_ctx_get(c); if (h2_ctx_is_task(ctx)) { if (!ctx->task_env->serialize_headers) { ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_h2, processing request directly"); h2_task_process_request(ctx->task_env); return DONE; } ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_task(%s), serialized handling", ctx->task_env->id); } return DECLINED; }
int h2_h2_cleanup_conn(conn_rec* c) { h2_ctx *ctx = h2_ctx_get(c, 0); if (ctx) { if (h2_ctx_is_task(c)) { /* cleanup on task connections */ ap_remove_input_filter_byhandle(c->input_filters, "reqtimeout"); } else if (!h2_ctx_is_negotiated(c)) { /* cleanup on master h2 connections */ ap_remove_input_filter_byhandle(c->input_filters, "reqtimeout"); } } return DECLINED; }
static int h2_task_pre_conn(conn_rec* c, void *arg) { h2_ctx *ctx = h2_ctx_get(c); (void)arg; if (h2_ctx_is_task(ctx)) { h2_task *task = h2_ctx_get_task(ctx); ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_h2, pre_connection, found stream task"); /* Add our own, network level in- and output filters. */ ap_add_input_filter("H2_TO_H1", task, NULL, c); ap_add_output_filter("H1_TO_H2", task, NULL, c); } return OK; }
static int h2_task_pre_conn(conn_rec* c, void *arg) { h2_ctx *ctx; if (!c->master) { return OK; } ctx = h2_ctx_get(c, 0); (void)arg; if (h2_ctx_is_task(ctx)) { ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_h2, pre_connection, found stream task"); ap_add_input_filter("H2_SLAVE_IN", NULL, NULL, c); ap_add_output_filter("H2_PARSE_H1", NULL, NULL, c); ap_add_output_filter("H2_SLAVE_OUT", NULL, NULL, c); } return OK; }
static int h2_task_pre_conn(conn_rec* c, void *arg) { (void)arg; h2_ctx *ctx = h2_ctx_get(c); if (h2_ctx_is_task(ctx)) { h2_task_env *env = h2_ctx_get_task(ctx); /* This connection is a pseudo-connection used for a h2_task. * Since we read/write directly from it ourselves, we need * to disable a possible ssl connection filter. */ h2_tls_disable(c); ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_h2, pre_connection, found stream task"); /* Add our own, network level in- and output filters. */ ap_add_input_filter("H2_TO_H1", env, NULL, c); ap_add_output_filter("H1_TO_H2", env, NULL, c); } return OK; }
int h2_h2_process_conn(conn_rec* c) { apr_status_t status; h2_ctx *ctx; if (c->master) { return DECLINED; } ctx = h2_ctx_get(c, 0); ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, process_conn"); if (h2_ctx_is_task(ctx)) { /* our stream pseudo connection */ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_h2, task, declined"); return DECLINED; } if (!ctx && c->keepalives == 0) { const char *proto = ap_get_protocol(c); if (APLOGctrace1(c)) { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, process_conn, " "new connection using protocol '%s', direct=%d, " "tls acceptable=%d", proto, h2_allows_h2_direct(c), h2_is_acceptable_connection(c, 1)); } if (!strcmp(AP_PROTOCOL_HTTP1, proto) && h2_allows_h2_direct(c) && h2_is_acceptable_connection(c, 1)) { /* Fresh connection still is on http/1.1 and H2Direct is enabled. * Otherwise connection is in a fully acceptable state. * -> peek at the first 24 incoming bytes */ apr_bucket_brigade *temp; char *s = NULL; apr_size_t slen; temp = apr_brigade_create(c->pool, c->bucket_alloc); status = ap_get_brigade(c->input_filters, temp, AP_MODE_SPECULATIVE, APR_BLOCK_READ, 24); if (status != APR_SUCCESS) { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, c, APLOGNO(03054) "h2_h2, error reading 24 bytes speculative"); apr_brigade_destroy(temp); return DECLINED; } apr_brigade_pflatten(temp, &s, &slen, c->pool); if ((slen >= 24) && !memcmp(H2_MAGIC_TOKEN, s, 24)) { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, direct mode detected"); if (!ctx) { ctx = h2_ctx_get(c, 1); } h2_ctx_protocol_set(ctx, h2_h2_is_tls(c)? "h2" : "h2c"); } else { ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_h2, not detected in %d bytes: %s", (int)slen, s); } apr_brigade_destroy(temp); } } if (ctx) { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "process_conn"); if (!h2_ctx_session_get(ctx)) { status = h2_conn_setup(ctx, c, NULL); ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, c, "conn_setup"); if (status != APR_SUCCESS) { h2_ctx_clear(c); return status; } } return h2_conn_run(ctx, c); } ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, declined"); return DECLINED; }
int h2_h2_process_conn(conn_rec* c) { h2_ctx *ctx = h2_ctx_get(c); ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, process_conn"); if (h2_ctx_is_task(ctx)) { /* our stream pseudo connection */ return DECLINED; } if (h2_ctx_protocol_get(c)) { /* Something has been negotiated */ } else if (!strcmp(AP_PROTOCOL_HTTP1, ap_get_protocol(c)) && h2_allows_h2_direct(c) && h2_is_acceptable_connection(c, 1)) { /* connection still is on http/1.1 and H2Direct is enabled. * Otherwise connection is in a fully acceptable state. * -> peek at the first 24 incoming bytes */ apr_bucket_brigade *temp; apr_status_t status; char *s = NULL; apr_size_t slen; temp = apr_brigade_create(c->pool, c->bucket_alloc); status = ap_get_brigade(c->input_filters, temp, AP_MODE_SPECULATIVE, APR_BLOCK_READ, 24); if (status != APR_SUCCESS) { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, c, "h2_h2, error reading 24 bytes speculative"); apr_brigade_destroy(temp); return DECLINED; } apr_brigade_pflatten(temp, &s, &slen, c->pool); if ((slen >= 24) && !memcmp(H2_MAGIC_TOKEN, s, 24)) { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, direct mode detected"); h2_ctx_protocol_set(ctx, h2_h2_is_tls(c)? "h2" : "h2c"); } else { ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "h2_h2, not detected in %d bytes: %s", (int)slen, s); } apr_brigade_destroy(temp); } else { /* the connection is not HTTP/1.1 or not for us, don't touch it */ return DECLINED; } /* If "h2" was selected as protocol (by whatever mechanism), take over * the connection. */ if (h2_ctx_is_active(ctx)) { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, connection, h2 active"); return h2_conn_process(c, NULL, ctx->server); } ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, declined"); return DECLINED; }