Bug 611897 - r=jst,bzbarsky a=blocking1.9.16+
authorSteven Michaud <smichaud@pobox.com>
Thu, 18 Nov 2010 19:46:58 -0600
changeset 27216 05202664ed20d295109b92050be5baa9dba6ae80
parent 27215 4fac36e8cd3ee00ad63a4bfdce43a38507590173
child 27217 eab9c1dd1f1758eebf245efb75325a2d8d50af9e
push id2573
push usersmichaud@pobox.com
push dateFri, 19 Nov 2010 01:48:01 +0000
reviewersjst, bzbarsky, blocking1.9.16
bugs611897
milestone1.9.1.16pre
Bug 611897 - r=jst,bzbarsky a=blocking1.9.16+
modules/oji/src/ProxyJNI.cpp
modules/oji/src/nsCSecurityContext.cpp
modules/oji/src/nsCSecurityContext.h
netwerk/base/public/nsNetUtil.h
--- a/modules/oji/src/ProxyJNI.cpp
+++ b/modules/oji/src/ProxyJNI.cpp
@@ -42,16 +42,17 @@
 #include "nscore.h"
 #include "jvmmgr.h"
 #include "nsISecureEnv.h"
 #include "nsIJVMPlugin.h"
 #include "nsHashtable.h"
 #include "nsVoidArray.h"
 #include "plstr.h"
 #include "ProxyClassLoader.h"
+#include "nsCSecurityContext.h"
 
 #include "ProxyJNI.h"
 #include "nsDataHashtable.h"
 
 #ifdef DEBUG
 #include "nsDebug.h"
 #endif
 
@@ -276,28 +277,50 @@ static jvalue kErrorValue;
 
 class ProxyJNIEnv : public JNIEnv {
 private:
     static JNINativeInterface_ theFuncs;
     static nsDataHashtable<JavaClassMemberKey, void*>* theIDTable;
     nsISecureEnv* mSecureEnv;
     nsISecurityContext* mContext;
     jbool mInProxyFindClass;
+    nsXPIDLCString mFakeOrigin;
 
     static ProxyJNIEnv& GetProxyEnv(JNIEnv* env) { return *(ProxyJNIEnv*)env; }
 
     nsISecurityContext* getContext() { 
         if (!mContext) {
             return  JVM_GetJSSecurityContext();
         } else {
             mContext->AddRef();
             return mContext;
         }
     }
 
+    // Don't generate a new fake origin on every call to
+    // nsCSecurityContext::GetOrigin().
+    nsresult getOrSetFakeOrigin(nsCSecurityContext *securityContext)
+    {
+        if (!securityContext)
+            return NS_OK;
+        if (!mFakeOrigin.IsVoid())
+            securityContext->SetFakeOrigin(mFakeOrigin);
+        char origin[256];
+        nsresult rv = securityContext->GetOrigin(origin, 256);
+        if (NS_FAILED(rv))
+            return rv;
+        if (mFakeOrigin.IsVoid()) {
+            const nsCString& contextFakeOrigin =
+               securityContext->GetFakeOrigin();
+            if (!contextFakeOrigin.IsVoid())
+                mFakeOrigin.Assign(contextFakeOrigin);
+        }
+        return NS_OK;
+    }
+
     static jint JNICALL GetVersion(JNIEnv* env)
     {
         jint version = 0;
         nsISecureEnv* secureEnv = GetSecureEnv(env);
         nsresult result;
         result = secureEnv->GetVersion(&version);
         return version;
     }
@@ -494,32 +517,33 @@ private:
         jobject outObject = NULL;
         
         // convert the va_list into an array of jvalues.
         JNIMethod* method = (JNIMethod*)methodID;
         MarshalledArgs jargs(method, args);
         ProxyJNIEnv& proxyEnv = GetProxyEnv(env);
         nsISecureEnv* secureEnv = GetSecureEnv(env);
         nsISecurityContext* securityContext = proxyEnv.getContext();
-        nsresult result;
-        result = secureEnv->NewObject(clazz, method->mMethodID, jargs, &outObject, securityContext);
+        nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext);
+        if (NS_SUCCEEDED(rv))
+            secureEnv->NewObject(clazz, method->mMethodID, jargs, &outObject, securityContext);
         NS_IF_RELEASE(securityContext);
