You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ic...@apache.org on 2022/04/07 10:55:09 UTC

svn commit: r1899649 - in /httpd/httpd/trunk: ./ modules/http2/ test/modules/http2/

Author: icing
Date: Thu Apr  7 10:55:09 2022
New Revision: 1899649

URL: http://svn.apache.org/viewvc?rev=1899649&view=rev
Log:
  *) 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.


Removed:
    httpd/httpd/trunk/modules/http2/h2_headers.c
    httpd/httpd/trunk/modules/http2/h2_headers.h
Modified:
    httpd/httpd/trunk/CMakeLists.txt
    httpd/httpd/trunk/modules/http2/NWGNUmod_http2
    httpd/httpd/trunk/modules/http2/config2.m4
    httpd/httpd/trunk/modules/http2/h2.h
    httpd/httpd/trunk/modules/http2/h2_bucket_beam.c
    httpd/httpd/trunk/modules/http2/h2_bucket_eos.c
    httpd/httpd/trunk/modules/http2/h2_c1.c
    httpd/httpd/trunk/modules/http2/h2_c2.c
    httpd/httpd/trunk/modules/http2/h2_c2_filter.c
    httpd/httpd/trunk/modules/http2/h2_c2_filter.h
    httpd/httpd/trunk/modules/http2/h2_conn_ctx.c
    httpd/httpd/trunk/modules/http2/h2_mplx.c
    httpd/httpd/trunk/modules/http2/h2_protocol.c
    httpd/httpd/trunk/modules/http2/h2_push.c
    httpd/httpd/trunk/modules/http2/h2_push.h
    httpd/httpd/trunk/modules/http2/h2_session.c
    httpd/httpd/trunk/modules/http2/h2_stream.c
    httpd/httpd/trunk/modules/http2/h2_stream.h
    httpd/httpd/trunk/modules/http2/h2_util.c
    httpd/httpd/trunk/modules/http2/h2_util.h
    httpd/httpd/trunk/modules/http2/h2_workers.c
    httpd/httpd/trunk/modules/http2/mod_http2.dsp
    httpd/httpd/trunk/test/modules/http2/test_200_header_invalid.py

