summaryrefslogtreecommitdiffstats
path: root/modules/http2/h2_stream.c
diff options
context:
space:
mode:
authorStefan Eissing <icing@apache.org>2022-04-07 12:55:09 +0200
committerStefan Eissing <icing@apache.org>2022-04-07 12:55:09 +0200
commit8ce99f9ef1f08bf4e9c209002ae92b9f08c307f5 (patch)
treebf85a7d03678cada347f2129ac73761954f12ceb /modules/http2/h2_stream.c
parent *) core/mod_http: use RESPONSE meta buckets and a new HTTP/1.x specific (diff)
downloadapache2-8ce99f9ef1f08bf4e9c209002ae92b9f08c307f5.tar.xz
apache2-8ce99f9ef1f08bf4e9c209002ae92b9f08c307f5.zip
*) mod_http2: use the new RESPONSE buckets introduced in r1899648.
This replaces the internal H2_HEADERS bucket, removing its source file and also obsoletes any interim response parsing needs. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1899649 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'modules/http2/h2_stream.c')
-rw-r--r--modules/http2/h2_stream.c127
1 files changed, 79 insertions, 48 deletions
diff --git a/modules/http2/h2_stream.c b/modules/http2/h2_stream.c
index 71c005ff2f..9b879e923a 100644
--- a/modules/http2/h2_stream.c
+++ b/modules/http2/h2_stream.c
@@ -26,6 +26,7 @@
#include <http_core.h>
#include <http_connection.h>
#include <http_log.h>
+#include <http_protocol.h>
#include <http_ssl.h>
#include <nghttp2/nghttp2.h>
@@ -39,7 +40,6 @@
#include "h2_mplx.h"
#include "h2_push.h"
#include "h2_request.h"
-#include "h2_headers.h"
#include "h2_session.h"
#include "h2_stream.h"
#include "h2_c2.h"
@@ -243,15 +243,12 @@ static apr_status_t close_input(h2_stream *stream)
if (!stream->rst_error
&& stream->trailers_in
&& !apr_is_empty_table(stream->trailers_in)) {
- h2_headers *r;
-
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, stream->session->c1,
H2_STRM_MSG(stream, "adding trailers"));
- r = h2_headers_create(HTTP_OK, stream->trailers_in, NULL,
- stream->in_trailer_octets, stream->pool);
- stream->trailers_in = NULL;
- b = h2_bucket_headers_create(c->bucket_alloc, r);
+ b = ap_bucket_headers_create(stream->trailers_in,
+ stream->pool, c->bucket_alloc);
input_append_bucket(stream, b);
+ stream->trailers_in = NULL;
}
stream->input_closed = 1;
@@ -865,12 +862,12 @@ cleanup:
return status;
}
-static apr_bucket *get_first_headers_bucket(apr_bucket_brigade *bb)
+static apr_bucket *get_first_response_bucket(apr_bucket_brigade *bb)
{
if (bb) {
apr_bucket *b = APR_BRIGADE_FIRST(bb);
while (b != APR_BRIGADE_SENTINEL(bb)) {
- if (H2_BUCKET_IS_HEADERS(b)) {
+ if (AP_BUCKET_IS_RESPONSE(b)) {
return b;
}
b = APR_BUCKET_NEXT(b);
@@ -949,7 +946,9 @@ cleanup:
static int bucket_pass_to_c1(apr_bucket *b)
{
- return !H2_BUCKET_IS_HEADERS(b) && !APR_BUCKET_IS_EOS(b);
+ return !AP_BUCKET_IS_RESPONSE(b)
+ && !AP_BUCKET_IS_HEADERS(b)
+ && !APR_BUCKET_IS_EOS(b);
}
apr_status_t h2_stream_read_to(h2_stream *stream, apr_bucket_brigade *bb,
@@ -970,7 +969,8 @@ apr_status_t h2_stream_read_to(h2_stream *stream, apr_bucket_brigade *bb,
static apr_status_t buffer_output_process_headers(h2_stream *stream)
{
conn_rec *c1 = stream->session->c1;
- h2_headers *headers = NULL;
+ ap_bucket_response *resp = NULL;
+ ap_bucket_headers *headers = NULL;
apr_status_t rv = APR_EAGAIN;
int ngrv = 0, is_empty;
h2_ngheader *nh = NULL;
@@ -982,13 +982,22 @@ static apr_status_t buffer_output_process_headers(h2_stream *stream)
while (b != APR_BRIGADE_SENTINEL(stream->out_buffer)) {
e = APR_BUCKET_NEXT(b);
if (APR_BUCKET_IS_METADATA(b)) {
- if (H2_BUCKET_IS_HEADERS(b)) {
- headers = h2_bucket_headers_get(b);
+ if (AP_BUCKET_IS_RESPONSE(b)) {
+ resp = b->data;
+ APR_BUCKET_REMOVE(b);
+ apr_bucket_destroy(b);
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c1,
+ H2_STRM_MSG(stream, "process response %d"),
+ resp->status);
+ b = e;
+ break;
+ }
+ else if (AP_BUCKET_IS_HEADERS(b)) {
+ headers = b->data;
APR_BUCKET_REMOVE(b);
apr_bucket_destroy(b);
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c1,
- H2_STRM_MSG(stream, "process headers, response %d"),
- headers->status);
+ H2_STRM_MSG(stream, "process headers"));
b = e;
break;
}
@@ -1004,32 +1013,32 @@ static apr_status_t buffer_output_process_headers(h2_stream *stream)
}
b = e;
}
- if (!headers) goto cleanup;
- if (stream->response) {
- rv = h2_res_create_ngtrailer(&nh, stream->pool, headers);
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c1,
- H2_STRM_LOG(APLOGNO(03072), stream, "submit %d trailers"),
- (int)nh->nvlen);
- if (APR_SUCCESS != rv) {
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c1,
- H2_STRM_LOG(APLOGNO(10024), stream, "invalid trailers"));
- h2_stream_rst(stream, NGHTTP2_PROTOCOL_ERROR);
+ if (resp) {
+ nghttp2_data_provider provider, *pprovider = NULL;
+
+ if (resp->status < 100) {
+ h2_stream_rst(stream, resp->status);
goto cleanup;
}
- ngrv = nghttp2_submit_trailer(stream->session->ngh2, stream->id, nh->nv, nh->nvlen);
- }
- else if (headers->status < 100) {
- h2_stream_rst(stream, headers->status);
- goto cleanup;
- }
- else {
- nghttp2_data_provider provider, *pprovider = NULL;
+ if (resp->status == HTTP_FORBIDDEN && resp->notes) {
+ const char *cause = apr_table_get(resp->notes, "ssl-renegotiate-forbidden");
+ if (cause) {
+ /* This request triggered a TLS renegotiation that is not allowed
+ * in HTTP/2. Tell the client that it should use HTTP/1.1 for this.
+ */
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, resp->status, c1,
+ H2_STRM_LOG(APLOGNO(03061), stream,
+ "renegotiate forbidden, cause: %s"), cause);
+ h2_stream_rst(stream, H2_ERR_HTTP_1_1_REQUIRED);
+ goto cleanup;
+ }
+ }
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c1,
H2_STRM_LOG(APLOGNO(03073), stream,
- "submit response %d"), headers->status);
+ "submit response %d"), resp->status);
/* If this stream is not a pushed one itself,
* and HTTP/2 server push is enabled here,
@@ -1038,7 +1047,7 @@ static apr_status_t buffer_output_process_headers(h2_stream *stream)
* -> find and perform any pushes on this stream
* *before* we submit the stream response itself.
* This helps clients avoid opening new streams on Link
- * headers that get pushed right afterwards.
+ * resp that get pushed right afterwards.
*
* *) the response code is relevant, as we do not want to
* make pushes on 401 or 403 codes and friends.
@@ -1050,31 +1059,31 @@ static apr_status_t buffer_output_process_headers(h2_stream *stream)
&& !stream->response
&& stream->request && stream->request->method
&& !strcmp("GET", stream->request->method)
- && (headers->status < 400)
- && (headers->status != 304)
+ && (resp->status < 400)
+ && (resp->status != 304)
&& h2_session_push_enabled(stream->session)) {
/* PUSH is possible and enabled on server, unless the request
* denies it, submit resources to push */
- const char *s = apr_table_get(headers->notes, H2_PUSH_MODE_NOTE);
+ const char *s = apr_table_get(resp->notes, H2_PUSH_MODE_NOTE);
if (!s || strcmp(s, "0")) {
- h2_stream_submit_pushes(stream, headers);
+ h2_stream_submit_pushes(stream, resp);
}
}
if (!stream->pref_priority) {
- stream->pref_priority = h2_stream_get_priority(stream, headers);
+ stream->pref_priority = h2_stream_get_priority(stream, resp);
}
h2_session_set_prio(stream->session, stream, stream->pref_priority);
- if (headers->status == 103
+ if (resp->status == 103
&& !h2_config_sgeti(stream->session->s, H2_CONF_EARLY_HINTS)) {
/* suppress sending this to the client, it might have triggered
* pushes and served its purpose nevertheless */
rv = APR_SUCCESS;
goto cleanup;
}
- if (h2_headers_are_final_response(headers)) {
- stream->response = headers;
+ if (resp->status >= 200) {
+ stream->response = resp;
}
/* Do we know if this stream has no response body? */
@@ -1099,7 +1108,7 @@ static apr_status_t buffer_output_process_headers(h2_stream *stream)
pprovider = &provider;
}
- rv = h2_res_create_ngheader(&nh, stream->pool, headers);
+ rv = h2_res_create_ngheader(&nh, stream->pool, resp);
if (APR_SUCCESS != rv) {
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c1,
H2_STRM_LOG(APLOGNO(10025), stream, "invalid response"));
@@ -1115,6 +1124,25 @@ static apr_status_t buffer_output_process_headers(h2_stream *stream)
++stream->session->responses_submitted;
}
}
+ else if (headers) {
+ if (!stream->response) {
+ h2_stream_rst(stream, HTTP_INTERNAL_SERVER_ERROR);
+ goto cleanup;
+ }
+ rv = h2_res_create_ngtrailer(&nh, stream->pool, headers);
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c1,
+ H2_STRM_LOG(APLOGNO(03072), stream, "submit %d trailers"),
+ (int)nh->nvlen);
+ if (APR_SUCCESS != rv) {
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c1,
+ H2_STRM_LOG(APLOGNO(10024), stream, "invalid trailers"));
+ h2_stream_rst(stream, NGHTTP2_PROTOCOL_ERROR);
+ goto cleanup;
+ }
+
+ ngrv = nghttp2_submit_trailer(stream->session->ngh2, stream->id, nh->nv, nh->nvlen);
+ stream->sent_trailers = 1;
+ }
cleanup:
if (nghttp2_is_fatal(ngrv)) {
@@ -1128,7 +1156,7 @@ cleanup:
return rv;
}
-apr_status_t h2_stream_submit_pushes(h2_stream *stream, h2_headers *response)
+apr_status_t h2_stream_submit_pushes(h2_stream *stream, ap_bucket_response *response)
{
apr_status_t status = APR_SUCCESS;
apr_array_header_t *pushes;
@@ -1157,7 +1185,7 @@ apr_table_t *h2_stream_get_trailers(h2_stream *stream)
}
const h2_priority *h2_stream_get_priority(h2_stream *stream,
- h2_headers *response)
+ ap_bucket_response *response)
{
if (response && stream->initiated_on) {
const char *ctype = apr_table_get(response->headers, "content-type");
@@ -1175,7 +1203,7 @@ int h2_stream_is_ready(h2_stream *stream)
if (stream->response) {
return 1;
}
- else if (stream->out_buffer && get_first_headers_bucket(stream->out_buffer)) {
+ else if (stream->out_buffer && get_first_response_bucket(stream->out_buffer)) {
return 1;
}
return 0;
@@ -1268,7 +1296,10 @@ static apr_off_t buffer_output_data_to_send(h2_stream *stream, int *peos)
*peos = 1;
break;
}
- else if (H2_BUCKET_IS_HEADERS(b)) {
+ else if (AP_BUCKET_IS_RESPONSE(b)) {
+ break;
+ }
+ else if (AP_BUCKET_IS_HEADERS(b)) {
break;
}
}