]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
I really just did that on my test-merge branch??? fueque... reverting r1775787
authorWilliam A. Rowe Jr <wrowe@apache.org>
Fri, 23 Dec 2016 05:22:13 +0000 (05:22 +0000)
committerWilliam A. Rowe Jr <wrowe@apache.org>
Fri, 23 Dec 2016 05:22:13 +0000 (05:22 +0000)
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x@1775788 13f79535-47bb-0310-9956-ffa450edef68

13 files changed:
CHANGES
STATUS
docs/manual/mod/core.xml
include/ap_mmn.h
include/http_core.h
include/http_protocol.h
include/httpd.h
modules/http/http_filters.c
server/core.c
server/gen_test_char.c
server/protocol.c
server/util.c
server/vhost.c

diff --git a/CHANGES b/CHANGES
index d430aa81b0c751ba1d6a74bb662e460307114239..3f81842f044f5ddf8c548d717a5b4da9f0312758 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,46 +1,17 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.2.32
 
-  *) SECURITY: CVE-2016-8743 (cve.mitre.org)
-     Enforce HTTP request grammar corresponding to RFC7230 for request lines
-     and request headers, to prevent response splitting and cache pollution by
-     malicious clients or downstream proxies. [William Rowe, Stefan Fritsch]
-
-  *) CVE-2016-5387: core: Mitigate [f]cgi "httpoxy" issues.
+  *) core: CVE-2016-5387: Mitigate [f]cgi "httpoxy" issues.
      [Dominic Scheirlinck <dominic vendhq.com>, Yann Ylavic]
 
-  *) Validate HTTP response header grammar defined by RFC7230, resulting
-     in a 500 error in the event that invalid response header contents are
-     detected when serving the response, to avoid response splitting and cache
-     pollution by malicious clients, upstream servers or faulty modules.
-     [Stefan Fritsch, Eric Covener, Yann Ylavic]
-
-  *) core: Enforce LimitRequestFieldSize after multiple headers with the same
-     name have been merged. [Stefan Fritsch]
-
-  *) core: Drop Content-Length header and message-body from HTTP 204 responses.
-     PR 51350 [Luca Toscano]
-
-  *) core: Permit unencoded ';' characters to appear in proxy requests and
-     Location: response headers. Corresponds to modern browser behavior.
-     [William Rowe]
-
-  *) core: ap_rgetline_core now pulls from r->proto_input_filters.
-
-  *) core: Correctly parse an IPv6 literal host specification in an absolute
-     URL in the request line. [Stefan Fritsch]
-
-  *) core: New directive RegisterHttpMethod for registering non-standard
-     HTTP methods. [Stefan Fritsch]
-
   *) core: Limit to ten the number of tolerated empty lines between request.
      [Yann Ylavic]
 
-  *) core: reject NULLs in request line or request headers.
+  *) Core: reject NULLs in request line or request headers.
      PR 43039 [Nick Kew]
 
-  *) core: Avoid a possible truncation of the faulty header included in the
-     HTML response when LimitRequestFieldSize is reached.  [Yann Ylavic]
+  *) mod_ssl: Fix a possible memory leak on restart for custom [EC]DH params.
+     [Jan Kaluza, Yann Ylavic]
 
   *) mod_proxy: Fix a regression with 2.2.31 that caused inherited workers to
      use a different scoreboard slot then the original one.  PR 58267.
@@ -71,12 +42,6 @@ Changes with Apache 2.2.32
      failures under Visual Studio 2015 and other mismatched MSVCRT flavors.
      PR59630 [Jan Ehrhardt <phpdev ehrhardt.nl>]
 
-  *) mod_ssl: Fix a possible memory leak on restart for custom [EC]DH params.
-     [Jan Kaluza, Yann Ylavic]
-
-  *) core: Support custom ErrorDocuments for HTTP 501 and 414 status codes.
-     PR 57167 [Edward Lu <Chaosed0 gmail.com>]
-
 Changes with Apache 2.2.31
 
   *) Correct win32 build issues for mod_proxy exports, OpenSSL 1.0.x headers.
diff --git a/STATUS b/STATUS
index 1d86a94089be4b13e5f099a113b91a9e19a0e876..ad111c78a354e6558b2942a581e6455fa1d23472 100644 (file)
--- a/STATUS
+++ b/STATUS
@@ -99,32 +99,6 @@ CURRENT RELEASE NOTES:
 
 RELEASE SHOWSTOPPERS:
 
-  *) Rather than odds-and-ends applied out of order, proposing we revert
-     r1757240, r1757256, r1757295, r1758671, r1758672, r1775232, all of
-     which is now recorded in the 2.2.x-merge-http-strict branch, and
-     bring that branch back into 2.2.x for 2.4.32 release.
-     Merges;
-       -c-1775232 .
-       -c-1757672 .
-       -c-1757671 .
-       -c-1757295 .
-       -c-1757256 .
-       -c-1757240 .
-     [here we are back at 2.2.32-dev bump]
-       -r1775685:1775780 https://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x-merge-http-strict/
-     Roll-up patch of the above (not recommended for casual reading, these
-     would be committed individually as noted above... but for only for sanity
-     testing the end result. Due to intervening CHANGES/ap_mmn changes, there
-     is small delta after reverting the above...)
-       https://raw.githubusercontent.com/wrowe/patches/master/httpd-2.2-HEAD-http-protocol-strict.patch
-       This patch above does *NOT* apply to the 2.2.31 release, c.f. the delta
-       of the 2.2.x-merge-http-strict branch for that information. This is for
-       folks who are testing rollbacks plus 2.4.x activity against 2.2.x HEAD!
-       Sorry to start from scratch, but yann's correct observation was correct,
-       that nothing will apply out-of-order, and everything on 2.2 branch had
-       already become disordered.
-     +1: wrowe
-
 
 PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
   [ start all new proposals below, under PATCHES PROPOSED. ]
@@ -178,6 +152,44 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK:
          http://home.apache.org/~ylavic/patches/httpd-2.2.x-r1753592.patch
       +1: ylavic
 
+  *) Enforce LimitRequestFieldSize after multiple headers with the same
+     name have been merged, Ensure LimitRequestFieldSize is always logged.
+     Downgrade some more log messages indicating client errors from level error
+     to info. Add log messages for various reasons to return HTTP_BAD_REQUEST.
+     Correctly return a 400 (Bad request) in case of a HTTP/0.9 request like
+     "GET @example.org/foo".
+     Add some trace logging to core (using AP_DEBUG_THE_REQUEST macro, because
+     the TRACE5 facilities aren't in 2.2.x branch).
+     Improve error message (PR 54384).
+     Submitted by: sf, rpluem, jailletc36
+     [Note: everything in this patch is modifying logging and brings in the
+     LimitRequestFieldSize logic used for the lifespan of 2.4.x]
+     Trunk version of patch
+         http://svn.apache.org/r951900 (server/protocol.c alone)
+         http://svn.apache.org/r1178566
+         http://svn.apache.org/r1185385
+         http://svn.apache.org/r1188745
+         http://svn.apache.org/r1352911
+         http://svn.apache.org/r1433613
+     Backport: (Adjustments dodging 2.4'isms such as APLOGNO's)
+         https://raw.githubusercontent.com/wrowe/patches/master/backport-2.2.x-r951900-r1178566-r1185385-r1188745-r1352911-r1433613.patch 
+     +1: wrowe, covener
+     ylavic: the patch does not apply cleanly? (I tried both w/ and w/o
+             backport-2.2.x-r892678.patch first, conflicts in protocol.c)
+
+  *) core: ErrorDocument now works for requests without a Host header.
+     Support custom ErrorDocuments for HTTP 501 and 414 status codes.
+     PR: 48357, 57167
+     Submitted by: trawick,  [Edward Lu <Chaosed0 gmail.com>]
+     Trunk version of patch
+         http://svn.apache.org/r1392347
+         http://svn.apache.org/r1635762
+     Backport:
+         https://raw.githubusercontent.com/wrowe/patches/master/backport-2.2.x-r1392347-r1635762.patch 
+     +1: wrowe, covener
+     ylavic: same here (hunk + access_status = HTTP_BAD_REQUEST;)
+             depends on the previous one?
+
   *) core: potential rejection of valid MaxMemFree and ThreadStackSize directives
      trunk patch: https://svn.apache.org/r1542338
      2.4.x patch: https://svn.apache.org/r1542549
index 326ce7e26e1a69cb9b150238b6e7e4f81d6112fc..da401dba8effeb6d1e67cd0824c07b9cb0f8412e 100644 (file)
@@ -1440,82 +1440,6 @@ MIME content-type</description>
 </usage>
 </directivesynopsis>
 
