Hi,

Basically it adds servletnormalizecheck to mod_proxy for ProxyPass/ProxyPassMatch and mod_rewrite when using P
I have tested the following uses:
#ProxyPass /docs ajp://localhost:8009/docs secret=%A1b2!@ servletnormalizecheck

#ProxyPassMatch "^/docs(.*)$" "ajp://localhost:8009/docs$1" secret=%A1b2!@ servletnormalizecheck

#RewriteEngine On
#RewriteRule "^/docs(.*)$" "ajp://localhost:8009/docs$1" [P,SNC]
#<Proxy "ajp://localhost:8009/docs">
#ProxySet connectiontimeout=5 timeout=30 secret=%A1b2!@
#</Proxy>

#<Location "/docs">
#  ProxyPass  ajp://localhost:8009/docs secret=%A1b2!@ servletnormalizecheck
#</Location>

What is not supported is
curl -v --path-as-is "http://localhost:8000/docs/..;foo=bar/;foo=bar/test/index.jsp";

that could be remapped to
ProxyPass /test ajp://localhost:8009/test secret=%A1b2!@ servletnormalizecheck
or a <location test/>

Comments?

--
Cheers

Jean-Frederic
Index: build/find_apr.m4
===================================================================
--- build/find_apr.m4	(revision 1878566)
+++ build/find_apr.m4	(nonexistent)
@@ -1,202 +0,0 @@
-dnl -------------------------------------------------------- -*- autoconf -*-
-dnl Licensed to the Apache Software Foundation (ASF) under one or more
-dnl contributor license agreements.  See the NOTICE file distributed with
-dnl this work for additional information regarding copyright ownership.
-dnl The ASF licenses this file to You under the Apache License, Version 2.0
-dnl (the "License"); you may not use this file except in compliance with
-dnl the License.  You may obtain a copy of the License at
-dnl
-dnl     http://www.apache.org/licenses/LICENSE-2.0
-dnl
-dnl Unless required by applicable law or agreed to in writing, software
-dnl distributed under the License is distributed on an "AS IS" BASIS,
-dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-dnl See the License for the specific language governing permissions and
-dnl limitations under the License.
-
-dnl
-dnl find_apr.m4 : locate the APR include files and libraries
-dnl
-dnl This macro file can be used by applications to find and use the APR
-dnl library. It provides a standardized mechanism for using APR. It supports
-dnl embedding APR into the application source, or locating an installed
-dnl copy of APR.
-dnl
-dnl APR_FIND_APR(srcdir, builddir, implicit-install-check, acceptable-majors,
-dnl              detailed-check)
-dnl
-dnl   where srcdir is the location of the bundled APR source directory, or
-dnl   empty if source is not bundled.
-dnl
-dnl   where builddir is the location where the bundled APR will will be built,
-dnl   or empty if the build will occur in the srcdir.
-dnl
-dnl   where implicit-install-check set to 1 indicates if there is no
-dnl   --with-apr option specified, we will look for installed copies.
-dnl
-dnl   where acceptable-majors is a space separated list of acceptable major
-dnl   version numbers. Often only a single major version will be acceptable.
-dnl   If multiple versions are specified, and --with-apr=PREFIX or the
-dnl   implicit installed search are used, then the first (leftmost) version
-dnl   in the list that is found will be used.  Currently defaults to [0 1].
-dnl
-dnl   where detailed-check is an M4 macro which sets the apr_acceptable to
-dnl   either "yes" or "no". The macro will be invoked for each installed
-dnl   copy of APR found, with the apr_config variable set appropriately.
-dnl   Only installed copies of APR which are considered acceptable by
-dnl   this macro will be considered found. If no installed copies are
-dnl   considered acceptable by this macro, apr_found will be set to either
-dnl   either "no" or "reconfig".
-dnl
-dnl Sets the following variables on exit:
-dnl
-dnl   apr_found : "yes", "no", "reconfig"
-dnl
-dnl   apr_config : If the apr-config tool exists, this refers to it. If
-dnl                apr_found is "reconfig", then the bundled directory
-dnl                should be reconfigured *before* using apr_config.
-dnl
-dnl Note: this macro file assumes that apr-config has been installed; it
-dnl       is normally considered a required part of an APR installation.
-dnl
-dnl If a bundled source directory is available and needs to be (re)configured,
-dnl then apr_found is set to "reconfig". The caller should reconfigure the
-dnl (passed-in) source directory, placing the result in the build directory,
-dnl as appropriate.
-dnl
-dnl If apr_found is "yes" or "reconfig", then the caller should use the
-dnl value of apr_config to fetch any necessary build/link information.
-dnl
-
-AC_DEFUN([APR_FIND_APR], [
-  apr_found="no"
-
-  if test "$target_os" = "os2-emx"; then
-    # Scripts don't pass test -x on OS/2
-    TEST_X="test -f"
-  else
-    TEST_X="test -x"
-  fi
-
-  ifelse([$4], [], [
-         ifdef(AC_WARNING,AC_WARNING([$0: missing argument 4 (acceptable-majors): Defaulting to APR 0.x then APR 1.x]))
-         acceptable_majors="0 1"],
-         [acceptable_majors="$4"])
-
-  apr_temp_acceptable_apr_config=""
-  for apr_temp_major in $acceptable_majors
-  do
-    case $apr_temp_major in
-      0)
-      apr_temp_acceptable_apr_config="$apr_temp_acceptable_apr_config apr-config"
-      ;;
-      *)
-      apr_temp_acceptable_apr_config="$apr_temp_acceptable_apr_config apr-$apr_temp_major-config"
-      ;;
-    esac
-  done
-
-  AC_MSG_CHECKING(for APR)
-  AC_ARG_WITH(apr,
-  [  --with-apr=PATH         prefix for installed APR or the full path to 
-                             apr-config],
-  [
-    if test "$withval" = "no" || test "$withval" = "yes"; then
-      AC_MSG_ERROR([--with-apr requires a directory or file to be provided])
-    fi
-
-    for apr_temp_apr_config_file in $apr_temp_acceptable_apr_config
-    do
-      for lookdir in "$withval/bin" "$withval"
-      do
-        if $TEST_X "$lookdir/$apr_temp_apr_config_file"; then
-          apr_config="$lookdir/$apr_temp_apr_config_file"
-          ifelse([$5], [], [], [
-          apr_acceptable="yes"
-          $5
-          if test "$apr_acceptable" != "yes"; then
-            AC_MSG_WARN([Found APR in $apr_config, but we think it is considered unacceptable])
-            continue
-          fi])
-          apr_found="yes"
-          break 2
-        fi
-      done
-    done
-
-    if test "$apr_found" != "yes" && $TEST_X "$withval" && $withval --help > /dev/null 2>&1 ; then
-      apr_config="$withval"
-      ifelse([$5], [], [apr_found="yes"], [
-          apr_acceptable="yes"
-          $5
-          if test "$apr_acceptable" = "yes"; then
-                apr_found="yes"
-          fi])
-    fi
-
-    dnl if --with-apr is used, it is a fatal error for its argument
-    dnl to be invalid
-    if test "$apr_found" != "yes"; then
-      AC_MSG_ERROR([the --with-apr parameter is incorrect. It must specify an install prefix, a build directory, or an apr-config file.])
-    fi
-  ],[
-    dnl If we allow installed copies, check those before using bundled copy.
-    if test -n "$3" && test "$3" = "1"; then
-      for apr_temp_apr_config_file in $apr_temp_acceptable_apr_config
-      do
-        if $apr_temp_apr_config_file --help > /dev/null 2>&1 ; then
-          apr_config="$apr_temp_apr_config_file"
-          ifelse([$5], [], [], [
-          apr_acceptable="yes"
-          $5
-          if test "$apr_acceptable" != "yes"; then
-            AC_MSG_WARN([skipped APR at $apr_config, version not acceptable])
-            continue
-          fi])
-          apr_found="yes"
-          break
-        else
-          dnl look in some standard places
-          for lookdir in /usr /usr/local /usr/local/apr /opt/apr; do
-            if $TEST_X "$lookdir/bin/$apr_temp_apr_config_file"; then
-              apr_config="$lookdir/bin/$apr_temp_apr_config_file"
-              ifelse([$5], [], [], [
-              apr_acceptable="yes"
-              $5
-              if test "$apr_acceptable" != "yes"; then
-                AC_MSG_WARN([skipped APR at $apr_config, version not acceptable])
-                continue
-              fi])
-              apr_found="yes"
-              break 2
-            fi
-          done
-        fi
-      done
-    fi
-    dnl if we have not found anything yet and have bundled source, use that
-    if test "$apr_found" = "no" && test -d "$1"; then
-      apr_temp_abs_srcdir="`cd \"$1\" && pwd`"
-      apr_found="reconfig"
-      apr_bundled_major="`sed -n '/#define.*APR_MAJOR_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p' \"$1/include/apr_version.h\"`"
-      case $apr_bundled_major in
-        "")
-          AC_MSG_ERROR([failed to find major version of bundled APR])
-        ;;
-        0)
-          apr_temp_apr_config_file="apr-config"
-        ;;
-        *)
-          apr_temp_apr_config_file="apr-$apr_bundled_major-config"
-        ;;
-      esac
-      if test -n "$2"; then
-        apr_config="$2/$apr_temp_apr_config_file"
-      else
-        apr_config="$1/$apr_temp_apr_config_file"
-      fi
-    fi
-  ])
-
-  AC_MSG_RESULT($apr_found)
-])

