httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From wr...@apache.org
Subject svn commit: r1769669 [2/2] - in /httpd/httpd/branches/2.4.x-merge-http-strict: ./ docs/manual/ docs/manual/mod/ include/ server/
Date Mon, 14 Nov 2016 17:59:10 GMT
Modified: httpd/httpd/branches/2.4.x-merge-http-strict/server/gen_test_char.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-merge-http-strict/server/gen_test_char.c?rev=1769669&r1=1769668&r2=1769669&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x-merge-http-strict/server/gen_test_char.c (original)
+++ httpd/httpd/branches/2.4.x-merge-http-strict/server/gen_test_char.c Mon Nov 14 17:59:10
2016
@@ -53,11 +53,12 @@
 #define T_ESCAPE_FORENSIC     (0x20)
 #define T_ESCAPE_URLENCODED   (0x40)
 #define T_HTTP_CTRLS          (0x80)
+#define T_URI_RFC3986        (0x100)
 
 int main(int argc, char *argv[])
 {
     unsigned c;
-    unsigned char flags;
+    unsigned short flags;
 
     printf("/* this file is automatically generated by gen_test_char, "
            "do not edit */\n"
@@ -69,8 +70,9 @@ int main(int argc, char *argv[])
            "#define T_ESCAPE_FORENSIC      (%u)\n"
            "#define T_ESCAPE_URLENCODED    (%u)\n"
            "#define T_HTTP_CTRLS           (%u)\n"
+           "#define T_URI_RFC3986          (%u)\n"
            "\n"
-           "static const unsigned char test_char_table[256] = {",
+           "static const unsigned short test_char_table[256] = {",
            T_ESCAPE_SHELL_CMD,
            T_ESCAPE_PATH_SEGMENT,
            T_OS_ESCAPE_PATH,
@@ -78,7 +80,8 @@ int main(int argc, char *argv[])
            T_ESCAPE_LOGITEM,
            T_ESCAPE_FORENSIC,
            T_ESCAPE_URLENCODED,
-           T_HTTP_CTRLS);
+           T_HTTP_CTRLS,
+           T_URI_RFC3986);
 
     for (c = 0; c < 256; ++c) {
         flags = 0;
@@ -110,7 +113,7 @@ int main(int argc, char *argv[])
             flags |= T_ESCAPE_PATH_SEGMENT;
         }
 