-<directivesynopsis>
-<name>HttpProtocolOptions</name>
-<description>Modify restrictions on HTTP Request Messages</description>
-<syntax>HttpProtocolOptions [Strict|Unsafe] [RegisteredMethods|LenientMethods]
- [Allow0.9|Require1.0]</syntax>
-<default>HttpProtocolOptions Strict LenientMethods Allow0.9</default>
-<contextlist><context>server config</context>
-<context>virtual host</context></contextlist>
-<compatibility>2.2.32 or 2.4.24 and later</compatibility>
-
-<usage>
-    <p>This directive changes the rules applied to the HTTP Request Line
-    (<a href="https://tools.ietf.org/html/rfc7230#section-3.1.1"
-      >RFC 7230 &sect;3.1.1</a>) and the HTTP Request Header Fields
-    (<a href="https://tools.ietf.org/html/rfc7230#section-3.2"
-      >RFC 7230 &sect;3.2</a>), which are now applied by default or using
-    the <code>Strict</code> option. Due to legacy modules, applications or
-    custom user-agents which must be deperecated the <code>Unsafe</code>
-    option has been added to revert to the legacy behaviors. These rules
-    are applied prior to request processing, so must be configured at the
-    global or default (first) matching virtual host section, by IP/port
-    interface (and not by name) to be honored.</p>
-
-    <p>Prior to the introduction of this directive, the Apache HTTP Server
-    request message parsers were tolerant of a number of forms of input
-    which did not conform to the protocol.
-    <a href="https://tools.ietf.org/html/rfc7230#section-9.4"
-      >RFC 7230 &sect;9.4 Request Splitting</a> and
-    <a href="https://tools.ietf.org/html/rfc7230#section-9.5"
-      >&sect;9.5 Response Smuggling</a> call out only two of the potential
-    risks of accepting non-conformant request messages, while
-    <a href="https://tools.ietf.org/html/rfc7230#section-3.5"
-         >RFC 7230 &sect;3.5</a> "Message Parsing Robustness" identify the
-    risks of accepting obscure whitespace and request message formatting. 
-    As of the introduction of this directive, all grammer rules of the
-    specification are enforced in the default <code>Strict</code> operating
-    mode, and the strict whitespace suggested by section 3.5 is enforced
-    and cannot be relaxed.</p>
-
-    <p>Users are strongly cautioned against toggling the <code>Unsafe</code>
-    mode of operation, particularly on outward-facing, publicly accessible
-    server deployments.  If an interface is required for faulty monitoring
-    or other custom service consumers running on an intranet, users should
-    toggle the Unsafe option only on a specific virtual host configured
-    to service their internal private network.</p>
-
-    <p>Reviewing the messages logged to the <directive>ErrorLog</directive>,
-    configured with <directive>LogLevel</directive> <code>debug</code> level,
-    can help identify such faulty requests along with their origin.
-    Users should pay particular attention to the 400 responses in the access
-    log for invalid requests which were unexpectedly rejected.</p>
-
-    <p><a href="https://tools.ietf.org/html/rfc7231#section-4.1"
-         >RFC 7231 &sect;4.1</a> "Request Methods" "Overview" requires that
-    origin servers shall respond with an error when an unsupported method
-    is encountered in the request line. This already happens when the
-    <code>LenientMethods</code> option is used, but administrators may wish
-    to toggle the <code>RegisteredMethods</code> option and register any
-    non-standard methods using the <directive>RegisterHttpMethod</directive>
-    directive, particularly if the <code>Unsafe</code> option has been toggled.
-    The <code>RegisteredMethods</code> option should <strong>not</strong>
-    be toggled for forward proxy hosts, as the methods supported by the
-    origin servers are unknown to the proxy server.</p>
-
-    <p><a href="https://tools.ietf.org/html/rfc2616#section-19.6"
-         >RFC 2616 &sect;19.6</a> "Compatibility With Previous Versions" had
-    encouraged HTTP servers to support legacy HTTP/0.9 requests. RFC 7230
-    superceeds this with "The expectation to support HTTP/0.9 requests has
-    been removed" and offers additional comments in 
-    <a href="https://tools.ietf.org/html/rfc7230#appendix-A"
-      >RFC 7230 Appendix A</a>. The <code>Require1.0</code> option allows
-    the user to remove support of the default <code>Allow0.9</code> option's
-    behavior.</p>
-</usage>
-</directivesynopsis>
-
 <directivesynopsis type="section">
 <name>IfDefine</name>
 <description>Encloses directives that will be processed only
@@ -3757,19 +3681,5 @@ hostname or IP address</description>
 </usage>
 </directivesynopsis>
 
-<directivesynopsis>
-<name>RegisterHttpMethod</name>
-<description>Register non-standard HTTP methods</description>
-<syntax>RegisterHttpMethod <var>method</var> [<var>method</var> [...]]</syntax>
-<contextlist><context>server config</context></contextlist>
-<usage>
-<p>HTTP Methods that are not conforming to the relvant RFCs are normally
-rejected by request processing in Apache HTTPD. To avoid this, modules
-can register non-standard HTTP methods they support.
-The <directive>RegisterHttpMethod</directive> allows to register such
-methods manually. This can be useful for if such methods are forwared
-for external processing, e.g. to a CGI script.</p>
-</usage>
-</directivesynopsis>
 
 </modulesynopsis>
index c459b915dcebaead6f9140456953ac6ca270a3a5..29227d53f4c63268965fdaf4153e00945bccabce 100644 (file)
  * 20051115.40 (2.2.30) Add ap_map_http_request_error()
  * 20051115.41 (2.2.32) Add s member to proxy_server_conf struct and server
  *                      member to proxy_worker struct.
- * 20151115.42 (2.2.32) Add http09_enable, http_conformance, and
- *                      http_methods to core_server_config
- *                      Add ap_scan_http_field_token(),
- *                      ap_scan_http_field_content(),
- *                      and ap_scan_vchar_obstext()
- *                      Replaced fold boolean with with multiple bit flags
- *                      to ap_[r]getline()
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503232UL /* "AP22" */
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
 #define MODULE_MAGIC_NUMBER_MAJOR 20051115
 #endif
-#define MODULE_MAGIC_NUMBER_MINOR 42                    /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 41                    /* 0...n */
 
 /**
  * Determine if the server's current MODULE_MAGIC_NUMBER is at least a
index 4a85db67323ad9bf45bdec8b3600c49afb7fa9f7..c397962bd4235250eaffffde038a4d004ed3f1cb 100644 (file)
@@ -627,21 +627,6 @@ typedef struct {
 #define AP_MERGE_TRAILERS_DISABLE  2
     int merge_trailers;
 
-#define AP_HTTP09_UNSET   0
-#define AP_HTTP09_ENABLE  1
-#define AP_HTTP09_DISABLE 2
-    char http09_enable;
-
-#define AP_HTTP_CONFORMANCE_UNSET     0
-#define AP_HTTP_CONFORMANCE_UNSAFE    1
-#define AP_HTTP_CONFORMANCE_STRICT    2
-    char http_conformance;
-
-#define AP_HTTP_METHODS_UNSET         0
-#define AP_HTTP_METHODS_LENIENT       1
-#define AP_HTTP_METHODS_REGISTERED    2
-    char http_methods;
-
 } core_server_config;
 
 /* for AddOutputFiltersByType in core.c */
index 1fed3b58d4e5cfeebdb1932b6ce018c91a3d73ff..185d62cc985bf1734634e3dfdd3d604a8b9f9cd2 100644 (file)
@@ -510,22 +510,17 @@ AP_DECLARE(int) ap_get_basic_auth_pw(request_rec *r, const char **pw);
  */
 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 */
-
 /**
  * Get the next line of input for the request
  * @param s The buffer into which to read the line
  * @param n The size of the buffer
  * @param r The request
- * @param flags Bit flag of multiple parsing options
- *              AP_GETLINE_FOLD Whether to merge continuation lines
- *              AP_GETLINE_CRLF Whether line ends must be in the form CR LF
+ * @param fold Whether to merge continuation lines
  * @return The length of the line, if successful
  *         n, if the line is too big to fit in the buffer
  *         -1 for miscellaneous errors
  */
-AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int flags);
+AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int fold);
 
 /**
  * Get the next line of input for the request
@@ -543,9 +538,7 @@ AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int flags);
  * @param n The size of the buffer
  * @param read The length of the line.
  * @param r The request
- * @param flags Bit flag of multiple parsing options
- *              AP_GETLINE_FOLD Whether to merge continuation lines
- *              AP_GETLINE_CRLF Whether line ends must be in the form CR LF
+ * @param fold Whether to merge continuation lines
  * @param bb Working brigade to use when reading buckets
  * @return APR_SUCCESS, if successful
  *         APR_ENOSPC, if the line is too big to fit in the buffer
@@ -554,7 +547,7 @@ AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int flags);
 #if APR_CHARSET_EBCDIC
 AP_DECLARE(apr_status_t) ap_rgetline(char **s, apr_size_t n, 
                                      apr_size_t *read,
-                                     request_rec *r, int flags,
+                                     request_rec *r, int fold,
                                      apr_bucket_brigade *bb);
 #else /* ASCII box */
 #define ap_rgetline(s, n, read, r, fold, bb) \
@@ -564,7 +557,7 @@ AP_DECLARE(apr_status_t) ap_rgetline(char **s, apr_size_t n,
 /** @see ap_rgetline */
 AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, 
                                           apr_size_t *read,
-                                          request_rec *r, int flags,
+                                          request_rec *r, int fold,
                                           apr_bucket_brigade *bb);
 
 /**
index 55da87a0971b0d1f70813f20d9342cbf7edc719c..6f4c3d4538ea1b23e526d42417fe0e473a51cbbb 100644 (file)
@@ -1414,28 +1414,6 @@ AP_DECLARE(char *) ap_get_list_item(apr_pool_t *p, const char **field);
  */
 AP_DECLARE(int) ap_find_list_item(apr_pool_t *p, const char *line, const char *tok);
 
