update to mod_http2 1.0.7-DEV

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4-http2-alpha@1716203 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/modules/http2/config.m4 b/modules/http2/config.m4
index f383b3c..e10bb81 100644
--- a/modules/http2/config.m4
+++ b/modules/http2/config.m4
@@ -154,6 +154,8 @@
       if test "x$liberrors" != "x"; then
         AC_MSG_WARN([nghttp2 library is unusable])
       fi
+      AC_CHECK_FUNCS([nghttp2_session_change_stream_priority], 
+        [APR_ADDTO(MOD_CPPFLAGS, ["-DH2_NG2_CHANGE_PRIO"])], [])
     else
       AC_MSG_WARN([nghttp2 version is too old])
     fi
diff --git a/modules/http2/h2_from_h1.c b/modules/http2/h2_from_h1.c
index dfcfb03..755b7d6 100644
--- a/modules/http2/h2_from_h1.c
+++ b/modules/http2/h2_from_h1.c
@@ -51,10 +51,6 @@
 
 apr_status_t h2_from_h1_destroy(h2_from_h1 *from_h1)
 {
-    if (from_h1->response) {
-        h2_response_destroy(from_h1->response);
-        from_h1->response = NULL;
-    }
     from_h1->bb = NULL;
     return APR_SUCCESS;
 }
@@ -520,7 +516,7 @@
     if (eb) {
         int st = eb->status;
         apr_brigade_cleanup(bb);
-        ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, f->c,
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, f->c,
                       "h2_from_h1(%d): err bucket status=%d", 
                       from_h1->stream_id, st);
         ap_die(st, r);
diff --git a/modules/http2/h2_h2.h b/modules/http2/h2_h2.h
index 4974d86..563abe3 100644
--- a/modules/http2/h2_h2.h
+++ b/modules/http2/h2_h2.h
@@ -58,6 +58,17 @@
 
 #define H2_STREAM_CLIENT_INITIATED(id)      (id&0x01)
 
+typedef enum {
+    H2_DEPENDANT_AFTER,
+    H2_DEPENDANT_INTERLEAVED,
+    H2_DEPENDANT_BEFORE,
+} h2_dependency;
+
+typedef struct h2_priority {
+    h2_dependency dependency;
+    int           weight;
+} h2_priority;
+
 /**
  * Provide a user readable description of the HTTP/2 error code-
  * @param h2_error http/2 error code, as in rfc 7540, ch. 7
diff --git a/modules/http2/h2_io.c b/modules/http2/h2_io.c
index a1d9eff..6bd2b83 100644
--- a/modules/http2/h2_io.c
+++ b/modules/http2/h2_io.c
@@ -52,7 +52,7 @@
     AP_DEBUG_ASSERT(io->pool);
     AP_DEBUG_ASSERT(response);
     AP_DEBUG_ASSERT(!io->response);
-    io->response = h2_response_copy(io->pool, response);
+    io->response = h2_response_clone(io->pool, response);
     if (response->rst_error) {
         h2_io_rst(io, response->rst_error);
     }
diff --git a/modules/http2/h2_mplx.c b/modules/http2/h2_mplx.c
index 3890a5a..6f2a512 100644
--- a/modules/http2/h2_mplx.c
+++ b/modules/http2/h2_mplx.c
@@ -711,8 +711,8 @@
                      * insert an error one so that our streams can properly
                      * reset.
                      */
-                    h2_response *r = h2_response_create(stream_id, 0, 
-                                                        500, NULL, m->pool);
+                    h2_response *r = h2_response_die(stream_id, APR_EGENERAL, 
+                                                     io->request, m->pool);
                     status = out_open(m, stream_id, r, NULL, NULL, NULL);
                     ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, m->c,
                                   "h2_mplx(%ld-%d): close, no response, no rst", 
diff --git a/modules/http2/h2_push.c b/modules/http2/h2_push.c
index dd972cf..65b2b7b 100644
--- a/modules/http2/h2_push.c
+++ b/modules/http2/h2_push.c
@@ -301,6 +301,9 @@
                 h2_request_end_headers(req, ctx->pool, 1);
                 push->req = req;
                 
+                push->prio.dependency = H2_DEPENDANT_AFTER;
+                push->prio.weight = NGHTTP2_DEFAULT_WEIGHT;
+                
                 if (!ctx->pushes) {
                     ctx->pushes = apr_array_make(ctx->pool, 5, sizeof(h2_push*));
                 }
