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;
}