-/* Scan a string for field content chars, as defined by RFC7230 section 3.2
- * including VCHAR/obs-text, as well as HT and SP
- * @param ptr The string to scan
- * @return A pointer to the first (non-HT) ASCII ctrl character.
- * @note lws and trailing whitespace are scanned, the caller is responsible
- * for trimming leading and trailing whitespace
- */
-AP_DECLARE(const char *) ap_scan_http_field_content(const char *ptr);
-
-/* Scan a string for token characters, as defined by RFC7230 section 3.2.6 
- * @param ptr The string to scan
- * @return A pointer to the first non-token character.
- */
-AP_DECLARE(const char *) ap_scan_http_token(const char *ptr);
-
-/* Scan a string for visible ASCII (0x21-0x7E) or obstext (0x80+)
- * and return a pointer to the first SP/CTL/NUL character encountered.
- * @param ptr The string to scan
- * @return A pointer to the first SP/CTL character.
- */
-AP_DECLARE(const char *) ap_scan_vchar_obstext(const char *ptr);
-
 /**
  * Retrieve a token, spacing over it and adjusting the pointer to
  * the first non-white byte afterwards.  Note that these tokens
index 8e95494f1fc9ab6702d7ad262264044234047e0a..006af7ef09d8e609e7b9e77d4a9a36704aa2098d 100644 (file)
@@ -125,15 +125,14 @@ static apr_status_t bail_out_on_error(http_ctx_t *ctx,
 
 /**
  * Parse a chunk line with optional extension, detect overflow.
- * There are several error cases:
- *  1) If the chunk link is misformatted, APR_EINVAL is returned.
- *  2) If the conversion would require too many bits, APR_EGENERAL is returned.
- *  3) If the conversion used the correct number of bits, but an overflow
+ * There are two error cases:
+ *  1) If the conversion would require too many bits, APR_EGENERAL is returned.
+ *  2) If the conversion used the correct number of bits, but an overflow
  *     caused only the sign bit to flip, then APR_ENOSPC is returned.
- * A negative chunk length always indicates an overflow error.
+ * In general, any negative number can be considered an overflow error.
  */
 static apr_status_t parse_chunk_size(http_ctx_t *ctx, const char *buffer,
-                                     apr_size_t len, int linelimit, int strict)
+                                     apr_size_t len, int linelimit)
 {
     apr_size_t i = 0;
 
@@ -146,12 +145,6 @@ static apr_status_t parse_chunk_size(http_ctx_t *ctx, const char *buffer,
         if (ctx->state == BODY_CHUNK_END
                 || ctx->state == BODY_CHUNK_END_LF) {
             if (c == LF) {
-                if (strict && (ctx->state != BODY_CHUNK_END_LF)) {
-                    /*
-                     * CR missing before LF.
-                     */
-                    return APR_EINVAL;
-                }
                 ctx->state = BODY_CHUNK;
             }
             else if (c == CR && ctx->state == BODY_CHUNK_END) {
@@ -159,7 +152,7 @@ static apr_status_t parse_chunk_size(http_ctx_t *ctx, const char *buffer,
             }
             else {
                 /*
-                 * CRLF expected.
+                 * LF expected.
                  */
                 return APR_EINVAL;
             }
@@ -186,12 +179,6 @@ static apr_status_t parse_chunk_size(http_ctx_t *ctx, const char *buffer,
         }
 
         if (c == LF) {
-            if (strict && (ctx->state != BODY_CHUNK_LF)) {
-                /*
-                 * CR missing before LF.
-                 */
-                return APR_EINVAL;
-            }
             if (ctx->remaining) {
                 ctx->state = BODY_CHUNK_DATA;
             }
@@ -213,17 +200,14 @@ static apr_status_t parse_chunk_size(http_ctx_t *ctx, const char *buffer,
         }
         else if (ctx->state == BODY_CHUNK_EXT) {
             /*
-             * Control chars (excluding tabs) are invalid.
-             * TODO: more precisely limit input
+             * Control chars (but tabs) are invalid.
              */
             if (c != '\t' && apr_iscntrl(c)) {
                 return APR_EINVAL;
             }
         }
         else if (c == ' ' || c == '\t') {
-            /* Be lenient up to 10 implied *LWS, a legacy of RFC 2616,
-             * and noted as errata to RFC7230;
-             * https://www.rfc-editor.org/errata_search.php?rfc=7230&eid=4667
+            /* Be lenient up to 10 BWS (term from rfc7230 - 3.2.3).
              */
             ctx->state = BODY_CHUNK_CR;
             if (++ctx->chunk_bws > 10) {
@@ -339,10 +323,7 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b,
                             ap_input_mode_t mode, apr_read_type_e block,
                             apr_off_t readbytes)
 {
-    core_server_config *conf =
-        (core_server_config *)ap_get_module_config(f->r->server->module_config,
-                                                   &core_module);
-    int strict = (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE);
+    core_server_config *conf;
     apr_bucket *e;
     http_ctx_t *ctx = f->ctx;
     apr_status_t rv;
@@ -350,6 +331,9 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b,
     apr_bucket_brigade *bb;
     int again;
 
+    conf = (core_server_config *)
+        ap_get_module_config(f->r->server->module_config, &core_module);
+
     /* just get out of the way of things we don't want. */
     if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE) {
         return ap_get_brigade(f->next, b, mode, block, readbytes);
@@ -541,7 +525,7 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b,
                     if (rv == APR_SUCCESS) {
                         parsing = 1;
                         rv = parse_chunk_size(ctx, buffer, len,
-                                f->r->server->limit_req_fieldsize, strict);
+                                f->r->server->limit_req_fieldsize);
                     }
                     if (rv != APR_SUCCESS) {
                         ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, f->r,
@@ -683,83 +667,14 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b,
     return APR_SUCCESS;
 }
 
-struct check_header_ctx {
-    request_rec *r;
-    int strict;
-};
-
-/* check a single header, to be used with apr_table_do() */
-static int check_header(void *arg, const char *name, const char *val)
-{
-    struct check_header_ctx *ctx = arg;
-    const char *test;
-
-    if (name[0] == '\0') {
-        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r,
-                      "Empty response header name, aborting request");
-        return 0;
-    }
-
-    if (ctx->strict) { 
-        test = ap_scan_http_token(name);
-    }
-    else {
-        test = ap_scan_vchar_obstext(name);
-    }
-    if (*test) {
-        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r,
-                      "Response header name '%s' contains invalid "
-                      "characters, aborting request",
-                      name);
-        return 0;
-    }
-
-    test = ap_scan_http_field_content(val);
-    if (*test) {
-        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r,
-                      "Response header '%s' value of '%s' contains invalid "
-                      "characters, aborting request",
-                      name, val);
-        return 0;
-    }
-    return 1;
-}
-
-/**
- * Check headers for HTTP conformance
- * @return 1 if ok, 0 if bad
- */
-static APR_INLINE int check_headers(request_rec *r)
-{
-    struct check_header_ctx ctx;
-    core_server_config *conf =
-        (core_server_config *)ap_get_module_config(r->server->module_config,
-                                                   &core_module);
-
-    ctx.r = r;
-    ctx.strict = (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE);
-    return apr_table_do(check_header, &ctx, r->headers_out, NULL) &&
-           apr_table_do(check_header, &ctx, r->err_headers_out, NULL);
-}
-
-static int check_headers_recursion(request_rec *r)
-{
-    void *check = NULL;
-    apr_pool_userdata_get(&check, "check_headers_recursion", r->pool);
-    if (check) {
-        return 1;
-    }
-    apr_pool_userdata_setn("true", "check_headers_recursion", NULL, r->pool);
-    return 0;
-}
-
 typedef struct header_struct {
     apr_pool_t *pool;
     apr_bucket_brigade *bb;
 } header_struct;
 
 /* Send a single HTTP header field to the client.  Note that this function
- * is used in calls to apr_table_do(), so don't change its interface.
+ * is used in calls to table_do(), so their interfaces are co-dependent.
+ * In other words, don't change this one without checking table_do in alloc.c.
  * It returns true unless there was a write error of some kind.
  */
 static int form_header_field(header_struct *h,
@@ -1231,7 +1146,6 @@ AP_DECLARE_NONSTD(int) ap_send_http_trace(request_rec *r)
 
 typedef struct header_filter_ctx {
     int headers_sent;
-    int headers_error;
 } header_filter_ctx;
 
 AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
@@ -1247,23 +1161,19 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
     header_filter_ctx *ctx = f->ctx;
     const char *ctype;
     ap_bucket_error *eb = NULL;
-    apr_bucket *eos = NULL;
 
     AP_DEBUG_ASSERT(!r->main);
 
-    if (!ctx) {
-        ctx = f->ctx = apr_pcalloc(r->pool, sizeof(header_filter_ctx));
-    }
-    if (ctx->headers_sent) {
-        /* Eat body if response must not have one. */
-        if (r->header_only || r->status == HTTP_NO_CONTENT) {
+    if (r->header_only) {
+        if (!ctx) {
+            ctx = f->ctx = apr_pcalloc(r->pool, sizeof(header_filter_ctx));
+        }
+        else if (ctx->headers_sent) {
             apr_brigade_cleanup(b);
-            return APR_SUCCESS;
+            return OK;
         }
     }
-    else if (!ctx->headers_error && !check_headers(r)) {
-        ctx->headers_error = 1;
-    }
+
     for (e = APR_BRIGADE_FIRST(b);
          e != APR_BRIGADE_SENTINEL(b);
          e = APR_BUCKET_NEXT(e))
@@ -1280,44 +1190,10 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
             ap_remove_output_filter(f);
             return ap_pass_brigade(f->next, b);
         }
-        if (ctx->headers_error && APR_BUCKET_IS_EOS(e)) {
-            eos = e;
-        }
-    }
-    if (ctx->headers_error) {
-        if (!eos) {
-            /* Eat body until EOS */
-            apr_brigade_cleanup(b);
-            return APR_SUCCESS;
-        }
-
-        /* We may come back here from ap_die() below,
-         * so clear anything from this response.
-         */
-        ctx->headers_error = 0;
-        apr_table_clear(r->headers_out);
-        apr_table_clear(r->err_headers_out);
-
-        /* Don't recall ap_die() if we come back here (from its own internal
-         * redirect or error response), otherwise we can end up in infinite
-         * recursion; better fall through with 500, minimal headers and an
-         * empty body (EOS only).
-         */
-        if (!check_headers_recursion(r)) {
-            apr_brigade_cleanup(b);
-            ap_die(HTTP_INTERNAL_SERVER_ERROR, r);
-            return AP_FILTER_ERROR;
-        }
-        APR_BUCKET_REMOVE(eos);
-        apr_brigade_cleanup(b);
-        APR_BRIGADE_INSERT_TAIL(b, eos);
-        r->status = HTTP_INTERNAL_SERVER_ERROR;
-        r->content_type = r->content_encoding = NULL;
-        r->content_languages = NULL;
-        ap_set_content_length(r, 0);
     }
-    else if (eb) {
+    if (eb) {
         int status;
+
         status = eb->status;
         apr_brigade_cleanup(b);
         ap_die(status, r);
@@ -1374,10 +1250,6 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
         apr_table_unset(r->headers_out, "Content-Length");
     }
 
-    if (r->status == HTTP_NO_CONTENT) {
-        apr_table_unset(r->headers_out, "Content-Length");
-    }
-
     ctype = ap_make_content_type(r, r->content_type);
     if (strcasecmp(ctype, NO_CONTENT_TYPE)) {
         apr_table_setn(r->headers_out, "Content-Type", ctype);
@@ -1466,11 +1338,11 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
     terminate_header(b2);
 
     ap_pass_brigade(f->next, b2);
-    ctx->headers_sent = 1;
 
-    if (r->header_only || r->status == HTTP_NO_CONTENT) {
+    if (r->header_only) {
         apr_brigade_cleanup(b);
-        return APR_SUCCESS;
+        ctx->headers_sent = 1;
+        return OK;
     }
 
     r->sent_bodyct = 1;         /* Whatever follows is real body stuff... */
index b401d93a637c454500bc6754a00c0c591221cf5f..ddcfa6004b6ed83ff3e86c65cf5647b9274c9ff3 100644 (file)
@@ -546,15 +546,6 @@ static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv)
                            ? virt->merge_trailers
                            : base->merge_trailers;
 
-    if (virt->http09_enable != AP_HTTP09_UNSET)
-        conf->http09_enable = virt->http09_enable;
-
-    if (virt->http_conformance != AP_HTTP_CONFORMANCE_UNSET)
-        conf->http_conformance = virt->http_conformance;
-
-    if (virt->http_methods != AP_HTTP_METHODS_UNSET)
-        conf->http_methods = virt->http_methods;
-
     return conf;
 }
 
@@ -3250,57 +3241,6 @@ static const char *add_ct_output_filters(cmd_parms *cmd, void *conf_,
 
     return NULL;
 }
-
-static const char *set_http_protocol_options(cmd_parms *cmd, void *dummy,
-                                             const char *arg)
-{
-    core_server_config *conf = ap_get_module_config(cmd->server->module_config,
-                                                    &core_module);
-    if (strcasecmp(arg, "allow0.9") == 0)
-        conf->http09_enable |= AP_HTTP09_ENABLE;
-    else if (strcasecmp(arg, "require1.0") == 0)
-        conf->http09_enable |= AP_HTTP09_DISABLE;
-    else if (strcasecmp(arg, "strict") == 0)
-        conf->http_conformance |= AP_HTTP_CONFORMANCE_STRICT;
-    else if (strcasecmp(arg, "unsafe") == 0)
-        conf->http_conformance |= AP_HTTP_CONFORMANCE_UNSAFE;
-    else if (strcasecmp(arg, "registeredmethods") == 0)
-        conf->http_methods |= AP_HTTP_METHODS_REGISTERED;
-    else if (strcasecmp(arg, "lenientmethods") == 0)
-        conf->http_methods |= AP_HTTP_METHODS_LENIENT;
-    else
-        return "HttpProtocolOptions accepts "
-               "'Unsafe' or 'Strict' (default), "
-               "'RegisteredMethods' or 'LenientMethods' (default), and "
-               "'Require1.0' or 'Allow0.9' (default)";
-
-    if ((conf->http09_enable & AP_HTTP09_ENABLE)
-            && (conf->http09_enable & AP_HTTP09_DISABLE))
-        return "HttpProtocolOptions 'Allow0.9' and 'Require1.0'"
-               " are mutually exclusive";
-
-    if ((conf->http_conformance & AP_HTTP_CONFORMANCE_STRICT)
-            && (conf->http_conformance & AP_HTTP_CONFORMANCE_UNSAFE))
-        return "HttpProtocolOptions 'Strict' and 'Unsafe'"
-               " are mutually exclusive";
-
-    if ((conf->http_methods & AP_HTTP_METHODS_REGISTERED)
-            && (conf->http_methods & AP_HTTP_METHODS_LENIENT))
-        return "HttpProtocolOptions 'RegisteredMethods' and 'LenientMethods'"
-               " are mutually exclusive";
-
-    return NULL;
-}
-
-static const char *set_http_method(cmd_parms *cmd, void *conf, const char *arg)
-{
-    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
-    if (err != NULL)
-        return err;
-    ap_method_register(cmd->pool, arg);
-    return NULL;
-}
-
 /*
  * Insert filters requested by the AddOutputFilterByType
  * configuration directive. We cannot add filters based
@@ -3610,12 +3550,6 @@ AP_INIT_FLAG("Suexec", unixd_set_suexec, NULL, RSRC_CONF,
 #endif
 AP_INIT_FLAG("MergeTrailers", set_merge_trailers, NULL, RSRC_CONF,
               "merge request trailers into request headers or not"),
-AP_INIT_ITERATE("HttpProtocolOptions", set_http_protocol_options, NULL, RSRC_CONF,
-                "'Allow0.9' or 'Require1.0' (default); "
-                "'RegisteredMethods' or 'LenientMethods' (default); "
-                "'Unsafe' or 'Strict' (default). Sets HTTP acceptance rules"),
-AP_INIT_ITERATE("RegisterHttpMethod", set_http_method, NULL, RSRC_CONF,
-                "Registers non-standard HTTP methods"),
 { NULL }
 };
 
index 01f1ac57ec0f5f506b70a5f0269a7b90d80781a4..a0b55100f4ef9894bd0906ddc430cd40b6ea1ee8 100644 (file)
 
 #ifdef CROSS_COMPILE
 
-#include <ctype.h>
 #define apr_isalnum(c) (isalnum(((unsigned char)(c))))
 #define apr_isalpha(c) (isalpha(((unsigned char)(c))))
 #define apr_iscntrl(c) (iscntrl(((unsigned char)(c))))
 #define apr_isprint(c) (isprint(((unsigned char)(c))))
+#include <ctype.h>
 #define APR_HAVE_STDIO_H 1
 #define APR_HAVE_STRING_H 1
 
 #define T_HTTP_TOKEN_STOP     (0x08)
 #define T_ESCAPE_LOGITEM      (0x10)
 #define T_ESCAPE_FORENSIC     (0x20)
-#define T_HTTP_CTRLS          (0x80)
-#define T_VCHAR_OBSTEXT      (0x100)
 
 int main(int argc, char *argv[])
 {
     unsigned c;
-    unsigned short flags;
+    unsigned char flags;
 
     printf("/* this file is automatically generated by gen_test_char, "
            "do not edit */\n"
@@ -67,22 +65,18 @@ int main(int argc, char *argv[])
            "#define T_HTTP_TOKEN_STOP      (%u)\n"
            "#define T_ESCAPE_LOGITEM       (%u)\n"
            "#define T_ESCAPE_FORENSIC      (%u)\n"
-           "#define T_HTTP_CTRLS           (%u)\n"
-           "#define T_VCHAR_OBSTEXT        (%u)\n"
            "\n"
-           "static const unsigned short test_char_table[256] = {",
+           "static const unsigned char test_char_table[256] = {",
            T_ESCAPE_SHELL_CMD,
            T_ESCAPE_PATH_SEGMENT,
            T_OS_ESCAPE_PATH,
            T_HTTP_TOKEN_STOP,
            T_ESCAPE_LOGITEM,
-           T_ESCAPE_FORENSIC,
-           T_HTTP_CTRLS,
-           T_VCHAR_OBSTEXT);
+           T_ESCAPE_FORENSIC);
 
     for (c = 0; c < 256; ++c) {
         flags = 0;
-        if (c % 8 == 0)
+        if (c % 20 == 0)
             printf("\n    ");
 
         /* escape_shell_cmd */
@@ -110,36 +104,15 @@ 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;
         }
 
-        /* Stop for any non-'token' character, including ctrls, obs-text,
-         * and "tspecials" (RFC2068) a.k.a. "separators" (RFC2616), which
-         * is easer to express as characters remaining in the ASCII token set
-         */
-        if (!c || !(apr_isalnum(c) || strchr("!#$%&'*+-.^_`|~", c))) {
+        /* these are the "tspecials" (RFC2068) or "separators" (RFC2616) */
+        if (c && (apr_iscntrl(c) || strchr(" \t()<>@,;:\\\"/[]?={}", c))) {
             flags |= T_HTTP_TOKEN_STOP;
         }
 
-        /* Catch CTRLs other than VCHAR, HT and SP, and obs-text (RFC7230 3.2)
-         * This includes only the C0 plane, not C1 (which is obs-text itself.)
-         * XXX: We should verify that all ASCII C0 ctrls/DEL corresponding to
-         * the current EBCDIC translation are captured, and ASCII C1 ctrls
-         * corresponding are all permitted (as they fall under obs-text rule)
-         */
-        if (!c || (apr_iscntrl(c) && c != '\t')) {
-            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 && !apr_iscntrl(c) && c != ' ') {
-            flags |= T_VCHAR_OBSTEXT;
-        }
-
         /* For logging, escape all control characters,
          * double quotes (because they delimit the request in the log file)
          * backslashes (because we use backslash for escaping)
@@ -157,7 +130,7 @@ int main(int argc, char *argv[])
             flags |= T_ESCAPE_FORENSIC;
         }
 
-        printf("0x%03x%c", flags, (c < 255) ? ',' : ' ');
+        printf("%u%c", flags, (c < 255) ? ',' : ' ');
     }
 
     printf("\n};\n");
index 4a22b766f779c90cd1f3aeccb7993036e3937ea0..6ce98cc1655a5da17009e06be7bbdf28a4c3f0e8 100644 (file)
@@ -183,13 +183,12 @@ AP_DECLARE(apr_time_t) ap_rationalize_mtime(request_rec *r, apr_time_t mtime)
     return (mtime > now) ? now : mtime;
 }
 
+/* Min # of bytes to allocate when reading a request line */
+#define MIN_LINE_ALLOC 80
+
 /* Get a line of protocol input, including any continuation lines
  * caused by MIME folding (or broken clients) if fold != 0, and place it
  * in the buffer s, of size n bytes, without the ending newline.
- * 
- * Pulls from r->proto_input_filters instead of r->input_filters for
- * stricter protocol adherence and better input filter behavior during
- * chunked trailer processing (for http).
  *
  * If s is NULL, ap_rgetline_core will allocate necessary memory from r->pool.
  *
@@ -199,7 +198,7 @@ AP_DECLARE(apr_time_t) ap_rationalize_mtime(request_rec *r, apr_time_t mtime)
  * APR_ENOSPC is returned if there is not enough buffer space.
  * Other errors may be returned on other errors.
  *
- * The [CR]LF are *not* returned in the buffer.  Therefore, a *read of 0
+ * The LF is *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
@@ -210,35 +209,32 @@ AP_DECLARE(apr_time_t) ap_rationalize_mtime(request_rec *r, apr_time_t mtime)
  */
 AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
                                           apr_size_t *read, request_rec *r,
-                                          int flags, apr_bucket_brigade *bb)
+                                          int fold, 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
      * against APR_ASCII_LF at the end of the loop if bb only contains
      * zero-length buckets.
      */
-    if (last_char)
+    if (last_char) {
         *last_char = '\0';
+    }
 
     for (;;) {
         apr_brigade_cleanup(bb);
-        rv = ap_get_brigade(r->proto_input_filters, bb, AP_MODE_GETLINE,
+        rv = ap_get_brigade(r->input_filters, bb, AP_MODE_GETLINE,
                             APR_BLOCK_READ, 0);
         if (rv != APR_SUCCESS) {
             return rv;
         }
 
-        /* Something horribly wrong happened.  Someone didn't block! 
-         * (this also happens at the end of each keepalive connection)
-         */
+        /* Something horribly wrong happened.  Someone didn't block! */
         if (APR_BRIGADE_EMPTY(bb)) {
             return APR_EGENERAL;
         }
@@ -289,6 +285,9 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
                 /* We'll assume the common case where one bucket is enough. */
                 if (!*s) {
                     current_alloc = len;
+                    if (current_alloc < MIN_LINE_ALLOC) {
+                        current_alloc = MIN_LINE_ALLOC;
+                    }
                     *s = apr_palloc(r->pool, current_alloc);
                 }
                 else if (bytes_handled + len > current_alloc) {
@@ -324,13 +323,6 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
         }
     }
 
-    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) {
@@ -353,7 +345,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
             apr_brigade_cleanup(bb);
 
             /* We only care about the first byte. */
-            rv = ap_get_brigade(r->proto_input_filters, bb, AP_MODE_SPECULATIVE,
+            rv = ap_get_brigade(r->input_filters, bb, AP_MODE_SPECULATIVE,
                                 APR_BLOCK_READ, 1);
             if (rv != APR_SUCCESS) {
                 return rv;
@@ -404,8 +396,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
                      */
                     if (do_alloc) {
                         tmp = NULL;
-                    }
-                    else {
+                    } else {
                         /* We're null terminated. */
                         tmp = last_char;
                     }
@@ -475,7 +466,7 @@ AP_DECLARE(apr_status_t) ap_rgetline(char **s, apr_size_t n,
 }
 #endif
 
-AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int flags)
+AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int fold)
 {
     char *tmp_s = s;
     apr_status_t rv;
@@ -483,7 +474,7 @@ AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int flags)
     apr_bucket_brigade *tmp_bb;
 
     tmp_bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
-    rv = ap_rgetline(&tmp_s, n, &len, r, flags, tmp_bb);
+    rv = ap_rgetline(&tmp_s, n, &len, r, fold, tmp_bb);
     apr_brigade_destroy(tmp_bb);
 
     /* Map the out-of-space condition to the old API. */
@@ -563,31 +554,16 @@ AP_CORE_DECLARE(void) ap_parse_uri(request_rec *r, const char *uri)
     }
 }
 
-/* get the length of the field name for logging, but no more than 80 bytes */
-#define LOG_NAME_MAX_LEN 80
-static int field_name_len(const char *field)
-{
-    const char *end = ap_strchr_c(field, ':');
-    if (end == NULL || end - field > LOG_NAME_MAX_LEN)
-        return LOG_NAME_MAX_LEN;
-    return end - field;
-}
-
 static int read_request_line(request_rec *r, apr_bucket_brigade *bb)
 {
-    enum {
-        rrl_none, rrl_badmethod, rrl_badwhitespace, rrl_excesswhitespace,
-        rrl_missinguri, rrl_baduri, rrl_badprotocol, rrl_trailingtext,
-        rrl_badmethod09, rrl_reject09
-    } deferred_error = rrl_none;
-    char *ll;
-    char *uri;
+    const char *ll;
+    const char *uri;
+    const char *pro;
+
+    unsigned int major = 1, minor = 0;   /* Assume HTTP/1.0 if non-"HTTP" protocol */
+    char http[5];
     apr_size_t len;
     int num_blank_lines = DEFAULT_LIMIT_BLANK_LINES;
-    core_server_config *conf =
-        (core_server_config *)ap_get_module_config(r->server->module_config,
-                                                   &core_module);
-    int strict = (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE);
 
     /* Read past empty lines until we get a real request line,
      * a read error, the connection closes (EOF), or we timeout.
@@ -612,7 +588,7 @@ static int read_request_line(request_rec *r, apr_bucket_brigade *bb)
          */
         r->the_request = NULL;
         rv = ap_rgetline(&(r->the_request), (apr_size_t)(r->server->limit_req_line + 2),
-                         &len, r, strict ? AP_GETLINE_CRLF : 0, bb);
+                         &len, r, 0, bb);
 
         if (rv != APR_SUCCESS) {
             r->request_time = apr_time_now();
@@ -622,7 +598,7 @@ static int read_request_line(request_rec *r, apr_bucket_brigade *bb)
              * happen if it exceeds the configured limit for a request-line.
              */
             if (APR_STATUS_IS_ENOSPC(rv)) {
-                r->status = HTTP_REQUEST_URI_TOO_LARGE;
+                r->status    = HTTP_REQUEST_URI_TOO_LARGE;
             }
             else if (APR_STATUS_IS_TIMEUP(rv)) {
                 r->status = HTTP_REQUEST_TIME_OUT;
@@ -637,282 +613,68 @@ static int read_request_line(request_rec *r, apr_bucket_brigade *bb)
     } while ((len <= 0) && (--num_blank_lines >= 0));
 
     r->request_time = apr_time_now();
+    ll = r->the_request;
+    r->method = ap_getword_white(r->pool, &ll);
 
-    r->method = r->the_request;
-
-    /* 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);
-    }
-    else {
-        ll = (char*) ap_scan_vchar_obstext(r->method);
-    }
-
-    if (((ll == r->method) || (*ll && !apr_isspace(*ll)))
-            && deferred_error == rrl_none) {
-        deferred_error = rrl_badmethod;
-        ll = strpbrk(ll, "\t\n\v\f\r ");
-    }
+    uri = ap_getword_white(r->pool, &ll);
 
-    /* Verify method terminated with a single SP, or mark as specific error */
-    if (!ll) {
-        if (deferred_error == rrl_none)
-            deferred_error = rrl_missinguri;
-        r->protocol = uri = "";
-        len = 0;
-        goto rrl_done;
-    }
-    else if (strict && 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 (*uri != ' ' && deferred_error == rrl_none)
-            deferred_error = rrl_badwhitespace; 
-    *ll = '\0';
-
-    if (!*uri && deferred_error == rrl_none)
-        deferred_error = rrl_missinguri;
-
-    /* Scan the URI up to the next whitespace, ensure it contains no raw
-     * control characters, otherwise mark in error
-     */
-    ll = (char*) ap_scan_vchar_obstext(uri);
-    if (ll == uri || (*ll && !apr_isspace(*ll))) {
-        deferred_error = rrl_baduri;
-        ll = strpbrk(ll, "\t\n\v\f\r ");
-    }
-
-    /* Verify URI terminated with a single SP, or mark as specific error */
-    if (!ll) {
-        r->protocol = "";
-        len = 0;
-        goto rrl_done;
-    }
-    else if (strict && 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 (*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 = (char*) ap_scan_vchar_obstext(r->protocol))) {
-        len = strlen(r->protocol);
-        goto rrl_done;
-    }
-    len = ll - r->protocol;
-
-    /* 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 (*ll && !apr_isspace(*ll)) {
-        deferred_error = rrl_badprotocol;
-    }
-    else if (strict && *ll) {
-        deferred_error = rrl_excesswhitespace;
-    }
-    else {
-        for ( ; apr_isspace(*ll); ++ll)
-            if (*ll != ' ' && deferred_error == rrl_none)
-                deferred_error = rrl_badwhitespace; 
-        if (*ll && deferred_error == rrl_none)
-            deferred_error = rrl_trailingtext;
+    if (!*r->method || !*uri) {
+        r->status    = HTTP_BAD_REQUEST;
+        r->proto_num = HTTP_VERSION(1,0);
+        r->protocol  = apr_pstrdup(r->pool, "HTTP/1.0");
+        return 0;
     }
-    *((char *)r->protocol + len) = '\0';
 
-rrl_done:
-    /* 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);
+    /* Provide quick information about the request method as soon as known */
 
-    if (len == 8
-            && r->protocol[0] == 'H' && r->protocol[1] == 'T'
-            && r->protocol[2] == 'T' && r->protocol[3] == 'P'
-            && r->protocol[4] == '/' && apr_isdigit(r->protocol[5])
-            && r->protocol[6] == '.' && apr_isdigit(r->protocol[7])
-            && r->protocol[5] != '0') {
-        r->assbackwards = 0;
-        r->proto_num = HTTP_VERSION(r->protocol[5] - '0', r->protocol[7] - '0');
-    }
-    else if (len == 8
-                 && (r->protocol[0] == 'H' || r->protocol[0] == 'h')
-                 && (r->protocol[1] == 'T' || r->protocol[1] == 't')
-                 && (r->protocol[2] == 'T' || r->protocol[2] == 't')
-                 && (r->protocol[3] == 'P' || r->protocol[3] == 'p')
-                 && r->protocol[4] == '/' && apr_isdigit(r->protocol[5])
-                 && r->protocol[6] == '.' && apr_isdigit(r->protocol[7])
-                 && r->protocol[5] != '0') {
-        r->assbackwards = 0;
-        r->proto_num = HTTP_VERSION(r->protocol[5] - '0', r->protocol[7] - '0');
-        if (strict && deferred_error == rrl_none)
-            deferred_error = rrl_badprotocol;
-        else
-            memcpy((char*)r->protocol, "HTTP", 4);
-    }
-    else if (r->protocol[0]) {
-        r->proto_num = HTTP_VERSION(0, 9);
-        /* Defer setting the r->protocol string till error msg is composed */
-        if (deferred_error == rrl_none)
-            deferred_error = rrl_badprotocol;
-    }
-    else {
-        r->assbackwards = 1;
-        r->protocol  = apr_pstrdup(r->pool, "HTTP/0.9");
-        r->proto_num = HTTP_VERSION(0, 9);
-    }
-
-    /* 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);
-    if (r->method_number == M_GET && r->method[0] == 'H')
+    if (r->method_number == M_GET && r->method[0] == 'H') {
         r->header_only = 1;
-
-    ap_parse_uri(r, uri);
-
-    /* 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_DEBUG, 0, r,
-                          "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,
-                          "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_DEBUG, 0, r,
-                          "HTTP Request Line; Missing URI");
-        else if (deferred_error == rrl_baduri)
-            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
-                          "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_DEBUG, 0, r,
-                          "HTTP Request Line; Invalid whitespace");
-        else if (deferred_error == rrl_excesswhitespace)
-            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
-                          "HTTP Request Line; Excess whitespace "
-                          "(disallowed by HttpProtocolOptions Strict");
-        else if (deferred_error == rrl_trailingtext)
-            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
-                          "HTTP Request Line; Extraneous text found '%.*s' "
-                          "(perhaps whitespace was injected?)",
-                          field_name_len(ll), ll);
-        else if (deferred_error == rrl_reject09)
-            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
-                          "HTTP Request Line; Rejected HTTP/0.9 request");
-        else if (deferred_error == rrl_badprotocol)
-            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
-                          "HTTP Request Line; Unrecognized protocol '%.*s' "
-                          "(perhaps whitespace was injected?)",
-                          field_name_len(r->protocol), r->protocol);
-        r->status = HTTP_BAD_REQUEST;
-        goto rrl_failed;
     }
 
-    if (conf->http_methods == AP_HTTP_METHODS_REGISTERED
-            && r->method_number == M_INVALID) {
-        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
-                      "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 */
+    ap_parse_uri(r, uri);
+    if (r->status != HTTP_OK) {
+        r->proto_num = HTTP_VERSION(1,0);
+        r->protocol  = apr_pstrdup(r->pool, "HTTP/1.0");
         return 0;
     }
 
-    if (r->status != HTTP_OK) {
-        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
-                      "HTTP Request Line; Unable to parse URI: '%.*s'",
-                      field_name_len(r->uri), r->uri);
-        goto rrl_failed;
+    if (ll[0]) {
+        r->assbackwards = 0;
+        pro = ll;
+        len = strlen(ll);
+    } else {
+        r->assbackwards = 1;
+        pro = "HTTP/0.9";
+        len = 8;
     }
+    r->protocol = apr_pstrmemdup(r->pool, pro, len);
 
-    if (strict) {
-        if (r->parsed_uri.fragment) {
-            /* RFC3986 3.5: no fragment */
-            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
-                          "HTTP Request Line; URI must not contain a fragment");
-            r->status = HTTP_BAD_REQUEST;
-            goto rrl_failed;
-        }
-        if (r->parsed_uri.user || r->parsed_uri.password) {
-            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
-                          "HTTP Request Line; URI must not contain a "
-                          "username/password");
-            r->status = HTTP_BAD_REQUEST;
-            goto rrl_failed;
-        }
-    }
+    /* Avoid sscanf in the common case */
+    if (len == 8
+        && pro[0] == 'H' && pro[1] == 'T' && pro[2] == 'T' && pro[3] == 'P'
+        && pro[4] == '/' && apr_isdigit(pro[5]) && pro[6] == '.'
+        && apr_isdigit(pro[7])) {
+        r->proto_num = HTTP_VERSION(pro[5] - '0', pro[7] - '0');
+    }
+    else if (3 == sscanf(r->protocol, "%4s/%u.%u", http, &major, &minor)
+             && (strcasecmp("http", http) == 0)
+             && (minor < HTTP_VERSION(1, 0)) ) /* don't allow HTTP/0.1000 */
+        r->proto_num = HTTP_VERSION(major, minor);
+    else
+        r->proto_num = HTTP_VERSION(1, 0);
 
     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  = apr_pstrdup(r->pool, "HTTP/1.0");
-    }
-    return 0;
 }
 
