You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@jakarta.apache.org by se...@apache.org on 2010/07/02 00:36:07 UTC

svn commit: r959801 - in /jakarta/jmeter/trunk: src/protocol/http/org/apache/jmeter/protocol/http/sampler/ src/protocol/http/org/apache/jmeter/protocol/http/util/ test/src/org/apache/jmeter/protocol/http/util/ xdocs/ xdocs/usermanual/

Author: sebb
Date: Thu Jul  1 22:36:07 2010
New Revision: 959801

URL: http://svn.apache.org/viewvc?rev=959801&view=rev
Log:
Bug 49083 - collapse '/pathsegment/..' in redirect URLs

Modified:
    jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSamplerBase.java
    jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/util/ConversionUtils.java
    jakarta/jmeter/trunk/test/src/org/apache/jmeter/protocol/http/util/TestHTTPUtils.java
    jakarta/jmeter/trunk/xdocs/changes.xml
    jakarta/jmeter/trunk/xdocs/usermanual/component_reference.xml

Modified: jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSamplerBase.java
URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSamplerBase.java?rev=959801&r1=959800&r2=959801&view=diff
==============================================================================
--- jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSamplerBase.java (original)
+++ jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSamplerBase.java Thu Jul  1 22:36:07 2010
@@ -204,7 +204,7 @@ public abstract class HTTPSamplerBase ex
     private static final String RESPONSE_PARSERS= // list of parsers
         JMeterUtils.getProperty("HTTPResponse.parsers");//$NON-NLS-1$
 
