FULL PRODUCT VERSION : java version "1.6.0" Java(TM) SE Runtime Environment (build 1.6.0-b105) Java HotSpot(TM) Client VM (build 1.6.0-b105, mixed mode, sharing) ADDITIONAL OS VERSION INFORMATION : Microsoft Windows XP [Version 5.1.2600] Linux server11.*******.com 2.6.9-42.0.3.ELsmp #1 SMP Fri Oct 6 06:28:26 CDT 2006 x86_64 x86_64 x86_64 GNU/Linux A DESCRIPTION OF THE PROBLEM : The constructor URL(URL context, String spec) does not produce the correct URL if the relative spec is only a query. According to RFC 1808 (http://www.ietf.org/rfc/rfc1808.txt), section 5.1 given a base of "http://a/b/c/d;p?q#f" and a relative URL of "?y", the new URL should be "http://a/b/c/d;p?y". The URL created using the constructor is "http://a/b/c/?y" (the final d is missing from the path). STEPS TO FOLLOW TO REPRODUCE THE PROBLEM : This behavior can be seen by using a base URL that includes a filename at the end of its path (i.e. not just a directory) such as that in RFC 1808 section 5.1., and a relative URL that contains only a query, such as "?y" (without the quotes), or a session if and a query such as ";q?y" (without the quotes). See the source code supplied below. EXPECTED VERSUS ACTUAL BEHAVIOR : EXPECTED - The following should be printed to standard output: actual : http://a/b/c/d;p?y desired: http://a/b/c/d;p?y ACTUAL - The following is printed to standard output: actual : http://a/b/c/?y desired: http://a/b/c/d;p?y REPRODUCIBILITY : This bug can be reproduced always. ---------- BEGIN SOURCE ---------- import java.net.URL; public class temp { public static final String base = "http://a/b/c/d;p?q#f"; public static final String relative = "?y"; public static final String desiredResult = "http://a/b/c/d;p?y"; public static void main(String[] args) { try { URL baseUrl = new URL(base); URL relativeUrl = new URL(baseUrl, relative); System.out.println("actual : " + relativeUrl); System.out.println("desired: " + desiredResult); } catch (Exception e) { throw new RuntimeException(e); } } } ---------- END SOURCE ---------- CUSTOMER SUBMITTED WORKAROUND : Detect the situation and before using the constructor replace the query with the base path plus the query, using a method such as the following: static String fixupRelative(String baseURL, String relative) { String workingRelative = relative.trim(); if ((workingRelative.length() > 0) && ((workingRelative.charAt(0) == '?') || (workingRelative.charAt(0) == ';'))) { char stripTo = workingRelative.charAt(0); int stripToLoc = baseURL.indexOf(stripTo); if ((0 > stripToLoc) && (';' == stripTo)) { stripToLoc = baseURL.indexOf('?'); // if relative and has a ';' but the baseURL does not, then we will strip to ? if (0 > stripToLoc) { stripToLoc = baseURL.length(); } } if (-1 == stripToLoc) { stripToLoc = baseURL.length(); } int startLoc = baseURL.lastIndexOf('/', stripToLoc) + 1; if ((0 < startLoc) && (startLoc <= stripToLoc)) { // only enter if we have good values, otherwise give up and hope for the best String prefix = baseURL.substring(startLoc, stripToLoc); workingRelative = prefix + workingRelative; } } return workingRelative; }
|