diff options
author | Stefan Eissing <icing@apache.org> | 2015-11-24 15:21:26 +0100 |
---|---|---|
committer | Stefan Eissing <icing@apache.org> | 2015-11-24 15:21:26 +0100 |
commit | 98a612bb81ab49092e4fc101ea6c855e46739d6b (patch) | |
tree | b88ffe3e9a8fe13e92eda318b3342d624e3c9c2a | |
parent | Follow up to r1715876: fix typo. (diff) | |
download | apache2-98a612bb81ab49092e4fc101ea6c855e46739d6b.tar.xz apache2-98a612bb81ab49092e4fc101ea6c855e46739d6b.zip |
start of PUSH priority handling, fixing core when task produces no response at all
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1716146 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to '')
-rw-r--r-- | modules/http2/config.m4 | 2 | ||||
-rw-r--r-- | modules/http2/h2_from_h1.c | 6 | ||||
-rw-r--r-- | modules/http2/h2_io.c | 2 | ||||
-rw-r--r-- | modules/http2/h2_mplx.c | 4 | ||||
-rw-r--r-- | modules/http2/h2_push.c | 3 | ||||
-rw-r--r-- | modules/http2/h2_push.h | 11 | ||||
-rw-r--r-- | modules/http2/h2_request.c | 125 | ||||
-rw-r--r-- | modules/http2/h2_request.h | 10 | ||||
-rw-r--r-- | modules/http2/h2_response.c | 106 | ||||
-rw-r--r-- | modules/http2/h2_response.h | 34 | ||||
-rw-r--r-- | modules/http2/h2_session.c | 94 | ||||
-rw-r--r-- | modules/http2/h2_task.c | 158 | ||||
-rw-r--r-- | modules/http2/h2_task_output.c | 2 | ||||
-rw-r--r-- | modules/http2/h2_version.h | 4 |
14 files changed, 370 insertions, 191 deletions
diff --git a/modules/http2/config.m4 b/modules/http2/config.m4 index f383b3cd83..e10bb8158f 100644 --- a/modules/http2/config.m4 +++ b/modules/http2/config.m4 @@ -154,6 +154,8 @@ AC_DEFUN([APACHE_CHECK_NGHTTP2],[ 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 db0c80db05..4801ec5623 100644 --- a/modules/http2/h2_from_h1.c +++ b/modules/http2/h2_from_h1.c @@ -51,10 +51,6 @@ h2_from_h1 *h2_from_h1_create(int stream_id, apr_pool_t *pool) 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 @@ apr_status_t h2_response_output_filter(ap_filter_t *f, apr_bucket_brigade *bb) 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_io.c b/modules/http2/h2_io.c index a1d9eff317..6bd2b83739 100644 --- a/modules/http2/h2_io.c +++ b/modules/http2/h2_io.c @@ -52,7 +52,7 @@ void h2_io_set_response(h2_io *io, h2_response *response) 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 3890a5a064..6f2a512465 100644 --- a/modules/http2/h2_mplx.c +++ b/modules/http2/h2_mplx.c @@ -711,8 +711,8 @@ apr_status_t h2_mplx_out_close(h2_mplx *m, int stream_id, apr_table_t *trailers) * 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 dd972cf8e2..3cfacd7fe3 100644 --- a/modules/http2/h2_push.c +++ b/modules/http2/h2_push.c @@ -301,6 +301,9 @@ static int add_push(link_ctx *ctx) h2_request_end_headers(req, ctx->pool, 1); push->req = req; + push->dep_pref = H2_PUSH_DEP_AFTER; + push->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 64edee65d1..546a992873 100644 --- a/modules/http2/h2_push.h +++ b/modules/http2/h2_push.h @@ -19,10 +19,17 @@ struct h2_request; struct h2_response; struct h2_ngheader; +typedef enum { + H2_PUSH_DEP_AFTER, + H2_PUSH_DEP_INTERLEAVED, + H2_PUSH_DEP_BEFORE, +} h2_push_dep_t; + typedef struct h2_push { - int initiating_id; + int initiating_id; const struct h2_request *req; - const char *as; + h2_push_dep_t dep_pref; + int weight; } h2_push; diff --git a/modules/http2/h2_request.c b/modules/http2/h2_request.c index a5f7d9d4fb..e1a371f6a4 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 @@ h2_request *h2_request_createn(int id, apr_pool_t *pool, 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 @@ void h2_request_copy(apr_pool_t *p, h2_request *dst, const h2_request *src) 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 19005a88e6..69d24f38a2 100644 --- a/modules/http2/h2_request.h +++ b/modules/http2/h2_request.h @@ -38,6 +38,7 @@ struct h2_request { 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 @@ apr_status_t h2_request_end_headers(h2_request *req, apr_pool_t *pool, int eos); 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 505f2451d6..d16fee29ba 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 @@ h2_response *h2_response_create(int stream_id, 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 @@ h2_response *h2_response_rcreate(int stream_id, request_rec *r, 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 518ef2e3c1..426eeead72 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 @@ typedef struct h2_response { 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 720a1eb30d..9212e2af8f 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> @@ -1226,6 +1227,13 @@ static apr_status_t submit_response(h2_session *session, h2_stream *stream) return status; } +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); +} + struct h2_stream *h2_session_push(h2_session *session, h2_stream *is, h2_push *push) { @@ -1251,6 +1259,92 @@ struct h2_stream *h2_session_push(h2_session *session, h2_stream *is, session->id, push->initiating_id, nid, push->req->method, push->req->path); +#ifdef H2_NG2_CHANGE_PRIO + /* If different than default, change the priority of the pushed stream + * as specified in the h2_push: + */ + if (push->weight != NGHTTP2_DEFAULT_WEIGHT || push->dep_pref != H2_PUSH_DEP_AFTER) { + nghttp2_stream *s_init, *s_dep, *s_push; + int id_init = push->initiating_id; + + s_push = nghttp2_session_find_stream(session->ngh2, nid); + if (!s_push) { + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, + "h2_stream(%ld-%d): lookup of PUSHed stream failed", + session->id, nid); + } + s_init = nghttp2_session_find_stream(session->ngh2, id_init); + if (s_push && s_init) { + nghttp2_priority_spec ps; + int id_dep, w_init, w, rv = 0; + + switch (push->dep_pref) { + case H2_PUSH_DEP_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. + */ + s_dep = nghttp2_stream_get_parent(s_init); + if (s_dep) { + id_dep = nghttp2_stream_get_stream_id(s_dep); + w_init = nghttp2_stream_get_weight(s_init); + w = valid_weight(w_init * ((float)NGHTTP2_MAX_WEIGHT / push->weight)); + nghttp2_priority_spec_init(&ps, id_dep, w, 0); + rv = nghttp2_session_change_stream_priority(session->ngh2, nid, &ps); + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, + "h2_stream(%ld-%d): PUSH INTERLEAVE, weight=%d, " + "depends=%d, returned=%d", + session->id, nid, w, id_dep, rv); + } + break; + case H2_PUSH_DEP_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. + */ + s_dep = nghttp2_stream_get_parent(s_init); + if (s_dep) { + id_dep = nghttp2_stream_get_stream_id(s_dep); + w_init = nghttp2_stream_get_weight(s_init); + nghttp2_priority_spec_init(&ps, id_dep, valid_weight(w_init), 0); + rv = nghttp2_session_change_stream_priority(session->ngh2, nid, &ps); + if (!rv) { + nghttp2_priority_spec_init(&ps, nid, NGHTTP2_MAX_WEIGHT, 0); + rv = nghttp2_session_change_stream_priority(session->ngh2, id_init, &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_init, ps.weight, ps.stream_id, rv); + } + } + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, + "h2_stream(%ld-%d): PUSH BEFORE, weight=%d, " + "depends=%d, before=%d, returned=%d", + session->id, nid, w_init, id_dep, id_init, rv); + } + break; + case H2_PUSH_DEP_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_init, valid_weight(push->weight), 0); + rv = nghttp2_session_change_stream_priority(session->ngh2, nid, &ps); + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, + "h2_stream(%ld-%d): PUSH AFTER, weight=%d, " + "depends=%d, returned=%d", + session->id, nid, ps.weight, ps.stream_id, rv); + break; + } + } + } +#endif + stream = h2_session_open_stream(session, nid); if (stream) { h2_stream_set_h2_request(stream, is->id, push->req); diff --git a/modules/http2/h2_task.c b/modules/http2/h2_task.c index 3702fa88f2..fee406e1bb 100644 --- a/modules/http2/h2_task.c +++ b/modules/http2/h2_task.c @@ -82,8 +82,6 @@ static apr_status_t h2_filter_read_response(ap_filter_t* f, 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 @@ static int h2_task_pre_conn(conn_rec* c, void *arg) 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 @@ apr_status_t h2_task_do(h2_task *task, h2_worker *worker) 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 @@ static apr_status_t h2_task_process_request(h2_task *task) 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 71fefdec05..1d097ab359 100644 --- a/modules/http2/h2_task_output.c +++ b/modules/http2/h2_task_output.c @@ -94,7 +94,7 @@ static apr_table_t *get_trailers(h2_task_output *output) { 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 76dd2db0fc..ef883b29b9 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 */ |