bug 313956: expand installer .exe contents to make complete mar. r=ted.
[gecko.git] / ipc / testshell / XPCShellEnvironment.cpp
bloba046f15fe9b2ec2d9e07987da13a52b95bf754ee
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 JS_GC_ZEAL
433 static JSBool
434 GCZeal(JSContext *cx,
435 uintN argc,
436 jsval *vp)
438 jsval* argv = JS_ARGV(cx, vp);
440 uint32 zeal;
441 if (!JS_ValueToECMAUint32(cx, argv[0], &zeal))
442 return JS_FALSE;
444 JS_SetGCZeal(cx, PRUint8(zeal));
445 return JS_TRUE;
447 #endif
449 #ifdef DEBUG
451 static JSBool
452 DumpHeap(JSContext *cx,
453 uintN argc,
454 jsval *vp)
456 JSAutoByteString fileName;
457 void* startThing = NULL;
458 uint32 startTraceKind = 0;
459 void *thingToFind = NULL;
460 size_t maxDepth = (size_t)-1;
461 void *thingToIgnore = NULL;
462 FILE *dumpFile;
463 JSBool ok;
465 jsval *argv = JS_ARGV(cx, vp);
466 JS_SET_RVAL(cx, vp, JSVAL_VOID);
468 vp = argv + 0;
469 if (argc > 0 && *vp != JSVAL_NULL && *vp != JSVAL_VOID) {
470 JSString *str;
472 str = JS_ValueToString(cx, *vp);
473 if (!str)
474 return JS_FALSE;
475 *vp = STRING_TO_JSVAL(str);
476 if (!fileName.encode(cx, str))
477 return JS_FALSE;
480 vp = argv + 1;
481 if (argc > 1 && *vp != JSVAL_NULL && *vp != JSVAL_VOID) {
482 if (!JSVAL_IS_TRACEABLE(*vp))
483 goto not_traceable_arg;
484 startThing = JSVAL_TO_TRACEABLE(*vp);
485 startTraceKind = JSVAL_TRACE_KIND(*vp);
488 vp = argv + 2;
489 if (argc > 2 && *vp != JSVAL_NULL && *vp != JSVAL_VOID) {
490 if (!JSVAL_IS_TRACEABLE(*vp))
491 goto not_traceable_arg;
492 thingToFind = JSVAL_TO_TRACEABLE(*vp);
495 vp = argv + 3;
496 if (argc > 3 && *vp != JSVAL_NULL && *vp != JSVAL_VOID) {
497 uint32 depth;
499 if (!JS_ValueToECMAUint32(cx, *vp, &depth))
500 return JS_FALSE;
501 maxDepth = depth;
504 vp = argv + 4;
505 if (argc > 4 && *vp != JSVAL_NULL && *vp != JSVAL_VOID) {
506 if (!JSVAL_IS_TRACEABLE(*vp))
507 goto not_traceable_arg;
508 thingToIgnore = JSVAL_TO_TRACEABLE(*vp);
511 if (!fileName) {
512 dumpFile = stdout;
513 } else {
514 dumpFile = fopen(fileName.ptr(), "w");
515 if (!dumpFile) {
516 fprintf(stderr, "dumpHeap: can't open %s: %s\n",
517 fileName.ptr(), strerror(errno));
518 return JS_FALSE;
522 ok = JS_DumpHeap(cx, dumpFile, startThing, startTraceKind, thingToFind,
523 maxDepth, thingToIgnore);
524 if (dumpFile != stdout)
525 fclose(dumpFile);
526 return ok;
528 not_traceable_arg:
529 fprintf(stderr,
530 "dumpHeap: argument %u is not null or a heap-allocated thing\n",
531 (unsigned)(vp - argv));
532 return JS_FALSE;
535 #endif /* DEBUG */
537 static JSBool
538 Clear(JSContext *cx,
539 uintN argc,
540 jsval *vp)
542 jsval *argv = JS_ARGV(cx, vp);
543 if (argc > 0 && !JSVAL_IS_PRIMITIVE(argv[0])) {
544 JS_ClearScope(cx, JSVAL_TO_OBJECT(argv[0]));
545 } else {
546 JS_ReportError(cx, "'clear' requires an object");
547 return JS_FALSE;
549 JS_SET_RVAL(cx, vp, JSVAL_VOID);
550 return JS_TRUE;
553 JSFunctionSpec gGlobalFunctions[] =
555 {"print", Print, 0,0},
556 {"load", Load, 1,0},
557 {"quit", Quit, 0,0},
558 {"version", Version, 1,0},
559 {"build", BuildDate, 0,0},
560 {"dumpXPC", DumpXPC, 1,0},
561 {"dump", Dump, 1,0},
562 {"gc", GC, 0,0},
563 #ifdef JS_GC_ZEAL
564 {"gczeal", GCZeal, 1,0},
565 #endif
566 {"clear", Clear, 1,0},
567 #ifdef DEBUG
568 {"dumpHeap", DumpHeap, 5,0},
569 #endif
570 #ifdef MOZ_CALLGRIND
571 {"startCallgrind", js_StartCallgrind, 0,0},
572 {"stopCallgrind", js_StopCallgrind, 0,0},
573 {"dumpCallgrind", js_DumpCallgrind, 1,0},
574 #endif
575 {nsnull,nsnull,0,0}
578 typedef enum JSShellErrNum
580 #define MSG_DEF(name, number, count, exception, format) \
581 name = number,
582 #include "jsshell.msg"
583 #undef MSG_DEF
584 JSShellErr_Limit
585 #undef MSGDEF
586 } JSShellErrNum;
588 static void
589 ProcessFile(JSContext *cx,
590 JSObject *obj,
591 const char *filename,
592 FILE *file,
593 JSBool forceTTY)
595 XPCShellEnvironment* env = Environment(cx);
596 XPCShellEnvironment::AutoContextPusher pusher(env);
598 JSScript *script;
599 jsval result;
600 int lineno, startline;
601 JSBool ok, hitEOF;
602 char *bufp, buffer[4096];
603 JSString *str;
605 if (forceTTY) {
606 file = stdin;
608 else
609 #ifdef HAVE_ISATTY
610 if (!isatty(fileno(file)))
611 #endif
614 * It's not interactive - just execute it.
616 * Support the UNIX #! shell hack; gobble the first line if it starts
617 * with '#'. TODO - this isn't quite compatible with sharp variables,
618 * as a legal js program (using sharp variables) might start with '#'.
619 * But that would require multi-character lookahead.
621 int ch = fgetc(file);
622 if (ch == '#') {
623 while((ch = fgetc(file)) != EOF) {
624 if(ch == '\n' || ch == '\r')
625 break;
628 ungetc(ch, file);
630 JSAutoRequest ar(cx);
632 JSAutoEnterCompartment ac;
633 if (!ac.enter(cx, obj)) {
634 NS_ERROR("Failed to enter compartment!");
635 return;
638 JSScript* script =
639 JS_CompileFileHandleForPrincipals(cx, obj, filename, file,
640 env->GetPrincipal());
641 if (script) {
642 if (!env->ShouldCompileOnly())
643 (void)JS_ExecuteScript(cx, obj, script, &result);
644 JS_DestroyScript(cx, script);
647 return;
650 /* It's an interactive filehandle; drop into read-eval-print loop. */
651 lineno = 1;
652 hitEOF = JS_FALSE;
653 do {
654 bufp = buffer;
655 *bufp = '\0';
657 JSAutoRequest ar(cx);
659 JSAutoEnterCompartment ac;
660 if (!ac.enter(cx, obj)) {
661 NS_ERROR("Failed to enter compartment!");
662 return;
666 * Accumulate lines until we get a 'compilable unit' - one that either
667 * generates an error (before running out of source) or that compiles
668 * cleanly. This should be whenever we get a complete statement that
669 * coincides with the end of a line.
671 startline = lineno;
672 do {
673 if (!GetLine(bufp, file, startline == lineno ? "js> " : "")) {
674 hitEOF = JS_TRUE;
675 break;
677 bufp += strlen(bufp);
678 lineno++;
679 } while (!JS_BufferIsCompilableUnit(cx, obj, buffer, strlen(buffer)));
681 /* Clear any pending exception from previous failed compiles. */
682 JS_ClearPendingException(cx);
683 script =
684 JS_CompileScriptForPrincipals(cx, obj, env->GetPrincipal(), buffer,
685 strlen(buffer), "typein", startline);
686 if (script) {
687 JSErrorReporter older;
689 if (!env->ShouldCompileOnly()) {
690 ok = JS_ExecuteScript(cx, obj, script, &result);
691 if (ok && result != JSVAL_VOID) {
692 /* Suppress error reports from JS_ValueToString(). */
693 older = JS_SetErrorReporter(cx, NULL);
694 str = JS_ValueToString(cx, result);
695 JSAutoByteString bytes;
696 if (str)
697 bytes.encode(cx, str);
698 JS_SetErrorReporter(cx, older);
700 if (!!bytes)
701 fprintf(stdout, "%s\n", bytes.ptr());
702 else
703 ok = JS_FALSE;
706 JS_DestroyScript(cx, script);
708 } while (!hitEOF && !env->IsQuitting());
710 fprintf(stdout, "\n");
713 } /* anonymous namespace */
715 NS_INTERFACE_MAP_BEGIN(FullTrustSecMan)
716 NS_INTERFACE_MAP_ENTRY(nsIXPCSecurityManager)
717 NS_INTERFACE_MAP_ENTRY(nsIScriptSecurityManager)
718 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCSecurityManager)
719 NS_INTERFACE_MAP_END
721 NS_IMPL_ADDREF(FullTrustSecMan)
722 NS_IMPL_RELEASE(FullTrustSecMan)
724 NS_IMETHODIMP
725 FullTrustSecMan::CanCreateWrapper(JSContext * aJSContext,
726 const nsIID & aIID,
727 nsISupports *aObj,
728 nsIClassInfo *aClassInfo,
729 void * *aPolicy)
731 return NS_OK;
734 NS_IMETHODIMP
735 FullTrustSecMan::CanCreateInstance(JSContext * aJSContext,
736 const nsCID & aCID)
738 return NS_OK;
741 NS_IMETHODIMP
742 FullTrustSecMan::CanGetService(JSContext * aJSContext,
743 const nsCID & aCID)
745 return NS_OK;
748 NS_IMETHODIMP
749 FullTrustSecMan::CanAccess(PRUint32 aAction,
750 nsAXPCNativeCallContext *aCallContext,
751 JSContext * aJSContext,
752 JSObject * aJSObject,
753 nsISupports *aObj,
754 nsIClassInfo *aClassInfo,
755 jsid aName,
756 void * *aPolicy)
758 return NS_OK;
761 NS_IMETHODIMP
762 FullTrustSecMan::CheckPropertyAccess(JSContext * aJSContext,
763 JSObject * aJSObject,
764 const char *aClassName,
765 jsid aProperty,
766 PRUint32 aAction)
768 return NS_OK;
771 NS_IMETHODIMP
772 FullTrustSecMan::CheckLoadURIFromScript(JSContext * cx,
773 nsIURI *uri)
775 return NS_OK;
778 NS_IMETHODIMP
779 FullTrustSecMan::CheckLoadURIWithPrincipal(nsIPrincipal *aPrincipal,
780 nsIURI *uri,
781 PRUint32 flags)
783 return NS_OK;
786 NS_IMETHODIMP
787 FullTrustSecMan::CheckLoadURI(nsIURI *from,
788 nsIURI *uri,
789 PRUint32 flags)
791 return NS_OK;
794 NS_IMETHODIMP
795 FullTrustSecMan::CheckLoadURIStrWithPrincipal(nsIPrincipal *aPrincipal,
796 const nsACString & uri,
797 PRUint32 flags)
799 return NS_OK;
802 NS_IMETHODIMP
803 FullTrustSecMan::CheckLoadURIStr(const nsACString & from,
804 const nsACString & uri,
805 PRUint32 flags)
807 return NS_OK;
810 NS_IMETHODIMP
811 FullTrustSecMan::CheckFunctionAccess(JSContext * cx,
812 void * funObj,
813 void * targetObj)
815 return NS_OK;
818 NS_IMETHODIMP
819 FullTrustSecMan::CanExecuteScripts(JSContext * cx,
820 nsIPrincipal *principal,
821 PRBool *_retval)
823 *_retval = PR_TRUE;
824 return NS_OK;
827 NS_IMETHODIMP
828 FullTrustSecMan::GetSubjectPrincipal(nsIPrincipal **_retval)
830 NS_IF_ADDREF(*_retval = mSystemPrincipal);
831 return *_retval ? NS_OK : NS_ERROR_FAILURE;
834 NS_IMETHODIMP
835 FullTrustSecMan::GetSystemPrincipal(nsIPrincipal **_retval)
837 NS_IF_ADDREF(*_retval = mSystemPrincipal);
838 return *_retval ? NS_OK : NS_ERROR_FAILURE;
841 NS_IMETHODIMP
842 FullTrustSecMan::GetCertificatePrincipal(const nsACString & aCertFingerprint,
843 const nsACString & aSubjectName,
844 const nsACString & aPrettyName,
845 nsISupports *aCert,
846 nsIURI *aURI,
847 nsIPrincipal **_retval)
849 NS_IF_ADDREF(*_retval = mSystemPrincipal);
850 return *_retval ? NS_OK : NS_ERROR_FAILURE;
853 NS_IMETHODIMP
854 FullTrustSecMan::GetCodebasePrincipal(nsIURI *aURI,
855 nsIPrincipal **_retval)
857 NS_IF_ADDREF(*_retval = mSystemPrincipal);
858 return *_retval ? NS_OK : NS_ERROR_FAILURE;
861 NS_IMETHODIMP
862 FullTrustSecMan::RequestCapability(nsIPrincipal *principal,
863 const char *capability,
864 PRInt16 *_retval)
866 *_retval = nsIPrincipal::ENABLE_GRANTED;
867 return NS_OK;
870 NS_IMETHODIMP
871 FullTrustSecMan::IsCapabilityEnabled(const char *capability,
872 PRBool *_retval)
874 *_retval = PR_TRUE;
875 return NS_OK;
878 NS_IMETHODIMP
879 FullTrustSecMan::EnableCapability(const char *capability)
881 return NS_OK;;
884 NS_IMETHODIMP
885 FullTrustSecMan::RevertCapability(const char *capability)
887 return NS_OK;
890 NS_IMETHODIMP
891 FullTrustSecMan::DisableCapability(const char *capability)
893 return NS_OK;
896 NS_IMETHODIMP
897 FullTrustSecMan::SetCanEnableCapability(const nsACString & certificateFingerprint,
898 const char *capability,
899 PRInt16 canEnable)
901 return NS_OK;
904 NS_IMETHODIMP
905 FullTrustSecMan::GetObjectPrincipal(JSContext * cx,
906 JSObject * obj,
907 nsIPrincipal **_retval)
909 NS_IF_ADDREF(*_retval = mSystemPrincipal);
910 return *_retval ? NS_OK : NS_ERROR_FAILURE;
913 NS_IMETHODIMP
914 FullTrustSecMan::SubjectPrincipalIsSystem(PRBool *_retval)
916 *_retval = PR_TRUE;
917 return NS_OK;
920 NS_IMETHODIMP
921 FullTrustSecMan::CheckSameOrigin(JSContext * aJSContext,
922 nsIURI *aTargetURI)
924 return NS_OK;
927 NS_IMETHODIMP
928 FullTrustSecMan::CheckSameOriginURI(nsIURI *aSourceURI,
929 nsIURI *aTargetURI,
930 PRBool reportError)
932 return NS_OK;
935 NS_IMETHODIMP
936 FullTrustSecMan::GetPrincipalFromContext(JSContext * cx,
937 nsIPrincipal **_retval)
939 NS_IF_ADDREF(*_retval = mSystemPrincipal);
940 return *_retval ? NS_OK : NS_ERROR_FAILURE;
943 NS_IMETHODIMP
944 FullTrustSecMan::GetChannelPrincipal(nsIChannel *aChannel,
945 nsIPrincipal **_retval)
947 NS_IF_ADDREF(*_retval = mSystemPrincipal);
948 return *_retval ? NS_OK : NS_ERROR_FAILURE;
951 NS_IMETHODIMP
952 FullTrustSecMan::IsSystemPrincipal(nsIPrincipal *aPrincipal,
953 PRBool *_retval)
955 *_retval = aPrincipal == mSystemPrincipal;
956 return NS_OK;
959 NS_IMETHODIMP_(nsIPrincipal *)
960 FullTrustSecMan::GetCxSubjectPrincipal(JSContext *cx)
962 return mSystemPrincipal;
965 NS_IMETHODIMP_(nsIPrincipal *)
966 FullTrustSecMan::GetCxSubjectPrincipalAndFrame(JSContext *cx,
967 JSStackFrame **fp)
969 *fp = nsnull;
970 return mSystemPrincipal;
973 NS_IMETHODIMP
974 FullTrustSecMan::PushContextPrincipal(JSContext *cx,
975 JSStackFrame *fp,
976 nsIPrincipal *principal)
978 return NS_OK;
981 NS_IMETHODIMP
982 FullTrustSecMan::PopContextPrincipal(JSContext *cx)
984 return NS_OK;
987 NS_IMETHODIMP_(nsrefcnt)
988 XPCShellDirProvider::AddRef()
990 return 2;
993 NS_IMETHODIMP_(nsrefcnt)
994 XPCShellDirProvider::Release()
996 return 1;
999 NS_IMPL_QUERY_INTERFACE1(XPCShellDirProvider, nsIDirectoryServiceProvider)
1001 PRBool
1002 XPCShellDirProvider::SetGREDir(const char *dir)
1004 nsresult rv = XRE_GetFileFromPath(dir, getter_AddRefs(mGREDir));
1005 return NS_SUCCEEDED(rv);
1008 NS_IMETHODIMP
1009 XPCShellDirProvider::GetFile(const char *prop,
1010 PRBool *persistent,
1011 nsIFile* *result)
1013 if (mGREDir && !strcmp(prop, NS_GRE_DIR)) {
1014 *persistent = PR_TRUE;
1015 NS_ADDREF(*result = mGREDir);
1016 return NS_OK;
1019 return NS_ERROR_FAILURE;
1022 XPCShellEnvironment::
1023 AutoContextPusher::AutoContextPusher(XPCShellEnvironment* aEnv)
1025 NS_ASSERTION(aEnv->mCx, "Null context?!");
1027 if (NS_SUCCEEDED(aEnv->mCxStack->Push(aEnv->mCx))) {
1028 mEnv = aEnv;
1032 XPCShellEnvironment::
1033 AutoContextPusher::~AutoContextPusher()
1035 if (mEnv) {
1036 JSContext* cx;
1037 mEnv->mCxStack->Pop(&cx);
1038 NS_ASSERTION(cx == mEnv->mCx, "Wrong context on the stack!");
1042 // static
1043 XPCShellEnvironment*
1044 XPCShellEnvironment::CreateEnvironment()
1046 XPCShellEnvironment* env = new XPCShellEnvironment();
1047 if (env && !env->Init()) {
1048 delete env;
1049 env = nsnull;
1051 return env;
1054 XPCShellEnvironment::XPCShellEnvironment()
1055 : mCx(NULL),
1056 mJSPrincipals(NULL),
1057 mExitCode(0),
1058 mQuitting(JS_FALSE),
1059 mReportWarnings(JS_TRUE),
1060 mCompileOnly(JS_FALSE)
1064 XPCShellEnvironment::~XPCShellEnvironment()
1066 if (mCx) {
1067 JS_BeginRequest(mCx);
1069 JSObject* global = GetGlobalObject();
1070 if (global) {
1071 JS_ClearScope(mCx, global);
1073 mGlobalHolder.Release();
1075 JS_GC(mCx);
1077 mCxStack = nsnull;
1079 if (mJSPrincipals) {
1080 JSPRINCIPALS_DROP(mCx, mJSPrincipals);
1083 JSRuntime* rt = gOldContextCallback ? JS_GetRuntime(mCx) : NULL;
1085 JS_DestroyContext(mCx);
1087 if (gOldContextCallback) {
1088 NS_ASSERTION(rt, "Should never be null!");
1089 JS_SetContextCallback(rt, gOldContextCallback);
1090 gOldContextCallback = NULL;
1095 bool
1096 XPCShellEnvironment::Init()
1098 nsresult rv;
1100 #ifdef HAVE_SETBUF
1101 // unbuffer stdout so that output is in the correct order; note that stderr
1102 // is unbuffered by default
1103 setbuf(stdout, 0);
1104 #endif
1106 nsCOMPtr<nsIJSRuntimeService> rtsvc =
1107 do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
1108 if (!rtsvc) {
1109 NS_ERROR("failed to get nsJSRuntimeService!");
1110 return false;
1113 JSRuntime *rt;
1114 if (NS_FAILED(rtsvc->GetRuntime(&rt)) || !rt) {
1115 NS_ERROR("failed to get JSRuntime from nsJSRuntimeService!");
1116 return false;
1119 if (!mGlobalHolder.Hold(rt)) {
1120 NS_ERROR("Can't protect global object!");
1121 return false;
1124 gOldContextCallback = JS_SetContextCallback(rt, ContextCallback);
1126 JSContext *cx = JS_NewContext(rt, 8192);
1127 if (!cx) {
1128 NS_ERROR("JS_NewContext failed!");
1130 JS_SetContextCallback(rt, gOldContextCallback);
1131 gOldContextCallback = NULL;
1133 return false;
1135 mCx = cx;
1137 JS_SetContextPrivate(cx, this);
1139 nsCOMPtr<nsIXPConnect> xpc =
1140 do_GetService(nsIXPConnect::GetCID());
1141 if (!xpc) {
1142 NS_ERROR("failed to get nsXPConnect service!");
1143 return false;
1146 xpc_LocalizeContext(cx);
1148 nsRefPtr<FullTrustSecMan> secman(new FullTrustSecMan());
1149 xpc->SetSecurityManagerForJSContext(cx, secman, 0xFFFF);
1151 nsCOMPtr<nsIPrincipal> principal;
1153 nsCOMPtr<nsIScriptSecurityManager> securityManager =
1154 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
1155 if (NS_SUCCEEDED(rv) && securityManager) {
1156 rv = securityManager->GetSystemPrincipal(getter_AddRefs(principal));
1157 if (NS_FAILED(rv)) {
1158 fprintf(stderr, "+++ Failed to obtain SystemPrincipal from ScriptSecurityManager service.\n");
1159 } else {
1160 // fetch the JS principals and stick in a global
1161 rv = principal->GetJSPrincipals(cx, &mJSPrincipals);
1162 if (NS_FAILED(rv)) {
1163 fprintf(stderr, "+++ Failed to obtain JS principals from SystemPrincipal.\n");
1165 secman->SetSystemPrincipal(principal);
1167 } else {
1168 fprintf(stderr, "+++ Failed to get ScriptSecurityManager service, running without principals");
1171 nsCOMPtr<nsIJSContextStack> cxStack =
1172 do_GetService("@mozilla.org/js/xpc/ContextStack;1");
1173 if (!cxStack) {
1174 NS_ERROR("failed to get the nsThreadJSContextStack service!");
1175 return false;
1177 mCxStack = cxStack;
1179 AutoContextPusher pusher(this);
1181 nsCOMPtr<nsIXPCScriptable> backstagePass;
1182 rv = rtsvc->GetBackstagePass(getter_AddRefs(backstagePass));
1183 if (NS_FAILED(rv)) {
1184 NS_ERROR("Failed to get backstage pass from rtsvc!");
1185 return false;
1188 nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
1189 rv = xpc->InitClassesWithNewWrappedGlobal(cx, backstagePass,
1190 NS_GET_IID(nsISupports),
1191 principal,
1192 nsnull,
1193 nsIXPConnect::
1194 FLAG_SYSTEM_GLOBAL_OBJECT,
1195 getter_AddRefs(holder));
1196 if (NS_FAILED(rv)) {
1197 NS_ERROR("InitClassesWithNewWrappedGlobal failed!");
1198 return false;
1201 JSObject *globalObj;
1202 rv = holder->GetJSObject(&globalObj);
1203 if (NS_FAILED(rv)) {
1204 NS_ERROR("Failed to get global JSObject!");
1205 return false;
1210 JSAutoRequest ar(cx);
1212 JSAutoEnterCompartment ac;
1213 if (!ac.enter(cx, globalObj)) {
1214 NS_ERROR("Failed to enter compartment!");
1215 return false;
1218 if (!JS_DefineFunctions(cx, globalObj, gGlobalFunctions) ||
1219 !JS_DefineProfilingFunctions(cx, globalObj)) {
1220 NS_ERROR("JS_DefineFunctions failed!");
1221 return false;
1225 mGlobalHolder = globalObj;
1227 FILE* runtimeScriptFile = fopen(kDefaultRuntimeScriptFilename, "r");
1228 if (runtimeScriptFile) {
1229 fprintf(stdout, "[loading '%s'...]\n", kDefaultRuntimeScriptFilename);
1230 ProcessFile(cx, globalObj, kDefaultRuntimeScriptFilename,
1231 runtimeScriptFile, JS_FALSE);
1232 fclose(runtimeScriptFile);
1235 return true;
1238 bool
1239 XPCShellEnvironment::EvaluateString(const nsString& aString,
1240 nsString* aResult)
1242 XPCShellEnvironment* env = Environment(mCx);
1243 XPCShellEnvironment::AutoContextPusher pusher(env);
1245 JSAutoRequest ar(mCx);
1247 JS_ClearPendingException(mCx);
1249 JSObject* global = GetGlobalObject();
1251 JSAutoEnterCompartment ac;
1252 if (!ac.enter(mCx, global)) {
1253 NS_ERROR("Failed to enter compartment!");
1254 return false;
1257 JSScript* script =
1258 JS_CompileUCScriptForPrincipals(mCx, global, GetPrincipal(),
1259 aString.get(), aString.Length(),
1260 "typein", 0);
1261 if (!script) {
1262 return false;
1265 if (!ShouldCompileOnly()) {
1266 if (aResult) {
1267 aResult->Truncate();
1270 jsval result;
1271 JSBool ok = JS_ExecuteScript(mCx, global, script, &result);
1272 if (ok && result != JSVAL_VOID) {
1273 JSErrorReporter old = JS_SetErrorReporter(mCx, NULL);
1274 JSString* str = JS_ValueToString(mCx, result);
1275 nsDependentJSString depStr;
1276 if (str)
1277 depStr.init(mCx, str);
1278 JS_SetErrorReporter(mCx, old);
1280 if (!depStr.IsEmpty() && aResult) {
1281 aResult->Assign(depStr);
1286 JS_DestroyScript(mCx, script);
1288 return true;