You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Jim Jagielski <ji...@jaguNET.com> on 2002/10/07 20:59:57 UTC

[PATCH] bogus header handling in ap_proxy_read_headers

This patch adds a directive that controls how the proxy module should
handle bogus headers when reading headers... Right now, any bogus
header results in in BAD_GATEWAY... 1.3 was somewhat more resiliant.


Index: modules/proxy/mod_proxy.c
===================================================================
RCS file: /home/cvs/httpd-2.0/modules/proxy/mod_proxy.c,v
retrieving revision 1.89
diff -u -r1.89 mod_proxy.c
--- modules/proxy/mod_proxy.c	8 Sep 2002 17:56:18 -0000	1.89
+++ modules/proxy/mod_proxy.c	7 Oct 2002 18:54:03 -0000
@@ -63,8 +63,6 @@
 
 #include "apr_optional.h"
 
-extern module AP_MODULE_DECLARE_DATA proxy_module;
-
 #ifndef MAX
 #define MAX(x,y) ((x) >= (y) ? (x) : (y))
 #endif
@@ -499,10 +497,12 @@
     ps->maxfwd_set = 0;
     ps->error_override = 0; 
     ps->error_override_set = 0; 
-    ps->preserve_host_set =0;
-    ps->preserve_host =0;    
-    ps->timeout=0;
-    ps->timeout_set=0;
+    ps->preserve_host_set = 0;
+    ps->preserve_host = 0;    
+    ps->timeout = 0;
+    ps->timeout_set = 0;
+    ps->badopt = bad_error;
+    ps->badopt_set = 0;
     return ps;
 }
 
@@ -529,6 +529,7 @@
     ps->error_override = (overrides->error_override_set == 0) ? base->error_override : overrides->error_override;
     ps->preserve_host = (overrides->preserve_host_set == 0) ? base->preserve_host : overrides->preserve_host;
     ps->timeout= (overrides->timeout_set == 0) ? base->timeout : overrides->timeout;
+    ps->badopt = (overrides->badopt_set == 0) ? base->badopt : overrides->badopt;
 
     return ps;
 }
@@ -914,6 +915,27 @@
     return NULL;    
 }
 
+static const char*
+    set_bad_opt(cmd_parms *parms, void *dummy, const char *arg)
+{
+    proxy_server_conf *psf =
+    ap_get_module_config(parms->server->module_config, &proxy_module);
+
+    if (strcasecmp(arg, "IsError") == 0)
+        psf->badopt = bad_error;
+    else if (strcasecmp(arg, "Ignore") == 0)
+        psf->badopt = bad_ignore;
+    else if (strcasecmp(arg, "StartBody") == 0)
+        psf->badopt = bad_body;
+    else {
+        return "ProxyBadHeader must be one of: "
+            "IsError | Ignore | StartBody";
+    }
+
+    psf->badopt_set = 1;
+    return NULL;    
+}
+
 static void ap_add_per_proxy_conf(server_rec *s, ap_conf_vector_t *dir_config)
 {
     proxy_server_conf *sconf = ap_get_module_config(s->module_config,
@@ -1042,6 +1064,8 @@
     AP_INIT_TAKE1("ProxyTimeout", set_proxy_timeout, NULL, RSRC_CONF,
      "Set the timeout (in seconds) for a proxied connection. "
      "This overrides the server timeout"),
+    AP_INIT_TAKE1("ProxyBadHeader", set_bad_opt, NULL, RSRC_CONF,
+     "How to handle bad header line in response: IsError | Ignore | StartBody"),
  
     {NULL}
 };
Index: modules/proxy/mod_proxy.h
===================================================================
RCS file: /home/cvs/httpd-2.0/modules/proxy/mod_proxy.h,v
retrieving revision 1.84
diff -u -r1.84 mod_proxy.h
--- modules/proxy/mod_proxy.h	11 Jul 2002 18:45:22 -0000	1.84
+++ modules/proxy/mod_proxy.h	7 Oct 2002 18:54:04 -0000
@@ -195,6 +195,12 @@
     int preserve_host_set;
     apr_interval_time_t timeout;
     apr_interval_time_t timeout_set;
+    enum {
+      bad_error,
+      bad_ignore,
+      bad_body
+    } badopt;                   /* how to deal with bad headers */
+    char badopt_set;
 
 } proxy_server_conf;
 
