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 2019/07/18 12:31:01 UTC

svn commit: r1863276 - in /httpd/httpd/trunk: CHANGES modules/http2/h2_stream.c

Author: icing
Date: Thu Jul 18 12:31:01 2019
New Revision: 1863276

URL: http://svn.apache.org/viewvc?rev=1863276&view=rev
Log:
  *) mod_http2: core setting "LimitRequestFieldSize" is not additionally checked on
     merged header fields, just as HTTP/1.1 does. [Stefan Eissing, Michael Kaufmann]


Modified:
    httpd/httpd/trunk/CHANGES
    httpd/httpd/trunk/modules/http2/h2_stream.c

Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=1863276&r1=1863275&r2=1863276&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Thu Jul 18 12:31:01 2019
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.1
 
+  *) mod_http2: core setting "LimitRequestFieldSize" is not additionally checked on
+     merged header fields, just as HTTP/1.1 does. [Stefan Eissing, Michael Kaufmann]
+
   *) mod_http2: fixed a bug that prevented proper stream cleanup when connection
      throttling was in place. Stream resets by clients on streams initiated by them
      are counted as possible trigger for throttling. [Stefan Eissing] 

Modified: httpd/httpd/trunk/modules/http2/h2_stream.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_stream.c?rev=1863276&r1=1863275&r2=1863276&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_stream.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_stream.c Thu Jul 18 12:31:01 2019
@@ -398,12 +398,7 @@ apr_status_t h2_stream_send_frame(h2_str
                 ap_assert(stream->request == NULL);
                 ap_assert(stream->rtmp != NULL);
                 status = h2_stream_end_headers(stream, 1, 0);
-                if (status != APR_SUCCESS) {
-                    return status;
-                }
-                set_policy_for(stream, stream->rtmp);
-                stream->request = stream->rtmp;
-                stream->rtmp = NULL;
+                if (status != APR_SUCCESS) goto leave;
             break;
             
         default:
@@ -415,6 +410,7 @@ apr_status_t h2_stream_send_frame(h2_str
     if (status == APR_SUCCESS && eos) {
         status = transit(stream, on_event(stream, H2_SEV_CLOSED_L));
     }
+leave:
     return status;
 }
 
@@ -456,12 +452,7 @@ apr_status_t h2_stream_recv_frame(h2_str
                     return APR_EINVAL;
                 }
                 status = h2_stream_end_headers(stream, eos, frame_len);
-                if (status != APR_SUCCESS) {
-                    return status;
-                }
-                set_policy_for(stream, stream->rtmp);
-                stream->request = stream->rtmp;
-                stream->rtmp = NULL;
+                if (status != APR_SUCCESS) goto leave;
             }
             break;
             
@@ -472,6 +463,7 @@ apr_status_t h2_stream_recv_frame(h2_str
     if (status == APR_SUCCESS && eos) {
         status = transit(stream, on_event(stream, H2_SEV_CLOSED_R));
     }
+leave:
     return status;
 }
 
@@ -761,9 +753,45 @@ apr_status_t h2_stream_add_header(h2_str
     return status;
 }
 
+typedef struct {
+    apr_size_t maxlen;
+    const char *failed_key;
+} val_len_check_ctx;
+
+static int table_check_val_len(void *baton, const char *key, const char *value)
+{
+    val_len_check_ctx *ctx = baton;
+
+    if (strlen(value) <= ctx->maxlen) return 1;
+    ctx->failed_key = key;
+    return 0;
+}
+
 apr_status_t h2_stream_end_headers(h2_stream *stream, int eos, size_t raw_bytes)
 {
-    return h2_request_end_headers(stream->rtmp, stream->pool, eos, raw_bytes);
+    apr_status_t status;
+    val_len_check_ctx ctx;
+    
+    status = h2_request_end_headers(stream->rtmp, stream->pool, eos, raw_bytes);
+    if (APR_SUCCESS == status) {
+        set_policy_for(stream, stream->rtmp);
+        stream->request = stream->rtmp;
+        stream->rtmp = NULL;
+        
+        ctx.maxlen = stream->session->s->limit_req_fieldsize;
+        ctx.failed_key = NULL;
+        apr_table_do(table_check_val_len, &ctx, stream->request->headers, NULL);
+        if (ctx.failed_key) {
+            ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, stream->session->c,  
+                          H2_STRM_LOG(APLOGNO(), stream,"Request header exceeds "
+                                      "LimitRequestFieldSize: %.*s"),
+                          (int)H2MIN(strlen(ctx.failed_key), 80), ctx.failed_key);
+            set_error_response(stream, HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE);
+            /* keep on returning APR_SUCCESS, so that we send a HTTP response and
+             * do not RST the stream. */
+        }
+    }
+    return status;
 }
 
 static apr_bucket *get_first_headers_bucket(apr_bucket_brigade *bb)