Property changes on: build/find_apr.m4
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Index: build/find_apu.m4
===================================================================
--- build/find_apu.m4	(revision 1878566)
+++ build/find_apu.m4	(nonexistent)
@@ -1,211 +0,0 @@
-dnl -------------------------------------------------------- -*- autoconf -*-
-dnl Licensed to the Apache Software Foundation (ASF) under one or more
-dnl contributor license agreements.  See the NOTICE file distributed with
-dnl this work for additional information regarding copyright ownership.
-dnl The ASF licenses this file to You under the Apache License, Version 2.0
-dnl (the "License"); you may not use this file except in compliance with
-dnl the License.  You may obtain a copy of the License at
-dnl
-dnl     http://www.apache.org/licenses/LICENSE-2.0
-dnl
-dnl Unless required by applicable law or agreed to in writing, software
-dnl distributed under the License is distributed on an "AS IS" BASIS,
-dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-dnl See the License for the specific language governing permissions and
-dnl limitations under the License.
-
-dnl
-dnl find_apu.m4 : locate the APR-util (APU) include files and libraries
-dnl
-dnl This macro file can be used by applications to find and use the APU
-dnl library. It provides a standardized mechanism for using APU. It supports
-dnl embedding APU into the application source, or locating an installed
-dnl copy of APU.
-dnl
-dnl APR_FIND_APU(srcdir, builddir, implicit-install-check, acceptable-majors,
-dnl              detailed-check)
-dnl
-dnl   where srcdir is the location of the bundled APU source directory, or
-dnl   empty if source is not bundled.
-dnl
-dnl   where builddir is the location where the bundled APU will be built,
-dnl   or empty if the build will occur in the srcdir.
-dnl
-dnl   where implicit-install-check set to 1 indicates if there is no
-dnl   --with-apr-util option specified, we will look for installed copies.
-dnl
-dnl   where acceptable-majors is a space separated list of acceptable major
-dnl   version numbers. Often only a single major version will be acceptable.
-dnl   If multiple versions are specified, and --with-apr-util=PREFIX or the
-dnl   implicit installed search are used, then the first (leftmost) version
-dnl   in the list that is found will be used.  Currently defaults to [0 1].
-dnl
-dnl   where detailed-check is an M4 macro which sets the apu_acceptable to
-dnl   either "yes" or "no". The macro will be invoked for each installed
-dnl   copy of APU found, with the apu_config variable set appropriately.
-dnl   Only installed copies of APU which are considered acceptable by
-dnl   this macro will be considered found. If no installed copies are
-dnl   considered acceptable by this macro, apu_found will be set to either
-dnl   either "no" or "reconfig".
-dnl
-dnl Sets the following variables on exit:
-dnl
-dnl   apu_found : "yes", "no", "reconfig"
-dnl
-dnl   apu_config : If the apu-config tool exists, this refers to it.  If
-dnl                apu_found is "reconfig", then the bundled directory
-dnl                should be reconfigured *before* using apu_config.
-dnl
-dnl Note: this macro file assumes that apr-config has been installed; it
-dnl       is normally considered a required part of an APR installation.
-dnl
-dnl Note: At this time, we cannot find *both* a source dir and a build dir.
-dnl       If both are available, the build directory should be passed to
-dnl       the --with-apr-util switch.
-dnl
-dnl Note: the installation layout is presumed to follow the standard
-dnl       PREFIX/lib and PREFIX/include pattern. If the APU config file
-dnl       is available (and can be found), then non-standard layouts are
-dnl       possible, since it will be described in the config file.
-dnl
-dnl If a bundled source directory is available and needs to be (re)configured,
-dnl then apu_found is set to "reconfig". The caller should reconfigure the
-dnl (passed-in) source directory, placing the result in the build directory,
-dnl as appropriate.
-dnl
-dnl If apu_found is "yes" or "reconfig", then the caller should use the
-dnl value of apu_config to fetch any necessary build/link information.
-dnl
-
-AC_DEFUN([APR_FIND_APU], [
-  apu_found="no"
-
-  if test "$target_os" = "os2-emx"; then
-    # Scripts don't pass test -x on OS/2
-    TEST_X="test -f"
-  else
-    TEST_X="test -x"
-  fi
-
-  ifelse([$4], [],
-  [
-    ifdef(AC_WARNING,([$0: missing argument 4 (acceptable-majors): Defaulting to APU 0.x then APU 1.x]))
-    acceptable_majors="0 1"
-  ], [acceptable_majors="$4"])
-
-  apu_temp_acceptable_apu_config=""
-  for apu_temp_major in $acceptable_majors
-  do
-    case $apu_temp_major in
-      0)
-      apu_temp_acceptable_apu_config="$apu_temp_acceptable_apu_config apu-config"
-      ;;
-      *)
-      apu_temp_acceptable_apu_config="$apu_temp_acceptable_apu_config apu-$apu_temp_major-config"
-      ;;
-    esac
-  done
-
-  AC_MSG_CHECKING(for APR-util)
-  AC_ARG_WITH(apr-util,
-  [  --with-apr-util=PATH    prefix for installed APU or the full path to 
-                             apu-config],
-  [
-    if test "$withval" = "no" || test "$withval" = "yes"; then
-      AC_MSG_ERROR([--with-apr-util requires a directory or file to be provided])
-    fi
-
-    for apu_temp_apu_config_file in $apu_temp_acceptable_apu_config
-    do
-      for lookdir in "$withval/bin" "$withval"
-      do
-        if $TEST_X "$lookdir/$apu_temp_apu_config_file"; then
-          apu_config="$lookdir/$apu_temp_apu_config_file"
-          ifelse([$5], [], [], [
-          apu_acceptable="yes"
-          $5
-          if test "$apu_acceptable" != "yes"; then
-            AC_MSG_WARN([Found APU in $apu_config, but it is considered unacceptable])
-            continue
-          fi])
-          apu_found="yes"
-          break 2
-        fi
-      done
-    done
-
-    if test "$apu_found" != "yes" && $TEST_X "$withval" && $withval --help > /dev/null 2>&1 ; then
-      apu_config="$withval"
-      ifelse([$5], [], [apu_found="yes"], [
-          apu_acceptable="yes"
-          $5
-          if test "$apu_acceptable" = "yes"; then
-                apu_found="yes"
-          fi])
-    fi
-
-    dnl if --with-apr-util is used, it is a fatal error for its argument
-    dnl to be invalid
-    if test "$apu_found" != "yes"; then
-      AC_MSG_ERROR([the --with-apr-util parameter is incorrect. It must specify an install prefix, a build directory, or an apu-config file.])
-    fi
-  ],[
-    if test -n "$3" && test "$3" = "1"; then
-      for apu_temp_apu_config_file in $apu_temp_acceptable_apu_config
-      do
-        if $apu_temp_apu_config_file --help > /dev/null 2>&1 ; then
-          apu_config="$apu_temp_apu_config_file" 
-          ifelse([$5], [], [], [
-          apu_acceptable="yes"
-          $5
-          if test "$apu_acceptable" != "yes"; then
-            AC_MSG_WARN([skipped APR-util at $apu_config, version not acceptable])
-            continue
-          fi])
-          apu_found="yes"
-          break
-        else
-          dnl look in some standard places (apparently not in builtin/default)
-          for lookdir in /usr /usr/local /usr/local/apr /opt/apr; do
-            if $TEST_X "$lookdir/bin/$apu_temp_apu_config_file"; then
-              apu_config="$lookdir/bin/$apu_temp_apu_config_file"
-              ifelse([$5], [], [], [
-              apu_acceptable="yes"
-              $5
-              if test "$apu_acceptable" != "yes"; then
-                AC_MSG_WARN([skipped APR-util at $apu_config, version not acceptable])
-                continue
-              fi])
-              apu_found="yes"
-              break 2
-            fi
-          done
-        fi
-      done
-    fi
-    dnl if we have not found anything yet and have bundled source, use that
-    if test "$apu_found" = "no" && test -d "$1"; then
-      apu_temp_abs_srcdir="`cd \"$1\" && pwd`"
-      apu_found="reconfig"
-      apu_bundled_major="`sed -n '/#define.*APU_MAJOR_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p' \"$1/include/apu_version.h\"`"
-      case $apu_bundled_major in
-        "")
-          AC_MSG_ERROR([failed to find major version of bundled APU])
-        ;;
-        0)
-          apu_temp_apu_config_file="apu-config"
-        ;;
-        *)
-          apu_temp_apu_config_file="apu-$apu_bundled_major-config"
-        ;;
-      esac
-      if test -n "$2"; then
-        apu_config="$2/$apu_temp_apu_config_file"
-      else
-        apu_config="$1/$apu_temp_apu_config_file"
-      fi
-    fi
-  ])
-
-  AC_MSG_RESULT($apu_found)
-])

