Merge tracemonkey to mozilla-central. (a=blockers)
[mozilla-central.git] / ipc / testshell / XPCShellEnvironment.cpp
blobde0d2c1a4becf198a995dd67c7fed15694cf4879
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is Mozilla IPCShell.
16 * The Initial Developer of the Original Code is
17 * Ben Turner <bent.mozilla@gmail.com>.
18 * Portions created by the Initial Developer are Copyright (C) 2009
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 #include <stdlib.h>
38 #include <errno.h>
39 #ifdef HAVE_IO_H
40 #include <io.h> /* for isatty() */
41 #endif
42 #ifdef HAVE_UNISTD_H
43 #include <unistd.h> /* for isatty() */
44 #endif
46 #include "base/basictypes.h"
48 #include "jsapi.h"
49 #include "jscntxt.h"
50 #include "jsdbgapi.h"
51 #include "jsprf.h"
53 #include "xpcpublic.h"
55 #include "XPCShellEnvironment.h"
57 #include "mozilla/XPCOM.h"
59 #include "nsIChannel.h"
60 #include "nsIClassInfo.h"
61 #include "nsIDirectoryService.h"
62 #include "nsIJSContextStack.h"
63 #include "nsIJSRuntimeService.h"
64 #include "nsIPrincipal.h"
65 #include "nsIScriptSecurityManager.h"
66 #include "nsIURI.h"
67 #include "nsIXPConnect.h"
68 #include "nsIXPCScriptable.h"
70 #include "nsJSUtils.h"
71 #include "nsThreadUtils.h"
72 #include "nsXULAppAPI.h"
74 #include "TestShellChild.h"
75 #include "TestShellParent.h"
77 #define EXITCODE_RUNTIME_ERROR 3
78 #define EXITCODE_FILE_NOT_FOUND 4
80 using mozilla::ipc::XPCShellEnvironment;
81 using mozilla::ipc::TestShellChild;
82 using mozilla::ipc::TestShellParent;
84 namespace {
86 static const char kDefaultRuntimeScriptFilename[] = "xpcshell.js";
88 class FullTrustSecMan : public nsIScriptSecurityManager
90 public:
91 NS_DECL_ISUPPORTS
92 NS_DECL_NSIXPCSECURITYMANAGER
93 NS_DECL_NSISCRIPTSECURITYMANAGER
95 FullTrustSecMan() { }
96 virtual ~FullTrustSecMan() { }
98 void SetSystemPrincipal(nsIPrincipal *aPrincipal) {
99 mSystemPrincipal = aPrincipal;
102 private:
103 nsCOMPtr<nsIPrincipal> mSystemPrincipal;
106 class XPCShellDirProvider : public nsIDirectoryServiceProvider
108 public:
109 NS_DECL_ISUPPORTS
110 NS_DECL_NSIDIRECTORYSERVICEPROVIDER
112 XPCShellDirProvider() { }
113 ~XPCShellDirProvider() { }
115 PRBool SetGREDir(const char *dir);
116 void ClearGREDir() { mGREDir = nsnull; }
118 private:
119 nsCOMPtr<nsILocalFile> mGREDir;
122 inline XPCShellEnvironment*
123 Environment(JSContext* cx)
125 XPCShellEnvironment* env =
126 static_cast<XPCShellEnvironment*>(JS_GetContextPrivate(cx));
127 NS_ASSERTION(env, "Should never be null!");
128 return env;
131 static void
132 ScriptErrorReporter(JSContext *cx,
133 const char *message,
134 JSErrorReport *report)
136 int i, j, k, n;
137 char *prefix = NULL, *tmp;
138 const char *ctmp;
139 JSStackFrame * fp = nsnull;
140 nsCOMPtr<nsIXPConnect> xpc;
142 // Don't report an exception from inner JS frames as the callers may intend
143 // to handle it.
144 while ((fp = JS_FrameIterator(cx, &fp))) {
145 if (JS_IsScriptFrame(cx, fp)) {
146 return;
150 // In some cases cx->fp is null here so use XPConnect to tell us about inner
151 // frames.
152 if ((xpc = do_GetService(nsIXPConnect::GetCID()))) {
153 nsAXPCNativeCallContext *cc = nsnull;
154 xpc->GetCurrentNativeCallContext(&cc);
155 if (cc) {
156 nsAXPCNativeCallContext *prev = cc;
157 while (NS_SUCCEEDED(prev->GetPreviousCallContext(&prev)) && prev) {
158 PRUint16 lang;
159 if (NS_SUCCEEDED(prev->GetLanguage(&lang)) &&
160 lang == nsAXPCNativeCallContext::LANG_JS) {
161 return;
167 if (!report) {
168 fprintf(stderr, "%s\n", message);
169 return;
172 /* Conditionally ignore reported warnings. */
173 if (JSREPORT_IS_WARNING(report->flags) &&
174 !Environment(cx)->ShouldReportWarnings()) {
175 return;
178 if (report->filename)
179 prefix = JS_smprintf("%s:", report->filename);
180 if (report->lineno) {
181 tmp = prefix;
182 prefix = JS_smprintf("%s%u: ", tmp ? tmp : "", report->lineno);
183 JS_free(cx, tmp);
185 if (JSREPORT_IS_WARNING(report->flags)) {
186 tmp = prefix;
187 prefix = JS_smprintf("%s%swarning: ",
188 tmp ? tmp : "",
189 JSREPORT_IS_STRICT(report->flags) ? "strict " : "");
190 JS_free(cx, tmp);
193 /* embedded newlines -- argh! */
194 while ((ctmp = strchr(message, '\n')) != 0) {
195 ctmp++;
196 if (prefix) fputs(prefix, stderr);
197 fwrite(message, 1, ctmp - message, stderr);
198 message = ctmp;
200 /* If there were no filename or lineno, the prefix might be empty */
201 if (prefix)
202 fputs(prefix, stderr);
203 fputs(message, stderr);
205 if (!report->linebuf) {
206 fputc('\n', stderr);
207 goto out;
210 fprintf(stderr, ":\n%s%s\n%s", prefix, report->linebuf, prefix);
211 n = report->tokenptr - report->linebuf;
212 for (i = j = 0; i < n; i++) {
213 if (report->linebuf[i] == '\t') {
214 for (k = (j + 8) & ~7; j < k; j++) {
215 fputc('.', stderr);
217 continue;
219 fputc('.', stderr);
220 j++;
222 fputs("^\n", stderr);
223 out:
224 if (!JSREPORT_IS_WARNING(report->flags)) {
225 Environment(cx)->SetExitCode(EXITCODE_RUNTIME_ERROR);
227 JS_free(cx, prefix);
230 JSContextCallback gOldContextCallback = NULL;
232 static JSBool
233 ContextCallback(JSContext *cx,
234 uintN contextOp)
236 if (gOldContextCallback && !gOldContextCallback(cx, contextOp))
237 return JS_FALSE;
239 if (contextOp == JSCONTEXT_NEW) {
240 JS_SetErrorReporter(cx, ScriptErrorReporter);
241 JS_SetVersion(cx, JSVERSION_LATEST);
243 return JS_TRUE;
246 static JSBool
247 Print(JSContext *cx,
248 uintN argc,
249 jsval *vp)
251 uintN i, n;
252 JSString *str;
254 jsval *argv = JS_ARGV(cx, vp);
255 for (i = n = 0; i < argc; i++) {
256 str = JS_ValueToString(cx, argv[i]);
257 if (!str)
258 return JS_FALSE;
259 JSAutoByteString bytes(cx, str);
260 if (!bytes)
261 return JS_FALSE;
262 fprintf(stdout, "%s%s", i ? " " : "", bytes.ptr());
263 fflush(stdout);
265 n++;
266 if (n)
267 fputc('\n', stdout);
268 JS_SET_RVAL(cx, vp, JSVAL_VOID);
269 return JS_TRUE;
272 static JSBool
273 GetLine(char *bufp,
274 FILE *file,
275 const char *prompt)
277 char line[256];
278 fputs(prompt, stdout);
279 fflush(stdout);
280 if (!fgets(line, sizeof line, file))
281 return JS_FALSE;
282 strcpy(bufp, line);
283 return JS_TRUE;
286 static JSBool
287 Dump(JSContext *cx,
288 uintN argc,
289 jsval *vp)
291 JS_SET_RVAL(cx, vp, JSVAL_VOID);
293 JSString *str;
294 if (!argc)
295 return JS_TRUE;
297 str = JS_ValueToString(cx, JS_ARGV(cx, vp)[0]);
298 if (!str)
299 return JS_FALSE;
300 JS_FileEscapedString(stdout, str, 0);
301 fflush(stdout);
302 return JS_TRUE;
305 static JSBool
306 Load(JSContext *cx,
307 uintN argc,
308 jsval *vp)
310 uintN i;
311 JSString *str;
312 JSScript *script;
313 JSBool ok;
314 jsval result;
315 FILE *file;
317 JSObject *obj = JS_THIS_OBJECT(cx, vp);
318 if (!obj)
319 return JS_FALSE;
321 jsval *argv = JS_ARGV(cx, vp);
322 for (i = 0; i < argc; i++) {
323 str = JS_ValueToString(cx, argv[i]);
324 if (!str)
325 return JS_FALSE;
326 argv[i] = STRING_TO_JSVAL(str);
327 JSAutoByteString filename(cx, str);
328 if (!filename)
329 return JS_FALSE;
330 file = fopen(filename.ptr(), "r");
331 if (!file) {
332 JS_ReportError(cx, "cannot open file '%s' for reading", filename.ptr());
333 return JS_FALSE;
335 script = JS_CompileFileHandleForPrincipals(cx, obj, filename.ptr(), file,
336 Environment(cx)->GetPrincipal());
337 fclose(file);
338 if (!script)
339 return JS_FALSE;
341 ok = !Environment(cx)->ShouldCompileOnly()
342 ? JS_ExecuteScript(cx, obj, script, &result)
343 : JS_TRUE;
344 JS_DestroyScript(cx, script);
345 if (!ok)
346 return JS_FALSE;
348 JS_SET_RVAL(cx, vp, JSVAL_VOID);
349 return JS_TRUE;
352 static JSBool
353 Version(JSContext *cx,
354 uintN argc,
355 jsval *vp)
357 jsval *argv = JS_ARGV(cx, vp);
358 if (argc > 0 && JSVAL_IS_INT(argv[0]))
359 JS_SET_RVAL(cx, vp, INT_TO_JSVAL(JS_SetVersion(cx, JSVersion(JSVAL_TO_INT(argv[0])))));
360 else
361 JS_SET_RVAL(cx, vp, INT_TO_JSVAL(JS_GetVersion(cx)));
362 return JS_TRUE;
365 static JSBool
366 BuildDate(JSContext *cx, uintN argc, jsval *vp)
368 fprintf(stdout, "built on %s at %s\n", __DATE__, __TIME__);
369 return JS_TRUE;
372 static JSBool
373 Quit(JSContext *cx,
374 uintN argc,
375 jsval *vp)
377 int exitCode = 0;
378 JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "/ i", &exitCode);
380 XPCShellEnvironment* env = Environment(cx);
381 env->SetExitCode(exitCode);
382 env->SetIsQuitting();
384 return JS_FALSE;
387 static JSBool
388 DumpXPC(JSContext *cx,
389 uintN argc,
390 jsval *vp)
392 int32 depth = 2;
394 if (argc > 0) {
395 if (!JS_ValueToInt32(cx, JS_ARGV(cx, vp)[0], &depth))
396 return JS_FALSE;
399 nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
400 if(xpc)
401 xpc->DebugDump((int16)depth);
402 JS_SET_RVAL(cx, vp, JSVAL_VOID);
403 return JS_TRUE;
406 static JSBool
407 GC(JSContext *cx,
408 uintN argc,
409 jsval *vp)
411 JSRuntime *rt;
412 uint32 preBytes;
414 rt = cx->runtime;
415 preBytes = rt->gcBytes;
416 JS_GC(cx);
417 fprintf(stdout, "before %lu, after %lu, break %08lx\n",
418 (unsigned long)preBytes, (unsigned long)rt->gcBytes,
419 #ifdef XP_UNIX
420 (unsigned long)sbrk(0)
421 #else
423 #endif
425 #ifdef JS_GCMETER
426 js_DumpGCStats(rt, stdout);
427 #endif
428 JS_SET_RVAL(cx, vp, JSVAL_VOID);
429 return JS_TRUE;
432 #ifdef DEBUG
434 static JSBool
435 DumpHeap(JSContext *cx,
436 uintN argc,
437 jsval *vp)
439 JSAutoByteString fileName;
440 void* startThing = NULL;
441 uint32 startTraceKind = 0;
442 void *thingToFind = NULL;
443 size_t maxDepth = (size_t)-1;
444 void *thingToIgnore = NULL;
445 FILE *dumpFile;
446 JSBool ok;
448 jsval *argv = JS_ARGV(cx, vp);
449 JS_SET_RVAL(cx, vp, JSVAL_VOID);
451 vp = argv + 0;
452 if (argc > 0 && *vp != JSVAL_NULL && *vp != JSVAL_VOID) {
453 JSString *str;
455 str = JS_ValueToString(cx, *vp);
456 if (!str)
457 return JS_FALSE;
458 *vp = STRING_TO_JSVAL(str);
459 if (!fileName.encode(cx, str))
460 return JS_FALSE;
463 vp = argv + 1;
464 if (argc > 1 && *vp != JSVAL_NULL && *vp != JSVAL_VOID) {
465 if (!JSVAL_IS_TRACEABLE(*vp))
466 goto not_traceable_arg;
467 startThing = JSVAL_TO_TRACEABLE(*vp);
468 startTraceKind = JSVAL_TRACE_KIND(*vp);
471 vp = argv + 2;
472 if (argc > 2 && *vp != JSVAL_NULL && *vp != JSVAL_VOID) {
473 if (!JSVAL_IS_TRACEABLE(*vp))
474 goto not_traceable_arg;
475 thingToFind = JSVAL_TO_TRACEABLE(*vp);
478 vp = argv + 3;
479 if (argc > 3 && *vp != JSVAL_NULL && *vp != JSVAL_VOID) {
480 uint32 depth;
482 if (!JS_ValueToECMAUint32(cx, *vp, &depth))
483 return JS_FALSE;
484 maxDepth = depth;
487 vp = argv + 4;
488 if (argc > 4 && *vp != JSVAL_NULL && *vp != JSVAL_VOID) {
489 if (!JSVAL_IS_TRACEABLE(*vp))
490 goto not_traceable_arg;
491 thingToIgnore = JSVAL_TO_TRACEABLE(*vp);
494 if (!fileName) {
495 dumpFile = stdout;
496 } else {
497 dumpFile = fopen(fileName.ptr(), "w");
498 if (!dumpFile) {
499 fprintf(stderr, "dumpHeap: can't open %s: %s\n",
500 fileName.ptr(), strerror(errno));
501 return JS_FALSE;
505 ok = JS_DumpHeap(cx, dumpFile, startThing, startTraceKind, thingToFind,
506 maxDepth, thingToIgnore);
507 if (dumpFile != stdout)
508 fclose(dumpFile);
509 return ok;
511 not_traceable_arg:
512 fprintf(stderr,
513 "dumpHeap: argument %u is not null or a heap-allocated thing\n",
514 (unsigned)(vp - argv));
515 return JS_FALSE;
518 #endif /* DEBUG */
520 static JSBool
521 Clear(JSContext *cx,
522 uintN argc,
523 jsval *vp)
525 jsval *argv = JS_ARGV(cx, vp);
526 if (argc > 0 && !JSVAL_IS_PRIMITIVE(argv[0])) {
527 JS_ClearScope(cx, JSVAL_TO_OBJECT(argv[0]));
528 } else {
529 JS_ReportError(cx, "'clear' requires an object");
530 return JS_FALSE;
532 JS_SET_RVAL(cx, vp, JSVAL_VOID);
533 return JS_TRUE;
536 JSFunctionSpec gGlobalFunctions[] =
538 {"print", Print, 0,0},
539 {"load", Load, 1,0},
540 {"quit", Quit, 0,0},
541 {"version", Version, 1,0},
542 {"build", BuildDate, 0,0},
543 {"dumpXPC", DumpXPC, 1,0},
544 {"dump", Dump, 1,0},
545 {"gc", GC, 0,0},
546 {"clear", Clear, 1,0},
547 #ifdef DEBUG
548 {"dumpHeap", DumpHeap, 5,0},
549 #endif
550 #ifdef MOZ_CALLGRIND
551 {"startCallgrind", js_StartCallgrind, 0,0},
552 {"stopCallgrind", js_StopCallgrind, 0,0},
553 {"dumpCallgrind", js_DumpCallgrind, 1,0},
554 #endif
555 {nsnull,nsnull,0,0}
558 typedef enum JSShellErrNum
560 #define MSG_DEF(name, number, count, exception, format) \
561 name = number,
562 #include "jsshell.msg"
563 #undef MSG_DEF
564 JSShellErr_Limit
565 #undef MSGDEF
566 } JSShellErrNum;
568 static void
569 ProcessFile(JSContext *cx,
570 JSObject *obj,
571 const char *filename,
572 FILE *file,
573 JSBool forceTTY)
575 XPCShellEnvironment* env = Environment(cx);
576 XPCShellEnvironment::AutoContextPusher pusher(env);
578 JSScript *script;
579 jsval result;
580 int lineno, startline;
581 JSBool ok, hitEOF;
582 char *bufp, buffer[4096];
583 JSString *str;
585 if (forceTTY) {
586 file = stdin;
588 else
589 #ifdef HAVE_ISATTY
590 if (!isatty(fileno(file)))
591 #endif
594 * It's not interactive - just execute it.
596 * Support the UNIX #! shell hack; gobble the first line if it starts
597 * with '#'. TODO - this isn't quite compatible with sharp variables,
598 * as a legal js program (using sharp variables) might start with '#'.
599 * But that would require multi-character lookahead.
601 int ch = fgetc(file);
602 if (ch == '#') {
603 while((ch = fgetc(file)) != EOF) {
604 if(ch == '\n' || ch == '\r')
605 break;
608 ungetc(ch, file);
610 JSAutoRequest ar(cx);
612 JSAutoEnterCompartment ac;
613 if (!ac.enter(cx, obj)) {
614 NS_ERROR("Failed to enter compartment!");
615 return;
618 JSScript* script =
619 JS_CompileFileHandleForPrincipals(cx, obj, filename, file,
620 env->GetPrincipal());
621 if (script) {
622 if (!env->ShouldCompileOnly())
623 (void)JS_ExecuteScript(cx, obj, script, &result);
624 JS_DestroyScript(cx, script);
627 return;
630 /* It's an interactive filehandle; drop into read-eval-print loop. */
631 lineno = 1;
632 hitEOF = JS_FALSE;
633 do {
634 bufp = buffer;
635 *bufp = '\0';
637 JSAutoRequest ar(cx);
639 JSAutoEnterCompartment ac;
640 if (!ac.enter(cx, obj)) {
641 NS_ERROR("Failed to enter compartment!");
642 return;
646 * Accumulate lines until we get a 'compilable unit' - one that either
647 * generates an error (before running out of source) or that compiles
648 * cleanly. This should be whenever we get a complete statement that
649 * coincides with the end of a line.
651 startline = lineno;
652 do {
653 if (!GetLine(bufp, file, startline == lineno ? "js> " : "")) {
654 hitEOF = JS_TRUE;
655 break;
657 bufp += strlen(bufp);
658 lineno++;
659 } while (!JS_BufferIsCompilableUnit(cx, obj, buffer, strlen(buffer)));
661 /* Clear any pending exception from previous failed compiles. */
662 JS_ClearPendingException(cx);
663 script =
664 JS_CompileScriptForPrincipals(cx, obj, env->GetPrincipal(), buffer,
665 strlen(buffer), "typein", startline);
666 if (script) {
667 JSErrorReporter older;
669 if (!env->ShouldCompileOnly()) {
670 ok = JS_ExecuteScript(cx, obj, script, &result);
671 if (ok && result != JSVAL_VOID) {
672 /* Suppress error reports from JS_ValueToString(). */
673 older = JS_SetErrorReporter(cx, NULL);
674 str = JS_ValueToString(cx, result);
675 JSAutoByteString bytes;
676 if (str)
677 bytes.encode(cx, str);
678 JS_SetErrorReporter(cx, older);
680 if (!!bytes)
681 fprintf(stdout, "%s\n", bytes.ptr());
682 else
683 ok = JS_FALSE;
686 JS_DestroyScript(cx, script);
688 } while (!hitEOF && !env->IsQuitting());
690 fprintf(stdout, "\n");
693 } /* anonymous namespace */
695 NS_INTERFACE_MAP_BEGIN(FullTrustSecMan)
696 NS_INTERFACE_MAP_ENTRY(nsIXPCSecurityManager)
697 NS_INTERFACE_MAP_ENTRY(nsIScriptSecurityManager)
698 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCSecurityManager)
699 NS_INTERFACE_MAP_END
701 NS_IMPL_ADDREF(FullTrustSecMan)
702 NS_IMPL_RELEASE(FullTrustSecMan)
704 NS_IMETHODIMP
705 FullTrustSecMan::CanCreateWrapper(JSContext * aJSContext,
706 const nsIID & aIID,
707 nsISupports *aObj,
708 nsIClassInfo *aClassInfo,
709 void * *aPolicy)
711 return NS_OK;
714 NS_IMETHODIMP
715 FullTrustSecMan::CanCreateInstance(JSContext * aJSContext,
716 const nsCID & aCID)
718 return NS_OK;
721 NS_IMETHODIMP
722 FullTrustSecMan::CanGetService(JSContext * aJSContext,
723 const nsCID & aCID)
725 return NS_OK;
728 NS_IMETHODIMP
729 FullTrustSecMan::CanAccess(PRUint32 aAction,
730 nsAXPCNativeCallContext *aCallContext,
731 JSContext * aJSContext,
732 JSObject * aJSObject,
733 nsISupports *aObj,
734 nsIClassInfo *aClassInfo,
735 jsid aName,
736 void * *aPolicy)
738 return NS_OK;
741 NS_IMETHODIMP
742 FullTrustSecMan::CheckPropertyAccess(JSContext * aJSContext,
743 JSObject * aJSObject,
744 const char *aClassName,
745 jsid aProperty,
746 PRUint32 aAction)
748 return NS_OK;
751 NS_IMETHODIMP
752 FullTrustSecMan::CheckLoadURIFromScript(JSContext * cx,
753 nsIURI *uri)
755 return NS_OK;
758 NS_IMETHODIMP
759 FullTrustSecMan::CheckLoadURIWithPrincipal(nsIPrincipal *aPrincipal,
760 nsIURI *uri,
761 PRUint32 flags)
763 return NS_OK;
766 NS_IMETHODIMP
767 FullTrustSecMan::CheckLoadURI(nsIURI *from,
768 nsIURI *uri,
769 PRUint32 flags)
771 return NS_OK;
774 NS_IMETHODIMP
775 FullTrustSecMan::CheckLoadURIStrWithPrincipal(nsIPrincipal *aPrincipal,
776 const nsACString & uri,
777 PRUint32 flags)
779 return NS_OK;
782 NS_IMETHODIMP
783 FullTrustSecMan::CheckLoadURIStr(const nsACString & from,
784 const nsACString & uri,
785 PRUint32 flags)
787 return NS_OK;
790 NS_IMETHODIMP
791 FullTrustSecMan::CheckFunctionAccess(JSContext * cx,
792 void * funObj,
793 void * targetObj)
795 return NS_OK;
798 NS_IMETHODIMP
799 FullTrustSecMan::CanExecuteScripts(JSContext * cx,
800 nsIPrincipal *principal,
801 PRBool *_retval)
803 *_retval = PR_TRUE;
804 return NS_OK;
807 NS_IMETHODIMP
808 FullTrustSecMan::GetSubjectPrincipal(nsIPrincipal **_retval)
810 NS_IF_ADDREF(*_retval = mSystemPrincipal);
811 return *_retval ? NS_OK : NS_ERROR_FAILURE;
814 NS_IMETHODIMP
815 FullTrustSecMan::GetSystemPrincipal(nsIPrincipal **_retval)
817 NS_IF_ADDREF(*_retval = mSystemPrincipal);
818 return *_retval ? NS_OK : NS_ERROR_FAILURE;
821 NS_IMETHODIMP
822 FullTrustSecMan::GetCertificatePrincipal(const nsACString & aCertFingerprint,
823 const nsACString & aSubjectName,
824 const nsACString & aPrettyName,
825 nsISupports *aCert,
826 nsIURI *aURI,
827 nsIPrincipal **_retval)
829 NS_IF_ADDREF(*_retval = mSystemPrincipal);
830 return *_retval ? NS_OK : NS_ERROR_FAILURE;
833 NS_IMETHODIMP
834 FullTrustSecMan::GetCodebasePrincipal(nsIURI *aURI,
835 nsIPrincipal **_retval)
837 NS_IF_ADDREF(*_retval = mSystemPrincipal);
838 return *_retval ? NS_OK : NS_ERROR_FAILURE;
841 NS_IMETHODIMP
842 FullTrustSecMan::RequestCapability(nsIPrincipal *principal,
843 const char *capability,
844 PRInt16 *_retval)
846 *_retval = nsIPrincipal::ENABLE_GRANTED;
847 return NS_OK;
850 NS_IMETHODIMP
851 FullTrustSecMan::IsCapabilityEnabled(const char *capability,
852 PRBool *_retval)
854 *_retval = PR_TRUE;
855 return NS_OK;
858 NS_IMETHODIMP
859 FullTrustSecMan::EnableCapability(const char *capability)
861 return NS_OK;;
864 NS_IMETHODIMP
865 FullTrustSecMan::RevertCapability(const char *capability)
867 return NS_OK;
870 NS_IMETHODIMP
871 FullTrustSecMan::DisableCapability(const char *capability)
873 return NS_OK;
876 NS_IMETHODIMP
877 FullTrustSecMan::SetCanEnableCapability(const nsACString & certificateFingerprint,
878 const char *capability,
879 PRInt16 canEnable)
881 return NS_OK;
884 NS_IMETHODIMP
885 FullTrustSecMan::GetObjectPrincipal(JSContext * cx,
886 JSObject * obj,
887 nsIPrincipal **_retval)
889 NS_IF_ADDREF(*_retval = mSystemPrincipal);
890 return *_retval ? NS_OK : NS_ERROR_FAILURE;
893 NS_IMETHODIMP
894 FullTrustSecMan::SubjectPrincipalIsSystem(PRBool *_retval)
896 *_retval = PR_TRUE;
897 return NS_OK;
900 NS_IMETHODIMP
901 FullTrustSecMan::CheckSameOrigin(JSContext * aJSContext,
902 nsIURI *aTargetURI)
904 return NS_OK;
907 NS_IMETHODIMP
908 FullTrustSecMan::CheckSameOriginURI(nsIURI *aSourceURI,
909 nsIURI *aTargetURI,
910 PRBool reportError)
912 return NS_OK;
915 NS_IMETHODIMP
916 FullTrustSecMan::GetPrincipalFromContext(JSContext * cx,
917 nsIPrincipal **_retval)
919 NS_IF_ADDREF(*_retval = mSystemPrincipal);
920 return *_retval ? NS_OK : NS_ERROR_FAILURE;
923 NS_IMETHODIMP
924 FullTrustSecMan::GetChannelPrincipal(nsIChannel *aChannel,
925 nsIPrincipal **_retval)
927 NS_IF_ADDREF(*_retval = mSystemPrincipal);
928 return *_retval ? NS_OK : NS_ERROR_FAILURE;
931 NS_IMETHODIMP
932 FullTrustSecMan::IsSystemPrincipal(nsIPrincipal *aPrincipal,
933 PRBool *_retval)
935 *_retval = aPrincipal == mSystemPrincipal;
936 return NS_OK;
939 NS_IMETHODIMP_(nsIPrincipal *)
940 FullTrustSecMan::GetCxSubjectPrincipal(JSContext *cx)
942 return mSystemPrincipal;
945 NS_IMETHODIMP_(nsIPrincipal *)
946 FullTrustSecMan::GetCxSubjectPrincipalAndFrame(JSContext *cx,
947 JSStackFrame **fp)
949 *fp = nsnull;
950 return mSystemPrincipal;
953 NS_IMETHODIMP
954 FullTrustSecMan::PushContextPrincipal(JSContext *cx,
955 JSStackFrame *fp,
956 nsIPrincipal *principal)
958 return NS_OK;
961 NS_IMETHODIMP
962 FullTrustSecMan::PopContextPrincipal(JSContext *cx)
964 return NS_OK;
967 NS_IMETHODIMP_(nsrefcnt)
968 XPCShellDirProvider::AddRef()
970 return 2;
973 NS_IMETHODIMP_(nsrefcnt)
974 XPCShellDirProvider::Release()
976 return 1;
979 NS_IMPL_QUERY_INTERFACE1(XPCShellDirProvider, nsIDirectoryServiceProvider)
981 PRBool
982 XPCShellDirProvider::SetGREDir(const char *dir)
984 nsresult rv = XRE_GetFileFromPath(dir, getter_AddRefs(mGREDir));
985 return NS_SUCCEEDED(rv);
988 NS_IMETHODIMP
989 XPCShellDirProvider::GetFile(const char *prop,
990 PRBool *persistent,
991 nsIFile* *result)
993 if (mGREDir && !strcmp(prop, NS_GRE_DIR)) {
994 *persistent = PR_TRUE;
995 NS_ADDREF(*result = mGREDir);
996 return NS_OK;
999 return NS_ERROR_FAILURE;
1002 XPCShellEnvironment::
1003 AutoContextPusher::AutoContextPusher(XPCShellEnvironment* aEnv)
1005 NS_ASSERTION(aEnv->mCx, "Null context?!");
1007 if (NS_SUCCEEDED(aEnv->mCxStack->Push(aEnv->mCx))) {
1008 mEnv = aEnv;
1012 XPCShellEnvironment::
1013 AutoContextPusher::~AutoContextPusher()
1015 if (mEnv) {
1016 JSContext* cx;
1017 mEnv->mCxStack->Pop(&cx);
1018 NS_ASSERTION(cx == mEnv->mCx, "Wrong context on the stack!");
1022 // static
1023 XPCShellEnvironment*
1024 XPCShellEnvironment::CreateEnvironment()
1026 XPCShellEnvironment* env = new XPCShellEnvironment();
1027 if (env && !env->Init()) {
1028 delete env;
1029 env = nsnull;
1031 return env;
1034 XPCShellEnvironment::XPCShellEnvironment()
1035 : mCx(NULL),
1036 mJSPrincipals(NULL),
1037 mExitCode(0),
1038 mQuitting(JS_FALSE),
1039 mReportWarnings(JS_TRUE),
1040 mCompileOnly(JS_FALSE)
1044 XPCShellEnvironment::~XPCShellEnvironment()
1046 if (mCx) {
1047 JS_BeginRequest(mCx);
1049 JSObject* global = GetGlobalObject();
1050 if (global) {
1051 JS_ClearScope(mCx, global);
1053 mGlobalHolder.Release();
1055 JS_GC(mCx);
1057 mCxStack = nsnull;
1059 if (mJSPrincipals) {
1060 JSPRINCIPALS_DROP(mCx, mJSPrincipals);
1063 JSRuntime* rt = gOldContextCallback ? JS_GetRuntime(mCx) : NULL;
1065 JS_DestroyContext(mCx);
1067 if (gOldContextCallback) {
1068 NS_ASSERTION(rt, "Should never be null!");
1069 JS_SetContextCallback(rt, gOldContextCallback);
1070 gOldContextCallback = NULL;
1075 bool
1076 XPCShellEnvironment::Init()
1078 nsresult rv;
1080 #ifdef HAVE_SETBUF
1081 // unbuffer stdout so that output is in the correct order; note that stderr
1082 // is unbuffered by default
1083 setbuf(stdout, 0);
1084 #endif
1086 nsCOMPtr<nsIJSRuntimeService> rtsvc =
1087 do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
1088 if (!rtsvc) {
1089 NS_ERROR("failed to get nsJSRuntimeService!");
1090 return false;
1093 JSRuntime *rt;
1094 if (NS_FAILED(rtsvc->GetRuntime(&rt)) || !rt) {
1095 NS_ERROR("failed to get JSRuntime from nsJSRuntimeService!");
1096 return false;
1099 if (!mGlobalHolder.Hold(rt)) {
1100 NS_ERROR("Can't protect global object!");
1101 return false;
1104 gOldContextCallback = JS_SetContextCallback(rt, ContextCallback);
1106 JSContext *cx = JS_NewContext(rt, 8192);
1107 if (!cx) {
1108 NS_ERROR("JS_NewContext failed!");
1110 JS_SetContextCallback(rt, gOldContextCallback);
1111 gOldContextCallback = NULL;
1113 return false;
1115 mCx = cx;
1117 JS_SetContextPrivate(cx, this);
1119 nsCOMPtr<nsIXPConnect> xpc =
1120 do_GetService(nsIXPConnect::GetCID());
1121 if (!xpc) {
1122 NS_ERROR("failed to get nsXPConnect service!");
1123 return false;
1126 xpc_LocalizeContext(cx);
1128 nsRefPtr<FullTrustSecMan> secman(new FullTrustSecMan());
1129 xpc->SetSecurityManagerForJSContext(cx, secman, 0xFFFF);
1131 nsCOMPtr<nsIPrincipal> principal;
1133 nsCOMPtr<nsIScriptSecurityManager> securityManager =
1134 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
1135 if (NS_SUCCEEDED(rv) && securityManager) {
1136 rv = securityManager->GetSystemPrincipal(getter_AddRefs(principal));
1137 if (NS_FAILED(rv)) {
1138 fprintf(stderr, "+++ Failed to obtain SystemPrincipal from ScriptSecurityManager service.\n");
1139 } else {
1140 // fetch the JS principals and stick in a global
1141 rv = principal->GetJSPrincipals(cx, &mJSPrincipals);
1142 if (NS_FAILED(rv)) {
1143 fprintf(stderr, "+++ Failed to obtain JS principals from SystemPrincipal.\n");
1145 secman->SetSystemPrincipal(principal);
1147 } else {
1148 fprintf(stderr, "+++ Failed to get ScriptSecurityManager service, running without principals");
1151 nsCOMPtr<nsIJSContextStack> cxStack =
1152 do_GetService("@mozilla.org/js/xpc/ContextStack;1");
1153 if (!cxStack) {
1154 NS_ERROR("failed to get the nsThreadJSContextStack service!");
1155 return false;
1157 mCxStack = cxStack;
1159 AutoContextPusher pusher(this);
1161 nsCOMPtr<nsIXPCScriptable> backstagePass;
1162 rv = rtsvc->GetBackstagePass(getter_AddRefs(backstagePass));
1163 if (NS_FAILED(rv)) {
1164 NS_ERROR("Failed to get backstage pass from rtsvc!");
1165 return false;
1168 nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
1169 rv = xpc->InitClassesWithNewWrappedGlobal(cx, backstagePass,
1170 NS_GET_IID(nsISupports),
1171 principal,
1172 nsnull,
1173 nsIXPConnect::
1174 FLAG_SYSTEM_GLOBAL_OBJECT,
1175 getter_AddRefs(holder));
1176 if (NS_FAILED(rv)) {
1177 NS_ERROR("InitClassesWithNewWrappedGlobal failed!");
1178 return false;
1181 JSObject *globalObj;
1182 rv = holder->GetJSObject(&globalObj);
1183 if (NS_FAILED(rv)) {
1184 NS_ERROR("Failed to get global JSObject!");
1185 return false;
1190 JSAutoRequest ar(cx);
1192 JSAutoEnterCompartment ac;
1193 if (!ac.enter(cx, globalObj)) {
1194 NS_ERROR("Failed to enter compartment!");
1195 return false;
1198 if (!JS_DefineFunctions(cx, globalObj, gGlobalFunctions) ||
1199 !JS_DefineProfilingFunctions(cx, globalObj)) {
1200 NS_ERROR("JS_DefineFunctions failed!");
1201 return false;
1205 mGlobalHolder = globalObj;
1207 FILE* runtimeScriptFile = fopen(kDefaultRuntimeScriptFilename, "r");
1208 if (runtimeScriptFile) {
1209 fprintf(stdout, "[loading '%s'...]\n", kDefaultRuntimeScriptFilename);
1210 ProcessFile(cx, globalObj, kDefaultRuntimeScriptFilename,
1211 runtimeScriptFile, JS_FALSE);
1212 fclose(runtimeScriptFile);
1215 return true;
1218 bool
1219 XPCShellEnvironment::EvaluateString(const nsString& aString,
1220 nsString* aResult)
1222 XPCShellEnvironment* env = Environment(mCx);
1223 XPCShellEnvironment::AutoContextPusher pusher(env);
1225 JSAutoRequest ar(mCx);
1227 JS_ClearPendingException(mCx);
1229 JSObject* global = GetGlobalObject();
1231 JSAutoEnterCompartment ac;
1232 if (!ac.enter(mCx, global)) {
1233 NS_ERROR("Failed to enter compartment!");
1234 return false;
1237 JSScript* script =
1238 JS_CompileUCScriptForPrincipals(mCx, global, GetPrincipal(),
1239 aString.get(), aString.Length(),
1240 "typein", 0);
1241 if (!script) {
1242 return false;
1245 if (!ShouldCompileOnly()) {
1246 if (aResult) {
1247 aResult->Truncate();
1250 jsval result;
1251 JSBool ok = JS_ExecuteScript(mCx, global, script, &result);
1252 if (ok && result != JSVAL_VOID) {
1253 JSErrorReporter old = JS_SetErrorReporter(mCx, NULL);
1254 JSString* str = JS_ValueToString(mCx, result);
1255 nsDependentJSString depStr;
1256 if (str)
1257 depStr.init(mCx, str);
1258 JS_SetErrorReporter(mCx, old);
1260 if (!depStr.IsEmpty() && aResult) {
1261 aResult->Assign(depStr);
1266 JS_DestroyScript(mCx, script);
1268 return true;