-   static{
+    static{
         String []parsers = JOrphanUtils.split(RESPONSE_PARSERS, " " , true);// returns empty array for null
         for (int i=0;i<parsers.length;i++){
             final String parser = parsers[i];
@@ -231,6 +231,10 @@ public abstract class HTTPSamplerBase ex
         }
     }
 
+    // Bug 49083
+    /** Whether to remove '/pathsegment/..' from redirects; default true */
+    private static boolean REMOVESLASHDOTDOT = JMeterUtils.getPropDefault("httpsampler.redirect.removeslashdotdot", true);
+
     ////////////////////// Variables //////////////////////
 
     private boolean dynamicPath = false;// Set false if spaces are already encoded
@@ -1223,7 +1227,11 @@ public abstract class HTTPSamplerBase ex
             // Browsers seem to tolerate Location headers with spaces,
             // replacing them automatically with %20. We want to emulate
             // this behaviour.
-            String location = encodeSpaces(lastRes.getRedirectLocation());
+            String location = lastRes.getRedirectLocation(); 
+            if (REMOVESLASHDOTDOT) {
+                location = ConversionUtils.removeSlashDotDot(location);
+            }
+            location = encodeSpaces(location);
             try {
                 lastRes = sample(ConversionUtils.makeRelativeURL(lastRes.getURL(), location), GET, true, frameDepth);
             } catch (MalformedURLException e) {

Modified: jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/util/ConversionUtils.java
URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/util/ConversionUtils.java?rev=959801&r1=959800&r2=959801&view=diff
==============================================================================
--- jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/util/ConversionUtils.java (original)
+++ jakarta/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/util/ConversionUtils.java Thu Jul  1 22:36:07 2010
@@ -21,6 +21,9 @@ package org.apache.jmeter.protocol.http.
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -35,6 +38,11 @@ public class ConversionUtils {
 
     private static final String CHARSET_EQ = "charset="; // $NON-NLS-1$
     private static final int CHARSET_EQ_LEN = CHARSET_EQ.length();
+    
+	private static final String SLASHDOTDOT = "/..";
+	private static final String DOTDOT = "..";
+	private static final String SLASH = "/";
+	private static final String COLONSLASHSLASH = "://";
 
     /**
      * Extract the encoding (charset) from the Content-Type,
@@ -85,6 +93,7 @@ public class ConversionUtils {
      */
     public static URL makeRelativeURL(URL baseURL, String location) throws MalformedURLException{
         URL initial = new URL(baseURL,location);
+        
         // skip expensive processing if it cannot apply
         if (!location.startsWith("../")){// $NON-NLS-1$
             return initial;
@@ -101,4 +110,116 @@ public class ConversionUtils {
         }
         return initial;
     }
+
+	/**
+	 * collapses absolute or relative URLs containing '/..' converting
+	 * http://host/path1/../path2 to http://host/path2 or /one/two/../three to
+	 * /one/three
+	 * 
+	 * @param url
+	 * @return collapsed URL
+	 */
+    public static String removeSlashDotDot(String url)
+    {
+        if (url == null || (url = url.trim()).length() < 4 || !url.contains(SLASHDOTDOT))
+        {
+            return url;
+        }
+
+        /**
+         * http://auth@host:port/path1/path2/path3/?query#anchor
+         */
+
+        // get to 'path' part of the URL, preserving schema, auth, host if
+        // present
+
+        // find index of path start
+
+        int dotSlashSlashIndex = url.indexOf(COLONSLASHSLASH);
+        final int pathStartIndex;
+        if (dotSlashSlashIndex >= 0)
+        {
+            // absolute URL
+            pathStartIndex = url.indexOf(SLASH, dotSlashSlashIndex + COLONSLASHSLASH.length());
+        } else
+        {
+            // document or context-relative URL like:
+            // '/path/to'
+            // OR '../path/to'
+            // OR '/path/to/../path/'
+            pathStartIndex = 0;
+        }
+
+        // find path endIndex
+        int pathEndIndex = url.length();
+
+        int questionMarkIdx = url.indexOf('?');
+        if (questionMarkIdx > 0)
+        {
+            pathEndIndex = questionMarkIdx;
+        } else {
+            int anchorIdx = url.indexOf('#');
+            if (anchorIdx > 0)
+            {
+                pathEndIndex = anchorIdx;
+            }
+        }
+
+        // path is between idx='pathStartIndex' (inclusive) and
+        // idx='pathEndIndex' (exclusive)
+        String currentPath = url.substring(pathStartIndex, pathEndIndex);
+
+        final boolean startsWithSlash = currentPath.startsWith(SLASH);
+        final boolean endsWithSlash = currentPath.endsWith(SLASH);
+
+        StringTokenizer st = new StringTokenizer(currentPath, SLASH);
+        List<String> tokens = new ArrayList<String>();
+        while (st.hasMoreTokens())
+        {
+            tokens.add(st.nextToken());
+        }
+
+        for (int i = 0; i < tokens.size(); i++)
+        {
+            if (i < tokens.size() - 1)
+            {
+                final String thisToken = tokens.get(i);
+
+                // Verify for a ".." component at next iteration
+                if (thisToken.length() > 0 && !thisToken.equals(DOTDOT) && tokens.get(i + 1).equals(DOTDOT))
+                {
+                    tokens.remove(i);
+                    tokens.remove(i);
+                    i = i - 2;
+                    if (i < -1)
+                    {
+                        i = -1;
+                    }
+                }
+            }
+
+        }
+
+        StringBuilder newPath = new StringBuilder();
+        if (startsWithSlash) {
+            newPath.append(SLASH);
+        }
+        for (int i = 0; i < tokens.size(); i++)
+        {
+            newPath.append(tokens.get(i));
+
+            // append '/' if this isn't the last token or it is but the original
+            // path terminated w/ a '/'
+            boolean appendSlash = i < (tokens.size() - 1) ? true : endsWithSlash;
+            if (appendSlash)
+            {
+                newPath.append(SLASH);
+            }
+        }
+
+        // install new path
+        StringBuilder s = new StringBuilder(url);
+        s.replace(pathStartIndex, pathEndIndex, newPath.toString());
+        return s.toString();
+    }
 }

Modified: jakarta/jmeter/trunk/test/src/org/apache/jmeter/protocol/http/util/TestHTTPUtils.java
URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/test/src/org/apache/jmeter/protocol/http/util/TestHTTPUtils.java?rev=959801&r1=959800&r2=959801&view=diff
==============================================================================
--- jakarta/jmeter/trunk/test/src/org/apache/jmeter/protocol/http/util/TestHTTPUtils.java (original)
+++ jakarta/jmeter/trunk/test/src/org/apache/jmeter/protocol/http/util/TestHTTPUtils.java Thu Jul  1 22:36:07 2010
@@ -59,4 +59,25 @@ public class TestHTTPUtils extends TestC
             assertEquals(new URL("http://192.168.0.1/../d"),ConversionUtils.makeRelativeURL(base,"/../d"));
             assertEquals(new URL("http://192.168.0.1/a/b/c/d"),ConversionUtils.makeRelativeURL(base,"./d"));
         }
+		
+		public void testRemoveSlashDotDot()
+		{
+			assertEquals("/path/", ConversionUtils.removeSlashDotDot("/path/"));
+			assertEquals("http://host/", ConversionUtils.removeSlashDotDot("http://host/"));
+            assertEquals("http://host/one", ConversionUtils.removeSlashDotDot("http://host/one"));
+			assertEquals("/two", ConversionUtils.removeSlashDotDot("/one/../two"));
+			assertEquals("http://host:8080/two", ConversionUtils.removeSlashDotDot("http://host:8080/one/../two"));
+			assertEquals("http://host:8080/two/", ConversionUtils.removeSlashDotDot("http://host:8080/one/../two/"));
+			assertEquals("http://usr@host:8080/two/", ConversionUtils.removeSlashDotDot("http://usr@host:8080/one/../two/"));
+			assertEquals("http://host:8080/two/?query#anchor", ConversionUtils.removeSlashDotDot("http://host:8080/one/../two/?query#anchor"));
+			assertEquals("one", ConversionUtils.removeSlashDotDot("one/two/.."));
+			assertEquals("../../path", ConversionUtils.removeSlashDotDot("../../path"));
+			assertEquals("/", ConversionUtils.removeSlashDotDot("/one/.."));
+			assertEquals("/", ConversionUtils.removeSlashDotDot("/one/../"));
+			assertEquals("/?a", ConversionUtils.removeSlashDotDot("/one/..?a"));
+			assertEquals("http://host/one", ConversionUtils.removeSlashDotDot("http://host/one/../one"));
+			assertEquals("http://host/one/two", ConversionUtils.removeSlashDotDot("http://host/one/two/../../one/two"));
+            assertEquals("http://host/..", ConversionUtils.removeSlashDotDot("http://host/.."));
+            assertEquals("http://host/../abc", ConversionUtils.removeSlashDotDot("http://host/../abc"));
+		}
 }

Modified: jakarta/jmeter/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/xdocs/changes.xml?rev=959801&r1=959800&r2=959801&view=diff
==============================================================================
--- jakarta/jmeter/trunk/xdocs/changes.xml (original)
+++ jakarta/jmeter/trunk/xdocs/changes.xml Thu Jul  1 22:36:07 2010
@@ -161,6 +161,7 @@ This does not affect existing test plans
 <li>Bug 48153 - Support for Cache-Control and Expires headers</li>
 <li>Bug 47946 - Proxy should enable Grouping inside a Transaction Controller</li>
 <li>Bug 48300 - Allow override of IP source address for HTTP HttpClient requests</li>
+<li>Bug 49083 - collapse '/pathsegment/..' in redirect URLs</li>
 </ul>
 
 <h3>Other samplers</h3>

Modified: jakarta/jmeter/trunk/xdocs/usermanual/component_reference.xml
URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/xdocs/usermanual/component_reference.xml?rev=959801&r1=959800&r2=959801&view=diff
==============================================================================
--- jakarta/jmeter/trunk/xdocs/usermanual/component_reference.xml (original)
+++ jakarta/jmeter/trunk/xdocs/usermanual/component_reference.xml Thu Jul  1 22:36:07 2010
@@ -197,6 +197,11 @@ https.default.protocol=SSLv3
 		Note that the HttpClient sampler may log the following message:<br/>
 		"Redirect requested but followRedirects is disabled"<br/>
 		This can be ignored.
+        <br/>
+        In versions after 2.3.4, JMeter will collapse paths of the form '/../segment' in
+        both absolute and relative URLs. For example http://host/one/../two => http://host/two.
+        If necessary, this behaviour can be suppressed by setting the JMeter property
+        <code>httpsampler.redirect.removeslashdotdot=false</code>
 		</property>
 		<property name="Use KeepAlive" required="Yes">JMeter sets the Connection: keep-alive header. This does not work properly with the default HTTP implementation, as connection re-use is not under user-control. 
                   It does work with the Jakarta httpClient implementation.</property>



---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@jakarta.apache.org
For additional commands, e-mail: notifications-help@jakarta.apache.org