httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From wr...@apache.org
Subject svn commit: r1755118 - /httpd/httpd/trunk/server/protocol.c
Date Wed, 03 Aug 2016 21:51:05 GMT
Author: wrowe
Date: Wed Aug  3 21:51:04 2016
New Revision: 1755118

URL: http://svn.apache.org/viewvc?rev=1755118&view=rev
Log:
Revert to r1754577 based on last_field NULL on first-pass defect 
noted by Jacob Champion, discarding my work of today.


Modified:
    httpd/httpd/trunk/server/protocol.c

Modified: httpd/httpd/trunk/server/protocol.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/protocol.c?rev=1755118&r1=1755117&r2=1755118&view=diff
==============================================================================
--- httpd/httpd/trunk/server/protocol.c (original)
+++ httpd/httpd/trunk/server/protocol.c Wed Aug  3 21:51:04 2016
@@ -790,6 +790,7 @@ AP_DECLARE(void) ap_get_mime_headers_cor
      */
     while(1) {
         apr_status_t rv;
+        int folded = 0;
 
         field = NULL;
         rv = ap_rgetline(&field, r->server->limit_req_fieldsize + 2,
@@ -834,197 +835,196 @@ AP_DECLARE(void) ap_get_mime_headers_cor
             return;
         }
 
-        /* Process an obs-fold immediately by appending it to last_field */
-        if ((*field == '\t') || *field == ' ') {
-
-            apr_size_t fold_len;
-
-            if (last_field == NULL) {
-                r->status = HTTP_BAD_REQUEST;
-                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03442)
-                              "Line folding encountered before first"
-                              " header line");
-                return;
-            }
+        if (last_field != NULL) {
+            if ((len > 0) && ((*field == '\t') || *field == ' ')) {
+                /* This line is a continuation of the preceding line(s),
+                 * so append it to the line that we've set aside.
+                 * Note: this uses a power-of-two allocator to avoid
+                 * doing O(n) allocs and using O(n^2) space for
+                 * continuations that span many many lines.
+                 */
+                apr_size_t fold_len = last_len + len + 1; /* trailing null */
 
-            /* This line is a continuation of the preceding line(s),
-             * so append it to the line that we've set aside.
-             * Note: this uses a power-of-two allocator to avoid
-             * doing O(n) allocs and using O(n^2) space for
-             * continuations that span many many lines.
-             */
-            fold_len = last_len + len + 1; /* trailing null */
+                if (fold_len >= (apr_size_t)(r->server->limit_req_fieldsize)) {
+                    const char *field_escaped;
 
-            if (fold_len >= (apr_size_t)(r->server->limit_req_fieldsize)) {
-                const char *field_escaped;
-
-                r->status = HTTP_BAD_REQUEST;
-                /* report what we have accumulated so far before the
-                 * overflow (last_field) as the field with the problem
-                 */
-                field_escaped = ap_escape_html(r->pool, last_field);
-                apr_table_setn(r->notes, "error-notes",
-                    apr_psprintf(r->pool,
-                                 "Size of a request header field after folding"
-                                 " exceeds server limit.<br />\n"
-                                 "<pre>\n%.*s\n</pre>\n", 
-                                 field_name_len(field_escaped), 
-                                 field_escaped));
-                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00562)
-                              "Request header exceeds LimitRequestFieldSize "
-                              "after folding: %.*s",
-                              field_name_len(last_field), last_field);
-                return;
-            }
+                    r->status = HTTP_BAD_REQUEST;
+                    /* report what we have accumulated so far before the
+                     * overflow (last_field) as the field with the problem
+                     */
+                    field_escaped = ap_escape_html(r->pool, last_field);
+                    apr_table_setn(r->notes, "error-notes",
+                                   apr_psprintf(r->pool,
+                                               "Size of a request header field "
+                                               "after folding "
+                                               "exceeds server limit.<br />\n"
+                                               "<pre>\n%.*s\n</pre>\n", 
+                                               field_name_len(field_escaped), 
+                                               field_escaped));
+                    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00562)
+                                  "Request header exceeds LimitRequestFieldSize "
+                                  "after folding: %.*s",
+                                  field_name_len(last_field), last_field);
+                    return;
+                }
 
