]> granicus.if.org Git - apache/commitdiff
core: Add and handle AP_GETLINE_NOSPC_EOL flag in ap_rgetline_core().
authorYann Ylavic <ylavic@apache.org>
Thu, 19 Apr 2018 15:01:10 +0000 (15:01 +0000)
committerYann Ylavic <ylavic@apache.org>
Thu, 19 Apr 2018 15:01:10 +0000 (15:01 +0000)
This tells the ap_getline() family of functions to consume the end of line
when the buffer is exhausted.

PR 62198.

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

CHANGES
include/ap_mmn.h
include/http_protocol.h
server/protocol.c

diff --git a/CHANGES b/CHANGES
index 6057eec2d6f076285b16d4de12dfdee13e75b7c3..a940dada8e1a980cf63df695c7973ace0c23b0ec 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,10 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.1
 
+  *) core: Add and handle AP_GETLINE_NOSPC_EOL flag for ap_getline() family
+     of functions to consume the end of line when the buffer is exhausted.
+     PR 62198. [Yann Ylavic]
+
   *) mod_xml2enc: Fix forwarding of error metadata/responses. PR 62180.
      [Micha Lenk <micha lenk.info>, Yann Ylavic]
 
index b8ed6f25adac2404eb6a5fd56f913f79aeed054b..25cd91b90050c61c9b912c003658ada463179438 100644 (file)
  * 20171014.8 (2.5.1-dev)  Add CONN_STATE_NUM to enum conn_state_e
  * 20171014.9 (2.5.1-dev)  Add response_field_size to proxy_worker_shared 
  * 20180417.1 (2.5.1-dev)  Toggle ap_filter_input|output_pending API to _NONSTD
+ * 20180417.2 (2.5.1-dev)  Add AP_GETLINE_NOSPC_EOL flag to http_protocol.h
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
 #define MODULE_MAGIC_NUMBER_MAJOR 20180417
 #endif
-#define MODULE_MAGIC_NUMBER_MINOR 1                 /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 2                 /* 0...n */
 
 /**
  * Determine if the server's current MODULE_MAGIC_NUMBER is at least a
index 4ddee84adce8be031895b0e7c71722afc3ff5a9a..f38b413b83ebafa9106d38e5a19fca7b284dc277 100644 (file)
@@ -631,7 +631,9 @@ AP_DECLARE(apr_status_t) ap_get_basic_auth_components(const request_rec *r,
 AP_CORE_DECLARE(void) ap_parse_uri(request_rec *r, const char *uri);
 
 #define AP_GETLINE_FOLD 1 /* Whether to merge continuation lines */
-#define AP_GETLINE_CRLF 2 /*Whether line ends must be in the form CR LF */
+#define AP_GETLINE_CRLF 2 /* Whether line ends must be in the form CR LF */
+#define AP_GETLINE_NOSPC_EOL 4 /* Whether to consume up to and including the
+                                  end of line on APR_ENOSPC */
 
 /**
  * Get the next line of input for the request
index 460bf00dd98a69fa2520b273e99578eab3d0c889..d744ce459eaae1252df5c137efb755438ac65a0e 100644 (file)
@@ -224,6 +224,8 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
     int do_alloc = (*s == NULL), saw_eos = 0;
     int fold = flags & AP_GETLINE_FOLD;
     int crlf = flags & AP_GETLINE_CRLF;
+    int nospc_eol = flags & AP_GETLINE_NOSPC_EOL;
+    int saw_eol = 0, saw_nospc = 0;
 
     if (!n) {
         /* Needs room for NUL byte at least */
@@ -239,7 +241,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
     if (last_char)
         *last_char = '\0';
 