Property changes on: build/find_apu.m4
___________________________________________________________________
Deleted: svn:eol-style
## -1 +0,0 ##
-native
\ No newline at end of property
Index: include/httpd.h
===================================================================
--- include/httpd.h	(revision 1878566)
+++ include/httpd.h	(working copy)
@@ -1789,6 +1789,15 @@
                  AP_FN_ATTR_NONNULL_ALL;
 
 /**
+ * Remove all ./ and xx/../ substrings from a file name. Also remove
+ * any leading ../ or /../ substrings.
+ * @param name the file name to parse
+ * @param servletnormalize if set also remove the ;foo=bar/ from any path segment
+ */
+AP_DECLARE(void) ap_getparents_ex(char *name, int servletnormalize)
+                 AP_FN_ATTR_NONNULL_ALL;
+
+/**
  * Escape a path segment, as defined in RFC 1808
  * @param p The pool to allocate from
  * @param s The path to convert
Index: modules/mappers/mod_rewrite.c
===================================================================
--- modules/mappers/mod_rewrite.c	(revision 1878566)
+++ modules/mappers/mod_rewrite.c	(working copy)
@@ -168,6 +168,7 @@
 #define RULEFLAG_END                (1<<17)
 #define RULEFLAG_ESCAPENOPLUS       (1<<18)
 #define RULEFLAG_QSLAST             (1<<19)
+#define RULEFLAG_SNC                (1<<20)
 
 /* return code of the rewrite rule
  * the result may be escaped - or not
@@ -3763,6 +3764,9 @@
     case 'S':
         if (!*key || !strcasecmp(key, "kip")) {            /* skip */
             cfg->skip = atoi(val);
