]> granicus.if.org Git - apache/commitdiff
fixed segfault in connection shutdown, added accept-push-policy support
authorStefan Eissing <icing@apache.org>
Wed, 23 Dec 2015 14:50:54 +0000 (14:50 +0000)
committerStefan Eissing <icing@apache.org>
Wed, 23 Dec 2015 14:50:54 +0000 (14:50 +0000)
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1721547 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
modules/http2/h2_push.c
modules/http2/h2_push.h
modules/http2/h2_request.c
modules/http2/h2_request.h
modules/http2/mod_http2.c

diff --git a/CHANGES b/CHANGES
index c0323386f1e8e67227450466e9c1486f5bf09c15..e6846a0f57d78623eeaf27053e5488df22a0aa38 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,12 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.0
 
+  *) mod_http2: Fixed segfault on connection shutdown, callback ran into a semi
+     dismantled session. Added support for experimental accept-push-policy draft
+     (https://tools.ietf.org/html/draft-ruellan-http-accept-push-policy-00). Clients
+     may now influence server pushes by sending accept-push-policy headers.
+     [Stefan Eissing]
+
   *) mod_http2: On async MPMs (event), idle HTTP/2 connections will enter KEEPALIVE
      state and become eligible for MPM cleanup under load. Rewrote connection
      state handling. Defaults for H2KeepAliveTimeout shortened. Cleaned up logging.
index 9997c5769c55c1be121b8c3204b3432b51b8b8d3..1ba4ea6fb85e31a2952992a352bbd32eabb3b53d 100644 (file)
 #include "h2_request.h"
 #include "h2_response.h"
 
+static const char *policy_str(h2_push_policy policy)
+{
+    switch (policy) {
+        case H2_PUSH_NONE:
+            return "none";
+        case H2_PUSH_FAST_LOAD:
+            return "fast-load";
+        case H2_PUSH_HEAD:
+            return "head";
+        default:
+            return "default";
+    }
+}
 
 typedef struct {
     const h2_request *req;
@@ -269,6 +282,7 @@ static int add_push(link_ctx *ctx)
         if (apr_uri_parse(ctx->pool, ctx->link, &uri) == APR_SUCCESS) {
             if (uri.path && same_authority(ctx->req, &uri)) {
                 char *path;
+                const char *method;
                 apr_table_t *headers;
                 h2_request *req;
                 h2_push *push;
@@ -283,6 +297,14 @@ static int add_push(link_ctx *ctx)
                 
                 push = apr_pcalloc(ctx->pool, sizeof(*push));
                 
+                switch (ctx->req->push_policy) {
+                    case H2_PUSH_HEAD:
+                        method = "HEAD";
+                        break;
+                    default:
+                        method = "GET";
+                        break;
+                }
                 headers = apr_table_make(ctx->pool, 5);
                 apr_table_do(set_header, headers, ctx->req->headers,
                              "User-Agent",
@@ -290,7 +312,7 @@ static int add_push(link_ctx *ctx)
                              "Accept-Language",
                              NULL);
                 req = h2_request_createn(0, ctx->pool, ctx->req->config, 
-                                         "GET", ctx->req->scheme,
+                                         method, ctx->req->scheme,
                                          ctx->req->authority, 
                                          path, headers);
                 /* atm, we do not push on pushes */
@@ -374,23 +396,58 @@ static int head_iter(void *ctx, const char *key, const char *value)
 apr_array_header_t *h2_push_collect(apr_pool_t *p, const h2_request *req, 
                                     const h2_response *res)
 {
-    /* Collect push candidates from the request/response pair.
-     * 
-     * One source for pushes are "rel=preload" link headers
-     * in the response.
-     * 
-     * TODO: This may be extended in the future by hooks or callbacks
-     * where other modules can provide push information directly.
-     */
-    if (res->headers) {
-        link_ctx ctx;
-        
-        memset(&ctx, 0, sizeof(ctx));
-        ctx.req = req;
-        ctx.pool = p;
-    
-        apr_table_do(head_iter, &ctx, res->headers, NULL);
-        return ctx.pushes;
+    if (req && req->push_policy != H2_PUSH_NONE) {
+        /* Collect push candidates from the request/response pair.
+         * 
+         * One source for pushes are "rel=preload" link headers
+         * in the response.
+         * 
+         * TODO: This may be extended in the future by hooks or callbacks
+         * where other modules can provide push information directly.
+         */
+        if (res->headers) {
+            link_ctx ctx;
+            
+            memset(&ctx, 0, sizeof(ctx));
+            ctx.req = req;
+            ctx.pool = p;
+            
+            apr_table_do(head_iter, &ctx, res->headers, NULL);
+            if (ctx.pushes) {
+                apr_table_setn(res->headers, "push-policy", policy_str(req->push_policy));
+            }
+            return ctx.pushes;
+        }
     }
     return NULL;
 }
+
+void h2_push_policy_determine(struct h2_request *req, apr_pool_t *p, int push_enabled)
+{
+    h2_push_policy policy = H2_PUSH_NONE;
+    if (push_enabled) {
+        const char *val = apr_table_get(req->headers, "accept-push-policy");
+        if (val) {
+            if (ap_find_token(p, val, "fast-load")) {
+                policy = H2_PUSH_FAST_LOAD;
+            }
+            else if (ap_find_token(p, val, "head")) {
+                policy = H2_PUSH_HEAD;
+            }
+            else if (ap_find_token(p, val, "default")) {
+                policy = H2_PUSH_DEFAULT;
+            }
+            else if (ap_find_token(p, val, "none")) {
+                policy = H2_PUSH_NONE;
+            }
+            else {
+                /* nothing known found in this header, go by default */
+                policy = H2_PUSH_DEFAULT;
+            }
+        }
+        else {
+            policy = H2_PUSH_DEFAULT;
+        }
+    }
+    req->push_policy = policy;
+}
index 871548cee3fa13733377a48d95e2fe584d9f1bcc..f3a8601c34526e711542747f4de452df7d7aefb0 100644 (file)
@@ -19,6 +19,13 @@ struct h2_request;
 struct h2_response;
 struct h2_ngheader;
 
+typedef enum {
+    H2_PUSH_NONE,
+    H2_PUSH_DEFAULT,
+    H2_PUSH_HEAD,
+    H2_PUSH_FAST_LOAD,
+} h2_push_policy;
+
 typedef struct h2_push {
     const struct h2_request *req;
 } h2_push;
@@ -28,4 +35,6 @@ apr_array_header_t *h2_push_collect(apr_pool_t *p,
                                     const struct h2_request *req, 
                                     const struct h2_response *res);
 
+void h2_push_policy_determine(struct h2_request *req, apr_pool_t *p, int push_enabled);
+
 #endif /* defined(__mod_h2__h2_push__) */
index 04227efea545499ab891ca537117840f6f2239a0..6fafa45f1a52f94171c8461b7fe083bffe1d6a9d 100644 (file)
@@ -32,6 +32,7 @@
 #include "h2_private.h"
 #include "h2_config.h"
 #include "h2_mplx.h"
+#include "h2_push.h"
 #include "h2_request.h"
 #include "h2_task.h"
 #include "h2_util.h"
@@ -272,7 +273,7 @@ apr_status_t h2_request_end_headers(h2_request *req, apr_pool_t *pool,
     }
 
     req->eoh = 1;
-    req->push = push;
+    h2_push_policy_determine(req, pool, push);
     
     /* In the presence of trailers, force behaviour of chunked encoding */
     s = apr_table_get(req->headers, "Trailer");
index 561fed8dcf9423e7dba9aed9496817e781010896..cc01ed1238b36115c928bcf826b5962f83ad885a 100644 (file)
@@ -44,8 +44,7 @@ struct h2_request {
     unsigned int chunked : 1; /* iff requst body needs to be forwarded as chunked */
     unsigned int eoh     : 1; /* iff end-of-headers has been seen and request is complete */
     unsigned int body    : 1; /* iff this request has a body */
-    unsigned int push    : 1; /* iff server push is possible for this request */
-    
+    unsigned int push_policy; /* which push policy to use for this request */
     const struct h2_config *config;
 };
 
index 8e95e519c8fda558f53a693a9140f0cd87776de5..53a460fe3185c9d2ead31f31fafd5762a2fcfaec 100644 (file)
@@ -32,6 +32,7 @@
 #include "h2_config.h"
 #include "h2_ctx.h"
 #include "h2_h2.h"
+#include "h2_push.h"
 #include "h2_request.h"
 #include "h2_switch.h"
 #include "h2_version.h"
@@ -171,7 +172,7 @@ static char *value_of_H2PUSH(apr_pool_t *p, server_rec *s,
         ctx = h2_ctx_rget(r);
         if (ctx) {
             h2_task *task = h2_ctx_get_task(ctx);
-            return task && task->request->push? "on" : "off";
+            return (task && task->request->push_policy != H2_PUSH_NONE)? "on" : "off";
         }
     }
     else if (c) {