Apache HTTPD
h2_c2.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <assert.h>
18#include <stddef.h>
19
20#include <apr_atomic.h>
21#include <apr_strings.h>
22
23#include <httpd.h>
24#include <http_core.h>
25#include <http_config.h>
26#include <http_connection.h>
27#include <http_protocol.h>
28#include <http_request.h>
29#include <http_log.h>
30#include <http_vhost.h>
31#include <util_filter.h>
32#include <ap_mmn.h>
33#include <ap_mpm.h>
34#include <mpm_common.h>
35#include <mod_core.h>
36#include <scoreboard.h>
37
38#include "h2_private.h"
39#include "h2.h"
40#include "h2_bucket_beam.h"
41#include "h2_c1.h"
42#include "h2_config.h"
43#include "h2_conn_ctx.h"
44#include "h2_c2_filter.h"
45#include "h2_protocol.h"
46#include "h2_mplx.h"
47#include "h2_request.h"
48#include "h2_headers.h"
49#include "h2_session.h"
50#include "h2_stream.h"
51#include "h2_ws.h"
52#include "h2_c2.h"
53#include "h2_util.h"
54#include "mod_http2.h"
55
56
57static module *mpm_module;
58static int mpm_supported = 1;
60
61#if AP_HAS_RESPONSE_BUCKETS
62
67
68#endif /* AP_HAS_RESPONSE_BUCKETS */
69
70static void check_modules(int force)
71{
72 static int checked = 0;
73 int i;
74
75 if (force || !checked) {
76 for (i = 0; ap_loaded_modules[i]; ++i) {
77 module *m = ap_loaded_modules[i];
78
79 if (!strcmp("event.c", m->name)) {
80 mpm_module = m;
81 break;
82 }
83 else if (!strcmp("motorz.c", m->name)) {
84 mpm_module = m;
85 break;
86 }
87 else if (!strcmp("mpm_netware.c", m->name)) {
88 mpm_module = m;
89 break;
90 }
91 else if (!strcmp("prefork.c", m->name)) {
92 mpm_module = m;
93 /* While http2 can work really well on prefork, it collides
94 * today's use case for prefork: running single-thread app engines
95 * like php. If we restrict h2_workers to 1 per process, php will
96 * work fine, but browser will be limited to 1 active request at a
97 * time. */
98 mpm_supported = 0;
99 break;
100 }
101 else if (!strcmp("simple_api.c", m->name)) {
102 mpm_module = m;
103 mpm_supported = 0;
104 break;
105 }
106 else if (!strcmp("mpm_winnt.c", m->name)) {
107 mpm_module = m;
108 break;
109 }
110 else if (!strcmp("worker.c", m->name)) {
111 mpm_module = m;
112 break;
113 }
114 }
115 checked = 1;
116 }
117}
118
119const char *h2_conn_mpm_name(void)
120{
121 check_modules(0);
122 return mpm_module? mpm_module->name : "unknown";
123}
124
126{
127 check_modules(0);
128 return mpm_supported;
129}
130
137
138static void h2_c2_log_io(conn_rec *c2, apr_off_t bytes_sent)
139{
140 if (bytes_sent && h2_c_logio_add_bytes_out) {
141 h2_c_logio_add_bytes_out(c2, bytes_sent);
142 }
143}
144
146{
148
150 "h2_c2(%s): destroy", c2->log_id);
151 if(!c2->aborted && conn_ctx && conn_ctx->bytes_sent) {
152 h2_c2_log_io(c2, conn_ctx->bytes_sent);
153 }
155}
156
158{
160
162 AP_DEBUG_ASSERT(conn_ctx->stream_id);
163 if(!c2->aborted && conn_ctx->bytes_sent) {
164 h2_c2_log_io(c2, conn_ctx->bytes_sent);
165 }
166
167 if (conn_ctx->beam_in) {
168 h2_beam_abort(conn_ctx->beam_in, from);
169 }
170 if (conn_ctx->beam_out) {
171 h2_beam_abort(conn_ctx->beam_out, from);
172 }
173 c2->aborted = 1;
174}
175
176typedef struct {
177 apr_bucket_brigade *bb; /* c2: data in holding area */
178 unsigned did_upgrade_eos:1; /* for Upgrade, we added an extra EOS */
180
186{
188 h2_c2_fctx_in_t *fctx = f->ctx;
190 apr_bucket *b;
191 apr_off_t bblen;
194
197
198 if (mode == AP_MODE_INIT) {
199 return ap_get_brigade(f->c->input_filters, bb, mode, block, readbytes);
200 }
201
202 if (f->c->aborted) {
203 return APR_ECONNABORTED;
204 }
205
206 if (APLOGctrace3(f->c)) {
208 "h2_c2_in(%s-%d): read, mode=%d, block=%d, readbytes=%ld",
209 conn_ctx->id, conn_ctx->stream_id, mode, block,
210 (long)readbytes);
211 }
212
213 if (!fctx) {
214 fctx = apr_pcalloc(f->c->pool, sizeof(*fctx));
215 f->ctx = fctx;
216 fctx->bb = apr_brigade_create(f->c->pool, f->c->bucket_alloc);
217 if (!conn_ctx->beam_in) {
218 b = apr_bucket_eos_create(f->c->bucket_alloc);
220 }
221 }
222
223 /* If this is a HTTP Upgrade, it means the request we process
224 * has not Content, although the stream is not necessarily closed.
225 * On first read, we insert an EOS to signal processing that it
226 * has the complete body. */
227 if (conn_ctx->is_upgrade && !fctx->did_upgrade_eos) {
228 b = apr_bucket_eos_create(f->c->bucket_alloc);
230 fctx->did_upgrade_eos = 1;
231 }
232
233 while (APR_BRIGADE_EMPTY(fctx->bb)) {
234 /* Get more input data for our request. */
235 if (APLOGctrace2(f->c)) {
237 "h2_c2_in(%s-%d): get more data from mplx, block=%d, "
238 "readbytes=%ld",
239 conn_ctx->id, conn_ctx->stream_id, block, (long)readbytes);
240 }
241 if (conn_ctx->beam_in) {
242 if (conn_ctx->pipe_in[H2_PIPE_OUT]) {
243receive:
244 status = h2_beam_receive(conn_ctx->beam_in, f->c, fctx->bb, APR_NONBLOCK_READ,
245 conn_ctx->mplx->stream_max_mem);
248 if (APR_SUCCESS == status) {
249 goto receive;
250 }
251 }
252 }
253 else {
254 status = h2_beam_receive(conn_ctx->beam_in, f->c, fctx->bb, block,
255 conn_ctx->mplx->stream_max_mem);
256 }
257 }
258 else {
259 status = APR_EOF;
260 }
261
262 if (APLOGctrace3(f->c)) {
264 "h2_c2_in(%s-%d): read returned",
265 conn_ctx->id, conn_ctx->stream_id);
266 }
269 /* chunked input handling does not seem to like it if we
270 * return with APR_EAGAIN from a GETLINE read...
271 * upload 100k test on test-ser.example.org hangs */
273 }
274 else if (APR_STATUS_IS_EOF(status)) {
275 break;
276 }
277 else if (status != APR_SUCCESS) {
278 conn_ctx->last_err = status;
279 return status;
280 }
281
282 if (APLOGctrace3(f->c)) {
283 h2_util_bb_log(f->c, conn_ctx->stream_id, APLOG_TRACE3,
284 "c2 input recv raw", fctx->bb);
285 }
287 apr_brigade_length(bb, 0, &bblen);
288 h2_c_logio_add_bytes_in(f->c, bblen);
289 }
290 }
291
292 /* Nothing there, no more data to get. Return. */
293 if (status == APR_EOF && APR_BRIGADE_EMPTY(fctx->bb)) {
294 return status;
295 }
296
297 if (APLOGctrace3(f->c)) {
298 h2_util_bb_log(f->c, conn_ctx->stream_id, APLOG_TRACE3,
299 "c2 input.bb", fctx->bb);
300 }
301
302 if (APR_BRIGADE_EMPTY(fctx->bb)) {
303 if (APLOGctrace3(f->c)) {
305 "h2_c2_in(%s-%d): no data",
306 conn_ctx->id, conn_ctx->stream_id);
307 }
309 }
310
311 if (mode == AP_MODE_EXHAUSTIVE) {
312 /* return all we have */
313 APR_BRIGADE_CONCAT(bb, fctx->bb);
314 }
315 else if (mode == AP_MODE_READBYTES) {
317 }
318 else if (mode == AP_MODE_SPECULATIVE) {
319 status = h2_brigade_copy_length(bb, fctx->bb, rmax);
320 }
321 else if (mode == AP_MODE_GETLINE) {
322 /* we are reading a single LF line, e.g. the HTTP headers.
323 * this has the nasty side effect to split the bucket, even
324 * though it ends with CRLF and creates a 0 length bucket */
327 if (APLOGctrace3(f->c)) {
328 char buffer[1024];
329 apr_size_t len = sizeof(buffer)-1;
331 buffer[len] = 0;
333 "h2_c2_in(%s-%d): getline: %s",
334 conn_ctx->id, conn_ctx->stream_id, buffer);
335 }
336 }
337 else {
338 /* Hmm, well. There is mode AP_MODE_EATCRLF, but we chose not
339 * to support it. Seems to work. */
341 APLOGNO(03472)
342 "h2_c2_in(%s-%d), unsupported READ mode %d",
343 conn_ctx->id, conn_ctx->stream_id, mode);
345 }
346
347 if (APLOGctrace3(f->c)) {
348 apr_brigade_length(bb, 0, &bblen);
350 "h2_c2_in(%s-%d): %ld data bytes",
351 conn_ctx->id, conn_ctx->stream_id, (long)bblen);
352 }
353 return status;
354}
355
357{
358 apr_off_t written = 0;
359 apr_status_t rv;
360
361 rv = h2_beam_send(conn_ctx->beam_out, c2, bb, APR_BLOCK_READ, &written);
362 if (APR_STATUS_IS_EAGAIN(rv)) {
363 rv = APR_SUCCESS;
364 }
365 return rv;
366}
367
369{
371 apr_status_t rv;
372
373 if (bb == NULL) {
374#if !AP_MODULE_MAGIC_AT_LEAST(20180720, 1)
375 f->c->data_in_output_filters = 0;
376#endif
377 return APR_SUCCESS;
378 }
379
381#if AP_HAS_RESPONSE_BUCKETS
382 if (!conn_ctx->has_final_response) {
383 apr_bucket *e;
384
385 for (e = APR_BRIGADE_FIRST(bb);
386 e != APR_BRIGADE_SENTINEL(bb);
388 {
391 if (resp->status >= 200) {
392 conn_ctx->has_final_response = 1;
393 break;
394 }
395 }
396 if (APR_BUCKET_IS_EOS(e)) {
397 break;
398 }
399 }
400 }
401#endif /* AP_HAS_RESPONSE_BUCKETS */
402 rv = beam_out(f->c, conn_ctx, bb);
403
405 "h2_c2(%s-%d): output leave",
406 conn_ctx->id, conn_ctx->stream_id);
407 if (APR_SUCCESS != rv) {
408 h2_c2_abort(f->c, f->c);
409 }
410 return rv;
411}
412
413static int addn_headers(void *udata, const char *name, const char *value)
414{
417 return 1;
418}
419
420static void check_early_hints(request_rec *r, const char *tag)
421{
423 apr_table_t *early_headers = h2_config_early_headers(r);
424
425 if (!r->expecting_100 &&
426 ((push_list && push_list->nelts > 0) ||
427 (early_headers && !apr_is_empty_table(early_headers)))) {
428 int have_hints = 0, i;
429
430 if (push_list && push_list->nelts > 0) {
432 "%s, early announcing %d resources for push",
433 tag, push_list->nelts);
434 for (i = 0; i < push_list->nelts; ++i) {
435 h2_push_res *push = &APR_ARRAY_IDX(push_list, i, h2_push_res);
436 apr_table_add(r->headers_out, "Link",
437 apr_psprintf(r->pool, "<%s>; rel=preload%s",
438 push->uri_ref, push->critical? "; critical" : ""));
439 }
440 have_hints = 1;
441 }
442 if (early_headers && !apr_is_empty_table(early_headers)) {
443 apr_table_do(addn_headers, r->headers_out, early_headers, NULL);
444 have_hints = 1;
445 }
446
447 if (have_hints) {
448 int old_status;
449 const char *old_line;
450
451 if (h2_config_rgeti(r, H2_CONF_PUSH) == 0 &&
454 }
457 r->status = 103;
458 r->status_line = "103 Early Hints";
462 }
463 }
464}
465
467{
468 conn_rec *c2 = r->connection;
470
471 if (!c2->master || !(conn_ctx = h2_conn_ctx_get(c2)) || !conn_ctx->stream_id) {
472 return DECLINED;
473 }
474
475 check_early_hints(r, "late_fixup");
476
477 return DECLINED;
478}
479
481 struct apr_pollfd_t *pfd,
483{
484#if H2_USE_PIPES
485 if (c->master) {
487 if (ctx) {
488 if (ctx->beam_in && ctx->pipe_in[H2_PIPE_OUT]) {
490 pfd->desc.f = ctx->pipe_in[H2_PIPE_OUT];
491 if (ptimeout)
492 *ptimeout = h2_beam_timeout_get(ctx->beam_in);
493 }
494 else {
495 /* no input */
496 pfd->desc_type = APR_NO_DESC;
497 if (ptimeout)
498 *ptimeout = -1;
499 }
500 return APR_SUCCESS;
501 }
502 }
503#else
504 (void)c;
505 (void)pfd;
506 (void)ptimeout;
507#endif /* H2_USE_PIPES */
508 return APR_ENOTIMPL;
509}
510
511#if AP_HAS_RESPONSE_BUCKETS
512
513static void c2_pre_read_request(request_rec *r, conn_rec *c2)
514{
516
517 if (!c2->master || !(conn_ctx = h2_conn_ctx_get(c2)) || !conn_ctx->stream_id) {
518 return;
519 }
521 "h2_c2(%s-%d): adding request filters",
522 conn_ctx->id, conn_ctx->stream_id);
525}
526
528{
530 conn_rec *c2 = r->connection;
532
533 if (!c2->master || !(conn_ctx = h2_conn_ctx_get(c2)) || !conn_ctx->stream_id) {
534 return DECLINED;
535 }
536 /* Now that the request_rec is fully initialized, set relevant params */
537 conn_ctx->server = r->server;
539 if (timeout <= 0) {
541 }
543 /* We only handle this one request on the connection and tell everyone
544 * that there is no need to keep it "clean" if something fails. Also,
545 * this prevents mod_reqtimeout from doing funny business with monitoring
546 * keepalive timeouts.
547 */
549
550 if (conn_ctx->beam_in && !apr_table_get(r->headers_in, "Content-Length")) {
551 r->body_indeterminate = 1;
552 }
553
556 "h2_mplx(%s-%d): copy_files in output",
557 conn_ctx->id, conn_ctx->stream_id);
558 h2_beam_set_copy_files(conn_ctx->beam_out, 1);
559 }
560
561 /* Add the raw bytes of the request (e.g. header frame lengths to
562 * the logio for this request. */
563 if (conn_ctx->request->raw_bytes && h2_c_logio_add_bytes_in) {
564 h2_c_logio_add_bytes_in(c2, conn_ctx->request->raw_bytes);
565 }
566 return OK;
567}
568
569static int c2_hook_pre_connection(conn_rec *c2, void *csd)
570{
572
573 if (!c2->master || !(conn_ctx = h2_conn_ctx_get(c2)) || !conn_ctx->stream_id) {
574 return DECLINED;
575 }
576
578 "h2_c2(%s-%d), adding filters",
579 conn_ctx->id, conn_ctx->stream_id);
582 if (c2->keepalives == 0) {
583 /* Simulate that we had already a request on this connection. Some
584 * hooks trigger special behaviour when keepalives is 0.
585 * (Not necessarily in pre_connection, but later. Set it here, so it
586 * is in place.) */
587 c2->keepalives = 1;
588 /* We signal that this connection will be closed after the request.
589 * Which is true in that sense that we throw away all traffic data
590 * on this c2 connection after each requests. Although we might
591 * reuse internal structures like memory pools.
592 * The wanted effect of this is that httpd does not try to clean up
593 * any dangling data on this connection when a request is done. Which
594 * is unnecessary on a h2 stream.
595 */
597 }
598 return OK;
599}
600
601void h2_c2_register_hooks(void)
602{
603 /* When the connection processing actually starts, we might
604 * take over, if the connection is for a h2 stream.
605 */
608
609 /* We need to manipulate the standard HTTP/1.1 protocol filters and
610 * install our own. This needs to be done very early. */
615#if H2_USE_POLLFD_FROM_CONN
618#endif
620
633}
634
635#else /* AP_HAS_RESPONSE_BUCKETS */
636
638{
639 if (c2->keepalives == 0) {
640 /* Simulate that we had already a request on this connection. Some
641 * hooks trigger special behaviour when keepalives is 0.
642 * (Not necessarily in pre_connection, but later. Set it here, so it
643 * is in place.) */
644 c2->keepalives = 1;
645 /* We signal that this connection will be closed after the request.
646 * Which is true in that sense that we throw away all traffic data
647 * on this c2 connection after each requests. Although we might
648 * reuse internal structures like memory pools.
649 * The wanted effect of this is that httpd does not try to clean up
650 * any dangling data on this connection when a request is done. Which
651 * is unnecessary on a h2 stream.
652 */
654 return ap_run_pre_connection(c2, csd);
655 }
657 return APR_SUCCESS;
658}
659
661{
663
665 ap_assert(conn_ctx->mplx);
666
667 /* See the discussion at <https://github.com/icing/mod_h2/issues/195>
668 *
669 * Each conn_rec->id is supposed to be unique at a point in time. Since
670 * some modules (and maybe external code) uses this id as an identifier
671 * for the request_rec they handle, it needs to be unique for secondary
672 * connections also.
673 *
674 * The MPM module assigns the connection ids and mod_unique_id is using
675 * that one to generate identifier for requests. While the implementation
676 * works for HTTP/1.x, the parallel execution of several requests per
677 * connection will generate duplicate identifiers on load.
678 *
679 * The original implementation for secondary connection identifiers used
680 * to shift the master connection id up and assign the stream id to the
681 * lower bits. This was cramped on 32 bit systems, but on 64bit there was
682 * enough space.
683 *
684 * As issue 195 showed, mod_unique_id only uses the lower 32 bit of the
685 * connection id, even on 64bit systems. Therefore collisions in request ids.
686 *
687 * The way master connection ids are generated, there is some space "at the
688 * top" of the lower 32 bits on allmost all systems. If you have a setup
689 * with 64k threads per child and 255 child processes, you live on the edge.
690 *
691 * The new implementation shifts 8 bits and XORs in the worker
692 * id. This will experience collisions with > 256 h2 workers and heavy
693 * load still. There seems to be no way to solve this in all possible
694 * configurations by mod_h2 alone.
695 */
696 c2->id = (c2->master->id << 8)^worker_id;
697
698 if (!conn_ctx->pre_conn_done) {
700 "h2_c2(%s-%d), adding filters",
701 conn_ctx->id, conn_ctx->stream_id);
702 ap_add_input_filter("H2_C2_NET_IN", NULL, NULL, c2);
703 ap_add_output_filter("H2_C2_NET_CATCH_H1", NULL, NULL, c2);
704 ap_add_output_filter("H2_C2_NET_OUT", NULL, NULL, c2);
705
707 conn_ctx->pre_conn_done = 1;
708 }
709
711 "h2_c2(%s-%d): process connection",
712 conn_ctx->id, conn_ctx->stream_id);
713
714 c2->current_thread = thread;
716
718 "h2_c2(%s-%d): processing done",
719 conn_ctx->id, conn_ctx->stream_id);
720
721 return APR_SUCCESS;
722}
723
725{
726 const h2_request *req = conn_ctx->request;
727 conn_state_t *cs = c->cs;
728 request_rec *r = NULL;
729 const char *tenc;
732
733 if (req->protocol && !strcmp("websocket", req->protocol)) {
734 req = h2_ws_rewrite_request(req, c, conn_ctx->beam_in == NULL);
735 if (!req) {
736 rv = APR_EGENERAL;
737 goto cleanup;
738 }
739 }
740
741 r = h2_create_request_rec(req, c, conn_ctx->beam_in == NULL);
742
743 if (!r) {
745 "h2_c2(%s-%d): create request_rec failed, r=NULL",
746 conn_ctx->id, conn_ctx->stream_id);
747 goto cleanup;
748 }
749 if (r->status != HTTP_OK) {
751 "h2_c2(%s-%d): create request_rec failed, r->status=%d",
752 conn_ctx->id, conn_ctx->stream_id, r->status);
753 goto cleanup;
754 }
755
756 tenc = apr_table_get(r->headers_in, "Transfer-Encoding");
757 conn_ctx->input_chunked = tenc && ap_is_chunked(r->pool, tenc);
758
760 "h2_c2(%s-%d): created request_rec for %s",
761 conn_ctx->id, conn_ctx->stream_id, r->the_request);
762 conn_ctx->server = r->server;
764 if (timeout <= 0) {
766 }
768
771 "h2_mplx(%s-%d): copy_files in output",
772 conn_ctx->id, conn_ctx->stream_id);
773 h2_beam_set_copy_files(conn_ctx->beam_out, 1);
774 }
775
777 if (cs) {
779 }
781 "h2_c2(%s-%d): start process_request",
782 conn_ctx->id, conn_ctx->stream_id);
783
784 /* Add the raw bytes of the request (e.g. header frame lengths to
785 * the logio for this request. */
788 }
789
791 /* After the call to ap_process_request, the
792 * request pool may have been deleted. */
793 r = NULL;
794 if (conn_ctx->beam_out) {
795 h2_beam_close(conn_ctx->beam_out, c);
796 }
797
799 "h2_c2(%s-%d): process_request done",
800 conn_ctx->id, conn_ctx->stream_id);
801 if (cs)
803
804cleanup:
805 return rv;
806}
807
810{
812 conn_rec *c2;
813 void *cfg;
814
815 ap_assert(c1);
817 "h2_c2: create for c1(%ld)", c1->id);
818
819 /* We create a pool with its own allocator to be used for
820 * processing a request. This is the only way to have the processing
821 * independent of its parent pool in the sense that it can work in
822 * another thread.
823 */
825 apr_pool_tag(pool, "h2_c2_conn");
826
827 c2 = (conn_rec *) apr_palloc(pool, sizeof(conn_rec));
828 memcpy(c2, c1, sizeof(conn_rec));
829
830 c2->master = c1;
831 c2->pool = pool;
833 c2->notes = apr_table_make(pool, 5);
834 c2->input_filters = NULL;
835 c2->output_filters = NULL;
836 c2->keepalives = 0;
837#if AP_MODULE_MAGIC_AT_LEAST(20180903, 1)
838 c2->filter_conn_ctx = NULL;
839#endif
841#if !AP_MODULE_MAGIC_AT_LEAST(20180720, 1)
842 c2->data_in_input_filters = 0;
844#endif
845 /* prevent mpm_event from making wrong assumptions about this connection,
846 * like e.g. using its socket for an async read check. */
848 c2->log = NULL;
849 c2->aborted = 0;
850 /* We cannot install the master connection socket on the secondary, as
851 * modules mess with timeouts/blocking of the socket, with
852 * unwanted side effects to the master connection processing.
853 * Fortunately, since we never use the secondary socket, we can just install
854 * a single, process-wide dummy and everyone is happy.
855 */
857 /* TODO: these should be unique to this thread */
858 c2->sbh = NULL; /*c1->sbh;*/
859 /* TODO: not all mpm modules have learned about secondary connections yet.
860 * copy their config from master to secondary.
861 */
862 if (mpm_module) {
863 cfg = ap_get_module_config(c1->conn_config, mpm_module);
864 ap_set_module_config(c2->conn_config, mpm_module, cfg);
865 }
866
868 "h2_c2(%s): created", c2->log_id);
869 return c2;
870}
871
873{
875
876 if (conn_ctx && conn_ctx->stream_id && ap_is_initial_req(r)) {
877
879 "h2_c2(%s-%d): adding request filters",
880 conn_ctx->id, conn_ctx->stream_id);
881
882 /* setup the correct filters to process the request for h2 */
883 ap_add_input_filter("H2_C2_REQUEST_IN", NULL, r, r->connection);
884
885 /* replace the core http filter that formats response headers
886 * in HTTP/1 with our own that collects status and headers */
888
889 ap_add_output_filter("H2_C2_RESPONSE_OUT", NULL, r, r->connection);
890 ap_add_output_filter("H2_C2_TRAILERS_OUT", NULL, r, r->connection);
891 }
892 return DECLINED;
893}
894
896{
898
899 if (!c->master) {
900 return DECLINED;
901 }
902
904 if (ctx->stream_id) {
906 "h2_h2, processing request directly");
907 c2_process(ctx, c);
908 return DONE;
909 }
910 else {
912 "secondary_conn(%ld): no h2 stream assing?", c->id);
913 }
914 return DECLINED;
915}
916
918{
919 /* When the connection processing actually starts, we might
920 * take over, if the connection is for a h2 stream.
921 */
924 /* We need to manipulate the standard HTTP/1.1 protocol filters and
925 * install our own. This needs to be done very early. */
928#if H2_USE_POLLFD_FROM_CONN
931#endif
933
940
947}
948
949#endif /* else AP_HAS_RESPONSE_BUCKETS */
Module Magic Number.
Apache Multi-Processing Module library.
const char apr_size_t len
Definition ap_regex.h:187
APR Atomic Operations.
APR Strings library.
ap_conf_vector_t * ap_create_conn_config(apr_pool_t *p)
Definition config.c:361
int ap_run_pre_connection(conn_rec *c, void *csd)
Definition connection.c:43
int ap_run_process_connection(conn_rec *c)
Definition connection.c:42
void ap_hook_process_connection(ap_HOOK_process_connection_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition connection.c:42
void ap_hook_pre_connection(ap_HOOK_pre_connection_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition connection.c:43
#define ap_get_module_config(v, m)
#define ap_set_module_config(v, m, val)
request_rec * r
void * csd
#define HUGE_STRING_LEN
Definition httpd.h:303
#define DECLINED
Definition httpd.h:457
#define OK
Definition httpd.h:456
#define DONE
Definition httpd.h:458
ap_filter_t * ap_add_input_filter(const char *name, void *ctx, request_rec *r, conn_rec *c)
apr_status_t ap_remove_output_filter_byhandle(ap_filter_t *next, const char *handle)
ap_filter_t * ap_add_input_filter_handle(ap_filter_rec_t *f, void *ctx, request_rec *r, conn_rec *c)
ap_filter_rec_t * ap_register_output_filter(const char *name, ap_out_filter_func filter_func, ap_init_filter_func filter_init, ap_filter_type ftype)
ap_filter_t * ap_add_output_filter(const char *name, void *ctx, request_rec *r, conn_rec *c)
apr_status_t ap_filter_rec_t * ap_register_input_filter(const char *name, ap_in_filter_func filter_func, ap_init_filter_func filter_init, ap_filter_type ftype)
ap_filter_t * ap_add_output_filter_handle(ap_filter_rec_t *f, void *ctx, request_rec *r, conn_rec *c)
apr_status_t ap_get_brigade(ap_filter_t *filter, apr_bucket_brigade *bucket, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes)
@ AP_FTYPE_NETWORK
@ AP_FTYPE_PROTOCOL
apr_socket_t * ap_get_conn_socket(conn_rec *c)
Definition core.c:5202
void ap_hook_get_pollfd_from_conn(ap_HOOK_get_pollfd_from_conn_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition core.c:113
#define APLOGNO(n)
Definition http_log.h:117
#define APLOGctrace2(c)
Definition http_log.h:258
#define ap_log_rerror
Definition http_log.h:454
#define APLOG_ERR
Definition http_log.h:67
#define APLOG_TRACE3
Definition http_log.h:74
#define ap_log_cerror
Definition http_log.h:498
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_TRACE2
Definition http_log.h:73
#define APLOGctrace3(c)
Definition http_log.h:259
#define APLOG_TRACE1
Definition http_log.h:72
void ap_send_interim_response(request_rec *r, int send_headers)
Definition protocol.c:2316
void ap_hook_pre_read_request(ap_HOOK_pre_read_request_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition protocol.c:2583
void ap_hook_post_read_request(ap_HOOK_post_read_request_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition protocol.c:2585
void ap_process_request(request_rec *r)
int ap_is_initial_req(request_rec *r)
Definition request.c:2567
void ap_hook_fixups(ap_HOOK_fixups_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition request.c:87
#define APR_EAGAIN
Definition apr_errno.h:730
#define APR_EGENERAL
Definition apr_errno.h:313
#define APR_EOF
Definition apr_errno.h:461
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_ECONNABORTED
Definition apr_errno.h:769
#define APR_STATUS_IS_EAGAIN(s)
Definition apr_errno.h:1272
#define APR_STATUS_IS_EOF(s)
Definition apr_errno.h:567
apr_file_t * f
#define APR_BRIGADE_INSERT_TAIL(b, e)
#define APR_BUCKET_NEXT(e)
apr_read_type_e
Definition apr_buckets.h:57
apr_bucket * e
#define APR_BRIGADE_CONCAT(a, b)
#define APR_BRIGADE_EMPTY(b)
#define APR_BRIGADE_SENTINEL(b)
#define APR_BUCKET_IS_EOS(e)
apr_brigade_flush void * ctx
#define APR_BRIGADE_FIRST(b)
@ APR_BLOCK_READ
Definition apr_buckets.h:58
@ APR_NONBLOCK_READ
Definition apr_buckets.h:59
apr_dbd_transaction_t int mode
Definition apr_dbd.h:261
#define APR_HOOK_FIRST
Definition apr_hooks.h:301
#define APR_HOOK_LAST
Definition apr_hooks.h:305
#define APR_HOOK_REALLY_FIRST
Definition apr_hooks.h:299
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
#define APR_REGISTER_OPTIONAL_FN(name)
#define HTTP_OK
Definition httpd.h:490
#define APR_PROTO_TCP
const char const char int ap_is_chunked(apr_pool_t *p, const char *line)
Definition util.c:1786
#define AP_DEBUG_ASSERT(exp)
Definition httpd.h:2283
#define ap_assert(exp)
Definition httpd.h:2271
@ AP_CONN_CLOSE
Definition httpd.h:1145
@ CONN_STATE_WRITE_COMPLETION
Definition httpd.h:1262
@ CONN_STATE_HANDLER
Definition httpd.h:1261
apr_size_t size
const char int apr_pool_t * pool
Definition apr_cstr.h:84
const char * value
Definition apr_env.h:51
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
void const char apr_status_t(* cleanup)(void *))
char * buffer
apr_vformatter_buff_t * c
Definition apr_lib.h:175
#define APR_INET
@ APR_POLL_FILE
Definition apr_poll.h:94
@ APR_NO_DESC
Definition apr_poll.h:92
apr_pool_t * b
Definition apr_pools.h:529
apr_pool_t * parent
Definition apr_pools.h:197
#define apr_pool_create(newpool, parent)
Definition apr_pools.h:322
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const char * s
Definition apr_strings.h:95
const void * m
#define APR_ARRAY_IDX(ary, i, type)
Definition apr_tables.h:141
int int status
apr_int64_t apr_interval_time_t
Definition apr_time.h:55
apr_int64_t apr_time_t
Definition apr_time.h:45
#define H2_PUSH_MODE_NOTE
Definition h2.h:200
void h2_beam_abort(h2_bucket_beam *beam, conn_rec *c)
apr_interval_time_t h2_beam_timeout_get(h2_bucket_beam *beam)
void h2_beam_close(h2_bucket_beam *beam, conn_rec *c)
apr_status_t h2_beam_send(h2_bucket_beam *beam, conn_rec *from, apr_bucket_brigade *sender_bb, apr_read_type_e block, apr_off_t *pwritten)
void h2_beam_set_copy_files(h2_bucket_beam *beam, int enabled)
apr_status_t h2_beam_receive(h2_bucket_beam *beam, conn_rec *to, apr_bucket_brigade *bb, apr_read_type_e block, apr_off_t readbytes)
apr_OFN_ap_logio_add_bytes_in_t * h2_c_logio_add_bytes_in
Definition h2_c1.c:52
apr_OFN_ap_logio_add_bytes_out_t * h2_c_logio_add_bytes_out
Definition h2_c1.c:53
static int c2_hook_fixups(request_rec *r)
Definition h2_c2.c:466
static apr_socket_t * dummy_socket
Definition h2_c2.c:59
static void check_early_hints(request_rec *r, const char *tag)
Definition h2_c2.c:420
void h2_c2_abort(conn_rec *c2, conn_rec *from)
Definition h2_c2.c:157
static int h2_c2_hook_process(conn_rec *c)
Definition h2_c2.c:895
conn_rec * h2_c2_create(conn_rec *c1, apr_pool_t *parent, apr_bucket_alloc_t *buckt_alloc)
Definition h2_c2.c:808
static apr_status_t beam_out(conn_rec *c2, h2_conn_ctx_t *conn_ctx, apr_bucket_brigade *bb)
Definition h2_c2.c:356
void h2_c2_register_hooks(void)
Definition h2_c2.c:917
void h2_c2_destroy(conn_rec *c2)
Definition h2_c2.c:145
int h2_mpm_supported(void)
Definition h2_c2.c:125
static int addn_headers(void *udata, const char *name, const char *value)
Definition h2_c2.c:413
static apr_status_t http2_get_pollfd_from_conn(conn_rec *c, struct apr_pollfd_t *pfd, apr_interval_time_t *ptimeout)
Definition h2_c2.c:480
apr_status_t h2_c2_child_init(apr_pool_t *pool, server_rec *s)
Definition h2_c2.c:131
static int mpm_supported
Definition h2_c2.c:58
static apr_status_t h2_c2_filter_in(ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes)
Definition h2_c2.c:181
static int h2_c2_hook_post_read_request(request_rec *r)
Definition h2_c2.c:872
apr_status_t h2_c2_process(conn_rec *c2, apr_thread_t *thread, int worker_id)
Definition h2_c2.c:660
const char * h2_conn_mpm_name(void)
Definition h2_c2.c:119
static void check_modules(int force)
Definition h2_c2.c:70
static apr_status_t c2_run_pre_connection(conn_rec *c2, apr_socket_t *csd)
Definition h2_c2.c:637
static void h2_c2_log_io(conn_rec *c2, apr_off_t bytes_sent)
Definition h2_c2.c:138
static apr_status_t h2_c2_filter_out(ap_filter_t *f, apr_bucket_brigade *bb)
Definition h2_c2.c:368
static apr_status_t c2_process(h2_conn_ctx_t *conn_ctx, conn_rec *c)
Definition h2_c2.c:724
apr_status_t h2_c2_filter_response_out(ap_filter_t *f, apr_bucket_brigade *bb)
apr_status_t h2_c2_filter_trailers_out(ap_filter_t *f, apr_bucket_brigade *bb)
apr_status_t h2_c2_filter_request_in(ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes)
apr_status_t h2_c2_filter_catch_h1_out(ap_filter_t *f, apr_bucket_brigade *bb)
apr_array_header_t * h2_config_push_list(request_rec *r)
Definition h2_config.c:537
int h2_config_rgeti(request_rec *r, h2_config_var_t var)
Definition h2_config.c:527
apr_table_t * h2_config_early_headers(request_rec *r)
Definition h2_config.c:549
apr_int64_t h2_config_geti64(request_rec *r, server_rec *s, h2_config_var_t var)
Definition h2_config.c:521
int h2_config_sgeti(server_rec *s, h2_config_var_t var)
Definition h2_config.c:506
@ H2_CONF_PUSH
Definition h2_config.h:38
@ H2_CONF_STREAM_TIMEOUT
Definition h2_config.h:45
@ H2_CONF_COPY_FILES
Definition h2_config.h:40
void h2_conn_ctx_set_timeout(h2_conn_ctx_t *conn_ctx, apr_interval_time_t timeout)
#define H2_PIPE_OUT
Definition h2_conn_ctx.h:29
#define h2_conn_ctx_get(c)
Definition h2_conn_ctx.h:78
request_rec * h2_create_request_rec(const h2_request *req, conn_rec *c, int no_body)
Definition h2_request.c:370
apr_status_t h2_util_wait_on_pipe(apr_file_t *pipe)
Definition h2_util.c:1907
apr_status_t h2_brigade_copy_length(apr_bucket_brigade *dest, apr_bucket_brigade *src, apr_off_t length)
Definition h2_util.c:1228
apr_status_t h2_brigade_concat_length(apr_bucket_brigade *dest, apr_bucket_brigade *src, apr_off_t length)
Definition h2_util.c:1193
#define h2_util_bb_log(c, sid, level, tag, bb)
Definition h2_util.h:456
const h2_request * h2_ws_rewrite_request(const h2_request *req, conn_rec *c2, int no_body)
Definition h2_ws.c:348
Apache Configuration.
Apache connection library.
CORE HTTP Daemon.
Apache Logging library.
HTTP protocol handling.
Apache Request library.
Virtual Host package.
HTTP Daemon routines.
mod_core private header file
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
Multi-Processing Modules functions.
Apache scoreboard library.
#define SERVER_BUSY_WRITE
Definition scoreboard.h:60
int ap_update_child_status(ap_sb_handle_t *sbh, int status, request_rec *r)
Definition scoreboard.c:590
char * name
This structure is used for recording information about the registered filters. It associates a name w...
The representation of a filter chain.
void * data
apr_pool_t * pool
apr_datatype_e desc_type
Definition apr_poll.h:110
apr_descriptor desc
Definition apr_poll.h:113
Structure to store things which are per connection.
Definition httpd.h:1152
unsigned int clogging_input_filters
Definition httpd.h:1212
const struct ap_logconf * log
Definition httpd.h:1230
int data_in_output_filters
Definition httpd.h:1207
apr_pool_t * pool
Definition httpd.h:1154
ap_conn_keepalive_e keepalive
Definition httpd.h:1223
struct ap_filter_t * input_filters
Definition httpd.h:1195
struct ap_filter_t * output_filters
Definition httpd.h:1197
struct apr_bucket_alloc_t * bucket_alloc
Definition httpd.h:1201
apr_table_t * notes
Definition httpd.h:1193
const char * log_id
Definition httpd.h:1235
int keepalives
Definition httpd.h:1226
conn_rec * master
Definition httpd.h:1248
struct ap_conf_vector_t * conn_config
Definition httpd.h:1190
int data_in_input_filters
Definition httpd.h:1205
unsigned aborted
Definition httpd.h:1219
void * sbh
Definition httpd.h:1199
long id
Definition httpd.h:1187
A structure to contain connection state information.
Definition httpd.h:1280
conn_state_e state
Definition httpd.h:1282
apr_bucket_brigade * bb
Definition h2_c2.c:177
unsigned did_upgrade_eos
Definition h2_c2.c:178
apr_off_t raw_bytes
Definition h2.h:178
const char * protocol
Definition h2.h:174
A structure that represents the current request.
Definition httpd.h:845
int status
Definition httpd.h:891
struct ap_filter_t * output_filters
Definition httpd.h:1070
unsigned expecting_100
Definition httpd.h:951
char * the_request
Definition httpd.h:866
apr_pool_t * pool
Definition httpd.h:847
conn_rec * connection
Definition httpd.h:849
apr_table_t * headers_in
Definition httpd.h:976
server_rec * server
Definition httpd.h:851
const char * status_line
Definition httpd.h:889
apr_table_t * headers_out
Definition httpd.h:978
A structure to store information for each virtual server.
Definition httpd.h:1322
apr_interval_time_t timeout
Definition httpd.h:1372
apr_file_t * f
Definition apr_poll.h:100
apr_status_t apr_socket_create(apr_socket_t **new, int ofamily, int type, int protocol, apr_pool_t *cont)
Definition sockets.c:116
Apache filter library.
ap_input_mode_t
input filtering modes
Definition util_filter.h:41
@ AP_MODE_SPECULATIVE
Definition util_filter.h:53
@ AP_MODE_READBYTES
Definition util_filter.h:43
@ AP_MODE_INIT
Definition util_filter.h:62
@ AP_MODE_EXHAUSTIVE
Definition util_filter.h:58
@ AP_MODE_GETLINE
Definition util_filter.h:48
IN ULONG IN INT timeout