mirror of
https://github.com/apache/httpd.git
synced 2025-08-08 15:02:10 +03:00
mod_http2: more const goodiness and checks on h2 request creation, less NULL checking while processing
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1759547 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
@@ -370,7 +370,6 @@ $(OBJDIR)/mod_http2.imp : NWGNUmod_http2
|
|||||||
@echo $(DL) h2_headers_add_h1,$(DL) >> $@
|
@echo $(DL) h2_headers_add_h1,$(DL) >> $@
|
||||||
@echo $(DL) h2_req_create,$(DL) >> $@
|
@echo $(DL) h2_req_create,$(DL) >> $@
|
||||||
@echo $(DL) h2_req_createn,$(DL) >> $@
|
@echo $(DL) h2_req_createn,$(DL) >> $@
|
||||||
@echo $(DL) h2_req_make,$(DL) >> $@
|
|
||||||
@echo $(DL) h2_util_camel_case_header,$(DL) >> $@
|
@echo $(DL) h2_util_camel_case_header,$(DL) >> $@
|
||||||
@echo $(DL) h2_util_frame_print,$(DL) >> $@
|
@echo $(DL) h2_util_frame_print,$(DL) >> $@
|
||||||
@echo $(DL) h2_util_ngheader_make_req,$(DL) >> $@
|
@echo $(DL) h2_util_ngheader_make_req,$(DL) >> $@
|
||||||
|
@@ -130,7 +130,6 @@ struct h2_request {
|
|||||||
apr_off_t content_length;
|
apr_off_t content_length;
|
||||||
|
|
||||||
unsigned int chunked : 1; /* iff requst body needs to be forwarded as chunked */
|
unsigned int chunked : 1; /* iff requst body needs to be forwarded as chunked */
|
||||||
unsigned int eoh : 1; /* iff end-of-headers has been seen and request is complete */
|
|
||||||
unsigned int body : 1; /* iff this request has a body */
|
unsigned int body : 1; /* iff this request has a body */
|
||||||
unsigned int serialize : 1; /* iff this request is written in HTTP/1.1 serialization */
|
unsigned int serialize : 1; /* iff this request is written in HTTP/1.1 serialization */
|
||||||
unsigned int push_policy; /* which push policy to use for this request */
|
unsigned int push_policy; /* which push policy to use for this request */
|
||||||
|
@@ -512,7 +512,7 @@ static int task_print(void *ctx, void *val)
|
|||||||
h2_mplx *m = ctx;
|
h2_mplx *m = ctx;
|
||||||
h2_task *task = val;
|
h2_task *task = val;
|
||||||
|
|
||||||
if (task && task->request) {
|
if (task) {
|
||||||
h2_stream *stream = h2_ihash_get(m->streams, task->stream_id);
|
h2_stream *stream = h2_ihash_get(m->streams, task->stream_id);
|
||||||
|
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, m->c, /* NO APLOGNO */
|
ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, m->c, /* NO APLOGNO */
|
||||||
|
@@ -346,7 +346,7 @@ static int add_push(link_ctx *ctx)
|
|||||||
}
|
}
|
||||||
headers = apr_table_make(ctx->pool, 5);
|
headers = apr_table_make(ctx->pool, 5);
|
||||||
apr_table_do(set_push_header, headers, ctx->req->headers, NULL);
|
apr_table_do(set_push_header, headers, ctx->req->headers, NULL);
|
||||||
req = h2_req_createn(0, ctx->pool, method, ctx->req->scheme,
|
req = h2_req_create(0, ctx->pool, method, ctx->req->scheme,
|
||||||
ctx->req->authority, path, headers,
|
ctx->req->authority, path, headers,
|
||||||
ctx->req->serialize);
|
ctx->req->serialize);
|
||||||
/* atm, we do not push on pushes */
|
/* atm, we do not push on pushes */
|
||||||
|
@@ -30,6 +30,7 @@
|
|||||||
#include <scoreboard.h>
|
#include <scoreboard.h>
|
||||||
|
|
||||||
#include "h2_private.h"
|
#include "h2_private.h"
|
||||||
|
#include "h2_config.h"
|
||||||
#include "h2_push.h"
|
#include "h2_push.h"
|
||||||
#include "h2_request.h"
|
#include "h2_request.h"
|
||||||
#include "h2_util.h"
|
#include "h2_util.h"
|
||||||
@@ -42,15 +43,39 @@ static apr_status_t inspect_clen(h2_request *req, const char *s)
|
|||||||
return (s == end)? APR_EINVAL : APR_SUCCESS;
|
return (s == end)? APR_EINVAL : APR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_status_t h2_request_rwrite(h2_request *req, apr_pool_t *pool,
|
typedef struct {
|
||||||
|
apr_table_t *headers;
|
||||||
|
apr_pool_t *pool;
|
||||||
|
} h1_ctx;
|
||||||
|
|
||||||
|
static int set_h1_header(void *ctx, const char *key, const char *value)
|
||||||
|
{
|
||||||
|
h1_ctx *x = ctx;
|
||||||
|
size_t klen = strlen(key);
|
||||||
|
if (!h2_req_ignore_header(key, klen)) {
|
||||||
|
h2_headers_add_h1(x->headers, x->pool, key, klen, value, strlen(value));
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
apr_status_t h2_request_rcreate(h2_request **preq, apr_pool_t *pool,
|
||||||
|
int stream_id, int initiated_on,
|
||||||
request_rec *r)
|
request_rec *r)
|
||||||
{
|
{
|
||||||
apr_status_t status;
|
h2_request *req;
|
||||||
const char *scheme, *authority;
|
const char *scheme, *authority, *path;
|
||||||
|
h1_ctx x;
|
||||||
|
|
||||||
|
*preq = NULL;
|
||||||
scheme = apr_pstrdup(pool, r->parsed_uri.scheme? r->parsed_uri.scheme
|
scheme = apr_pstrdup(pool, r->parsed_uri.scheme? r->parsed_uri.scheme
|
||||||
: ap_http_scheme(r));
|
: ap_http_scheme(r));
|
||||||
authority = (r->hostname ? apr_pstrdup(pool, r->hostname) : "");
|
authority = apr_pstrdup(pool, r->hostname);
|
||||||
|
path = apr_uri_unparse(pool, &r->parsed_uri, APR_URI_UNP_OMITSITEPART);
|
||||||
|
|
||||||
|
if (!r->method || !scheme || !r->hostname || !path) {
|
||||||
|
return APR_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
if (!ap_strchr_c(authority, ':') && r->server && r->server->port) {
|
if (!ap_strchr_c(authority, ':') && r->server && r->server->port) {
|
||||||
apr_port_t defport = apr_uri_port_of_scheme(scheme);
|
apr_port_t defport = apr_uri_port_of_scheme(scheme);
|
||||||
if (defport != r->server->port) {
|
if (defport != r->server->port) {
|
||||||
@@ -60,11 +85,25 @@ apr_status_t h2_request_rwrite(h2_request *req, apr_pool_t *pool,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
status = h2_req_make(req, pool, apr_pstrdup(pool, r->method), scheme,
|
req = apr_pcalloc(pool, sizeof(*req));
|
||||||
authority, apr_uri_unparse(pool, &r->parsed_uri,
|
req->id = stream_id;
|
||||||
APR_URI_UNP_OMITSITEPART),
|
req->initiated_on = initiated_on;
|
||||||
r->headers_in);
|
req->method = apr_pstrdup(pool, r->method);
|
||||||
return status;
|
req->scheme = scheme;
|
||||||
|
req->authority = authority;
|
||||||
|
req->path = path;
|
||||||
|
req->headers = apr_table_make(pool, 10);
|
||||||
|
if (r->server) {
|
||||||
|
req->serialize = h2_config_geti(h2_config_sget(r->server),
|
||||||
|
H2_CONF_SER_HEADERS);
|
||||||
|
}
|
||||||
|
|
||||||
|
x.pool = pool;
|
||||||
|
x.headers = req->headers;
|
||||||
|
apr_table_do(set_h1_header, &x, r->headers_in, NULL);
|
||||||
|
|
||||||
|
*preq = req;
|
||||||
|
return APR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_status_t h2_request_add_header(h2_request *req, apr_pool_t *pool,
|
apr_status_t h2_request_add_header(h2_request *req, apr_pool_t *pool,
|
||||||
@@ -126,11 +165,6 @@ apr_status_t h2_request_end_headers(h2_request *req, apr_pool_t *pool,
|
|||||||
{
|
{
|
||||||
const char *s;
|
const char *s;
|
||||||
|
|
||||||
if (req->eoh) {
|
|
||||||
/* already done */
|
|
||||||
return APR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* rfc7540, ch. 8.1.2.3:
|
/* rfc7540, ch. 8.1.2.3:
|
||||||
* - if we have :authority, it overrides any Host header
|
* - if we have :authority, it overrides any Host header
|
||||||
* - :authority MUST be ommited when converting h1->h2, so we
|
* - :authority MUST be ommited when converting h1->h2, so we
|
||||||
@@ -155,11 +189,13 @@ apr_status_t h2_request_end_headers(h2_request *req, apr_pool_t *pool,
|
|||||||
req->id, s);
|
req->id, s);
|
||||||
return APR_EINVAL;
|
return APR_EINVAL;
|
||||||
}
|
}
|
||||||
|
req->body = 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* no content-length given */
|
/* no content-length given */
|
||||||
req->content_length = -1;
|
req->content_length = -1;
|
||||||
if (!eos) {
|
req->body = !eos;
|
||||||
|
if (req->body) {
|
||||||
/* We have not seen a content-length and have no eos,
|
/* We have not seen a content-length and have no eos,
|
||||||
* simulate a chunked encoding for our HTTP/1.1 infrastructure,
|
* simulate a chunked encoding for our HTTP/1.1 infrastructure,
|
||||||
* in case we have "H2SerializeHeaders on" here
|
* in case we have "H2SerializeHeaders on" here
|
||||||
@@ -175,7 +211,6 @@ apr_status_t h2_request_end_headers(h2_request *req, apr_pool_t *pool,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
req->eoh = 1;
|
|
||||||
h2_push_policy_determine(req, pool, push);
|
h2_push_policy_determine(req, pool, push);
|
||||||
|
|
||||||
/* In the presence of trailers, force behaviour of chunked encoding */
|
/* In the presence of trailers, force behaviour of chunked encoding */
|
||||||
|
@@ -18,7 +18,8 @@
|
|||||||
|
|
||||||
#include "h2.h"
|
#include "h2.h"
|
||||||
|
|
||||||
apr_status_t h2_request_rwrite(h2_request *req, apr_pool_t *pool,
|
apr_status_t h2_request_rcreate(h2_request **preq, apr_pool_t *pool,
|
||||||
|
int stream_id, int initiated_on,
|
||||||
request_rec *r);
|
request_rec *r);
|
||||||
|
|
||||||
apr_status_t h2_request_add_header(h2_request *req, apr_pool_t *pool,
|
apr_status_t h2_request_add_header(h2_request *req, apr_pool_t *pool,
|
||||||
|
@@ -174,7 +174,7 @@ h2_response *h2_response_die(int stream_id, apr_status_t type,
|
|||||||
int status = (type >= 200 && type < 600)? type : 500;
|
int status = (type >= 200 && type < 600)? type : 500;
|
||||||
|
|
||||||
date = apr_palloc(pool, APR_RFC822_DATE_LEN);
|
date = apr_palloc(pool, APR_RFC822_DATE_LEN);
|
||||||
ap_recent_rfc822_date(date, req->request_time);
|
ap_recent_rfc822_date(date, req? req->request_time : apr_time_now());
|
||||||
apr_table_setn(headers, "Date", date);
|
apr_table_setn(headers, "Date", date);
|
||||||
apr_table_setn(headers, "Server", ap_get_server_banner());
|
apr_table_setn(headers, "Server", ap_get_server_banner());
|
||||||
|
|
||||||
|
@@ -143,10 +143,14 @@ h2_stream *h2_session_open_stream(h2_session *session, int stream_id,
|
|||||||
apr_pool_tag(stream_pool, "h2_stream");
|
apr_pool_tag(stream_pool, "h2_stream");
|
||||||
|
|
||||||
stream = h2_stream_open(stream_id, stream_pool, session,
|
stream = h2_stream_open(stream_id, stream_pool, session,
|
||||||
initiated_on, req);
|
initiated_on);
|
||||||
nghttp2_session_set_stream_user_data(session->ngh2, stream_id, stream);
|
nghttp2_session_set_stream_user_data(session->ngh2, stream_id, stream);
|
||||||
h2_ihash_add(session->streams, stream);
|
h2_ihash_add(session->streams, stream);
|
||||||
|
|
||||||
|
if (req) {
|
||||||
|
h2_stream_set_request(stream, req);
|
||||||
|
}
|
||||||
|
|
||||||
if (H2_STREAM_CLIENT_INITIATED(stream_id)) {
|
if (H2_STREAM_CLIENT_INITIATED(stream_id)) {
|
||||||
if (stream_id > session->remote.emitted_max) {
|
if (stream_id > session->remote.emitted_max) {
|
||||||
++session->remote.emitted_count;
|
++session->remote.emitted_count;
|
||||||
@@ -500,7 +504,7 @@ static int on_frame_recv_cb(nghttp2_session *ng2s,
|
|||||||
session->id, (int)frame->hd.stream_id,
|
session->id, (int)frame->hd.stream_id,
|
||||||
(int)frame->rst_stream.error_code);
|
(int)frame->rst_stream.error_code);
|
||||||
stream = get_stream(session, frame->hd.stream_id);
|
stream = get_stream(session, frame->hd.stream_id);
|
||||||
if (stream && stream->request && stream->request->initiated_on) {
|
if (stream && stream->initiated_on) {
|
||||||
++session->pushes_reset;
|
++session->pushes_reset;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1078,7 +1082,7 @@ static apr_status_t h2_session_start(h2_session *session, int *rv)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = h2_stream_set_request(stream, session->r);
|
status = h2_stream_set_request_rec(stream, session->r);
|
||||||
if (status != APR_SUCCESS) {
|
if (status != APR_SUCCESS) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -1508,8 +1512,7 @@ static apr_status_t on_stream_response(void *ctx, int stream_id)
|
|||||||
* as the client, having this resource in its cache, might
|
* as the client, having this resource in its cache, might
|
||||||
* also have the pushed ones as well.
|
* also have the pushed ones as well.
|
||||||
*/
|
*/
|
||||||
if (stream->request
|
if (!stream->initiated_on
|
||||||
&& !stream->request->initiated_on
|
|
||||||
&& h2_response_is_final(response)
|
&& h2_response_is_final(response)
|
||||||
&& H2_HTTP_2XX(response->http_status)
|
&& H2_HTTP_2XX(response->http_status)
|
||||||
&& h2_session_push_enabled(session)) {
|
&& h2_session_push_enabled(session)) {
|
||||||
@@ -1529,7 +1532,7 @@ static apr_status_t on_stream_response(void *ctx, int stream_id)
|
|||||||
stream->submitted = h2_response_is_final(response);
|
stream->submitted = h2_response_is_final(response);
|
||||||
session->have_written = 1;
|
session->have_written = 1;
|
||||||
|
|
||||||
if (stream->request && stream->request->initiated_on) {
|
if (stream->initiated_on) {
|
||||||
++session->pushes_submitted;
|
++session->pushes_submitted;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@@ -175,30 +175,18 @@ static apr_status_t stream_pool_cleanup(void *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
h2_stream *h2_stream_open(int id, apr_pool_t *pool, h2_session *session,
|
h2_stream *h2_stream_open(int id, apr_pool_t *pool, h2_session *session,
|
||||||
int initiated_on, const h2_request *creq)
|
int initiated_on)
|
||||||
{
|
{
|
||||||
h2_request *req;
|
|
||||||
h2_stream *stream = apr_pcalloc(pool, sizeof(h2_stream));
|
h2_stream *stream = apr_pcalloc(pool, sizeof(h2_stream));
|
||||||
|
|
||||||
stream->id = id;
|
stream->id = id;
|
||||||
|
stream->initiated_on = initiated_on;
|
||||||
stream->created = apr_time_now();
|
stream->created = apr_time_now();
|
||||||
stream->state = H2_STREAM_ST_IDLE;
|
stream->state = H2_STREAM_ST_IDLE;
|
||||||
stream->pool = pool;
|
stream->pool = pool;
|
||||||
stream->session = session;
|
stream->session = session;
|
||||||
|
|
||||||
set_state(stream, H2_STREAM_ST_OPEN);
|
set_state(stream, H2_STREAM_ST_OPEN);
|
||||||
|
|
||||||
if (creq) {
|
|
||||||
/* take it into out pool and assure correct id's */
|
|
||||||
req = h2_request_clone(pool, creq);
|
|
||||||
req->id = id;
|
|
||||||
req->initiated_on = initiated_on;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
req = h2_req_create(id, pool,
|
|
||||||
h2_config_geti(session->config, H2_CONF_SER_HEADERS));
|
|
||||||
}
|
|
||||||
stream->request = req;
|
|
||||||
|
|
||||||
apr_pool_cleanup_register(pool, stream, stream_pool_cleanup,
|
apr_pool_cleanup_register(pool, stream, stream_pool_cleanup,
|
||||||
apr_pool_cleanup_null);
|
apr_pool_cleanup_null);
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, APLOGNO(03082)
|
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, APLOGNO(03082)
|
||||||
@@ -276,31 +264,40 @@ struct h2_response *h2_stream_get_unsent_response(h2_stream *stream)
|
|||||||
return unsent;
|
return unsent;
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_status_t h2_stream_set_request(h2_stream *stream, request_rec *r)
|
apr_status_t h2_stream_set_request_rec(h2_stream *stream, request_rec *r)
|
||||||
{
|
{
|
||||||
|
h2_request *req;
|
||||||
apr_status_t status;
|
apr_status_t status;
|
||||||
AP_DEBUG_ASSERT(stream);
|
|
||||||
|
ap_assert(stream->request == NULL);
|
||||||
|
ap_assert(stream->rtmp == NULL);
|
||||||
if (stream->rst_error) {
|
if (stream->rst_error) {
|
||||||
return APR_ECONNRESET;
|
return APR_ECONNRESET;
|
||||||
}
|
}
|
||||||
set_state(stream, H2_STREAM_ST_OPEN);
|
status = h2_request_rcreate(&req, stream->pool, stream->id,
|
||||||
status = h2_request_rwrite(stream->request, stream->pool, r);
|
stream->initiated_on, r);
|
||||||
stream->request->serialize = h2_config_geti(h2_config_sget(r->server),
|
|
||||||
H2_CONF_SER_HEADERS);
|
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(03058)
|
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(03058)
|
||||||
"h2_request(%d): rwrite %s host=%s://%s%s",
|
"h2_request(%d): set_request_rec %s host=%s://%s%s",
|
||||||
stream->request->id, stream->request->method,
|
stream->id, req->method, req->scheme, req->authority,
|
||||||
stream->request->scheme, stream->request->authority,
|
req->path);
|
||||||
stream->request->path);
|
stream->rtmp = req;
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apr_status_t h2_stream_set_request(h2_stream *stream, const h2_request *r)
|
||||||
|
{
|
||||||
|
ap_assert(stream->request == NULL);
|
||||||
|
ap_assert(stream->rtmp == NULL);
|
||||||
|
stream->rtmp = h2_request_clone(stream->pool, r);
|
||||||
|
return APR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
apr_status_t h2_stream_add_header(h2_stream *stream,
|
apr_status_t h2_stream_add_header(h2_stream *stream,
|
||||||
const char *name, size_t nlen,
|
const char *name, size_t nlen,
|
||||||
const char *value, size_t vlen)
|
const char *value, size_t vlen)
|
||||||
{
|
{
|
||||||
AP_DEBUG_ASSERT(stream);
|
AP_DEBUG_ASSERT(stream);
|
||||||
|
|
||||||
if (!stream->response) {
|
if (!stream->response) {
|
||||||
if (name[0] == ':') {
|
if (name[0] == ':') {
|
||||||
if ((vlen) > stream->session->s->limit_req_line) {
|
if ((vlen) > stream->session->s->limit_req_line) {
|
||||||
@@ -336,14 +333,20 @@ apr_status_t h2_stream_add_header(h2_stream *stream,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (h2_stream_is_scheduled(stream)) {
|
if (h2_stream_is_scheduled(stream)) {
|
||||||
return h2_request_add_trailer(stream->request, stream->pool,
|
/* FIXME: this is not clean. we modify a struct that is being processed
|
||||||
|
* by another thread potentially. */
|
||||||
|
return h2_request_add_trailer((h2_request*)stream->request, stream->pool,
|
||||||
name, nlen, value, vlen);
|
name, nlen, value, vlen);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!input_open(stream)) {
|
if (!stream->rtmp) {
|
||||||
|
stream->rtmp = h2_req_create(stream->id, stream->pool,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, 0);
|
||||||
|
}
|
||||||
|
if (stream->state != H2_STREAM_ST_OPEN) {
|
||||||
return APR_ECONNRESET;
|
return APR_ECONNRESET;
|
||||||
}
|
}
|
||||||
return h2_request_add_header(stream->request, stream->pool,
|
return h2_request_add_header(stream->rtmp, stream->pool,
|
||||||
name, nlen, value, vlen);
|
name, nlen, value, vlen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -351,17 +354,12 @@ apr_status_t h2_stream_add_header(h2_stream *stream,
|
|||||||
apr_status_t h2_stream_schedule(h2_stream *stream, int eos, int push_enabled,
|
apr_status_t h2_stream_schedule(h2_stream *stream, int eos, int push_enabled,
|
||||||
h2_stream_pri_cmp *cmp, void *ctx)
|
h2_stream_pri_cmp *cmp, void *ctx)
|
||||||
{
|
{
|
||||||
apr_status_t status;
|
apr_status_t status = APR_EINVAL;
|
||||||
AP_DEBUG_ASSERT(stream);
|
AP_DEBUG_ASSERT(stream);
|
||||||
AP_DEBUG_ASSERT(stream->session);
|
AP_DEBUG_ASSERT(stream->session);
|
||||||
AP_DEBUG_ASSERT(stream->session->mplx);
|
AP_DEBUG_ASSERT(stream->session->mplx);
|
||||||
|
|
||||||
if (!output_open(stream)) {
|
if (!stream->scheduled) {
|
||||||
return APR_ECONNRESET;
|
|
||||||
}
|
|
||||||
if (stream->scheduled) {
|
|
||||||
return APR_EINVAL;
|
|
||||||
}
|
|
||||||
if (eos) {
|
if (eos) {
|
||||||
close_input(stream);
|
close_input(stream);
|
||||||
}
|
}
|
||||||
@@ -370,33 +368,45 @@ apr_status_t h2_stream_schedule(h2_stream *stream, int eos, int push_enabled,
|
|||||||
/* already have a resonse, probably a HTTP error code */
|
/* already have a resonse, probably a HTTP error code */
|
||||||
return h2_mplx_process(stream->session->mplx, stream, cmp, ctx);
|
return h2_mplx_process(stream->session->mplx, stream, cmp, ctx);
|
||||||
}
|
}
|
||||||
|
else if (!stream->request && stream->rtmp) {
|
||||||
/* Seeing the end-of-headers, we have everything we need to
|
/* This is the common case: a h2_request was being assembled, now
|
||||||
* start processing it.
|
* it gets finalized and checked for completness */
|
||||||
*/
|
status = h2_request_end_headers(stream->rtmp, stream->pool,
|
||||||
status = h2_request_end_headers(stream->request, stream->pool,
|
|
||||||
eos, push_enabled);
|
eos, push_enabled);
|
||||||
if (status == APR_SUCCESS) {
|
if (status == APR_SUCCESS) {
|
||||||
stream->request->body = !eos;
|
stream->rtmp->id = stream->id;
|
||||||
|
stream->rtmp->initiated_on = stream->initiated_on;
|
||||||
|
stream->rtmp->serialize = h2_config_geti(stream->session->config,
|
||||||
|
H2_CONF_SER_HEADERS);
|
||||||
|
|
||||||
|
stream->request = stream->rtmp;
|
||||||
|
stream->rtmp = NULL;
|
||||||
stream->scheduled = 1;
|
stream->scheduled = 1;
|
||||||
stream->input_remaining = stream->request->content_length;
|
stream->input_remaining = stream->request->content_length;
|
||||||
|
|
||||||
status = h2_mplx_process(stream->session->mplx, stream, cmp, ctx);
|
status = h2_mplx_process(stream->session->mplx, stream, cmp, ctx);
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, stream->session->c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, stream->session->c,
|
||||||
"h2_stream(%ld-%d): scheduled %s %s://%s%s",
|
"h2_stream(%ld-%d): scheduled %s %s://%s%s "
|
||||||
|
"clen=%ld, body=%d, chunked=%d",
|
||||||
stream->session->id, stream->id,
|
stream->session->id, stream->id,
|
||||||
stream->request->method, stream->request->scheme,
|
stream->request->method, stream->request->scheme,
|
||||||
stream->request->authority, stream->request->path);
|
stream->request->authority, stream->request->path,
|
||||||
|
(long)stream->request->content_length,
|
||||||
|
stream->request->body, stream->request->chunked);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
status = APR_ECONNRESET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
h2_stream_rst(stream, H2_ERR_INTERNAL_ERROR);
|
h2_stream_rst(stream, H2_ERR_INTERNAL_ERROR);
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, stream->session->c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, stream->session->c,
|
||||||
"h2_stream(%ld-%d): RST=2 (internal err) %s %s://%s%s",
|
"h2_stream(%ld-%d): RST=2 (internal err) %s %s://%s%s",
|
||||||
stream->session->id, stream->id,
|
stream->session->id, stream->id,
|
||||||
stream->request->method, stream->request->scheme,
|
stream->request->method, stream->request->scheme,
|
||||||
stream->request->authority, stream->request->path);
|
stream->request->authority, stream->request->path);
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,11 +445,11 @@ apr_status_t h2_stream_write_data(h2_stream *stream,
|
|||||||
if (!stream->input) {
|
if (!stream->input) {
|
||||||
return APR_EOF;
|
return APR_EOF;
|
||||||
}
|
}
|
||||||
if (input_closed(stream) || !stream->request->eoh) {
|
if (input_closed(stream) || !stream->request) {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
||||||
"h2_stream(%ld-%d): writing denied, closed=%d, eoh=%d",
|
"h2_stream(%ld-%d): writing denied, closed=%d, eoh=%d",
|
||||||
stream->session->id, stream->id, input_closed(stream),
|
stream->session->id, stream->id, input_closed(stream),
|
||||||
stream->request->eoh);
|
stream->request != NULL);
|
||||||
return APR_EINVAL;
|
return APR_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -583,8 +593,12 @@ apr_status_t h2_stream_set_error(h2_stream *stream, int http_status)
|
|||||||
if (stream->submitted) {
|
if (stream->submitted) {
|
||||||
return APR_EINVAL;
|
return APR_EINVAL;
|
||||||
}
|
}
|
||||||
response = h2_response_die(stream->id, http_status, stream->request,
|
if (stream->rtmp) {
|
||||||
stream->pool);
|
stream->request = stream->rtmp;
|
||||||
|
stream->rtmp = NULL;
|
||||||
|
}
|
||||||
|
response = h2_response_die(stream->id, http_status,
|
||||||
|
stream->request, stream->pool);
|
||||||
return h2_stream_add_response(stream, response, NULL);
|
return h2_stream_add_response(stream, response, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -714,7 +728,7 @@ apr_table_t *h2_stream_get_trailers(h2_stream *stream)
|
|||||||
|
|
||||||
const h2_priority *h2_stream_get_priority(h2_stream *stream)
|
const h2_priority *h2_stream_get_priority(h2_stream *stream)
|
||||||
{
|
{
|
||||||
if (stream->response && stream->request && stream->request->initiated_on) {
|
if (stream->response && stream->initiated_on) {
|
||||||
const char *ctype = apr_table_get(stream->response->headers, "content-type");
|
const char *ctype = apr_table_get(stream->response->headers, "content-type");
|
||||||
if (ctype) {
|
if (ctype) {
|
||||||
/* FIXME: Not good enough, config needs to come from request->server */
|
/* FIXME: Not good enough, config needs to come from request->server */
|
||||||
|
@@ -43,12 +43,14 @@ typedef struct h2_stream h2_stream;
|
|||||||
|
|
||||||
struct h2_stream {
|
struct h2_stream {
|
||||||
int id; /* http2 stream id */
|
int id; /* http2 stream id */
|
||||||
|
int initiated_on; /* initiating stream id (PUSH) or 0 */
|
||||||
apr_time_t created; /* when stream was created */
|
apr_time_t created; /* when stream was created */
|
||||||
h2_stream_state_t state; /* http/2 state of this stream */
|
h2_stream_state_t state; /* http/2 state of this stream */
|
||||||
struct h2_session *session; /* the session this stream belongs to */
|
struct h2_session *session; /* the session this stream belongs to */
|
||||||
|
|
||||||
apr_pool_t *pool; /* the memory pool for this stream */
|
apr_pool_t *pool; /* the memory pool for this stream */
|
||||||
struct h2_request *request; /* the request made in this stream */
|
const struct h2_request *request; /* the request made in this stream */
|
||||||
|
struct h2_request *rtmp; /* request being assembled */
|
||||||
struct h2_bucket_beam *input;
|
struct h2_bucket_beam *input;
|
||||||
int request_headers_added; /* number of request headers added */
|
int request_headers_added; /* number of request headers added */
|
||||||
|
|
||||||
@@ -83,7 +85,7 @@ struct h2_stream {
|
|||||||
* @return the newly opened stream
|
* @return the newly opened stream
|
||||||
*/
|
*/
|
||||||
h2_stream *h2_stream_open(int id, apr_pool_t *pool, struct h2_session *session,
|
h2_stream *h2_stream_open(int id, apr_pool_t *pool, struct h2_session *session,
|
||||||
int initiated_on, const struct h2_request *req);
|
int initiated_on);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleanup any resources still held by the stream, called by last bucket.
|
* Cleanup any resources still held by the stream, called by last bucket.
|
||||||
@@ -111,6 +113,13 @@ void h2_stream_cleanup(h2_stream *stream);
|
|||||||
*/
|
*/
|
||||||
apr_pool_t *h2_stream_detach_pool(h2_stream *stream);
|
apr_pool_t *h2_stream_detach_pool(h2_stream *stream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize stream->request with the given h2_request.
|
||||||
|
*
|
||||||
|
* @param stream stream to write request to
|
||||||
|
* @param r the request with all the meta data
|
||||||
|
*/
|
||||||
|
apr_status_t h2_stream_set_request(h2_stream *stream, const h2_request *r);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize stream->request with the given request_rec.
|
* Initialize stream->request with the given request_rec.
|
||||||
@@ -118,7 +127,7 @@ apr_pool_t *h2_stream_detach_pool(h2_stream *stream);
|
|||||||
* @param stream stream to write request to
|
* @param stream stream to write request to
|
||||||
* @param r the request with all the meta data
|
* @param r the request with all the meta data
|
||||||
*/
|
*/
|
||||||
apr_status_t h2_stream_set_request(h2_stream *stream, request_rec *r);
|
apr_status_t h2_stream_set_request_rec(h2_stream *stream, request_rec *r);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add a HTTP/2 header (including pseudo headers) or trailer
|
* Add a HTTP/2 header (including pseudo headers) or trailer
|
||||||
|
@@ -89,7 +89,7 @@ static apr_status_t input_handle_eos(h2_task *task, request_rec *r,
|
|||||||
{
|
{
|
||||||
apr_status_t status = APR_SUCCESS;
|
apr_status_t status = APR_SUCCESS;
|
||||||
apr_bucket_brigade *bb = task->input.bb;
|
apr_bucket_brigade *bb = task->input.bb;
|
||||||
apr_table_t *t = task->request? task->request->trailers : NULL;
|
apr_table_t *t = task->request->trailers;
|
||||||
|
|
||||||
if (task->input.chunked) {
|
if (task->input.chunked) {
|
||||||
apr_bucket_brigade *tmp = apr_brigade_split_ex(bb, b, NULL);
|
apr_bucket_brigade *tmp = apr_brigade_split_ex(bb, b, NULL);
|
||||||
@@ -116,7 +116,7 @@ static apr_status_t input_append_eos(h2_task *task, request_rec *r)
|
|||||||
{
|
{
|
||||||
apr_status_t status = APR_SUCCESS;
|
apr_status_t status = APR_SUCCESS;
|
||||||
apr_bucket_brigade *bb = task->input.bb;
|
apr_bucket_brigade *bb = task->input.bb;
|
||||||
apr_table_t *t = task->request? task->request->trailers : NULL;
|
apr_table_t *t = task->request->trailers;
|
||||||
|
|
||||||
if (task->input.chunked) {
|
if (task->input.chunked) {
|
||||||
if (t && !apr_is_empty_table(t)) {
|
if (t && !apr_is_empty_table(t)) {
|
||||||
@@ -153,7 +153,7 @@ static apr_status_t input_read(h2_task *task, ap_filter_t* f,
|
|||||||
return ap_get_brigade(f->c->input_filters, bb, mode, block, readbytes);
|
return ap_get_brigade(f->c->input_filters, bb, mode, block, readbytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f->c->aborted || !task->request) {
|
if (f->c->aborted) {
|
||||||
return APR_ECONNABORTED;
|
return APR_ECONNABORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -578,8 +578,7 @@ apr_status_t h2_task_add_response(h2_task *task, h2_response *response)
|
|||||||
|
|
||||||
int h2_task_can_redo(h2_task *task) {
|
int h2_task_can_redo(h2_task *task) {
|
||||||
if (task->response_sent
|
if (task->response_sent
|
||||||
|| (task->input.beam && h2_beam_was_received(task->input.beam))
|
|| (task->input.beam && h2_beam_was_received(task->input.beam))) {
|
||||||
|| !task->request) {
|
|
||||||
/* cannot repeat that. */
|
/* cannot repeat that. */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -683,6 +682,10 @@ h2_task *h2_task_create(conn_rec *c, const h2_request *req,
|
|||||||
apr_pool_t *pool;
|
apr_pool_t *pool;
|
||||||
h2_task *task;
|
h2_task *task;
|
||||||
|
|
||||||
|
ap_assert(mplx);
|
||||||
|
ap_assert(c);
|
||||||
|
ap_assert(req);
|
||||||
|
|
||||||
apr_pool_create(&pool, c->pool);
|
apr_pool_create(&pool, c->pool);
|
||||||
task = apr_pcalloc(pool, sizeof(h2_task));
|
task = apr_pcalloc(pool, sizeof(h2_task));
|
||||||
if (task == NULL) {
|
if (task == NULL) {
|
||||||
@@ -691,7 +694,6 @@ h2_task *h2_task_create(conn_rec *c, const h2_request *req,
|
|||||||
c->id, req->id);
|
c->id, req->id);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
task->id = apr_psprintf(pool, "%ld-%d", c->id, req->id);
|
task->id = apr_psprintf(pool, "%ld-%d", c->id, req->id);
|
||||||
task->stream_id = req->id;
|
task->stream_id = req->id;
|
||||||
task->c = c;
|
task->c = c;
|
||||||
|
@@ -1276,7 +1276,7 @@ apr_status_t h2_headers_add_h1(apr_table_t *headers, apr_pool_t *pool,
|
|||||||
* h2 request handling
|
* h2 request handling
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
h2_request *h2_req_createn(int id, apr_pool_t *pool, const char *method,
|
h2_request *h2_req_create(int id, apr_pool_t *pool, const char *method,
|
||||||
const char *scheme, const char *authority,
|
const char *scheme, const char *authority,
|
||||||
const char *path, apr_table_t *header, int serialize)
|
const char *path, apr_table_t *header, int serialize)
|
||||||
{
|
{
|
||||||
@@ -1294,49 +1294,6 @@ h2_request *h2_req_createn(int id, apr_pool_t *pool, const char *method,
|
|||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2_request *h2_req_create(int id, apr_pool_t *pool, int serialize)
|
|
||||||
{
|
|
||||||
return h2_req_createn(id, pool, NULL, NULL, NULL, NULL, NULL, serialize);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
apr_table_t *headers;
|
|
||||||
apr_pool_t *pool;
|
|
||||||
} h1_ctx;
|
|
||||||
|
|
||||||
static int set_h1_header(void *ctx, const char *key, const char *value)
|
|
||||||
{
|
|
||||||
h1_ctx *x = ctx;
|
|
||||||
size_t klen = strlen(key);
|
|
||||||
if (!h2_req_ignore_header(key, klen)) {
|
|
||||||
h2_headers_add_h1(x->headers, x->pool, key, klen, value, strlen(value));
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
apr_status_t h2_req_make(h2_request *req, apr_pool_t *pool,
|
|
||||||
const char *method, const char *scheme,
|
|
||||||
const char *authority, const char *path,
|
|
||||||
apr_table_t *headers)
|
|
||||||
{
|
|
||||||
h1_ctx x;
|
|
||||||
|
|
||||||
req->method = method;
|
|
||||||
req->scheme = scheme;
|
|
||||||
req->authority = authority;
|
|
||||||
req->path = path;
|
|
||||||
|
|
||||||
AP_DEBUG_ASSERT(req->scheme);
|
|
||||||
AP_DEBUG_ASSERT(req->authority);
|
|
||||||
AP_DEBUG_ASSERT(req->path);
|
|
||||||
AP_DEBUG_ASSERT(req->method);
|
|
||||||
|
|
||||||
x.pool = pool;
|
|
||||||
x.headers = req->headers;
|
|
||||||
apr_table_do(set_h1_header, &x, headers, NULL);
|
|
||||||
return APR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* frame logging
|
* frame logging
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
@@ -261,16 +261,10 @@ apr_status_t h2_headers_add_h1(apr_table_t *headers, apr_pool_t *pool,
|
|||||||
* h2_request helpers
|
* h2_request helpers
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
struct h2_request *h2_req_createn(int id, apr_pool_t *pool, const char *method,
|
struct h2_request *h2_req_create(int id, apr_pool_t *pool, const char *method,
|
||||||
const char *scheme, const char *authority,
|
const char *scheme, const char *authority,
|
||||||
const char *path, apr_table_t *header,
|
const char *path, apr_table_t *header,
|
||||||
int serialize);
|
int serialize);
|
||||||
struct h2_request *h2_req_create(int id, apr_pool_t *pool, int serialize);
|
|
||||||
|
|
||||||
apr_status_t h2_req_make(struct h2_request *req, apr_pool_t *pool,
|
|
||||||
const char *method, const char *scheme,
|
|
||||||
const char *authority, const char *path,
|
|
||||||
apr_table_t *headers);
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* apr brigade helpers
|
* apr brigade helpers
|
||||||
|
Reference in New Issue
Block a user