mbecke 2003/06/19 16:28:20 Modified: httpclient/src/java/org/apache/commons/httpclient URI.java httpclient/src/test/org/apache/commons/httpclient TestURI.java httpclient release_notes.txt Log: Updated URI path resolution to conform to http://www.apache.org/~fielding/uri/rev-2002/issues.html. PR: 20665 Reviewed by: Adrian Sutton and Oleg Kalnichevski Revision Changes Path 1.35 +64 -54 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/URI.java Index: URI.java =================================================================== RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/URI.java,v retrieving revision 1.34 retrieving revision 1.35 diff -u -r1.34 -r1.35 --- URI.java 5 Mar 2003 03:47:25 -0000 1.34 +++ URI.java 19 Jun 2003 23:28:19 -0000 1.35 @@ -2923,7 +2923,7 @@ if (relPath == null || relPath.length == 0) { return normalize(basePath); } else if (relPath[0] == '/') { - return relPath; + return normalize(relPath); } else { StringBuffer buff = new StringBuffer(base.length() + relPath.length); @@ -3401,6 +3401,9 @@ /** * Normalize the given hier path part. + * + * <p>Algorithm taken from URI reference parser at + * http://www.apache.org/~fielding/uri/rev-2002/issues.html. * * @param path the path to normalize * @return the normalized path @@ -3413,62 +3416,69 @@ } String normalized = new String(path); - boolean endsWithSlash = true; - // precondition - if (!normalized.endsWith("/")) { - normalized += '/'; - endsWithSlash = false; - } - if (normalized.endsWith("/./") || normalized.endsWith("/../")) { - endsWithSlash = true; - } - // Resolve occurrences of "/./" in the normalized path - while (true) { - int at = normalized.indexOf("/./"); - if (at == -1) { - break; + + // If the buffer begins with "./" or "../", the "." or ".." is removed. + if (normalized.startsWith("./")) { + normalized = normalized.substring(1); + } else if (normalized.startsWith("../")) { + normalized = normalized.substring(2); + } else if (normalized.startsWith("..")) { + normalized = normalized.substring(2); + } + + // All occurrences of "/./" in the buffer are replaced with "/" + int index = -1; + while ((index = normalized.indexOf("/./")) != -1) { + normalized = normalized.substring(0, index) + normalized.substring(index + 2); + } + + // If the buffer ends with "/.", the "." is removed. + if (normalized.endsWith("/.")) { + normalized = normalized.substring(0, normalized.length() - 1); + } + + int startIndex = 0; + + // All occurrences of "/<segment>/../" in the buffer, where ".." + // and <segment> are complete path segments, are iteratively replaced + // with "/" in order from left to right until no matching pattern remains. + // If the buffer ends with "/<segment>/..", that is also replaced + // with "/". Note that <segment> may be empty. + while ((index = normalized.indexOf("/../", startIndex)) != -1) { + int slashIndex = normalized.lastIndexOf('/', index - 1); + if (slashIndex >= 0) { + normalized = normalized.substring(0, slashIndex) + normalized.substring(index + 3); + } else { + startIndex = index + 3; } - normalized = normalized.substring(0, at) - + normalized.substring(at + 2); } - while (true) { - // Resolve occurrences of "//" in the normalized path - int at = normalized.indexOf("//"); - if (at != -1) { - normalized = normalized.substring(0, at) - + normalized.substring(at + 1); - continue; + if (normalized.endsWith("/..")) { + int slashIndex = normalized.lastIndexOf('/', normalized.length() - 4); + if (slashIndex >= 0) { + normalized = normalized.substring(0, slashIndex + 1); } - // Resolve occurrences of "/../" in the normalized path - at = normalized.indexOf("/../"); - if (at == -1) { + } + + // All prefixes of "<segment>/../" in the buffer, where ".." + // and <segment> are complete path segments, are iteratively replaced + // with "/" in order from left to right until no matching pattern remains. + // If the buffer ends with "<segment>/..", that is also replaced + // with "/". Note that <segment> may be empty. + while ((index = normalized.indexOf("/../")) != -1) { + int slashIndex = normalized.lastIndexOf('/', index - 1); + if (slashIndex >= 0) { break; - } - if (at == 0) { - // no more higher path level to be normalized - if (!endsWithSlash && normalized.endsWith("/")) { - normalized = - normalized.substring(0, normalized.length() - 1); - } else if (endsWithSlash && !normalized.endsWith("/")) { - normalized = normalized + "/"; - } - throw new URIException(URIException.PARSING, new String(path)); - } - int backward = normalized.lastIndexOf('/', at - 1); - if (backward == -1) { - // consider the rel_path - normalized = normalized.substring(at + 4); } else { - normalized = normalized.substring(0, backward) - + normalized.substring(at + 3); + normalized = normalized.substring(index + 3); } } - if (!endsWithSlash && normalized.endsWith("/")) { - normalized = normalized.substring(0, normalized.length() - 1); - } else if (endsWithSlash && !normalized.endsWith("/")) { - normalized = normalized + "/"; + if (normalized.endsWith("/..")) { + int slashIndex = normalized.lastIndexOf('/', normalized.length() - 4); + if (slashIndex < 0) { + normalized = "/"; + } } - // Set the normalized path that we have completed + return normalized.toCharArray(); } 1.4 +8 -10 jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestURI.java Index: TestURI.java =================================================================== RCS file: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestURI.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- TestURI.java 30 Jan 2003 21:44:56 -0000 1.3 +++ TestURI.java 19 Jun 2003 23:28:20 -0000 1.4 @@ -130,12 +130,10 @@ { "../..", "http", "a", "/", null, null, "http://a/" }, { "../../", "http", "a", "/", null, null, "http://a/" }, { "../../g", "http", "a", "/g", null, null, "http://a/g" }, - // Abnormal examples - // exception thrown the right below two - // { "../../../g", "http", "a", being-normalized path?, null, null, "http://a/../g?" }, - // { "../../../../g", "http", "a", being-normalied path?, null, null, "http://a/../../g?" }, - { "/./g", "http", "a", "/./g", null, null, "http://a/./g" }, - { "/../g", "http", "a", "/../g", null, null, "http://a/../g" }, + { "../../../g", "http", "a", "/g", null, null, "http://a/g" }, + { "../../../../g", "http", "a", "/g", null, null, "http://a/g" }, + { "/./g", "http", "a", "/g", null, null, "http://a/g" }, + { "/../g", "http", "a", "/g", null, null, "http://a/g" }, { "g.", "http", "a", "/b/c/g.", null, null, "http://a/b/c/g." }, { ".g", "http", "a", "/b/c/.g", null, null, "http://a/b/c/.g" }, { "g..", "http", "a", "/b/c/g..", null, null, "http://a/b/c/g.." }, @@ -152,12 +150,12 @@ { "g#s/../x", "http", "a", "/b/c/g", null, "s/../x", "http://a/b/c/g#s/../x" } }; for (int i = 0; i < testRelativeURIs.length; i++) { - URI testURI = null; try { testURI = new URI( baseURI, testRelativeURIs[i][0] ); } catch ( URIException e ) { + e.printStackTrace(); fail( "unable to create URI with relative value(" + testRelativeURIs[i][0] + "): " + e 1.6 +4 -0 jakarta-commons/httpclient/release_notes.txt Index: release_notes.txt =================================================================== RCS file: /home/cvs/jakarta-commons/httpclient/release_notes.txt,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- release_notes.txt 19 Jun 2003 21:09:19 -0000 1.5 +++ release_notes.txt 19 Jun 2003 23:28:20 -0000 1.6 @@ -1,5 +1,9 @@ Changes since Release 2.0 Beta 1: + * Changed URI to correctly handle path resolution according to + http://www.apache.org/~fielding/uri/rev-2002/issues.html. In + particular dot-segments are removed when not necessary. + * POST method correctly applies 'application/x-www-form-urlencoded' encoding
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]