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_c2.h"
52 #include "h2_util.h"
53 
54 
55 static h2_mpm_type_t mpm_type = H2_MPM_UNKNOWN;
56 static module *mpm_module;
57 static int mpm_supported = 1;
58 static apr_socket_t *dummy_socket;
59 
check_modules(int force)60 static void check_modules(int force)
61 {
62     static int checked = 0;
63     int i;
64 
65     if (force || !checked) {
66         for (i = 0; ap_loaded_modules[i]; ++i) {
67             module *m = ap_loaded_modules[i];
68 
69             if (!strcmp("event.c", m->name)) {
70                 mpm_type = H2_MPM_EVENT;
71                 mpm_module = m;
72                 break;
73             }
74             else if (!strcmp("motorz.c", m->name)) {
75                 mpm_type = H2_MPM_MOTORZ;
76                 mpm_module = m;
77                 break;
78             }
79             else if (!strcmp("mpm_netware.c", m->name)) {
80                 mpm_type = H2_MPM_NETWARE;
81                 mpm_module = m;
82                 break;
83             }
84             else if (!strcmp("prefork.c", m->name)) {
85                 mpm_type = H2_MPM_PREFORK;
86                 mpm_module = m;
87                 /* While http2 can work really well on prefork, it collides
88                  * today's use case for prefork: running single-thread app engines
89                  * like php. If we restrict h2_workers to 1 per process, php will
90                  * work fine, but browser will be limited to 1 active request at a
91                  * time. */
92                 mpm_supported = 0;
93                 break;
94             }
95             else if (!strcmp("simple_api.c", m->name)) {
96                 mpm_type = H2_MPM_SIMPLE;
97                 mpm_module = m;
98                 mpm_supported = 0;
99                 break;
100             }
101             else if (!strcmp("mpm_winnt.c", m->name)) {
102                 mpm_type = H2_MPM_WINNT;
103                 mpm_module = m;
104                 break;
105             }
106             else if (!strcmp("worker.c", m->name)) {
107                 mpm_type = H2_MPM_WORKER;
108                 mpm_module = m;
109                 break;
110             }
111         }
112         checked = 1;
113     }
114 }
115 
h2_conn_mpm_type(void)116 h2_mpm_type_t h2_conn_mpm_type(void)
117 {
118     check_modules(0);
119     return mpm_type;
120 }
121 
h2_conn_mpm_name(void)122 const char *h2_conn_mpm_name(void)
123 {
124     check_modules(0);
125     return mpm_module? mpm_module->name : "unknown";
126 }
127 
h2_mpm_supported(void)128 int h2_mpm_supported(void)
129 {
130     check_modules(0);
131     return mpm_supported;
132 }
133 
h2_conn_mpm_module(void)134 static module *h2_conn_mpm_module(void)
135 {
136     check_modules(0);
137     return mpm_module;
138 }
139 
h2_c2_child_init(apr_pool_t * pool,server_rec * s)140 apr_status_t h2_c2_child_init(apr_pool_t *pool, server_rec *s)
141 {
142     check_modules(1);
143     return apr_socket_create(&dummy_socket, APR_INET, SOCK_STREAM,
144                              APR_PROTO_TCP, pool);
145 }
146 
147 /* APR callback invoked if allocation fails. */
abort_on_oom(int retcode)148 static int abort_on_oom(int retcode)
149 {
150     ap_abort_on_oom();
151     return retcode; /* unreachable, hopefully. */
152 }
153 
h2_c2_create(conn_rec * c1,apr_pool_t * parent)154 conn_rec *h2_c2_create(conn_rec *c1, apr_pool_t *parent)
155 {
156     apr_allocator_t *allocator;
157     apr_status_t status;
158     apr_pool_t *pool;
159     conn_rec *c2;
160     void *cfg;
161     module *mpm;
162 
163     ap_assert(c1);
164     ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, c1,
165                   "h2_c2: create for c1(%ld)", c1->id);
166 
167     /* We create a pool with its own allocator to be used for
168      * processing a request. This is the only way to have the processing
169      * independent of its parent pool in the sense that it can work in
170      * another thread.
171      */
172     apr_allocator_create(&allocator);
173     apr_allocator_max_free_set(allocator, ap_max_mem_free);
174     status = apr_pool_create_ex(&pool, parent, NULL, allocator);
175     if (status != APR_SUCCESS) {
176         ap_log_cerror(APLOG_MARK, APLOG_ERR, status, c1,
177                       APLOGNO(10004) "h2_c2: create pool");
178         return NULL;
179     }
180     apr_allocator_owner_set(allocator, pool);
181     apr_pool_abort_set(abort_on_oom, pool);
182     apr_pool_tag(pool, "h2_c2_conn");
183 
184     c2 = (conn_rec *) apr_palloc(pool, sizeof(conn_rec));
185     memcpy(c2, c1, sizeof(conn_rec));
186 
187     c2->master                 = c1;
188     c2->pool                   = pool;
189     c2->conn_config            = ap_create_conn_config(pool);
190     c2->notes                  = apr_table_make(pool, 5);
191     c2->input_filters          = NULL;
192     c2->output_filters         = NULL;
193     c2->keepalives             = 0;
194 #if AP_MODULE_MAGIC_AT_LEAST(20180903, 1)
195     c2->filter_conn_ctx        = NULL;
196 #endif
197     c2->bucket_alloc           = apr_bucket_alloc_create(pool);
198 #if !AP_MODULE_MAGIC_AT_LEAST(20180720, 1)
199     c2->data_in_input_filters  = 0;
200     c2->data_in_output_filters = 0;
201 #endif
202     /* prevent mpm_event from making wrong assumptions about this connection,
203      * like e.g. using its socket for an async read check. */
204     c2->clogging_input_filters = 1;
205     c2->log                    = NULL;
206     c2->aborted                = 0;
207     /* We cannot install the master connection socket on the secondary, as
208      * modules mess with timeouts/blocking of the socket, with
209      * unwanted side effects to the master connection processing.
210      * Fortunately, since we never use the secondary socket, we can just install
211      * a single, process-wide dummy and everyone is happy.
212      */
213     ap_set_module_config(c2->conn_config, &core_module, dummy_socket);
214     /* TODO: these should be unique to this thread */
215     c2->sbh = NULL; /*c1->sbh;*/
216     /* TODO: not all mpm modules have learned about secondary connections yet.
217      * copy their config from master to secondary.
218      */
219     if ((mpm = h2_conn_mpm_module()) != NULL) {
220         cfg = ap_get_module_config(c1->conn_config, mpm);
221         ap_set_module_config(c2->conn_config, mpm, cfg);
222     }
223 
224     ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, c2,
225                   "h2_c2(%s): created", c2->log_id);
226     return c2;
227 }
228 
h2_c2_destroy(conn_rec * c2)229 void h2_c2_destroy(conn_rec *c2)
230 {
231     ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, c2,
232                   "h2_c2(%s): destroy", c2->log_id);
233     apr_pool_destroy(c2->pool);
234 }
235 
236 typedef struct {
237     apr_bucket_brigade *bb;       /* c2: data in holding area */
238 } h2_c2_fctx_in_t;
239 
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)240 static apr_status_t h2_c2_filter_in(ap_filter_t* f,
241                                            apr_bucket_brigade* bb,
242                                            ap_input_mode_t mode,
243                                            apr_read_type_e block,
244                                            apr_off_t readbytes)
245 {
246     h2_conn_ctx_t *conn_ctx;
247     h2_c2_fctx_in_t *fctx = f->ctx;
248     apr_status_t status = APR_SUCCESS;
249     apr_bucket *b, *next;
250     apr_off_t bblen;
251     const int trace1 = APLOGctrace1(f->c);
252     apr_size_t rmax = ((readbytes <= APR_SIZE_MAX)?
253                        (apr_size_t)readbytes : APR_SIZE_MAX);
254 
255     conn_ctx = h2_conn_ctx_get(f->c);
256     ap_assert(conn_ctx);
257 
258     if (trace1) {
259         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
260                       "h2_c2_in(%s-%d): read, mode=%d, block=%d, readbytes=%ld",
261                       conn_ctx->id, conn_ctx->stream_id, mode, block, (long)readbytes);
262     }
263 
264     if (mode == AP_MODE_INIT) {
265         return ap_get_brigade(f->c->input_filters, bb, mode, block, readbytes);
266     }
267 
268     if (f->c->aborted) {
269         return APR_ECONNABORTED;
270     }
271 
272     if (!fctx) {
273         fctx = apr_pcalloc(f->c->pool, sizeof(*fctx));
274         f->ctx = fctx;
275         fctx->bb = apr_brigade_create(f->c->pool, f->c->bucket_alloc);
276         if (!conn_ctx->beam_in) {
277             b = apr_bucket_eos_create(f->c->bucket_alloc);
278             APR_BRIGADE_INSERT_TAIL(fctx->bb, b);
279         }
280     }
281 
282     /* Cleanup brigades from those nasty 0 length non-meta buckets
283      * that apr_brigade_split_line() sometimes produces. */
284     for (b = APR_BRIGADE_FIRST(fctx->bb);
285          b != APR_BRIGADE_SENTINEL(fctx->bb); b = next) {
286         next = APR_BUCKET_NEXT(b);
287         if (b->length == 0 && !APR_BUCKET_IS_METADATA(b)) {
288             apr_bucket_delete(b);
289         }
290     }
291 
292     while (APR_BRIGADE_EMPTY(fctx->bb)) {
293         /* Get more input data for our request. */
294         if (trace1) {
295             ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, f->c,
296                           "h2_c2_in(%s-%d): get more data from mplx, block=%d, "
297                           "readbytes=%ld",
298                           conn_ctx->id, conn_ctx->stream_id, block, (long)readbytes);
299         }
300         if (conn_ctx->beam_in) {
301             if (conn_ctx->pipe_in_prod[H2_PIPE_OUT]) {
302 receive:
303                 status = h2_beam_receive(conn_ctx->beam_in, f->c, fctx->bb, APR_NONBLOCK_READ,
304                                          conn_ctx->mplx->stream_max_mem);
305                 if (APR_STATUS_IS_EAGAIN(status) && APR_BLOCK_READ == block) {
306                     status = h2_util_wait_on_pipe(conn_ctx->pipe_in_prod[H2_PIPE_OUT]);
307                     if (APR_SUCCESS == status) {
308                         goto receive;
309                     }
310                 }
311             }
312             else {
313                 status = h2_beam_receive(conn_ctx->beam_in, f->c, fctx->bb, block,
314                                          conn_ctx->mplx->stream_max_mem);
315             }
316         }
317         else {
318             status = APR_EOF;
319         }
320 
321         if (trace1) {
322             ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, f->c,
323                           "h2_c2_in(%s-%d): read returned",
324                           conn_ctx->id, conn_ctx->stream_id);
325         }
326         if (APR_STATUS_IS_EAGAIN(status)
327             && (mode == AP_MODE_GETLINE || block == APR_BLOCK_READ)) {
328             /* chunked input handling does not seem to like it if we
329              * return with APR_EAGAIN from a GETLINE read...
330              * upload 100k test on test-ser.example.org hangs */
331             status = APR_SUCCESS;
332         }
333         else if (APR_STATUS_IS_EOF(status)) {
334             break;
335         }
336         else if (status != APR_SUCCESS) {
337             conn_ctx->last_err = status;
338             return status;
339         }
340 
341         if (trace1) {
342             h2_util_bb_log(f->c, conn_ctx->stream_id, APLOG_TRACE2,
343                         "c2 input recv raw", fctx->bb);
344         }
345         if (h2_c_logio_add_bytes_in) {
346             apr_brigade_length(bb, 0, &bblen);
347             h2_c_logio_add_bytes_in(f->c, bblen);
348         }
349     }
350 
351     /* Nothing there, no more data to get. Return. */
352     if (status == APR_EOF && APR_BRIGADE_EMPTY(fctx->bb)) {
353         return status;
354     }
355 
356     if (trace1) {
357         h2_util_bb_log(f->c, conn_ctx->stream_id, APLOG_TRACE2,
358                     "c2 input.bb", fctx->bb);
359     }
360 
361     if (APR_BRIGADE_EMPTY(fctx->bb)) {
362         if (trace1) {
363             ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
364                           "h2_c2_in(%s-%d): no data",
365                           conn_ctx->id, conn_ctx->stream_id);
366         }
367         return (block == APR_NONBLOCK_READ)? APR_EAGAIN : APR_EOF;
368     }
369 
370     if (mode == AP_MODE_EXHAUSTIVE) {
371         /* return all we have */
372         APR_BRIGADE_CONCAT(bb, fctx->bb);
373     }
374     else if (mode == AP_MODE_READBYTES) {
375         status = h2_brigade_concat_length(bb, fctx->bb, rmax);
376     }
377     else if (mode == AP_MODE_SPECULATIVE) {
378         status = h2_brigade_copy_length(bb, fctx->bb, rmax);
379     }
380     else if (mode == AP_MODE_GETLINE) {
381         /* we are reading a single LF line, e.g. the HTTP headers.
382          * this has the nasty side effect to split the bucket, even
383          * though it ends with CRLF and creates a 0 length bucket */
384         status = apr_brigade_split_line(bb, fctx->bb, block,
385                                         HUGE_STRING_LEN);
386         if (APLOGctrace1(f->c)) {
387             char buffer[1024];
388             apr_size_t len = sizeof(buffer)-1;
389             apr_brigade_flatten(bb, buffer, &len);
390             buffer[len] = 0;
391             if (trace1) {
392                 ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, f->c,
393                               "h2_c2_in(%s-%d): getline: %s",
394                               conn_ctx->id, conn_ctx->stream_id, buffer);
395             }
396         }
397     }
398     else {
399         /* Hmm, well. There is mode AP_MODE_EATCRLF, but we chose not
400          * to support it. Seems to work. */
401         ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_ENOTIMPL, f->c,
402                       APLOGNO(03472)
403                       "h2_c2_in(%s-%d), unsupported READ mode %d",
404                       conn_ctx->id, conn_ctx->stream_id, mode);
405         status = APR_ENOTIMPL;
406     }
407 
408     if (trace1) {
409         apr_brigade_length(bb, 0, &bblen);
410         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, f->c,
411                       "h2_c2_in(%s-%d): %ld data bytes",
412                       conn_ctx->id, conn_ctx->stream_id, (long)bblen);
413     }
414     return status;
415 }
416 
beam_out(conn_rec * c2,h2_conn_ctx_t * conn_ctx,apr_bucket_brigade * bb)417 static apr_status_t beam_out(conn_rec *c2, h2_conn_ctx_t *conn_ctx, apr_bucket_brigade* bb)
418 {
419     apr_off_t written, header_len = 0;
420     apr_status_t rv;
421 
422     if (h2_c_logio_add_bytes_out) {
423         /* mod_logio wants to report the number of bytes  written in a
424          * response, including header and footer fields. Since h2 converts
425          * those during c1 processing into the HPACKed h2 HEADER frames,
426          * we need to give mod_logio something here and count just the
427          * raw lengths of all headers in the buckets. */
428         apr_bucket *b;
429         for (b = APR_BRIGADE_FIRST(bb);
430              b != APR_BRIGADE_SENTINEL(bb);
431              b = APR_BUCKET_NEXT(b)) {
432             if (H2_BUCKET_IS_HEADERS(b)) {
433                 header_len += (apr_off_t)h2_bucket_headers_headers_length(b);
434             }
435         }
436     }
437 
438     rv = h2_beam_send(conn_ctx->beam_out, c2, bb, APR_BLOCK_READ, &written);
439 
440     if (APR_STATUS_IS_EAGAIN(rv)) {
441         rv = APR_SUCCESS;
442     }
443     if (written && h2_c_logio_add_bytes_out) {
444         h2_c_logio_add_bytes_out(c2, written + header_len);
445     }
446     return rv;
447 }
448 
h2_c2_filter_out(ap_filter_t * f,apr_bucket_brigade * bb)449 static apr_status_t h2_c2_filter_out(ap_filter_t* f, apr_bucket_brigade* bb)
450 {
451     h2_conn_ctx_t *conn_ctx = h2_conn_ctx_get(f->c);
452     apr_status_t rv;
453 
454     ap_assert(conn_ctx);
455     rv = beam_out(f->c, conn_ctx, bb);
456 
457     ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, f->c,
458                   "h2_c2(%s-%d): output leave",
459                   conn_ctx->id, conn_ctx->stream_id);
460     if (APR_SUCCESS != rv) {
461         if (!conn_ctx->done) {
462             h2_beam_abort(conn_ctx->beam_out, f->c);
463         }
464         f->c->aborted = 1;
465     }
466     return rv;
467 }
468 
c2_run_pre_connection(conn_rec * c2,apr_socket_t * csd)469 static apr_status_t c2_run_pre_connection(conn_rec *c2, apr_socket_t *csd)
470 {
471     if (c2->keepalives == 0) {
472         /* Simulate that we had already a request on this connection. Some
473          * hooks trigger special behaviour when keepalives is 0.
474          * (Not necessarily in pre_connection, but later. Set it here, so it
475          * is in place.) */
476         c2->keepalives = 1;
477         /* We signal that this connection will be closed after the request.
478          * Which is true in that sense that we throw away all traffic data
479          * on this c2 connection after each requests. Although we might
480          * reuse internal structures like memory pools.
481          * The wanted effect of this is that httpd does not try to clean up
482          * any dangling data on this connection when a request is done. Which
483          * is unnecessary on a h2 stream.
484          */
485         c2->keepalive = AP_CONN_CLOSE;
486         return ap_run_pre_connection(c2, csd);
487     }
488     ap_assert(c2->output_filters);
489     return APR_SUCCESS;
490 }
491 
h2_c2_process(conn_rec * c2,apr_thread_t * thread,int worker_id)492 apr_status_t h2_c2_process(conn_rec *c2, apr_thread_t *thread, int worker_id)
493 {
494     h2_conn_ctx_t *conn_ctx = h2_conn_ctx_get(c2);
495 
496     ap_assert(conn_ctx);
497     ap_assert(conn_ctx->mplx);
498 
499     /* See the discussion at <https://github.com/icing/mod_h2/issues/195>
500      *
501      * Each conn_rec->id is supposed to be unique at a point in time. Since
502      * some modules (and maybe external code) uses this id as an identifier
503      * for the request_rec they handle, it needs to be unique for secondary
504      * connections also.
505      *
506      * The MPM module assigns the connection ids and mod_unique_id is using
507      * that one to generate identifier for requests. While the implementation
508      * works for HTTP/1.x, the parallel execution of several requests per
509      * connection will generate duplicate identifiers on load.
510      *
511      * The original implementation for secondary connection identifiers used
512      * to shift the master connection id up and assign the stream id to the
513      * lower bits. This was cramped on 32 bit systems, but on 64bit there was
514      * enough space.
515      *
516      * As issue 195 showed, mod_unique_id only uses the lower 32 bit of the
517      * connection id, even on 64bit systems. Therefore collisions in request ids.
518      *
519      * The way master connection ids are generated, there is some space "at the
520      * top" of the lower 32 bits on allmost all systems. If you have a setup
521      * with 64k threads per child and 255 child processes, you live on the edge.
522      *
523      * The new implementation shifts 8 bits and XORs in the worker
524      * id. This will experience collisions with > 256 h2 workers and heavy
525      * load still. There seems to be no way to solve this in all possible
526      * configurations by mod_h2 alone.
527      */
528     c2->id = (c2->master->id << 8)^worker_id;
529 
530     if (!conn_ctx->pre_conn_done) {
531         ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c2,
532                       "h2_c2(%s-%d), adding filters",
533                       conn_ctx->id, conn_ctx->stream_id);
534         ap_add_input_filter("H2_C2_NET_IN", NULL, NULL, c2);
535         ap_add_output_filter("H2_C2_NET_CATCH_H1", NULL, NULL, c2);
536         ap_add_output_filter("H2_C2_NET_OUT", NULL, NULL, c2);
537 
538         c2_run_pre_connection(c2, ap_get_conn_socket(c2));
539         conn_ctx->pre_conn_done = 1;
540     }
541 
542     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c2,
543                   "h2_c2(%s-%d): process connection",
544                   conn_ctx->id, conn_ctx->stream_id);
545 
546     c2->current_thread = thread;
547     ap_run_process_connection(c2);
548 
549     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c2,
550                   "h2_c2(%s-%d): processing done",
551                   conn_ctx->id, conn_ctx->stream_id);
552 
553     return APR_SUCCESS;
554 }
555 
c2_process(h2_conn_ctx_t * conn_ctx,conn_rec * c)556 static apr_status_t c2_process(h2_conn_ctx_t *conn_ctx, conn_rec *c)
557 {
558     const h2_request *req = conn_ctx->request;
559     conn_state_t *cs = c->cs;
560     request_rec *r;
561 
562     r = h2_create_request_rec(conn_ctx->request, c);
563     if (!r) {
564         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
565                       "h2_c2(%s-%d): create request_rec failed, r=NULL",
566                       conn_ctx->id, conn_ctx->stream_id);
567         goto cleanup;
568     }
569     if (r->status != HTTP_OK) {
570         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
571                       "h2_c2(%s-%d): create request_rec failed, r->status=%d",
572                       conn_ctx->id, conn_ctx->stream_id, r->status);
573         goto cleanup;
574     }
575 
576     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
577                   "h2_c2(%s-%d): created request_rec",
578                   conn_ctx->id, conn_ctx->stream_id);
579     conn_ctx->server = r->server;
580 
581     /* the request_rec->server carries the timeout value that applies */
582     h2_conn_ctx_set_timeout(conn_ctx, r->server->timeout);
583 
584     if (h2_config_sgeti(conn_ctx->server, H2_CONF_COPY_FILES)) {
585         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
586                       "h2_mplx(%s-%d): copy_files in output",
587                       conn_ctx->id, conn_ctx->stream_id);
588         h2_beam_set_copy_files(conn_ctx->beam_out, 1);
589     }
590 
591     ap_update_child_status(c->sbh, SERVER_BUSY_WRITE, r);
592     if (cs) {
593         cs->state = CONN_STATE_HANDLER;
594     }
595     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
596                   "h2_c2(%s-%d): start process_request",
597                   conn_ctx->id, conn_ctx->stream_id);
598 
599     /* Add the raw bytes of the request (e.g. header frame lengths to
600      * the logio for this request. */
601     if (req->raw_bytes && h2_c_logio_add_bytes_in) {
602         h2_c_logio_add_bytes_in(c, req->raw_bytes);
603     }
604 
605     ap_process_request(r);
606     /* After the call to ap_process_request, the
607      * request pool may have been deleted. */
608     r = NULL;
609 
610     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
611                   "h2_c2(%s-%d): process_request done",
612                   conn_ctx->id, conn_ctx->stream_id);
613     if (cs)
614         cs->state = CONN_STATE_WRITE_COMPLETION;
615 
616 cleanup:
617     return APR_SUCCESS;
618 }
619 
h2_c2_hook_process(conn_rec * c)620 static int h2_c2_hook_process(conn_rec* c)
621 {
622     h2_conn_ctx_t *ctx;
623 
624     if (!c->master) {
625         return DECLINED;
626     }
627 
628     ctx = h2_conn_ctx_get(c);
629     if (ctx->stream_id) {
630         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
631                       "h2_h2, processing request directly");
632         c2_process(ctx, c);
633         return DONE;
634     }
635     else {
636         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
637                       "secondary_conn(%ld): no h2 stream assing?", c->id);
638     }
639     return DECLINED;
640 }
641 
check_push(request_rec * r,const char * tag)642 static void check_push(request_rec *r, const char *tag)
643 {
644     apr_array_header_t *push_list = h2_config_push_list(r);
645 
646     if (!r->expecting_100 && push_list && push_list->nelts > 0) {
647         int i, old_status;
648         const char *old_line;
649 
650         ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
651                       "%s, early announcing %d resources for push",
652                       tag, push_list->nelts);
653         for (i = 0; i < push_list->nelts; ++i) {
654             h2_push_res *push = &APR_ARRAY_IDX(push_list, i, h2_push_res);
655             apr_table_add(r->headers_out, "Link",
656                            apr_psprintf(r->pool, "<%s>; rel=preload%s",
657                                         push->uri_ref, push->critical? "; critical" : ""));
658         }
659         old_status = r->status;
660         old_line = r->status_line;
661         r->status = 103;
662         r->status_line = "103 Early Hints";
663         ap_send_interim_response(r, 1);
664         r->status = old_status;
665         r->status_line = old_line;
666     }
667 }
668 
h2_c2_hook_post_read_request(request_rec * r)669 static int h2_c2_hook_post_read_request(request_rec *r)
670 {
671     h2_conn_ctx_t *conn_ctx = h2_conn_ctx_get(r->connection);
672 
673     if (conn_ctx && conn_ctx->stream_id) {
674 
675         ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r,
676                       "h2_c2(%s-%d): adding request filters",
677                       conn_ctx->id, conn_ctx->stream_id);
678 
679         /* setup the correct filters to process the request for h2 */
680         ap_add_input_filter("H2_C2_REQUEST_IN", NULL, r, r->connection);
681 
682         /* replace the core http filter that formats response headers
683          * in HTTP/1 with our own that collects status and headers */
684         ap_remove_output_filter_byhandle(r->output_filters, "HTTP_HEADER");
685 
686         ap_add_output_filter("H2_C2_RESPONSE_OUT", NULL, r, r->connection);
687         ap_add_output_filter("H2_C2_TRAILERS_OUT", NULL, r, r->connection);
688     }
689     return DECLINED;
690 }
691 
h2_c2_hook_fixups(request_rec * r)692 static int h2_c2_hook_fixups(request_rec *r)
693 {
694     /* secondary connection? */
695     if (r->connection->master) {
696         h2_conn_ctx_t *conn_ctx = h2_conn_ctx_get(r->connection);
697         if (conn_ctx) {
698             check_push(r, "late_fixup");
699         }
700     }
701     return DECLINED;
702 }
703 
h2_c2_register_hooks(void)704 void h2_c2_register_hooks(void)
705 {
706     /* When the connection processing actually starts, we might
707      * take over, if the connection is for a h2 stream.
708      */
709     ap_hook_process_connection(h2_c2_hook_process,
710                                NULL, NULL, APR_HOOK_FIRST);
711     /* We need to manipulate the standard HTTP/1.1 protocol filters and
712      * install our own. This needs to be done very early. */
713     ap_hook_post_read_request(h2_c2_hook_post_read_request, NULL, NULL, APR_HOOK_REALLY_FIRST);
714     ap_hook_fixups(h2_c2_hook_fixups, NULL, NULL, APR_HOOK_LAST);
715 
716     ap_register_input_filter("H2_C2_NET_IN", h2_c2_filter_in,
717                              NULL, AP_FTYPE_NETWORK);
718     ap_register_output_filter("H2_C2_NET_OUT", h2_c2_filter_out,
719                               NULL, AP_FTYPE_NETWORK);
720     ap_register_output_filter("H2_C2_NET_CATCH_H1", h2_c2_filter_catch_h1_out,
721                               NULL, AP_FTYPE_NETWORK);
722 
723     ap_register_input_filter("H2_C2_REQUEST_IN", h2_c2_filter_request_in,
724                              NULL, AP_FTYPE_PROTOCOL);
725     ap_register_output_filter("H2_C2_RESPONSE_OUT", h2_c2_filter_response_out,
726                               NULL, AP_FTYPE_PROTOCOL);
727     ap_register_output_filter("H2_C2_TRAILERS_OUT", h2_c2_filter_trailers_out,
728                               NULL, AP_FTYPE_PROTOCOL);
729 }
730 
731