-            if (fold_len > alloc_len) {
-                char *fold_buf;
-                alloc_len += alloc_len;
                 if (fold_len > alloc_len) {
-                    alloc_len = fold_len;
+                    char *fold_buf;
+                    alloc_len += alloc_len;
+                    if (fold_len > alloc_len) {
+                        alloc_len = fold_len;
+                    }
+                    fold_buf = (char *)apr_palloc(r->pool, alloc_len);
+                    memcpy(fold_buf, last_field, last_len);
+                    last_field = fold_buf;
                 }
-                fold_buf = (char *)apr_palloc(r->pool, alloc_len);
-                memcpy(fold_buf, last_field, last_len);
-                last_field = fold_buf;
-            }
-            memcpy(last_field + last_len, field, len +1); /* +1 for nul */
-            /* Replace obs-fold w/ SP per RFC 7230 3.2.4 */
-            if (conf->http_conformance & AP_HTTP_CONFORMANCE_STRICT) {
-                last_field[last_len] = ' ';
-            }
-            last_len += len;
-
-            /* The obs-fold continuation line is merged to the last_field
-             * so continue to the next input line
-             */
-            continue;
-        }
-
-        /* Not a continuation line, so process the last_field fully composed */
-
-        if (r->server->limit_req_fields
-                && (++fields_read > r->server->limit_req_fields)) {
-            r->status = HTTP_BAD_REQUEST;
-            apr_table_setn(r->notes, "error-notes",
-                           "The number of request header fields "
-                           "exceeds this server's limit.");
-            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00563)
-                          "Number of request headers exceeds "
-                          "LimitRequestFields");
-            return;
-        }
-
-        if (!(conf->http_conformance & AP_HTTP_CONFORMANCE_STRICT))
-        {
-            /* Not Strict, using the legacy parser */
-
-            if (!(value = strchr(last_field, ':'))) { /* Find ':' or */
-                r->status = HTTP_BAD_REQUEST;   /* abort bad request */
-                apr_table_setn(r->notes, "error-notes",
-                    apr_psprintf(r->pool,
-                                 "Request header field is "
-                                 "missing ':' separator.<br />\n"
-                                 "<pre>\n%.*s</pre>\n", (int)LOG_NAME_MAX_LEN,
-                                 ap_escape_html(r->pool, last_field)));
-                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00564)
-                              "Request header field is missing ':' "
-                              "separator: %.*s", (int)LOG_NAME_MAX_LEN,
-                              last_field);
-                return;
-            }
-
-            tmp_field = value - 1; /* last character of field-name */
-
-            *value++ = '\0'; /* NUL-terminate at colon */
-
-            while (*value == ' ' || *value == '\t') {
-                ++value;            /* Skip to start of value   */
-            }
-
-            /* Strip LWS after field-name: */
-            while (tmp_field > last_field
-                   && (*tmp_field == ' ' || *tmp_field == '\t')) {
-                *tmp_field-- = '\0';
-            }
-
-            /* Strip LWS after field-value: */
-            tmp_field = last_field + last_len - 1;
-            while (tmp_field > value
-                   && (*tmp_field == ' ' || *tmp_field == '\t')) {
-                *tmp_field-- = '\0';
-            }
-        }
-        else /* Using strict RFC7230 parsing */
-        {
-            /* Ensure valid token chars before ':' per RFC 7230 3.2.4 */
-            value = (char *)ap_scan_http_token(last_field);
-            if ((value == last_field) || *value != ':') {
-                r->status = HTTP_BAD_REQUEST;
-                apr_table_setn(r->notes, "error-notes",
-                    apr_psprintf(r->pool,
-                                 "Request header field name"
-                                 " is malformed.<br />\n"
-                                 "<pre>\n%.*s</pre>\n", (int)LOG_NAME_MAX_LEN,
-                                 ap_escape_html(r->pool, last_field)));
-                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02426)
-                              "Request header field name is malformed: "
-                              "%.*s", (int)LOG_NAME_MAX_LEN, last_field);
-                return;
+                memcpy(last_field + last_len, field, len +1); /* +1 for nul */
+                /* Replace obs-fold w/ SP per RFC 7230 3.2.4 */
+                if (conf->http_conformance & AP_HTTP_CONFORMANCE_STRICT) {
+                    last_field[last_len] = ' ';
+                }
+                last_len += len;
+                folded = 1;
             }
+            else /* not a continuation line */ {
 
-            *value++ = '\0'; /* NUL-terminate last_field name at ':' */
+                if (r->server->limit_req_fields
+                    && (++fields_read > r->server->limit_req_fields)) {
+                    r->status = HTTP_BAD_REQUEST;
+                    apr_table_setn(r->notes, "error-notes",
+                                   "The number of request header fields "
+                                   "exceeds this server's limit.");
+                    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00563)
+                                  "Number of request headers exceeds "
+                                  "LimitRequestFields");
+                    return;
+                }
 
-            while (*value == ' ' || *value == '\t') {
-                ++value;     /* Skip LWS of value */
-            }
+                if (!(conf->http_conformance & AP_HTTP_CONFORMANCE_STRICT))
+                {
+                    /* Not Strict, using the legacy parser */
+
+                    if (!(value = strchr(last_field, ':'))) { /* Find ':' or */
+                        r->status = HTTP_BAD_REQUEST;   /* abort bad request */
+                        apr_table_setn(r->notes, "error-notes",
+                            apr_psprintf(r->pool,
+                                         "Request header field is "
+                                         "missing ':' separator.<br />\n"
+                                         "<pre>\n%.*s</pre>\n", 
+                                         (int)LOG_NAME_MAX_LEN,
+                                         ap_escape_html(r->pool,
+                                                        last_field)));
+                        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00564)
+                                      "Request header field is missing ':' "
+                                      "separator: %.*s", (int)LOG_NAME_MAX_LEN,
+                                      last_field);
+                        return;
+                    }
+
+                    tmp_field = value - 1; /* last character of field-name */
+
+                    *value++ = '\0'; /* NUL-terminate at colon */
+
+                    while (*value == ' ' || *value == '\t') {
+                         ++value;            /* Skip to start of value   */
+                    }
+
+                    /* Strip LWS after field-name: */
+                    while (tmp_field > last_field
+                           && (*tmp_field == ' ' || *tmp_field == '\t')) {
+                        *tmp_field-- = '\0';
+                    }
+
+                    /* Strip LWS after field-value: */
+                    tmp_field = last_field + last_len - 1;
+                    while (tmp_field > value
+                           && (*tmp_field == ' ' || *tmp_field == '\t')) {
+                        *tmp_field-- = '\0';
+                    }
+                }
+                else /* Using strict RFC7230 parsing */
+                {
+                    /* Ensure valid token chars before ':' per RFC 7230 3.2.4 */
+                    value = (char *)ap_scan_http_token(last_field);
+                    if ((value == last_field) || *value != ':') {
+                        r->status = HTTP_BAD_REQUEST;
+                        apr_table_setn(r->notes, "error-notes",
+                            apr_psprintf(r->pool,
+                                         "Request header field name "
+                                         "is malformed.<br />\n"
+                                         "<pre>\n%.*s</pre>\n", 
+                                         (int)LOG_NAME_MAX_LEN,
+                                         ap_escape_html(r->pool, last_field)));
+                        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02426)
+                                      "Request header field name is malformed: "
+                                      "%.*s", (int)LOG_NAME_MAX_LEN, last_field);
+                        return;
+                    }
+
+                    *value++ = '\0'; /* NUL-terminate last_field name at ':' */
+
+                    while (*value == ' ' || *value == '\t') {
+                        ++value;     /* Skip LWS of value */
+                    }
 