+        } else if ( !strcasecmp(key, "NC")
+            || !strcasecmp(key, "ervletnormalizecheck")) { /* servletnormalizecheck */
+            cfg->flags |=  RULEFLAG_SNC;
         }
         else {
             ++error;
@@ -4305,6 +4309,19 @@
             rewritelog(r, 2, ctx->perdir, "escaped URI in per-dir context "
                        "for proxy, %s -> %s", old_filename, r->filename);
         }
+        if (p->flags & RULEFLAG_SNC) {
+            char *uri = apr_pstrdup(r->pool, ctx->uri);
+            ap_getparents_ex(uri, 1);
+            rewritelog(r, 2, ctx->perdir, "Checking pattern '%s' to normalized uri '%s'",
+                        p->pattern, uri);
+            rc = !ap_regexec(p->regexp, uri, AP_MAX_REG_MATCH, regmatch, 0);
+            if (! (( rc && !(p->flags & RULEFLAG_NOTMATCH)) ||
+                   (!rc &&  (p->flags & RULEFLAG_NOTMATCH))   ) ) {
+                rewritelog(r, 2, ctx->perdir, "rejecting via pattern '%s' for uri '%s'",
+                            p->pattern, uri);
+                return -1;
+            }
+        }
 
         fully_qualify_uri(r);
 
