httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ic...@apache.org
Subject svn commit: r1714219 - in /httpd/httpd/trunk: docs/manual/mod/ modules/http2/
Date Fri, 13 Nov 2015 14:54:16 GMT
Author: icing
Date: Fri Nov 13 14:54:15 2015
New Revision: 1714219

URL: http://svn.apache.org/viewvc?rev=1714219&view=rev
Log:
new directive H2Push on/off to en-/disable HTTP/2 server pushes. Server pushes are recognized by Link: headers in responses that carry the rel=preload parameter

Modified:
    httpd/httpd/trunk/docs/manual/mod/mod_http2.xml
    httpd/httpd/trunk/modules/http2/h2_config.c
    httpd/httpd/trunk/modules/http2/h2_config.h
    httpd/httpd/trunk/modules/http2/h2_h2.c
    httpd/httpd/trunk/modules/http2/h2_mplx.c
    httpd/httpd/trunk/modules/http2/h2_push.c
    httpd/httpd/trunk/modules/http2/h2_push.h
    httpd/httpd/trunk/modules/http2/h2_request.c
    httpd/httpd/trunk/modules/http2/h2_request.h
    httpd/httpd/trunk/modules/http2/h2_response.c
    httpd/httpd/trunk/modules/http2/h2_response.h
    httpd/httpd/trunk/modules/http2/h2_session.c
    httpd/httpd/trunk/modules/http2/h2_session.h
    httpd/httpd/trunk/modules/http2/h2_stream.c
    httpd/httpd/trunk/modules/http2/h2_stream.h
    httpd/httpd/trunk/modules/http2/h2_task_input.c
    httpd/httpd/trunk/modules/http2/h2_util.c
    httpd/httpd/trunk/modules/http2/h2_util.h
    httpd/httpd/trunk/modules/http2/h2_workers.c

Modified: httpd/httpd/trunk/docs/manual/mod/mod_http2.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/mod/mod_http2.xml?rev=1714219&r1=1714218&r2=1714219&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/mod/mod_http2.xml (original)
+++ httpd/httpd/trunk/docs/manual/mod/mod_http2.xml Fri Nov 13 14:54:15 2015
@@ -90,6 +90,74 @@
     </directivesynopsis>
 
     <directivesynopsis>
+        <name>H2Push</name>
+        <description>H2 Server Push Switch</description>
+        <syntax>H2Push on|off</syntax>
+        <default>H2Push on</default>
+        <contextlist>
+            <context>server config</context>
+            <context>virtual host</context>
+        </contextlist>
+        
+        <usage>
+            <p>
+                This directive toggles the usage of the HTTP/2 server push 
+                protocol feature. This should be used inside a 
+                <directive module="core" type="section">VirtualHost</directive> 
+                section to enable direct HTTP/2 communication for that virtual host. 
+            </p>
+            <p>
+                The HTTP/2 protocol allows the server to push other resources to
+                a client when it asked for a particular one. This is helpful
+                if those resources are connected in some way and the client can
+                be expected to ask for it anyway. The pushing then saves the
+                time it takes the client to ask for the resources itself. On the
+                other hand, pushing resources the client never needs or already
+                has is a waste of bandwidth.
+            </p>
+            <p>
+                Server pushes are detected by inspecting the <code>Link</code> headers of
+                responses (see https://tools.ietf.org/html/rfc5988 for the 
+                specification). When a link thus specified has the <code>rel=preload</code>
+                attribute, it is treated as a resource to be pushed.
+            </p>
+            <p> 
+                Link headers in responses are either set by the application or
+                can be configured via <module>mod_headers</module> as:
+            </p>
+            <example><title>mod_headers example</title>
+                <highlight language="config">
+                    <Location /index.html>
+                        Header add Link "</css/site.css>;rel=preload"
+                        Header add Link "</images/logo.jpg>;rel=preload"
+                    </Location>
+                </highlight>
+            </example>
+            <p>
+                As the example shows, there can be several link headers added
+                to a response, resulting in several pushes being triggered. There
+                are no checks in the module to avoid pushing the same resource
+                twice or more to one client. Use with care.
+            </p>
+            <p> 
+                HTTP/2 server pushes are enabled by default. This directive 
+                allows it to be switch off on all resources of this server/virtual
+                host.
+            </p>
+            <example><title>Example</title>
+                <highlight language="config">
+                    H2Push off
+                </highlight>
+            </example>
+            <p>
+                Last but not least, pushes happen only when the client signals
+                its willingness to accept those. Most browsers do, some, like Safari 9,
+                do not.
+            </p>
+        </usage>
+    </directivesynopsis>
+
+    <directivesynopsis>
         <name>H2Upgrade</name>
         <description>H2 Upgrade Protocol Switch</description>
         <syntax>H2Upgrade on|off</syntax>
@@ -285,7 +353,7 @@
             <p>
                 This directive sets maximum number of <em>extra</em> file handles
                 a HTTP/2 session is allowed to use. A file handle is counted as
-                <em>extra</em> when it is transfered from a h2 worker thread to
+                <em>extra</em> when it is transferred from a h2 worker thread to
                 the main HTTP/2 connection handling. This commonly happens when
                 serving static files.
             </p><p>
@@ -362,8 +430,8 @@
             <p>
                 The name stems from the 
                 <a href="https://wiki.mozilla.org/Security/Server_Side_TLS">Security/Server Side TLS</a>
-                definitions at mozilla where "modern compatiblity" is defined. Mozilla Firefox and
-                other browsers require modern compatiblity for HTTP/2 connections. As everything
+                definitions at mozilla where "modern compatibility" is defined. Mozilla Firefox and
+                other browsers require modern compatibility for HTTP/2 connections. As everything
                 in OpSec, this is a moving target and can be expected to evolve in the future.
             </p>
             <p>
@@ -423,7 +491,7 @@
             <p>
                 In deployments where servers are reached locally or over reliable
                 connections only, the value might be decreased with 0 disabling
-                any warmup phase alltogether.
+                any warmup phase altogether.
             </p>
             <p>
                 The following example sets the size to zero, effectively disabling
@@ -458,7 +526,7 @@
             <p>
                 See <directive type="section">H2TLSWarmUpSize</directive> for a
                 description of TLS warmup. H2TLSCoolDownSecs reflects the fact
-                that connections may detoriate over time (and TCP flow adjusts)
+                that connections may deteriorate over time (and TCP flow adjusts)
                 for idle connections as well. It is beneficial to overall performance
                 to fall back to the pre-warmup phase after a number of seconds that
                 no data has been sent. 
@@ -469,7 +537,7 @@
             </p>
             <p>
                 The following example sets the seconds to zero, effectively disabling
-                any cooldown. Warmed up TLS connections stay on maximum record
+                any cool down. Warmed up TLS connections stay on maximum record
                 size.
             </p>
             <example><title>Example</title>

Modified: httpd/httpd/trunk/modules/http2/h2_config.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_config.c?rev=1714219&r1=1714218&r2=1714219&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_config.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_config.c Fri Nov 13 14:54:15 2015
@@ -53,6 +53,7 @@ static h2_config defconf = {
     -1,               /* HTTP/1 Upgrade support */
     1024*1024,        /* TLS warmup size */
     1,                /* TLS cooldown secs */
+    1,                /* HTTP/2 server push enabled */
 };
 
 static int files_per_session = 0;
@@ -108,6 +109,7 @@ static void *h2_config_create(apr_pool_t
     conf->h2_upgrade           = DEF_VAL;
     conf->tls_warmup_size      = DEF_VAL;
     conf->tls_cooldown_secs    = DEF_VAL;
+    conf->h2_push              = DEF_VAL;
     
     return conf;
 }
