Commit 7be5f671 authored by Stefan Eissing's avatar Stefan Eissing
Browse files

mod_http2 v1.2.2 from trunk

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1725301 13f79535-47bb-0310-9956-ffa450edef68
parent e320d290
Loading
Loading
Loading
Loading
+11 −10
Original line number Diff line number Diff line
@@ -382,16 +382,17 @@ SET(mod_http2_extra_sources
  modules/http2/h2_alt_svc.c         modules/http2/h2_bucket_eoc.c
  modules/http2/h2_bucket_eos.c      modules/http2/h2_config.c
  modules/http2/h2_conn.c            modules/http2/h2_conn_io.c
  modules/http2/h2_ctx.c             modules/http2/h2_from_h1.c
  modules/http2/h2_h2.c              modules/http2/h2_io.c
  modules/http2/h2_io_set.c          modules/http2/h2_mplx.c
  modules/http2/h2_push.c            modules/http2/h2_request.c
  modules/http2/h2_response.c        modules/http2/h2_session.c
  modules/http2/h2_stream.c          modules/http2/h2_stream_set.c
  modules/http2/h2_switch.c          modules/http2/h2_task.c
  modules/http2/h2_task_input.c      modules/http2/h2_task_output.c
  modules/http2/h2_task_queue.c      modules/http2/h2_util.c
  modules/http2/h2_worker.c          modules/http2/h2_workers.c
  modules/http2/h2_ctx.c             modules/http2/h2_filter.c
  modules/http2/h2_from_h1.c         modules/http2/h2_h2.c
  modules/http2/h2_io.c              modules/http2/h2_io_set.c
  modules/http2/h2_mplx.c            modules/http2/h2_push.c
  modules/http2/h2_request.c         modules/http2/h2_response.c
  modules/http2/h2_session.c         modules/http2/h2_stream.c 
  modules/http2/h2_stream_set.c      modules/http2/h2_switch.c
  modules/http2/h2_task.c            modules/http2/h2_task_input.c
  modules/http2/h2_task_output.c     modules/http2/h2_task_queue.c
  modules/http2/h2_util.c            modules/http2/h2_worker.c
  modules/http2/h2_workers.c
)
SET(mod_ldap_extra_defines           LDAP_DECLARE_EXPORT)
SET(mod_ldap_extra_libs              wldap32)
+158 −2
Original line number Diff line number Diff line
@@ -53,6 +53,26 @@

    </summary>
    
    <section id="envvars"><title>Environment Variables</title>
        
        <p>This module can be configured to provide HTTP/2 related information
            as additional environment variables to the SSI and CGI namespace.
        </p>
        
        <table border="1">
            <columnspec><column width=".3"/><column width=".2"/><column width=".5"/>
            </columnspec>
            <tr>
                <th><a name="table3">Variable Name:</a></th>
                <th>Value Type:</th>
                <th>Description:</th>
            </tr>
            <tr><td><code>HTTPe</code></td>                         <td>flag</td>      <td>HTTP/2 is being used.</td></tr>
            <tr><td><code>H2PUSH</code></td>                        <td>flag</td>      <td>HTTP/2 Server Push is enabled for this request and also supported by the client.</td></tr>
        </table>
        
    </section>

    <directivesynopsis>
        <name>H2Direct</name>
        <description>H2 Direct Protocol Switch</description>