-    for (;;) {
+    do {
         apr_brigade_cleanup(bb);
         rv = ap_get_brigade(r->proto_input_filters, bb, AP_MODE_GETLINE,
                             APR_BLOCK_READ, 0);
@@ -283,8 +285,52 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
 
             /* Would this overrun our buffer?  If so, we'll die. */
             if (n < bytes_handled + len) {
-                rv = APR_ENOSPC;
-                goto cleanup;
+                /* Before we die, let's fill the buffer up to its limit (i.e.
+                 * fall through with the remaining length, if any), setting
+                 * saw_eol on LF to stop the outer loop appropriately; we may
+                 * come back here once the buffer is filled (no LF seen), and
+                 * either be done at that time or continue to wait for LF here
+                 * if nospc_eol is set.
+                 *
+                 * But there is also a corner cases which we want to address,
+                 * namely if the buffer is overrun by the final LF only (i.e.
+                 * the CR fits in); this is not really an overrun since we'll
+                 * strip the CR finally (and use it for NUL byte), but anyway
+                 * we have to handle the case so that it's not returned to the
+                 * caller as part of the truncated line (it's not!). This is
+                 * easier to consider that LF is out of counting and thus fall
+                 * through with no error (saw_eol is set to 2 so that we later
+                 * ignore LF handling already done here), while folding and
+                 * nospc_eol logics continue to work (or fail) appropriately.
+                 */
+                saw_eol = (str[len - 1] == APR_ASCII_LF);
+                if (/* First time around */
+                    saw_eol && !saw_nospc
+                    /*  Single LF completing the buffered CR, */
+                    && ((len == 1 && ((*s)[bytes_handled - 1] == APR_ASCII_CR))
+                    /*  or trailing CRLF overuns by LF only */
+                        || (len > 1 && str[len - 2] == APR_ASCII_CR
+                            && n - bytes_handled + 1 == len))) {
+                    /* In both cases *last_char is (to be) the CR stripped by
+                     * later 'bytes_handled = last_char - *s'.
+                     */
+                    saw_eol = 2;
+                }
+                else {
+                    /* In any other case we'd lose data. */
+                    rv = APR_ENOSPC;
+                    saw_nospc = 1;
+                }
+                len = n - bytes_handled;
+                if (!len) {
+                    if (saw_eol) {
+                        break;
+                    }
+                    if (nospc_eol) {
+                        continue;
+                    }
+                    goto cleanup;
+                }
             }
 
             /* Do we have to handle the allocation ourselves? */
@@ -323,18 +369,28 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
 
         /* If we got a full line of input, stop reading */
         if (last_char && (*last_char == APR_ASCII_LF)) {
-            break;
+            saw_eol = 1;
         }
+    } while (!saw_eol);
+
+    if (rv != APR_SUCCESS) {
+        /* End of line after APR_ENOSPC above */
+        goto cleanup;
     }
 
     /* Now terminate the string at the end of the line;
-     * if the last-but-one character is a CR, terminate there */
-    if (last_char > *s && last_char[-1] == APR_ASCII_CR) {
-        last_char--;
-    }
-    else if (crlf) {
-        rv = APR_EINVAL;
-        goto cleanup;
+     * if the last-but-one character is a CR, terminate there.
+     * LF is handled above (not accounted) when saw_eol == 2,
+     * the last char is CR to terminate at still.
+     */
+    if (saw_eol < 2) {
+        if (last_char > *s && last_char[-1] == APR_ASCII_CR) {
+            last_char--;
+        }
+        else if (crlf) {
+            rv = APR_EINVAL;
+            goto cleanup;
+        }
     }
     bytes_handled = last_char - *s;
 
@@ -443,22 +499,22 @@ cleanup:
     if (bytes_handled >= n) {
         bytes_handled = n - 1;
     }
+
+    *read = bytes_handled;
     if (*s) {
         /* ensure the string is NUL terminated */
-        (*s)[bytes_handled] = '\0';
-    }
-    *read = bytes_handled;
-
-    if (rv != APR_SUCCESS) {
-        return rv;
-    }
+        (*s)[*read] = '\0';
 
-    /* PR#43039: We shouldn't accept NULL bytes within the line */
-    if (strlen(*s) < bytes_handled) {
-        return APR_EINVAL;
+        /* PR#43039: We shouldn't accept NULL bytes within the line */
+        bytes_handled = strlen(*s);
+        if (bytes_handled < *read) {
+            *read = bytes_handled;
+            if (rv == APR_SUCCESS) {
+                rv = APR_EINVAL;
+            }
+        }
     }
-
-    return APR_SUCCESS;
+    return rv;
 }
 
 #if APR_CHARSET_EBCDIC