diff --git a/modules/http2/h2_push.h b/modules/http2/h2_push.h
index 64edee6..b98a2f7 100644
--- a/modules/http2/h2_push.h
+++ b/modules/http2/h2_push.h
@@ -20,9 +20,9 @@
 struct h2_ngheader;
 
 typedef struct h2_push {
-    int initiating_id;
+    int          initiating_id;
     const struct h2_request *req;
-    const char *as;
+    h2_priority  prio;
 } h2_push;
 
 
diff --git a/modules/http2/h2_request.c b/modules/http2/h2_request.c
index a5f7d9d..e1a371f 100644
--- a/modules/http2/h2_request.c
+++ b/modules/http2/h2_request.c
@@ -19,9 +19,15 @@
 
 #include <httpd.h>
 #include <http_core.h>
+#include <http_connection.h>
 #include <http_protocol.h>
-#include <http_config.h>
+#include <http_request.h>
 #include <http_log.h>
+#include <http_vhost.h>
+#include <util_filter.h>
+#include <ap_mpm.h>
+#include <mod_core.h>
+#include <scoreboard.h>
 
 #include "h2_private.h"
 #include "h2_mplx.h"
@@ -48,7 +54,8 @@
     req->authority      = authority;
     req->path           = path;
     req->headers        = header? header : apr_table_make(pool, 10);
-    
+    req->request_time   = apr_time_now();
+
     return req;
 }
 
@@ -322,3 +329,117 @@
     dst->eoh            = src->eoh;
 }
 
+request_rec *h2_request_create_rec(const h2_request *req, conn_rec *conn)
+{
+    request_rec *r;
+    apr_pool_t *p;
+    int access_status = HTTP_OK;    
+    
+    apr_pool_create(&p, conn->pool);
+    apr_pool_tag(p, "request");
+    r = apr_pcalloc(p, sizeof(request_rec));
+    AP_READ_REQUEST_ENTRY((intptr_t)r, (uintptr_t)conn);
+    r->pool            = p;
+    r->connection      = conn;
+    r->server          = conn->base_server;
+    
+    r->user            = NULL;
+    r->ap_auth_type    = NULL;
+    
+    r->allowed_methods = ap_make_method_list(p, 2);
+    
+    r->headers_in      = apr_table_copy(r->pool, req->headers);
+    r->trailers_in     = apr_table_make(r->pool, 5);
+    r->subprocess_env  = apr_table_make(r->pool, 25);
+    r->headers_out     = apr_table_make(r->pool, 12);
+    r->err_headers_out = apr_table_make(r->pool, 5);
+    r->trailers_out    = apr_table_make(r->pool, 5);
+    r->notes           = apr_table_make(r->pool, 5);
+    
+    r->request_config  = ap_create_request_config(r->pool);
+    /* Must be set before we run create request hook */
+    
+    r->proto_output_filters = conn->output_filters;
+    r->output_filters  = r->proto_output_filters;
+    r->proto_input_filters = conn->input_filters;
+    r->input_filters   = r->proto_input_filters;
+    ap_run_create_request(r);
+    r->per_dir_config  = r->server->lookup_defaults;
+    
+    r->sent_bodyct     = 0;                      /* bytect isn't for body */
+    
+    r->read_length     = 0;
+    r->read_body       = REQUEST_NO_BODY;
+    
+    r->status          = HTTP_OK;  /* Until further notice */
+    r->header_only     = 0;
+    r->the_request     = NULL;
+    
+    /* Begin by presuming any module can make its own path_info assumptions,
+     * until some module interjects and changes the value.
+     */
+    r->used_path_info = AP_REQ_DEFAULT_PATH_INFO;
+    
+    r->useragent_addr = conn->client_addr;
+    r->useragent_ip = conn->client_ip;
+    
+    ap_run_pre_read_request(r, conn);
+    
+    /* Time to populate r with the data we have. */
+    r->request_time = req->request_time;
+    r->method = req->method;
+    /* Provide quick information about the request method as soon as known */
+    r->method_number = ap_method_number_of(r->method);
+    if (r->method_number == M_GET && r->method[0] == 'H') {
+        r->header_only = 1;
+    }
+
+    ap_parse_uri(r, req->path);
+    r->protocol = (char*)"HTTP/2";
+    r->proto_num = HTTP_VERSION(2, 0);
+
+    r->the_request = apr_psprintf(r->pool, "%s %s %s", 
+                                  r->method, req->path, r->protocol);
+    
+    /* update what we think the virtual host is based on the headers we've
+     * now read. may update status.
+     * Leave r->hostname empty, vhost will parse if form our Host: header,
+     * otherwise we get complains about port numbers.
+     */
+    r->hostname = NULL;
+    ap_update_vhost_from_headers(r);
+    
+    /* we may have switched to another server */
+    r->per_dir_config = r->server->lookup_defaults;
+    
+    /*
+     * Add the HTTP_IN filter here to ensure that ap_discard_request_body
+     * called by ap_die and by ap_send_error_response works correctly on
+     * status codes that do not cause the connection to be dropped and
+     * in situations where the connection should be kept alive.
+     */
+    ap_add_input_filter_handle(ap_http_input_filter_handle,
+                               NULL, r, r->connection);
+    
+    if (access_status != HTTP_OK
+        || (access_status = ap_run_post_read_request(r))) {
+        /* Request check post hooks failed. An example of this would be a
+         * request for a vhost where h2 is disabled --> 421.
+         */
+        ap_die(access_status, r);
+        ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
+        ap_run_log_transaction(r);
+        r = NULL;
+        goto traceout;
+    }
+    
+    AP_READ_REQUEST_SUCCESS((uintptr_t)r, (char *)r->method, 
+                            (char *)r->uri, (char *)r->server->defn_name, 
+                            r->status);
+    return r;
+traceout:
+    AP_READ_REQUEST_FAILURE((uintptr_t)r);
+    return r;
+}
+
+
diff --git a/modules/http2/h2_request.h b/modules/http2/h2_request.h
index 19005a8..69d24f3 100644
--- a/modules/http2/h2_request.h
+++ b/modules/http2/h2_request.h
@@ -38,6 +38,7 @@
     apr_table_t *headers;
     apr_table_t *trailers;
 
