Back to index

lightning-sunbird  0.9+nobinonly
Public Member Functions | Protected Member Functions | Protected Attributes
nsJSThunk Class Reference
Inheritance diagram for nsJSThunk:
Inheritance graph
[legend]
Collaboration diagram for nsJSThunk:
Collaboration graph
[legend]

List of all members.

Public Member Functions

 nsJSThunk ()
NS_DECL_ISUPPORTS nsresult Init (nsIURI *uri)
nsresult EvaluateScript (nsIChannel *aChannel)
nsresult BringUpConsole (nsIDOMWindow *aDomWindow)
void close ()
 Close the stream.
unsigned long available ()
unsigned long read (in charPtr aBuf, in unsigned long aCount)
 Read data from the stream.
unsigned long readSegments (in nsWriteSegmentFun aWriter, in voidPtr aClosure, in unsigned long aCount)
 Low-level read method that has access to the stream's underlying buffer.
boolean isNonBlocking ()

Protected Member Functions

virtual ~nsJSThunk ()

Protected Attributes

nsCOMPtr< nsIURImURI
nsCOMPtr< nsIInputStreammInnerStream

Detailed Description

Definition at line 84 of file nsJSProtocolHandler.cpp.


Constructor & Destructor Documentation

Definition at line 109 of file nsJSProtocolHandler.cpp.

{
}
nsJSThunk::~nsJSThunk ( ) [protected, virtual]

Definition at line 113 of file nsJSProtocolHandler.cpp.

{
}

Member Function Documentation

unsigned long nsIInputStream::available ( ) [inherited]
Returns:
number of bytes currently available in the stream

Definition at line 403 of file nsJSProtocolHandler.cpp.

