Improve logging in jssh, allow loading of remote scripts, fix leak. Bug
authorbzbarsky@mit.edu
Mon, 23 Jul 2007 21:07:57 -0700
changeset 3823 ee8927c596ade21a5bcedba25a55a9d42bcb8189
parent 3822 cc97475054b04a020c7d10115bc4f1606a5173f8
child 3824 e7016a309584aae3f021ee207f297b0ddc154d74
push idunknown
push userunknown
push dateunknown
bugs369816
milestone1.9a7pre
Improve logging in jssh, allow loading of remote scripts, fix leak. Bug 369816, patch by Chris Shoemaker <chris.shoemaker@cox.net>, r=afri, sr=bzbarsky
extensions/jssh/nsJSSh.cpp
extensions/jssh/nsJSSh.h
extensions/jssh/nsJSShServer.cpp
--- a/extensions/jssh/nsJSSh.cpp
+++ b/extensions/jssh/nsJSSh.cpp
@@ -44,16 +44,21 @@
 #include "nsIScriptSecurityManager.h"
 #include "nsIIOService.h"
 #include "nsNetCID.h"
 #include "nsIChannel.h"
 #include "nsThreadUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsXPCOMCIDInternal.h"
 #include "nsMemory.h"
+#include "nsAutoPtr.h"
+
+#ifdef PR_LOGGING
+PRLogModuleInfo *gJSShLog = PR_NewLogModule("jssh");
+#endif
 
 //**********************************************************************
 // Javascript Environment
 
 const char *gWelcome = "Welcome to the Mozilla JavaScript Shell!\n";
 const char *gGoodbye = "Goodbye!\n";
 
 // GetJSShGlobal: helper for native js functions to obtain the global
