]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
core,modules: provide/use ap_parse_strict_length() helper.
authorYann Ylavic <ylavic@apache.org>
Wed, 20 May 2020 14:01:17 +0000 (14:01 +0000)
committerYann Ylavic <ylavic@apache.org>
Wed, 20 May 2020 14:01:17 +0000 (14:01 +0000)
It helps simplifying a lot of duplicated code based on apr_strtoff(), while
also rejecting leading plus/minus signs which are dissalowed in Content-Length
and (Content-)Range headers.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1877954 13f79535-47bb-0310-9956-ffa450edef68

19 files changed:
docs/log-message-tags/next-number
include/ap_mmn.h
include/httpd.h
modules/apreq/filter.c
modules/cache/mod_cache.c
modules/cache/mod_cache_disk.c
modules/cache/mod_cache_socache.c
modules/dav/main/mod_dav.c
modules/filters/mod_data.c
modules/filters/mod_reflector.c
modules/filters/mod_request.c
modules/http/byterange_filter.c
modules/http/http_filters.c
modules/mappers/mod_negotiation.c
modules/proxy/mod_proxy.c
modules/proxy/mod_proxy_ajp.c
modules/proxy/mod_proxy_http.c
server/apreq_module_cgi.c
server/util.c

index a45d5ebc997d3f27aac4ced5c1c0eafc5dd47b41..70e6b624f93a32c984231c84a7eb463251c5c52b 100644 (file)
@@ -1 +1 @@
-10242
+10244
index 8ac21c15f4170bde0b2b046644b78a0b828aad05..2a8ce4c2ca93ce02dc8fdb18c64ab86a3dc68c05 100644 (file)
  * 20200420.0 (2.5.1-dev)  Add flags to listen_rec in place of use_specific_errors
  * 20200420.1 (2.5.1-dev)  Add ap_filter_adopt_brigade()
  * 20200420.2 (2.5.1-dev)  Add ap_proxy_worker_can_upgrade()
+ * 20200420.3 (2.5.1-dev)  Add ap_parse_strict_length()
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
 #define MODULE_MAGIC_NUMBER_MAJOR 20200420
 #endif
-#define MODULE_MAGIC_NUMBER_MINOR 2            /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 3            /* 0...n */
 
 /**
  * Determine if the server's current MODULE_MAGIC_NUMBER is at least a
index c3a81ba4464342706a3f9ca2b8c327879c317b31..90293eb74cb0e68ea57502061c31bced08577ced 100644 (file)
@@ -2176,6 +2176,15 @@ AP_DECLARE(char *) ap_escape_quotes(apr_pool_t *p, const char *instring);
 AP_DECLARE(char *) ap_append_pid(apr_pool_t *p, const char *string,
                                  const char *delim);
 
+/**
+ * Parse a length string with decimal characters only, no leading sign nor
+ * trailing character, like Content-Length or (Content-)Range headers.
+ * @param len The parsed length (apr_off_t)
+ * @param str The string to parse
+ * @return 1 (success), 0 (failure)
+ */
+AP_DECLARE(int) ap_parse_strict_length(apr_off_t *len, const char *str);
+
 /**
  * Parse a given timeout parameter string into an apr_interval_time_t value.
  * The unit of the time interval is given as postfix string to the numeric
index d2d8996edac45718fff2fc708c0b6ef1d2d137ed..b4a1a4ebac75c87920f65501bf5d662ec3c8bab3 100644 (file)
@@ -121,18 +121,16 @@ void apreq_filter_init_context(ap_filter_t *f)
     }
 
     cl_header = apr_table_get(r->headers_in, "Content-Length");
-
     if (cl_header != NULL) {
-        char *dummy;
-        apr_uint64_t content_length = apr_strtoi64(cl_header, &dummy, 10);
+        apr_off_t cl;
 
-        if (dummy == NULL || *dummy != 0) {
+        if (!ap_parse_strict_length(&cl, cl_header)) {
             ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, r, APLOGNO(02045)
                           "Invalid Content-Length header (%s)", cl_header);
             ctx->body_status = APREQ_ERROR_BADHEADER;
             return;
         }
-        else if (content_length > ctx->read_limit) {
+        if ((apr_uint64_t)cl > ctx->read_limit) {
             ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, r, APLOGNO(02046)
                           "Content-Length header (%s) exceeds configured "
                           "max_body limit (%" APR_UINT64_T_FMT ")",
index 46aec7e163fe338d305f2f29be016dd6629e3dc8..cb59aae9928191efe2200c311704acb414772123 100644 (file)
@@ -1229,6 +1229,16 @@ static apr_status_t cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in)
         return APR_SUCCESS;
     }
 
+    /* Set the content length if known.
+     */
+    cl = apr_table_get(r->err_headers_out, "Content-Length");
+    if (cl == NULL) {
+        cl = apr_table_get(r->headers_out, "Content-Length");
+    }
+    if (cl && !ap_parse_strict_length(&size, cl)) {
+        reason = "invalid content length";
+    }
+
     if (reason) {
         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00768)
                 "cache: %s not cached for request %s. Reason: %s",