-static int table_do_fn_check_lengths(void *r_, const char *key,
-                                     const char *value)
+/* get the length of the field name for logging, but no more than 80 bytes */
+#define LOG_NAME_MAX_LEN 80
+static int field_name_len(const char *field)
 {
-    request_rec *r = r_;
-    if (value == NULL || r->server->limit_req_fieldsize >= strlen(value) )
-        return 1;
-
-    r->status = HTTP_BAD_REQUEST;
-    apr_table_setn(r->notes, "error-notes",
-                   "Size of a request header field exceeds server limit.");
-    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Request "
-                  "header exceeds LimitRequestFieldSize after merging: %.*s",
-                  field_name_len(key), key);
-    return 0;
+    const char *end = ap_strchr_c(field, ':');
+    if (end == NULL || end - field > LOG_NAME_MAX_LEN)
+        return LOG_NAME_MAX_LEN;
+    return end - field;
 }
 
 AP_DECLARE(void) ap_get_mime_headers_core(request_rec *r, apr_bucket_brigade *bb)
@@ -925,10 +687,6 @@ AP_DECLARE(void) ap_get_mime_headers_core(request_rec *r, apr_bucket_brigade *bb
     apr_size_t len;
     int fields_read = 0;
     char *tmp_field;
-    core_server_config *conf =
-        (core_server_config *)ap_get_module_config(r->server->module_config,
-                                                   &core_module);
-    int strict = (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE);
 
     /*
      * Read header lines until we get the empty separator line, a read error,
@@ -936,10 +694,11 @@ AP_DECLARE(void) ap_get_mime_headers_core(request_rec *r, apr_bucket_brigade *bb
      */
     while(1) {
         apr_status_t rv;
+        int folded = 0;
 
         field = NULL;
         rv = ap_rgetline(&field, r->server->limit_req_fieldsize + 2,
-                         &len, r, strict ? AP_GETLINE_CRLF : 0, bb);
+                         &len, r, 0, bb);
 
         if (rv != APR_SUCCESS) {
             if (APR_STATUS_IS_TIMEUP(rv)) {
@@ -955,228 +714,148 @@ AP_DECLARE(void) ap_get_mime_headers_core(request_rec *r, apr_bucket_brigade *bb
              * finding the end-of-line.  This is only going to happen if it
              * exceeds the configured limit for a field size.
              */
-            if (rv == APR_ENOSPC) {
+            if (rv == APR_ENOSPC && field) {
+                /* ensure ap_escape_html will terminate correctly */
+                field[len - 1] = '\0';
                 apr_table_setn(r->notes, "error-notes",
-                               "Size of a request header field "
-                               "exceeds server limit.");
-                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
-                              "Request header exceeds LimitRequestFieldSize%s"
-                              "%.*s",
-                              (field && *field) ? ": " : "",
-                              (field) ? field_name_len(field) : 0,
-                              (field) ? field : "");
+                               apr_psprintf(r->pool,
+                                           "Size of a request header field "
+                                           "exceeds server limit.<br />\n"
+                                           "<pre>\n%.*s\n</pre>/n",
+                                           field_name_len(field), 
+                                           ap_escape_html(r->pool, field)));
+                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 
+                              "Request header exceeds LimitRequestFieldSize: "
+                              "%.*s", field_name_len(field), field);
             }
             return;
         }
 
-        /* For all header values, and all obs-fold lines, the presence of
-         * additional whitespace is a no-op, so collapse trailing whitespace
-         * to save buffer allocation and optimize copy operations.
-         * Do not remove the last single whitespace under any condition.
-         */
-        while (len > 1 && (field[len-1] == '\t' || field[len-1] == ' ')) {
-            field[--len] = '\0';
-        } 
-
-        if (*field == '\t' || *field == ' ') {
-
-            /* Append any newly-read obs-fold line onto the preceding
-             * last_field line we are processing
-             */
-            apr_size_t fold_len;
-
-            if (last_field == NULL) {
-                r->status = HTTP_BAD_REQUEST;
-                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
-                              "Line folding encountered before first"
-                              " header line");
-                return;
-            }
-
-            if (field[1] == '\0') {
-                r->status = HTTP_BAD_REQUEST;
-                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
-                              "Empty folded line encountered");
-                return;
-            }
-
-            /* Leading whitespace on an obs-fold line can be
-             * similarly discarded */
-            while (field[1] == '\t' || field[1] == ' ') {
-                ++field; --len;
-            }
-
-            /* 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)) {
-                r->status = HTTP_BAD_REQUEST;
-                /* report what we have accumulated so far before the
-                 * overflow (last_field) as the field with the problem
+        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_table_setn(r->notes, "error-notes",
-                               "Size of a request header field "
-                               "exceeds server limit.");
-                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
-                              "Request header exceeds LimitRequestFieldSize "
-                              "after folding: %.*s",
-                              field_name_len(last_field), last_field);
-                return;
-            }
+                apr_size_t fold_len = last_len + len + 1; /* trailing null */
+
+                if (fold_len >= (apr_size_t)(r->server->limit_req_fieldsize)) {
+                    r->status = HTTP_BAD_REQUEST;
+                    /* report what we have accumulated so far before the
+                     * overflow (last_field) as the field with the problem
+                     */
+                    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(last_field),
+                                               ap_escape_html(r->pool, last_field)));
+                    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+                                  "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 */
+                last_len += len;
+                folded = 1;
             }