@@ -208,19 +213,17 @@ Suspend(JSContext *cx, JSObject *obj, ui
   nsJSSh* shell;
   if (!GetJSShGlobal(cx, obj, &shell)) return JS_FALSE;
 
   nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
 
   PR_AtomicIncrement(&shell->mSuspendCount);
   
   while (shell->mSuspendCount) {
-#ifdef DEBUG
-    printf("|");
-#endif
+    LOG(("|"));
     NS_ProcessNextEvent(thread);
   }
            
   return JS_TRUE;
 }
 
 JS_STATIC_DLL_CALLBACK(JSBool)
 Resume(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
@@ -243,17 +246,17 @@ AddressOf(JSContext *cx, JSObject *obj, 
   // instead.
   
   JSObject *arg_obj;
   if (!JS_ValueToObject(cx, argv[0], &arg_obj)) {
     return JS_FALSE;
   }
   
   char buf[80];
-  sprintf(buf,"%p",arg_obj);
+  sprintf(buf, "%p", arg_obj);
   JSString *str = JS_NewStringCopyZ(cx, buf);
   *rval = STRING_TO_JSVAL(str);
   return JS_TRUE;
 }
 
 JS_STATIC_DLL_CALLBACK(JSBool)
 SetProtocol(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
@@ -424,19 +427,17 @@ nsJSSh::nsJSSh(nsIInputStream* input,
     mInput(input), mOutput(output), mQuit(PR_FALSE), mStartupURI(startupURI),
     mSuspendCount(0), mPrompt("\n> "),
     mEmitHeader(PR_FALSE), mProtocol("interactive")
 {
 }
 
 nsJSSh::~nsJSSh()
 {
-#ifdef DEBUG
-  printf("JSSh: ~connection!\n");
-#endif  
+  LOG(("JSSh: ~connection!\n"));
 }
 
 already_AddRefed<nsIRunnable>
 CreateJSSh(nsIInputStream* input, nsIOutputStream*output,
            const nsACString &startupURI)
 {
   nsIRunnable* obj = new nsJSSh(input, output, startupURI);
   NS_IF_ADDREF(obj);
@@ -469,19 +470,17 @@ NS_IMETHODIMP nsJSSh::Run()
     NS_ASSERTION(pom, "uh-oh, no proxy object manager!");
     pom->GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
                            NS_GET_IID(nsIJSSh),
                            (nsIJSSh*)this,
                            NS_PROXY_SYNC,
                            getter_AddRefs(proxied_shell));
   }
   else {
-#ifdef DEBUG
-    printf("jssh shell will block main thread!\n");
-#endif
+    LOG(("jssh shell will block main thread!\n"));
     proxied_shell = this;
   }
   proxied_shell->Init();
 
   if (mInput) {
     // read-eval-print loop
     PRUint32 bytesWritten;
     if (mOutput && !mProtocol.Equals(NS_LITERAL_CSTRING("plain")))
@@ -668,18 +667,22 @@ NS_IMETHODIMP nsJSSh::ExecuteBuffer()
 
   if (script) {
     jsval result;
     if (JS_ExecuteScript(mJSContext, mContextObj, script, &result) && result!=JSVAL_VOID && mOutput) {
       // XXX for some wrapped native objects the following code will crash; probably because the
       // native object is getting released before we reach this:
        JSString *str = JS_ValueToString(mJSContext, result);
        if (str) {
+         nsDependentString chars(reinterpret_cast<const PRUnichar*>
+                                 (JS_GetStringChars(str)),
+                                 JS_GetStringLength(str));
+         NS_ConvertUTF16toUTF8 cstr(chars);
          PRUint32 bytesWritten;
-         mOutput->Write(JS_GetStringBytes(str), JS_GetStringLength(str), &bytesWritten);
+         mOutput->Write(cstr.get(), cstr.Length(), &bytesWritten);
        }
     }
     JS_DestroyScript(mJSContext, script);
   }
 
   JSContext *oldcx;
   mContextStack->Pop(&oldcx);
   NS_ASSERTION(oldcx == mJSContext, "JS thread context push/pop mismatch");
@@ -756,55 +759,55 @@ PRBool nsJSSh::LoadURL(const char *url, 
   
   nsCOMPtr<nsIInputStream> instream;
   channel->Open(getter_AddRefs(instream));
   if (!instream) {
     NS_ERROR("could not open stream");
     return PR_FALSE;
   }
 
-  PRInt32 content_length=-1;
-  if (NS_FAILED(channel->GetContentLength(&content_length))) {
-    NS_ERROR("could not get content length");
-    return PR_FALSE;
-  }
-  
-  char *buf = new char[content_length+1];
+  nsCString buffer;
+  nsAutoArrayPtr<char> buf(new char[1024]);
   if (!buf) {
     NS_ERROR("could not alloc buffer");
     return PR_FALSE;
   }
 
-  PRUint32 bytesRead=0;
-  instream->Read(buf, content_length, &bytesRead);
-  if (bytesRead!=content_length) {
-    NS_ERROR("stream read error");
-    return PR_FALSE;
-  }
+  PRUint32 bytesRead = 0;
+
+  do {
+    if (NS_FAILED(instream->Read(buf, 1024, &bytesRead))) {
+      NS_ERROR("stream read error");
+      return PR_FALSE;
+    }
+    buffer.Append(buf, bytesRead);
+    LOG(("appended %d bytes:\n%s", bytesRead, buffer.get()));
+  } while (bytesRead > 0);
+
+  LOG(("loaded %d bytes:\n%s", buffer.Length(), buffer.get()));
 
   JS_BeginRequest(mJSContext);
   JSPrincipals *jsprincipals;
   mPrincipal->GetJSPrincipals(mJSContext, &jsprincipals);
 
   if(NS_FAILED(mContextStack->Push(mJSContext))) {
     NS_ERROR("failed to push the current JSContext on the nsThreadJSContextStack");
     return NS_ERROR_FAILURE;
   }
 
   jsval result;
   JSBool ok = JS_EvaluateScriptForPrincipals(mJSContext, mContextObj,
-                                             jsprincipals, buf, content_length,
+                                             jsprincipals, buffer.get(),
+                                             buffer.Length(),
                                              url, 1, &result);
   JSPRINCIPALS_DROP(mJSContext, jsprincipals);
 
   JSContext *oldcx;
   mContextStack->Pop(&oldcx);
   NS_ASSERTION(oldcx == mJSContext, "JS thread context push/pop mismatch");
 
   if (ok && retval) *retval=result;
   
   JS_EndRequest(mJSContext);
 
-  delete[] buf;
-  
   return ok;
 }
   
--- a/extensions/jssh/nsJSSh.h
+++ b/extensions/jssh/nsJSSh.h
@@ -46,16 +46,29 @@
 #include "nsIOutputStream.h"
 #include "nsIJSSh.h"
 #include "nsIJSContextStack.h"
 #include "nsIPrincipal.h"
 #include "nsStringAPI.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIXPCScriptable.h"
 
+#ifdef MOZ_LOGGING
+#define FORCE_PR_LOG
+#endif
+#include "prlog.h"
+
+// NSPR_LOG_MODULES=jssh
+#ifdef PR_LOGGING
+extern PRLogModuleInfo *gJSShLog;
+#define LOG(args) PR_LOG(gJSShLog, PR_LOG_DEBUG, args)
+#else
+#define LOG(args)
+#endif
+
 class nsJSSh : public nsIRunnable, public nsIJSSh,
                public nsIScriptObjectPrincipal,
                public nsIXPCScriptable
 {
 public:
   nsJSSh(nsIInputStream* input, nsIOutputStream*output,
          const nsACString &startupURI);
   ~nsJSSh();
--- a/extensions/jssh/nsJSShServer.cpp
+++ b/extensions/jssh/nsJSShServer.cpp
@@ -98,51 +98,43 @@ NS_INTERFACE_MAP_END
 /* void onSocketAccepted (in nsIServerSocket aServ, in nsISocketTransport aTransport); */
 NS_IMETHODIMP ConnectionListener::OnSocketAccepted(nsIServerSocket *aServ, nsISocketTransport *aTransport)
 {
   nsCOMPtr<nsIInputStream> input;
   nsCOMPtr<nsIOutputStream> output;
   aTransport->OpenInputStream(nsITransport::OPEN_BLOCKING, 0, 0, getter_AddRefs(input));
   aTransport->OpenOutputStream(nsITransport::OPEN_BLOCKING, 0, 0, getter_AddRefs(output));
   
-#ifdef DEBUG
-  printf("JSSh server: new connection!\n");
-#endif
+  LOG(("JSSh server: new connection!\n"));
 
   nsCOMPtr<nsIRunnable> shell = CreateJSSh(input, output, mStartupURI);
 
   nsCOMPtr<nsIThread> thread;
   NS_NewThread(getter_AddRefs(thread), shell);
   return NS_OK;
 }
 
 /* void onStopListening (in nsIServerSocket aServ, in nsresult aStatus); */
 NS_IMETHODIMP ConnectionListener::OnStopListening(nsIServerSocket *aServ, nsresult aStatus)
 {
-#ifdef DEBUG
-  printf("JSSh server: stopped listening!\n");
-#endif
+  LOG(("JSSh server: stopped listening!\n"));
   return NS_OK;
 }
 
 //**********************************************************************
 // nsJSShServer implementation
 
 nsJSShServer::nsJSShServer()
 {
-#ifdef DEBUG
-  printf("nsJSShServer ctor\n");
-#endif
+  LOG(("nsJSShServer ctor\n"));
 }
 
 nsJSShServer::~nsJSShServer()
 {
-#ifdef DEBUG
-  printf("nsJSShServer dtor\n");
-#endif
+  LOG(("nsJSShServer dtor\n"));
   // XXX should we stop listening or not??
   StopServerSocket();
 }
 
 //----------------------------------------------------------------------
 // nsISupports methods:
 
 NS_IMPL_ADDREF(nsJSShServer)