+    apr_time_t request_time;
     apr_off_t content_length;
     int chunked;
     int eoh;
@@ -66,6 +67,15 @@
 
 void h2_request_copy(apr_pool_t *p, h2_request *dst, const h2_request *src);
 
+/**
+ * Create a request_rec representing the h2_request to be
+ * processed on the given connection.
+ *
+ * @param req the h2 request to process
+ * @param conn the connection to process the request on
+ * @return the request_rec representing the request
+ */
+request_rec *h2_request_create_rec(const h2_request *req, conn_rec *conn);
 
 
 #endif /* defined(__mod_h2__h2_request__) */
diff --git a/modules/http2/h2_response.c b/modules/http2/h2_response.c
index 505f245..d16fee2 100644
--- a/modules/http2/h2_response.c
+++ b/modules/http2/h2_response.c
@@ -21,42 +21,30 @@
 #include <httpd.h>
 #include <http_core.h>
 #include <http_log.h>
+#include <util_time.h>
 
 #include <nghttp2/nghttp2.h>
 
 #include "h2_private.h"
 #include "h2_h2.h"
 #include "h2_util.h"
+#include "h2_request.h"
 #include "h2_response.h"
 
 
-h2_response *h2_response_create(int stream_id,
-                                int rst_error,
-                                int http_status,
-                                apr_array_header_t *hlines,
-                                apr_pool_t *pool)
+static apr_table_t *parse_headers(apr_array_header_t *hlines, apr_pool_t *pool)
 {
-    apr_table_t *headers;
-    h2_response *response = apr_pcalloc(pool, sizeof(h2_response));
-    int i;
-    if (response == NULL) {
-        return NULL;
-    }
-    
-    response->stream_id = stream_id;
-    response->rst_error = rst_error;
-    response->http_status = http_status? http_status : 500;
-    response->content_length = -1;
-    
     if (hlines) {
-        headers = apr_table_make(pool, hlines->nelts);        
+        apr_table_t *headers = apr_table_make(pool, hlines->nelts);        
+        int i;
+        
         for (i = 0; i < hlines->nelts; ++i) {
             char *hline = ((char **)hlines->elts)[i];
             char *sep = ap_strchr(hline, ':');
             if (!sep) {
                 ap_log_perror(APLOG_MARK, APLOG_WARNING, APR_EINVAL, pool,
-                              APLOGNO(02955) "h2_response(%d): invalid header[%d] '%s'",
-                              response->stream_id, i, (char*)hline);
+                              APLOGNO(02955) "h2_response: invalid header[%d] '%s'",
+                              i, (char*)hline);
                 /* not valid format, abort */
                 return NULL;
             }
@@ -67,29 +55,66 @@
             
             if (!h2_util_ignore_header(hline)) {
                 apr_table_merge(headers, hline, sep);
-                if (*sep && H2_HD_MATCH_LIT_CS("content-length", hline)) {
-                    char *end;
-                    response->content_length = apr_strtoi64(sep, &end, 10);
-                    if (sep == end) {
-                        ap_log_perror(APLOG_MARK, APLOG_WARNING, APR_EINVAL, 
-                                      pool, APLOGNO(02956) 
-                                      "h2_response(%d): content-length"
-                                      " value not parsed: %s", 
-                                      response->stream_id, sep);
-                        response->content_length = -1;
-                    }
-                }
             }
         }
+        return headers;
     }
     else {
-        headers = apr_table_make(pool, 0);        
+        return apr_table_make(pool, 0);        
     }