-            memcpy(last_field + last_len, field, len +1); /* +1 for nul */
-            /* Replace obs-fold w/ SP per RFC 7230 3.2.4 */
-            last_field[last_len] = ' ';
-            last_len += len;
-
-            /* We've appended this obs-fold line to last_len, proceed to
-             * read the next input line
-             */
-            continue;
-        }
-        else if (last_field != NULL) {
+            else /* not a continuation line */ {
 
-            /* Process the previous last_field header line with all obs-folded
-             * segments already concatinated (this is not operating on the
-             * most recently read input line).
-             */
-
-            if (r->server->limit_req_fields
+                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,
-                              "Number of request headers exceeds "
-                              "LimitRequestFields");
-                return;
-            }
-
-            if (!strict)
-            {
-                /* Not Strict ('Unsafe' mode), using the legacy parser */
+                    r->status = HTTP_BAD_REQUEST;
+                    apr_table_setn(r->notes, "error-notes",
+                                   "The number of request header fields "
+                                   "exceeds this server's limit.");
+                    return;
+                }
 
-                if (!(value = strchr(last_field, ':'))) { /* Find ':' or */
-                    r->status = HTTP_BAD_REQUEST;   /* abort bad request */
+                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_DEBUG, 0, r,
                                   "Request header field is missing ':' "
                                   "separator: %.*s", (int)LOG_NAME_MAX_LEN,
                                   last_field);
+
                     return;
                 }
 