-        if (!apr_isalnum(c) && !strchr("$-_.+!*'(),:@&=/~", c)) {
+        if (!apr_isalnum(c) && !strchr("$-_.+!*'(),:;@&=/~", c)) {
             flags |= T_OS_ESCAPE_PATH;
         }
 
@@ -122,7 +125,7 @@ int main(int argc, char *argv[])
          * and "tspecials" (RFC2068) a.k.a. "separators" (RFC2616), which
          * is easer to express as characters remaining in the ASCII token set
          */
-        if (!(apr_isalnum(c) || strchr("!#$%&'*+-.^_`|~", c))) {
+        if (!c || !(apr_isalnum(c) || strchr("!#$%&'*+-.^_`|~", c))) {
             flags |= T_HTTP_TOKEN_STOP;
         }
 
@@ -136,6 +139,17 @@ int main(int argc, char *argv[])
             flags |= T_HTTP_CTRLS;
         }
 
+        /* From RFC3986, the specific sets of gen-delims, sub-delims (2.2),
+         * and unreserved (2.3) that are possible somewhere within a URI.
+         * Spec requires all others to be %XX encoded, including obs-text.
+         */
+        if (c && (strchr("%"                              /* pct-encode */
+                         ":/?#[]@"                        /* gen-delims */ 
+                         "!$&'()*+,;="                    /* sub-delims */
+                         "-._~", c) || apr_isalnum(c))) { /* unreserved */
+            flags |= T_URI_RFC3986;
+        }
+
         /* For logging, escape all control characters,
          * double quotes (because they delimit the request in the log file)
          * backslashes (because we use backslash for escaping)
@@ -153,7 +167,7 @@ int main(int argc, char *argv[])
             flags |= T_ESCAPE_FORENSIC;
         }
 
-        printf("0x%02x%c", flags, (c < 255) ? ',' : ' ');
+        printf("0x%03x%c", flags, (c < 255) ? ',' : ' ');
     }
 
     printf("\n};\n");

Modified: httpd/httpd/branches/2.4.x-merge-http-strict/server/protocol.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-merge-http-strict/server/protocol.c?rev=1769669&r1=1769668&r2=1769669&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x-merge-http-strict/server/protocol.c (original)
+++ httpd/httpd/branches/2.4.x-merge-http-strict/server/protocol.c Mon Nov 14 17:59:10 2016
@@ -204,7 +204,7 @@ AP_DECLARE(apr_time_t) ap_rationalize_mt
  * APR_ENOSPC is returned if there is not enough buffer space.
  * Other errors may be returned on other errors.
  *
- * The LF is *not* returned in the buffer.  Therefore, a *read of 0
+ * The [CR]LF are *not* returned in the buffer.  Therefore, a *read of 0
  * indicates that an empty line was read.
  *
  * Notes: Because the buffer uses 1 char for NUL, the most we can return is
@@ -215,13 +215,15 @@ AP_DECLARE(apr_time_t) ap_rationalize_mt
  */
 AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
                                           apr_size_t *read, request_rec *r,
-                                          int fold, apr_bucket_brigade *bb)
+                                          int flags, apr_bucket_brigade *bb)
 {
     apr_status_t rv;
     apr_bucket *e;
     apr_size_t bytes_handled = 0, current_alloc = 0;
     char *pos, *last_char = *s;
     int do_alloc = (*s == NULL), saw_eos = 0;
+    int fold = flags & AP_GETLINE_FOLD;
+    int crlf = flags & AP_GETLINE_CRLF;
 
     /*
      * Initialize last_char as otherwise a random value will be compared
@@ -327,6 +329,13 @@ AP_DECLARE(apr_status_t) ap_rgetline_cor
         }
     }
 
+    if (crlf && (last_char <= *s || last_char[-1] != APR_ASCII_CR)) {
+        *last_char = '\0';
+        bytes_handled = last_char - *s;
+        *read = bytes_handled;
+        return APR_EINVAL;
+    }
+
     /* Now NUL-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) {
@@ -471,7 +480,7 @@ AP_DECLARE(apr_status_t) ap_rgetline(cha
 }
 #endif
 
-AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int fold)
+AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int flags)
 {
     char *tmp_s = s;
     apr_status_t rv;
@@ -479,7 +488,7 @@ AP_DECLARE(int) ap_getline(char *s, int
     apr_bucket_brigade *tmp_bb;
 
     tmp_bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
-    rv = ap_rgetline(&tmp_s, n, &len, r, fold, tmp_bb);
+    rv = ap_rgetline(&tmp_s, n, &len, r, flags, tmp_bb);
     apr_brigade_destroy(tmp_bb);
 
     /* Map the out-of-space condition to the old API. */
@@ -573,7 +582,8 @@ static int read_request_line(request_rec
 {
     enum {
         rrl_none, rrl_badmethod, rrl_badwhitespace, rrl_excesswhitespace,
-        rrl_missinguri, rrl_badprotocol, rrl_trailingtext
+        rrl_missinguri, rrl_baduri, rrl_badprotocol, rrl_trailingtext,
+        rrl_badmethod09, rrl_reject09
     } deferred_error = rrl_none;
     char *ll;
     char *uri;
@@ -581,8 +591,7 @@ static int read_request_line(request_rec
     int num_blank_lines = DEFAULT_LIMIT_BLANK_LINES;
     core_server_config *conf = ap_get_core_module_config(r->server->module_config);
     int strict = (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE);
-    const char *badwhitespace = strict ? "\t\n\v\f\r" : "\n\v\f\r";
-    int strictspaces = (conf->http_whitespace == AP_HTTP_WHITESPACE_STRICT);
+    int stricturi = (conf->http_stricturi != AP_HTTP_URI_UNSAFE);
 
     /* Read past empty lines until we get a real request line,
      * a read error, the connection closes (EOF), or we timeout.
@@ -607,7 +616,7 @@ static int read_request_line(request_rec
          */
         r->the_request = NULL;
         rv = ap_rgetline(&(r->the_request), (apr_size_t)(r->server->limit_req_line
+ 2),
-                         &len, r, 0, bb);
+                         &len, r, strict ? AP_GETLINE_CRLF : 0, bb);
 
         if (rv != APR_SUCCESS) {
             r->request_time = apr_time_now();
@@ -640,14 +649,21 @@ static int read_request_line(request_rec
     r->request_time = apr_time_now();
 
     r->method = r->the_request;
-    if (apr_isspace(*r->method))
-        deferred_error = rrl_excesswhitespace; 
-    for ( ; apr_isspace(*r->method); ++r->method)
-        ; 
 
+    /* If there is whitespace before a method, skip it and mark in error */
+    if (apr_isspace(*r->method)) {
+        deferred_error = rrl_badwhitespace; 
+        for ( ; apr_isspace(*r->method); ++r->method)
+            ; 
+    }
+
+    /* Scan the method up to the next whitespace, ensure it contains only
+     * valid http-token characters, otherwise mark in error
+     */
     if (strict) {
         ll = (char*) ap_scan_http_token(r->method);
-        if ((ll == r->method) || (*ll && !apr_isspace(*ll))) {
+        if (((ll == r->method) || (*ll && !apr_isspace(*ll)))
+                && deferred_error == rrl_none) {
             deferred_error = rrl_badmethod;
             ll = strpbrk(ll, "\t\n\v\f\r ");
         }
@@ -655,6 +671,8 @@ static int read_request_line(request_rec
     else {
         ll = strpbrk(r->method, "\t\n\v\f\r ");
     }
+
+    /* Verify method terminated with a single SP, or mark as specific error */
     if (!ll) {
         if (deferred_error == rrl_none)
             deferred_error = rrl_missinguri;
@@ -662,47 +680,84 @@ static int read_request_line(request_rec
         len = 0;
         goto rrl_done;
     }
-
-    if (strictspaces && ll[0] && (ll[0] != ' ' || apr_isspace(ll[1]))
-            && deferred_error == rrl_none) {
+    else if (strict && ll[0] && (ll[0] != ' ' || apr_isspace(ll[1]))
+                 && deferred_error == rrl_none) {
         deferred_error = rrl_excesswhitespace; 
     }
+
+    /* Advance uri pointer over leading whitespace, NUL terminate the method
+     * If non-SP whitespace is encountered, mark as specific error
+     */
     for (uri = ll; apr_isspace(*uri); ++uri) 
-        if (ap_strchr_c(badwhitespace, *uri) && deferred_error == rrl_none)
+        if (ap_strchr_c("\t\n\v\f\r", *uri)
+                && deferred_error == rrl_none)
             deferred_error = rrl_badwhitespace; 
     *ll = '\0';
+
     if (!*uri && deferred_error == rrl_none)
         deferred_error = rrl_missinguri;
 
-    if (!(ll = strpbrk(uri, " \t\n\v\f\r"))) {
+    /* Scan the URI up to the next whitespace, ensure it contains only
+     * valid RFC3986 characters, otherwise mark in error
+     */
+    if (stricturi) {
+        ll = (char*) ap_scan_http_uri_safe(uri);
+        if (ll == uri || (*ll && !apr_isspace(*ll))) {
+            deferred_error = rrl_baduri;
+            ll = strpbrk(ll, "\t\n\v\f\r ");
+        }
+    }
+    else {
+        ll = strpbrk(uri, "\t\n\v\f\r ");
+    }
+
+    /* Verify method terminated with a single SP, or mark as specific error */
+    if (!ll) {
         r->protocol = "";
         len = 0;
         goto rrl_done;
     }
+    else if (strict && ll[0] && (ll[0] != ' ' || apr_isspace(ll[1]))
+            && deferred_error == rrl_none) {
+        deferred_error = rrl_excesswhitespace; 
+    }
+
+    /* Advance protocol pointer over leading whitespace, NUL terminate the uri
+     * If non-SP whitespace is encountered, mark as specific error
+     */
     for (r->protocol = ll; apr_isspace(*r->protocol); ++r->protocol) 
-        if (ap_strchr_c(badwhitespace, *r->protocol) && deferred_error == rrl_none)
+        if (ap_strchr_c("\t\n\v\f\r", *r->protocol)
+                && deferred_error == rrl_none)
             deferred_error = rrl_badwhitespace; 
     *ll = '\0';
+
+    /* Scan the protocol up to the next whitespace, validation comes later */
     if (!(ll = strpbrk(r->protocol, " \t\n\v\f\r"))) {
         len = strlen(r->protocol);
         goto rrl_done;
     }
     len = ll - r->protocol;
-    if (strictspaces && *ll)
-        deferred_error = rrl_excesswhitespace; 
-    for ( ; apr_isspace(*ll); ++ll)
-        if (ap_strchr_c(badwhitespace, *ll) && deferred_error == rrl_none)
-            deferred_error = rrl_badwhitespace; 
-    if (*ll && deferred_error == rrl_none)
-        deferred_error = rrl_trailingtext;
-    ll = (char *)r->protocol + len;
-    *ll = '\0';
+
+    /* Advance over trailing whitespace, if found mark in error,
+     * determine if trailing text is found, unconditionally mark in error,
+     * finally NUL terminate the protocol string
+     */
+    if (strict && *ll) {
+        deferred_error = rrl_excesswhitespace;
+    }
+    else {
+        for ( ; apr_isspace(*ll); ++ll)
+            if (ap_strchr_c("\t\n\v\f\r", *ll)
+                    && deferred_error == rrl_none)
+                deferred_error = rrl_badwhitespace; 
+        if (*ll && deferred_error == rrl_none)
+            deferred_error = rrl_trailingtext;
+    }
+    *((char *)r->protocol + len) = '\0';
 
 rrl_done:
-    /* For internal integrety, reconstruct the_request
-     * using only single SP characters, per spec.
-     * Once the method, uri and protocol are processed,
-     * we can then resume deferred error reporting
+    /* For internal integrety and palloc efficiency, reconstruct the_request
+     * in one palloc, using only single SP characters, per spec.
      */
     r->the_request = apr_pstrcat(r->pool, r->method, *uri ? " " : NULL, uri,
                                  *r->protocol ? " " : NULL, r->protocol, NULL);
@@ -746,7 +801,7 @@ rrl_done:
         r->proto_num = HTTP_VERSION(0, 9);
     }
 
-    /* Satisfy the method_number and uri fields prior to invoking error
+    /* Determine the method_number and parse the uri prior to invoking error
      * handling, such that these fields are available for subsitution
      */
     r->method_number = ap_method_number_of(r->method);
@@ -755,99 +810,118 @@ rrl_done:
 
     ap_parse_uri(r, uri);
 
-    if (r->proto_num == HTTP_VERSION(0, 9)) {
-        if (conf->http09_enable == AP_HTTP09_DISABLE
-                && deferred_error == rrl_none) {
-            /* If we deny 0.9, send error message with 1.x behavior */
-            r->assbackwards = 0;
-            r->connection->keepalive = AP_CONN_CLOSE;
-            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02401)
-                          "HTTP Request Line; Rejected HTTP/0.9 request");
-            r->status = HTTP_VERSION_NOT_SUPPORTED;
-            return 0;
-        }
-        if (strict && strcmp(r->method, "GET") && deferred_error == rrl_none)
{
-            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03444)
-                          "HTTP Request Line; Invalid method token: '%.*s'"
-                          " (only GET is allowed for HTTP/0.9 requests)",
-                          field_name_len(r->method), r->method);
-            r->status = HTTP_BAD_REQUEST;
-            return 0;
-        }
+    /* With the request understood, we can consider HTTP/0.9 specific errors */
+    if (r->proto_num == HTTP_VERSION(0, 9) && deferred_error == rrl_none) {
+        if (conf->http09_enable == AP_HTTP09_DISABLE)
+            deferred_error = rrl_reject09;
+        else if (strict && (r->method_number != M_GET || r->header_only))
+            deferred_error = rrl_badmethod09;
     }
 
+    /* Now that the method, uri and protocol are all processed,
+     * we can safely resume any deferred error reporting
+     */
     if (deferred_error != rrl_none) {
         if (deferred_error == rrl_badmethod)
-            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03445)
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03445)
                           "HTTP Request Line; Invalid method token: '%.*s'",
                           field_name_len(r->method), r->method);
+        else if (deferred_error == rrl_badmethod09)
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03444)
+                          "HTTP Request Line; Invalid method token: '%.*s'"
+                          " (only GET is allowed for HTTP/0.9 requests)",
+                          field_name_len(r->method), r->method);
         else if (deferred_error == rrl_missinguri)
-            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03446)
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03446)
                           "HTTP Request Line; Missing URI");