@@ -283,5 +289,8 @@
 PROXY_DECLARE(int) ap_proxy_connect_to_backend(apr_socket_t **, const char *, apr_sockaddr_t *, const char *, proxy_server_conf *, server_rec *, apr_pool_t *);
 PROXY_DECLARE(int) ap_proxy_ssl_enable(conn_rec *c);
 PROXY_DECLARE(int) ap_proxy_ssl_disable(conn_rec *c);
+
+/* For proxy_util */
+extern module AP_MODULE_DECLARE_DATA proxy_module;
 
 #endif /*MOD_PROXY_H*/
Index: modules/proxy/proxy_util.c
===================================================================
RCS file: /home/cvs/httpd-2.0/modules/proxy/proxy_util.c,v
retrieving revision 1.98
diff -u -r1.98 proxy_util.c
--- modules/proxy/proxy_util.c	25 Aug 2002 20:40:11 -0000	1.98
+++ modules/proxy/proxy_util.c	7 Oct 2002 18:54:05 -0000
@@ -433,6 +433,11 @@
     int len;
     char *value, *end;
     char field[MAX_STRING_LEN];
+    int saw_headers = 0;
+    void *sconf = r->server->module_config;
+    proxy_server_conf *psc;
+
+    psc = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
 
     headers_out = apr_table_make(r->pool, 20);
 
@@ -444,19 +449,46 @@
 
 	if (!(value = strchr(buffer, ':'))) {     /* Find the colon separator */
 
-	    /* Buggy MS IIS servers sometimes return invalid headers
-	     * (an extra "HTTP/1.0 200, OK" line sprinkled in between
-	     * the usual MIME headers). Try to deal with it in a sensible
-	     * way, but log the fact.
-	     * XXX: The mask check is buggy if we ever see an HTTP/1.10 */
+	    /* We may encounter invalid headers, usually from buggy
+	     * MS IIS servers, so we need to determine just how to handle
+	     * them. We can either ignore them, assume that they mark the
+	     * start-of-body (eg: a missing CRLF) or (the default) mark
+	     * the headers as totally bogus. The sole exception is an extra 
+	     * "HTTP/1.0 200, OK" line sprinkled in between the usual MIME
+	     * headers, which is a favorite IIS bug.
+	     */
+	     /* XXX: The mask check is buggy if we ever see an HTTP/1.10 */
 
 	    if (!apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
-		/* Nope, it wasn't even an extra HTTP header. Give up. */
-		return NULL;
+		if (psc->badopt == bad_error) {
+		    /* Nope, it wasn't even an extra HTTP header. Give up. */
+		    return NULL;
+		}
+		else if (psc->badopt == bad_body) {
+		    /* if we've already started loading headers_out, then
+		     * return what we've accumulated so far, in the hopes
+		     * that they are useful. Otherwise, we completely bail.
+		     */
+		    /* FIXME: We've already scarfed the supposed 1st line of
+		     * the body, so the actual content may end up being bogus
+		     * as well. If the content is HTML, we may be lucky.
+		     */
+		    if (saw_headers) {
+			ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
+			 "proxy: Starting body due to bogus non-header in headers "
+			 "returned by %s (%s)", r->uri, r->method);
+			return headers_out;
+		    } else {
+			 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
+			 "proxy: No HTTP headers "
+			 "returned by %s (%s)", r->uri, r->method);
+			return NULL;
+		    }
+		}
 	    }
-
+	    /* this is the psc->badopt == bad_ignore case */
 	    ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
-			 "proxy: Ignoring duplicate HTTP header "
+			 "proxy: Ignoring bogus HTTP header "
 			 "returned by %s (%s)", r->uri, r->method);
 	    continue;
 	}
@@ -475,6 +507,7 @@
 
         /* make sure we add so as not to destroy duplicated headers */
         apr_table_add(headers_out, buffer, value);
+        saw_headers = 1;
 
 	/* the header was too long; at the least we should skip extra data */
 	if (len >= size - 1) { 
-- 
===========================================================================
   Jim Jagielski   [|]   jim@jaguNET.com   [|]   http://www.jaguNET.com/
      "A society that will trade a little liberty for a little order
             will lose both and deserve neither" - T.Jefferson

RE: [PATCH] bogus header handling in ap_proxy_read_headers

Posted by Bill Stoddard <bi...@wstoddard.com>.
> This patch adds a directive

Do we really need a new directive?  I just have this general unease at the
number of new config directives we have been creating lately...

Bill