-                /* last character of field-name */
-                tmp_field = value - (value > last_field ? 1 : 0);
+                tmp_field = value - 1; /* last character of field-name */
 
                 *value++ = '\0'; /* NUL-terminate at colon */
 
-                if (strpbrk(last_field, "\t\n\v\f\r ")) {
-                    r->status = HTTP_BAD_REQUEST;
-                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
-                                  "Request header field name presented"
-                                  " invalid whitespace");
-                    return;
-                }
-
                 while (*value == ' ' || *value == '\t') {
-                     ++value;            /* Skip to start of value   */
-                }
-
-                if (strpbrk(value, "\n\v\f\r")) {
-                    r->status = HTTP_BAD_REQUEST;
-                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
-                                  "Request header field value presented"
-                                  " bad whitespace");
-                    return;
+                    ++value;            /* Skip to start of value   */
                 }
 
-                if (tmp_field == last_field) {
-                    r->status = HTTP_BAD_REQUEST;
-                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
-                                  "Request header field name was empty");
-                    return;
+                /* Strip LWS after field-name: */
+                while (tmp_field > last_field
+                       && (*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;
-                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
-                                  "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 */
+                /* Strip LWS after field-value: */
+                tmp_field = last_field + last_len - 1;
+                while (tmp_field > value
+                       && (*tmp_field == ' ' || *tmp_field == '\t')) {
+                    *tmp_field-- = '\0';
                 }
 
-                /* Find invalid, non-HT ctrl char, or the trailing NULL */
-                tmp_field = (char *)ap_scan_http_field_content(value);
+                apr_table_addn(r->headers_in, last_field, value);
 
-                /* 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
+                /* 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
                  */
-                if (*tmp_field != '\0') {
-                    r->status = HTTP_BAD_REQUEST;
-                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
-                                  "Request header value is malformed: "
-                                  "%.*s", (int)LOG_NAME_MAX_LEN, value);
-                    return;
-                }
-            }
-
-            apr_table_addn(r->headers_in, last_field, value);
+                alloc_len = 0;
 
-            /* This last_field header is now stored in headers_in,
-             * resume processing of the current input line.
-             */
+            } /* end if current line is not a continuation starting with tab */
         }
 
-        /* Found the terminating empty end-of-headers line, stop. */
+        /* Found a blank line, stop. */
         if (len == 0) {
             break;
         }
 
-        /* Keep track of this new header line so that we can extend it across
-         * any obs-fold or parse it on the next loop iteration. We referenced
-         * our previously allocated buffer in r->headers_in,
-         * so allocate a fresh buffer if required.
+        /* 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
      * field-name, following RFC 2616, 4.2.
      */
     apr_table_compress(r->headers_in, APR_OVERLAP_TABLES_MERGE);
-
-    /* enforce LimitRequestFieldSize for merged headers */
-    apr_table_do(table_do_fn_check_lengths, r, r->headers_in, NULL);
 }
 
 AP_DECLARE(void) ap_get_mime_headers(request_rec *r)
@@ -1244,38 +923,33 @@ request_rec *ap_read_request(conn_rec *conn)
 
     /* Get the request... */
     if (!read_request_line(r, tmp_bb)) {
-        switch (r->status) {
-        case HTTP_REQUEST_URI_TOO_LARGE:
-        case HTTP_BAD_REQUEST:
-        case HTTP_VERSION_NOT_SUPPORTED:
-        case HTTP_NOT_IMPLEMENTED:
-            if (r->status == HTTP_REQUEST_URI_TOO_LARGE) {
-                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
-                              "request failed: client's request-line exceeds LimitRequestLine (longer than %d)",
-                              r->server->limit_req_line);
+        if (r->status == HTTP_REQUEST_URI_TOO_LARGE
+            || r->status == HTTP_BAD_REQUEST) {
+            if (r->status == HTTP_BAD_REQUEST) {
+                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                              "request failed: invalid characters in URI");
             }
-            else if (r->method == NULL) {
-                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
-                              "request failed: malformed request line");
+            else {
+                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                              "request failed: URI too long (longer than %d)", r->server->limit_req_line);
             }
-            access_status = r->status;
-            r->status = HTTP_OK;
-            ap_die(access_status, r);
+            ap_send_error_response(r, 0);
             ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
             ap_run_log_transaction(r);
-            r = NULL;
             apr_brigade_destroy(tmp_bb);
             return r;
-        case HTTP_REQUEST_TIME_OUT:
+        }
+        else if (r->status == HTTP_REQUEST_TIME_OUT) {
             ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
-            if (!r->connection->keepalives)
+            if (!r->connection->keepalives) {
                 ap_run_log_transaction(r);
-            apr_brigade_destroy(tmp_bb);
-            return r;
-        default:
+            }
             apr_brigade_destroy(tmp_bb);
             return r;
         }
+
+        apr_brigade_destroy(tmp_bb);
+        return NULL;
     }
 
     /* We may have been in keep_alive_timeout mode, so toggle back
@@ -1294,7 +968,7 @@ request_rec *ap_read_request(conn_rec *conn)
 
         ap_get_mime_headers_core(r, tmp_bb);
         if (r->status != HTTP_OK) {
-            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                           "request failed: error reading the headers");
             ap_send_error_response(r, 0);
             ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
@@ -1313,7 +987,7 @@ request_rec *ap_read_request(conn_rec *conn)
              */
             if (!(strcasecmp(tenc, "chunked") == 0 /* fast path */
                     || ap_find_last_token(r->pool, tenc, "chunked"))) {
-                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
                               "client sent unknown Transfer-Encoding "
                               "(%s): %s", tenc, r->uri);
                 r->status = HTTP_BAD_REQUEST;
@@ -1334,6 +1008,25 @@ request_rec *ap_read_request(conn_rec *conn)
             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_ERR, 0, r,
+                          "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);
+            return r;
+        }
+    }
 
     apr_brigade_destroy(tmp_bb);
 
@@ -1341,7 +1034,6 @@ request_rec *ap_read_request(conn_rec *conn)
      * now read. may update status.
      */
     ap_update_vhost_from_headers(r);
-    access_status = r->status;
 
     /* Toggle to the Host:-based vhost's timeout mode to fetch the
      * request body and send the response body, if needed.
@@ -1364,8 +1056,8 @@ request_rec *ap_read_request(conn_rec *conn)
          * HTTP/1.1 mentions twice (S9, S14.23) that a request MUST contain
          * 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_DEBUG, 0, r,
+        r->status = HTTP_BAD_REQUEST;
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                       "client sent HTTP/1.1 request without hostname "
                       "(see RFC2616 section 14.23): %s", r->uri);
     }
@@ -1380,8 +1072,14 @@ request_rec *ap_read_request(conn_rec *conn)
     ap_add_input_filter_handle(ap_http_input_filter_handle,
                                NULL, r, r->connection);
 
-    if (access_status != HTTP_OK
-        || (access_status = ap_run_post_read_request(r))) {
+    if (r->status != HTTP_OK) {
+        ap_send_error_response(r, 0);
+        ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
+        ap_run_log_transaction(r);
+        return r;
+    }
+
+    if ((access_status = ap_run_post_read_request(r))) {
         ap_die(access_status, r);
         ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
         ap_run_log_transaction(r);
@@ -1581,7 +1279,7 @@ AP_DECLARE(int) ap_get_basic_auth_pw(request_rec *r, const char **pw)
 
     if (strcasecmp(ap_getword(r->pool, &auth_line, ' '), "Basic")) {
         /* Client tried to authenticate using wrong auth scheme */
-        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                       "client used wrong authentication scheme: %s", r->uri);
         ap_note_basic_auth_failure(r);
         return HTTP_UNAUTHORIZED;
index 054cc1760d562d46ee48933bb4f074c100fc9c1f..5dee87fd22925475ebfe5f37cf45fe568559aa98 100644 (file)
@@ -71,7 +71,7 @@
  * char in here and get it to work, because if char is signed then it
  * will first be sign extended.
  */
-#define TEST_CHAR(c, f)        (test_char_table[(unsigned char)(c)] & (f))
+#define TEST_CHAR(c, f)        (test_char_table[(unsigned)(c)] & (f))
 
 /* Win32/NetWare/OS2 need to check for both forward and back slashes
  * in ap_getparents() and ap_escape_url.
@@ -1425,36 +1425,6 @@ AP_DECLARE(int) ap_find_list_item(apr_pool_t *p, const char *line,
     return good;
 }
 
-/* Scan a string for HTTP VCHAR/obs-text characters including HT and SP
- * (as used in header values, for example, in RFC 7230 section 3.2)
- * returning the pointer to the first non-HT ASCII ctrl character.
- */
-AP_DECLARE(const char *) ap_scan_http_field_content(const char *ptr)
-{
-    for ( ; !TEST_CHAR(*ptr, T_HTTP_CTRLS); ++ptr) ;
-
-    return ptr;
-}
-
-/* Scan a string for HTTP token characters, returning the pointer to
- * the first non-token character.
- */
-AP_DECLARE(const char *) ap_scan_http_token(const char *ptr)
-{
-    for ( ; !TEST_CHAR(*ptr, T_HTTP_TOKEN_STOP); ++ptr) ;
-
-    return ptr;
-}
-
-/* Scan a string for visible ASCII (0x21-0x7E) or obstext (0x80+)
- * and return a pointer to the first ctrl/space character encountered.
- */
-AP_DECLARE(const char *) ap_scan_vchar_obstext(const char *ptr)
-{
-    for ( ; TEST_CHAR(*ptr, T_VCHAR_OBSTEXT); ++ptr) ;
-
-    return ptr;
-}
 
 /* Retrieve a token, spacing over it and returning a pointer to
  * the first non-white byte afterwards.  Note that these tokens
index c38b9368eb159457711e6aaab9ec43b60618de1d..b8e9ca7594ca3af6cd8d07b7a47f2ae39d2da317 100644 (file)
@@ -687,116 +687,6 @@ AP_DECLARE(void) ap_fini_vhost_config(apr_pool_t *p, server_rec *main_s)
  * run-time vhost matching functions
  */
 