Modified: httpd/httpd/trunk/CMakeLists.txt
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CMakeLists.txt?rev=1899649&r1=1899648&r2=1899649&view=diff
==============================================================================
--- httpd/httpd/trunk/CMakeLists.txt (original)
+++ httpd/httpd/trunk/CMakeLists.txt Thu Apr  7 10:55:09 2022
@@ -473,7 +473,7 @@ SET(mod_http2_extra_sources
   modules/http2/h2_c1.c              modules/http2/h2_c1_io.c
   modules/http2/h2_c2.c              modules/http2/h2_c2_filter.c
   modules/http2/h2_config.c          modules/http2/h2_conn_ctx.c
-  modules/http2/h2_headers.c         modules/http2/h2_mplx.c
+  modules/http2/h2_mplx.c
   modules/http2/h2_protocol.c        modules/http2/h2_push.c
   modules/http2/h2_request.c         modules/http2/h2_session.c
   modules/http2/h2_stream.c          modules/http2/h2_switch.c

Modified: httpd/httpd/trunk/modules/http2/NWGNUmod_http2
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/NWGNUmod_http2?rev=1899649&r1=1899648&r2=1899649&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/NWGNUmod_http2 (original)
+++ httpd/httpd/trunk/modules/http2/NWGNUmod_http2 Thu Apr  7 10:55:09 2022
@@ -192,7 +192,6 @@ FILES_nlm_objs = \
 	$(OBJDIR)/h2_c2_filter.lo \
 	$(OBJDIR)/h2_config.lo \
 	$(OBJDIR)/h2_conn_ctx.lo \
-	$(OBJDIR)/h2_headers.lo \
 	$(OBJDIR)/h2_mplx.lo \
 	$(OBJDIR)/h2_protocol.lo \
 	$(OBJDIR)/h2_push.lo \

Modified: httpd/httpd/trunk/modules/http2/config2.m4
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/config2.m4?rev=1899649&r1=1899648&r2=1899649&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/config2.m4 (original)
+++ httpd/httpd/trunk/modules/http2/config2.m4 Thu Apr  7 10:55:09 2022
@@ -27,7 +27,6 @@ h2_c2.lo dnl
 h2_c2_filter.lo dnl
 h2_config.lo dnl
 h2_conn_ctx.lo dnl
-h2_headers.lo dnl
 h2_mplx.lo dnl
 h2_protocol.lo dnl
 h2_push.lo dnl

Modified: httpd/httpd/trunk/modules/http2/h2.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2.h?rev=1899649&r1=1899648&r2=1899649&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2.h (original)
+++ httpd/httpd/trunk/modules/http2/h2.h Thu Apr  7 10:55:09 2022
@@ -203,14 +203,6 @@ struct h2_request {
  */
 #define H2_HTTP_STATUS_UNSET (0)
 
-typedef struct h2_headers h2_headers;
-struct h2_headers {
-    int         status;
-    apr_table_t *headers;
-    apr_table_t *notes;
-    apr_off_t   raw_bytes;      /* RAW network bytes that generated this request - if known. */
-};
-
 typedef apr_status_t h2_io_data_cb(void *ctx, const char *data, apr_off_t len);
 
 typedef int h2_stream_pri_cmp_fn(int stream_id1, int stream_id2, void *session);

Modified: httpd/httpd/trunk/modules/http2/h2_bucket_beam.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_bucket_beam.c?rev=1899649&r1=1899648&r2=1899649&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_bucket_beam.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_bucket_beam.c Thu Apr  7 10:55:09 2022
@@ -28,7 +28,6 @@
 
 #include "h2_private.h"
 #include "h2_conn_ctx.h"
-#include "h2_headers.h"
 #include "h2_util.h"
 #include "h2_bucket_beam.h"
 
@@ -637,8 +636,14 @@ transfer:
             else if (APR_BUCKET_IS_FLUSH(bsender)) {
                 brecv = apr_bucket_flush_create(bb->bucket_alloc);
             }
-            else if (H2_BUCKET_IS_HEADERS(bsender)) {
-                brecv = h2_bucket_headers_clone(bsender, bb->p, bb->bucket_alloc);
+            else if (AP_BUCKET_IS_RESPONSE(bsender)) {
+                brecv = ap_bucket_response_clone(bsender, bb->p, bb->bucket_alloc);
+            }
+            else if (AP_BUCKET_IS_REQUEST(bsender)) {
+                brecv = ap_bucket_request_clone(bsender, bb->p, bb->bucket_alloc);
+            }
+            else if (AP_BUCKET_IS_HEADERS(bsender)) {
+                brecv = ap_bucket_headers_clone(bsender, bb->p, bb->bucket_alloc);
             }
             else if (AP_BUCKET_IS_ERROR(bsender)) {
                 ap_bucket_error *eb = bsender->data;

Modified: httpd/httpd/trunk/modules/http2/h2_bucket_eos.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_bucket_eos.c?rev=1899649&r1=1899648&r2=1899649&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_bucket_eos.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_bucket_eos.c Thu Apr  7 10:55:09 2022
@@ -21,6 +21,7 @@
 #include <http_core.h>
 #include <http_connection.h>
 #include <http_log.h>
+#include <http_protocol.h>
 
 #include "h2_private.h"
 #include "h2.h"

Modified: httpd/httpd/trunk/modules/http2/h2_c1.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_c1.c?rev=1899649&r1=1899648&r2=1899649&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_c1.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_c1.c Thu Apr  7 10:55:09 2022
@@ -36,7 +36,6 @@
 #include "h2_bucket_beam.h"
 #include "h2_config.h"
 #include "h2_conn_ctx.h"
-#include "h2_headers.h"
 #include "h2_mplx.h"
 #include "h2_session.h"
 #include "h2_stream.h"

Modified: httpd/httpd/trunk/modules/http2/h2_c2.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_c2.c?rev=1899649&r1=1899648&r2=1899649&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_c2.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_c2.c Thu Apr  7 10:55:09 2022
@@ -45,7 +45,6 @@
 #include "h2_protocol.h"
 #include "h2_mplx.h"
 #include "h2_request.h"
-#include "h2_headers.h"
 #include "h2_session.h"
 #include "h2_stream.h"
 #include "h2_c2.h"
@@ -56,6 +55,11 @@ static module *mpm_module;
 static int mpm_supported = 1;
 static apr_socket_t *dummy_socket;
 
+static ap_filter_rec_t *c2_net_in_filter_handle;
+static ap_filter_rec_t *c2_net_out_filter_handle;
+static ap_filter_rec_t *c2_notes_out_filter_handle;
+
+
 static void check_modules(int force)
 {
     static int checked = 0;
@@ -330,8 +334,11 @@ static apr_status_t beam_out(conn_rec *c
         for (b = APR_BRIGADE_FIRST(bb);
              b != APR_BRIGADE_SENTINEL(bb);
              b = APR_BUCKET_NEXT(b)) {
-            if (H2_BUCKET_IS_HEADERS(b)) {
-                header_len += (apr_off_t)h2_bucket_headers_headers_length(b);
+            if (AP_BUCKET_IS_RESPONSE(b)) {
+                header_len += (apr_off_t)response_length_estimate(b->data);
+            }
+            if (AP_BUCKET_IS_HEADERS(b)) {
+                header_len += (apr_off_t)headers_length_estimate(b->data);
             }
         }
     }
@@ -429,9 +436,8 @@ apr_status_t h2_c2_process(conn_rec *c2,
         ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c2,
                       "h2_c2(%s-%d), adding filters",
                       conn_ctx->id, conn_ctx->stream_id);
-        ap_add_input_filter("H2_C2_NET_IN", NULL, NULL, c2);
-        ap_add_output_filter("H2_C2_NET_CATCH_H1", NULL, NULL, c2);
-        ap_add_output_filter("H2_C2_NET_OUT", NULL, NULL, c2);
+        ap_add_input_filter_handle(c2_net_in_filter_handle, NULL, NULL, c2);
+        ap_add_output_filter_handle(c2_net_out_filter_handle, NULL, NULL, c2);
 
         c2_run_pre_connection(c2, ap_get_conn_socket(c2));
         conn_ctx->pre_conn_done = 1;
@@ -583,16 +589,7 @@ static int h2_c2_hook_post_read_request(
         ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r,
                       "h2_c2(%s-%d): adding request filters",
                       conn_ctx->id, conn_ctx->stream_id);
-
-        /* setup the correct filters to process the request for h2 */
-        ap_add_input_filter("H2_C2_REQUEST_IN", NULL, r, r->connection);
-
-        /* replace the core http filter that formats response headers
-         * in HTTP/1 with our own that collects status and headers */
-        ap_remove_output_filter_byhandle(r->output_filters, "HTTP_HEADER");
-
-        ap_add_output_filter("H2_C2_RESPONSE_OUT", NULL, r, r->connection);
-        ap_add_output_filter("H2_C2_TRAILERS_OUT", NULL, r, r->connection);
+        ap_add_output_filter_handle(c2_notes_out_filter_handle, NULL, r, r->connection);
     }
     return DECLINED;
 }
@@ -623,18 +620,14 @@ void h2_c2_register_hooks(void)
     ap_hook_post_read_request(h2_c2_hook_post_read_request, NULL, NULL, APR_HOOK_REALLY_FIRST);
     ap_hook_fixups(h2_c2_hook_fixups, NULL, NULL, APR_HOOK_LAST);
 
-    ap_register_input_filter("H2_C2_NET_IN", h2_c2_filter_in,
-                             NULL, AP_FTYPE_NETWORK);
-    ap_register_output_filter("H2_C2_NET_OUT", h2_c2_filter_out,
-                              NULL, AP_FTYPE_NETWORK);
-    ap_register_output_filter("H2_C2_NET_CATCH_H1", h2_c2_filter_catch_h1_out,
-                              NULL, AP_FTYPE_NETWORK);
-
-    ap_register_input_filter("H2_C2_REQUEST_IN", h2_c2_filter_request_in,
-                             NULL, AP_FTYPE_PROTOCOL);
-    ap_register_output_filter("H2_C2_RESPONSE_OUT", h2_c2_filter_response_out,
-                              NULL, AP_FTYPE_PROTOCOL);
-    ap_register_output_filter("H2_C2_TRAILERS_OUT", h2_c2_filter_trailers_out,
-                              NULL, AP_FTYPE_PROTOCOL);
+    c2_net_in_filter_handle =
+        ap_register_input_filter("H2_C2_NET_IN", h2_c2_filter_in,
+                                 NULL, AP_FTYPE_NETWORK);
+    c2_net_out_filter_handle =
+        ap_register_output_filter("H2_C2_NET_OUT", h2_c2_filter_out,
+                                  NULL, AP_FTYPE_NETWORK);
+    c2_notes_out_filter_handle =
+        ap_register_output_filter("H2_C2_NOTES_OUT", h2_c2_filter_notes_out,
+                                  NULL, AP_FTYPE_PROTOCOL);
 }
 

Modified: httpd/httpd/trunk/modules/http2/h2_c2_filter.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_c2_filter.c?rev=1899649&r1=1899648&r2=1899649&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_c2_filter.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_c2_filter.c Thu Apr  7 10:55:09 2022
@@ -30,8 +30,9 @@
 #include <util_time.h>
 
 #include "h2_private.h"
+#include "h2.h"
+#include "h2_config.h"
 #include "h2_conn_ctx.h"
-#include "h2_headers.h"
 #include "h2_c1.h"
 #include "h2_c2_filter.h"
 #include "h2_c2.h"
@@ -40,715 +41,49 @@
 #include "h2_util.h"
 
 
-#define H2_FILTER_LOG(name, c, level, rv, msg, bb) \
-    do { \
-        if (APLOG_C_IS_LEVEL((c),(level))) { \
-            char buffer[4 * 1024]; \
-            apr_size_t len, bmax = sizeof(buffer)/sizeof(buffer[0]); \
-            len = h2_util_bb_print(buffer, bmax, "", "", (bb)); \
-            ap_log_cerror(APLOG_MARK, (level), rv, (c), \
-                          "FILTER[%s]: %s %s", \
-                          (name), (msg), len? buffer : ""); \
-        } \
-    } while (0)
-
-
-/* This routine is called by apr_table_do and merges all instances of
- * the passed field values into a single array that will be further
- * processed by some later routine.  Originally intended to help split
- * and recombine multiple Vary fields, though it is generic to any field
- * consisting of comma/space-separated tokens.
- */
-static int uniq_field_values(void *d, const char *key, const char *val)
-{
-    apr_array_header_t *values;
-    char *start;
-    char *e;
-    char **strpp;
-    int  i;
-    
-    (void)key;
-    values = (apr_array_header_t *)d;
-    
-    e = apr_pstrdup(values->pool, val);
-    
-    do {
-        /* Find a non-empty fieldname */
-        
-        while (*e == ',' || apr_isspace(*e)) {
-            ++e;
-        }
-        if (*e == '\0') {
-            break;
-        }
-        start = e;
-        while (*e != '\0' && *e != ',' && !apr_isspace(*e)) {
-            ++e;
-        }
-        if (*e != '\0') {
-            *e++ = '\0';
-        }
-        
-        /* Now add it to values if it isn't already represented.
-         * Could be replaced by a ap_array_strcasecmp() if we had one.
-         */
-        for (i = 0, strpp = (char **) values->elts; i < values->nelts;
-             ++i, ++strpp) {
-            if (*strpp && apr_strnatcasecmp(*strpp, start) == 0) {
-                break;
-            }
-        }
-        if (i == values->nelts) {  /* if not found */
-            *(char **)apr_array_push(values) = start;
-        }
-    } while (*e != '\0');
-    
-    return 1;
-}
-
-/*
- * Since some clients choke violently on multiple Vary fields, or
- * Vary fields with duplicate tokens, combine any multiples and remove
- * any duplicates.
- */
-static void fix_vary(request_rec *r)
-{
-    apr_array_header_t *varies;
-    
-    varies = apr_array_make(r->pool, 5, sizeof(char *));
-    
-    /* Extract all Vary fields from the headers_out, separate each into
-     * its comma-separated fieldname values, and then add them to varies
-     * if not already present in the array.
-     */
-    apr_table_do(uniq_field_values, varies, r->headers_out, "Vary", NULL);
-    
-    /* If we found any, replace old Vary fields with unique-ified value */
-    
-    if (varies->nelts > 0) {
-        apr_table_setn(r->headers_out, "Vary",
-                       apr_array_pstrcat(r->pool, varies, ','));
-    }
-}
-
-static h2_headers *create_response(request_rec *r)
-{
-    const char *clheader;
-    const char *ctype;
-
-    /*
-     * Now that we are ready to send a response, we need to combine the two
-     * header field tables into a single table.  If we don't do this, our
-     * later attempts to set or unset a given fieldname might be bypassed.
-     */
-    if (!apr_is_empty_table(r->err_headers_out)) {
-        r->headers_out = apr_table_overlay(r->pool, r->err_headers_out,
-                                           r->headers_out);
-        apr_table_clear(r->err_headers_out);
-    }
-    
-    /*
-     * Remove the 'Vary' header field if the client can't handle it.
-     * Since this will have nasty effects on HTTP/1.1 caches, force
-     * the response into HTTP/1.0 mode.
-     */
-    if (apr_table_get(r->subprocess_env, "force-no-vary") != NULL) {
-        apr_table_unset(r->headers_out, "Vary");
-        r->proto_num = HTTP_VERSION(1,0);
-        apr_table_setn(r->subprocess_env, "force-response-1.0", "1");
-    }
-    else {
-        fix_vary(r);
-    }
-    
-    /*
-     * Now remove any ETag response header field if earlier processing
-     * says so (such as a 'FileETag None' directive).
-     */
-    if (apr_table_get(r->notes, "no-etag") != NULL) {
-        apr_table_unset(r->headers_out, "ETag");
-    }
-    
-    /* determine the protocol and whether we should use keepalives. */
-    ap_set_keepalive(r);
-    
-    if (AP_STATUS_IS_HEADER_ONLY(r->status)) {
-        apr_table_unset(r->headers_out, "Transfer-Encoding");
-        apr_table_unset(r->headers_out, "Content-Length");
-        r->content_type = r->content_encoding = NULL;
-        r->content_languages = NULL;
-        r->clength = r->chunked = 0;
-    }
-    else if (r->chunked) {
-        apr_table_mergen(r->headers_out, "Transfer-Encoding", "chunked");
-        apr_table_unset(r->headers_out, "Content-Length");
-    }
-
-    ctype = ap_make_content_type(r, r->content_type);
-    if (ctype) {
-        apr_table_setn(r->headers_out, "Content-Type", ctype);
-    }
-    
-    if (r->content_encoding) {
-        apr_table_setn(r->headers_out, "Content-Encoding",
-                       r->content_encoding);
-    }
-    
-    if (!apr_is_empty_array(r->content_languages)) {
-        unsigned int i;
-        char *token;
-        char **languages = (char **)(r->content_languages->elts);
-        const char *field = apr_table_get(r->headers_out, "Content-Language");
-        
-        while (field && (token = ap_get_list_item(r->pool, &field)) != NULL) {
-            for (i = 0; i < r->content_languages->nelts; ++i) {
-                if (!apr_strnatcasecmp(token, languages[i]))
-                    break;
-            }
-            if (i == r->content_languages->nelts) {
-                *((char **) apr_array_push(r->content_languages)) = token;
-            }
-        }
-        
-        field = apr_array_pstrcat(r->pool, r->content_languages, ',');
-        apr_table_setn(r->headers_out, "Content-Language", field);
-    }
-    
-    /*
-     * Control cachability for non-cachable responses if not already set by
-     * some other part of the server configuration.
-     */
-    if (r->no_cache && !apr_table_get(r->headers_out, "Expires")) {
-        char *date = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
-        ap_recent_rfc822_date(date, r->request_time);
-        apr_table_add(r->headers_out, "Expires", date);
-    }
-    
-    /* This is a hack, but I can't find anyway around it.  The idea is that
-     * we don't want to send out 0 Content-Lengths if it is a head request.
-     * This happens when modules try to outsmart the server, and return
-     * if they see a HEAD request.  Apache 1.3 handlers were supposed to
-     * just return in that situation, and the core handled the HEAD.  In
-     * 2.0, if a handler returns, then the core sends an EOS bucket down
-     * the filter stack, and the content-length filter computes a C-L of
-     * zero and that gets put in the headers, and we end up sending a
-     * zero C-L to the client.  We can't just remove the C-L filter,
-     * because well behaved 2.0 handlers will send their data down the stack,
-     * and we will compute a real C-L for the head request. RBB
-     */
-    if (r->header_only
-        && (clheader = apr_table_get(r->headers_out, "Content-Length"))
-        && !strcmp(clheader, "0")) {
-        apr_table_unset(r->headers_out, "Content-Length");
-    }
-    
-    /*
-     * keep the set-by-proxy server and date headers, otherwise
-     * generate a new server header / date header
-     */
-    if (r->proxyreq == PROXYREQ_NONE
-        || !apr_table_get(r->headers_out, "Date")) {
-        char *date = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
-        ap_recent_rfc822_date(date, r->request_time);
-        apr_table_setn(r->headers_out, "Date", date );
-    }
-    if (r->proxyreq == PROXYREQ_NONE
-        || !apr_table_get(r->headers_out, "Server")) {
-        const char *us = ap_get_server_banner();
-        if (us && *us) {
-            apr_table_setn(r->headers_out, "Server", us);
-        }
-    }
-    
-    return h2_headers_rcreate(r, r->status, r->headers_out, r->pool);
-}
-
-typedef enum {
-    H2_RP_STATUS_LINE,
-    H2_RP_HEADER_LINE,
-    H2_RP_DONE
-} h2_rp_state_t;
-
-typedef struct h2_response_parser h2_response_parser;
-struct h2_response_parser {
-    const char *id;
-    h2_rp_state_t state;
-    conn_rec *c;
-    apr_pool_t *pool;
-    int http_status;
-    apr_array_header_t *hlines;
-    apr_bucket_brigade *tmp;
-    apr_bucket_brigade *saveto;
-};
-
-static apr_status_t parse_header(h2_response_parser *parser, char *line) {
-    const char *hline;
-    if (line[0] == ' ' || line[0] == '\t') {
-        char **plast;
-        /* continuation line from the header before this */
-        while (line[0] == ' ' || line[0] == '\t') {
-            ++line;
-        }
-        
-        plast = apr_array_pop(parser->hlines);
-        if (plast == NULL) {
-            /* not well formed */
-            return APR_EINVAL;
-        }
-        hline = apr_psprintf(parser->pool, "%s %s", *plast, line);
-    }
-    else {
-        /* new header line */
-        hline = apr_pstrdup(parser->pool, line);
-    }
-    APR_ARRAY_PUSH(parser->hlines, const char*) = hline; 
-    return APR_SUCCESS;
-}
-
-static apr_status_t get_line(h2_response_parser *parser, apr_bucket_brigade *bb, 
-                             char *line, apr_size_t len)
-{
-    apr_status_t status;
-    
-    if (!parser->tmp) {
-        parser->tmp = apr_brigade_create(parser->pool, parser->c->bucket_alloc);
-    }
-    status = apr_brigade_split_line(parser->tmp, bb, APR_BLOCK_READ, 
-                                    len);
-    if (status == APR_SUCCESS) {
-        --len;
-        status = apr_brigade_flatten(parser->tmp, line, &len);
-        if (status == APR_SUCCESS) {
-            /* we assume a non-0 containing line and remove trailing crlf. */
-            line[len] = '\0';
-            /*
-             * XXX: What to do if there is an LF but no CRLF?
-             *      Should we error out?
-             */
-            if (len >= 2 && !strcmp(H2_CRLF, line + len - 2)) {
-                len -= 2;
-                line[len] = '\0';
-                apr_brigade_cleanup(parser->tmp);
-                ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, parser->c,
-                              "h2_c2(%s): read response line: %s",
-                              parser->id, line);
-            }
-            else {
-                apr_off_t brigade_length;
-
-                /*
-                 * If the brigade parser->tmp becomes longer than our buffer
-                 * for flattening we never have a chance to get a complete
-                 * line. This can happen if we are called multiple times after
-                 * previous calls did not find a H2_CRLF and we returned
-                 * APR_EAGAIN. In this case parser->tmp (correctly) grows
-                 * with each call to apr_brigade_split_line.
-                 *
-                 * XXX: Currently a stack based buffer of HUGE_STRING_LEN is
-                 * used. This means we cannot cope with lines larger than
-                 * HUGE_STRING_LEN which might be an issue.
-                 */
-                status = apr_brigade_length(parser->tmp, 0, &brigade_length);
-                if ((status != APR_SUCCESS) || (brigade_length > len)) {
-                    ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, parser->c, APLOGNO(10257)
-                                  "h2_c2(%s): read response, line too long",
-                                  parser->id);
-                    return APR_ENOSPC;
-                }
-                /* this does not look like a complete line yet */
-                ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, parser->c,
-                              "h2_c2(%s): read response, incomplete line: %s",
-                              parser->id, line);
-                if (!parser->saveto) {
-                    parser->saveto = apr_brigade_create(parser->pool,
-                                                        parser->c->bucket_alloc);
-                }
-                /*
-                 * Be on the save side and save the parser->tmp brigade
-                 * as it could contain transient buckets which could be
-                 * invalid next time we are here.
-                 *
-                 * NULL for the filter parameter is ok since we
-                 * provide our own brigade as second parameter
-                 * and ap_save_brigade does not need to create one.
-                 */
-                ap_save_brigade(NULL, &(parser->saveto), &(parser->tmp),
-                                parser->tmp->p);
-                APR_BRIGADE_CONCAT(parser->tmp, parser->saveto);
-                return APR_EAGAIN;
-            }
-        }
-    }
-    apr_brigade_cleanup(parser->tmp);
-    return status;
-}
-
-static apr_table_t *make_table(h2_response_parser *parser)
-{
-    apr_array_header_t *hlines = parser->hlines;
-    if (hlines) {
-        apr_table_t *headers = apr_table_make(parser->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_cerror(APLOG_MARK, APLOG_WARNING, APR_EINVAL, parser->c,
-                              APLOGNO(02955) "h2_c2(%s): invalid header[%d] '%s'",
-                              parser->id, i, (char*)hline);
-                /* not valid format, abort */
-                return NULL;
-            }
-            (*sep++) = '\0';
-            while (*sep == ' ' || *sep == '\t') {
-                ++sep;
-            }
-            
-            if (!h2_util_ignore_header(hline)) {
-                apr_table_merge(headers, hline, sep);
-            }
-        }
-        return headers;
-    }
-    else {
-        return apr_table_make(parser->pool, 0);
-    }
-}
-
-static apr_status_t pass_response(h2_conn_ctx_t *conn_ctx, ap_filter_t *f,
-                                  h2_response_parser *parser)
+apr_status_t h2_c2_filter_notes_out(ap_filter_t *f, apr_bucket_brigade *bb)
 {
     apr_bucket *b;
-    apr_status_t status;
-    
-    h2_headers *response = h2_headers_create(parser->http_status, 
-                                             make_table(parser),
-                                             NULL, 0, parser->pool);
-    apr_brigade_cleanup(parser->tmp);
-    b = h2_bucket_headers_create(parser->c->bucket_alloc, response);
-    APR_BRIGADE_INSERT_TAIL(parser->tmp, b);
-    b = apr_bucket_flush_create(parser->c->bucket_alloc);
-    APR_BRIGADE_INSERT_TAIL(parser->tmp, b);                      
-    status = ap_pass_brigade(f->next, parser->tmp);
-    apr_brigade_cleanup(parser->tmp);
-    
-    /* reset parser for possible next response */
-    parser->state = H2_RP_STATUS_LINE;
-    apr_array_clear(parser->hlines);
+    request_rec *r_prev;
+    ap_bucket_response *resp;
+    const char *err;
 
-    if (response->status >= 200) {
-        conn_ctx->has_final_response = 1;
+    if (!f->r) {
+        goto pass;
     }
-    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, parser->c,
-                  APLOGNO(03197) "h2_c2(%s): passed response %d",
-                  parser->id, response->status);
-    return status;
-}
 
