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; }
static int h2_protocol_propose(conn_rec *c, request_rec *r, server_rec *s, const apr_array_header_t *offers, apr_array_header_t *proposals) { int proposed = 0; int is_tls = h2_h2_is_tls(c); const char **protos = is_tls? h2_tls_protos : h2_clear_protos; (void)s; if (strcmp(AP_PROTOCOL_HTTP1, ap_get_protocol(c))) { /* We do not know how to switch from anything else but http/1.1. */ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "protocol switch: current proto != http/1.1, declined"); return DECLINED; } if (!h2_is_acceptable_connection(c, 0)) { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "protocol propose: connection requirements not met"); return DECLINED; } if (r) { /* So far, this indicates an HTTP/1 Upgrade header initiated * protocol switch. For that, the HTTP2-Settings header needs * to be present and valid for the connection. */ const char *p; if (!h2_allows_h2_upgrade(c)) { return DECLINED; } p = apr_table_get(r->headers_in, "HTTP2-Settings"); if (!p) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "upgrade without HTTP2-Settings declined"); return DECLINED; } p = apr_table_get(r->headers_in, "Connection"); if (!ap_find_token(r->pool, p, "http2-settings")) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "upgrade without HTTP2-Settings declined"); return DECLINED; } /* We also allow switching only for requests that have no body. */ p = apr_table_get(r->headers_in, "Content-Length"); if (p && strcmp(p, "0")) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "upgrade with content-length: %s, declined", p); return DECLINED; } } while (*protos) { /* Add all protocols we know (tls or clear) and that * are part of the offerings (if there have been any). */ if (!offers || ap_array_str_contains(offers, *protos)) { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "proposing protocol '%s'", *protos); APR_ARRAY_PUSH(proposals, const char*) = *protos; proposed = 1; } ++protos; } return proposed? DECLINED : OK; }
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; }