+}
 
+static h2_response *h2_response_create_int(int stream_id,
+                                           int rst_error,
+                                           int http_status,
+                                           apr_table_t *headers,
+                                           apr_pool_t *pool)
+{
+    h2_response *response;
+    const char *s;
+
+    if (!headers) {
+        return NULL;
+    }
+    
+    response = apr_pcalloc(pool, sizeof(h2_response));
+    if (response == NULL) {
+        return NULL;
+    }
+    
+    response->stream_id = stream_id;
+    response->rst_error = rst_error;
+    response->http_status = http_status? http_status : 500;
+    response->content_length = -1;
     response->headers = headers;
+    
+    s = apr_table_get(headers, "Content-Length");
+    if (s) {
+        char *end;
+        
+        response->content_length = apr_strtoi64(s, &end, 10);
+        if (s == end) {
+            ap_log_perror(APLOG_MARK, APLOG_WARNING, APR_EINVAL, 
+                          pool, APLOGNO(02956) 
+                          "h2_response: content-length"
+                          " value not parsed: %s", s);
+            response->content_length = -1;
+        }
+    }
     return response;
 }
 
+
+h2_response *h2_response_create(int stream_id,
+                                int rst_error,
+                                int http_status,
+                                apr_array_header_t *hlines,
+                                apr_pool_t *pool)
+{
+    return h2_response_create_int(stream_id, rst_error, http_status,
+                                  parse_headers(hlines, pool), pool);
+}
+
 h2_response *h2_response_rcreate(int stream_id, request_rec *r,
                                  apr_table_t *header, apr_pool_t *pool)
 {
@@ -119,12 +144,21 @@
     return response;
 }
 
-void h2_response_destroy(h2_response *response)
+h2_response *h2_response_die(int stream_id, apr_status_t type,
+                             const struct h2_request *req, apr_pool_t *pool)
 {
-    (void)response;
+    apr_table_t *headers = apr_table_make(pool, 5);
+    char *date = NULL;
+    
+    date = apr_palloc(pool, APR_RFC822_DATE_LEN);
+    ap_recent_rfc822_date(date, req->request_time);
+    apr_table_setn(headers, "Date", date);
+    apr_table_setn(headers, "Server", ap_get_server_banner());
+    
+    return h2_response_create_int(stream_id, 0, 500, headers, pool);
 }
 