@@ -173,6 +193,43 @@
        </usage>
    </directivesynopsis>

    <directivesynopsis>
        <name>H2PushDiarySize</name>
        <description>H2 Server Push Diary Size</description>
        <syntax>H2PushDiarySize n</syntax>
        <default>H2PushDiarySize 256</default>
        <contextlist>
            <context>server config</context>
            <context>virtual host</context>
        </contextlist>
        <compatibility>Available in version 2.4.19 and later.</compatibility>
        
        <usage>
            <p>
                This directive toggles the maximum number of HTTP/2 server pushes 
                that are remembered per HTTP/2 connection. This can be used inside the
                <directive module="core" type="section">VirtualHost</directive> 
                section to influence the number for all connections to that virtual host. 
            </p>
            <p>
                The push diary records a digest (currently using a 64 bit number) of pushed
                resources (their URL) to avoid duplicate pushes on the same connection.
                These value are not persisted, so clients openeing a new connection
                will experience known pushes again. There is ongoing work to enable
                a client to disclose a digest of the resources it already has, so
                the diary maybe initialized by the client on each connection setup.
            </p>
            <p>
                If the maximum size is reached, newer entries replace the oldest
                ones. A diary entry uses 8 bytes, letting a
                default diary with 256 entries consume around 2 KB of memory.
            </p>
            <p>
                A size of 0 will effectively disable the push diary.
            </p>
        </usage>
    </directivesynopsis>

    <directivesynopsis>
        <name>H2PushPriority</name>
        <description>H2 Server Push Priority</description>
@@ -404,7 +461,7 @@ H2PushPriority text/css interleaved # weight 256 default
        <name>H2WindowSize</name>
        <description>Size of Stream Window for upstream data.</description>
        <syntax>H2WindowSize <em>bytes</em></syntax>
        <default>H2WindowSize 65536</default>
        <default>H2WindowSize 65535</default>
        <contextlist>
            <context>server config</context>
            <context>virtual host</context>
@@ -498,7 +555,6 @@ H2PushPriority text/css interleaved # weight 256 default
        <name>H2SessionExtraFiles</name>
        <description>Number of Extra File Handles</description>
        <syntax>H2SessionExtraFiles <em>n</em></syntax>
        <default>H2SessionExtraFiles 5</default>
        <contextlist>
            <context>server config</context>
            <context>virtual host</context>
@@ -528,6 +584,11 @@ H2PushPriority text/css interleaved # weight 256 default
                    H2SessionExtraFiles 10
                </highlight>
            </example>
            <p>
                If nothing is configured, the module tries to make a conservative
                guess how many files are safe to use. This depends largely on the 
                MPM chosen.
            </p>
        </usage>
    </directivesynopsis>

@@ -705,4 +766,99 @@ H2PushPriority text/css interleaved # weight 256 default
        </usage>
    </directivesynopsis>
    
    <directivesynopsis>
        <name>H2Timeout</name>
        <description>Timeout (in seconds) for HTTP/2 connections</description>
        <syntax>H2Timeout seconds</syntax>
        <default>H2Timeout 5</default>
        <contextlist>
            <context>server config</context>
            <context>virtual host</context>
        </contextlist>
        <compatibility>Available in version 2.4.19 and later.</compatibility>

        <usage>
            <p>
                This directive sets the timeout for read/write operations on
                connections where HTTP/2 is negotiated. This can be used server wide or for specific
                <directive module="core" type="section">VirtualHost</directive>s. 
            </p>
            <p>
                This directive is similar to the 
                <directive module="core" type="section">Timeout</directive>, but
                applies only to HTTP/2 connections.
            </p>
            <p>
                A value of 0 enforces no timeout.
            </p>
        </usage>
    </directivesynopsis>

    <directivesynopsis>
        <name>H2KeepAliveTimeout</name>
        <description>Timeout (in seconds) for idle HTTP/2 connections</description>
        <syntax>H2KeepAliveTimeout seconds</syntax>
        <contextlist>
            <context>server config</context>
            <context>virtual host</context>
        </contextlist>
        <compatibility>Available in version 2.4.19 and later.</compatibility>

        <usage>
            <p>
                This directive sets the timeout for read/write operations on
                idle connections where HTTP/2 is negotiated. This can be used server wide or for specific
                <directive module="core" type="section">VirtualHost</directive>s. 
            </p>
            <p>
                This directive is similar to the 
                <directive module="core" type="section">KeepAliveTimeout</directive>, but
                applies only to HTTP/2 connections. A HTTP/2 connection is considered
                idle when no streams are open, e.g. no requests are ongoing.
            </p>
            <p>
                By default, for non-async MPMs (prefork, worker) the keepalive timeout
                will be the same as H2Timeout. For async MPMs, the keepalive handling for
                HTTP/1 connections applies as no special action is taken.
            </p>
        </usage>
    </directivesynopsis>

    <directivesynopsis>
        <name>H2StreamTimeout</name>
        <description>Timeout (in seconds) for idle HTTP/2 connections</description>
        <syntax>H2StreamTimeout seconds</syntax>
        <default>H2StreamTimeout 0</default>
        <contextlist>
            <context>server config</context>
            <context>virtual host</context>
        </contextlist>
        <compatibility>Available in version 2.4.19 and later.</compatibility>

        <usage>
            <p>
                This directive sets the timeout for read/write operations on
                HTTP/2 streams, e.g. individual requests. This can be used server wide or for specific
                <directive module="core" type="section">VirtualHost</directive>s. 
            </p>
            <p>
                Due to the nature of HTTP/2, which sends multiple requests over a single
                connection and has priority scheduling, individual streams might not
                see input for much longer times than HTTP/1.1 requests would. 
            </p>
            <p>
                A value of 0 enforces no timeout, so could wait on chances to receive
                input or write data indefinitely. This expose a server to
                risks of thread exhaustion. 
            </p>
            <p>
                Depending on your handling of pushed streams,
                priorities and general responsiveness, a site might need to increase
                this value. For example, if you PUSH a large resource <em>before</em>
                the requested one, the initial stream will not write until the
                pushed resource is fully sent.
            </p>
        </usage>
    </directivesynopsis>

</modulesynopsis>
+9 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ h2_config.lo dnl
h2_conn.lo dnl
h2_conn_io.lo dnl
h2_ctx.lo dnl
h2_filter.lo dnl
h2_from_h1.lo dnl
h2_h2.lo dnl
h2_io.lo dnl
@@ -180,6 +181,11 @@ APACHE_MODULE(http2, [HTTP/2 protocol handling in addition to HTTP protocol
handling. Implemented by mod_http2. This module requires a libnghttp2 installation. 
See --with-nghttp2 on how to manage non-standard locations. This module
is usually linked shared and requires loading. ], $http2_objs, , most, [
    APACHE_CHECK_OPENSSL
    if test "$ac_cv_openssl" = "yes" ; then
        APR_ADDTO(MOD_CPPFLAGS, ["-DH2_OPENSSL"])
    fi

    APACHE_CHECK_NGHTTP2
    if test "$ac_cv_nghttp2" = "yes" ; then
        if test "x$enable_http2" = "xshared"; then
@@ -192,6 +198,9 @@ is usually linked shared and requires loading. ], $http2_objs, , most, [
    fi
])

# Ensure that other modules can pick up mod_http2.h
APR_ADDTO(INCLUDES, [-I\$(top_srcdir)/$modpath_current])

dnl #  end of module specific part
APACHE_MODPATH_FINISH
+6 −8
Original line number Diff line number Diff line
@@ -41,17 +41,18 @@ void h2_alt_svc_register_hooks(void)
 * - do not percent encode token values
 * - do not use quotation marks
 */