+        else if (deferred_error == rrl_baduri)
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03454)
+                          "HTTP Request Line; URI incorrectly encoded: '%.*s'",
+                          field_name_len(r->uri), r->uri);
         else if (deferred_error == rrl_badwhitespace)
-            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03447)
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03447)
                           "HTTP Request Line; Invalid whitespace");
         else if (deferred_error == rrl_excesswhitespace)
-            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03448)
-                          "HTTP Request Line; Inappropriate whitespace "
-                          "(disallowed by StrictWhitespace");
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03448)
+                          "HTTP Request Line; Excess whitespace "
+                          "(disallowed by HttpProtocolOptions Strict");
         else if (deferred_error == rrl_trailingtext)
-            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03449)
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03449)
                           "HTTP Request Line; Extraneous text found '%.*s' "
                           "(perhaps whitespace was injected?)",
                           field_name_len(ll), ll);
-        else if (deferred_error == rrl_badprotocol) {
-            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02418)
+        else if (deferred_error == rrl_reject09)
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02401)
+                          "HTTP Request Line; Rejected HTTP/0.9 request");
+        else if (deferred_error == rrl_badprotocol)
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02418)
                           "HTTP Request Line; Unrecognized protocol '%.*s' "
                           "(perhaps whitespace was injected?)",
                           field_name_len(r->protocol), r->protocol);