-            /* Find invalid, non-HT ctrl char, or the trailing NULL */
-            tmp_field = (char *)ap_scan_http_field_content(value);
+                    /* Find invalid, non-HT ctrl char, or the trailing NULL */
+                    tmp_field = (char *)ap_scan_http_field_content(value);
                 
-            /* Strip LWS after field-value, if string not empty */
-            if (*value && (*tmp_field == '\0')) {
-                tmp_field--;
-                while (*tmp_field == ' ' || *tmp_field == '\t') {
-                    *tmp_field-- = '\0';
+                    /* Strip LWS after field-value, if string not empty */
+                    if (*value && (*tmp_field == '\0')) {
+                        tmp_field--;
+                        while (*tmp_field == ' ' || *tmp_field == '\t') {
+                            *tmp_field-- = '\0';
+                        }
+                        ++tmp_field;
+                    }
+
+                    /* Reject value for all garbage input (CTRLs excluding HT)
+                     * e.g. only VCHAR / SP / HT / obs-text are allowed per
+                     * RFC7230 3.2.6 - leave all more explicit rule enforcement
+                     * for specific header handler logic later in the cycle
+                     */
+                    if (*tmp_field != '\0') {
+                        r->status = HTTP_BAD_REQUEST;
+                        apr_table_setn(r->notes, "error-notes",
+                            apr_psprintf(r->pool,
+                                         "Request header value "
+                                         "is malformed.<br />\n"
+                                         "<pre>\n%.*s</pre>\n", 
+                                         (int)LOG_NAME_MAX_LEN,
+                                         ap_escape_html(r->pool, value)));
+                        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02427)
+                                      "Request header value is malformed: "
+                                      "%.*s", (int)LOG_NAME_MAX_LEN, value);
+                        return;
+                    }
                 }
-                ++tmp_field;
-            }
 
-            /* Reject value for all garbage input (CTRLs excluding HT)
-             * e.g. only VCHAR / SP / HT / obs-text are allowed per
-             * RFC7230 3.2.6 - leave all more explicit rule enforcement
-             * for specific header handler logic later in the cycle
-             */
-            if (*tmp_field != '\0') {
-                r->status = HTTP_BAD_REQUEST;
-                apr_table_setn(r->notes, "error-notes",
-                    apr_psprintf(r->pool,
-                                 "Request header value is malformed.<br />\n"
-                                 "<pre>\n%.*s</pre>\n", (int)LOG_NAME_MAX_LEN,
-                                 ap_escape_html(r->pool, value)));
-                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02427)
-                              "Request header value is malformed: "
-                              "%.*s", (int)LOG_NAME_MAX_LEN, value);
-                return;
-            }
-        }
+                apr_table_addn(r->headers_in, last_field, value);
 
-        apr_table_addn(r->headers_in, last_field, value);
+                /* reset the alloc_len so that we'll allocate a new
+                 * buffer if we have to do any more folding: we can't
+                 * use the previous buffer because its contents are
+                 * now part of r->headers_in
+                 */
+                alloc_len = 0;
 
-        /* After recording the last_field header line, we end our read loop
-         * here upon encountering the trailing line terminating headers
-         */
+            } /* end if current line is not a continuation starting with tab */
+        }
+
+        /* Found a blank line, stop. */
         if (len == 0) {
             break;
         }
 
-        /* Keep track of this new header line (not an obs-fold). We will merge
-         * subsequent obs_fold lines on the next loop iterations. The zero
-         * alloc_len signals we have not allocated an obs-folding buffer yet
+        /* Keep track of this line so that we can parse it on
+         * the next loop iteration.  (In the folded case, last_field
+         * has been updated already.)
          */
-        alloc_len = 0;
-        last_field = field;
-        last_len = len;
+        if (!folded) {
+            last_field = field;
+            last_len = len;
+        }
     }
 
     /* Combine multiple message-header fields with the same



Mime
View raw message