Name: rv122619 Date: 06/08/2004
When AppletClassLoader needs to fetch a loose class file from the applet codebase, it uses a very simplistic approach to construct the url for the .class file. The URL which AppletClassLoader uses does NOT encode Unicode characters as it should, and in fact appears to make no attempt at encoding non-ASCII characters in the class' name.
This is an issue when trying to deploy an applet with Hebrew characters in the applet class name.
Frequency: always
How to reproduce:
The following classes demonstrate a reduced form without using the Java Plug-in. Client allocates an AppletClassLoader and instructs it to load a class name containing Hebrew characters. The Server program provides a hex dump of the Client's http request. Comparing the name of the class requested with the bytes of the http request shows that significant information is lost -- there is no way that this URL request would ever be correct! Contrast this with the output of URI.toASCIIString or what a web server might actually respond to. For example, a successful hit against the class file (achieved by navigating Apache's directory listings) shows up as ...%d7%99%d7%a7%d7%a01.class in an Apache log. This value matches the output of URI.toASCIIString(). Clearly URI.toASCIIString is more appropriate that what AppletClassLoader is currently doing.
When run from dos boxes with Hebrew support turned on, Client outputs:
url = http://localhost:4321/ª¿íÙíÕ1.class
uri = http://localhost:4321/ª¿íÙíÕ1.class
uri.toASCIIString() = http://localhost:4321/%D7%99%D7%A7%D7%A01.class
uri.toURL() = http://localhost:4321/ª¿íÙíÕ1.class
And Server outputs:
received connection from /127.0.0.1
0: 47 45 54 20 2f e9 f7 f0 31 2e 63 6c 61 73 73 20 GET /ª¿íÙíÕ1.class
16: 48 54 54 50 2f 31 2e 31 0d 0a 55 73 65 72 2d 41 HTTP/1.1..User-A
32: 67 65 6e 74 3a 20 4a 61 76 61 2f 31 2e 34 2e 32 gent: Java/1.4.2
48: 5f 30 34 0d 0a 48 6f 73 74 3a 20 6c 6f 63 61 6c _04..Host: local
64: 68 6f 73 74 3a 34 33 32 31 0d 0a 41 63 63 65 70 host:4321..Accep
80: 74 3a 20 74 65 78 74 2f 68 74 6d 6c 2c 20 69 6d t: text/html, im
96: 61 67 65 2f 67 69 66 2c 20 69 6d 61 67 65 2f 6a age/gif, image/j
112: 70 65 67 2c 20 2a 3b 20 71 3d 2e 32 2c 20 2a 2f peg, *; q=.2, */
128: 2a 3b 20 71 3d 2e 32 0d 0a 43 6f 6e 6e 65 63 74 *; q=.2..Connect
144: 69 6f 6e 3a 20 6b 65 65 70 2d 61 6c 69 76 65 0d ion: keep-alive.
160: 0a 0d 0a í¡
When the unaltered Client and Server are run from dos boxes with Hebrew support turned off, Client outputs:
url = http://localhost:4321/???1.class
uri = http://localhost:4321/???1.class
uri.toASCIIString() = http://localhost:4321/%D7%99%D7%A7%D7%A01.class
uri.toURL() = http://localhost:4321/???1.class
And Server outputs:
received connection from /127.0.0.1
0: 47 45 54 20 2f 3f 3f 3f 31 2e 63 6c 61 73 73 20 GET /???1.class
16: 48 54 54 50 2f 31 2e 31 0d 0a 55 73 65 72 2d 41 HTTP/1.1..User-A
32: 67 65 6e 74 3a 20 4a 61 76 61 2f 31 2e 34 2e 32 gent: Java/1.4.2
48: 5f 30 34 0d 0a 48 6f 73 74 3a 20 6c 6f 63 61 6c _04..Host: local
64: 68 6f 73 74 3a 34 33 32 31 0d 0a 41 63 63 65 70 host:4321..Accep
80: 74 3a 20 74 65 78 74 2f 68 74 6d 6c 2c 20 69 6d t: text/html, im
96: 61 67 65 2f 67 69 66 2c 20 69 6d 61 67 65 2f 6a age/gif, image/j
112: 70 65 67 2c 20 2a 3b 20 71 3d 2e 32 2c 20 2a 2f peg, *; q=.2, */
128: 2a 3b 20 71 3d 2e 32 0d 0a 43 6f 6e 6e 65 63 74 *; q=.2..Connect
144: 69 6f 6e 3a 20 6b 65 65 70 2d 61 6c 69 76 65 0d ion: keep-alive.
160: 0a 0d 0a ...
Note that by putting a class with the example name in the current directory results results in Client successfully loading the class, proving that example class name is legal and loadable with other ClassLoaders.
Source Code:
import java.io.*;
import java.net.*;
import java.util.*;
import sun.applet.AppletClassLoader;
public class Client extends AppletClassLoader
{
private static final String NAME = "\u05d9\u05e7\u05e01";
public static void main(String[] args)
throws Exception
{
URL base = new URL("http://localhost:4321/");
AppletClassLoader cl = new Client(base);
URL url = new URL(base, NAME + ".class");
System.out.println("url = " + url);
URI uri = new URI("http://localhost:4321/" + NAME + ".class");
System.out.println("uri = " + uri);
System.out.println("uri.toASCIIString() = " + uri.toASCIIString());
System.out.println("uri.toURL() = " + uri.toURL());
try {
Class c = cl.loadClass(NAME);
System.out.println("loaded: " + c);
} catch (ClassNotFoundException cnfe) { cnfe.printStackTrace(); }
}
public Client(URL base)
{
super(base);
}
}
----- end Client.java -----
----- begin Server.java -----
import java.io.*;
import java.net.*;
public class Server
{
public static void main(String[] args)
throws Exception
{
ServerSocket ss = new ServerSocket(4321);
Socket s = ss.accept();
System.out.println("received connection from " + s.getInetAddress());
InputStream is = null;
try {
is = s.getInputStream();
int b;
while ( (b = is.read()) != -1 )
output(b);
} finally {
if (is != null) {
try { is.close(); }
catch (IOException ioe) {}
}
finishOutput();
System.out.flush();
}
}
private static final char[] HEX = "0123456789abcdef".toCharArray();
private static long s_pos = 0;
private static int s_linePos = 0;
private static byte[] s_pendingChars = new byte [16];
// want format:
// xxxx: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff 0123456789abcdef
private static void output(int b)
throws IOException
{
char c = (char) (b & 0xff);
if ( Character.isISOControl(c) || (c < 32) )
c = '.';
else if ( Character.isWhitespace(c) )
c = ' ';
if (s_linePos == 0)
System.out.print(s_pos + ":");
if (s_linePos == 8)
System.out.print(' ');
// output hex digits
System.out.print(' ');
System.out.print( HEX[ (b >> 4) & 0xf ] );
System.out.print( HEX[b & 0xf] );
s_pendingChars[s_linePos++] = (byte) c;
if (s_linePos >= 16) {
s_linePos = 0;
System.out.print(" ");
System.out.write(s_pendingChars);
System.out.println();
}
s_pos++;
}
private static void finishOutput()
throws IOException
{
if (s_linePos == 0) return;
int nSpace = 3 * (16 - s_linePos) + 2;
if (s_linePos < 8)
nSpace++;
for (int i = 0; i < nSpace; i++)
System.out.print(' ');
System.out.write(s_pendingChars, 0, s_linePos);
System.out.println();
s_linePos = 0;
}
}
======================================================================
When AppletClassLoader needs to fetch a loose class file from the applet codebase, it uses a very simplistic approach to construct the url for the .class file. The URL which AppletClassLoader uses does NOT encode Unicode characters as it should, and in fact appears to make no attempt at encoding non-ASCII characters in the class' name.
This is an issue when trying to deploy an applet with Hebrew characters in the applet class name.
Frequency: always
How to reproduce:
The following classes demonstrate a reduced form without using the Java Plug-in. Client allocates an AppletClassLoader and instructs it to load a class name containing Hebrew characters. The Server program provides a hex dump of the Client's http request. Comparing the name of the class requested with the bytes of the http request shows that significant information is lost -- there is no way that this URL request would ever be correct! Contrast this with the output of URI.toASCIIString or what a web server might actually respond to. For example, a successful hit against the class file (achieved by navigating Apache's directory listings) shows up as ...%d7%99%d7%a7%d7%a01.class in an Apache log. This value matches the output of URI.toASCIIString(). Clearly URI.toASCIIString is more appropriate that what AppletClassLoader is currently doing.
When run from dos boxes with Hebrew support turned on, Client outputs:
url = http://localhost:4321/ª¿íÙíÕ1.class
uri = http://localhost:4321/ª¿íÙíÕ1.class
uri.toASCIIString() = http://localhost:4321/%D7%99%D7%A7%D7%A01.class
uri.toURL() = http://localhost:4321/ª¿íÙíÕ1.class
And Server outputs:
received connection from /127.0.0.1
0: 47 45 54 20 2f e9 f7 f0 31 2e 63 6c 61 73 73 20 GET /ª¿íÙíÕ1.class
16: 48 54 54 50 2f 31 2e 31 0d 0a 55 73 65 72 2d 41 HTTP/1.1..User-A
32: 67 65 6e 74 3a 20 4a 61 76 61 2f 31 2e 34 2e 32 gent: Java/1.4.2
48: 5f 30 34 0d 0a 48 6f 73 74 3a 20 6c 6f 63 61 6c _04..Host: local
64: 68 6f 73 74 3a 34 33 32 31 0d 0a 41 63 63 65 70 host:4321..Accep
80: 74 3a 20 74 65 78 74 2f 68 74 6d 6c 2c 20 69 6d t: text/html, im
96: 61 67 65 2f 67 69 66 2c 20 69 6d 61 67 65 2f 6a age/gif, image/j
112: 70 65 67 2c 20 2a 3b 20 71 3d 2e 32 2c 20 2a 2f peg, *; q=.2, */
128: 2a 3b 20 71 3d 2e 32 0d 0a 43 6f 6e 6e 65 63 74 *; q=.2..Connect
144: 69 6f 6e 3a 20 6b 65 65 70 2d 61 6c 69 76 65 0d ion: keep-alive.
160: 0a 0d 0a í¡
When the unaltered Client and Server are run from dos boxes with Hebrew support turned off, Client outputs:
url = http://localhost:4321/???1.class
uri = http://localhost:4321/???1.class
uri.toASCIIString() = http://localhost:4321/%D7%99%D7%A7%D7%A01.class
uri.toURL() = http://localhost:4321/???1.class
And Server outputs:
received connection from /127.0.0.1
0: 47 45 54 20 2f 3f 3f 3f 31 2e 63 6c 61 73 73 20 GET /???1.class
16: 48 54 54 50 2f 31 2e 31 0d 0a 55 73 65 72 2d 41 HTTP/1.1..User-A
32: 67 65 6e 74 3a 20 4a 61 76 61 2f 31 2e 34 2e 32 gent: Java/1.4.2
48: 5f 30 34 0d 0a 48 6f 73 74 3a 20 6c 6f 63 61 6c _04..Host: local
64: 68 6f 73 74 3a 34 33 32 31 0d 0a 41 63 63 65 70 host:4321..Accep
80: 74 3a 20 74 65 78 74 2f 68 74 6d 6c 2c 20 69 6d t: text/html, im
96: 61 67 65 2f 67 69 66 2c 20 69 6d 61 67 65 2f 6a age/gif, image/j
112: 70 65 67 2c 20 2a 3b 20 71 3d 2e 32 2c 20 2a 2f peg, *; q=.2, */
128: 2a 3b 20 71 3d 2e 32 0d 0a 43 6f 6e 6e 65 63 74 *; q=.2..Connect
144: 69 6f 6e 3a 20 6b 65 65 70 2d 61 6c 69 76 65 0d ion: keep-alive.
160: 0a 0d 0a ...
Note that by putting a class with the example name in the current directory results results in Client successfully loading the class, proving that example class name is legal and loadable with other ClassLoaders.
Source Code:
import java.io.*;
import java.net.*;
import java.util.*;
import sun.applet.AppletClassLoader;
public class Client extends AppletClassLoader
{
private static final String NAME = "\u05d9\u05e7\u05e01";
public static void main(String[] args)
throws Exception
{
URL base = new URL("http://localhost:4321/");
AppletClassLoader cl = new Client(base);
URL url = new URL(base, NAME + ".class");
System.out.println("url = " + url);
URI uri = new URI("http://localhost:4321/" + NAME + ".class");
System.out.println("uri = " + uri);
System.out.println("uri.toASCIIString() = " + uri.toASCIIString());
System.out.println("uri.toURL() = " + uri.toURL());
try {
Class c = cl.loadClass(NAME);
System.out.println("loaded: " + c);
} catch (ClassNotFoundException cnfe) { cnfe.printStackTrace(); }
}
public Client(URL base)
{
super(base);
}
}
----- end Client.java -----
----- begin Server.java -----
import java.io.*;
import java.net.*;
public class Server
{
public static void main(String[] args)
throws Exception
{
ServerSocket ss = new ServerSocket(4321);
Socket s = ss.accept();
System.out.println("received connection from " + s.getInetAddress());
InputStream is = null;
try {
is = s.getInputStream();
int b;
while ( (b = is.read()) != -1 )
output(b);
} finally {
if (is != null) {
try { is.close(); }
catch (IOException ioe) {}
}
finishOutput();
System.out.flush();
}
}
private static final char[] HEX = "0123456789abcdef".toCharArray();
private static long s_pos = 0;
private static int s_linePos = 0;
private static byte[] s_pendingChars = new byte [16];
// want format:
// xxxx: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff 0123456789abcdef
private static void output(int b)
throws IOException
{
char c = (char) (b & 0xff);
if ( Character.isISOControl(c) || (c < 32) )
c = '.';
else if ( Character.isWhitespace(c) )
c = ' ';
if (s_linePos == 0)
System.out.print(s_pos + ":");
if (s_linePos == 8)
System.out.print(' ');
// output hex digits
System.out.print(' ');
System.out.print( HEX[ (b >> 4) & 0xf ] );
System.out.print( HEX[b & 0xf] );
s_pendingChars[s_linePos++] = (byte) c;
if (s_linePos >= 16) {
s_linePos = 0;
System.out.print(" ");
System.out.write(s_pendingChars);
System.out.println();
}
s_pos++;
}
private static void finishOutput()
throws IOException
{
if (s_linePos == 0) return;
int nSpace = 3 * (16 - s_linePos) + 2;
if (s_linePos < 8)
nSpace++;
for (int i = 0; i < nSpace; i++)
System.out.print(' ');
System.out.write(s_pendingChars, 0, s_linePos);
System.out.println();
s_linePos = 0;
}
}
======================================================================
- relates to
-
JDK-5012012 Storing classes/packages whose names are not valid on the file system
- Open