-            r->protocol  = "HTTP/1.0";
-        }
         r->status = HTTP_BAD_REQUEST;
-        return 0;
+        goto rrl_failed;
     }
 
     if (conf->http_methods == AP_HTTP_METHODS_REGISTERED
             && r->method_number == M_INVALID) {
-        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02423)
+        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02423)
                       "HTTP Request Line; Unrecognized HTTP method: '%.*s' "
                       "(disallowed by RegisteredMethods)",
                       field_name_len(r->method), r->method);
         r->status = HTTP_NOT_IMPLEMENTED;
+        /* This can't happen in an HTTP/0.9 request, we verified GET above */
         return 0;
     }
 
     if (r->status != HTTP_OK) {
-        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03450)
-                      "HTTP Request Line; URI parsing failed");
-        return 0;
+        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03450)
+                      "HTTP Request Line; Unable to parse URI: '%.*s'",
+                      field_name_len(r->uri), r->uri);
+        goto rrl_failed;
     }
 
     if (strict) {
-        if (ap_has_cntrl(r->the_request)) {
-            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02420)
+        /* No sense re-testing here for what was evaulated above */
+        if (!stricturi && ap_has_cntrl(r->the_request)) {
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02420)
                           "HTTP Request Line; URI must not contain control"
                           " characters");
             r->status = HTTP_BAD_REQUEST;
