Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-5060040

APPLETCLASSLOADER CONSTRUCTS INCORRECT URLS FOR CLASS NAMES WITH INTERNATIONAL C

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: P4 P4
    • None
    • 1.4.2_01
    • core-libs
    • Fix Understood
    • x86
    • windows_xp

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



      ======================================================================

            Unassigned Unassigned
            rverabel Raghu Verabelli (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Imported:
              Indexed: