diff options
author | Stefan Eissing <icing@apache.org> | 2022-04-07 12:55:09 +0200 |
---|---|---|
committer | Stefan Eissing <icing@apache.org> | 2022-04-07 12:55:09 +0200 |
commit | 8ce99f9ef1f08bf4e9c209002ae92b9f08c307f5 (patch) | |
tree | bf85a7d03678cada347f2129ac73761954f12ceb /modules/http2/h2_stream.c | |
parent | *) core/mod_http: use RESPONSE meta buckets and a new HTTP/1.x specific (diff) | |
download | apache2-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.c | 127 |
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; } } |