@@ -1251,19 +1261,6 @@ static apr_status_t cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in)
     /* Make it so that we don't execute this path again. */
     cache->in_checked = 1;
 
-    /* Set the content length if known.
-     */
-    cl = apr_table_get(r->err_headers_out, "Content-Length");
-    if (cl == NULL) {
-        cl = apr_table_get(r->headers_out, "Content-Length");
-    }
-    if (cl) {
-        char *errp;
-        if (apr_strtoff(&size, cl, &errp, 10) || *errp || size < 0) {
-            cl = NULL; /* parse error, see next 'if' block */
-        }
-    }
-
     if (!cl) {
         /* if we don't get the content-length, see if we have all the
          * buckets and use their length to calculate the size
index 7392b9981a816c9f4c1399d2b8938c0b72e71059..4b1e0227bf3c419ff064549c4c4ccd7b1fca67f5 100644 (file)
@@ -1276,9 +1276,9 @@ static apr_status_t store_body(cache_handle_t *h, request_rec *r,
      * sanity checks.
      */
     if (seen_eos) {
-        const char *cl_header = apr_table_get(r->headers_out, "Content-Length");
-
         if (!dobj->disk_info.header_only) {
+            const char *cl_header;
+            apr_off_t cl;
 
             if (dobj->data.tempfd) {
                 rv = apr_file_close(dobj->data.tempfd);
@@ -1297,6 +1297,7 @@ static apr_status_t store_body(cache_handle_t *h, request_rec *r,
                 apr_pool_destroy(dobj->data.pool);
                 return APR_EGENERAL;
             }
+
             if (dobj->file_size < dconf->minfs) {
                 ap_log_rerror(
                         APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00734) "URL %s failed the size check "
@@ -1305,17 +1306,16 @@ static apr_status_t store_body(cache_handle_t *h, request_rec *r,
                 apr_pool_destroy(dobj->data.pool);
                 return APR_EGENERAL;
             }
-            if (cl_header) {
-                apr_int64_t cl = apr_atoi64(cl_header);
-                if ((errno == 0) && (dobj->file_size != cl)) {
-                    ap_log_rerror(
-                            APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00735) "URL %s didn't receive complete response, not caching", h->cache_obj->key);
-                    /* Remove the intermediate cache file and return non-APR_SUCCESS */
-                    apr_pool_destroy(dobj->data.pool);
-                    return APR_EGENERAL;
-                }
-            }
 
+            cl_header = apr_table_get(r->headers_out, "Content-Length");
+            if (cl_header && (!ap_parse_strict_length(&cl, cl_header)
+                              || cl != dobj->file_size)) {
+                ap_log_rerror(
+                        APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00735) "URL %s didn't receive complete response, not caching", h->cache_obj->key);
+                /* Remove the intermediate cache file and return non-APR_SUCCESS */
+                apr_pool_destroy(dobj->data.pool);
+                return APR_EGENERAL;
+            }
         }
 
         /* All checks were fine, we're good to go when the commit comes */
index cddda5dbbd90dec1345dfb0b76e3b503dc13a973..f369004a417c4df3ccbac60d62bf11f9bc2b32c5 100644 (file)
@@ -1046,7 +1046,8 @@ static apr_status_t store_body(cache_handle_t *h, request_rec *r,
     /* Was this the final bucket? If yes, perform sanity checks.
      */
     if (seen_eos) {
-        const char *cl_header = apr_table_get(r->headers_out, "Content-Length");
+        const char *cl_header;
+        apr_off_t cl;
 
         if (r->connection->aborted || r->no_cache) {
             ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02380)
@@ -1057,18 +1058,16 @@ static apr_status_t store_body(cache_handle_t *h, request_rec *r,
             sobj->pool = NULL;
             return APR_EGENERAL;
         }
-        if (cl_header) {
-            apr_off_t cl;
-            char *cl_endp;
-            if (apr_strtoff(&cl, cl_header, &cl_endp, 10) != APR_SUCCESS
-                    || *cl_endp != '\0' || cl != sobj->body_length) {
-                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02381)
-                        "URL %s didn't receive complete response, not caching",
-                        h->cache_obj->key);
-                apr_pool_destroy(sobj->pool);
-                sobj->pool = NULL;
-                return APR_EGENERAL;
-            }
+
+        cl_header = apr_table_get(r->headers_out, "Content-Length");
+        if (cl_header && (!ap_parse_strict_length(&cl, cl_header)
+                          || cl != sobj->body_length)) {
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02381)
+                    "URL %s didn't receive complete response, not caching",
+                    h->cache_obj->key);
+            apr_pool_destroy(sobj->pool);
+            sobj->pool = NULL;
+            return APR_EGENERAL;
         }
 
         /* All checks were fine, we're good to go when the commit comes */
index d84db03e09a5d9256c522f14cdcdf56272294721..721c57a16bdba2ffa10d04515590762a6d5994b7 100644 (file)
@@ -814,7 +814,6 @@ static int dav_parse_range(request_rec *r,
     char *range;
     char *dash;
     char *slash;
-    char *errp;
 
     range_c = apr_table_get(r->headers_in, "content-range");
     if (range_c == NULL)
@@ -831,20 +830,19 @@ static int dav_parse_range(request_rec *r,
     *dash++ = *slash++ = '\0';
 
     /* detect invalid ranges */
-    if (apr_strtoff(range_start, range + 6, &errp, 10)
-        || *errp || *range_start < 0) {
+    if (!ap_parse_strict_length(range_start, range + 6)) {
         return -1;
     }
-    if (apr_strtoff(range_end, dash, &errp, 10)
-        || *errp || *range_end < 0 || *range_end < *range_start) {
+    if (!ap_parse_strict_length(range_end, dash)
+            || *range_end < *range_start) {
         return -1;
     }
 
     if (*slash != '*') {
         apr_off_t dummy;
 
-        if (apr_strtoff(&dummy, slash, &errp, 10)
-            || *errp || dummy <= *range_end) {
+        if (!ap_parse_strict_length(&dummy, slash)
+                || dummy <= *range_end) {
             return -1;
         }
     }
@@ -2538,20 +2536,13 @@ static int process_mkcol_body(request_rec *r)
         r->read_chunked = 1;
     }
     else if (lenp) {
-        const char *pos = lenp;
-
-        while (apr_isdigit(*pos) || apr_isspace(*pos)) {
-            ++pos;
-        }
-
-        if (*pos != '\0') {
+        if (!ap_parse_strict_length(&r->remaining, lenp)) {
+            r->remaining = 0;
             /* This supplies additional information for the default message. */
             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00590)
                           "Invalid Content-Length %s", lenp);
             return HTTP_BAD_REQUEST;
         }
-
-        r->remaining = apr_atoi64(lenp);
     }
 
     if (r->read_chunked || r->remaining > 0) {
index d083d322047c429596233de9f7065da649b773d8..ddadd1b360540a3966c30e8cdcf36cb011ef0669 100644 (file)
@@ -107,8 +107,8 @@ static apr_status_t data_out_filter(ap_filter_t *f, apr_bucket_brigade *bb)
         if (content_length) {
             apr_off_t len, clen;
             apr_brigade_length(ctx->bb, 1, &len);
-            clen = apr_atoi64(content_length);
-            if (clen >= 0 && clen < APR_INT32_MAX) {
+            if (ap_parse_strict_length(&clen, content_length)
+                    && clen < APR_INT32_MAX) {
                 ap_set_content_length(r, len +
                                       apr_base64_encode_len((int)clen) - 1);
             }
index 961092d0ea7cb8214f6488a8c54f8641bf8bc15e..5979cb8f727db55f033b56767a65347a27efb26a 100644 (file)
@@ -91,11 +91,16 @@ static int reflector_handler(request_rec * r)
 
         /* reflect the content length, if present */
         if ((content_length = apr_table_get(r->headers_in, "Content-Length"))) {
-            apr_off_t offset;
+            apr_off_t clen;
 
-            apr_strtoff(&offset, content_length, NULL, 10);
-            ap_set_content_length(r, offset);
+            if (!ap_parse_strict_length(&clen, content_length)) {
+                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10243)
+                              "reflector_handler: invalid content-length '%s'",
+                              content_length);
+                return HTTP_BAD_REQUEST;
+            }
 
+            ap_set_content_length(r, clen);
         }
 
         /* reflect the content type, if present */
index 21db7de36cf86c4c79920c56b87ac2dde02994c5..daa8e5977b9d456d23b656c6e056d7ebb27e8ed5 100644 (file)
@@ -76,7 +76,6 @@ static apr_status_t keep_body_filter(ap_filter_t *f, apr_bucket_brigade *b,
 
     if (!ctx) {
         const char *lenp;
-        char *endstr = NULL;
         request_dir_conf *dconf = ap_get_module_config(f->r->per_dir_config,
                                                        &request_module);
 
@@ -93,13 +92,12 @@ static apr_status_t keep_body_filter(ap_filter_t *f, apr_bucket_brigade *b,
         if (lenp) {
 
             /* Protects against over/underflow, non-digit chars in the
-             * string (excluding leading space) (the endstr checks)
-             * and a negative number. */
-            if (apr_strtoff(&ctx->remaining, lenp, &endstr, 10)
-                || endstr == lenp || *endstr || ctx->remaining < 0) {
-
+             * string, leading plus/minus signs, trailing characters and
+             * a negative number.
+             */
+            if (!ap_parse_strict_length(&ctx->remaining, lenp)) {
                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, APLOGNO(01411)
-                              "Invalid Content-Length");
+                              "Invalid Content-Length '%s'", lenp);
 
                 ap_remove_input_filter(f);
                 return bail_out_on_error(b, f, HTTP_REQUEST_ENTITY_TOO_LARGE);
index 5ed90aaa9175cbe2050ceb7f2c2efd419a2259ac..8c5a670c6cb1f0a9a288297610c31e581ce8a218 100644 (file)
@@ -137,7 +137,6 @@ static int ap_set_byterange(request_rec *r, apr_off_t clength,
     *indexes = apr_array_make(r->pool, ranges, sizeof(indexes_t));
     while ((cur = ap_getword(r->pool, &range, ','))) {
         char *dash;
-        char *errp;
         apr_off_t number, start, end;
 
         if (!*cur)
@@ -154,7 +153,7 @@ static int ap_set_byterange(request_rec *r, apr_off_t clength,
 
         if (dash == cur) {
             /* In the form "-5" */
-            if (apr_strtoff(&number, dash+1, &errp, 10) || *errp) {
+            if (!ap_parse_strict_length(&number, dash+1)) {
                 return 0;
             }
             if (number < 1) {
@@ -165,12 +164,12 @@ static int ap_set_byterange(request_rec *r, apr_off_t clength,
         }
         else {
             *dash++ = '\0';
-            if (apr_strtoff(&number, cur, &errp, 10) || *errp) {
+            if (!ap_parse_strict_length(&number, cur)) {
                 return 0;
             }
             start = number;
             if (*dash) {
-                if (apr_strtoff(&number, dash, &errp, 10) || *errp) {
+                if (!ap_parse_strict_length(&number, dash)) {
                     return 0;
                 }
                 end = number;
index 5bebe2c500c13e63dc8234c7dd777247fd38e59e..016bcf5e9708c01e4efc3bb82788bb363fde9488 100644 (file)
@@ -364,16 +364,13 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b,
             lenp = NULL;
         }
         if (lenp) {
-            char *endstr;
-
             ctx->state = BODY_LENGTH;
 
             /* Protects against over/underflow, non-digit chars in the
-             * string (excluding leading space) (the endstr checks)
-             * and a negative number. */
-            if (apr_strtoff(&ctx->remaining, lenp, &endstr, 10)
-                    || endstr == lenp || *endstr || ctx->remaining < 0) {
-
+             * string, leading plus/minus signs, trailing characters and
+             * a negative number.
+             */
+            if (!ap_parse_strict_length(&ctx->remaining, lenp)) {
                 ctx->remaining = 0;
                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, APLOGNO(01587)
                               "Invalid Content-Length");
@@ -1667,13 +1664,10 @@ AP_DECLARE(int) ap_setup_client_block(request_rec *r, int read_policy)
         r->read_chunked = 1;
     }
     else if (lenp) {
-        char *endstr;
-
-        if (apr_strtoff(&r->remaining, lenp, &endstr, 10)
-            || *endstr || r->remaining < 0) {
+        if (!ap_parse_strict_length(&r->remaining, lenp)) {
             r->remaining = 0;
             ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(01594)
-                          "Invalid Content-Length");
+                          "Invalid Content-Length '%s'", lenp);
             return HTTP_BAD_REQUEST;
         }
     }
index dc0211487cf580feac7cc0a0a4f644669cf159b0..c056b284550d1bddcc5def659899cd43fb12b47c 100644 (file)
@@ -988,19 +988,17 @@ static int read_type_map(apr_file_t **map, negotiation_state *neg,
                 has_content = 1;
             }
             else if (!strncmp(buffer, "content-length:", 15)) {
-                char *errp;
-                apr_off_t number;
+                apr_off_t clen;
 
                 body1 = ap_get_token(neg->pool, &body, 0);
-                if (apr_strtoff(&number, body1, &errp, 10) != APR_SUCCESS
-                    || *errp || number < 0) {
+                if (!ap_parse_strict_length(&clen, body1)) {
                     ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00684)
                                   "Parse error in type map, Content-Length: "
                                   "'%s' in %s is invalid.",
                                   body1, r->filename);
                     break;
                 }
-                mime_info.bytes = number;
+                mime_info.bytes = clen;
                 has_content = 1;
             }
             else if (!strncmp(buffer, "content-language:", 17)) {
index c0a44222c8afc913a88ef228706b075558fd148b..edbf1bcc947cbd83bfc49f80097719068a5fad1f 100644 (file)
@@ -1225,7 +1225,6 @@ static int proxy_handler(request_rec *r)
                     /* Did the scheme handler process the request? */
                     if (access_status != DECLINED) {
                         const char *cl_a;
-                        char *end;
                         apr_off_t cl;
 
                         /*
@@ -1235,18 +1234,17 @@ static int proxy_handler(request_rec *r)
                         if (access_status != HTTP_BAD_GATEWAY) {
                             goto cleanup;
                         }
+
                         cl_a = apr_table_get(r->headers_in, "Content-Length");
-                        if (cl_a) {
-                            apr_strtoff(&cl, cl_a, &end, 10);
+                        if (cl_a && (!ap_parse_strict_length(&cl, cl_a)
+                                     || cl > 0)) {
                             /*
                              * The request body is of length > 0. We cannot
                              * retry with a direct connection since we already
                              * sent (parts of) the request body to the proxy
                              * and do not have any longer.
                              */
-                            if (cl > 0) {
-                                goto cleanup;
-                            }
+                            goto cleanup;
                         }
                         /*
                          * Transfer-Encoding was set as input header, so we had
index aa8bc94d7ebb1640ad97649152302a8fe3e48f04..9ae0f437da318cb9ca926815eb5a038390b8b260 100644 (file)
@@ -126,11 +126,8 @@ static apr_off_t get_content_length(request_rec * r)
     if (r->main == NULL) {
         const char *clp = apr_table_get(r->headers_in, "Content-Length");
 
-        if (clp) {
-            char *errp;
-            if (apr_strtoff(&len, clp, &errp, 10) || *errp || len < 0) {
-                len = 0; /* parse error */
-            }
+        if (clp && !ap_parse_strict_length(&len, clp)) {
+            len = -1; /* parse error */
         }
     }
 
@@ -253,10 +250,14 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
     } else {
         /* Get client provided Content-Length header */
         content_length = get_content_length(r);
-        status = ap_get_brigade(r->input_filters, input_brigade,
-                                AP_MODE_READBYTES, APR_BLOCK_READ,
-                                maxsize - AJP_HEADER_SZ);
-
+        if (content_length < 0) {
+            status = APR_EINVAL;
+        }
+        else {
+            status = ap_get_brigade(r->input_filters, input_brigade,
+                                    AP_MODE_READBYTES, APR_BLOCK_READ,
+                                    maxsize - AJP_HEADER_SZ);
+        }
         if (status != APR_SUCCESS) {
             /* We had a failure: Close connection to backend */
             conn->close = 1;
index 739050d2e3c59eff38f49a5e5be556f7ed6cca12..f2857439d20a21fc9f6914868d2eec7d2c21fa66 100644 (file)
@@ -804,9 +804,7 @@ static int ap_proxy_http_prefetch(proxy_http_req_t *req,
     }
     else if (req->old_cl_val) {
         if (r->input_filters == r->proto_input_filters) {
-            char *endstr;
-            status = apr_strtoff(&req->cl_val, req->old_cl_val, &endstr, 10);
-            if (status != APR_SUCCESS || *endstr || req->cl_val < 0) {
+            if (!ap_parse_strict_length(&req->cl_val, req->old_cl_val)) {
                 ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01085)
                               "could not parse request Content-Length (%s)",
                               req->old_cl_val);
index 3b03c378e058a58aecb7af97e2166b19a78f3353..779115dd6e484f3c835cb821855aa9200595dd1a 100644 (file)
@@ -24,6 +24,8 @@
 #include "apr_env.h"
 #include "apreq_util.h"
 
+#include "httpd.h"
+
 #define USER_DATA_KEY "apreq"
 
 /* Parroting APLOG_* ... */
@@ -351,16 +353,15 @@ static void init_body(apreq_handle_t *handle)
     apr_bucket *eos, *pipe;
 
     if (cl_header != NULL) {
-        char *dummy;
-        apr_int64_t content_length = apr_strtoi64(cl_header, &dummy, 10);
+        apr_off_t content_length;
 
-        if (dummy == NULL || *dummy != 0) {
+        if (!ap_parse_strict_length(&content_length, cl_header)) {
             req->body_status = APREQ_ERROR_BADHEADER;
             cgi_log_error(CGILOG_MARK, CGILOG_ERR, req->body_status, handle,
                           "Invalid Content-Length header (%s)", cl_header);
             return;
         }
-        else if ((apr_uint64_t)content_length > req->read_limit) {
+        if ((apr_uint64_t)content_length > req->read_limit) {
             req->body_status = APREQ_ERROR_OVERLIMIT;
             cgi_log_error(CGILOG_MARK, CGILOG_ERR, req->body_status, handle,
                           "Content-Length header (%s) exceeds configured "
index 7603895e02bd5ba6569a30e7d0d04c3d70914a01..59e273e9110ee8acbbd1188bbed305e5a273cac5 100644 (file)
@@ -2673,6 +2673,15 @@ AP_DECLARE(apr_status_t) ap_timeout_parameter_parse(
     return APR_SUCCESS;
 }
 
+AP_DECLARE(int) ap_parse_strict_length(apr_off_t *len, const char *str)
+{
+    char *end;
+
+    return (apr_isdigit(*str)
+            && apr_strtoff(len, str, &end, 10) == APR_SUCCESS
+            && *end == '\0');
+}
+
 /**
  * Determine if a request has a request body or not.
  *
@@ -2682,20 +2691,13 @@ AP_DECLARE(apr_status_t) ap_timeout_parameter_parse(
 AP_DECLARE(int) ap_request_has_body(request_rec *r)
 {
     apr_off_t cl;
-    char *estr;
     const char *cls;
-    int has_body;
-
-    has_body = (!r->header_only
-                && (r->kept_body
-                    || apr_table_get(r->headers_in, "Transfer-Encoding")
-                    || ( (cls = apr_table_get(r->headers_in, "Content-Length"))
-                        && (apr_strtoff(&cl, cls, &estr, 10) == APR_SUCCESS)
-                        && (!*estr)
-                        && (cl > 0) )
-                    )
-                );
-    return has_body;
+
+    return (!r->header_only
+            && (r->kept_body
+                || apr_table_get(r->headers_in, "Transfer-Encoding")
+                || ((cls = apr_table_get(r->headers_in, "Content-Length"))
+                    && ap_parse_strict_length(&cl, cls) && cl > 0)));
 }
 
 /**