-h2_response *h2_response_copy(apr_pool_t *pool, h2_response *from)
+h2_response *h2_response_clone(apr_pool_t *pool, h2_response *from)
 {
     h2_response *to = apr_pcalloc(pool, sizeof(h2_response));
     to->stream_id = from->stream_id;
diff --git a/modules/http2/h2_response.h b/modules/http2/h2_response.h
index 518ef2e..426eeea 100644
--- a/modules/http2/h2_response.h
+++ b/modules/http2/h2_response.h
@@ -16,6 +16,7 @@
 #ifndef __mod_h2__h2_response__
 #define __mod_h2__h2_response__
 
+struct h2_request;
 struct h2_push;
 
 typedef struct h2_response {
@@ -27,18 +28,47 @@
     apr_table_t *trailers;
 } h2_response;
 
+/**
+ * Create the response from the status and parsed header lines.
+ * @param stream_id id of the stream to create the response for
+ * @param rst_error error for reset or 0
+ * @param http_status  http status code of response
+ * @param hlines the text lines of the response header
+ * @param pool the memory pool to use
+ */
 h2_response *h2_response_create(int stream_id,
                                 int rst_error,
                                 int http_status,
                                 apr_array_header_t *hlines,
                                 apr_pool_t *pool);
 
+/**
+ * Create the response from the given request_rec.
+ * @param stream_id id of the stream to create the response for
+ * @param r the request record which was processed
+ * @param header the headers of the response
+ * @param pool the memory pool to use
+ */
 h2_response *h2_response_rcreate(int stream_id, request_rec *r,
                                  apr_table_t *header, apr_pool_t *pool);
 
-void h2_response_destroy(h2_response *response);
+/**
+ * Create the response for the given error.
+ * @param stream_id id of the stream to create the response for
+ * @param type the error code
+ * @param req the original h2_request
+ * @param pool the memory pool to use
+ */
+h2_response *h2_response_die(int stream_id, apr_status_t type,
+                             const struct h2_request *req, apr_pool_t *pool);
 
-h2_response *h2_response_copy(apr_pool_t *pool, h2_response *from);
+/**
+ * Deep copies the response into a new pool.
+ * @param pool the pool to use for the clone
+ * @param from the response to clone
+ * @return the cloned response
+ */
+h2_response *h2_response_clone(apr_pool_t *pool, h2_response *from);
 
 /**
  * Set the trailers in the reponse. Will replace any existing trailers. Will
diff --git a/modules/http2/h2_session.c b/modules/http2/h2_session.c
index 720a1eb..73cdac9 100644
--- a/modules/http2/h2_session.c
+++ b/modules/http2/h2_session.c
@@ -14,6 +14,7 @@
  */
 
 #include <assert.h>
+#include <math.h>
 #include <apr_thread_cond.h>
 #include <apr_base64.h>
 #include <apr_strings.h>
@@ -1166,6 +1167,7 @@
         nghttp2_data_provider provider;
         h2_response *response = stream->response;
         h2_ngheader *ngh;
+        h2_priority *prio;
         
         memset(&provider, 0, sizeof(provider));
         provider.source.fd = stream->id;
@@ -1175,6 +1177,12 @@
                       "h2_stream(%ld-%d): submit response %d",
                       session->id, stream->id, response->http_status);
         