-static apr_status_t parse_status(h2_response_parser *parser, char *line)
-{
-    int sindex = (apr_date_checkmask(line, "HTTP/#.# ###*")? 9 :
-                  (apr_date_checkmask(line, "HTTP/# ###*")? 7 : 0));
-    if (sindex > 0) {
-        int k = sindex + 3;
-        char keepchar = line[k];
-        line[k] = '\0';
-        parser->http_status = atoi(&line[sindex]);
-        line[k] = keepchar;
-        parser->state = H2_RP_HEADER_LINE;
-        
-        return APR_SUCCESS;
-    }
-    /* Seems like there is garbage on the connection. May be a leftover
-     * from a previous proxy request. 
-     * This should only happen if the H2_RESPONSE filter is not yet in 
-     * place (post_read_request has not been reached and the handler wants
-     * to write something. Probably just the interim response we are
-     * waiting for. But if there is other data hanging around before
-     * that, this needs to fail. */
-    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, parser->c, APLOGNO(03467)
-                  "h2_c2(%s): unable to parse status line: %s",
-                  parser->id, line);
-    return APR_EINVAL;
-}
-
-static apr_status_t parse_response(h2_response_parser *parser,
-                                   h2_conn_ctx_t *conn_ctx,
-                                   ap_filter_t* f, apr_bucket_brigade *bb)
-{
-    char line[HUGE_STRING_LEN];
-    apr_status_t status = APR_SUCCESS;
-
-    while (!APR_BRIGADE_EMPTY(bb) && status == APR_SUCCESS) {
-        switch (parser->state) {
-            case H2_RP_STATUS_LINE:
-            case H2_RP_HEADER_LINE:
-                status = get_line(parser, bb, line, sizeof(line));
-                if (status == APR_EAGAIN) {
-                    /* need more data */
-                    return APR_SUCCESS;
-                }
-                else if (status != APR_SUCCESS) {
-                    return status;
-                }
-                if (parser->state == H2_RP_STATUS_LINE) {
-                    /* instead of parsing, just take it directly */
-                    status = parse_status(parser, line);
-                }
-                else if (line[0] == '\0') {
-                    /* end of headers, pass response onward */
-                    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, parser->c,
-                                  "h2_c2(%s): end of response", parser->id);
-                    return pass_response(conn_ctx, f, parser);
-                }
-                else {
-                    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, parser->c,
-                                  "h2_c2(%s): response header %s", parser->id, line);
-                    status = parse_header(parser, line);
-                }
-                break;
-                
-            default:
-                return status;
-        }
-    }
-    return status;
-}
-
-apr_status_t h2_c2_filter_catch_h1_out(ap_filter_t* f, apr_bucket_brigade* bb)
-{
-    h2_conn_ctx_t *conn_ctx = h2_conn_ctx_get(f->c);
-    h2_response_parser *parser = f->ctx;
-    apr_status_t rv;
-
-    ap_assert(conn_ctx);
-    H2_FILTER_LOG("c2_catch_h1_out", f->c, APLOG_TRACE2, 0, "check", bb);
-
-    if (!conn_ctx->has_final_response) {
-        if (!parser) {
-            parser = apr_pcalloc(f->c->pool, sizeof(*parser));
-            parser->id = apr_psprintf(f->c->pool, "%s-%d", conn_ctx->id, conn_ctx->stream_id);
-            parser->pool = f->c->pool;
-            parser->c = f->c;
-            parser->state = H2_RP_STATUS_LINE;
-            parser->hlines = apr_array_make(parser->pool, 10, sizeof(char *));
-            f->ctx = parser;
-        }
-
-        if (!APR_BRIGADE_EMPTY(bb)) {
-            apr_bucket *b = APR_BRIGADE_FIRST(bb);
-            if (AP_BUCKET_IS_EOR(b)) {
-                /* TODO: Yikes, this happens when errors are encountered on input
-                 * before anything from the repsonse has been processed. The
-                 * ap_die_r() call will do nothing in certain conditions.
+    for (b = APR_BRIGADE_FIRST(bb);
+         b != APR_BRIGADE_SENTINEL(bb);
+         b = APR_BUCKET_NEXT(b))
+    {
+        if (AP_BUCKET_IS_RESPONSE(b)) {
+            resp = b->data;
+            if (resp->status >= 400 && f->r->prev) {
+                /* Error responses are commonly handled via internal
+                 * redirects to error documents. That creates a new
+                 * request_rec with 'prev' set to the original.
+                 * Each of these has its onw 'notes'.
+                 * We'd like to copy interesting ones into the current 'r->notes'
+                 * as we reset HTTP/2 stream with H2 specific error codes then.
                  */
-                int result = ap_map_http_request_error(conn_ctx->last_err,
-                                                       HTTP_INTERNAL_SERVER_ERROR);
-                request_rec *r = h2_create_request_rec(conn_ctx->request, f->c);
-                ap_die((result >= 400)? result : HTTP_INTERNAL_SERVER_ERROR, r);
-                b = ap_bucket_eor_create(f->c->bucket_alloc, r);
-                APR_BRIGADE_INSERT_TAIL(bb, b);
-            }
-        }
-        /* There are cases where we need to parse a serialized http/1.1 response.
-         * One example is a 100-continue answer via a mod_proxy setup. */
-        while (bb && !f->c->aborted && !conn_ctx->has_final_response) {
-            rv = parse_response(parser, conn_ctx, f, bb);
-            ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, f->c,
-                          "h2_c2(%s): parsed response", parser->id);
-            if (APR_BRIGADE_EMPTY(bb) || APR_SUCCESS != rv) {
-                return rv;
-            }
-        }
-    }
-
-    return ap_pass_brigade(f->next, bb);
-}
-
-apr_status_t h2_c2_filter_response_out(ap_filter_t *f, apr_bucket_brigade *bb)
-{
-    h2_conn_ctx_t *conn_ctx = h2_conn_ctx_get(f->c);
-    request_rec *r = f->r;
-    apr_bucket *b, *bresp, *body_bucket = NULL, *next;
-    ap_bucket_error *eb = NULL;
-    h2_headers *response = NULL;
-    int headers_passing = 0;
-
-    H2_FILTER_LOG("c2_response_out", f->c, APLOG_TRACE1, 0, "called with", bb);
-
-    if (f->c->aborted || !conn_ctx || conn_ctx->has_final_response) {
-        return ap_pass_brigade(f->next, bb);
-    }
-
-    if (!conn_ctx->has_final_response) {
-        /* check, if we need to send the response now. Until we actually
-         * see a DATA bucket or some EOS/EOR, we do not do so. */
-        for (b = APR_BRIGADE_FIRST(bb);
-             b != APR_BRIGADE_SENTINEL(bb);
-             b = APR_BUCKET_NEXT(b))
-        {
-            if (AP_BUCKET_IS_ERROR(b) && !eb) {
-                eb = b->data;
+                for (r_prev = f->r; r_prev != NULL; r_prev = r_prev->prev) {
+                    if ((err = apr_table_get(r_prev->notes, "ssl-renegotiate-forbidden"))) {
+                        if (r_prev != f->r) {
+                            apr_table_setn(resp->notes, "ssl-renegotiate-forbidden", err);
+                        }
+                        break;
+                    }
+                }
             }
-            else if (AP_BUCKET_IS_EOC(b)) {
-                /* If we see an EOC bucket it is a signal that we should get out
-                 * of the way doing nothing.
-                 */
-                ap_remove_output_filter(f);
+            else if (h2_config_rgeti(f->r, H2_CONF_PUSH) == 0
+                     && h2_config_sgeti(f->r->server, H2_CONF_PUSH) != 0) {
+                /* location configuration turns off H2 PUSH handling */
                 ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, f->c,
-                              "h2_c2(%s): eoc bucket passed", conn_ctx->id);
-                return ap_pass_brigade(f->next, bb);
+                              "h2_c2_filter_notes_out, turning PUSH off");
+                apr_table_setn(resp->notes, H2_PUSH_MODE_NOTE, "0");
             }
-            else if (H2_BUCKET_IS_HEADERS(b)) {
-                headers_passing = 1;
-            }
-            else if (!APR_BUCKET_IS_FLUSH(b)) {
-                body_bucket = b;
-                break;
-            }
-        }
-
-        if (eb) {
-            int st = eb->status;
-            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, f->c, APLOGNO(03047)
-                          "h2_c2(%s): err bucket status=%d",
-                          conn_ctx->id, st);
-            /* throw everything away and replace it with the error response
-             * generated by ap_die() */
-            apr_brigade_cleanup(bb);
-            ap_die(st, r);
-            return AP_FILTER_ERROR;
-        }
-
-        if (body_bucket || !headers_passing) {
-            /* time to insert the response bucket before the body or if
-             * no h2_headers is passed, e.g. the response is empty */
-            response = create_response(r);
-            if (response == NULL) {
-                ap_log_cerror(APLOG_MARK, APLOG_NOTICE, 0, f->c, APLOGNO(03048)
-                              "h2_c2(%s): unable to create response", conn_ctx->id);
-                return APR_ENOMEM;
-            }
-
-            bresp = h2_bucket_headers_create(f->c->bucket_alloc, response);
-            if (body_bucket) {
-                APR_BUCKET_INSERT_BEFORE(body_bucket, bresp);
-            }
-            else {
-                APR_BRIGADE_INSERT_HEAD(bb, bresp);
-            }
-            conn_ctx->has_final_response = 1;
-            r->sent_bodyct = 1;
-            ap_remove_output_filter_byhandle(f->r->output_filters, "H2_C2_NET_CATCH_H1");
         }
     }
