diff options
Diffstat (limited to 'modules/http2/h2_switch.c')
-rw-r--r-- | modules/http2/h2_switch.c | 85 |
1 files changed, 62 insertions, 23 deletions
diff --git a/modules/http2/h2_switch.c b/modules/http2/h2_switch.c index 5e73568..3799701 100644 --- a/modules/http2/h2_switch.c +++ b/modules/http2/h2_switch.c @@ -25,14 +25,17 @@ #include <http_config.h> #include <http_connection.h> #include <http_protocol.h> +#include <http_ssl.h> #include <http_log.h> #include "h2_private.h" +#include "h2.h" #include "h2_config.h" -#include "h2_ctx.h" -#include "h2_conn.h" -#include "h2_h2.h" +#include "h2_conn_ctx.h" +#include "h2_c1.h" +#include "h2_c2.h" +#include "h2_protocol.h" #include "h2_switch.h" /******************************************************************************* @@ -52,10 +55,9 @@ static int h2_protocol_propose(conn_rec *c, request_rec *r, 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; + int is_tls = ap_ssl_conn_is_ssl(c); + const char **protos = is_tls? h2_protocol_ids_tls : h2_protocol_ids_clear; - (void)s; if (!h2_mpm_supported()) { return DECLINED; } @@ -68,7 +70,7 @@ static int h2_protocol_propose(conn_rec *c, request_rec *r, return DECLINED; } - if (!h2_is_acceptable_connection(c, 0)) { + if (!h2_protocol_is_acceptable_c1(c, r, 0)) { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(03084) "protocol propose: connection requirements not met"); return DECLINED; @@ -81,7 +83,7 @@ static int h2_protocol_propose(conn_rec *c, request_rec *r, */ const char *p; - if (!h2_allows_h2_upgrade(c)) { + if (!h2_c1_can_upgrade(r)) { return DECLINED; } @@ -102,9 +104,10 @@ static int h2_protocol_propose(conn_rec *c, request_rec *r, /* 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")) { + if ((p && strcmp(p, "0")) + || (!p && apr_table_get(r->headers_in, "Transfer-Encoding"))) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03087) - "upgrade with content-length: %s, declined", p); + "upgrade with body declined"); return DECLINED; } } @@ -124,11 +127,35 @@ static int h2_protocol_propose(conn_rec *c, request_rec *r, return proposed? DECLINED : OK; } +#if AP_HAS_RESPONSE_BUCKETS +static void remove_output_filters_below(ap_filter_t *f, ap_filter_type ftype) +{ + ap_filter_t *fnext; + + while (f && f->frec->ftype < ftype) { + fnext = f->next; + ap_remove_output_filter(f); + f = fnext; + } +} + +static void remove_input_filters_below(ap_filter_t *f, ap_filter_type ftype) +{ + ap_filter_t *fnext; + + while (f && f->frec->ftype < ftype) { + fnext = f->next; + ap_remove_input_filter(f); + f = fnext; + } +} +#endif + static int h2_protocol_switch(conn_rec *c, request_rec *r, server_rec *s, const char *protocol) { int found = 0; - const char **protos = h2_h2_is_tls(c)? h2_tls_protos : h2_clear_protos; + const char **protos = ap_ssl_conn_is_ssl(c)? h2_protocol_ids_tls : h2_protocol_ids_clear; const char **p = protos; (void)s; @@ -145,35 +172,41 @@ static int h2_protocol_switch(conn_rec *c, request_rec *r, server_rec *s, } if (found) { - h2_ctx *ctx = h2_ctx_get(c, 1); - ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "switching protocol to '%s'", protocol); - h2_ctx_protocol_set(ctx, protocol); - h2_ctx_server_set(ctx, s); - + h2_conn_ctx_create_for_c1(c, s, protocol); + if (r != NULL) { apr_status_t status; +#if AP_HAS_RESPONSE_BUCKETS + /* Switching in the middle of a request means that + * we have to send out the response to this one in h2 + * format. So we need to take over the connection + * and remove all old filters with type up to the + * CONNEDCTION/NETWORK ones. + */ + remove_input_filters_below(r->input_filters, AP_FTYPE_CONNECTION); + remove_output_filters_below(r->output_filters, AP_FTYPE_CONNECTION); +#else /* Switching in the middle of a request means that * we have to send out the response to this one in h2 * format. So we need to take over the connection * right away. */ ap_remove_input_filter_byhandle(r->input_filters, "http_in"); - ap_remove_input_filter_byhandle(r->input_filters, "reqtimeout"); ap_remove_output_filter_byhandle(r->output_filters, "HTTP_HEADER"); - +#endif /* Ok, start an h2_conn on this one. */ - h2_ctx_server_set(ctx, r->server); - status = h2_conn_setup(ctx, r->connection, r); + status = h2_c1_setup(c, r, s); + if (status != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(03088) "session setup"); - h2_ctx_clear(c); + h2_conn_ctx_detach(c); return !OK; } - h2_conn_run(ctx, c); + h2_c1_run(c); } return OK; } @@ -183,7 +216,13 @@ static int h2_protocol_switch(conn_rec *c, request_rec *r, server_rec *s, static const char *h2_protocol_get(const conn_rec *c) { - return h2_ctx_protocol_get(c); + h2_conn_ctx_t *ctx; + + if (c->master) { + c = c->master; + } + ctx = h2_conn_ctx_get(c); + return ctx? ctx->protocol : NULL; } void h2_switch_register_hooks(void) |