@@ -4478,6 +4495,10 @@
              *  last-rule and new-round flags.
              */
             if (p->flags & (RULEFLAG_PROXY | RULEFLAG_LASTRULE)) {
+                if (rc == -1) {
+                    r->status = HTTP_BAD_REQUEST;
+                    return ACTION_STATUS; 
+                }
                 break;
             }
 
Index: modules/proxy/mod_proxy.c
===================================================================
--- modules/proxy/mod_proxy.c	(revision 1878566)
+++ modules/proxy/mod_proxy.c	(working copy)
@@ -679,6 +679,7 @@
     char *found = NULL;
     int mismatch = 0;
     unsigned int nocanon = ent->flags & PROXYPASS_NOCANON;
+    unsigned int servletnormalizecheck = ent->flags & PROXY_SERVLET_NORMALIZE_CHECK;
     const char *use_uri = nocanon ? r->unparsed_uri : r->uri;
 
     if (dconf && (dconf->interpolate_env == 1) && (ent->flags & PROXYPASS_INTERPOLATE)) {
@@ -703,6 +704,16 @@
                               "'%s'; declining", r->uri);
                 return DECLINED;
             }
+            if (servletnormalizecheck) {
+                /* check against the endback servlet url and return 400 in case something weird */
+                char *uri = apr_pstrdup(r->pool, r->uri);
+                ap_getparents_ex(uri, 1);
+                if (ap_regexec(ent->regex, uri, AP_MAX_REG_MATCH, regm, 0)) {
+                   ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
+                                  "servlet_normalized URL path doesn't correctly match ProxyMatchPass");
+                    return HTTP_BAD_REQUEST;
+                }
+            }
             /* test that we haven't reduced the URI */
             if (nocanon && ap_regexec(ent->regex, r->unparsed_uri,
                     AP_MAX_REG_MATCH, reg1, 0)) {
@@ -749,6 +760,18 @@
                               "'%s'; declining", r->uri);
                 return DECLINED;
             }