+        prio = h2_stream_get_priority(stream);
+        if (prio) {
+            h2_session_set_prio(session, stream, prio);
+            /* no showstopper if that fails for some reason */
+        }
+        
         ngh = h2_util_ngheader_make_res(stream->pool, response->http_status, 
                                         response->headers);
         rv = nghttp2_submit_response(session->ngh2, response->stream_id,
@@ -1254,6 +1262,7 @@
     stream = h2_session_open_stream(session, nid);
     if (stream) {
         h2_stream_set_h2_request(stream, is->id, push->req);
+        h2_stream_set_priority(stream, &push->prio);
         status = stream_schedule(session, stream, 1);
         if (status != APR_SUCCESS) {
             ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, session->c,
@@ -1278,6 +1287,108 @@
     return stream;
 }
 
+static int valid_weight(float f) 
+{
+    int w = floor(f);
+    return (w < NGHTTP2_MIN_WEIGHT? NGHTTP2_MIN_WEIGHT : 
+            (w > NGHTTP2_MAX_WEIGHT)? NGHTTP2_MAX_WEIGHT : w);
+}
+
+apr_status_t h2_session_set_prio(h2_session *session, h2_stream *stream, 
+                                 h2_priority *prio)
+{
+    apr_status_t status = APR_SUCCESS;
+#ifdef H2_NG2_CHANGE_PRIO
+    nghttp2_stream *s_grandpa, *s_parent, *s;
+    
+    s = nghttp2_session_find_stream(session->ngh2, stream->id);
+    if (!s) {
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
+                      "h2_stream(%ld-%d): lookup of nghttp2_stream failed",
+                      session->id, stream->id);
+        return APR_EINVAL;
+    }
+    
+    s_parent = nghttp2_stream_get_parent(s);
+    if (s_parent) {
+        nghttp2_priority_spec ps;
+        int id_parent, id_grandpa, w_parent, w, rv = 0;
+        char *ptype = "AFTER";
+        h2_dependency dep = prio->dependency;
+        
+        id_parent = nghttp2_stream_get_stream_id(s_parent);
+        s_grandpa = nghttp2_stream_get_parent(s_parent);
+        if (s_grandpa) {
+            id_grandpa = nghttp2_stream_get_stream_id(s_grandpa);
+        }
+        else {
+            /* parent of parent does not exist, 
+             * only possible if parent == root */
+            dep = H2_DEPENDANT_AFTER;
+        }
+        
+        switch (dep) {
+            case H2_DEPENDANT_INTERLEAVED:
+                /* PUSHed stream is to be interleaved with initiating stream.
+                 * It is made a sibling of the initiating stream and gets a
+                 * proportional weight [1, MAX_WEIGHT] of the initiaing
+                 * stream weight.
+                 */
+                ptype = "INTERLEAVED";
+                w_parent = nghttp2_stream_get_weight(s_parent);
+                w = valid_weight(w_parent * ((float)NGHTTP2_MAX_WEIGHT / prio->weight));
+                nghttp2_priority_spec_init(&ps, id_grandpa, w, 0);
+                break;
+                
+            case H2_DEPENDANT_BEFORE:
+                /* PUSHed stream os to be sent BEFORE the initiating stream.
+                 * It gets the same weight as the initiating stream, replaces
+                 * that stream in the dependency tree and has the initiating
+                 * stream as child with MAX_WEIGHT.
+                 */
+                ptype = "BEFORE";
+                nghttp2_priority_spec_init(&ps, stream->id, NGHTTP2_MAX_WEIGHT, 0);
+                rv = nghttp2_session_change_stream_priority(session->ngh2, id_parent, &ps);
+                if (rv < 0) {
+                    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
+                                  "h2_stream(%ld-%d): PUSH BEFORE2, weight=%d, "
+                                  "depends=%d, returned=%d",
+                                  session->id, id_parent, ps.weight, ps.stream_id, rv);
+                    return APR_EGENERAL;
+                }
+                id_grandpa = nghttp2_stream_get_stream_id(s_grandpa);
+                w_parent = nghttp2_stream_get_weight(s_parent);
+                nghttp2_priority_spec_init(&ps, id_grandpa, valid_weight(w_parent), 0);
+                break;
+                
+            case H2_DEPENDANT_AFTER:
+                /* The PUSHed stream is to be sent after the initiating stream.
+                 * Give if the specified weight and let it depend on the intiating
+                 * stream.
+                 */
+                /* fall through, it's the default */
+            default:
+                nghttp2_priority_spec_init(&ps, id_parent, valid_weight(prio->weight), 0);
+                break;
+        }
+
+
+        rv = nghttp2_session_change_stream_priority(session->ngh2, stream->id, &ps);
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
+                      "h2_stream(%ld-%d): PUSH %s, weight=%d, "
+                      "depends=%d, returned=%d",
+                      session->id, stream->id, ptype, 
+                      ps.weight, ps.stream_id, rv);
+        status = (rv < 0)? APR_EGENERAL : APR_SUCCESS;
+    }
+#else
+    (void)session;
+    (void)stream;
+    (void)prio;
+#endif
+    return status;
+}
+
 apr_status_t h2_session_stream_destroy(h2_session *session, h2_stream *stream)
 {
     apr_pool_t *pool = h2_stream_detach_pool(stream);
diff --git a/modules/http2/h2_session.h b/modules/http2/h2_session.h
index 5c3be0a..16767fb 100644
--- a/modules/http2/h2_session.h
+++ b/modules/http2/h2_session.h
@@ -41,6 +41,7 @@
 struct apr_thread_cond_t;
 struct h2_config;
 struct h2_mplx;
+struct h2_priority;
 struct h2_push;
 struct h2_response;
 struct h2_session;
@@ -195,4 +196,9 @@
 struct h2_stream *h2_session_push(h2_session *session, 
                                   struct h2_stream *is, struct h2_push *push);
 
+apr_status_t h2_session_set_prio(h2_session *session, 
+                                 struct h2_stream *stream, 
+                                 struct h2_priority *prio);
+
+
 #endif /* defined(__mod_h2__h2_session__) */
diff --git a/modules/http2/h2_stream.c b/modules/http2/h2_stream.c
index a091e42..c9f88a2 100644
--- a/modules/http2/h2_stream.c
+++ b/modules/http2/h2_stream.c
@@ -668,3 +668,15 @@
 {
     return stream->response? stream->response->trailers : NULL;
 }
+
+void h2_stream_set_priority(h2_stream *stream, h2_priority *prio)
+{
+    stream->prio = apr_pcalloc(stream->pool, sizeof(*prio));
+    memcpy(stream->prio, prio, sizeof(*prio));
+}
+
+h2_priority *h2_stream_get_priority(h2_stream *stream)
+{
+    return stream->prio;
+}
+
diff --git a/modules/http2/h2_stream.h b/modules/http2/h2_stream.h
index 7980172..8de3ecb 100644
--- a/modules/http2/h2_stream.h
+++ b/modules/http2/h2_stream.h
@@ -41,6 +41,7 @@
 } h2_stream_state_t;
 
 struct h2_mplx;
+struct h2_priority;
 struct h2_request;
 struct h2_response;
 struct h2_session;
@@ -69,6 +70,8 @@
     
     apr_bucket_brigade *bbout;  /* output DATA */
     apr_off_t data_frames_sent; /* # of DATA frames sent out for this stream */
+    
+    struct h2_priority *prio;   /* priority information to set before submit */
 };
 
 
@@ -300,4 +303,16 @@
  */
 apr_table_t *h2_stream_get_trailers(h2_stream *stream);
 
+/**
+ * Get priority information set for this stream.
+ */
+struct h2_priority *h2_stream_get_priority(h2_stream *stream);
+
+/**
+ * Set the priority information to use on the submit of the stream.
+ * @param stream the stream to set priority on
+ * @param prio the priority information
+ */
+void h2_stream_set_priority(h2_stream *stream, struct h2_priority *prio);
+
 #endif /* defined(__mod_h2__h2_stream__) */
diff --git a/modules/http2/h2_task.c b/modules/http2/h2_task.c
index 3702fa8..fee406e 100644
--- a/modules/http2/h2_task.c
+++ b/modules/http2/h2_task.c
@@ -82,8 +82,6 @@
     return h2_from_h1_read_response(task->output->from_h1, f, bb);
 }
 
-static apr_status_t h2_task_process_request(h2_task *task);
-
 /*******************************************************************************
  * Register various hooks
  */
@@ -137,24 +135,6 @@
     return OK;
 }
 
-static int h2_task_process_conn(conn_rec* c)
-{
-    h2_ctx *ctx = h2_ctx_get(c);
-    
-    if (h2_ctx_is_task(ctx)) {
-        if (!ctx->task->serialize_headers) {
-            ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, 
-                          "h2_h2, processing request directly");
-            h2_task_process_request(ctx->task);
-            return DONE;
-        }
-        ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, 
-                      "h2_task(%s), serialized handling", ctx->task->id);
-    }
-    return DECLINED;
-}
-
-
 h2_task *h2_task_create(long session_id, const h2_request *req, 
                         apr_pool_t *pool, h2_mplx *mplx, int eos)
 {
@@ -236,128 +216,12 @@
     return status;
 }
 