-
-    if (r->header_only || AP_STATUS_IS_HEADER_ONLY(r->status)) {
-        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
-                      "h2_c2(%s): headers only, cleanup output brigade", conn_ctx->id);
-        b = body_bucket? body_bucket : APR_BRIGADE_FIRST(bb);
-        while (b != APR_BRIGADE_SENTINEL(bb)) {
-            next = APR_BUCKET_NEXT(b);
-            if (APR_BUCKET_IS_EOS(b) || AP_BUCKET_IS_EOR(b)) {
-                break;
-            }
-            if (!H2_BUCKET_IS_HEADERS(b)) {
-                APR_BUCKET_REMOVE(b);
-                apr_bucket_destroy(b);
-            }
-            b = next;
-        }
-    }
-    if (conn_ctx->has_final_response) {
-        /* lets get out of the way, our task is done */
-        ap_remove_output_filter(f);
-    }
+pass:
     return ap_pass_brigade(f->next, bb);
 }
-
-
-apr_status_t h2_c2_filter_request_in(ap_filter_t* f,
-                                  apr_bucket_brigade* bb,
-                                  ap_input_mode_t mode,
-                                  apr_read_type_e block,
-                                  apr_off_t readbytes)
-{
-    h2_conn_ctx_t *conn_ctx = h2_conn_ctx_get(f->c);
-    request_rec *r = f->r;
-    apr_status_t status = APR_SUCCESS;
-    apr_bucket *b, *next;
-    core_server_config *conf =
-        (core_server_config *) ap_get_module_config(r->server->module_config,
-                                                    &core_module);
-    ap_assert(conn_ctx);
-
-    ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, f->r,
-                  "h2_c2(%s-%d): request input, exp=%d",
-                  conn_ctx->id, conn_ctx->stream_id, r->expecting_100);
-
-    status = ap_get_brigade(f->next, bb, mode, block, readbytes);
-    /* pipe data through, just take care of trailers */
-    for (b = APR_BRIGADE_FIRST(bb);
-         b != APR_BRIGADE_SENTINEL(bb); b = next) {
-        next = APR_BUCKET_NEXT(b);
-        if (H2_BUCKET_IS_HEADERS(b)) {
-            h2_headers *headers = h2_bucket_headers_get(b);
-            ap_assert(headers);
-            ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
-                          "h2_c2(%s-%d): receiving trailers",
-                          conn_ctx->id, conn_ctx->stream_id);
-            r->trailers_in = headers->headers;
-            if (conf && conf->merge_trailers == AP_MERGE_TRAILERS_ENABLE) {
-                r->headers_in = apr_table_overlay(r->pool, r->headers_in,
-                                                  r->trailers_in);
-            }
-            APR_BUCKET_REMOVE(b);
-            apr_bucket_destroy(b);
-            ap_remove_input_filter(f);
-
-            if (headers->raw_bytes && h2_c_logio_add_bytes_in) {
-                h2_c_logio_add_bytes_in(f->c, headers->raw_bytes);
-            }
-            break;
-        }
-    }
-    return status;
-}
-
-apr_status_t h2_c2_filter_trailers_out(ap_filter_t *f, apr_bucket_brigade *bb)
-{
-    h2_conn_ctx_t *conn_ctx = h2_conn_ctx_get(f->c);
-    request_rec *r = f->r;
-    apr_bucket *b, *e;
- 
-    if (conn_ctx && r) {
-        /* Detect the EOS/EOR bucket and forward any trailers that may have
-         * been set to our h2_headers.
-         */
-        for (b = APR_BRIGADE_FIRST(bb);
-             b != APR_BRIGADE_SENTINEL(bb);
-             b = APR_BUCKET_NEXT(b))
-        {
-            if ((APR_BUCKET_IS_EOS(b) || AP_BUCKET_IS_EOR(b))
-                && r->trailers_out && !apr_is_empty_table(r->trailers_out)) {
-                h2_headers *headers;
-                apr_table_t *trailers;
-                
-                ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, f->c, APLOGNO(03049)
-                              "h2_c2(%s-%d): sending trailers",
-                              conn_ctx->id, conn_ctx->stream_id);
-                trailers = apr_table_clone(r->pool, r->trailers_out);
-                headers = h2_headers_rcreate(r, HTTP_OK, trailers, r->pool);
-                e = h2_bucket_headers_create(bb->bucket_alloc, headers);
-                APR_BUCKET_INSERT_BEFORE(b, e);
-                apr_table_clear(r->trailers_out);
-                ap_remove_output_filter(f);
-                break;
-            }
-        }     
-    }
-     
-    return ap_pass_brigade(f->next, bb);
-}
-

