static int h2_h2_post_read_req(request_rec *r) { /* slave connection? */ if (r->connection->master) { h2_ctx *ctx = h2_ctx_rget(r); struct h2_task *task = h2_ctx_get_task(ctx); /* This hook will get called twice on internal redirects. Take care * that we manipulate filters only once. */ if (task && !task->filters_set) { ap_filter_t *f; ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, "h2_task(%s): adding request filters", task->id); /* setup the correct filters to process the request for h2 */ ap_add_input_filter("H2_REQUEST", task, r, r->connection); /* replace the core http filter that formats response headers * in HTTP/1 with our own that collects status and headers */ ap_remove_output_filter_byhandle(r->output_filters, "HTTP_HEADER"); ap_add_output_filter("H2_RESPONSE", task, r, r->connection); for (f = r->input_filters; f; f = f->next) { if (!strcmp("H2_SLAVE_IN", f->frec->name)) { f->r = r; break; } } ap_add_output_filter("H2_TRAILERS_OUT", task, r, r->connection); task->filters_set = 1; } } return DECLINED; }
static int h2_h2_post_read_req(request_rec *r) { h2_ctx *ctx = h2_ctx_rget(r); struct h2_task *task = h2_ctx_get_task(ctx); if (task) { /* FIXME: sometimes, this hook gets called twice for a single request. * This should not be, right? */ /* h2_task connection for a stream, not for h2c */ ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, "adding h1_to_h2_resp output filter"); if (task->serialize_headers) { ap_remove_output_filter_byhandle(r->output_filters, "H1_TO_H2_RESP"); ap_add_output_filter("H1_TO_H2_RESP", task, r, r->connection); } else { /* replace the core http filter that formats response headers * in HTTP/1 with our own that collects status and headers */ ap_remove_output_filter_byhandle(r->output_filters, "HTTP_HEADER"); ap_remove_output_filter_byhandle(r->output_filters, "H2_RESPONSE"); ap_add_output_filter("H2_RESPONSE", task, r, r->connection); } ap_add_output_filter("H2_TRAILERS", task, r, r->connection); } 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_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_h2_late_fixups(request_rec *r) { /* slave connection? */ if (r->connection->master) { h2_ctx *ctx = h2_ctx_rget(r); struct h2_task *task = h2_ctx_get_task(ctx); if (task) { /* check if we copy vs. setaside files in this location */ task->output.copy_files = h2_config_geti(h2_config_rget(r), H2_CONF_COPY_FILES); if (task->output.copy_files) { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, task->c, "h2_slave_out(%s): copy_files on", task->id); h2_beam_on_file_beam(task->output.beam, h2_beam_no_files, NULL); } check_push(r, "late_fixup"); } } return DECLINED; }
int h2_h2_post_read_req(request_rec *r) { h2_ctx *ctx = h2_ctx_rget(r, 0); struct h2_task *task = ctx? h2_ctx_get_task(ctx) : NULL; if (task) { /* h2_task connection for a stream, not for h2c */ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "adding h1_to_h2_resp output filter"); if (0) { ap_add_output_filter("H1_TO_H2_RESP", task, r, r->connection); } else { /* replace the core http filter that formats response headers * in HTTP/1 with our own that collects status and headers */ ap_remove_output_filter_byhandle(r->output_filters, "HTTP_HEADER"); ap_add_output_filter("H2_RESPONSE", task, r, r->connection); } } return DECLINED; }
static int h2_h2_post_read_req(request_rec *r) { /* slave connection? */ if (r->connection->master) { h2_ctx *ctx = h2_ctx_rget(r); struct h2_task *task = h2_ctx_get_task(ctx); /* This hook will get called twice on internal redirects. Take care * that we manipulate filters only once. */ if (task && !task->filters_set) { ap_filter_t *f; /* setup the correct output filters to process the response * on the proper mod_http2 way. */ ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, "adding task output filter"); if (task->ser_headers) { ap_add_output_filter("H1_TO_H2_RESP", task, r, r->connection); } else { /* replace the core http filter that formats response headers * in HTTP/1 with our own that collects status and headers */ ap_remove_output_filter_byhandle(r->output_filters, "HTTP_HEADER"); ap_add_output_filter("H2_RESPONSE", task, r, r->connection); } /* trailers processing. Incoming trailers are added to this * request via our h2 input filter, outgoing trailers * in a special h2 out filter. */ for (f = r->input_filters; f; f = f->next) { if (!strcmp("H2_TO_H1", f->frec->name)) { f->r = r; break; } } ap_add_output_filter("H2_TRAILERS", task, r, r->connection); task->filters_set = 1; } } return DECLINED; }
int h2_filter_h2_status_handler(request_rec *r) { h2_ctx *ctx = h2_ctx_rget(r); h2_task *task; if (strcmp(r->handler, "http2-status")) { return DECLINED; } if (r->method_number != M_GET) { return DECLINED; } task = ctx? h2_ctx_get_task(ctx) : NULL; if (task) { /* We need to handle the actual output on the main thread, as * we need to access h2_session information. */ apr_table_setn(r->notes, H2_RESP_SOS_NOTE, H2_SOS_H2_STATUS); apr_table_setn(r->headers_out, "Content-Type", "application/json"); r->status = 200; return DONE; } return DECLINED; }
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; }