|  | /* | 
|  | * Copyright 2008 Google Inc. | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); you may not | 
|  | * use this file except in compliance with the License. You may obtain a copy of | 
|  | * the License at | 
|  | * | 
|  | * http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | 
|  | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | 
|  | * License for the specific language governing permissions and limitations under | 
|  | * the License. | 
|  | */ | 
|  |  | 
|  | #include "Debug.h" | 
|  | #include "JSRunner.h" | 
|  |  | 
|  | #include "nsCOMPtr.h" | 
|  | #include "nsIPrincipal.h" | 
|  | #include "nsIScriptGlobalObject.h" | 
|  | #include "nsIScriptObjectPrincipal.h" | 
|  | #include "nsIURI.h" | 
|  | #include "nsIXPConnect.h" | 
|  | #include "nsStringAPI.h" | 
|  |  | 
|  | // from js_runner_ff.cc in Gears (http://code.google.com/p/gears/) | 
|  |  | 
|  | bool JSRunner::eval(JSContext* ctx, JSObject* object, const std::string& script) { | 
|  | // To eval the script, we need the JSPrincipals to be acquired through | 
|  | // nsIPrincipal.  nsIPrincipal can be queried through the | 
|  | // nsIScriptObjectPrincipal interface on the Script Global Object.  In order | 
|  | // to get the Script Global Object, we need to request the private data | 
|  | // associated with the global JSObject on the current context. | 
|  | nsCOMPtr<nsIScriptGlobalObject> sgo; | 
|  | nsISupports *priv = reinterpret_cast<nsISupports *>(JS_GetPrivate( | 
|  | ctx, | 
|  | object)); | 
|  | nsCOMPtr<nsIXPConnectWrappedNative> wrapped_native = do_QueryInterface(priv); | 
|  |  | 
|  | if (wrapped_native) { | 
|  | // The global object is a XPConnect wrapped native, the native in | 
|  | // the wrapper might be the nsIScriptGlobalObject. | 
|  | sgo = do_QueryWrappedNative(wrapped_native); | 
|  | } else { | 
|  | sgo = do_QueryInterface(priv); | 
|  | } | 
|  |  | 
|  | JSPrincipals *jsprin = nsnull; | 
|  | std::string virtual_filename; | 
|  | nsresult nr; | 
|  |  | 
|  | nsCOMPtr<nsIScriptObjectPrincipal> obj_prin = do_QueryInterface(sgo, &nr); | 
|  | if (NS_FAILED(nr)) { | 
|  | Debug::log(Debug::Error) << "Error getting object principal" << Debug::flush; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | nsIPrincipal *principal = obj_prin->GetPrincipal(); | 
|  | if (!principal) { | 
|  | Debug::log(Debug::Error) << "Error getting principal" << Debug::flush; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Get the script scheme and host from the principal.  This is the URI that | 
|  | // Firefox treats this script as running from. | 
|  |  | 
|  | // If the codebase is null, the script may be running from a chrome context. | 
|  | // In that case, don't construct a virtual filename. | 
|  |  | 
|  | nsCOMPtr<nsIURI> codebase; | 
|  | nr = principal->GetURI(getter_AddRefs(codebase)); | 
|  | if (codebase) { | 
|  | nsCString scheme; | 
|  | nsCString host; | 
|  |  | 
|  | if (NS_FAILED(codebase->GetScheme(scheme)) || | 
|  | NS_FAILED(codebase->GetHostPort(host))) { | 
|  | Debug::log(Debug::Error) << "Error getting codebase" << Debug::flush; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Build a virtual filename that we'll run as.  This is to workaround | 
|  | // http://lxr.mozilla.org/seamonkey/source/dom/src/base/nsJSEnvironment.cpp#500 | 
|  | // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=387477 | 
|  | // The filename is being used as the security origin instead of the principal. | 
|  | // TODO(zork): Remove this section if this bug is resolved. | 
|  | virtual_filename = std::string(scheme.BeginReading()); | 
|  | virtual_filename += "://"; | 
|  | virtual_filename += host.BeginReading(); | 
|  | } | 
|  |  | 
|  | principal->GetJSPrincipals(ctx, &jsprin); | 
|  |  | 
|  | // Set up the JS stack so that our context is on top.  This is needed to | 
|  | // play nicely with plugins that access the context stack, such as Firebug. | 
|  | //  nsCOMPtr<nsIJSContextStack> stack = | 
|  | //      do_GetService("@mozilla.org/js/xpc/ContextStack;1"); | 
|  | //  if (!stack) { return false; } | 
|  | // | 
|  | //  stack->Push(js_engine_context_); | 
|  |  | 
|  | uintN line_number_start = 0; | 
|  | jsval rval; | 
|  | JSBool js_ok = JS_EvaluateScriptForPrincipals(ctx, object, jsprin, | 
|  | script.c_str(), script.length(), virtual_filename.c_str(), | 
|  | line_number_start, &rval); | 
|  |  | 
|  | // Restore the context stack. | 
|  | //  JSContext *cx; | 
|  | //  stack->Pop(&cx); | 
|  |  | 
|  | // Decrements ref count on jsprin (Was added in GetJSPrincipals()). | 
|  | (void) JSPRINCIPALS_DROP(ctx, jsprin); | 
|  | if (!js_ok) { | 
|  | Debug::log(Debug::Error) << "JS execution failed in JSRunner::eval" | 
|  | << Debug::flush; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } |