JDK-6519518 : URL incorrectly removes path leaf when the relative spec is query only (RFC1808)
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 6
  • Priority: P4
  • Status: Closed
  • Resolution: Won't Fix
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2007-01-31
  • Updated: 2010-04-04
  • Resolved: 2009-03-26
Description
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;
}

Comments
EVALUATION URI is the preferred class for manipulating URLs. Due to legacy compatibility concerns, we cannot make this change to URL.
26-03-2009