"Fossies" - the Fresh Open Source Software Archive

Member "mod_http2-1.15.17/mod_http2/mod_http2.c" (22 Feb 2021, 12416 Bytes) of package /linux/www/apache_httpd_modules/mod_http2-1.15.17.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "mod_http2.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.15.16_vs_1.15.17.

    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 <apr_optional.h>
   18 #include <apr_optional_hooks.h>
   19 #include <apr_strings.h>
   20 #include <apr_time.h>
   21 #include <apr_want.h>
   22 
   23 #include <httpd.h>
   24 #include <http_protocol.h>
   25 #include <http_request.h>
   26 #include <http_log.h>
   27 
   28 #include "mod_http2.h"
   29 
   30 #include <nghttp2/nghttp2.h>
   31 #include "h2_stream.h"
   32 #include "h2_alt_svc.h"
   33 #include "h2_conn.h"
   34 #include "h2_filter.h"
   35 #include "h2_task.h"
   36 #include "h2_session.h"
   37 #include "h2_config.h"
   38 #include "h2_ctx.h"
   39 #include "h2_h2.h"
   40 #include "h2_mplx.h"
   41 #include "h2_push.h"
   42 #include "h2_request.h"
   43 #include "h2_switch.h"
   44 #include "h2_version.h"
   45 
   46 
   47 static void h2_hooks(apr_pool_t *pool);
   48 
   49 AP_DECLARE_MODULE(http2) = {
   50     STANDARD20_MODULE_STUFF,
   51     h2_config_create_dir, /* func to create per dir config */
   52     h2_config_merge_dir,  /* func to merge per dir config */
   53     h2_config_create_svr, /* func to create per server config */
   54     h2_config_merge_svr,  /* func to merge per server config */
   55     h2_cmds,              /* command handlers */
   56     h2_hooks,
   57 #if defined(AP_MODULE_FLAG_NONE)
   58     AP_MODULE_FLAG_ALWAYS_MERGE
   59 #endif
   60 };
   61 
   62 static int h2_h2_fixups(request_rec *r);
   63 
   64 typedef struct {
   65     unsigned int change_prio : 1;
   66     unsigned int sha256 : 1;
   67     unsigned int inv_headers : 1;
   68     unsigned int dyn_windows : 1;
   69 } features;
   70 
   71 static features myfeats;
   72 static int mpm_warned;
   73 
   74 /* The module initialization. Called once as apache hook, before any multi
   75  * processing (threaded or not) happens. It is typically at least called twice, 
   76  * see
   77  * http://wiki.apache.org/httpd/ModuleLife
   78  * Since the first run is just a "practise" run, we want to initialize for real
   79  * only on the second try. This defeats the purpose of the first dry run a bit, 
   80  * since apache wants to verify that a new configuration actually will work. 
   81  * So if we have trouble with the configuration, this will only be detected 
   82  * when the server has already switched.
   83  * On the other hand, when we initialize lib nghttp2, all possible crazy things 
   84  * might happen and this might even eat threads. So, better init on the real 
   85  * invocation, for now at least.
   86  */
   87 static int h2_post_config(apr_pool_t *p, apr_pool_t *plog,
   88                           apr_pool_t *ptemp, server_rec *s)
   89 {
   90     void *data = NULL;
   91     const char *mod_h2_init_key = "mod_http2_init_counter";
   92     nghttp2_info *ngh2;
   93     apr_status_t status;
   94     
   95     (void)plog;(void)ptemp;
   96 #ifdef H2_NG2_CHANGE_PRIO
   97     myfeats.change_prio = 1;
   98 #endif
   99 #ifdef H2_OPENSSL
  100     myfeats.sha256 = 1;
  101 #endif
  102 #ifdef H2_NG2_INVALID_HEADER_CB
  103     myfeats.inv_headers = 1;
  104 #endif
  105 #ifdef H2_NG2_LOCAL_WIN_SIZE
  106     myfeats.dyn_windows = 1;
  107 #endif
  108     
  109     apr_pool_userdata_get(&data, mod_h2_init_key, s->process->pool);
  110     if ( data == NULL ) {
  111         ap_log_error( APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(03089)
  112                      "initializing post config dry run");
  113         apr_pool_userdata_set((const void *)1, mod_h2_init_key,
  114                               apr_pool_cleanup_null, s->process->pool);
  115         return APR_SUCCESS;
  116     }
  117     
  118     ngh2 = nghttp2_version(0);
  119     ap_log_error( APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(03090)
  120                  "mod_http2 (v%s, feats=%s%s%s%s, nghttp2 %s), initializing...",
  121                  MOD_HTTP2_VERSION, 
  122                  myfeats.change_prio? "CHPRIO"  : "", 
  123                  myfeats.sha256?      "+SHA256" : "",
  124                  myfeats.inv_headers? "+INVHD"  : "",
  125                  myfeats.dyn_windows? "+DWINS"  : "",
  126                  ngh2?                ngh2->version_str : "unknown");
  127     
  128     switch (h2_conn_mpm_type()) {
  129         case H2_MPM_SIMPLE:
  130         case H2_MPM_MOTORZ:
  131         case H2_MPM_NETWARE:
  132         case H2_MPM_WINNT:
  133             /* not sure we need something extra for those. */
  134             break;
  135         case H2_MPM_EVENT:
  136         case H2_MPM_WORKER:
  137             /* all fine, we know these ones */
  138             break;
  139         case H2_MPM_PREFORK:
  140             /* ok, we now know how to handle that one */
  141             break;
  142         case H2_MPM_UNKNOWN:
  143             /* ??? */
  144             ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(03091)
  145                          "post_config: mpm type unknown");
  146             break;
  147     }
  148     
  149     if (!h2_mpm_supported() && !mpm_warned) {
  150         mpm_warned = 1;
  151         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(10034)
  152                      "The mpm module (%s) is not supported by mod_http2. The mpm determines "
  153                      "how things are processed in your server. HTTP/2 has more demands in "
  154                      "this regard and the currently selected mpm will just not do. "
  155                      "This is an advisory warning. Your server will continue to work, but "
  156                      "the HTTP/2 protocol will be inactive.", 
  157                      h2_conn_mpm_name());
  158     }
  159     
  160     status = h2_h2_init(p, s);
  161     if (status == APR_SUCCESS) {
  162         status = h2_switch_init(p, s);
  163     }
  164     if (status == APR_SUCCESS) {
  165         status = h2_task_init(p, s);
  166     }
  167     
  168     return status;
  169 }
  170 
  171 static char *http2_var_lookup(apr_pool_t *, server_rec *,
  172                          conn_rec *, request_rec *, char *name);
  173 static int http2_is_h2(conn_rec *);
  174 
  175 static void http2_get_num_workers(server_rec *s, int *minw, int *maxw)
  176 {
  177     h2_get_num_workers(s, minw, maxw);
  178 }
  179 
  180 /* Runs once per created child process. Perform any process 
  181  * related initionalization here.
  182  */
  183 static void h2_child_init(apr_pool_t *pchild, server_rec *s)
  184 {
  185     apr_allocator_t *allocator;
  186     apr_thread_mutex_t *mutex;
  187     apr_status_t status;
  188 
  189     /* The allocator of pchild has no mutex with MPM prefork, but we need one
  190      * for h2 workers threads synchronization. Even though mod_http2 shouldn't
  191      * be used with prefork, better be safe than sorry, so forcibly set the
  192      * mutex here. For MPM event/worker, pchild has no allocator so pconf's
  193      * is used, with its mutex.
  194      */
  195     allocator = apr_pool_allocator_get(pchild);
  196     if (allocator) {
  197         mutex = apr_allocator_mutex_get(allocator);
  198         if (!mutex) {
  199             apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_DEFAULT, pchild);
  200             apr_allocator_mutex_set(allocator, mutex);
  201         }
  202     }
  203 
  204     /* Set up our connection processing */
  205     status = h2_conn_child_init(pchild, s);
  206     if (status != APR_SUCCESS) {
  207         ap_log_error(APLOG_MARK, APLOG_ERR, status, s,
  208                      APLOGNO(02949) "initializing connection handling");
  209     }
  210 }
  211 
  212 /* Install this module into the apache2 infrastructure.
  213  */
  214 static void h2_hooks(apr_pool_t *pool)
  215 {
  216     static const char *const mod_ssl[] = { "mod_ssl.c", NULL};
  217     
  218     APR_REGISTER_OPTIONAL_FN(http2_is_h2);
  219     APR_REGISTER_OPTIONAL_FN(http2_var_lookup);
  220     APR_REGISTER_OPTIONAL_FN(http2_get_num_workers);
  221 
  222     ap_log_perror(APLOG_MARK, APLOG_TRACE1, 0, pool, "installing hooks");
  223     
  224     /* Run once after configuration is set, but before mpm children initialize.
  225      */
  226     ap_hook_post_config(h2_post_config, mod_ssl, NULL, APR_HOOK_MIDDLE);
  227     
  228     /* Run once after a child process has been created.
  229      */
  230     ap_hook_child_init(h2_child_init, NULL, NULL, APR_HOOK_MIDDLE);
  231 
  232     h2_h2_register_hooks();
  233     h2_switch_register_hooks();
  234     h2_task_register_hooks();
  235 
  236     h2_alt_svc_register_hooks();
  237     
  238     /* Setup subprocess env for certain variables 
  239      */
  240     ap_hook_fixups(h2_h2_fixups, NULL,NULL, APR_HOOK_MIDDLE);
  241     
  242     /* test http2 connection status handler */
  243     ap_hook_handler(h2_filter_h2_status_handler, NULL, NULL, APR_HOOK_MIDDLE);
  244 }
  245 
  246 static const char *val_HTTP2(apr_pool_t *p, server_rec *s,
  247                              conn_rec *c, request_rec *r, h2_ctx *ctx)
  248 {
  249     return ctx? "on" : "off";
  250 }
  251 
  252 static const char *val_H2_PUSH(apr_pool_t *p, server_rec *s,
  253                                conn_rec *c, request_rec *r, h2_ctx *ctx)
  254 {
  255     if (ctx) {
  256         if (r) {
  257             if (ctx->task) {
  258                 h2_stream *stream = h2_mplx_t_stream_get(ctx->task->mplx, ctx->task);
  259                 if (stream && stream->push_policy != H2_PUSH_NONE) {
  260                     return "on";
  261                 }
  262             }
  263         }
  264         else if (c && h2_session_push_enabled(ctx->session)) {
  265             return "on";
  266         }
  267     }
  268     else if (s) {
  269         if (h2_config_geti(r, s, H2_CONF_PUSH)) {
  270             return "on";
  271         }
  272     }
  273     return "off";
  274 }
  275 
  276 static const char *val_H2_PUSHED(apr_pool_t *p, server_rec *s,
  277                                  conn_rec *c, request_rec *r, h2_ctx *ctx)
  278 {
  279     if (ctx) {
  280         if (ctx->task && !H2_STREAM_CLIENT_INITIATED(ctx->task->stream_id)) {
  281             return "PUSHED";
  282         }
  283     }
  284     return "";
  285 }
  286 
  287 static const char *val_H2_PUSHED_ON(apr_pool_t *p, server_rec *s,
  288                                     conn_rec *c, request_rec *r, h2_ctx *ctx)
  289 {
  290     if (ctx) {
  291         if (ctx->task && !H2_STREAM_CLIENT_INITIATED(ctx->task->stream_id)) {
  292             h2_stream *stream = h2_mplx_t_stream_get(ctx->task->mplx, ctx->task);
  293             if (stream) {
  294                 return apr_itoa(p, stream->initiated_on);
  295             }
  296         }
  297     }
  298     return "";
  299 }
  300 
  301 static const char *val_H2_STREAM_TAG(apr_pool_t *p, server_rec *s,
  302                                      conn_rec *c, request_rec *r, h2_ctx *ctx)
  303 {
  304     if (ctx) {
  305         if (ctx->task) {
  306             return ctx->task->id;
  307         }
  308     }
  309     return "";
  310 }
  311 
  312 static const char *val_H2_STREAM_ID(apr_pool_t *p, server_rec *s,
  313                                     conn_rec *c, request_rec *r, h2_ctx *ctx)
  314 {
  315     const char *cp = val_H2_STREAM_TAG(p, s, c, r, ctx);
  316     if (cp && (cp = ap_strchr_c(cp, '-'))) {
  317         return ++cp;
  318     }
  319     return NULL;
  320 }
  321 
  322 typedef const char *h2_var_lookup(apr_pool_t *p, server_rec *s,
  323                                   conn_rec *c, request_rec *r, h2_ctx *ctx);
  324 typedef struct h2_var_def {
  325     const char *name;
  326     h2_var_lookup *lookup;
  327     unsigned int  subprocess : 1;    /* should be set in r->subprocess_env */
  328 } h2_var_def;
  329 
  330 static h2_var_def H2_VARS[] = {
  331     { "HTTP2",               val_HTTP2,  1 },
  332     { "H2PUSH",              val_H2_PUSH, 1 },
  333     { "H2_PUSH",             val_H2_PUSH, 1 },
  334     { "H2_PUSHED",           val_H2_PUSHED, 1 },
  335     { "H2_PUSHED_ON",        val_H2_PUSHED_ON, 1 },
  336     { "H2_STREAM_ID",        val_H2_STREAM_ID, 1 },
  337     { "H2_STREAM_TAG",       val_H2_STREAM_TAG, 1 },
  338 };
  339 
  340 #ifndef H2_ALEN
  341 #define H2_ALEN(a)          (sizeof(a)/sizeof((a)[0]))
  342 #endif
  343 
  344 
  345 static int http2_is_h2(conn_rec *c)
  346 {
  347     return h2_ctx_get(c->master? c->master : c, 0) != NULL;
  348 }
  349 
  350 static char *http2_var_lookup(apr_pool_t *p, server_rec *s,
  351                               conn_rec *c, request_rec *r, char *name)
  352 {
  353     int i;
  354     /* If the # of vars grow, we need to put definitions in a hash */
  355     for (i = 0; i < H2_ALEN(H2_VARS); ++i) {
  356         h2_var_def *vdef = &H2_VARS[i];
  357         if (!strcmp(vdef->name, name)) {
  358             h2_ctx *ctx = (r? h2_ctx_get(c, 0) : 
  359                            h2_ctx_get(c->master? c->master : c, 0));
  360             return (char *)vdef->lookup(p, s, c, r, ctx);
  361         }
  362     }
  363     return (char*)"";
  364 }
  365 
  366 static int h2_h2_fixups(request_rec *r)
  367 {
  368     if (r->connection->master) {
  369         h2_ctx *ctx = h2_ctx_get(r->connection, 0);
  370         int i;
  371         
  372         for (i = 0; ctx && i < H2_ALEN(H2_VARS); ++i) {
  373             h2_var_def *vdef = &H2_VARS[i];
  374             if (vdef->subprocess) {
  375                 apr_table_setn(r->subprocess_env, vdef->name, 
  376                                vdef->lookup(r->pool, r->server, r->connection, 
  377                                             r, ctx));
  378             }
  379         }
  380     }
  381     return DECLINED;
  382 }