{
    nsresult rv;

    // First, get the Window Mediator service.
    nsCOMPtr<nsIWindowMediator> windowMediator =
        do_GetService(kWindowMediatorCID, &rv);

    if (NS_FAILED(rv)) return rv;

    // Next, find out whether there's a console already open.
    nsCOMPtr<nsIDOMWindowInternal> console;
    rv = windowMediator->GetMostRecentWindow(NS_LITERAL_STRING("global:console").get(),
                                             getter_AddRefs(console));
    if (NS_FAILED(rv)) return rv;

    if (console) {
        // If the console is already open, bring it to the top.
        rv = console->Focus();
    } else {
        nsCOMPtr<nsIJSConsoleService> jsconsole;

        jsconsole = do_GetService("@mozilla.org/embedcomp/jsconsole-service;1", &rv);
        if (NS_FAILED(rv) || !jsconsole) return rv;
        jsconsole->Open(aDomWindow);
    }
    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsIInputStream::close ( ) [inherited]

Close the stream.

Definition at line 137 of file nsJSProtocolHandler.cpp.

{
    nsresult rv;

    NS_ENSURE_ARG_POINTER(aChannel);

    // Get the script string to evaluate...
    nsCAutoString script;
    rv = mURI->GetPath(script);
    if (NS_FAILED(rv)) return rv;

    // The the global object owner from the channel
    nsCOMPtr<nsIScriptGlobalObjectOwner> globalOwner;
    NS_QueryNotificationCallbacks(aChannel, globalOwner);
    NS_ASSERTION(globalOwner, 
                 "Unable to get an nsIScriptGlobalObjectOwner from the "
                 "channel!");
    if (!globalOwner) {
        return NS_ERROR_FAILURE;
    }

    // So far so good: get the script context from its owner.
    nsIScriptGlobalObject* global = globalOwner->GetScriptGlobalObject();

    NS_ASSERTION(global,
                 "Unable to get an nsIScriptGlobalObject from the "
                 "ScriptGlobalObjectOwner!");
    if (!global) {
        return NS_ERROR_FAILURE;
    }

    nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(global));

    // Get the document out of the window to make sure we create a new
    // inner window if one doesn't already exist (see bug 306630).
    nsCOMPtr<nsIDOMDocument> doc;
    win->GetDocument(getter_AddRefs(doc));

    nsPIDOMWindow *innerWin = win->GetCurrentInnerWindow();

    if (!innerWin) {
        return NS_ERROR_UNEXPECTED;
    }

    nsCOMPtr<nsIScriptGlobalObject> innerGlobal = do_QueryInterface(innerWin);

    JSObject *globalJSObject = innerGlobal->GetGlobalJSObject();

    nsCOMPtr<nsIDOMWindow> domWindow(do_QueryInterface(global, &rv));
    if (NS_FAILED(rv)) {
        return NS_ERROR_FAILURE;
    }

    // If mURI is just "javascript:", we bring up the Error console
    // and return NS_ERROR_DOM_RETVAL_UNDEFINED.
    if (script.IsEmpty()) {
        rv = BringUpConsole(domWindow);
        if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
        return NS_ERROR_DOM_RETVAL_UNDEFINED;
    }

    // Now get the DOM Document.  Accessing the document will create one
    // if necessary.  So, basically, this call ensures that a document gets
    // created -- if necessary.
    rv = domWindow->GetDocument(getter_AddRefs(doc));
    NS_ASSERTION(doc, "No DOMDocument!");
    if (NS_FAILED(rv)) {
        return NS_ERROR_FAILURE;
    }

    nsCOMPtr<nsIScriptContext> scriptContext = global->GetContext();
    if (!scriptContext)
        return NS_ERROR_FAILURE;

    // Unescape the script
    NS_UnescapeURL(script);

    // Get the url.
    nsCAutoString url;
    rv = mURI->GetSpec(url);
    if (NS_FAILED(rv)) return rv;

    // Get principal of code for execution
    nsCOMPtr<nsISupports> owner;
    rv = aChannel->GetOwner(getter_AddRefs(owner));
    nsCOMPtr<nsIPrincipal> principal;
    if (NS_FAILED(rv))
        return rv;

    nsCOMPtr<nsIScriptSecurityManager> securityManager;
    securityManager = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
    if (NS_FAILED(rv))
        return rv;

    PRBool useSandbox = PR_TRUE;

    if (owner) {
        principal = do_QueryInterface(owner, &rv);
        NS_ASSERTION(principal, "Channel's owner is not a principal");
        if (!principal)
            return NS_ERROR_FAILURE;

        //-- Don't run if the script principal is different from the principal
        //   of the context, unless the script has the system principal.
        nsCOMPtr<nsIPrincipal> objectPrincipal;
        rv = securityManager->GetObjectPrincipal(
                                (JSContext*)scriptContext->GetNativeContext(),
                                globalJSObject,
                                getter_AddRefs(objectPrincipal));
        if (NS_FAILED(rv))
            return rv;

        nsCOMPtr<nsIPrincipal> systemPrincipal;
        securityManager->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
        if (principal != systemPrincipal) {
            rv = securityManager->CheckSameOriginPrincipal(principal,
                                                           objectPrincipal);
            if (NS_SUCCEEDED(rv)) {
                useSandbox = PR_FALSE;
            }
        } else {
            useSandbox = PR_FALSE;
        }
    }

    nsString result;
    PRBool isUndefined;

    // Finally, we have everything needed to evaluate the expression.

    if (useSandbox) {
        // No owner from channel, or we have a principal
        // mismatch. Evaluate the javascript URL in a sandbox to
        // prevent it from accessing data it doesn't have permissions
        // to access.

        // First check to make sure it's OK to evaluate this script to
        // start with.  For example, script could be disabled.
        nsCOMPtr<nsIPrincipal> enabledCheckPrincipal = principal;
        if (!enabledCheckPrincipal) {
            // We just need a principal that's not the system principal and
            // isn't whitelisted by CanExecuteScripts.  An about:blank
            // principal will do nicely.
            nsCOMPtr<nsIURI> uri;
            rv = NS_NewURI(getter_AddRefs(uri), "about:blank");
            NS_ENSURE_SUCCESS(rv, rv);
            rv = securityManager->
                GetCodebasePrincipal(uri,
                                     getter_AddRefs(enabledCheckPrincipal));
            NS_ENSURE_SUCCESS(rv, rv);
        }

        JSContext *cx = (JSContext*)scriptContext->GetNativeContext();

        PRBool ok;
        rv = securityManager->CanExecuteScripts(cx, enabledCheckPrincipal,
                                                &ok);
        if (NS_FAILED(rv)) {
            return rv;
        }

        if (!ok) {
            // Treat this as returning undefined from the script.  That's what
            // nsJSContext does.
            return NS_ERROR_DOM_RETVAL_UNDEFINED;
        }

        nsIXPConnect *xpc = nsContentUtils::XPConnect();
        nsCOMPtr<nsIXPConnect_MOZILLA_1_8_BRANCH2> xpc_18 =
            do_QueryInterface(xpc);

        nsCOMPtr<nsIXPConnectJSObjectHolder> sandbox;
        rv = xpc_18->CreateSandbox(cx, principal, getter_AddRefs(sandbox));
        NS_ENSURE_SUCCESS(rv, rv);

        jsval rval = JSVAL_VOID;
        nsAutoGCRoot root(&rval, &rv);
        if (NS_FAILED(rv)) {
            return rv;
        }

        // Push our JSContext on the context stack so the JS_ValueToString call
        // (and JS_ReportPendingException, if relevant) will use the principal
        // of cx.  Note that we do this as late as possible to make popping
        // simpler.
        nsCOMPtr<nsIJSContextStack> stack =
            do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
        if (NS_SUCCEEDED(rv)) {
            rv = stack->Push(cx);
        }
        if (NS_FAILED(rv)) {
            return rv;
        }

        rv = xpc_18->EvalInSandboxObject2(NS_ConvertUTF8toUTF16(script), cx,
                                          sandbox, PR_TRUE, &rval);

        // Propagate and report exceptions that happened in the
        // sandbox.
        if (JS_IsExceptionPending(cx)) {
            JS_ReportPendingException(cx);
            isUndefined = PR_TRUE;
        } else {
            isUndefined = rval == JSVAL_VOID;
        }

        if (!isUndefined && NS_SUCCEEDED(rv)) {
            NS_ASSERTION(JSVAL_IS_STRING(rval), "evalInSandbox is broken");
            result = nsDependentJSString(JSVAL_TO_STRING(rval));
        }

        stack->Pop(nsnull);
    } else {
        // No need to use the sandbox, evaluate the script directly in
        // the given scope.
        rv = scriptContext->EvaluateString(NS_ConvertUTF8toUTF16(script),
                                           globalJSObject, // obj
                                           principal,
                                           url.get(),      // url
                                           1,              // line no
                                           nsnull,
                                           &result,
                                           &isUndefined);
    }

    if (NS_FAILED(rv)) {
        rv = NS_ERROR_MALFORMED_URI;
    }
    else if (isUndefined) {
        rv = NS_ERROR_DOM_RETVAL_UNDEFINED;
    }
    else {
        char *bytes;
        PRUint32 bytesLen;
        NS_NAMED_LITERAL_CSTRING(isoCharset, "ISO-8859-1");
        NS_NAMED_LITERAL_CSTRING(utf8Charset, "UTF-8");
        const nsCString *charset;
        if (IsISO88591(result)) {
            // For compatibility, if the result is ISO-8859-1, we use
            // ISO-8859-1, so that people can compatibly create images
            // using javascript: URLs.
            bytes = ToNewCString(result);
            bytesLen = result.Length();
            charset = &isoCharset;
        }
        else {
            bytes = ToNewUTF8String(result, &bytesLen);
            charset = &utf8Charset;
        }
        aChannel->SetContentCharset(*charset);
        if (bytes) {
            rv = NS_NewByteInputStream(getter_AddRefs(mInnerStream),
                                       bytes, bytesLen);
            if (mInnerStream) {
                nsCOMPtr<nsIStringInputStream> sis
                    = do_QueryInterface(mInnerStream);
                sis->AdoptData(bytes, bytesLen); // Previous call was |ShareData|
            }
        }
        else
            rv = NS_ERROR_OUT_OF_MEMORY;
    }

    return rv;
}