-static request_rec *h2_task_create_request(h2_task *task)
+static apr_status_t h2_task_process_request(const h2_request *req, conn_rec *c)
 {
-    conn_rec *conn = task->c;
-    request_rec *r;
-    apr_pool_t *p;
-    int access_status = HTTP_OK;    
-    
-    apr_pool_create(&p, conn->pool);
-    apr_pool_tag(p, "request");
-    r = apr_pcalloc(p, sizeof(request_rec));
-    AP_READ_REQUEST_ENTRY((intptr_t)r, (uintptr_t)conn);
-    r->pool            = p;
-    r->connection      = conn;
-    r->server          = conn->base_server;
-    
-    r->user            = NULL;
-    r->ap_auth_type    = NULL;
-    
-    r->allowed_methods = ap_make_method_list(p, 2);
-    
-    r->headers_in      = apr_table_copy(r->pool, task->request->headers);
-    r->trailers_in     = apr_table_make(r->pool, 5);
-    r->subprocess_env  = apr_table_make(r->pool, 25);
-    r->headers_out     = apr_table_make(r->pool, 12);
-    r->err_headers_out = apr_table_make(r->pool, 5);
-    r->trailers_out    = apr_table_make(r->pool, 5);
-    r->notes           = apr_table_make(r->pool, 5);
-    
-    r->request_config  = ap_create_request_config(r->pool);
-    /* Must be set before we run create request hook */
-    
-    r->proto_output_filters = conn->output_filters;
-    r->output_filters  = r->proto_output_filters;
-    r->proto_input_filters = conn->input_filters;
-    r->input_filters   = r->proto_input_filters;
-    ap_run_create_request(r);
-    r->per_dir_config  = r->server->lookup_defaults;
-    
-    r->sent_bodyct     = 0;                      /* bytect isn't for body */
-    
-    r->read_length     = 0;
-    r->read_body       = REQUEST_NO_BODY;
-    
-    r->status          = HTTP_OK;  /* Until further notice */
-    r->header_only     = 0;
-    r->the_request     = NULL;
-    
-    /* Begin by presuming any module can make its own path_info assumptions,
-     * until some module interjects and changes the value.
-     */
-    r->used_path_info = AP_REQ_DEFAULT_PATH_INFO;
-    
-    r->useragent_addr = conn->client_addr;
-    r->useragent_ip = conn->client_ip;
-    
-    ap_run_pre_read_request(r, conn);
-    
-    /* Time to populate r with the data we have. */
-    r->request_time = apr_time_now();
-    r->method = task->request->method;
-    /* Provide quick information about the request method as soon as known */
-    r->method_number = ap_method_number_of(r->method);
-    if (r->method_number == M_GET && r->method[0] == 'H') {
-        r->header_only = 1;
-    }
-
-    ap_parse_uri(r, task->request->path);
-    r->protocol = (char*)"HTTP/2";
-    r->proto_num = HTTP_VERSION(2, 0);
-
-    r->the_request = apr_psprintf(r->pool, "%s %s %s", 
-                                  r->method, task->request->path, r->protocol);
-    
-    /* update what we think the virtual host is based on the headers we've
-     * now read. may update status.
-     * Leave r->hostname empty, vhost will parse if form our Host: header,
-     * otherwise we get complains about port numbers.
-     */
-    r->hostname = NULL;
-    ap_update_vhost_from_headers(r);
-    
-    /* we may have switched to another server */
-    r->per_dir_config = r->server->lookup_defaults;
-    
-    /*
-     * Add the HTTP_IN filter here to ensure that ap_discard_request_body
-     * called by ap_die and by ap_send_error_response works correctly on
-     * status codes that do not cause the connection to be dropped and
-     * in situations where the connection should be kept alive.
-     */
-    ap_add_input_filter_handle(ap_http_input_filter_handle,
-                               NULL, r, r->connection);
-    
-    if (access_status != HTTP_OK
-        || (access_status = ap_run_post_read_request(r))) {
-        /* Request check post hooks failed. An example of this would be a
-         * request for a vhost where h2 is disabled --> 421.
-         */
-        ap_die(access_status, r);
-        ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
-        ap_run_log_transaction(r);
-        r = NULL;
-        goto traceout;
-    }
-    
-    AP_READ_REQUEST_SUCCESS((uintptr_t)r, (char *)r->method, 
-                            (char *)r->uri, (char *)r->server->defn_name, 
-                            r->status);
-    return r;
-traceout:
-    AP_READ_REQUEST_FAILURE((uintptr_t)r);
-    return r;
-}
-
-
-static apr_status_t h2_task_process_request(h2_task *task)
-{
-    conn_rec *c = task->c;
     request_rec *r;
     conn_state_t *cs = c->cs;
 
-    r = h2_task_create_request(task);
+    r = h2_request_create_rec(req, c);
     if (r && (r->status == HTTP_OK)) {
         ap_update_child_status(c->sbh, SERVER_BUSY_READ, r);
         
@@ -381,6 +245,24 @@
     return APR_SUCCESS;
 }
 
+static int h2_task_process_conn(conn_rec* c)
+{
+    h2_ctx *ctx = h2_ctx_get(c);
+    
+    if (h2_ctx_is_task(ctx)) {
+        if (!ctx->task->serialize_headers) {
+            ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, 
+                          "h2_h2, processing request directly");
+            h2_task_process_request(ctx->task->request, c);
+            return DONE;
+        }
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, 
+                      "h2_task(%s), serialized handling", ctx->task->id);
+    }
+    return DECLINED;
+}
+
+
 
 
 
diff --git a/modules/http2/h2_task_output.c b/modules/http2/h2_task_output.c
index 71fefde..1d097ab 100644
--- a/modules/http2/h2_task_output.c
+++ b/modules/http2/h2_task_output.c
@@ -94,7 +94,7 @@
 {
     if (!output->trailers_passed) {
         h2_response *response = h2_from_h1_get_response(output->from_h1);
-        if (response->trailers) {
+        if (response && response->trailers) {
             output->trailers_passed = 1;
             return response->trailers;
         }
diff --git a/modules/http2/h2_version.h b/modules/http2/h2_version.h
index 76dd2db..ef883b2 100644
--- a/modules/http2/h2_version.h
+++ b/modules/http2/h2_version.h
@@ -20,7 +20,7 @@
  * @macro
  * Version number of the h2 module as c string
  */
-#define MOD_HTTP2_VERSION "1.0.6-DEV"
+#define MOD_HTTP2_VERSION "1.0.7-DEV"
 
 /**
  * @macro
@@ -28,7 +28,7 @@
  * release. This is a 24 bit number with 8 bits for major number, 8 bits
  * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
  */
-#define MOD_HTTP2_VERSION_NUM 0x010006
+#define MOD_HTTP2_VERSION_NUM 0x010007
 
 
 #endif /* mod_h2_h2_version_h */