$FreeBSD$

--- ../../deploy/src/plugin/src/share/classes/sun/plugin/javascript/JSClassLoader.java	1 Jan 1970 00:00:00 -0000
+++ ../../deploy/src/plugin/src/share/classes/sun/plugin/javascript/JSClassLoader.java	3 Dec 2004 03:56:58 -0000	1.1
@@ -0,0 +1,238 @@
+/*
+ * @(#)JSClassLoader.java	1.1 04/06/20
+ *
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ */
+
+package sun.plugin.javascript;
+
+import java.security.AllPermission;
+import java.security.AccessController;
+import java.security.PermissionCollection;
+import java.security.SecureClassLoader;
+import java.security.PrivilegedExceptionAction;
+import java.security.CodeSource;
+import java.io.InputStream;
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.HttpURLConnection;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.AccessibleObject;
+import sun.net.www.ParseUtil;
+import sun.security.util.SecurityConstants;
+
+/*
+ * Create a trampoline class for JavaScript to Java
+ * method invocations.
+ * 
+ */
+public final class JSClassLoader extends SecureClassLoader {
+    private static String JS_PROXY_PKG = "sun.plugin.javascript.invoke.";
+    private static String TRAMPOLINE = JS_PROXY_PKG + "JSInvoke";
+    private static Method bounce; 
+
+    /*
+     * Bounce through the trampoline.
+     */
+    public static Object invoke(Method m, Object obj, Object[] params)
+	throws Exception {
+	try {
+	    return bounce().invoke(null, new Object[] {m, obj, params});
+	} catch (InvocationTargetException ie) {
+	    Throwable t = ie.getCause();
+
+	    if (t instanceof InvocationTargetException) {
+		throw (InvocationTargetException)t;
+	    } else {
+		throw ie;
+	    }
+	}
+    }
+
+    /**
+     * Check the package access permission by giving a class
+     * 
+     * @param clazz: The Class object trying to get access to
+     *
+     */
+    public static void checkPackageAccess(Class clazz) {
+	String clsname = clazz.getName();
+	int index = clsname.lastIndexOf(".");
+	if (index != -1) {
+	    String pkgname = clsname.substring(0, index);
+	    SecurityManager s = System.getSecurityManager();
+	    if (s != null) {
+		s.checkPackageAccess(pkgname);
+	    }
+	}
+    }
+
+    public static boolean isPackageAccessible(Class clazz) {
+	try {
+	    checkPackageAccess(clazz);
+	} catch (SecurityException e) {
+	    return false;
+	}
+	return true;
+    }
+
+
+    private synchronized static Method bounce() throws Exception {
+	if (bounce == null) {
+	    bounce = (Method) AccessController.doPrivileged(new PrivilegedExceptionAction() {
+		public Object run() throws Exception {
+	    	    Class[] types;
+	    	    Class t = getTrampoline();
+		    Method b;
+
+	    	    types = new Class[] {Method.class, Object.class, Object[].class};
+	            b = t.getDeclaredMethod("invoke", types);
+	    	    ((AccessibleObject)b).setAccessible(true);
+		    return b;
+		}
+	    });
+	}
+	return bounce;
+    }
+
+    private static Class getTrampoline() {
+        try {
+	    return Class.forName(TRAMPOLINE, true, new JSClassLoader());
+	} catch (ClassNotFoundException e) {
+	}
+	return null;
+    }
+
+
+    protected synchronized Class loadClass(String name, boolean resolve)
+	throws ClassNotFoundException
+    {
+	SecurityManager s = System.getSecurityManager();
+	if (s != null) {
+	    String cname = name.replace('/', '.');
+	    if (cname.startsWith("[")) {
+		int b = cname.lastIndexOf('[') + 2;
+		if (b > 1 && b < cname.length()) {
+		    cname = cname.substring(b);
+		}
+	    }
+	    int i = cname.lastIndexOf('.');
+	    if (i != -1) {
+		s.checkPackageAccess(cname.substring(0, i));
+	    }
+	}
+	// First, check if the class has already been loaded
+	Class c = findLoadedClass(name);
+	if (c == null) {
+	    try {
+	        c = findClass(name);
+	    } catch (ClassNotFoundException e) {
+		// Fall through ...
+	    }
+	    if (c == null) {
+		c = getParent().loadClass(name);
+	    }
+	}
+	if (resolve) {
+	    resolveClass(c);
+	}
+	return c;
+    }
+
+
+    protected Class findClass(final String name)
+	throws ClassNotFoundException
+    {
+	if (!name.startsWith(JS_PROXY_PKG)) {
+	    throw new ClassNotFoundException(name);
+	}
+	String path = name.replace('.', '/').concat(".class");
+	URL res = getResource(path);
+	if (res != null) {
+	    try {
+		return defineClass(name, res);
+	    } catch (IOException e) {
+		throw new ClassNotFoundException(name, e);
+	    }
+	} else {
+	    throw new ClassNotFoundException(name);
+	}
+    }
+
+
+    /*
+     * Define the JavaScript proxy classes
+     */
+    private Class defineClass(String name, URL url) throws IOException {
+	byte[] b = getBytes(url);
+	CodeSource cs = new CodeSource(null, (java.security.cert.Certificate[])null);
+	if (!name.equals(TRAMPOLINE)) {
+	    throw new IOException("JSClassLoader: bad name " + name);
+	}
+	return defineClass(name, b, 0, b.length, cs);
+    }
+
+
+    /*
+     * Returns the contents of the specified URL as an array of bytes.
+     */
+    private static byte[] getBytes(URL url) throws IOException {
+	URLConnection uc = url.openConnection();
+        if (uc instanceof java.net.HttpURLConnection) {
+            java.net.HttpURLConnection huc = (java.net.HttpURLConnection) uc;
+            int code = huc.getResponseCode();
+            if (code >= java.net.HttpURLConnection.HTTP_BAD_REQUEST) {
+                throw new IOException("open HTTP connection failed.");
+            }
+        }
+        int len = uc.getContentLength();
+        InputStream in = new BufferedInputStream(uc.getInputStream());
+	
+        byte[] b;
+        try {
+            if (len != -1) {
+                // Read exactly len bytes from the input stream
+                b = new byte[len];
+                while (len > 0) {
+                    int n = in.read(b, b.length - len, len);
+                    if (n == -1) {
+                        throw new IOException("unexpected EOF");
+                    }
+                    len -= n;
+                }
+            } else {
+                b = new byte[8192];
+                int total = 0;
+                while ((len = in.read(b, total, b.length - total)) != -1) {
+                    total += len;
+                    if (total >= b.length) {
+                        byte[] tmp = new byte[total * 2];
+                        System.arraycopy(b, 0, tmp, 0, total);
+                        b = tmp;
+                    }
+                }
+                // Trim array to correct size, if necessary
+                if (total != b.length) {
+                    byte[] tmp = new byte[total];
+                    System.arraycopy(b, 0, tmp, 0, total);
+                    b = tmp;
+                }
+            }
+        } finally {
+            in.close();
+        }
+        return b;
+    }
+
+
+    protected PermissionCollection getPermissions(CodeSource codesource)
+    {
+	PermissionCollection perms = super.getPermissions(codesource);
+	perms.add(new AllPermission());
+	return perms;
+    }
+}