h2_alt_svc *h2_alt_svc_parse(const char *s, apr_pool_t *pool) {
h2_alt_svc *h2_alt_svc_parse(const char *s, apr_pool_t *pool)
{
    const char *sep = ap_strchr_c(s, '=');
    if (sep) {
        const char *alpn = apr_pstrndup(pool, s, sep - s);
        const char *alpn = apr_pstrmemdup(pool, s, sep - s);
        const char *host = NULL;
        int port = 0;
        s = sep + 1;
        sep = ap_strchr_c(s, ':');  /* mandatory : */
        if (sep) {
            if (sep != s) {    /* optional host */
                host = apr_pstrndup(pool, s, sep - s);
                host = apr_pstrmemdup(pool, s, sep - s);
            }
            s = sep + 1;
            if (*s) {          /* must be a port number */
@@ -73,7 +74,6 @@ h2_alt_svc *h2_alt_svc_parse(const char *s, apr_pool_t *pool) {

static int h2_alt_svc_handler(request_rec *r)
{
    h2_ctx *ctx;
    const h2_config *cfg;
    int i;
    
@@ -82,8 +82,7 @@ static int h2_alt_svc_handler(request_rec *r)
        return DECLINED;
    }
    
    ctx = h2_ctx_rget(r);
    if (h2_ctx_is_active(ctx) || h2_ctx_is_task(ctx)) {
    if (h2_ctx_rget(r)) {
        return DECLINED;
    }
    
@@ -122,11 +121,10 @@ static int h2_alt_svc_handler(request_rec *r)
                }
            }
            if (*alt_svc) {
                apr_table_set(r->headers_out, "Alt-Svc", alt_svc);
                apr_table_setn(r->headers_out, "Alt-Svc", alt_svc);
            }
        }
    }
    
    return DECLINED;
}
+101 −53
Original line number Diff line number Diff line
@@ -59,32 +59,16 @@ static h2_config defconf = {
    1,                      /* TLS cooldown secs */
    1,                      /* HTTP/2 server push enabled */
    NULL,                   /* map of content-type to priorities */
};

static int files_per_session = 0;
    -1,                     /* connection timeout */
    -1,                     /* keepalive timeout */
    0,                      /* stream timeout */
    256,                    /* push diary size */
    
void h2_config_init(apr_pool_t *pool) {
    /* Determine a good default for this platform and mpm?
     * TODO: not sure how APR wants to hand out this piece of 
     * information.
     */
    int max_files = 256;
    int conn_threads = 1;
    int tx_files = max_files / 4;
};

void h2_config_init(apr_pool_t *pool)
{
    (void)pool;
    ap_mpm_query(AP_MPMQ_MAX_THREADS, &conn_threads);
    switch (h2_conn_mpm_type()) {
        case H2_MPM_PREFORK:
        case H2_MPM_WORKER:
        case H2_MPM_EVENT:
            /* allow that many transfer open files per mplx */
            files_per_session = (tx_files / conn_threads);
            break;
        default:
            /* don't know anything about it, stay safe */
            break;
    }
}

static void *h2_config_create(apr_pool_t *pool,
@@ -93,11 +77,7 @@ static void *h2_config_create(apr_pool_t *pool,
    h2_config *conf = (h2_config *)apr_pcalloc(pool, sizeof(h2_config));
    
    const char *s = x? x : "unknown";
    char *name = apr_pcalloc(pool, strlen(prefix) + strlen(s) + 20);
    strcpy(name, prefix);
    strcat(name, "[");
    strcat(name, s);
    strcat(name, "]");
    char *name = apr_pstrcat(pool, prefix, "[", s, "]", NULL);
    
    conf->name                 = name;
    conf->h2_max_streams       = DEF_VAL;
@@ -116,6 +96,10 @@ static void *h2_config_create(apr_pool_t *pool,
    conf->tls_cooldown_secs    = DEF_VAL;
    conf->h2_push              = DEF_VAL;
    conf->priorities           = NULL;
    conf->h2_timeout           = DEF_VAL;
    conf->h2_keepalive         = DEF_VAL;
    conf->h2_stream_timeout    = DEF_VAL;
    conf->push_diary_size      = DEF_VAL;
    
    return conf;
}
@@ -136,12 +120,7 @@ void *h2_config_merge(apr_pool_t *pool, void *basev, void *addv)
    h2_config *add = (h2_config *)addv;
    h2_config *n = (h2_config *)apr_pcalloc(pool, sizeof(h2_config));

    char *name = apr_pcalloc(pool, 20 + strlen(add->name) + strlen(base->name));
    strcpy(name, "merged[");
    strcat(name, add->name);
    strcat(name, ", ");
    strcat(name, base->name);
    strcat(name, "]");
    char *name = apr_pstrcat(pool, "merged[", add->name, ", ", base->name, "]", NULL);
    n->name = name;

    n->h2_max_streams       = H2_CONFIG_GET(add, base, h2_max_streams);
@@ -166,6 +145,10 @@ void *h2_config_merge(apr_pool_t *pool, void *basev, void *addv)
    else {
        n->priorities       = add->priorities? add->priorities : base->priorities;
    }
    n->h2_timeout           = H2_CONFIG_GET(add, base, h2_timeout);
    n->h2_keepalive = H2_CONFIG_GET(add, base, h2_keepalive);
    n->h2_stream_timeout    = H2_CONFIG_GET(add, base, h2_stream_timeout);
    n->push_diary_size      = H2_CONFIG_GET(add, base, push_diary_size);
    
    return n;
}
@@ -177,7 +160,6 @@ int h2_config_geti(const h2_config *conf, h2_config_var_t var)

apr_int64_t h2_config_geti64(const h2_config *conf, h2_config_var_t var)
{
    int n;
    switch(var) {
        case H2_CONF_MAX_STREAMS:
            return H2_CONFIG_GET(conf, &defconf, h2_max_streams);
@@ -202,17 +184,21 @@ apr_int64_t h2_config_geti64(const h2_config *conf, h2_config_var_t var)
        case H2_CONF_DIRECT:
            return H2_CONFIG_GET(conf, &defconf, h2_direct);
        case H2_CONF_SESSION_FILES:
            n = H2_CONFIG_GET(conf, &defconf, session_extra_files);
            if (n < 0) {
                n = files_per_session;
            }
            return n;
            return H2_CONFIG_GET(conf, &defconf, session_extra_files);
        case H2_CONF_TLS_WARMUP_SIZE:
            return H2_CONFIG_GET(conf, &defconf, tls_warmup_size);
        case H2_CONF_TLS_COOLDOWN_SECS:
            return H2_CONFIG_GET(conf, &defconf, tls_cooldown_secs);
        case H2_CONF_PUSH:
            return H2_CONFIG_GET(conf, &defconf, h2_push);
        case H2_CONF_TIMEOUT_SECS:
            return H2_CONFIG_GET(conf, &defconf, h2_timeout);
        case H2_CONF_KEEPALIVE_SECS:
            return H2_CONFIG_GET(conf, &defconf, h2_keepalive);
        case H2_CONF_STREAM_TIMEOUT_SECS:
            return H2_CONFIG_GET(conf, &defconf, h2_stream_timeout);
        case H2_CONF_PUSH_DIARY_SIZE:
            return H2_CONFIG_GET(conf, &defconf, push_diary_size);
        default:
            return DEF_VAL;
    }
@@ -256,7 +242,7 @@ static const char *h2_conf_set_window_size(cmd_parms *parms,
    cfg->h2_window_size = (int)apr_atoi64(value);
    (void)arg;
    if (cfg->h2_window_size < 1024) {
        return "value must be > 1k";
        return "value must be >= 1024";
    }
    return NULL;
}
@@ -268,7 +254,7 @@ static const char *h2_conf_set_min_workers(cmd_parms *parms,
    cfg->min_workers = (int)apr_atoi64(value);
    (void)arg;
    if (cfg->min_workers < 1) {
        return "value must be > 1";
        return "value must be > 0";
    }
    return NULL;
}
@@ -280,7 +266,7 @@ static const char *h2_conf_set_max_workers(cmd_parms *parms,
    cfg->max_workers = (int)apr_atoi64(value);
    (void)arg;
    if (cfg->max_workers < 1) {
        return "value must be > 1";
        return "value must be > 0";
    }
    return NULL;
}
@@ -292,7 +278,7 @@ static const char *h2_conf_set_max_worker_idle_secs(cmd_parms *parms,
    cfg->max_worker_idle_secs = (int)apr_atoi64(value);
    (void)arg;
    if (cfg->max_worker_idle_secs < 1) {
        return "value must be > 1";
        return "value must be > 0";
    }
    return NULL;
}
@@ -306,7 +292,7 @@ static const char *h2_conf_set_stream_max_mem_size(cmd_parms *parms,
    cfg->stream_max_mem_size = (int)apr_atoi64(value);
    (void)arg;
    if (cfg->stream_max_mem_size < 1024) {
        return "value must be > 1k";
        return "value must be >= 1024";
    }
    return NULL;
}
@@ -510,6 +496,59 @@ static const char *h2_conf_set_tls_cooldown_secs(cmd_parms *parms,
    return NULL;
}

static const char *h2_conf_set_timeout(cmd_parms *parms,
                                       void *arg, const char *value)
{
    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
    (void)arg;
    cfg->h2_timeout = (int)apr_atoi64(value);
    if (cfg->h2_timeout < 0) {
        return "value must be >= 0";
    }
    return NULL;
}

static const char *h2_conf_set_keepalive(cmd_parms *parms,
                                                 void *arg, const char *value)
{
    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
    (void)arg;
    cfg->h2_keepalive = (int)apr_atoi64(value);
    if (cfg->h2_keepalive < 0) {
        return "value must be >= 0";
    }
    return NULL;
}

static const char *h2_conf_set_stream_timeout(cmd_parms *parms,
                                              void *arg, const char *value)
{
    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
    (void)arg;
    cfg->h2_stream_timeout = (int)apr_atoi64(value);
    if (cfg->h2_stream_timeout < 0) {
        return "value must be >= 0";
    }
    return NULL;
}

static const char *h2_conf_set_push_diary_size(cmd_parms *parms,
                                               void *arg, const char *value)
{
    h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
    (void)arg;
    cfg->push_diary_size = (int)apr_atoi64(value);
    if (cfg->push_diary_size < 0) {
        return "value must be >= 0";
    }
    if (cfg->push_diary_size > 0 && (cfg->push_diary_size & (cfg->push_diary_size-1))) {
        return "value must a power of 2";
    }
    if (cfg->push_diary_size > (1 << 15)) {
        return "value must <= 65536";
    }
    return NULL;
}

#define AP_END_CMD     AP_INIT_TAKE1(NULL, NULL, NULL, RSRC_CONF, NULL)

@@ -548,6 +587,14 @@ const command_rec h2_cmds[] = {
                  RSRC_CONF, "off to disable HTTP/2 server push"),
    AP_INIT_TAKE23("H2PushPriority", h2_conf_add_push_priority, NULL,
                  RSRC_CONF, "define priority of PUSHed resources per content type"),
    AP_INIT_TAKE1("H2Timeout", h2_conf_set_timeout, NULL,
                  RSRC_CONF, "read/write timeout (seconds) for HTTP/2 connections"),
    AP_INIT_TAKE1("H2KeepAliveTimeout", h2_conf_set_keepalive, NULL,
                  RSRC_CONF, "timeout (seconds) for idle HTTP/2 connections, no streams open"),
    AP_INIT_TAKE1("H2StreamTimeout", h2_conf_set_stream_timeout, NULL,
                  RSRC_CONF, "read/write timeout (seconds) for HTTP/2 streams"),
    AP_INIT_TAKE1("H2PushDiarySize", h2_conf_set_push_diary_size, NULL,
                  RSRC_CONF, "size of push diary"),
    AP_END_CMD
};

@@ -561,8 +608,9 @@ const h2_config *h2_config_rget(request_rec *r)

const h2_config *h2_config_get(conn_rec *c)
{
    h2_ctx *ctx = h2_ctx_get(c);
    h2_ctx *ctx = h2_ctx_get(c, 0);
    
    if (ctx) {
        if (ctx->config) {
            return ctx->config;
        }
@@ -570,7 +618,7 @@ const h2_config *h2_config_get(conn_rec *c)
            ctx->config = h2_config_sget(ctx->server);
            return ctx->config;
        }
    }
    
    return h2_config_sget(c->base_server);
}
Loading