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