-            return 0;
+            goto rrl_failed;
         }
         if (r->parsed_uri.fragment) {
             /* RFC3986 3.5: no fragment */
-            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02421)
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02421)
                           "HTTP Request Line; URI must not contain a fragment");
             r->status = HTTP_BAD_REQUEST;
-            return 0;
+            goto rrl_failed;
         }
         if (r->parsed_uri.user || r->parsed_uri.password) {
-            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02422)
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02422)
                           "HTTP Request Line; URI must not contain a "
                           "username/password");
             r->status = HTTP_BAD_REQUEST;
-            return 0;
+            goto rrl_failed;
         }
     }
 
     return 1;
+
+rrl_failed:
+    if (r->proto_num == HTTP_VERSION(0, 9)) {
+        /* Send all parsing and protocol error response with 1.x behavior,
+         * and reserve 505 errors for actual HTTP protocols presented.
+         * As called out in RFC7230 3.5, any errors parsing the protocol
+         * from the request line are nearly always misencoded HTTP/1.x
+         * requests. Only a valid 0.9 request with no parsing errors
+         * at all may be treated as a simple request, if allowed.
+         */
+        r->assbackwards = 0;
+        r->connection->keepalive = AP_CONN_CLOSE;
+        r->proto_num = HTTP_VERSION(1, 0);
+        r->protocol  = "HTTP/1.0";
+    }
+    return 0;
 }
 
 static int table_do_fn_check_lengths(void *r_, const char *key,
@@ -878,7 +952,6 @@ AP_DECLARE(void) ap_get_mime_headers_cor
     char *tmp_field;
     core_server_config *conf = ap_get_core_module_config(r->server->module_config);
     int strict = (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE);
-    int strictspaces = (conf->http_whitespace == AP_HTTP_WHITESPACE_STRICT);
 
     /*
      * Read header lines until we get the empty separator line, a read error,
@@ -889,7 +962,7 @@ AP_DECLARE(void) ap_get_mime_headers_cor
 
         field = NULL;
         rv = ap_rgetline(&field, r->server->limit_req_fieldsize + 2,
-                         &len, r, 0, bb);
+                         &len, r, strict ? AP_GETLINE_CRLF : 0, bb);
 
         if (rv != APR_SUCCESS) {
             if (APR_STATUS_IS_TIMEUP(rv)) {
@@ -937,7 +1010,7 @@ AP_DECLARE(void) ap_get_mime_headers_cor
 
             if (last_field == NULL) {
                 r->status = HTTP_BAD_REQUEST;
-                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03442)
+                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03442)
                               "Line folding encountered before first"
                               " header line");
                 return;
@@ -945,7 +1018,7 @@ AP_DECLARE(void) ap_get_mime_headers_cor
 
             if (field[1] == '\0') {
                 r->status = HTTP_BAD_REQUEST;
-                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03443)
+                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03443)
                               "Empty folded line encountered");
                 return;
             }
@@ -991,9 +1064,7 @@ AP_DECLARE(void) ap_get_mime_headers_cor
             }
             memcpy(last_field + last_len, field, len +1); /* +1 for nul */
             /* Replace obs-fold w/ SP per RFC 7230 3.2.4 */
-            if (strict || strictspaces) {
-                last_field[last_len] = ' ';
-            }
+            last_field[last_len] = ' ';
             last_len += len;
 
             /* We've appended this obs-fold line to last_len, proceed to
@@ -1024,22 +1095,9 @@ AP_DECLARE(void) ap_get_mime_headers_cor
             {
                 /* Not Strict ('Unsafe' mode), using the legacy parser */
 
-                if (strictspaces && strpbrk(last_field, "\n\v\f\r")) {
-                    r->status = HTTP_BAD_REQUEST;
-                    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03451)
-                                  "Request header presented bad whitespace "
-                                  "(disallowed by StrictWhitespace)");
-                    return;
-                }
-                else {
-                    char *ll = last_field;
-                    while ((ll = strpbrk(ll, "\n\v\f\r")))
-                        *(ll++) = ' ';
-                }
-
                 if (!(value = strchr(last_field, ':'))) { /* Find ':' or */
                     r->status = HTTP_BAD_REQUEST;   /* abort bad request */
-                    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00564)
+                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00564)
                                   "Request header field is missing ':' "
                                   "separator: %.*s", (int)LOG_NAME_MAX_LEN,
                                   last_field);
@@ -1051,11 +1109,11 @@ AP_DECLARE(void) ap_get_mime_headers_cor
 
                 *value++ = '\0'; /* NUL-terminate at colon */
 
-                if (strictspaces && strpbrk(last_field, " \t")) {
+                if (strpbrk(last_field, "\t\n\v\f\r ")) {
                     r->status = HTTP_BAD_REQUEST;
-                    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03452)
-                                  "Request header field name with whitespace "
-                                  "(disallowed by StrictWhitespace)");
+                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03452)
+                                  "Request header field name presented"
+                                  " invalid whitespace");
                     return;
                 }
 
@@ -1063,15 +1121,17 @@ AP_DECLARE(void) ap_get_mime_headers_cor
                      ++value;            /* Skip to start of value   */
                 }
 
-                /* Strip LWS after field-name: */
-                while (tmp_field > last_field
-                           && (*tmp_field == ' ' || *tmp_field == '\t')) {
-                    *(tmp_field--) = '\0';
+                if (strpbrk(value, "\n\v\f\r")) {
+                    r->status = HTTP_BAD_REQUEST;
+                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03451)
+                                  "Request header field value presented"
+                                  " bad whitespace");
+                    return;
                 }
 
                 if (tmp_field == last_field) {
                     r->status = HTTP_BAD_REQUEST;
-                    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03453)
+                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03453)
                                   "Request header field name was empty");
                     return;
                 }