Here is the call graph for this function:

Definition at line 117 of file nsJSProtocolHandler.cpp.

{
    NS_ENSURE_ARG_POINTER(uri);

    mURI = uri;
    return NS_OK;
}
Returns:
true if stream is non-blocking
unsigned long nsIInputStream::read ( in charPtr  aBuf,
in unsigned long  aCount 
) [inherited]

Read data from the stream.

Parameters:
aBufthe buffer into which the data is to be read
aCountthe maximum number of bytes to be read
Returns:
number of bytes read (may be less than aCount).
0 if reached end of file
Exceptions:
NS_BASE_STREAM_WOULD_BLOCKif reading from the input stream would block the calling thread (non-blocking mode only)
<other-error>on failure
unsigned long nsIInputStream::readSegments ( in nsWriteSegmentFun  aWriter,
in voidPtr  aClosure,
in unsigned long  aCount 
) [inherited]

Low-level read method that has access to the stream's underlying buffer.

The writer function may be called multiple times for segmented buffers. ReadSegments is expected to keep calling the writer until either there is nothing left to read or the writer returns an error. ReadSegments should not call the writer with zero bytes to consume.

Parameters:
aWriterthe "consumer" of the data to be read
aClosureopaque parameter passed to writer
aCountthe maximum number of bytes to be read
Returns:
number of bytes read (may be less than aCount)
0 if reached end of file (or if aWriter refused to consume data)
Exceptions:
NS_BASE_STREAM_WOULD_BLOCKif reading from the input stream would block the calling thread (non-blocking mode only)
<other-error>on failure

NOTE: this function may be unimplemented if a stream has no underlying buffer (e.g., socket input stream).


Member Data Documentation

Definition at line 100 of file nsJSProtocolHandler.cpp.

Definition at line 99 of file nsJSProtocolHandler.cpp.


The documentation for this class was generated from the following file: