Skip to content

Commit

Permalink
fixed segfault in connection shutdown, added accept-push-policy support
Browse files Browse the repository at this point in the history
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1721547 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
icing committed Dec 23, 2015
1 parent 922612b commit 93c6092
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 22 deletions.
6 changes: 6 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
93 changes: 75 additions & 18 deletions modules/http2/h2_push.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,19 @@
#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;
Expand Down Expand Up @@ -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;
Expand All @@ -283,14 +297,22 @@ 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",
"Cache-Control",
"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 */
Expand Down Expand Up @@ -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;
}
9 changes: 9 additions & 0 deletions modules/http2/h2_push.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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__) */
3 changes: 2 additions & 1 deletion modules/http2/h2_request.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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");
Expand Down
3 changes: 1 addition & 2 deletions modules/http2/h2_request.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down
3 changes: 2 additions & 1 deletion modules/http2/mod_http2.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit 93c6092

Please sign in to comment.