-static apr_status_t fix_hostname_v6_literal(request_rec *r, char *host)
-{
-    char *dst;
-    int double_colon = 0;
-
-    for (dst = host; *dst; dst++) {
-        if (apr_isxdigit(*dst)) {
-            if (apr_isupper(*dst)) {
-                *dst = apr_tolower(*dst);
-            }
-        }
-        else if (*dst == ':') {
-            if (*(dst + 1) == ':') {
-                if (double_colon)
-                    return APR_EINVAL;
-                double_colon = 1;
-            }
-            else if (*(dst + 1) == '.') {
-                return APR_EINVAL;
-            }
-        }
-        else if (*dst == '.') {
-            /* For IPv4-mapped IPv6 addresses like ::FFFF:129.144.52.38 */
-            if (*(dst + 1) == ':' || *(dst + 1) == '.')
-                return APR_EINVAL;
-        }
-        else {
-            return APR_EINVAL;
-        }
-    }
-    return APR_SUCCESS;
-}
-
-static apr_status_t fix_hostname_non_v6(request_rec *r, char *host)
-{
-    char *dst;
-
-    for (dst = host; *dst; dst++) {
-        if (apr_islower(*dst)) {
-            /* leave char unchanged */
-        }
-        else if (*dst == '.') {
-            if (*(dst + 1) == '.') {
-                return APR_EINVAL;
-            }
-        }
-        else if (apr_isupper(*dst)) {
-            *dst = apr_tolower(*dst);
-        }
-        else if (*dst == '/' || *dst == '\\') {
-            return APR_EINVAL;
-        }
-    }
-    /* strip trailing gubbins */
-    if (dst > host && dst[-1] == '.') {
-        dst[-1] = '\0';
-    }
-    return APR_SUCCESS;
-}
-
-/*
- * If strict mode ever becomes the default, this should be folded into
- * fix_hostname_non_v6()
- */
-static apr_status_t strict_hostname_check(request_rec *r, char *host)
-{
-    char *ch;
-    int is_dotted_decimal = 1, leading_zeroes = 0, dots = 0;
-
-    for (ch = host; *ch; ch++) {
-        if (!apr_isascii(*ch)) {
-            goto bad;
-        }
-        else if (apr_isalpha(*ch) || *ch == '-') {
-            is_dotted_decimal = 0;
-        }
-        else if (ch[0] == '.') {
-            dots++;
-            if (ch[1] == '0' && apr_isdigit(ch[2]))
-                leading_zeroes = 1;
-        }
-        else if (!apr_isdigit(*ch)) {
-           /* also takes care of multiple Host headers by denying commas */
-            goto bad;
-        }
-    }
-    if (is_dotted_decimal) {
-        if (host[0] == '.' || (host[0] == '0' && apr_isdigit(host[1])))
-            leading_zeroes = 1;
-        if (leading_zeroes || dots != 3) {
-            /* RFC 3986 7.4 */
-            goto bad;
-        }
-    }
-    else {
-        /* The top-level domain must start with a letter (RFC 1123 2.1) */
-        while (ch > host && *ch != '.')
-            ch--;
-        if (ch[0] == '.' && ch[1] != '\0' && !apr_isalpha(ch[1]))
-            goto bad;
-    }
-    return APR_SUCCESS;
-
-bad:
-    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
-                  "[strict] Invalid host name '%s'%s%.6s",
-                  host, *ch ? ", problem near: " : "", ch);
-    return APR_EINVAL;
-}
-
 /* Lowercase and remove any trailing dot and/or :port from the hostname,
  * and check that it is sane.
  *
@@ -810,90 +700,78 @@ bad:
  * Instead we just check for filesystem metacharacters: directory
  * separators / and \ and sequences of more than one dot.
  */
-static int fix_hostname(request_rec *r, const char *host_header,
-                        unsigned http_conformance)
+static void fix_hostname(request_rec *r)
 {
-    const char *src;
     char *host, *scope_id;
+    char *dst;
     apr_port_t port;
     apr_status_t rv;
     const char *c;
-    int is_v6literal = 0;
-    int strict = (http_conformance != AP_HTTP_CONFORMANCE_UNSAFE);
-
-    src = host_header ? host_header : r->hostname;
 
-    /* According to RFC 2616, Host header field CAN be blank */
-    if (!*src) {
-        return is_v6literal;
+    /* According to RFC 2616, Host header field CAN be blank. */
+    if (!*r->hostname) {
+        return;
     }
 
     /* apr_parse_addr_port will interpret a bare integer as a port
      * which is incorrect in this context.  So treat it separately.
      */
-    for (c = src; apr_isdigit(*c); ++c);
-    if (!*c) {
-        /* pure integer */
-        if (strict) {
-            /* RFC 3986 7.4 */
-            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
-                         "[strict] purely numeric host names not allowed: %s",
-                         src);
-            goto bad_nolog;
-        }
-        r->hostname = src;
-        return is_v6literal;
+    for (c = r->hostname; apr_isdigit(*c); ++c);
+    if (!*c) {  /* pure integer */
+        return;
     }
 
-    if (host_header) {
-        rv = apr_parse_addr_port(&host, &scope_id, &port, src, r->pool);
-        if (rv != APR_SUCCESS || scope_id)
-            goto bad;
-        if (port) {
-            /* Don't throw the Host: header's port number away:
-               save it in parsed_uri -- ap_get_server_port() needs it! */
-            /* @@@ XXX there should be a better way to pass the port.
-             *         Like r->hostname, there should be a r->portno
-             */
-            r->parsed_uri.port = port;
-            r->parsed_uri.port_str = apr_itoa(r->pool, (int)port);
-        }
-        if (host_header[0] == '[')
-            is_v6literal = 1;
+    rv = apr_parse_addr_port(&host, &scope_id, &port, r->hostname, r->pool);
+    if (rv != APR_SUCCESS || scope_id) {
+        goto bad;
     }
-    else {
-        /*
-         * Already parsed, surrounding [ ] (if IPv6 literal) and :port have
-         * already been removed.
+
+    if (port) {
+        /* Don't throw the Host: header's port number away:
+           save it in parsed_uri -- ap_get_server_port() needs it! */
+        /* @@@ XXX there should be a better way to pass the port.
+         *         Like r->hostname, there should be a r->portno
          */
-        host = apr_pstrdup(r->pool, r->hostname);
-        if (ap_strchr(host, ':') != NULL)
-            is_v6literal = 1;
+        r->parsed_uri.port = port;
+        r->parsed_uri.port_str = apr_itoa(r->pool, (int)port);
     }
 
-    if (is_v6literal) {
-        rv = fix_hostname_v6_literal(r, host);
-    }
-    else {
-        rv = fix_hostname_non_v6(r, host);
-        if (strict && rv == APR_SUCCESS)
-            rv = strict_hostname_check(r, host);
+    /* if the hostname is an IPv6 numeric address string, it was validated
+     * already; otherwise, further validation is needed
+     */
+    if (r->hostname[0] != '[') {
+        for (dst = host; *dst; dst++) {
+            if (apr_islower(*dst)) {
+                /* leave char unchanged */
+            }
+            else if (*dst == '.') {
+                if (*(dst + 1) == '.') {
+                    goto bad;
+                }
+            }
+            else if (apr_isupper(*dst)) {
+                *dst = apr_tolower(*dst);
+            }
+            else if (*dst == '/' || *dst == '\\') {
+                goto bad;
+            }
+        }
+        /* strip trailing gubbins */
+        if (dst > host && dst[-1] == '.') {
+            dst[-1] = '\0';
+        }
     }
-    if (rv != APR_SUCCESS)
-        goto bad;
-
     r->hostname = host;
-    return is_v6literal;
+    return;
 
 bad:
-    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
-                  "Client sent malformed Host header: %s",
-                  src);
-bad_nolog:
     r->status = HTTP_BAD_REQUEST;
-    return is_v6literal;
+    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                  "Client sent malformed Host header");
+    return;
 }
 
+
 /* return 1 if host matches ServerName or ServerAliases */
 static int matches_aliases(server_rec *s, const char *host)
 {
@@ -1090,78 +968,15 @@ static void check_serverpath(request_rec *r)
     }
 }
 
-static APR_INLINE const char *construct_host_header(request_rec *r,
-                                                    int is_v6literal)
-{
-    struct iovec iov[5];
-    apr_size_t nvec = 0;
-    /*
-     * We cannot use ap_get_server_name/port here, because we must
-     * ignore UseCanonicalName/Port.
-     */
-    if (is_v6literal) {
-        iov[nvec].iov_base = "[";
-        iov[nvec].iov_len = 1;
-        nvec++;
-    }
-    iov[nvec].iov_base = (void *)r->hostname;
-    iov[nvec].iov_len = strlen(r->hostname);
-    nvec++;
-    if (is_v6literal) {
-        iov[nvec].iov_base = "]";
-        iov[nvec].iov_len = 1;
-        nvec++;
-    }
-    if (r->parsed_uri.port_str) {
-        iov[nvec].iov_base = ":";
-        iov[nvec].iov_len = 1;
-        nvec++;
-        iov[nvec].iov_base = r->parsed_uri.port_str;
-        iov[nvec].iov_len = strlen(r->parsed_uri.port_str);
-        nvec++;
-    }
-    return apr_pstrcatv(r->pool, iov, nvec, NULL);
-}
 
 AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r)
 {
-    core_server_config *conf =
-        (core_server_config *)ap_get_module_config(r->server->module_config,
-                                                   &core_module);
-    const char *host_header = apr_table_get(r->headers_in, "Host");
-    int is_v6literal = 0;
-    int have_hostname_from_url = 0;
-
-    if (r->hostname) {
-        /*
-         * If there was a host part in the Request-URI, ignore the 'Host'
-         * header.
-         */
-        have_hostname_from_url = 1;
-        is_v6literal = fix_hostname(r, NULL, conf->http_conformance);
-    }
-    else if (host_header != NULL) {
-        is_v6literal = fix_hostname(r, host_header, conf->http_conformance);
-    }
-    if (r->status != HTTP_OK)
-        return;
-
-    if (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE) {
-        /*
-         * If we have both hostname from an absoluteURI and a Host header,
-         * we must ignore the Host header (RFC 2616 5.2).
-         * To enforce this, we reset the Host header to the value from the
-         * request line.
-         */
-        if (have_hostname_from_url && host_header != NULL) {
-            const char *repl = construct_host_header(r, is_v6literal);
-            apr_table_set(r->headers_in, "Host", repl);
-            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
-                          "Replacing host header '%s' with host '%s' given "
-                          "in the request uri", host_header, repl);
-        }
+    /* must set this for HTTP/1.1 support */
+    if (r->hostname || (r->hostname = apr_table_get(r->headers_in, "Host"))) {
+        fix_hostname(r);
+        if (r->status != HTTP_OK)
+            return;
     }
-
     /* check if we tucked away a name_chain */
     if (r->connection->vhost_lookup_data) {
         if (r->hostname)