Back to index

lightning-sunbird  0.9+nobinonly
ProxyClassLoader.cpp File Reference
#include "ProxyClassLoader.h"
#include "jsapi.h"
#include "jsjava.h"
#include "prprf.h"
#include "nsIServiceManager.h"
#include "nsIScriptSecurityManager.h"
#include "nsIJSContextStack.h"
#include "nsIPrincipal.h"
#include "nsIScriptContext.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsNetUtil.h"
#include "ProxyJNI.h"
#include "nsCNullSecurityContext.h"

Go to the source code of this file.


static nsresult getScriptClassLoader (JNIEnv *env, jobject *classloader)
 Obtain the netscape.oji.ProxyClassLoader instance associated with the document of the currently running script.
jclass ProxyFindClass (JNIEnv *env, const char *name)

Function Documentation

static nsresult getScriptClassLoader ( JNIEnv env,
jobject classloader 
) [static]

Obtain the netscape.oji.ProxyClassLoader instance associated with the document of the currently running script.

For now, store a LiveConnect wrapper for this instance in window.navigator.javaclasses. There hopefully aren't any security concerns with exposing this to scripts, as the constructor is private, and the class loader itself can only load classes from the document's URL and below.

Definition at line 65 of file ProxyClassLoader.cpp.

    // get the current JSContext from the context stack service.
    nsresult rv;
    nsCOMPtr<nsIJSContextStack> contexts =
        do_GetService(";1", &rv);
    if (NS_FAILED(rv)) return rv;
    JSContext* cx;
    rv = contexts->Peek(&cx);
    if (NS_FAILED(rv)) return rv;
    // lookup "window.navigator.javaclasses", if it exists, this is the class
    // loader bound to this page.
    JSObject* window = JS_GetGlobalObject(cx);
    if (!window) return NS_ERROR_FAILURE;

    jsval navigator = JSVAL_NULL;
    if (!JS_LookupProperty(cx, window, "navigator", &navigator))
        return NS_ERROR_FAILURE;
    jsval javaclasses = JSVAL_NULL;
    if (!JSVAL_IS_PRIMITIVE(navigator)) {
        uintN attrs;
        JSBool found;

        // Make sure that we pull out the correct javaclasses object that we
        // set.  Since content can't spoof READONLY or PERMANANT properties,
        // their presence on this property indicates that this truely is the
        // correct object.
        JSObject *obj = JSVAL_TO_OBJECT(navigator);
        if (!JS_GetPropertyAttributes(cx, obj, "javaclasses", &attrs, &found))
            return NS_ERROR_FAILURE;
        if ((~attrs & (JSPROP_READONLY | JSPROP_PERMANENT)) == 0 &&
            !JS_GetProperty(cx, obj, "javaclasses", &javaclasses)) {
            return NS_ERROR_FAILURE;

        // Unwrap this, the way LiveConnect does it. Note that this function
        // checks if javaclasses is primitive or not.
        if (JSJ_ConvertJSValueToJavaObject(cx, javaclasses, classloader))
            return NS_OK;

    // use default netscape.oji.ProxyClassLoaderFactory (which is no longer
    // supported in recent JRE) as the classloader
    jclass netscape_oji_ProxyClassLoaderFac =
    if (!netscape_oji_ProxyClassLoaderFac) {
        return NS_ERROR_FAILURE;
    jmethodID staticMethodID =
    if (!staticMethodID) {
        return NS_ERROR_FAILURE;

    // Obtain the URL of the document of the currently running script. This will
    // be used as the default location to download classes from.
    nsCOMPtr<nsIScriptSecurityManager> secMan =
    if (NS_FAILED(rv)) return rv;

    nsCOMPtr<nsIPrincipal> principal, sysprincipal;
    rv = secMan->GetPrincipalFromContext(cx, getter_AddRefs(principal));
    if (NS_FAILED(rv)) return rv;

    rv = secMan->GetSystemPrincipal(getter_AddRefs(sysprincipal));
    if (NS_FAILED(rv)) return rv;

    PRBool equals;
    rv = principal->Equals(sysprincipal, &equals);
    // Can't get URI from system principal
    if (NS_FAILED(rv)) return rv;
    if (equals) return NS_ERROR_FAILURE;

    nsCOMPtr<nsIURI> codebase;
    rv = principal->GetURI(getter_AddRefs(codebase));
    if (NS_FAILED(rv)) return rv;

    // create a netscape.oji.ProxyClassLoader instance.
    nsCAutoString spec;
    rv = codebase->GetSpec(spec);
    if (NS_FAILED(rv)) return rv;
    jstring jspec = env->NewStringUTF(spec.get());
    if (!jspec) {
        return NS_ERROR_FAILURE;

    // In order to have permission to create classloader, we need to grant
    // enough permission
    nsISecurityContext* origContext = nsnull;
    if (NS_FAILED(GetSecurityContext(env, &origContext))) {
        return NS_ERROR_FAILURE;
    nsCOMPtr<nsISecurityContext> nullContext(new nsCNullSecurityContext());
    if (!nullContext) {
        return NS_ERROR_OUT_OF_MEMORY;
    SetSecurityContext(env, nullContext);
    *classloader = env->CallStaticObjectMethod(netscape_oji_ProxyClassLoaderFac,
                                               staticMethodID, jspec);
    SetSecurityContext(env, origContext);
    if (!*classloader) {
        return NS_ERROR_FAILURE;

    // now, cache the class loader in "window.navigator.javaclasses"
    if (!JSVAL_IS_PRIMITIVE(navigator) &&
        JSJ_ConvertJavaObjectToJSValue(cx, *classloader, &javaclasses) &&
        !JS_DefineProperty(cx, JSVAL_TO_OBJECT(navigator), "javaclasses",
                           javaclasses, NULL, NULL, JSPROP_ENUMERATE |
                           JSPROP_READONLY | JSPROP_PERMANENT)) {
        return NS_ERROR_FAILURE;
    return NS_OK;

Here is the call graph for this function:

Here is the caller graph for this function:

jclass ProxyFindClass ( JNIEnv env,
const char *  name 

Definition at line 194 of file ProxyClassLoader.cpp.

    do {
        // TODO:  prevent recursive call to ProxyFindClass, if netscape.oji.ProxyClassLoader
        // isn't found by getScriptClassLoader().
        jobject classloader;
        jthrowable jException = env->ExceptionOccurred();
        if (jException != NULL) {
            // Clean up exception
            // Release local ref
        nsresult rv = getScriptClassLoader(env, &classloader);
        if (NS_FAILED(rv)) break;

        jclass netscape_oji_ProxyClassLoader = env->GetObjectClass(classloader);
        jmethodID loadClassID = env->GetMethodID(netscape_oji_ProxyClassLoader, "loadClass",
        if (!loadClassID) {
        jstring jname = env->NewStringUTF(name);
        jvalue jargs[1]; jargs[0].l = jname;
        jclass c = (jclass) env->CallObjectMethodA(classloader, loadClassID, jargs);
        return c;
    } while (0);
    return 0;

Here is the call graph for this function:

Here is the caller graph for this function: