Bug 34369 - java.net.URI.relativize(URI) method returns incorrect results
Summary: java.net.URI.relativize(URI) method returns incorrect results
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libgcj (show other bugs)
Version: 4.1.2
: P3 normal
Target Milestone: 4.3.0
Assignee: Tom Tromey
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2007-12-06 22:10 UTC by Luciano Chavez
Modified: 2008-01-21 20:09 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2008-01-21 20:00:24


Attachments
testcase (419 bytes, text/plain)
2007-12-06 22:12 UTC, Luciano Chavez
Details
gcc-libjava-uri-relativize.patch to fix java.net.URI.relativize(URI) method (355 bytes, patch)
2007-12-06 22:15 UTC, Luciano Chavez
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Luciano Chavez 2007-12-06 22:10:25 UTC
The method java.net.URI.relativize(URI) returns incorrect results for a couple of cases when compared to implementations from IBM Java or Sun Java.

This problem affects directly the debugging process of C projects on Eclipse. Whenever someone is debugging a project whose part of its name is the
name of another project on the workspace, Eclipse doesn't find the correct path
for the project source files. For instance, if we have a project named "a" and
another project named "aa" and we try to debug a file on "aa", Eclipse will
match the path for the file on "aa" with the path to the project "a" and will
not find the file as it doesn't exist on project "a".

The method documentaion at
http://java.sun.com/j2se/1.4.2/docs/api/java/net/URI.html#relativize(java.net.URI)
says:

 The relativization of the given URI against this URI is computed as follows:

   1. If either this URI or the given URI are opaque, or if the scheme and
authority components of the two URIs are not identical, or if the path of this
URI is not a prefix of the path of the given URI, then the given URI is returned.

   2. Otherwise a new relative hierarchical URI is constructed with query and
fragment components taken from the given URI and with a path component computed
by removing this URI's path from the beginning of the given URI's path.

The test for "if the path of this URI is not a prefix of the path of the given URI then the given URI is returned" in libjava/classpath/java/net/URI.java does not appear correct:

  public URI relativize(URI uri)
  {
    if (isOpaque() || uri.isOpaque())
      return uri;
    if (scheme == null && uri.getScheme() != null)
      return uri;
    if (scheme != null && !(scheme.equals(uri.getScheme())))
      return uri;
    if (rawAuthority == null && uri.getRawAuthority() != null)
      return uri;
    if (rawAuthority != null && !(rawAuthority.equals(uri.getRawAuthority())))
      return uri;
    if (!(uri.getRawPath().startsWith(rawPath)))  <---- this test
      return uri;

In some cases I would expect uri.getRawPath().startsWith(rawPath) to return true since with a simple string character sequence test of startsWith() such as with the string 

"file:/home/eclipse/runtime-New_configuration/simple"

would be a prefix of

"file:/home/eclipse/runtime-New_configuration/simple_spu/simple_spu.c"

even though simple and simple_spu are technically different paths. This I think
is where the other VM implementations must be doing it correctly as they likely
examine components of a path as opposed to just a string prefix check.

A second problem is that when the code drops through to 

        return new URI(null, null,
                       uri.getRawPath().substring(rawPath.length()),
                       uri.getRawQuery(), uri.getRawFragment());

the substring() method may end up returning a leading '/' on the path in some cases which all the other JVMs do not.

The proposed solution is to create a new path with '/' appended to this.rawPath for the given base URI we are checking for. We would have to check that it isn't
already the last character. Example:

"file:/home/eclipse/runtime-New_configuration/simple"

becomes 

"file:/home/eclipse/runtime-New_configuration/simple/"

which is stored in basePath and then the

if (!(uri.getRawPath().startsWith(basePath)))

should end up returning uri since it doesn't have basePath as prefix when it is
for the path 
"file:/home/eclipse/runtime-New_configuration/simple_spu/simple_spu.c" for example. 

In addition, to correct avoiding returning a leading '/' a one line change is done to uri.getRawPath().substring(rawPath.length()) to instead get the length of the basePath string as it should always conclude with a '/'.

A testcase is supplied to provide examples of the results from various calls to the URI.relativize() method. Here is the results from the unpatched, failing code as it is right now:

[eclipse@chavez ~]$ java Test
_spu/simple_spu.c
<>
eclipse
/runtime-New_configuration/simple

Here are the results after applying the patch and re-running the testcase:

[eclipse@chavez ~]$ java Test
file:/home/eclipse/runtime-New_configuration/simple_spu/simple_spu.c
<>
eclipse
runtime-New_configuration/simple

The above output is consistent with that provided by executing the testcase using IBM Java 5, Sun Java 5 and IBM Java 1.4.2.
Comment 1 Luciano Chavez 2007-12-06 22:12:09 UTC
Created attachment 14704 [details]
testcase

Sample java code providing two examples where URI.relativize() method is not consistent with other JVM implementations.
Comment 2 Luciano Chavez 2007-12-06 22:15:29 UTC
Created attachment 14705 [details]
gcc-libjava-uri-relativize.patch to fix java.net.URI.relativize(URI) method

This patch corrects two issues found in URI.relativize() method in
libjava/classpath/java/net/URI.java. It applies from gcc 4.1.2 through latest trunk:

* does stricter check for a path match while still using String.startsWith()
* excludes leading '/' if necessary for relative path fragment being returned
Comment 3 Tom Tromey 2008-01-21 20:00:24 UTC
I'm handling this.
Comment 4 Tom Tromey 2008-01-21 20:09:00 UTC
Fixed on trunk.
Comment 5 Tom Tromey 2008-01-21 20:09:24 UTC
Subject: Bug 34369

Author: tromey
Date: Mon Jan 21 20:08:38 2008
New Revision: 131701

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=131701
Log:
2008-01-21  Luciano Chavez  <lnx1138@us.ibm.com>

	PR libgcj/34369:
	* java/net/URI.java (relativize): Check initial segment for
	trailing "/".

Modified:
    trunk/libjava/classpath/ChangeLog
    trunk/libjava/classpath/java/net/URI.java
    trunk/libjava/classpath/lib/java/net/URI.class

Comment 6 cvs-commit@developer.classpath.org 2008-01-21 20:11:45 UTC
Subject: Bug 34369

CVSROOT:	/cvsroot/classpath
Module name:	classpath
Changes by:	Tom Tromey <tromey>	08/01/21 20:09:56

Modified files:
	.              : ChangeLog 
	java/net       : URI.java 

Log message:
	2008-01-21  Luciano Chavez  <lnx1138@us.ibm.com>
	
		PR libgcj/34369:
		* java/net/URI.java (relativize): Check initial segment for
		trailing "/".

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/classpath/ChangeLog?cvsroot=classpath&r1=1.9474&r2=1.9475
http://cvs.savannah.gnu.org/viewcvs/classpath/java/net/URI.java?cvsroot=classpath&r1=1.20&r2=1.21