United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-4273532 : toURL() method in File class needs to escape excluded URL characters

Details
Type:
Bug
Submit Date:
1999-09-20
Status:
Closed
Updated Date:
2004-10-15
Project Name:
JDK
Resolved Date:
2002-07-19
Component:
core-libs
OS:
solaris_8,solaris_2.6,windows_nt,generic,windows_98
Sub-Component:
java.io
CPU:
x86,sparc,generic
Priority:
P2
Resolution:
Won't Fix
Affected Versions:
s8u6,solaris_8u1,1.2.0,1.2.1,1.2.1_04,1.2.2,1.3.0,1.3.1
Fixed Versions:

Related Reports
Duplicate:
Duplicate:
Duplicate:
Duplicate:
Duplicate:
Relates:
Relates:
Relates:
Relates:
Relates:
Relates:
Relates:
Relates:
Relates:
Relates:
Relates:

Sub Tasks

Description
The File class toURL() method does not escape "excluded" URL
characters when mapping a file path to a file: URL. For example, space
characters or '#' characters etc. should be escaped with a '%' followed by the
hexidecimal encoding of the character.

	See RFC 2396 section 2.4.3.

Name: rlT66838			Date: 02/15/2000


java version "1.2.2"
HotSpot VM (1.0.1, mixed mode, build g)

1. Make directory, which name containts "!" sign and go to it.
2. Create java file like:
import java.net.*;
import java.io.*;
public class q
{
    public q()
    {
        try {
            URL u = getClass().getResource("myresources");
            System.out.println("" + u);
            InputStream in = u.openStream();
            System.out.println("" + in);
            InputStreamReader inr = new InputStreamReader(in);
         } catch (Throwable t)
        {
            t.printStackTrace();
        }
    }
    
    public static void main(String args[])
    {
        q qq = new q();
    }
}

3. Create file named "myresources"
4. Place q.class and myresources to JAR file, by example "test.jar"
5. Run java -classpath test.jar q
6. Look at console:
jar:file:/M:/test/!/test.jar!/myresources
java.util.zip.ZipException: error in opening zip file
        at java.util.zip.ZipFile.open(Native Method)
        at java.util.zip.ZipFile.<init>(ZipFile.java:69)
        at java.util.jar.JarFile.<init>(JarFile.java:71)
        at java.util.jar.JarFile.<init>(JarFile.java:58)
        at sun.net.www.protocol.jar.JarFileFactory.get(JarFileFactory.java:76)
        at sun.net.www.protocol.jar.JarURLConnection.connect
(JarURLConnection.java:92)
        at sun.net.www.protocol.jar.JarURLConnection.getInputStream
(JarURLConnection.java:
112)
        at java.net.URL.openStream(URL.java:818)
        at q.<init>(q.java:10)
        at q.main(q.java:21)

7. Place all files in, by example, "test" directory.
Run again. All is OK.

Problem occurs because "!" is Jar resource delimiter sign, and I think
that either "!" must not be resource delimiter sign, or
JarURLConnection::getResource() needed to be changed.
(Review ID: 101275)
======================================================================
###@###.### 10/15/04 18:46 GMT

                                    

Comments
EVALUATION

File.toURL now uses code in sun.net.www.ParseUtil to escape reserved and
excluded characters in the path. The path is UTF-8 encoded as well.
michael.mccloskey@eng 2000-02-24

We could not go ahead with this fix because of compatibility. Use File.toURI().toURL().
###@###.### 2002-07-19
                                     
2000-02-24
WORK AROUND

Use file.toURI().toURL().
###@###.### 2002-07-19
                                     
2002-07-19
PUBLIC COMMENTS

	The File class toURL() method does not escape illegal URL
characters when mapping a file path to a file: URL.
                                     
2004-06-10
SUGGESTED FIX

src/share/classes/java/io/File.java:

public URL toURL() throws MalformedURLException {
    String path = getAbsolutePath();
    path = ParseUtil.encodePath(path, isDirectory());
    return new URL("file", "", path);
}

src/share/classes/sun/net/www/ParseUtil.java:

    static BitSet encodedInPath;

    static {
        encodedInPath = new BitSet(256);

        // Set the bits corresponding to characters that are encoded in the
        // path component of a URI.

        // These characters are reserved in the path segment as described in
        // RFC2396 section 3.3.
        encodedInPath.set('=');
        encodedInPath.set(';');
        encodedInPath.set('?');
        encodedInPath.set('/');

        // These characters are defined as excluded in RFC2396 section 2.4.3
        // and must be escaped if they occur in the data part of a URI.
        encodedInPath.set('#');
        encodedInPath.set(' ');
        encodedInPath.set('<');
        encodedInPath.set('>');
        encodedInPath.set('%');
        encodedInPath.set('"');
        encodedInPath.set('{');
        encodedInPath.set('}');
        encodedInPath.set('|');
        encodedInPath.set('\\');
        encodedInPath.set('^');
        encodedInPath.set('[');
        encodedInPath.set(']');
        encodedInPath.set('`');

        // US ASCII control characters 00-1F and 7F.
        for (int i=0; i<32; i++)
            encodedInPath.set(i);
        encodedInPath.set(127);
    }

    /**
     * Constructs an encoded version of the specified path string suitable
     * for use in the construction of a URL.
     *
     * If the path does not start with a '/' then a '/' is prepended. If
     * <tt>directory</tt> is <tt>true</tt> then a '/' is appended to the
     * specified path.
     *
     * A path separator is replaced by a forward slash. The string is UTF8
     * encoded. The % escape sequence is used for characters that are above
     * 0x7F or those defined in RFC2396 as reserved or excluded in the path
     * component of a URL.
     */
    public static String encodePath(String path, boolean directory) {
        StringBuffer sb = new StringBuffer();
	int n = path.length();
        for (int i=0; i<n; i++) {
            char c = path.charAt(i);
            if (c == File.separatorChar)
                sb.append('/');
            else {
                if (c <= 0x007F) {
                    if (encodedInPath.get(c))
                        escape(sb, c);
                    else
                        sb.append(c);
                } else if (c > 0x07FF) {
                    escape(sb, (char)(0xE0 | ((c >> 12) & 0x0F)));
                    escape(sb, (char)(0x80 | ((c >>  6) & 0x3F)));
                    escape(sb, (char)(0x80 | ((c >>  0) & 0x3F)));
                } else {
                    escape(sb, (char)(0xC0 | ((c >>  6) & 0x1F)));
                    escape(sb, (char)(0x80 | ((c >>  0) & 0x3F)));
                }
            }
        }
        path = sb.toString();
        if (!path.startsWith("/")) {
	    path = "/" + path;
	}
	if (!path.endsWith("/") && directory) {
	    path = path + "/";
	}
        return path;
    }

    /**
     * Appends the URL escape sequence for the specified char to the
     * specified StringBuffer.
     */
    private static void escape(StringBuffer s, char c) {
        s.append('%');
        s.append(Character.forDigit((c >> 4) & 0xF, 16));
        s.append(Character.forDigit(c & 0xF, 16));
    }
                                     
2004-06-11



Hardware and Software, Engineered to Work Together