@@ -151,6 +153,7 @@ void *h2_config_merge(apr_pool_t *pool,
     n->h2_upgrade           = H2_CONFIG_GET(add, base, h2_upgrade);
     n->tls_warmup_size      = H2_CONFIG_GET(add, base, tls_warmup_size);
     n->tls_cooldown_secs    = H2_CONFIG_GET(add, base, tls_cooldown_secs);
+    n->h2_push              = H2_CONFIG_GET(add, base, h2_push);
     
     return n;
 }
@@ -196,6 +199,8 @@ apr_int64_t h2_config_geti64(h2_config *
             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);
         default:
             return DEF_VAL;
     }
@@ -358,6 +363,23 @@ static const char *h2_conf_set_direct(cm
     return "value must be On or Off";
 }
 
+static const char *h2_conf_set_push(cmd_parms *parms,
+                                    void *arg, const char *value)
+{
+    h2_config *cfg = h2_config_sget(parms->server);
+    if (!strcasecmp(value, "On")) {
+        cfg->h2_push = 1;
+        return NULL;
+    }
+    else if (!strcasecmp(value, "Off")) {
+        cfg->h2_push = 0;
+        return NULL;
+    }
+    
+    (void)arg;
+    return "value must be On or Off";
+}
+
 static const char *h2_conf_set_modern_tls_only(cmd_parms *parms,
                                                void *arg, const char *value)
 {
@@ -444,6 +466,8 @@ const command_rec h2_cmds[] = {
                   RSRC_CONF, "number of bytes on TLS connection before doing max writes"),
     AP_INIT_TAKE1("H2TLSCoolDownSecs", h2_conf_set_tls_cooldown_secs, NULL,
                   RSRC_CONF, "seconds of idle time on TLS before shrinking writes"),
+    AP_INIT_TAKE1("H2Push", h2_conf_set_push, NULL,
+                  RSRC_CONF, "off to disable HTTP/2 server push"),
     AP_END_CMD
 };
 

Modified: httpd/httpd/trunk/modules/http2/h2_config.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_config.h?rev=1714219&r1=1714218&r2=1714219&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_config.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_config.h Fri Nov 13 14:54:15 2015
@@ -38,6 +38,7 @@ typedef enum {
     H2_CONF_UPGRADE,
     H2_CONF_TLS_WARMUP_SIZE,
     H2_CONF_TLS_COOLDOWN_SECS,
+    H2_CONF_PUSH,
 } h2_config_var_t;
 
 /* Apache httpd module configuration for h2. */
@@ -59,6 +60,7 @@ typedef struct h2_config {
     int h2_upgrade;               /* Allow HTTP/1 upgrade to h2/h2c */
     apr_int64_t tls_warmup_size;  /* Amount of TLS data to send before going full write size */
     int tls_cooldown_secs;        /* Seconds of idle time before going back to small TLS records */
+    int h2_push;                  /* if HTTP/2 server push is enabled */
 } h2_config;
 
 

