summaryrefslogtreecommitdiffstats
path: root/modules/http2/h2_switch.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/http2/h2_switch.c')
-rw-r--r--modules/http2/h2_switch.c85
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)