@@ -1082,7 +1142,7 @@ AP_DECLARE(void) ap_get_mime_headers_cor
                 value = (char *)ap_scan_http_token(last_field);
                 if ((value == last_field) || *value != ':') {
                     r->status = HTTP_BAD_REQUEST;
-                    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02426)
+                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02426)
                                   "Request header field name is malformed: "
                                   "%.*s", (int)LOG_NAME_MAX_LEN, last_field);
                     return;
@@ -1104,7 +1164,7 @@ AP_DECLARE(void) ap_get_mime_headers_cor
                  */
                 if (*tmp_field != '\0') {
                     r->status = HTTP_BAD_REQUEST;
-                    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02427)
+                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02427)
                                   "Request header value is malformed: "
                                   "%.*s", (int)LOG_NAME_MAX_LEN, value);
                     return;
@@ -1225,7 +1285,7 @@ request_rec *ap_read_request(conn_rec *c
                               r->server->limit_req_line);
             }
             else if (r->method == NULL) {
-                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00566)
+                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00566)
                               "request failed: malformed request line");
             }
             access_status = r->status;
@@ -1265,7 +1325,7 @@ request_rec *ap_read_request(conn_rec *c
 
         ap_get_mime_headers_core(r, tmp_bb);
         if (r->status != HTTP_OK) {
-            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00567)
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00567)
                           "request failed: error reading the headers");
             ap_send_error_response(r, 0);
             ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
@@ -1284,7 +1344,7 @@ request_rec *ap_read_request(conn_rec *c
              */
             if (!(strcasecmp(tenc, "chunked") == 0 /* fast path */
                     || ap_find_last_token(r->pool, tenc, "chunked"))) {
-                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02539)
+                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02539)
                               "client sent unknown Transfer-Encoding "
                               "(%s): %s", tenc, r->uri);
                 r->status = HTTP_BAD_REQUEST;
@@ -1305,25 +1365,6 @@ request_rec *ap_read_request(conn_rec *c
             apr_table_unset(r->headers_in, "Content-Length");
         }
     }
-    else {
-        if (r->header_only) {
-            /*
-             * Client asked for headers only with HTTP/0.9, which doesn't send
-             * headers! Have to dink things just to make sure the error message
-             * comes through...
-             */
-            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00568)
-                          "client sent invalid HTTP/0.9 request: HEAD %s",
-                          r->uri);
-            r->header_only = 0;
-            r->status = HTTP_BAD_REQUEST;
-            ap_send_error_response(r, 0);
-            ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
-            ap_run_log_transaction(r);
-            apr_brigade_destroy(tmp_bb);
-            goto traceout;
-        }
-    }
 
     apr_brigade_destroy(tmp_bb);
 
@@ -1355,7 +1396,7 @@ request_rec *ap_read_request(conn_rec *c
          * a Host: header, and the server MUST respond with 400 if it doesn't.
          */
         access_status = HTTP_BAD_REQUEST;
-        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00569)
+        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00569)
                       "client sent HTTP/1.1 request without hostname "
                       "(see RFC2616 section 14.23): %s", r->uri);
     }

Modified: httpd/httpd/branches/2.4.x-merge-http-strict/server/util.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-merge-http-strict/server/util.c?rev=1769669&r1=1769668&r2=1769669&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x-merge-http-strict/server/util.c (original)
+++ httpd/httpd/branches/2.4.x-merge-http-strict/server/util.c Mon Nov 14 17:59:10 2016
@@ -1633,6 +1633,16 @@ AP_DECLARE(char *) ap_get_http_token(apr
     return tok;
 }
 
+/* Scan a string for valid URI characters per RFC3986, and 
+ * return a pointer to the first non-URI character encountered.
+ */
+AP_DECLARE(const char *) ap_scan_http_uri_safe(const char *ptr)
+{
+    for ( ; TEST_CHAR(*ptr, T_URI_RFC3986); ++ptr) ;
+
+    return ptr;
+}
+
 /* Retrieve a token, spacing over it and returning a pointer to
  * the first non-white byte afterwards.  Note that these tokens
  * are delimited by semis and commas; and can also be delimited



Mime
View raw message