+            if (servletnormalizecheck) {
+                /* check against the endback servlet url and return 400 in case something weird */
+                char *uri = apr_pstrdup(r->pool, r->uri);
+                int servlen;
+                ap_getparents_ex(uri, 1);
+                servlen = alias_match(uri, fake);
+                if (servlen != len) {
+                    ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
+                                  "servlet_normalized URL path doesn't correctly match ProxyPass");
+                    return HTTP_BAD_REQUEST;
+                }
+            }
             if (nocanon && len != alias_match(r->unparsed_uri, ent->fake)) {
                 mismatch = 1;
                 use_uri = r->uri;
@@ -1806,6 +1829,9 @@
         else if (!strcasecmp(word,"noquery")) {
             flags |= PROXYPASS_NOQUERY;
         }
+        else if (!strcasecmp(word,"servletnormalizecheck")) {
+            flags |= PROXY_SERVLET_NORMALIZE_CHECK;
+        }
         else {
             char *val = strchr(word, '=');
             if (!val) {
Index: modules/proxy/mod_proxy.h
===================================================================
--- modules/proxy/mod_proxy.h	(revision 1878566)
+++ modules/proxy/mod_proxy.h	(working copy)
@@ -123,6 +123,7 @@
 #define PROXYPASS_NOCANON 0x01
 #define PROXYPASS_INTERPOLATE 0x02
 #define PROXYPASS_NOQUERY 0x04
+#define PROXY_SERVLET_NORMALIZE_CHECK 0x08
 struct proxy_alias {
     const char  *real;
     const char  *fake;
Index: server/util.c
===================================================================
--- server/util.c	(revision 1878566)
+++ server/util.c	(working copy)
@@ -493,13 +493,42 @@
 }
 
 /*
- * Parse .. so we don't compromise security
+ * Parse .. and remove parameters in path segments so we don't compromise security
  */
 AP_DECLARE(void) ap_getparents(char *name)
 {
+    ap_getparents_ex(name, 0);
+}
+AP_DECLARE(void) ap_getparents_ex(char *name, int servletnormalize)
+{
     char *next;
     int l, w, first_dot;
 
+    if (servletnormalize) {
+        for (l = 1, w = 1; name[l] != '\0';) {
+             /* first remove ;foo=bar in path segments */
+             if (name[l] == ';') {
+                 l++;
+                 while (!IS_SLASH(name[l]) && name[l] != '\0') {
+                     l++;
+                 }
+                 continue;
+             }
+             /* Collapse ///// sequences to / */
+             if (name[w - 1] == '/') {
+                 if (name[l] == '/') {
+                     do {
+                         l++;
+                     } while (name[l] == '/');
+                     continue;
+                 }
+             }
+             /* The rest is done later by standard logic */
+             name[w++] = name[l++];
+         }
+         name[w] = '\0';
+    }
+
     /* Four paseses, as per RFC 1808 */
     /* a) remove ./ path segments */
     for (next = name; *next && (*next != '.'); next++) {

Reply via email to