Modified: httpd/httpd/trunk/modules/http2/h2_h2.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_h2.c?rev=1714219&r1=1714218&r2=1714219&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_h2.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_h2.c Fri Nov 13 14:54:15 2015
@@ -664,7 +664,7 @@ static int h2_h2_post_read_req(request_r
     struct h2_task *task = h2_ctx_get_task(ctx);
     if (task) {
         /* h2_task connection for a stream, not for h2c */
-        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+        ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r,
                       "adding h1_to_h2_resp output filter");
         if (task->serialize_headers) {
             ap_remove_output_filter_byhandle(r->output_filters, "H1_TO_H2_RESP");

Modified: httpd/httpd/trunk/modules/http2/h2_mplx.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_mplx.c?rev=1714219&r1=1714218&r2=1714219&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_mplx.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_mplx.c Fri Nov 13 14:54:15 2015
@@ -583,7 +583,7 @@ static apr_status_t out_open(h2_mplx *m,
     h2_io *io = h2_io_set_get(m->stream_ios, stream_id);
     if (io) {
         if (f) {
-            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, f->c,
+            ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
                           "h2_mplx(%ld-%d): open response: %d, rst=%d",
                           m->id, stream_id, response->http_status, 
                           response->rst_error);

Modified: httpd/httpd/trunk/modules/http2/h2_push.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_push.c?rev=1714219&r1=1714218&r2=1714219&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_push.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_push.c Fri Nov 13 14:54:15 2015
@@ -17,6 +17,7 @@
 #include <stdio.h>
 
 #include <apr_strings.h>
+#include <apr_lib.h>
 
 #include <httpd.h>
 #include <http_core.h>
@@ -31,18 +32,283 @@
 
 
 typedef struct {
-    apr_array_header_t *pushes;
-    apr_pool_t *pool;
     const h2_request *req;
+    apr_pool_t *pool;
+    apr_array_header_t *pushes;
+    const char *s;
+    size_t slen;
+    size_t i;
+    
+    const char *link;
+    apr_table_t *params;
+    char b[4096];
 } link_ctx;
 
-static size_t skip_ws(const char *s, size_t i, size_t max)
+static int attr_char(char c) 
+{
+    switch (c) {
+        case '!':
+        case '#':
+        case '$':
+        case '&':
+        case '+':
+        case '-':
+        case '.':
+        case '^':
+        case '_':
+        case '`':
+        case '|':
+        case '~':
+            return 1;
+        default:
+            return apr_isalnum(c);
+    }
+}
+
+static int ptoken_char(char c) 
+{
+    switch (c) {
+        case '!':
+        case '#':
+        case '$':
+        case '&':
+        case '\'':
+        case '(':
+        case ')':
+        case '*':
+        case '+':
+        case '-':
+        case '.':
+        case '/':
+        case ':':
+        case '<':
+        case '=':
+        case '>':
+        case '?':
+        case '@':
+        case '[':
+        case ']':
+        case '^':
+        case '_':
+        case '`':
+        case '{':
+        case '|':
+        case '}':
+        case '~':
+            return 1;
+        default:
+            return apr_isalnum(c);
+    }
+}
+
+static int skip_ws(link_ctx *ctx)
 {
     char c;
-    while (i < max && (((c = s[i]) == ' ') || (c == '\t'))) {
-        ++i;
+    while (ctx->i < ctx->slen 
+           && (((c = ctx->s[ctx->i]) == ' ') || (c == '\t'))) {
+        ++ctx->i;
+    }
+    return (ctx->i < ctx->slen);
+}
+
+static int find_chr(link_ctx *ctx, char c, size_t *pidx)
+{
+    size_t j;
+    for (j = ctx->i; j < ctx->slen; ++j) {
+        if (ctx->s[j] == c) {
+            *pidx = j;
+            return 1;
+        }
+    } 
+    return 0;
+}
+
+static int read_chr(link_ctx *ctx, char c)
+{
+    if (ctx->i < ctx->slen && ctx->s[ctx->i] == c) {
+        ++ctx->i;
+        return 1;
+    }
+    return 0;
+}
+
+static char *mk_str(link_ctx *ctx, size_t end) 
+{
+    if (ctx->i < end) {
+        return apr_pstrndup(ctx->pool, ctx->s + ctx->i, end - ctx->i);
+    }
+    return "";
+}
+
+static int read_qstring(link_ctx *ctx, char **ps)
+{
+    if (skip_ws(ctx) && read_chr(ctx, '\"')) {
+        size_t end;
+        if (find_chr(ctx, '\"', &end)) {
+            *ps = mk_str(ctx, end);
+            ctx->i = end + 1;
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static int read_ptoken(link_ctx *ctx, char **ps)
+{
+    if (skip_ws(ctx)) {
+        size_t i;
+        for (i = ctx->i; i < ctx->slen && ptoken_char(ctx->s[i]); ++i) {
+            /* nop */
+        }
+        if (i > ctx->i) {
+            *ps = mk_str(ctx, i);
+            ctx->i = i;
+            return 1;
+        }
+    }
+    return 0;
+}
+
+
+static int read_link(link_ctx *ctx)
+{
+    if (skip_ws(ctx) && read_chr(ctx, '<')) {
+        size_t end;
+        if (find_chr(ctx, '>', &end)) {
+            ctx->link = mk_str(ctx, end);
+            ctx->i = end + 1;
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static int read_pname(link_ctx *ctx, char **pname)
+{
+    if (skip_ws(ctx)) {
+        size_t i;
+        for (i = ctx->i; i < ctx->slen && attr_char(ctx->s[i]); ++i) {
+            /* nop */
+        }
+        if (i > ctx->i) {
+            *pname = mk_str(ctx, i);
+            ctx->i = i;
+            return 1;
+        }
     }
-    return i;
+    return 0;
+}
+
+static int read_pvalue(link_ctx *ctx, char **pvalue)
+{
+    if (skip_ws(ctx) && read_chr(ctx, '=')) {
+        if (read_qstring(ctx, pvalue) || read_ptoken(ctx, pvalue)) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static int read_param(link_ctx *ctx)
+{
+    if (skip_ws(ctx) && read_chr(ctx, ';')) {
+        char *name, *value = "";
+        if (read_pname(ctx, &name)) {
+            read_pvalue(ctx, &value); /* value is optional */
+            apr_table_setn(ctx->params, name, value);
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static int read_sep(link_ctx *ctx)
+{
+    if (skip_ws(ctx) && read_chr(ctx, ',')) {
+        return 1;
+    }
+    return 0;
+}
+
+static void init_params(link_ctx *ctx) 
+{
+    if (!ctx->params) {
+        ctx->params = apr_table_make(ctx->pool, 5);
+    }
+    else {
+        apr_table_clear(ctx->params);
+    }
+}
+
+static int same_authority(const h2_request *req, const apr_uri_t *uri)
+{
+    if (uri->scheme != NULL && strcmp(uri->scheme, req->scheme)) {
+        return 0;
+    }
+    if (uri->hostinfo != NULL && strcmp(uri->hostinfo, req->authority)) {
+        return 0;
+    }
+    return 1;
+}
+
+static int set_header(void *ctx, const char *key, const char *value) 
+{
+    apr_table_setn(ctx, key, value);
+    return 1;
+}
+
+
+static int add_push(link_ctx *ctx)
+{
+    /* so, we have read a Link header and need to decide
+     * if we transform it into a push.
+     */
+    const char *rel = apr_table_get(ctx->params, "rel");
+    if (rel && !strcmp("preload", rel)) {
+        apr_uri_t uri;
+        if (apr_uri_parse(ctx->pool, ctx->link, &uri) == APR_SUCCESS) {
+            if (uri.path && same_authority(ctx->req, &uri)) {
+                char *path;
+                apr_table_t *headers;
+                h2_request *req;
+                h2_push *push;
+                
+                /* We only want to generate pushes for resources in the
+                 * same authority than the original request.
+                 * icing: i think that is wise, otherwise we really need to
+                 * check that the vhost/server is available and uses the same
+                 * TLS (if any) parameters.
+                 */
+                path = apr_uri_unparse(ctx->pool, &uri, APR_URI_UNP_OMITSITEPART);
+                
+                push = apr_pcalloc(ctx->pool, sizeof(*push));
+                push->initiating_id = ctx->req->id;
+                
+                headers = apr_table_make(ctx->pool, 5);
+                apr_table_do(set_header, headers, ctx->req->headers,
+                             "User-Agent",
+                             "Cache-Control",
+                             "Accept-Language",
+                             NULL);
+                /* TODO: which headers do we add here?
+                 */
+                
+                req = h2_request_createn(0, ctx->pool,
+                                         ctx->req->method, 
+                                         ctx->req->scheme,
+                                         ctx->req->authority, 
+                                         path, headers);
+                h2_request_end_headers(req, ctx->pool, 1);
+                push->req = req;
+                
+                if (!ctx->pushes) {
+                    ctx->pushes = apr_array_make(ctx->pool, 5, sizeof(h2_push*));
+                }
+                APR_ARRAY_PUSH(ctx->pushes, h2_push*) = push;
+            }
+        }
+    }
+    return 0;
 }
 
 static void inspect_link(link_ctx *ctx, const char *s, size_t slen)
@@ -77,20 +343,41 @@ static void inspect_link(link_ctx *ctx,
       relation-type  = reg-rel-type | ext-rel-type
       reg-rel-type   = LOALPHA *( LOALPHA | DIGIT | "." | "-" )
       ext-rel-type   = URI
+      
+      and from <https://tools.ietf.org/html/rfc5987>
+      parmname      = 1*attr-char
+      attr-char     = ALPHA / DIGIT
+                       / "!" / "#" / "$" / "&" / "+" / "-" / "."
+                       / "^" / "_" / "`" / "|" / "~"
      */
-     /* TODO */
-     (void)skip_ws;
+
+     ctx->s = s;
+     ctx->slen = slen;
+     ctx->i = 0;
+     
+     while (read_link(ctx)) {
+        init_params(ctx);
+        while (read_param(ctx)) {
+            /* nop */
+        }
+        add_push(ctx);
+        if (!read_sep(ctx)) {
+            break;
+        }
+     }
+}
+
+static int head_iter(void *ctx, const char *key, const char *value) 
+{
+    if (!apr_strnatcasecmp("link", key)) {
+        inspect_link(ctx, value, strlen(value));
+    }
+    return 1;
 }
 
 apr_array_header_t *h2_push_collect(apr_pool_t *p, const h2_request *req, 
                                     const h2_response *res)
 {
-    link_ctx ctx;
-    
-    ctx.pushes = NULL;
-    ctx.pool = p;
-    ctx.req = req;
-    
     /* Collect push candidates from the request/response pair.
      * 
      * One source for pushes are "rel=preload" link headers
@@ -99,16 +386,15 @@ apr_array_header_t *h2_push_collect(apr_
      * TODO: This may be extended in the future by hooks or callbacks
      * where other modules can provide push information directly.
      */
-    if (res->ngheader) {
-        int i;
-        for (i = 0; i < res->ngheader->nvlen; ++i) {
-            nghttp2_nv *nv = &res->ngheader->nv[i];
-            if (nv->namelen == 4 
-                && apr_strnatcasecmp("link", (const char *)nv->name)) {
-                inspect_link(&ctx, (const char *)nv->value, nv->valuelen);
-            }
-        }
-    }
+    if (res->header) {
+        link_ctx ctx;
+        
+        memset(&ctx, 0, sizeof(ctx));
+        ctx.req = req;
+        ctx.pool = p;
     
-    return ctx.pushes;
+        apr_table_do(head_iter, &ctx, res->header, NULL);
+        return ctx.pushes;
+    }
+    return NULL;
 }

Modified: httpd/httpd/trunk/modules/http2/h2_push.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_push.h?rev=1714219&r1=1714218&r2=1714219&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_push.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_push.h Fri Nov 13 14:54:15 2015
@@ -22,7 +22,6 @@ struct h2_ngheader;
 typedef struct h2_push {
     int initiating_id;
     const struct h2_request *req;
-    const struct h2_ngheader *promise;
     const char *as;
 } h2_push;
 

Modified: httpd/httpd/trunk/modules/http2/h2_request.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_request.c?rev=1714219&r1=1714218&r2=1714219&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_request.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_request.c Fri Nov 13 14:54:15 2015
@@ -31,11 +31,22 @@
 
 h2_request *h2_request_create(int id, apr_pool_t *pool)
 {
+    return h2_request_createn(id, pool, NULL, NULL, NULL, NULL, NULL);
+}
+
+h2_request *h2_request_createn(int id, apr_pool_t *pool,
+                               const char *method, const char *scheme,
+                               const char *authority, const char *path,
+                               apr_table_t *header)
+{
     h2_request *req = apr_pcalloc(pool, sizeof(h2_request));
     
-    req->id = id;
-    req->headers = apr_table_make(pool, 10);
-    req->content_length = -1;
+    req->id             = id;
+    req->method         = method;
+    req->scheme         = scheme;
+    req->authority      = authority;
+    req->path           = path;
+    req->headers        = header? header : apr_table_make(pool, 10);
     
     return req;
 }
@@ -44,45 +55,26 @@ void h2_request_destroy(h2_request *req)
 {
 }
 
+static apr_status_t inspect_clen(h2_request *req, const char *s)
+{
+    char *end;
+    req->content_length = apr_strtoi64(s, &end, 10);
+    return (s == end)? APR_EINVAL : APR_SUCCESS;
+}
+
 static apr_status_t add_h1_header(h2_request *req, apr_pool_t *pool, 
                                   const char *name, size_t nlen,
                                   const char *value, size_t vlen)
 {
     char *hname, *hvalue;
     
-    if (H2_HD_MATCH_LIT("transfer-encoding", name, nlen)) {
-        if (!apr_strnatcasecmp("chunked", value)) {
-            /* This should never arrive here in a HTTP/2 request */
-            ap_log_perror(APLOG_MARK, APLOG_ERR, APR_BADARG, pool,
-                          APLOGNO(02945) 
-                          "h2_request: 'transfer-encoding: chunked' received");
-            return APR_BADARG;
-        }
-    }
-    else if (H2_HD_MATCH_LIT("content-length", name, nlen)) {
-        char *end;
-        req->content_length = apr_strtoi64(value, &end, 10);
-        if (value == end) {
-            ap_log_perror(APLOG_MARK, APLOG_WARNING, APR_EINVAL, pool,
-                          APLOGNO(02959) 
-                          "h2_request(%d): content-length value not parsed: %s",
-                          req->id, value);
-            return APR_EINVAL;
-        }
-        req->chunked = 0;
-    }
-    else if (H2_HD_MATCH_LIT("content-type", name, nlen)) {
-        /* If we see a content-type and have no length (yet),
-         * we need to chunk. */
-        req->chunked = (req->content_length == -1);
-    }
-    else if ((req->seen_host && H2_HD_MATCH_LIT("host", name, nlen))
-             || H2_HD_MATCH_LIT("expect", name, nlen)
-             || H2_HD_MATCH_LIT("upgrade", name, nlen)
-             || H2_HD_MATCH_LIT("connection", name, nlen)
-             || H2_HD_MATCH_LIT("proxy-connection", name, nlen)
-             || H2_HD_MATCH_LIT("keep-alive", name, nlen)
-             || H2_HD_MATCH_LIT("http2-settings", name, nlen)) {
+    if (H2_HD_MATCH_LIT("expect", name, nlen)
+        || H2_HD_MATCH_LIT("upgrade", name, nlen)
+        || H2_HD_MATCH_LIT("connection", name, nlen)
+        || H2_HD_MATCH_LIT("proxy-connection", name, nlen)
+        || H2_HD_MATCH_LIT("transfer-encoding", name, nlen)
+        || H2_HD_MATCH_LIT("keep-alive", name, nlen)
+        || H2_HD_MATCH_LIT("http2-settings", name, nlen)) {
         /* ignore these. */
         return APR_SUCCESS;
     }
@@ -91,7 +83,7 @@ static apr_status_t add_h1_header(h2_req
         if (existing) {
             char *nval;
             
-            /* Cookie headers come separately in HTTP/2, but need
+            /* Cookie header come separately in HTTP/2, but need
              * to be merged by "; " (instead of default ", ")
              */
             hvalue = apr_pstrndup(pool, value, vlen);
@@ -101,7 +93,9 @@ static apr_status_t add_h1_header(h2_req
         }
     }
     else if (H2_HD_MATCH_LIT("host", name, nlen)) {
-        req->seen_host = 1;
+        if (apr_table_get(req->headers, "Host")) {
+            return APR_SUCCESS; /* ignore duplicate */
+        }
     }
     
     hname = apr_pstrndup(pool, name, nlen);
@@ -124,13 +118,13 @@ static int set_h1_header(void *ctx, cons
     return 1;
 }
 
-static apr_status_t add_h1_headers(h2_request *req, apr_pool_t *pool, 
-                                   apr_table_t *headers)
+static apr_status_t add_all_h1_header(h2_request *req, apr_pool_t *pool, 
+                                      apr_table_t *header)
 {
     h1_ctx x;
     x.req = req;
     x.pool = pool;
-    apr_table_do(set_h1_header, &x, headers, NULL);
+    apr_table_do(set_h1_header, &x, header, NULL);
     return APR_SUCCESS;
 }
 
@@ -150,7 +144,7 @@ apr_status_t h2_request_rwrite(h2_reques
                                       r->parsed_uri.port_str);
     }
     
-    status = add_h1_headers(req, r->pool, r->headers_in);
+    status = add_all_h1_header(req, r->pool, r->headers_in);
 
     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r,
                   "h2_request(%d): rwrite %s host=%s://%s%s",
@@ -215,11 +209,22 @@ apr_status_t h2_request_add_header(h2_re
 
 apr_status_t h2_request_end_headers(h2_request *req, apr_pool_t *pool, int eos)
 {
+    const char *s;
+    
     if (req->eoh) {
         return APR_EINVAL;
     }
-    
-    if (!req->seen_host) {
+
+    /* be safe, some header we do not accept on h2(c) */
+    apr_table_unset(req->headers, "expect");
+    apr_table_unset(req->headers, "upgrade");
+    apr_table_unset(req->headers, "connection");
+    apr_table_unset(req->headers, "proxy-connection");
+    apr_table_unset(req->headers, "transfer-encoding");
+    apr_table_unset(req->headers, "keep-alive");
+    apr_table_unset(req->headers, "http2-settings");
+
+    if (!apr_table_get(req->headers, "Host")) {
         /* Need to add a "Host" header if not already there to
          * make virtual hosts work correctly. */
         if (!req->authority) {
@@ -228,20 +233,34 @@ apr_status_t h2_request_end_headers(h2_r
         apr_table_set(req->headers, "Host", req->authority);
     }
 
-    if (eos && req->chunked) {
-        /* We had chunking figured out, but the EOS is already there.
-         * unmark chunking and set a definitive content-length.
-         */
+    s = apr_table_get(req->headers, "Content-Length");
+    if (s) {
+        if (inspect_clen(req, s) != APR_SUCCESS) {
+            ap_log_perror(APLOG_MARK, APLOG_WARNING, APR_EINVAL, pool,
+                          APLOGNO(02959) 
+                          "h2_request(%d): content-length value not parsed: %s",
+                          req->id, s);
+            return APR_EINVAL;
+        }
         req->chunked = 0;
-        apr_table_setn(req->headers, "Content-Length", "0");
     }
-    else if (req->chunked) {
-        /* We have not seen a content-length. We therefore must
-         * pass any request content in chunked form.
-         */
-        apr_table_mergen(req->headers, "Transfer-Encoding", "chunked");
+    else {
+        /* no content-length given */
+        req->content_length = -1;
+        s = apr_table_get(req->headers, "Content-Type");
+        if (eos && s) {
+            req->chunked = 0;
+            apr_table_setn(req->headers, "Content-Length", "0");
+        }
+        else if (s) {
+            /* We have not seen a content-length, but a content-type. 
+             * must pass any request content in chunked form.
+             */
+            req->chunked = 1;
+            apr_table_mergen(req->headers, "Transfer-Encoding", "chunked");
+        }
     }
-    
+
     req->eoh = 1;
     
     return APR_SUCCESS;
@@ -253,13 +272,12 @@ void h2_request_copy(apr_pool_t *p, h2_r
 {
     /* keep the dst id */
     dst->method         = OPT_COPY(p, src->method);
-    dst->scheme         = OPT_COPY(p, src->method);
-    dst->authority      = OPT_COPY(p, src->method);
-    dst->path           = OPT_COPY(p, src->method);
+    dst->scheme         = OPT_COPY(p, src->scheme);
+    dst->authority      = OPT_COPY(p, src->authority);
+    dst->path           = OPT_COPY(p, src->path);
     dst->headers        = apr_table_clone(p, src->headers);
     dst->content_length = src->content_length;
     dst->chunked        = src->chunked;
     dst->eoh            = src->eoh;
-    dst->seen_host      = src->seen_host;  
 }
 

Modified: httpd/httpd/trunk/modules/http2/h2_request.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_request.h?rev=1714219&r1=1714218&r2=1714219&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_request.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_request.h Fri Nov 13 14:54:15 2015
@@ -40,12 +40,15 @@ struct h2_request {
     apr_off_t content_length;
     int chunked;
     int eoh;
-    
-    int seen_host;
 };
 
 h2_request *h2_request_create(int id, apr_pool_t *pool);
 
+h2_request *h2_request_createn(int id, apr_pool_t *pool,
+                               const char *method, const char *scheme,
+                               const char *authority, const char *path,
+                               apr_table_t *headers);
+
 void h2_request_destroy(h2_request *req);
 
 apr_status_t h2_request_rwrite(h2_request *req, request_rec *r);

Modified: httpd/httpd/trunk/modules/http2/h2_response.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_response.c?rev=1714219&r1=1714218&r2=1714219&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_response.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_response.c Fri Nov 13 14:54:15 2015
@@ -27,20 +27,8 @@
 #include "h2_private.h"
 #include "h2_h2.h"
 #include "h2_util.h"
-#include "h2_push.h"
 #include "h2_response.h"
 
-static void make_ngheader(apr_pool_t *pool, h2_response *to,
-                          apr_table_t *header);
-
-static int ignore_header(const char *name) 
-{
-    return (H2_HD_MATCH_LIT_CS("connection", name)
-            || H2_HD_MATCH_LIT_CS("proxy-connection", name)
-            || H2_HD_MATCH_LIT_CS("upgrade", name)
-            || H2_HD_MATCH_LIT_CS("keep-alive", name)
-            || H2_HD_MATCH_LIT_CS("transfer-encoding", name));
-}
 
 h2_response *h2_response_create(int stream_id,
                                 int rst_error,
@@ -76,10 +64,8 @@ h2_response *h2_response_create(int stre
             while (*sep == ' ' || *sep == '\t') {
                 ++sep;
             }
-            if (ignore_header(hline)) {
-                /* never forward, ch. 8.1.2.2 */
-            }
-            else {
+            
+            if (!h2_util_ignore_header(hline)) {
                 apr_table_merge(header, hline, sep);
                 if (*sep && H2_HD_MATCH_LIT_CS("content-length", hline)) {
                     char *end;
@@ -100,7 +86,7 @@ h2_response *h2_response_create(int stre
         header = apr_table_make(pool, 0);        
     }
 
-    response->rheader = header;
+    response->header = header;
     return response;
 }
 
@@ -115,7 +101,7 @@ h2_response *h2_response_rcreate(int str
     response->stream_id = stream_id;
     response->http_status = r->status;
     response->content_length = -1;
-    response->rheader = header;
+    response->header = header;
 
     if (response->http_status == HTTP_FORBIDDEN) {
         const char *cause = apr_table_get(r->notes, "ssl-renegotiate-forbidden");
@@ -144,149 +130,10 @@ h2_response *h2_response_copy(apr_pool_t
     to->stream_id = from->stream_id;
     to->http_status = from->http_status;
     to->content_length = from->content_length;
-    if (from->rheader) {
-        make_ngheader(pool, to, from->rheader);
+    if (from->header) {
+        to->header = apr_table_clone(pool, from->header);
     }
     return to;
 }
 
-typedef struct {
-    nghttp2_nv *nv;
-    size_t nvlen;
-    size_t nvstrlen;
-    size_t offset;
-    char *strbuf;
-    apr_pool_t *pool;
-    apr_array_header_t *pushes;
-} nvctx_t;
-
-static int count_header(void *ctx, const char *key, const char *value)
-{
-    if (!ignore_header(key)) {
-        nvctx_t *nvctx = (nvctx_t*)ctx;
-        nvctx->nvlen++;
-        nvctx->nvstrlen += strlen(key) + strlen(value) + 2;
-    }
-    return 1;
-}
-
-#define NV_ADD_LIT_CS(nv, k, v)     addnv_lit_cs(nv, k, sizeof(k) - 1, v, strlen(v))
-#define NV_ADD_CS_CS(nv, k, v)      addnv_cs_cs(nv, k, strlen(k), v, strlen(v))
-#define NV_BUF_ADD(nv, s, len)      memcpy(nv->strbuf, s, len); \
-                                    s = nv->strbuf; \
-                                    nv->strbuf += len + 1
-
-static void addnv_cs_cs(nvctx_t *ctx, const char *key, size_t key_len,
-                        const char *value, size_t val_len)
-{
-    nghttp2_nv *nv = &ctx->nv[ctx->offset];
-    
-    NV_BUF_ADD(ctx, key, key_len);
-    NV_BUF_ADD(ctx, value, val_len);
-    
-    nv->name = (uint8_t*)key;
-    nv->namelen = key_len;
-    nv->value = (uint8_t*)value;
-    nv->valuelen = val_len;
-    
-    ctx->offset++;
-}
-
-static void addnv_lit_cs(nvctx_t *ctx, const char *key, size_t key_len,
-                         const char *value, size_t val_len)
-{
-    nghttp2_nv *nv = &ctx->nv[ctx->offset];
-    
-    NV_BUF_ADD(ctx, value, val_len);
-    
-    nv->name = (uint8_t*)key;
-    nv->namelen = key_len;
-    nv->value = (uint8_t*)value;
-    nv->valuelen = val_len;
-    
-    ctx->offset++;
-}
-
-static h2_push *h2_parse_preload(apr_pool_t *pool, const char *str)
-{
-    /* TODO: implement this */
-    return NULL;
-}
-
-static int add_header(void *ctx, const char *key, const char *value)
-{
-    if (!ignore_header(key)) {
-        nvctx_t *nvctx = (nvctx_t*)ctx;
-        NV_ADD_CS_CS(nvctx, key, value);
-        
-        if (apr_strnatcasecmp("link", key) 
-            && ap_strstr_c("preload", value)) {
-            /* Detect link headers with rel=preload to use as possible
-             * server push candidates. */
-            h2_push *push;
-            if ((push = h2_parse_preload(nvctx->pool, value))) {
-                if (!nvctx->pushes) {
-                    nvctx->pushes = apr_array_make(nvctx->pool, 5, 
-                                                   sizeof(h2_push*));
-                }
-                APR_ARRAY_PUSH(nvctx->pushes, h2_push*) = push;
-            }
-        }
-    }
-    return 1;
-}
-
-static void make_ngheader(apr_pool_t *pool, h2_response *to,
-                          apr_table_t *header)
-{
-    size_t n;
-    h2_ngheader *h;
-    nvctx_t ctx;
-    char *status;
-    
-    to->ngheader = NULL;
-    to->pushes   = NULL;
-    
-    status = apr_psprintf(pool, "%d", to->http_status);
-    ctx.nv       = NULL;
-    ctx.nvlen    = 1;
-    ctx.nvstrlen = strlen(status) + 1;
-    ctx.offset   = 0;
-    ctx.strbuf   = NULL;
-    ctx.pool     = pool;
-    ctx.pushes   = NULL;
-    
-    apr_table_do(count_header, &ctx, header, NULL);
-    
-    n =  (sizeof(h2_ngheader)
-                 + (ctx.nvlen * sizeof(nghttp2_nv)) + ctx.nvstrlen); 
-    h = apr_pcalloc(pool, n);
-    if (h) {
-        ctx.nv = (nghttp2_nv*)(h + 1);
-        ctx.strbuf = (char*)&ctx.nv[ctx.nvlen];
-        
-        NV_ADD_LIT_CS(&ctx, ":status", status);
-        apr_table_do(add_header, &ctx, header, NULL);
-        
-        h->nv    = ctx.nv;
-        h->nvlen = ctx.nvlen;
-        
-        to->ngheader = h;
-        to->pushes = ctx.pushes;
-    }
-}
-
-int h2_response_push_count(h2_response *response)
-{
-    return response->pushes? response->pushes->nelts : 0;
-}
-
-h2_push *h2_response_get_push(h2_response *response, size_t i)
-{
-    if (response->pushes && i < response->pushes->nelts) {
-        return APR_ARRAY_IDX(response->pushes, i, h2_push*);
-    }
-    return NULL;
-}
-
 

Modified: httpd/httpd/trunk/modules/http2/h2_response.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_response.h?rev=1714219&r1=1714218&r2=1714219&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_response.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_response.h Fri Nov 13 14:54:15 2015
@@ -18,24 +18,12 @@
 
 struct h2_push;
 
-/* h2_response is just the data belonging the the head of a HTTP response,
- * suitable prepared to be fed to nghttp2 for response submit. 
- */
-typedef struct h2_ngheader {
-    nghttp2_nv *nv;
-    apr_size_t nvlen;
-} h2_ngheader;
-
-struct h2_push;
-
 typedef struct h2_response {
     int stream_id;
     int rst_error;
     int http_status;
     apr_off_t content_length;
-    apr_table_t *rheader;
-    h2_ngheader *ngheader;
-    apr_array_header_t *pushes;
+    apr_table_t *header;
 } h2_response;
 
 h2_response *h2_response_create(int stream_id,
@@ -51,20 +39,4 @@ void h2_response_destroy(h2_response *re
 
 h2_response *h2_response_copy(apr_pool_t *pool, h2_response *from);
 
-/**
- * Get the number of push proposals included with the response.
- * @return number of push proposals in this response
- */
-int h2_response_push_count(h2_response *response);
-
-/**
- * Get the ith h2_push contained in this response.
- * 
- * @param response the response
- * @param i the index of the push to get
- * @return the ith h2_push or NULL if out of bounds
- */
-struct h2_push *h2_response_get_push(h2_response *response, size_t i);
-
-
 #endif /* defined(__mod_h2__h2_response__) */

Modified: httpd/httpd/trunk/modules/http2/h2_session.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_session.c?rev=1714219&r1=1714218&r2=1714219&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_session.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_session.c Fri Nov 13 14:54:15 2015
@@ -30,6 +30,7 @@
 #include "h2_h2.h"
 #include "h2_mplx.h"
 #include "h2_push.h"
+#include "h2_request.h"
 #include "h2_response.h"
 #include "h2_stream.h"
 #include "h2_stream_set.h"
@@ -80,10 +81,6 @@ h2_stream *h2_session_open_stream(h2_ses
         session->max_stream_received = stream->id;
     }
     
-    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
-                  "h2_session: stream(%ld-%d): opened",
-                  session->id, stream_id);
-    
     return stream;
 }
 
@@ -305,7 +302,7 @@ static int on_frame_not_send_cb(nghttp2_
     return 0;
 }
 
-static apr_status_t stream_destroy(h2_session *session, 
+static apr_status_t stream_release(h2_session *session, 
                                    h2_stream *stream,
                                    uint32_t error_code) 
 {
@@ -342,12 +339,12 @@ static int on_stream_close_cb(nghttp2_se
     }
     stream = h2_session_get_stream(session, stream_id);
     if (stream) {
-        stream_destroy(session, stream, error_code);
+        stream_release(session, stream, error_code);
     }
     
     if (error_code) {
         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
-                      "h2_stream(%ld-%d): close error %d",
+                      "h2_stream(%ld-%d): closed, error=%d",
                       session->id, (int)stream_id, error_code);
     }
     
@@ -1121,24 +1118,40 @@ static apr_status_t submit_response(h2_s
     if (stream->submitted) {
         rv = NGHTTP2_PROTOCOL_ERROR;
     }
-    else if (stream->response && stream->response->ngheader) {
+    else if (stream->response && stream->response->header) {
         nghttp2_data_provider provider;
         h2_response *response = stream->response;
+        h2_ngheader *ngh;
         
         memset(&provider, 0, sizeof(provider));
         provider.source.fd = stream->id;
         provider.read_callback = stream_data_cb;
         
-        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, session->c,
-                      "h2_stream(%ld-%d): submitting response %d",
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
+                      "h2_stream(%ld-%d): submit response %d",
                       session->id, stream->id, response->http_status);
         
+        ngh = h2_util_ngheader_make_res(stream->pool, response->http_status, 
+                                        response->header);
         rv = nghttp2_submit_response(session->ngh2, response->stream_id,
-                                     response->ngheader->nv, 
-                                     response->ngheader->nvlen, &provider);
-                                     
+                                     ngh->nv, ngh->nvlen, &provider);
+        
+        /* If the submit worked,
+         * and this stream is not a pushed one itself,
+         * and HTTP/2 server push is enabled here,
+         * and the response is in the range 200-299 *),
+         * and the remote side has pushing enabled,
+         * -> find and perform any pushes on this stream
+         * 
+         * *) the response code is relevant, as we do not want to 
+         *    make pushes on 401 or 403 codes, neiterh on 301/302
+         *    and friends. And if we see a 304, we do not push either
+         *    as the client, having this resource in its cache, might
+         *    also have the pushed ones as well.
+         */
         if (!rv 
-            && !stream->promised_on
+            && !stream->initiated_on
+            && h2_config_geti(h2_config_get(session->c), H2_CONF_PUSH)
             && H2_HTTP_2XX(response->http_status)
             && h2_session_push_enabled(session)) {
             
@@ -1148,7 +1161,7 @@ static apr_status_t submit_response(h2_s
     else {
         int err = H2_STREAM_RST(stream, H2_ERR_PROTOCOL_ERROR);
         
-        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, session->c,
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
                       "h2_stream(%ld-%d): RST_STREAM, err=%d",
                       session->id, stream->id, err);
 
@@ -1169,15 +1182,18 @@ static apr_status_t submit_response(h2_s
     return status;
 }
 
-struct h2_stream *h2_session_push(h2_session *session, h2_push *push)
+struct h2_stream *h2_session_push(h2_session *session, h2_stream *is,
+                                  h2_push *push)
 {
     apr_status_t status;
     h2_stream *stream;
+    h2_ngheader *ngh;
     int nid;
     
+    ngh = h2_util_ngheader_make_req(is->pool, push->req);
     nid = nghttp2_submit_push_promise(session->ngh2, 0, push->initiating_id, 
-                                      push->promise->nv, push->promise->nvlen, 
-                                      NULL);
+                                      ngh->nv, ngh->nvlen, NULL);
+                                      
     if (nid <= 0) {
         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
                       "h2_stream(%ld-%d): submitting push promise fail: %s",
@@ -1186,16 +1202,17 @@ struct h2_stream *h2_session_push(h2_ses
         return NULL;
     }
     
-    ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, session->c,
-                  "h2_stream(%ld-%d): promised new stream %d",
-                  session->id, push->initiating_id, nid);
+    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
+                  "h2_stream(%ld-%d): promised new stream %d for %s %s",
+                  session->id, push->initiating_id, nid,
+                  push->req->method, push->req->path);
                   
     stream = h2_session_open_stream(session, nid);
     if (stream) {
-        h2_stream_set_h2_request(stream, push->req);
+        h2_stream_set_h2_request(stream, is->id, push->req);
         status = stream_end_headers(session, stream, 1);
         if (status != APR_SUCCESS) {
-            ap_log_cerror(APLOG_MARK, APLOG_WARNING, status, session->c,
+            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, session->c,
                           "h2_stream(%ld-%d): scheduling push stream",
                           session->id, stream->id);
             h2_stream_cleanup(stream);
@@ -1203,7 +1220,7 @@ struct h2_stream *h2_session_push(h2_ses
         }
     }
     else {
-        ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, session->c,
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
                       "h2_stream(%ld-%d): failed to create stream obj %d",
                       session->id, push->initiating_id, nid);
     }

Modified: httpd/httpd/trunk/modules/http2/h2_session.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_session.h?rev=1714219&r1=1714218&r2=1714219&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_session.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_session.h Fri Nov 13 14:54:15 2015
@@ -189,10 +189,11 @@ apr_status_t h2_session_stream_destroy(h
  * processing..
  * 
  * @param session the session to work in
- * @param stream the stream on which the push depends
+ * @param is the stream initiating the push
  * @param push the push to promise
  * @return the new promised stream or NULL
  */
-struct h2_stream *h2_session_push(h2_session *session, struct h2_push *push);
+struct h2_stream *h2_session_push(h2_session *session, 
+                                  struct h2_stream *is, struct h2_push *push);
 
 #endif /* defined(__mod_h2__h2_session__) */

Modified: httpd/httpd/trunk/modules/http2/h2_stream.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_stream.c?rev=1714219&r1=1714218&r2=1714219&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_stream.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_stream.c Fri Nov 13 14:54:15 2015
@@ -159,9 +159,6 @@ h2_stream *h2_stream_open(int id, apr_po
 apr_status_t h2_stream_destroy(h2_stream *stream)
 {
     AP_DEBUG_ASSERT(stream);
-    
-    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, stream->session->c,
-                  "h2_stream(%ld-%d): destroy", stream->session->id, stream->id);
     if (stream->request) {
         h2_request_destroy(stream->request);
         stream->request = NULL;
@@ -237,9 +234,12 @@ apr_status_t h2_stream_set_request(h2_st
     return status;
 }
 
-void h2_stream_set_h2_request(h2_stream *stream, const h2_request *req)
+void h2_stream_set_h2_request(h2_stream *stream, int initiated_on,
+                              const h2_request *req)
 {
     h2_request_copy(stream->pool, stream->request, req);
+    stream->initiated_on = initiated_on;
+    stream->request->eoh = 0;
 }
 
 apr_status_t h2_stream_add_header(h2_stream *stream,
@@ -286,10 +286,10 @@ apr_status_t h2_stream_schedule(h2_strea
     }
     
     ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, stream->session->c,
-                  "h2_mplx(%ld-%d): start stream, task %s %s (%s)",
+                  "h2_stream(%ld-%d): scheduled %s %s://%s%s",
                   stream->session->id, stream->id,
-                  stream->request->method, stream->request->path,
-                  stream->request->authority);
+                  stream->request->method, stream->request->scheme,
+                  stream->request->authority, stream->request->path);
     
     return status;
 }
@@ -545,9 +545,12 @@ apr_status_t h2_stream_submit_pushes(h2_
     
     pushes = h2_push_collect(stream->pool, stream->request, stream->response);
     if (pushes && !apr_is_empty_array(pushes)) {
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, stream->session->c,
+                      "h2_stream(%ld-%d): found %d push candidates",
+                      stream->session->id, stream->id, pushes->nelts);
         for (i = 0; i < pushes->nelts; ++i) {
             h2_push *push = APR_ARRAY_IDX(pushes, i, h2_push*);
-            h2_stream *s = h2_session_push(stream->session, push);
+            h2_stream *s = h2_session_push(stream->session, stream, push);
             if (!s) {
                 status = APR_ECONNRESET;
                 break;

Modified: httpd/httpd/trunk/modules/http2/h2_stream.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_stream.h?rev=1714219&r1=1714218&r2=1714219&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_stream.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_stream.h Fri Nov 13 14:54:15 2015
@@ -50,7 +50,7 @@ typedef struct h2_stream h2_stream;
 
 struct h2_stream {
     int id;                     /* http2 stream id */
-    int promised_on;            /* http2 stream this was a promise on, or 0 */
+    int initiated_on;           /* http2 stream id this was initiated on or 0 */
     h2_stream_state_t state;    /* http/2 state of this stream */
     struct h2_session *session; /* the session this stream belongs to */
     
@@ -131,7 +131,8 @@ apr_status_t h2_stream_set_request(h2_st
  * @param stream the stream to init the request for
  * @param req the request for initializing, will be copied
  */
-void h2_stream_set_h2_request(h2_stream *stream, const struct h2_request *req);
+void h2_stream_set_h2_request(h2_stream *stream, int initiated_on,
+                              const struct h2_request *req);
 
 /*
  * Add a HTTP/2 header (including pseudo headers) to the given stream.

Modified: httpd/httpd/trunk/modules/http2/h2_task_input.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_task_input.c?rev=1714219&r1=1714218&r2=1714219&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_task_input.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_task_input.c Fri Nov 13 14:54:15 2015
@@ -71,21 +71,6 @@ h2_task_input *h2_task_input_create(h2_t
             /* We do not serialize and have eos already, no need to
              * create a bucket brigade. */
         }
-        
-        if (APLOGcdebug(task->c)) {
-            char buffer[1024];
-            apr_size_t len = sizeof(buffer)-1;
-            if (input->bb) {
-                apr_brigade_flatten(input->bb, buffer, &len);
-            }
-            else {
-                len = 0;
-            }
-            buffer[len] = 0;
-            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, task->c,
-                          "h2_task_input(%s): request is: %s", 
-                          task->id, buffer);
-        }
     }
     return input;
 }
@@ -105,21 +90,20 @@ apr_status_t h2_task_input_read(h2_task_
     apr_status_t status = APR_SUCCESS;
     apr_off_t bblen = 0;
     
-    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, f->c,
+    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
                   "h2_task_input(%s): read, block=%d, mode=%d, readbytes=%ld", 
                   input->task->id, block, mode, (long)readbytes);
     
+    if (mode == AP_MODE_INIT) {
+        return ap_get_brigade(f->c->input_filters, bb, mode, block, readbytes);
+    }
+    
     if (is_aborted(f)) {
         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
-                      "h2_task_input(%s): is aborted", 
-                      input->task->id);
+                      "h2_task_input(%s): is aborted", input->task->id);
         return APR_ECONNABORTED;
     }
     
-    if (mode == AP_MODE_INIT) {
-        return ap_get_brigade(f->c->input_filters, bb, mode, block, readbytes);
-    }
-    
     if (input->bb) {
         status = apr_brigade_length(input->bb, 1, &bblen);
         if (status != APR_SUCCESS) {

Modified: httpd/httpd/trunk/modules/http2/h2_util.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_util.c?rev=1714219&r1=1714218&r2=1714219&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_util.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_util.c Fri Nov 13 14:54:15 2015
@@ -25,6 +25,7 @@
 #include <nghttp2/nghttp2.h>
 
 #include "h2_private.h"
+#include "h2_request.h"
 #include "h2_util.h"
 
 size_t h2_util_hex_dump(char *buffer, size_t maxlen,
@@ -205,6 +206,10 @@ const char *h2_util_first_token_match(ap
     return NULL;
 }
 
+/*******************************************************************************
+ * h2_util for bucket brigades
+ ******************************************************************************/
+
 /* DEEP_COPY==0 crashes under load. I think the setaside is fine, 
  * however buckets moved to another thread will still be
  * free'd against the old bucket_alloc. *And* if the old
@@ -789,3 +794,91 @@ apr_status_t h2_transfer_brigade(apr_buc
     return APR_SUCCESS;
 }
 
+/*******************************************************************************
+ * h2_ngheader
+ ******************************************************************************/
+ 
+int h2_util_ignore_header(const char *name) 
+{
+    /* never forward, ch. 8.1.2.2 */
+    return (H2_HD_MATCH_LIT_CS("connection", name)
+            || H2_HD_MATCH_LIT_CS("proxy-connection", name)
+            || H2_HD_MATCH_LIT_CS("upgrade", name)
+            || H2_HD_MATCH_LIT_CS("keep-alive", name)
+            || H2_HD_MATCH_LIT_CS("transfer-encoding", name));
+}
+
+static int count_header(void *ctx, const char *key, const char *value)
+{
+    if (!h2_util_ignore_header(key)) {
+        (*((size_t*)ctx))++;
+    }
+    return 1;
+}
+
+#define NV_ADD_LIT_CS(nv, k, v)     add_header(nv, k, sizeof(k) - 1, v, strlen(v))
+#define NV_ADD_CS_CS(nv, k, v)      add_header(nv, k, strlen(k), v, strlen(v))
+
+static int add_header(h2_ngheader *ngh, 
+                      const char *key, size_t key_len,
+                      const char *value, size_t val_len)
+{
+    nghttp2_nv *nv = &ngh->nv[ngh->nvlen++];
+    
+    nv->name = (uint8_t*)key;
+    nv->namelen = key_len;
+    nv->value = (uint8_t*)value;
+    nv->valuelen = val_len;
+    return 1;
+}
+
+static int add_table_header(void *ctx, const char *key, const char *value)
+{
+    if (!h2_util_ignore_header(key)) {
+        add_header(ctx, key, strlen(key), value, strlen(value));
+    }
+    return 1;
+}
+
+
+h2_ngheader *h2_util_ngheader_make_res(apr_pool_t *p, 
+                                       int http_status, 
+                                       apr_table_t *header)
+{
+    h2_ngheader *ngh;
+    size_t n;
+    
+    n = 1;
+    apr_table_do(count_header, &n, header, NULL);
+    
+    ngh = apr_pcalloc(p, sizeof(h2_ngheader));
+    ngh->nv =  apr_pcalloc(p, n * sizeof(nghttp2_nv));
+    NV_ADD_LIT_CS(ngh, ":status", apr_psprintf(p, "%d", http_status));
+    apr_table_do(add_table_header, ngh, header, NULL);
+
+    return ngh;
+}
+
+h2_ngheader *h2_util_ngheader_make_req(apr_pool_t *p, 
+                                       const struct h2_request *req)
+{
+    
+    h2_ngheader *ngh;
+    size_t n;
+    
+    AP_DEBUG_ASSERT(req);
+
+    n = 4;
+    apr_table_do(count_header, &n, req->headers, NULL);
+    
+    ngh = apr_pcalloc(p, sizeof(h2_ngheader));
+    ngh->nv =  apr_pcalloc(p, n * sizeof(nghttp2_nv));
+    NV_ADD_LIT_CS(ngh, ":scheme", req->scheme);
+    NV_ADD_LIT_CS(ngh, ":authority", req->authority);
+    NV_ADD_LIT_CS(ngh, ":path", req->path);
+    NV_ADD_LIT_CS(ngh, ":method", req->method);
+    apr_table_do(add_table_header, ngh, req->headers, NULL);
+
+    return ngh;
+}
+

Modified: httpd/httpd/trunk/modules/http2/h2_util.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_util.h?rev=1714219&r1=1714218&r2=1714219&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_util.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_util.h Fri Nov 13 14:54:15 2015
@@ -16,6 +16,7 @@
 #ifndef __mod_h2__h2_util__
 #define __mod_h2__h2_util__
 
+struct h2_request;
 struct nghttp2_frame;
 
 size_t h2_util_hex_dump(char *buffer, size_t maxlen,
@@ -67,6 +68,19 @@ apr_size_t h2_util_base64url_decode(cons
                                             nv->value = (uint8_t *)VALUE;     \
                                             nv->valuelen = strlen(VALUE)
 
+int h2_util_ignore_header(const char *name);
+
+typedef struct h2_ngheader {
+    nghttp2_nv *nv;
+    apr_size_t nvlen;
+} h2_ngheader;
+
+h2_ngheader *h2_util_ngheader_make_res(apr_pool_t *p, 
+                                       int http_status, 
+                                       apr_table_t *header);
+h2_ngheader *h2_util_ngheader_make_req(apr_pool_t *p, 
+                                       const struct h2_request *req);
+
 /**
  * Moves data from one brigade into another. If maxlen > 0, it only
  * moves up to maxlen bytes into the target brigade, making bucket splits

Modified: httpd/httpd/trunk/modules/http2/h2_workers.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_workers.c?rev=1714219&r1=1714218&r2=1714219&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_workers.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_workers.c Fri Nov 13 14:54:15 2015
@@ -174,7 +174,7 @@ static apr_status_t get_mplx_next(h2_wor
          * needed to give up with more than enough workers.
          */
         if (task) {
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, workers->s,
+            ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, workers->s,
                          "h2_worker(%d): start task(%s)",
                          h2_worker_get_id(worker), task->id);
             /* Since we hand out a reference to the worker, we increase
@@ -326,7 +326,7 @@ apr_status_t h2_workers_register(h2_work
 {
     apr_status_t status = apr_thread_mutex_lock(workers->lock);
     if (status == APR_SUCCESS) {
-        ap_log_error(APLOG_MARK, APLOG_DEBUG, status, workers->s,
+        ap_log_error(APLOG_MARK, APLOG_TRACE2, status, workers->s,
                      "h2_workers: register mplx(%ld)", m->id);
         if (in_list(workers, m)) {
             status = APR_EAGAIN;



Mime
View raw message