Modified: httpd/httpd/trunk/modules/http2/h2_c2_filter.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_c2_filter.h?rev=1899649&r1=1899648&r2=1899649&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_c2_filter.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_c2_filter.h Thu Apr  7 10:55:09 2022
@@ -31,19 +31,8 @@
  * we need to have all handlers and filters involved in request/response
  * processing, so this seems to be the way for now.
  */
-struct h2_headers;
 struct h2_response_parser;
 
-apr_status_t h2_c2_filter_catch_h1_out(ap_filter_t* f, apr_bucket_brigade* bb);
-
-apr_status_t h2_c2_filter_response_out(ap_filter_t *f, apr_bucket_brigade *bb);
-
-apr_status_t h2_c2_filter_request_in(ap_filter_t* f,
-                                  apr_bucket_brigade* brigade,
-                                  ap_input_mode_t mode,
-                                  apr_read_type_e block,
-                                  apr_off_t readbytes);
-
-apr_status_t h2_c2_filter_trailers_out(ap_filter_t *f, apr_bucket_brigade *bb);
+apr_status_t h2_c2_filter_notes_out(ap_filter_t *f, apr_bucket_brigade *bb);
 
 #endif /* defined(__mod_h2__h2_c2_filter__) */

Modified: httpd/httpd/trunk/modules/http2/h2_conn_ctx.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_conn_ctx.c?rev=1899649&r1=1899648&r2=1899649&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_conn_ctx.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_conn_ctx.c Thu Apr  7 10:55:09 2022
@@ -22,6 +22,7 @@
 #include <http_core.h>
 #include <http_config.h>
 #include <http_log.h>