-        
         return outObject;
     }
 
     static jobject JNICALL NewObjectA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args)
     {
         jobject outObject = NULL;
         ProxyJNIEnv& proxyEnv = GetProxyEnv(env);
         nsISecureEnv* secureEnv = GetSecureEnv(env);
         JNIMethod* method = (JNIMethod*)methodID;
         nsISecurityContext* securityContext = proxyEnv.getContext();
-        nsresult result;
-        result = secureEnv->NewObject(clazz, method->mMethodID, args, &outObject, securityContext);
+        nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext);
+        if (NS_SUCCEEDED(rv))
+            secureEnv->NewObject(clazz, method->mMethodID, args, &outObject, securityContext);
         NS_IF_RELEASE(securityContext);
         return outObject;
     }
 
     static jclass JNICALL GetObjectClass(JNIEnv *env, jobject obj)
     {
         jclass outClass = NULL;
         nsISecureEnv* secureEnv = GetSecureEnv(env);
@@ -563,17 +587,19 @@ private:
     // Virtual Invokers.
     
     static jvalue InvokeMethod(JNIEnv *env, jobject obj, JNIMethod* method, jvalue* args)
     {
         jvalue outValue;
         ProxyJNIEnv& proxyEnv = GetProxyEnv(env);
         nsISecureEnv* secureEnv = GetSecureEnv(env);
         nsISecurityContext* securityContext = proxyEnv.getContext();
-        nsresult rv = secureEnv->CallMethod(method->mReturnType, obj, method->mMethodID, args, &outValue, securityContext);
+        nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext);
+        if (NS_SUCCEEDED(rv))
+            rv = secureEnv->CallMethod(method->mReturnType, obj, method->mMethodID, args, &outValue, securityContext);
         NS_IF_RELEASE(securityContext);
         return NS_SUCCEEDED(rv) ? outValue : kErrorValue;
     }
     
     static jvalue InvokeMethod(JNIEnv *env, jobject obj, JNIMethod* method, va_list args)
     {
         // convert the va_list into an array of jvalues.
         MarshalledArgs jargs(method, args);
@@ -581,18 +607,19 @@ private:
     }
     
     static void InvokeVoidMethod(JNIEnv *env, jobject obj, JNIMethod* method, jvalue* args)
     {
         jvalue unusedValue;
         ProxyJNIEnv& proxyEnv = GetProxyEnv(env);
         nsISecureEnv* secureEnv = GetSecureEnv(env);
         nsISecurityContext* securityContext = proxyEnv.getContext();
-        nsresult result;
-        result = secureEnv->CallMethod(jvoid_type, obj, method->mMethodID, args, &unusedValue, securityContext);
+        nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext);
+        if (NS_SUCCEEDED(rv))
+            secureEnv->CallMethod(jvoid_type, obj, method->mMethodID, args, &unusedValue, securityContext);
         NS_IF_RELEASE(securityContext);
     }
 
     static void InvokeVoidMethod(JNIEnv *env, jobject obj, JNIMethod* method, va_list args)
     {
         // convert the va_list into an array of jvalues.
         MarshalledArgs jargs(method, args);
         InvokeVoidMethod(env, obj, method, jargs);
@@ -670,17 +697,19 @@ private:
     // Non-virtual Invokers.
 
     static jvalue InvokeNonVirtualMethod(JNIEnv *env, jobject obj, jclass clazz, JNIMethod* method, jvalue* args)
     {
         jvalue outValue;
         ProxyJNIEnv& proxyEnv = GetProxyEnv(env);
         nsISecureEnv* secureEnv = GetSecureEnv(env);
         nsISecurityContext* securityContext = proxyEnv.getContext();
-        nsresult rv = secureEnv->CallNonvirtualMethod(method->mReturnType, obj, clazz, method->mMethodID, args, &outValue, securityContext);
+        nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext);
+        if (NS_SUCCEEDED(rv))
+            rv = secureEnv->CallNonvirtualMethod(method->mReturnType, obj, clazz, method->mMethodID, args, &outValue, securityContext);
         NS_IF_RELEASE(securityContext);
         return NS_SUCCEEDED(rv) ? outValue : kErrorValue;
     }
     
     static jvalue InvokeNonVirtualMethod(JNIEnv *env, jobject obj, jclass clazz, JNIMethod* method, va_list args)
     {
         // convert the va_list into an array of jvalues.
         MarshalledArgs jargs(method, args);
@@ -688,18 +717,19 @@ private:
     }
     
     static void InvokeNonVirtualVoidMethod(JNIEnv *env, jobject obj, jclass clazz, JNIMethod* method, jvalue* args)
     {
         jvalue unusedValue;
         ProxyJNIEnv& proxyEnv = GetProxyEnv(env);
         nsISecureEnv* secureEnv = GetSecureEnv(env);
         nsISecurityContext* securityContext = proxyEnv.getContext();
-        nsresult result;
-        result = secureEnv->CallNonvirtualMethod(jvoid_type, obj, clazz, method->mMethodID, args, &unusedValue, securityContext);
+        nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext);
+        if (NS_SUCCEEDED(rv))
+            secureEnv->CallNonvirtualMethod(jvoid_type, obj, clazz, method->mMethodID, args, &unusedValue, securityContext);
         NS_IF_RELEASE(securityContext);
     }
 
     static void InvokeNonVirtualVoidMethod(JNIEnv *env, jobject obj, jclass clazz, JNIMethod* method, va_list args)
     {
         // convert the va_list into an array of jvalues.
         MarshalledArgs jargs(method, args);
         InvokeNonVirtualVoidMethod(env, obj, clazz, method, jargs);
@@ -775,17 +805,19 @@ private:
     }
 
     static jvalue GetField(JNIEnv* env, jobject obj, JNIField* field)
     {
         jvalue outValue;
         ProxyJNIEnv& proxyEnv = GetProxyEnv(env);
         nsISecureEnv* secureEnv = GetSecureEnv(env);
         nsISecurityContext* securityContext = proxyEnv.getContext();
-        nsresult rv = secureEnv->GetField(field->mFieldType, obj, field->mFieldID, &outValue, securityContext);
+        nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext);
+        if (NS_SUCCEEDED(rv))
+            rv = secureEnv->GetField(field->mFieldType, obj, field->mFieldID, &outValue, securityContext);
         NS_IF_RELEASE(securityContext);
         return NS_SUCCEEDED(rv) ? outValue : kErrorValue;
     }
 
 #define IMPLEMENT_GET_FIELD(methodName, returnType, jvalueField)                            \
     static returnType JNICALL methodName(JNIEnv *env, jobject obj, jfieldID fieldID)        \
     {                                                                                       \
         return GetField(env, obj, (JNIField*)fieldID).jvalueField;                          \
@@ -803,18 +835,19 @@ private:
 
 #undef IMPLEMENT_GET_FIELD
 
     static void SetField(JNIEnv* env, jobject obj, JNIField* field, jvalue value)
     {
         ProxyJNIEnv& proxyEnv = GetProxyEnv(env);
         nsISecureEnv* secureEnv = GetSecureEnv(env);
         nsISecurityContext* securityContext = proxyEnv.getContext();
-        nsresult result;
-        result = secureEnv->SetField(field->mFieldType, obj, field->mFieldID, value, securityContext);
+        nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext);
+        if (NS_SUCCEEDED(rv))
+            secureEnv->SetField(field->mFieldType, obj, field->mFieldID, value, securityContext);
         NS_IF_RELEASE(securityContext);
     }
 
 #define IMPLEMENT_SET_FIELD(methodName, fieldType, jvalueField)                                     \
     static void JNICALL methodName(JNIEnv *env, jobject obj, jfieldID fieldID, fieldType value)     \
     {                                                                                               \
         jvalue fieldValue;                                                                          \
         fieldValue.jvalueField = value;                                                             \
@@ -859,17 +892,19 @@ private:
     // Static Invokers.
     
     static jvalue InvokeStaticMethod(JNIEnv *env, jclass clazz, JNIMethod* method, jvalue* args)
     {
         jvalue outValue;
         ProxyJNIEnv& proxyEnv = GetProxyEnv(env);
         nsISecureEnv* secureEnv = GetSecureEnv(env);
         nsISecurityContext* securityContext = proxyEnv.getContext();
-        nsresult rv = secureEnv->CallStaticMethod(method->mReturnType, clazz, method->mMethodID, args, &outValue, securityContext);
+        nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext);
+        if (NS_SUCCEEDED(rv))
+            rv = secureEnv->CallStaticMethod(method->mReturnType, clazz, method->mMethodID, args, &outValue, securityContext);
         NS_IF_RELEASE(securityContext);
         return NS_SUCCEEDED(rv) ? outValue : kErrorValue;
     }
     
     static jvalue InvokeStaticMethod(JNIEnv *env, jclass clazz, JNIMethod* method, va_list args)
     {
         // convert the va_list into an array of jvalues.
         MarshalledArgs jargs(method, args);
@@ -877,18 +912,19 @@ private:
     }
     
     static void InvokeStaticVoidMethod(JNIEnv *env, jclass clazz, JNIMethod* method, jvalue* args)
     {
         jvalue unusedValue;
         ProxyJNIEnv& proxyEnv = GetProxyEnv(env);
         nsISecureEnv* secureEnv = GetSecureEnv(env);
         nsISecurityContext* securityContext = proxyEnv.getContext();
-        nsresult result;
-        result = secureEnv->CallStaticMethod(jvoid_type, clazz, method->mMethodID, args, &unusedValue, securityContext);
+        nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext);
+        if (NS_SUCCEEDED(rv))
+            secureEnv->CallStaticMethod(jvoid_type, clazz, method->mMethodID, args, &unusedValue, securityContext);
         NS_IF_RELEASE(securityContext);
     }
 
     static void InvokeStaticVoidMethod(JNIEnv *env, jclass clazz, JNIMethod* method, va_list args)
     {
         // convert the va_list into an array of jvalues.
         MarshalledArgs jargs(method, args);
         InvokeStaticVoidMethod(env, clazz, method, jargs);
@@ -964,17 +1000,19 @@ private:
     }
 
     static jvalue GetStaticField(JNIEnv* env, jclass clazz, JNIField* field)
     {
         jvalue outValue;
         ProxyJNIEnv& proxyEnv = GetProxyEnv(env);
         nsISecureEnv* secureEnv = GetSecureEnv(env);
         nsISecurityContext* securityContext = proxyEnv.getContext();
-        nsresult rv = secureEnv->GetStaticField(field->mFieldType, clazz, field->mFieldID, &outValue, securityContext);
+        nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext);
+        if (NS_SUCCEEDED(rv))
+            rv = secureEnv->GetStaticField(field->mFieldType, clazz, field->mFieldID, &outValue, securityContext);
         NS_IF_RELEASE(securityContext);
         return NS_SUCCEEDED(rv) ? outValue : kErrorValue;
     }
 
 #define IMPLEMENT_GET_FIELD(methodName, returnType, jvalueField)                            \
     static returnType JNICALL methodName(JNIEnv *env, jclass clazz, jfieldID fieldID)       \
     {                                                                                       \
         return GetStaticField(env, clazz, (JNIField*)fieldID).jvalueField;                  \
@@ -992,18 +1030,19 @@ private:
 
 #undef IMPLEMENT_GET_FIELD
 
     static void SetStaticField(JNIEnv* env, jclass clazz, JNIField* field, jvalue value)
     {
         ProxyJNIEnv& proxyEnv = GetProxyEnv(env);
         nsISecureEnv* secureEnv = GetSecureEnv(env);
         nsISecurityContext* securityContext = proxyEnv.getContext();
-        nsresult result;
-        result = secureEnv->SetStaticField(field->mFieldType, clazz, field->mFieldID, value, securityContext);
+        nsresult rv = proxyEnv.getOrSetFakeOrigin((nsCSecurityContext*)securityContext);
+        if (NS_SUCCEEDED(rv))
+            secureEnv->SetStaticField(field->mFieldType, clazz, field->mFieldID, value, securityContext);
         NS_IF_RELEASE(securityContext);
     }
 
 #define IMPLEMENT_SET_FIELD(methodName, fieldType, jvalueField)                                     \
     static void JNICALL methodName(JNIEnv *env, jclass clazz, jfieldID fieldID, fieldType value)    \
     {                                                                                               \
         jvalue fieldValue;                                                                          \
         fieldValue.jvalueField = value;                                                             \
@@ -1729,19 +1768,18 @@ ProxyJNIEnv::ProxyJNIEnv(nsIJVMPlugin* j
             NS_WARNING("CreateSecureEnv OK");
 #endif
     }
 }
 
 ProxyJNIEnv::~ProxyJNIEnv()
 {
     this->functions = NULL;
-    
-    if (mSecureEnv != NULL)
-        mSecureEnv->Release();
+
+    NS_IF_RELEASE(mSecureEnv);
 }
 
 JNIEnv* CreateProxyJNI(nsIJVMPlugin* jvmPlugin, nsISecureEnv* inSecureEnv)
 {
     ProxyJNIEnv* proxyEnv = new ProxyJNIEnv(jvmPlugin, inSecureEnv);
     if (proxyEnv->getSecureEnv() == NULL) {
         delete proxyEnv;
         return NULL;
--- a/modules/oji/src/nsCSecurityContext.cpp
+++ b/modules/oji/src/nsCSecurityContext.cpp
@@ -52,16 +52,17 @@
 #include "jvmmgr.h"
 #include "jsjava.h"
 
 // For GetOrigin()
 
 #include "nsIScriptSecurityManager.h"
 #include "nsIServiceManager.h"
 #include "nsCRT.h"
+#include "nsNetUtil.h"
 
 #include "nsTraceRefcnt.h"
 
 static NS_DEFINE_IID(kISecurityContextIID, NS_ISECURITYCONTEXT_IID);
 static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
 
 
 ////////////////////////////////////////////////////////////////////////////
@@ -98,48 +99,80 @@ nsCSecurityContext::Implies(const char* 
         *bAllowedAccess = m_HasUniversalJavaCapability;
     } else {
         *bAllowedAccess = PR_FALSE;
     }
 
     return NS_OK;
 }
 
+nsresult
+nsCSecurityContext::GetOriginImpl(nsXPIDLCString& origin)
+{
+    nsresult rv = NS_OK;
 
-NS_METHOD 
-nsCSecurityContext::GetOrigin(char* buf, int buflen)
-{
     if (!m_pPrincipal) {
         // Get the Script Security Manager.
-        nsresult rv = NS_OK;
         nsCOMPtr<nsIScriptSecurityManager> secMan =
              do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
-        if (NS_FAILED(rv) || !secMan) {
+        if (NS_FAILED(rv) || !secMan)
             return NS_ERROR_FAILURE;
-        }
 
         secMan->GetSubjectPrincipal(getter_AddRefs(m_pPrincipal));
-        if (!m_pPrincipal) {
+        if (!m_pPrincipal)
             return NS_ERROR_FAILURE;
-        }
     }
 
+    m_pPrincipal->GetOrigin(getter_Copies(origin));
+    if (origin.IsEmpty())
+        return NS_ERROR_FAILURE;
+
+    return NS_OK;
+}
+
+// This method is called from the OJI plugin without checking its return
+// value (from getAndPackSecurityInfo() in remotejni.cpp).  So we need to
+// set the origin appropriately except in the very worst of circumstances,
+// and only then do an error return.
+NS_METHOD
+nsCSecurityContext::GetOrigin(char* buf, int buflen)
+{
     nsXPIDLCString origin;
-    m_pPrincipal->GetOrigin(getter_Copies(origin));
+    PRBool javaCompatible = PR_FALSE;
+
+    if (NS_SUCCEEDED(GetOriginImpl(origin))) {
+        if (NS_FAILED(NS_CheckIsJavaCompatibleURLString(origin, &javaCompatible)))
+            javaCompatible = PR_FALSE;
+    } else {
+        javaCompatible = PR_FALSE;
+    }
 
     PRInt32 originlen = origin.Length();
-    if (origin.IsEmpty() || originlen > buflen - 1) {
+
+    // Don't pass back a value that Java won't be able to understand or
+    // won't handle correctly.  Instead pass back something that Java will
+    // understand but won't be able to use to access the network, and for
+    // which same-origin checks will always fail.
+    if (!javaCompatible) {
+        if (mFakeOrigin.IsVoid()) {
+            if (NS_FAILED(NS_MakeRandomInvalidURLString(mFakeOrigin)))
+                return NS_ERROR_FAILURE;
+        }
+        origin.Assign(mFakeOrigin);
+        originlen = origin.Length();
+    }
+
+    if (originlen > buflen - 1)
         return NS_ERROR_FAILURE;
-    }
 
     // Copy the string into to user supplied buffer. Is there a better
     // way to do this?
 
     memcpy(buf, origin, originlen);
-    buf[originlen] = nsnull; // Gotta terminate it.
+    buf[originlen] = '\0'; // Gotta terminate it.
 
     return NS_OK;
 }
 
 NS_METHOD 
 nsCSecurityContext::GetCertificateID(char* buf, int buflen)
 {
     nsCOMPtr<nsIPrincipal> principal;
--- a/modules/oji/src/nsCSecurityContext.h
+++ b/modules/oji/src/nsCSecurityContext.h
@@ -45,16 +45,17 @@
 #ifndef nsCSecurityContext_h___
 #define nsCSecurityContext_h___
 
 #include "jscntxt.h"
 #include "jsdbgapi.h"
 #include "nsISecurityContext.h"
 #include "nsIPrincipal.h"
 #include "nsCOMPtr.h"
+#include "nsString.h"
 
 struct JSContext;
 
 /**
  * nsCSecurityContext implements nsISecurityContext interface for navigator.
  * This is used by a JVM to implement netscape.javascript.JSObject functionality.
  */
 class nsCSecurityContext :public nsISecurityContext {
@@ -100,18 +101,27 @@ public:
 
     ////////////////////////////////////////////////////////////////////////////
     // from nsCSecurityContext:
 
     nsCSecurityContext(JSContext* cx);
     nsCSecurityContext(nsIPrincipal* principal);
     virtual ~nsCSecurityContext(void);
 
+    ////////////////////////////////////////////////////////////////////////////
+    // Miscellaneous
+
+    const nsCString& GetFakeOrigin() const { return mFakeOrigin; }
+    void SetFakeOrigin(nsCString& fakeOrigin) { mFakeOrigin.Assign(fakeOrigin); }
+
 protected:
     JSStackFrame *m_pJStoJavaFrame;
     JSContext    *m_pJSCX;
 private:
+    nsresult GetOriginImpl(nsXPIDLCString& origin);
+
     nsCOMPtr<nsIPrincipal> m_pPrincipal;
     PRBool        m_HasUniversalJavaCapability;
     PRBool        m_HasUniversalBrowserReadCapability;
+    nsXPIDLCString mFakeOrigin;
 };
 
 #endif // nsCSecurityContext_h___
--- a/netwerk/base/public/nsNetUtil.h
+++ b/netwerk/base/public/nsNetUtil.h
@@ -46,16 +46,18 @@
 #include "nsStringGlue.h"
 #include "nsMemory.h"
 #include "nsCOMPtr.h"
 #include "prio.h" // for read/write flags, permissions, etc.
 
 #include "nsCRT.h"
 #include "nsIURI.h"
 #include "nsIStandardURL.h"
+#include "nsIURLParser.h"
+#include "nsIUUIDGenerator.h"
 #include "nsIInputStream.h"
 #include "nsIOutputStream.h"
 #include "nsISafeOutputStream.h"
 #include "nsIStreamListener.h"
 #include "nsIRequestObserverProxy.h"
 #include "nsISimpleStreamListener.h"
 #include "nsILoadGroup.h"
 #include "nsIInterfaceRequestor.h"
@@ -1620,9 +1622,86 @@ NS_IsInternalSameURIRedirect(nsIChannel 
   if (!oldURI || !newURI) {
     return PR_FALSE;
   }
 
   PRBool res;
   return NS_SUCCEEDED(oldURI->Equals(newURI, &res)) && res;
 }
 
+/**
+ * Helper function to create a random URL string that's properly formed
+ * but guaranteed to be invalid.
+ */  
+#define NS_FAKE_SCHEME "http://"
+#define NS_FAKE_TLD ".invalid"
+inline nsresult
+NS_MakeRandomInvalidURLString(nsCString& result)
+{
+  nsresult rv;
+  nsCOMPtr<nsIUUIDGenerator> uuidgen =
+    do_GetService("@mozilla.org/uuid-generator;1", &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsID idee;
+  rv = uuidgen->GenerateUUIDInPlace(&idee);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  char chars[NSID_LENGTH];
+  idee.ToProvidedString(chars);
+
+  result.AssignLiteral(NS_FAKE_SCHEME);
+  // Strip off the '{' and '}' at the beginning and end of the UUID
+  result.Append(chars + 1, NSID_LENGTH - 3);
+  result.AppendLiteral(NS_FAKE_TLD);
+
+  return NS_OK;
+}
+#undef NS_FAKE_SCHEME
+#undef NS_FAKE_TLD
+
+/**
+ * Helper function to determine whether urlString is Java-compatible --
+ * whether it can be passed to the Java URL(String) constructor without the
+ * latter throwing a MalformedURLException, or without Java otherwise
+ * mishandling it.
+ */  
+inline nsresult
+NS_CheckIsJavaCompatibleURLString(nsCString& urlString, PRBool *result)
+{
+  *result = PR_FALSE; // Default to "no"
+
+  nsresult rv = NS_OK;
+  nsCOMPtr<nsIURLParser> urlParser =
+    do_GetService(NS_STDURLPARSER_CONTRACTID, &rv);
+  if (NS_FAILED(rv) || !urlParser)
+    return NS_ERROR_FAILURE;
+
+  PRBool compatible = PR_TRUE;
+  PRUint32 schemePos = 0;
+  PRInt32 schemeLen = 0;
+  urlParser->ParseURL(urlString.get(), -1, &schemePos, &schemeLen,
+                      nsnull, nsnull, nsnull, nsnull);
+  if (schemeLen != -1) {
+    nsCString scheme;
+    scheme.Assign(urlString.get() + schemePos, schemeLen);
+    // By default Java only understands a small number of URL schemes, and of
+    // these only some are likely to represent user input (for example from a
+    // link or the location bar) that Java can legitimately be expected to
+    // handle.  (Besides those listed below, Java also understands the "jar",
+    // "mailto" and "netdoc" schemes.  But it probably doesn't expect these
+    // from a browser, and is therefore likely to mishandle them.)
+    if (PL_strcasecmp(scheme.get(), "http") &&
+        PL_strcasecmp(scheme.get(), "https") &&
+        PL_strcasecmp(scheme.get(), "file") &&
+        PL_strcasecmp(scheme.get(), "ftp") &&
+        PL_strcasecmp(scheme.get(), "gopher"))
+      compatible = PR_FALSE;
+  } else {
+    compatible = PR_FALSE;
+  }
+
+  *result = compatible;
+
+  return NS_OK;
+}
+
 #endif // !nsNetUtil_h__