mirror of
https://github.com/apache/httpd.git
synced 2025-08-08 15:02:10 +03:00
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
This commit is contained in:
@@ -154,6 +154,8 @@ AC_DEFUN([APACHE_CHECK_NGHTTP2],[
|
|||||||
if test "x$liberrors" != "x"; then
|
if test "x$liberrors" != "x"; then
|
||||||
AC_MSG_WARN([nghttp2 library is unusable])
|
AC_MSG_WARN([nghttp2 library is unusable])
|
||||||
fi
|
fi
|
||||||
|
AC_CHECK_FUNCS([nghttp2_session_change_stream_priority],
|
||||||
|
[APR_ADDTO(MOD_CPPFLAGS, ["-DH2_NG2_CHANGE_PRIO"])], [])
|
||||||
else
|
else
|
||||||
AC_MSG_WARN([nghttp2 version is too old])
|
AC_MSG_WARN([nghttp2 version is too old])
|
||||||
fi
|
fi
|
||||||
|
@@ -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)
|
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;
|
from_h1->bb = NULL;
|
||||||
return APR_SUCCESS;
|
return APR_SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -520,7 +516,7 @@ apr_status_t h2_response_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
|
|||||||
if (eb) {
|
if (eb) {
|
||||||
int st = eb->status;
|
int st = eb->status;
|
||||||
apr_brigade_cleanup(bb);
|
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",
|
"h2_from_h1(%d): err bucket status=%d",
|
||||||
from_h1->stream_id, st);
|
from_h1->stream_id, st);
|
||||||
ap_die(st, r);
|
ap_die(st, r);
|
||||||
|
@@ -52,7 +52,7 @@ void h2_io_set_response(h2_io *io, h2_response *response)
|
|||||||
AP_DEBUG_ASSERT(io->pool);
|
AP_DEBUG_ASSERT(io->pool);
|
||||||
AP_DEBUG_ASSERT(response);
|
AP_DEBUG_ASSERT(response);
|
||||||
AP_DEBUG_ASSERT(!io->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) {
|
if (response->rst_error) {
|
||||||
h2_io_rst(io, response->rst_error);
|
h2_io_rst(io, response->rst_error);
|
||||||
}
|
}
|
||||||
|
@@ -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
|
* insert an error one so that our streams can properly
|
||||||
* reset.
|
* reset.
|
||||||
*/
|
*/
|
||||||
h2_response *r = h2_response_create(stream_id, 0,
|
h2_response *r = h2_response_die(stream_id, APR_EGENERAL,
|
||||||
500, NULL, m->pool);
|
io->request, m->pool);
|
||||||
status = out_open(m, stream_id, r, NULL, NULL, NULL);
|
status = out_open(m, stream_id, r, NULL, NULL, NULL);
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, m->c,
|
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, m->c,
|
||||||
"h2_mplx(%ld-%d): close, no response, no rst",
|
"h2_mplx(%ld-%d): close, no response, no rst",
|
||||||
|
@@ -301,6 +301,9 @@ static int add_push(link_ctx *ctx)
|
|||||||
h2_request_end_headers(req, ctx->pool, 1);
|
h2_request_end_headers(req, ctx->pool, 1);
|
||||||
push->req = req;
|
push->req = req;
|
||||||
|
|
||||||
|
push->dep_pref = H2_PUSH_DEP_AFTER;
|
||||||
|
push->weight = NGHTTP2_DEFAULT_WEIGHT;
|
||||||
|
|
||||||
if (!ctx->pushes) {
|
if (!ctx->pushes) {
|
||||||
ctx->pushes = apr_array_make(ctx->pool, 5, sizeof(h2_push*));
|
ctx->pushes = apr_array_make(ctx->pool, 5, sizeof(h2_push*));
|
||||||
}
|
}
|
||||||
|
@@ -19,10 +19,17 @@ struct h2_request;
|
|||||||
struct h2_response;
|
struct h2_response;
|
||||||
struct h2_ngheader;
|
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 {
|
typedef struct h2_push {
|
||||||
int initiating_id;
|
int initiating_id;
|
||||||
const struct h2_request *req;
|
const struct h2_request *req;
|
||||||
const char *as;
|
h2_push_dep_t dep_pref;
|
||||||
|
int weight;
|
||||||
} h2_push;
|
} h2_push;
|
||||||
|
|
||||||
|
|
||||||
|
@@ -19,9 +19,15 @@
|
|||||||
|
|
||||||
#include <httpd.h>
|
#include <httpd.h>
|
||||||
#include <http_core.h>
|
#include <http_core.h>
|
||||||
|
#include <http_connection.h>
|
||||||
#include <http_protocol.h>
|
#include <http_protocol.h>
|
||||||
#include <http_config.h>
|
#include <http_request.h>
|
||||||
#include <http_log.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_private.h"
|
||||||
#include "h2_mplx.h"
|
#include "h2_mplx.h"
|
||||||
@@ -48,7 +54,8 @@ h2_request *h2_request_createn(int id, apr_pool_t *pool,
|
|||||||
req->authority = authority;
|
req->authority = authority;
|
||||||
req->path = path;
|
req->path = path;
|
||||||
req->headers = header? header : apr_table_make(pool, 10);
|
req->headers = header? header : apr_table_make(pool, 10);
|
||||||
|
req->request_time = apr_time_now();
|
||||||
|
|
||||||
return req;
|
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;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -38,6 +38,7 @@ struct h2_request {
|
|||||||
apr_table_t *headers;
|
apr_table_t *headers;
|
||||||
apr_table_t *trailers;
|
apr_table_t *trailers;
|
||||||
|
|
||||||
|
apr_time_t request_time;
|
||||||
apr_off_t content_length;
|
apr_off_t content_length;
|
||||||
int chunked;
|
int chunked;
|
||||||
int eoh;
|
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);
|
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__) */
|
#endif /* defined(__mod_h2__h2_request__) */
|
||||||
|
@@ -21,42 +21,30 @@
|
|||||||
#include <httpd.h>
|
#include <httpd.h>
|
||||||
#include <http_core.h>
|
#include <http_core.h>
|
||||||
#include <http_log.h>
|
#include <http_log.h>
|
||||||
|
#include <util_time.h>
|
||||||
|
|
||||||
#include <nghttp2/nghttp2.h>
|
#include <nghttp2/nghttp2.h>
|
||||||
|
|
||||||
#include "h2_private.h"
|
#include "h2_private.h"
|
||||||
#include "h2_h2.h"
|
#include "h2_h2.h"
|
||||||
#include "h2_util.h"
|
#include "h2_util.h"
|
||||||
|
#include "h2_request.h"
|
||||||
#include "h2_response.h"
|
#include "h2_response.h"
|
||||||
|
|
||||||
|
|
||||||
h2_response *h2_response_create(int stream_id,
|
static apr_table_t *parse_headers(apr_array_header_t *hlines, apr_pool_t *pool)
|
||||||
int rst_error,
|
|
||||||
int http_status,
|
|
||||||
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) {
|
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) {
|
for (i = 0; i < hlines->nelts; ++i) {
|
||||||
char *hline = ((char **)hlines->elts)[i];
|
char *hline = ((char **)hlines->elts)[i];
|
||||||
char *sep = ap_strchr(hline, ':');
|
char *sep = ap_strchr(hline, ':');
|
||||||
if (!sep) {
|
if (!sep) {
|
||||||
ap_log_perror(APLOG_MARK, APLOG_WARNING, APR_EINVAL, pool,
|
ap_log_perror(APLOG_MARK, APLOG_WARNING, APR_EINVAL, pool,
|
||||||
APLOGNO(02955) "h2_response(%d): invalid header[%d] '%s'",
|
APLOGNO(02955) "h2_response: invalid header[%d] '%s'",
|
||||||
response->stream_id, i, (char*)hline);
|
i, (char*)hline);
|
||||||
/* not valid format, abort */
|
/* not valid format, abort */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -67,29 +55,66 @@ h2_response *h2_response_create(int stream_id,
|
|||||||
|
|
||||||
if (!h2_util_ignore_header(hline)) {
|
if (!h2_util_ignore_header(hline)) {
|
||||||
apr_table_merge(headers, hline, sep);
|
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 {
|
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;
|
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;
|
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,
|
h2_response *h2_response_rcreate(int stream_id, request_rec *r,
|
||||||
apr_table_t *header, apr_pool_t *pool)
|
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;
|
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));
|
h2_response *to = apr_pcalloc(pool, sizeof(h2_response));
|
||||||
to->stream_id = from->stream_id;
|
to->stream_id = from->stream_id;
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
#ifndef __mod_h2__h2_response__
|
#ifndef __mod_h2__h2_response__
|
||||||
#define __mod_h2__h2_response__
|
#define __mod_h2__h2_response__
|
||||||
|
|
||||||
|
struct h2_request;
|
||||||
struct h2_push;
|
struct h2_push;
|
||||||
|
|
||||||
typedef struct h2_response {
|
typedef struct h2_response {
|
||||||
@@ -27,18 +28,47 @@ typedef struct h2_response {
|
|||||||
apr_table_t *trailers;
|
apr_table_t *trailers;
|
||||||
} h2_response;
|
} 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,
|
h2_response *h2_response_create(int stream_id,
|
||||||
int rst_error,
|
int rst_error,
|
||||||
int http_status,
|
int http_status,
|
||||||
apr_array_header_t *hlines,
|
apr_array_header_t *hlines,
|
||||||
apr_pool_t *pool);
|
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,
|
h2_response *h2_response_rcreate(int stream_id, request_rec *r,
|
||||||
apr_table_t *header, apr_pool_t *pool);
|
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
|
* Set the trailers in the reponse. Will replace any existing trailers. Will
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <math.h>
|
||||||
#include <apr_thread_cond.h>
|
#include <apr_thread_cond.h>
|
||||||
#include <apr_base64.h>
|
#include <apr_base64.h>
|
||||||
#include <apr_strings.h>
|
#include <apr_strings.h>
|
||||||
@@ -1226,6 +1227,13 @@ static apr_status_t submit_response(h2_session *session, h2_stream *stream)
|
|||||||
return status;
|
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,
|
struct h2_stream *h2_session_push(h2_session *session, h2_stream *is,
|
||||||
h2_push *push)
|
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,
|
session->id, push->initiating_id, nid,
|
||||||
push->req->method, push->req->path);
|
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);
|
stream = h2_session_open_stream(session, nid);
|
||||||
if (stream) {
|
if (stream) {
|
||||||
h2_stream_set_h2_request(stream, is->id, push->req);
|
h2_stream_set_h2_request(stream, is->id, push->req);
|
||||||
|
@@ -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);
|
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
|
* Register various hooks
|
||||||
*/
|
*/
|
||||||
@@ -137,24 +135,6 @@ static int h2_task_pre_conn(conn_rec* c, void *arg)
|
|||||||
return OK;
|
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,
|
h2_task *h2_task_create(long session_id, const h2_request *req,
|
||||||
apr_pool_t *pool, h2_mplx *mplx, int eos)
|
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;
|
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;
|
request_rec *r;
|
||||||
conn_state_t *cs = c->cs;
|
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)) {
|
if (r && (r->status == HTTP_OK)) {
|
||||||
ap_update_child_status(c->sbh, SERVER_BUSY_READ, r);
|
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;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -94,7 +94,7 @@ static apr_table_t *get_trailers(h2_task_output *output)
|
|||||||
{
|
{
|
||||||
if (!output->trailers_passed) {
|
if (!output->trailers_passed) {
|
||||||
h2_response *response = h2_from_h1_get_response(output->from_h1);
|
h2_response *response = h2_from_h1_get_response(output->from_h1);
|
||||||
if (response->trailers) {
|
if (response && response->trailers) {
|
||||||
output->trailers_passed = 1;
|
output->trailers_passed = 1;
|
||||||
return response->trailers;
|
return response->trailers;
|
||||||
}
|
}
|
||||||
|
@@ -20,7 +20,7 @@
|
|||||||
* @macro
|
* @macro
|
||||||
* Version number of the h2 module as c string
|
* 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
|
* @macro
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
* release. This is a 24 bit number with 8 bits for major number, 8 bits
|
* 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.
|
* 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 */
|
#endif /* mod_h2_h2_version_h */
|
||||||
|
Reference in New Issue
Block a user