+#include <http_protocol.h>
 
 #include "h2_private.h"
 #include "h2_session.h"

Modified: httpd/httpd/trunk/modules/http2/h2_mplx.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_mplx.c?rev=1899649&r1=1899648&r2=1899649&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_mplx.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_mplx.c Thu Apr  7 10:55:09 2022
@@ -28,6 +28,7 @@
 #include <http_core.h>
 #include <http_connection.h>
 #include <http_log.h>
+#include <http_protocol.h>
 
 #include <mpm_common.h>
 

Modified: httpd/httpd/trunk/modules/http2/h2_protocol.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_protocol.c?rev=1899649&r1=1899648&r2=1899649&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_protocol.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_protocol.c Thu Apr  7 10:55:09 2022
@@ -39,7 +39,6 @@
 #include "h2_conn_ctx.h"
 #include "h2_c1.h"
 #include "h2_request.h"
-#include "h2_headers.h"
 #include "h2_session.h"
 #include "h2_util.h"
 #include "h2_protocol.h"

Modified: httpd/httpd/trunk/modules/http2/h2_push.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_push.c?rev=1899649&r1=1899648&r2=1899649&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_push.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_push.c Thu Apr  7 10:55:09 2022
@@ -29,13 +29,13 @@
 #include <httpd.h>
 #include <http_core.h>
 #include <http_log.h>
+#include <http_protocol.h>
 
 #include "h2_private.h"
 #include "h2_protocol.h"
 #include "h2_util.h"
 #include "h2_push.h"
 #include "h2_request.h"
-#include "h2_headers.h"
 #include "h2_session.h"
 #include "h2_stream.h"
 
@@ -433,7 +433,7 @@ static int head_iter(void *ctx, const ch
 }
 
 apr_array_header_t *h2_push_collect(apr_pool_t *p, const h2_request *req,
-                                    apr_uint32_t push_policy, const h2_headers *res)
+                                    apr_uint32_t push_policy, const ap_bucket_response *res)
 {
     if (req && push_policy != H2_PUSH_NONE) {
         /* Collect push candidates from the request/response pair.
@@ -675,9 +675,9 @@ apr_array_header_t *h2_push_diary_update
     return npushes;
 }
     
-apr_array_header_t *h2_push_collect_update(h2_stream *stream, 
-                                           const struct h2_request *req, 
-                                           const struct h2_headers *res)
+apr_array_header_t *h2_push_collect_update(struct h2_stream *stream,
+                                           const struct h2_request *req,
+                                           const ap_bucket_response *res)
 {
     apr_array_header_t *pushes;
     

Modified: httpd/httpd/trunk/modules/http2/h2_push.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_push.h?rev=1899649&r1=1899648&r2=1899649&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_push.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_push.h Thu Apr  7 10:55:09 2022
@@ -20,7 +20,6 @@
 #include "h2.h"
 
 struct h2_request;
-struct h2_headers;
 struct h2_ngheader;
 struct h2_session;
 struct h2_stream;
@@ -100,7 +99,7 @@ struct h2_push_diary {
 apr_array_header_t *h2_push_collect(apr_pool_t *p, 
                                     const struct h2_request *req, 
                                     apr_uint32_t push_policy, 
-                                    const struct h2_headers *res);
+                                    const ap_bucket_response *res);
 
 /**
  * Create a new push diary for the given maximum number of entries.
@@ -121,9 +120,9 @@ apr_array_header_t *h2_push_diary_update
  * Collect pushes for the given request/response pair, enter them into the
  * diary and return those pushes newly entered.
  */
-apr_array_header_t *h2_push_collect_update(struct h2_stream *stream, 
-                                           const struct h2_request *req, 
-                                           const struct h2_headers *res);
+apr_array_header_t *h2_push_collect_update(struct h2_stream *stream,
+                                           const struct h2_request *req,
+                                           const ap_bucket_response *res);
 /**
  * Get a cache digest as described in 
  * https://datatracker.ietf.org/doc/draft-kazuho-h2-cache-digest/

Modified: httpd/httpd/trunk/modules/http2/h2_session.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_session.c?rev=1899649&r1=1899648&r2=1899649&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_session.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_session.c Thu Apr  7 10:55:09 2022
@@ -26,6 +26,7 @@
 #include <http_core.h>
 #include <http_config.h>
 #include <http_log.h>
+#include <http_protocol.h>
 #include <scoreboard.h>
 
 #include <mpm_common.h>
@@ -40,7 +41,6 @@
 #include "h2_mplx.h"
 #include "h2_push.h"
 #include "h2_request.h"
-#include "h2_headers.h"
 #include "h2_stream.h"
 #include "h2_c2.h"
 #include "h2_session.h"

Modified: httpd/httpd/trunk/modules/http2/h2_stream.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_stream.c?rev=1899649&r1=1899648&r2=1899649&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_stream.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_stream.c Thu Apr  7 10:55:09 2022
@@ -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_strea
     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
 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_proces
     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_proces
         }
         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_proces
          * -> 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_proces
             && !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_proces
             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_proces
             ++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_s
 }
 
 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_s
                     *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;
                 }
             }

Modified: httpd/httpd/trunk/modules/http2/h2_stream.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_stream.h?rev=1899649&r1=1899648&r2=1899649&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_stream.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_stream.h Thu Apr  7 10:55:09 2022
@@ -26,18 +26,12 @@
  * connection to the client. The h2_session writes to the h2_stream,
  * adding HEADERS and DATA and finally an EOS. When headers are done,
  * h2_stream is scheduled for handling, which is expected to produce
- * a response h2_headers at least.
- * 
- * The h2_headers may be followed by more h2_headers (interim responses) and
- * by DATA frames read from the h2_stream until EOS is reached. Trailers
- * are send when a last h2_headers is received. This always closes the stream
- * output.
+ * RESPONSE buclets.
  */
 
 struct h2_mplx;
 struct h2_priority;
 struct h2_request;
-struct h2_headers;
 struct h2_session;
 struct h2_bucket_beam;
 
@@ -75,7 +69,7 @@ struct h2_stream {
     apr_table_t *trailers_in;   /* optional, incoming trailers */
     int request_headers_added;  /* number of request headers added */
 
-    struct h2_headers *response; /* the final, non-interim response or NULL */
+    ap_bucket_response *response; /* the final, non-interim response or NULL */
 
     struct h2_bucket_beam *input;
     apr_bucket_brigade *in_buffer;
@@ -84,6 +78,8 @@ struct h2_stream {
     
     struct h2_bucket_beam *output;
     apr_bucket_brigade *out_buffer;
+    unsigned int output_eos : 1; /* output EOS in buffer/sent */
+    unsigned int sent_trailers : 1; /* trailers have been submitted */
 
     int rst_error;              /* stream error for RST_STREAM */
     unsigned int aborted   : 1; /* was aborted */
@@ -268,13 +264,13 @@ apr_table_t *h2_stream_get_trailers(h2_s
  *
  * @param stream the stream for which to submit
  */
-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);
 
 /**
  * Get priority information set for this stream.
  */
 const struct h2_priority *h2_stream_get_priority(h2_stream *stream, 
-                                                 h2_headers *response);
+                                                 ap_bucket_response *response);
 
 /**
  * Return a textual representation of the stream state as in RFC 7540

Modified: httpd/httpd/trunk/modules/http2/h2_util.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_util.c?rev=1899649&r1=1899648&r2=1899649&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_util.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_util.c Thu Apr  7 10:55:09 2022
@@ -22,6 +22,7 @@
 #include <httpd.h>
 #include <http_core.h>
 #include <http_log.h>
+#include <http_protocol.h>
 #include <http_request.h>
 
 #include <nghttp2/nghttp2.h>
@@ -1620,30 +1621,30 @@ static apr_status_t ngheader_create(h2_n
     return ctx.status;
 }
 
-static int is_unsafe(h2_headers *h)
+static int is_unsafe(ap_bucket_response *h)
 {
-    const char *v = apr_table_get(h->notes, H2_HDR_CONFORMANCE);
+    const char *v = h->notes? apr_table_get(h->notes, H2_HDR_CONFORMANCE) : NULL;
     return (v && !strcmp(v, H2_HDR_CONFORMANCE_UNSAFE));
 }
 
-apr_status_t h2_res_create_ngtrailer(h2_ngheader **ph, apr_pool_t *p, 
-                                    h2_headers *headers)
+apr_status_t h2_res_create_ngtrailer(h2_ngheader **ph, apr_pool_t *p,
+                                    ap_bucket_headers *headers)
 {
-    return ngheader_create(ph, p, is_unsafe(headers), 
+    return ngheader_create(ph, p, 0,
                            0, NULL, NULL, headers->headers);
 }
                                      
 apr_status_t h2_res_create_ngheader(h2_ngheader **ph, apr_pool_t *p,
-                                    h2_headers *headers) 
+                                    ap_bucket_response *response)
 {
     const char *keys[] = {
         ":status"
     };
     const char *values[] = {
-        apr_psprintf(p, "%d", headers->status)
+        apr_psprintf(p, "%d", response->status)
     };
-    return ngheader_create(ph, p, is_unsafe(headers),  
-                           H2_ALEN(keys), keys, values, headers->headers);
+    return ngheader_create(ph, p, is_unsafe(response),
+                           H2_ALEN(keys), keys, values, response->headers);
 }
 
 apr_status_t h2_req_create_ngheader(h2_ngheader **ph, apr_pool_t *p, 
@@ -1942,3 +1943,24 @@ apr_status_t h2_util_wait_on_pipe(apr_fi
 
     return apr_file_read(pipe, rb, &nr);
 }
+
+static int add_header_lengths(void *ctx, const char *name, const char *value)
+{
+    apr_size_t *plen = ctx;
+    *plen += strlen(name) + strlen(value);
+    return 1;
+}
+
+apr_size_t headers_length_estimate(ap_bucket_headers *hdrs)
+{
+    apr_size_t len = 0;
+    apr_table_do(add_header_lengths, &len, hdrs->headers, NULL);
+    return len;
+}
+
+apr_size_t response_length_estimate(ap_bucket_response *resp)
+{
+    apr_size_t len = 3 + 1 + 8 + (resp->reason? strlen(resp->reason) : 10);
+    apr_table_do(add_header_lengths, &len, resp->headers, NULL);
+    return len;
+}
\ No newline at end of file

Modified: httpd/httpd/trunk/modules/http2/h2_util.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_util.h?rev=1899649&r1=1899648&r2=1899649&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_util.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_util.h Thu Apr  7 10:55:09 2022
@@ -395,17 +395,15 @@ const char *h2_util_base64url_encode(con
 
 int h2_util_ignore_header(const char *name);
 
-struct h2_headers;
-
 typedef struct h2_ngheader {
     nghttp2_nv *nv;
     apr_size_t nvlen;
 } h2_ngheader;
 
 apr_status_t h2_res_create_ngtrailer(h2_ngheader **ph, apr_pool_t *p, 
-                                     struct h2_headers *headers); 
-apr_status_t h2_res_create_ngheader(h2_ngheader **ph, apr_pool_t *p, 
-                                    struct h2_headers *headers); 
+                                     ap_bucket_headers *headers);
+apr_status_t h2_res_create_ngheader(h2_ngheader **ph, apr_pool_t *p,
+                                    ap_bucket_response *response);
 apr_status_t h2_req_create_ngheader(h2_ngheader **ph, apr_pool_t *p, 
                                     const struct h2_request *req);
 
@@ -530,4 +528,16 @@ void h2_util_drain_pipe(apr_file_t *pipe
  */
 apr_status_t h2_util_wait_on_pipe(apr_file_t *pipe);
 
+/**
+ * Give an estimate of the length of the header fields,
+ * without compression or other formatting decorations.
+ */
+apr_size_t headers_length_estimate(ap_bucket_headers *hdrs);
+
+/**
+ * Give an estimate of the length of the response meta data size,
+ * without compression or other formatting decorations.
+ */
+apr_size_t response_length_estimate(ap_bucket_response *resp);
+
 #endif /* defined(__mod_h2__h2_util__) */

Modified: httpd/httpd/trunk/modules/http2/h2_workers.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_workers.c?rev=1899649&r1=1899648&r2=1899649&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_workers.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_workers.c Thu Apr  7 10:55:09 2022
@@ -23,6 +23,7 @@
 #include <httpd.h>
 #include <http_core.h>
 #include <http_log.h>
+#include <http_protocol.h>
 
 #include "h2.h"
 #include "h2_private.h"

Modified: httpd/httpd/trunk/modules/http2/mod_http2.dsp
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/mod_http2.dsp?rev=1899649&r1=1899648&r2=1899649&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/mod_http2.dsp (original)
+++ httpd/httpd/trunk/modules/http2/mod_http2.dsp Thu Apr  7 10:55:09 2022
@@ -133,10 +133,6 @@ SOURCE=./h2_conn_ctx.c
 # End Source File
 # Begin Source File
 
-SOURCE=./h2_headers.c
-# End Source File
-# Begin Source File
-
 SOURCE=./h2_mplx.c
 # End Source File
 # Begin Source File

Modified: httpd/httpd/trunk/test/modules/http2/test_200_header_invalid.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_200_header_invalid.py?rev=1899649&r1=1899648&r2=1899649&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_200_header_invalid.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_200_header_invalid.py Thu Apr  7 10:55:09 2022
@@ -12,24 +12,22 @@ class TestInvalidHeaders:
         assert env.apache_restart() == 0
 
     # let the hecho.py CGI echo chars < 0x20 in field name
-    # for almost all such characters, the stream gets aborted with a h2 error and 
-    # there will be no http status, cr and lf are handled special
+    # for almost all such characters, the stream returns a 500
+    # cr is handled special
     def test_h2_200_01(self, env):
         url = env.mkurl("https", "cgi", "/hecho.py")
         for x in range(1, 32):
             r = env.curl_post_data(url, "name=x%%%02xx&value=yz" % x)
-            if x in [10]:
-                assert 0 == r.exit_code, "unexpected exit code for char 0x%02x" % x
-                assert 500 == r.response["status"], "unexpected status for char 0x%02x" % x
-            elif x in [13]:
+            if x in [13]:
                 assert 0 == r.exit_code, "unexpected exit code for char 0x%02x" % x
                 assert 200 == r.response["status"], "unexpected status for char 0x%02x" % x
             else:
-                assert 0 != r.exit_code, "unexpected exit code for char 0x%02x" % x
+                assert 0 == r.exit_code, "unexpected exit code for char 0x%02x" % x
+                assert 500 == r.response["status"], "unexpected status for char 0x%02x" % x
 
     # let the hecho.py CGI echo chars < 0x20 in field value
-    # for almost all such characters, the stream gets aborted with a h2 error and 
-    # there will be no http status, cr and lf are handled special
+    # for almost all such characters, the stream returns a 500
+    # cr and lf are handled special
     def test_h2_200_02(self, env):
         url = env.mkurl("https", "cgi", "/hecho.py")
         for x in range(1, 32):
@@ -39,17 +37,20 @@ class TestInvalidHeaders:
                     assert 0 == r.exit_code, "unexpected exit code for char 0x%02x" % x
                     assert 200 == r.response["status"], "unexpected status for char 0x%02x" % x
                 else:
-                    assert 0 != r.exit_code, "unexpected exit code for char 0x%02x" % x
+                    assert 0 == r.exit_code, "unexpected exit code for char 0x%02x" % x
+                    assert 500 == r.response["status"], "unexpected status for char 0x%02x" % x
 
     # let the hecho.py CGI echo 0x10 and 0x7f in field name and value
     def test_h2_200_03(self, env):
         url = env.mkurl("https", "cgi", "/hecho.py")
         for h in ["10", "7f"]:
             r = env.curl_post_data(url, "name=x%%%s&value=yz" % h)
-            assert 0 != r.exit_code
+            assert 0 == r.exit_code, "unexpected exit code for char 0x%02x" % h
+            assert 500 == r.response["status"], "unexpected status for char 0x%02x" % h
             r = env.curl_post_data(url, "name=x&value=y%%%sz" % h)
-            assert 0 != r.exit_code
-    
+            assert 0 == r.exit_code, "unexpected exit code for char 0x%02x" % h
+            assert 500 == r.response["status"], "unexpected status for char 0x%02x" % h
+
     # test header field lengths check, LimitRequestLine (default 8190)
     def test_h2_200_10(self, env):
         url = env.mkurl("https", "cgi", "/")