Addressed some comments, still need to address window events and prbool
authorRiccardo Pelizzi <r.pelizzi@gmail.com>
Mon, 28 May 2012 20:43:38 -0400
changeset 42 0b9377ea878bf6998a912cd94c5a6c351cf57aac
parent 41 6ab9e7c4d646bd0e1d1f90eedb99061f0e174052
child 43 dafd5c7104313ad67d058a813e884b2151cb3c91
push id24
push userr.pelizzi@gmail.com
push dateTue, 29 May 2012 01:06:07 +0000
Addressed some comments, still need to address window events and prbool
xssfilter
--- a/xssfilter
+++ b/xssfilter
@@ -256,28 +256,27 @@ diff --git a/caps/idl/nsIPrincipal.idl b
  
  [scriptable, uuid(B406A2DB-E547-4C95-B8E2-AD09ECB54CE0)]
  interface nsIPrincipal : nsISerializable
  {
      /**
       * Values of capabilities for each principal. Order is
       * significant: if an operation is performed on a set
       * of capabilities, the minimum is computed.
-@@ -245,9 +247,14 @@ interface nsIPrincipal : nsISerializable
+@@ -245,9 +247,13 @@ interface nsIPrincipal : nsISerializable
       * one, this will return null.  Getting this attribute never throws.
       */
      readonly attribute nsISupports certificate;
  
      /**
       * A Content Security Policy associated with this principal.
       */
      [noscript] attribute nsIContentSecurityPolicy csp;
 +    /**
-+     * XSS Filter associated with the principal. It is not an xpcom
-+     * object and it is not refcounted.
++     * Refcounted XSS Filter associated with the principal.
 +     */
 +    [noscript,notxpcom] attribute nsXSSFilter XSSFilter;
  };
 diff --git a/caps/include/nsPrincipal.h b/caps/include/nsPrincipal.h
 --- a/caps/include/nsPrincipal.h
 +++ b/caps/include/nsPrincipal.h
 @@ -137,16 +137,17 @@ protected:
    // Keep this is a pointer, even though it may slightly increase the
@@ -313,53 +312,53 @@ diff --git a/caps/include/nsScriptSecuri
  
  class nsIDocShell;
  class nsString;
  class nsIClassInfo;
  class nsIIOService;
  class nsIXPConnect;
  class nsIStringBundle;
  class nsSystemPrincipal;
-@@ -427,16 +428,21 @@ private:
+@@ -427,16 +428,20 @@ private:
      CheckObjectAccess(JSContext *cx, JSObject *obj,
                        jsid id, JSAccessMode mode,
                        jsval *vp);
  
      // Decides, based on CSP, whether or not eval() and stuff can be executed.
      static JSBool
      ContentSecurityPolicyPermitsJSAction(JSContext *cx);
  
 +    static JSBool
-+    XSSFilterPermitsJSAction(JSContext *cx, JSString *str,
-+                             XSSJSAction action);
++    XSSFilterPermitsJSAction(JSContext *cx, JSString *str);
 +
 +
      // Returns null if a principal cannot be found; generally callers
      // should error out at that point.
      static nsIPrincipal*
      doGetObjectPrincipal(JSObject *obj
  #ifdef DEBUG
                           , bool aAllowShortCircuit = true
  #endif
                           );
 diff --git a/caps/src/nsNullPrincipal.cpp b/caps/src/nsNullPrincipal.cpp
 --- a/caps/src/nsNullPrincipal.cpp
 +++ b/caps/src/nsNullPrincipal.cpp
-@@ -274,16 +274,31 @@ nsNullPrincipal::GetCsp(nsIContentSecuri
+@@ -274,16 +274,32 @@ nsNullPrincipal::GetCsp(nsIContentSecuri
  NS_IMETHODIMP
  nsNullPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp)
  {
    // CSP on a null principal makes no sense
    return NS_ERROR_NOT_AVAILABLE;
  }
  
  NS_IMETHODIMP
 +nsNullPrincipal::GetXSSFilter(nsXSSFilter** aXSS)
 +{
-+  // filter on a null principal makes no sense
++  // Null principals are never loaded from anywhere, and thus can
++  // never have an XSS filter
 +  *aXSS = nsnull;
 +  return NS_OK;
 +}
 +
 +NS_IMETHODIMP
 +nsNullPrincipal::SetXSSFilter(nsXSSFilter* aXSS)
 +{
 +  // filter on a null principal makes no sense
@@ -391,35 +390,17 @@ diff --git a/caps/src/nsPrincipal.cpp b/
  
  #include "nsPrincipal.h"
  
  #include "mozilla/Preferences.h"
  
  using namespace mozilla;
  
  static bool gCodeBasePrincipalSupport = false;
-@@ -111,16 +112,17 @@ nsPrincipal::Release()
-   }
- 
-   return count;
- }
- 
- nsPrincipal::nsPrincipal()
-   : mCapabilities(nsnull),
-     mSecurityPolicy(nsnull),
-+    mXSS(nsnull),
-     mTrusted(false),
-     mInitialized(false),
-     mCodebaseImmutable(false),
-     mDomainImmutable(false)
- {
-   if (!gIsObservingCodeBasePrincipalSupport) {
-     nsresult rv =
-       Preferences::AddBoolVarCache(&gCodeBasePrincipalSupport,
-@@ -789,16 +791,35 @@ nsPrincipal::SetCsp(nsIContentSecurityPo
+@@ -789,16 +790,34 @@ nsPrincipal::SetCsp(nsIContentSecurityPo
    if (mCSP)
      return NS_ERROR_ALREADY_INITIALIZED;
  
    mCSP = aCsp;
    return NS_OK;
  }
  
  NS_IMETHODIMP
@@ -427,18 +408,17 @@ diff --git a/caps/src/nsPrincipal.cpp b/
 +{
 +  NS_IF_ADDREF(*aXSS = mXSS);
 +  return NS_OK;
 +}
 +
 +NS_IMETHODIMP
 +nsPrincipal::SetXSSFilter(nsXSSFilter* aXSS)
 +{
-+  // If the filter was already set, it should not be destroyed!  Instead, it should
-+  // get set anew when a new principal is created.
++  // once assigned, the filter cannot be changed.
 +  if (mXSS)
 +    return NS_ERROR_ALREADY_INITIALIZED;
 +
 +  mXSS = aXSS;
 +  return NS_OK;
 +}
 +
 +NS_IMETHODIMP
@@ -477,32 +457,37 @@ diff --git a/caps/src/nsScriptSecurityMa
  static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
  
  nsIIOService    *nsScriptSecurityManager::sIOService = nsnull;
  nsIXPConnect    *nsScriptSecurityManager::sXPConnect = nsnull;
  nsIThreadJSContextStack *nsScriptSecurityManager::sJSContextStack = nsnull;
  nsIStringBundle *nsScriptSecurityManager::sStrBundle = nsnull;
  JSRuntime       *nsScriptSecurityManager::sRuntime   = 0;
  bool nsScriptSecurityManager::sStrictFileOriginPolicy = true;
-@@ -587,16 +595,62 @@ nsScriptSecurityManager::ContentSecurity
+@@ -587,16 +595,64 @@ nsScriptSecurityManager::ContentSecurity
                                   fileName,
                                   scriptSample,
                                   lineNum);
      }
  
      return evalOK;
  }
  
 +JSBool
-+nsScriptSecurityManager::XSSFilterPermitsJSAction(JSContext *cx, JSString *str,
-+                                                  XSSJSAction action)
++nsScriptSecurityManager::XSSFilterPermitsJSAction(JSContext *cx, JSString *str)
 +{
 +
 +    PR_LOG(gXssPRLog, PR_LOG_DEBUG, (">>>> XSSFilterPermitsJSAction"));
 +
++    if (!str) {
++        NS_ERROR("XSS: str is null.");
++        return true;
++    }
++
++
 +    // Get the security manager
 +    nsScriptSecurityManager *ssm =
 +        nsScriptSecurityManager::GetScriptSecurityManager();
 +
 +    NS_ASSERTION(ssm, "Failed to get security manager service");
 +
 +    nsresult rv;
 +    nsIPrincipal* subjectPrincipal = ssm->GetSubjectPrincipal(cx, &rv);
@@ -519,38 +504,35 @@ diff --git a/caps/src/nsScriptSecurityMa
 +    }
 +
 +    nsRefPtr<nsXSSFilter> xss;
 +    rv = subjectPrincipal->GetXSSFilter(getter_AddRefs(xss));
 +    // don't do anything unless there's a filter
 +    if (!xss) {
 +        return true;
 +    }
-+    if (str == NULL) {
-+        NS_WARNING("XSS: str is null");
++
++    nsDependentJSString ns_str;
++    if (!ns_str.init(cx, str)) {
++        NS_WARNING("Failed to initialize nsDependentJSString");
 +        return true;
 +    }
-+    nsDependentJSString nsStr;
-+    if (!nsStr.init(cx, str)) {
-+        NS_WARNING("Failed to get nsDependentJSString");
-+        return true;
-+    }
-+
-+    return xss->PermitsJSAction(nsStr, action);
++
++    return xss->PermitsJSAction(ns_str);
 +}
 +
  
  JSBool
  nsScriptSecurityManager::CheckObjectAccess(JSContext *cx, JSObject *obj,
                                             jsid id, JSAccessMode mode,
                                             jsval *vp)
  {
      // Get the security manager
      nsScriptSecurityManager *ssm =
-@@ -3380,17 +3434,18 @@ nsresult nsScriptSecurityManager::Init()
+@@ -3380,17 +3436,18 @@ nsresult nsScriptSecurityManager::Init()
  
      rv = runtimeService->GetRuntime(&sRuntime);
      NS_ENSURE_SUCCESS(rv, rv);
  
      static JSSecurityCallbacks securityCallbacks = {
          CheckObjectAccess,
          NULL,
          NULL,
@@ -791,114 +773,113 @@ diff --git a/content/base/src/nsDocument
  #endif
  
    // Start out mLastStyleSheetSet as null, per spec
    SetDOMStringToNull(mLastStyleSheetSet);
    
    mLinksToUpdate.Init();
  }
  
-@@ -2380,16 +2386,19 @@ nsDocument::StartDocumentLoad(const char
+@@ -2380,16 +2386,18 @@ nsDocument::StartDocumentLoad(const char
  
    RetrieveRelevantHeaders(aChannel);
  
    mChannel = aChannel;
  
    nsresult rv = InitCSP();
    NS_ENSURE_SUCCESS(rv, rv);
  
-+  rv = InitXSS();
-+  NS_ENSURE_SUCCESS(rv, rv);
++  InitXSSFilter();
 +
    return NS_OK;
  }
  
  nsresult
  nsDocument::InitCSP()
  {
    if (CSPService::sCSPEnabled) {
      nsAutoString cspHeaderValue;
-@@ -2503,16 +2512,61 @@ nsDocument::InitCSP()
+@@ -2503,16 +2511,61 @@ nsDocument::InitCSP()
    else { //CSP was not enabled!
      PR_LOG(gCspPRLog, PR_LOG_DEBUG, 
             ("CSP is disabled, skipping CSP init for document %p", this));
    }
  #endif
    return NS_OK;
  }
  
-+nsresult nsDocument::InitXSS()
++void nsDocument::InitXSSFilter()
 +{
 +  if (!nsXSSFilter::sXSSEnabled) {
-+    return NS_OK;
++    return;
 +  }
 +
 +  bool system = false;
 +  nsIScriptSecurityManager *ssm = nsContentUtils::GetSecurityManager();
 +
 +  if (NS_SUCCEEDED(ssm->IsSystemPrincipal(NodePrincipal(), &system)) && system) {
 +    // TODO: protection for privileged documents? how would attackers
 +    // provide untrusted input to it?
-+    return NS_OK;
++    return;
 +  }
 +
 +  nsIPrincipal* principal = GetPrincipal();
 +  if (!principal) {
 +#ifdef PR_LOGGING
 +    PR_LOG(gXssPRLog, PR_LOG_DEBUG,
 +           ("XSS: no principal to put filter in"));
-+    return NS_OK;
++    return;
 +#endif
 +  }
 +
 +  // since there is a principal and the pref is enabled, create the object.
 +  nsRefPtr<nsXSSFilter> xss = new nsXSSFilter(this);
 +
 +  nsresult rv = xss->ScanRequestData();
 +  if (NS_FAILED(rv)) {
 +    // not necessarily a failure if we bail out on X-XSS protection header
-+    return NS_OK;
++    return;
 +  }
 +  rv = principal->SetXSSFilter(xss);
 +  if (NS_FAILED(rv)) {
-+    return NS_OK;
++    return;
 +  }
 +
 +#ifdef PR_LOGGING
 +  PR_LOG(gXssPRLog, PR_LOG_DEBUG,
 +         ("XSS: Inserted XSSFilter at %p into principal %p", xss.get(), principal));
 +#endif
 +
-+  return NS_OK;
++  return;
 +}
 +
  void
  nsDocument::StopDocumentLoad()
  {
    if (mParser) {
      mParser->Terminate();
    }
  }
  
-@@ -2947,16 +3001,26 @@ nsDocument::SetBaseURI(nsIURI* aURI)
+@@ -2947,16 +3000,26 @@ nsDocument::SetBaseURI(nsIURI* aURI)
    if (aURI && mDocumentBaseURI) {
      bool equalBases = false;
      mDocumentBaseURI->Equals(aURI, &equalBases);
      if (equalBases) {
        return NS_OK;
      }
    }
  
-+  // xss check
++  // xss filter check
 +  nsRefPtr<nsXSSFilter> xss;
 +  nsresult rv = NodePrincipal()->GetXSSFilter(getter_AddRefs(xss));
 +  NS_ENSURE_SUCCESS(rv, rv);
 +  // only check if origin changed
 +  if (xss && !xss->PermitsBaseElement(mDocumentBaseURI, aURI)) {
-+    PR_LOG(gXssPRLog, PR_LOG_DEBUG, ("CSP blocked XSS <base> attack"));
++    PR_LOG(gXssPRLog, PR_LOG_DEBUG, ("XSS Filter blocked <base> attack"));
 +    return NS_OK;
 +  }
 +
    if (aURI) {
      mDocumentBaseURI = NS_TryToMakeImmutable(aURI);
    } else {
      mDocumentBaseURI = nsnull;
    }
@@ -912,17 +893,17 @@ diff --git a/content/base/src/nsDocument
    VisibilityState GetVisibilityState() const;
  
    void PostUnblockOnloadEvent();
    void DoUnblockOnload();
  
    nsresult CheckFrameOptions();
    nsresult InitCSP();
  
-+  nsresult InitXSS();
++  void InitXSSFilter();
 +
    /**
     * See if aDocument is a child of this.  If so, return the frame element in
     * this document that holds currentDoc (or an ancestor).
     */
    already_AddRefed<nsIDOMElement>
      CheckAncestryAndGetFrame(nsIDocument* aDocument) const;
  
@@ -969,17 +950,17 @@ diff --git a/content/base/src/nsObjectLo
  #endif
  
  #define LOG(args) PR_LOG(gObjectLog, PR_LOG_DEBUG, args)
  #define LOG_ENABLED() PR_LOG_TEST(gObjectLog, PR_LOG_DEBUG)
  
  #include "mozilla/Preferences.h"
  
  class nsAsyncInstantiateEvent : public nsRunnable {
-@@ -1256,16 +1258,34 @@ nsObjectLoadingContent::LoadObject(nsIUR
+@@ -1256,16 +1258,33 @@ nsObjectLoadingContent::LoadObject(nsIUR
                                  nsnull, //extra
                                  &shouldLoad,
                                  nsContentUtils::GetContentPolicy(),
                                  secMan);
      if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
        HandleBeingBlockedByContentPolicy(rv, shouldLoad);
        return NS_OK;
      }
@@ -988,19 +969,18 @@ diff --git a/content/base/src/nsObjectLo
 +    nsRefPtr<nsXSSFilter> xss;
 +    rv = doc->NodePrincipal()->GetXSSFilter(getter_AddRefs(xss));
 +    NS_ENSURE_SUCCESS(rv, rv);
 +
 +    if (xss) {
 +      PR_LOG(gXssPRLog, PR_LOG_DEBUG,
 +             ("nsObjectLoadingContent:XSSFilter:LoadObject"));
 +      if (!xss->PermitsExternalObject(aURI)) {
-+        PR_LOG(gXssPRLog, PR_LOG_DEBUG, ("XSSFilter blocked event handler."));
-+        // TODO: why are we not doing this?
-+        //HandleBeingBlockedByContentPolicy(rv, nsIContentPolicy::REJECT_SERVER);
++        PR_LOG(gXssPRLog, PR_LOG_DEBUG, ("XSSFilter blocked object loading."));
++        Fallback(false);
 +        return NS_OK;
 +      }
 +    }
 +
 +
    }
  
    nsresult rv = NS_ERROR_UNEXPECTED;
@@ -1068,17 +1048,17 @@ diff --git a/content/base/src/nsScriptLo
 +  nsRefPtr<nsXSSFilter> xss;
 +  rv = aDocument->NodePrincipal()->GetXSSFilter(getter_AddRefs(xss));
 +  NS_ENSURE_SUCCESS(rv, rv);
 +
 +  if (xss) {
 +    PR_LOG(gXssPRLog, PR_LOG_DEBUG, ("Scriptloader:XSSFilter:external"));
 +    if (!xss->PermitsExternalScript(aURI)) {
 +      PR_LOG(gXssPRLog, PR_LOG_DEBUG, ("XSSFilter blocked external script."));
-+      return NS_ERROR_FAILURE;
++      return NS_ERROR_XSS_BLOCK;
 +    }
 +  }
 +
    return NS_OK;
  }
  
  nsresult
  nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType)
@@ -1099,34 +1079,34 @@ diff --git a/content/base/src/nsScriptLo
 +  rv = mDocument->NodePrincipal()->GetXSSFilter(getter_AddRefs(xss));
 +  NS_ENSURE_SUCCESS(rv, rv);
 +  if (xss) {
 +    PR_LOG(gXssPRLog, PR_LOG_DEBUG, ("Scriptloader:XSSFilter:inline"));
 +    nsAutoString scriptText;
 +    aElement->GetScriptText(scriptText);
 +    if (!xss->PermitsInlineScript(scriptText)) {
 +      PR_LOG(gXssPRLog, PR_LOG_DEBUG, ("XSSFilter blocked inline script."));
-+      return NS_ERROR_FAILURE;
++      return NS_ERROR_XSS_BLOCK;
 +    }
 +  }
 +
 +
    request = new nsScriptLoadRequest(aElement, version);
    request->mJSVersion = version;
    request->mLoading = false;
    request->mIsInline = true;
    request->mURI = mDocument->GetDocumentURI();
    request->mLineNo = aElement->GetScriptLineNumber();
  
    if (aElement->GetParserCreated() == FROM_PARSER_XSLT &&
 diff --git a/content/base/src/nsXSSFilter.cpp b/content/base/src/nsXSSFilter.cpp
 new file mode 100644
 --- /dev/null
 +++ b/content/base/src/nsXSSFilter.cpp
-@@ -0,0 +1,566 @@
+@@ -0,0 +1,569 @@
 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 +/* ***** BEGIN LICENSE BLOCK *****
 + * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 + *
 + * The contents of this file are subject to the Mozilla Public License Version
 + * 1.1 (the "License"); you may not use this file except in compliance with
 + * the License. You may obtain a copy of the License at
 + * http://www.mozilla.org/MPL/
@@ -1221,16 +1201,17 @@ new file mode 100644
 +
 +nsXSSFilter::~nsXSSFilter()
 +{ }
 +
 +
 +void
 +nsXSSFilter::InitializeStatics()
 +{
++  nsXSSUtils::InitializeStatics();
 +  Preferences::AddBoolVarCache(&sXSSEnabled, "security.xssfilter.enabled");
 +  Preferences::AddBoolVarCache(&sReportOnly, "security.xssfilter.reportOnly");
 +  Preferences::AddBoolVarCache(&sBlockMode, "security.xssfilter.blockMode");
 +#ifdef PR_LOGGING
 +  if (!gXssPRLog)
 +    gXssPRLog = PR_NewLogModule("XSS");
 +#endif
 +  LOG_XSS("Initialized Statics for XSS Filter");
@@ -1253,18 +1234,20 @@ new file mode 100644
 +      ++pos;
 +  } else {
 +    while (pos != len && (str[pos] == '\t' || str[pos] == ' '))
 +      ++pos;
 +  }
 +  return pos != len;
 +}
 +
-+// Returns true if the function can match the whole token (case insensitive).
-+// Note: Might return pos == str.Length()
++/**
++ * Returns true if the function can match the whole token (case insensitive).
++ * Note: Might return pos == str.Length()
++ */
 +PRBool
 +skipToken(const nsACString& str, PRUint32& pos,
 +          const nsACString& token)
 +{
 +  PRUint32 len = str.Length();
 +  PRUint32 tokenPos = 0;
 +	PRUint32 tokenLen = token.Length();
 +
@@ -1286,17 +1269,17 @@ new file mode 100644
 +  }
 +  nsCOMPtr<nsIHttpChannel> httpChannel =
 +    do_QueryInterface(mParentDoc->GetChannel());
 +  if (!httpChannel) {
 +    return NS_ERROR_FAILURE;
 +  }
 +  LOG_XSS_CALL("ScanRequestData");
 +
-+  // Webkit logic:
++  // Webkit logic (the de facto standard we want to comply with):
 +  // 1. strip leading whitespaces.
 +  // 2. if the first char is 0, disable the filter
 +  // 3. if the first char is 1 enabled the filter
 +  // 4. if it is "1[ ]*mode[ ]*=[ ]*block$", then enabled in block mode
 +  // https://bugs.webkit.org/show_bug.cgi?id=27312
 +  nsCAutoString xssHeaderValue, strippedHeaderValue;
 +  httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("X-Xss-Protection"),
 +                                 xssHeaderValue);
@@ -1537,17 +1520,17 @@ new file mode 100644
 +  if (nsXSSUtils::HasAttack(GetParams())) {
 +    NotifyViolation("Data URL", NS_ConvertUTF8toUTF16(spec));
 +    return IsReportOnly();
 +  }
 +  return PR_TRUE;
 +}
 +
 +PRBool
-+nsXSSFilter::PermitsJSAction(const nsAString& aCode, XSSJSAction action)
++nsXSSFilter::PermitsJSAction(const nsAString& aCode)
 +{
 +  LOG_XSS_CALL("JSAction");
 +  LOG_XSS_1("JS: %s", NS_ConvertUTF16toUTF8(Substring(aCode, 0, 100)).get());
 +
 +  if (!IsEnabled()) {
 +    return PR_TRUE;
 +  }
 +
@@ -1833,17 +1816,17 @@ new file mode 100644
 +   * Checks whether a data URL that contains a script should be
 +   * executed. Lazy.
 +   */
 +  PRBool PermitsDataURL(nsIURI *aURI);
 +  /**
 +   * Checks whether the string argument from certain calls in
 +   * JavaScript (eval, setTimeout, setInterval) should be executed.
 +   */
-+  PRBool PermitsJSAction(const nsAString& code, XSSJSAction action);
++  PRBool PermitsJSAction(const nsAString& code);
 +
 +  /**
 +   * Sets up Observers for the static preferences described below.
 +   */
 +  static void InitializeStatics();
 +  /**
 +   * Synced to preference security.xssfilter.enabled
 +   * The filter allows all if this is set to false.
@@ -1930,17 +1913,17 @@ new file mode 100644
 +
 +
 +
 +#endif /* nsXSSFilter_h */
 diff --git a/content/base/src/nsXSSUtils.cpp b/content/base/src/nsXSSUtils.cpp
 new file mode 100644
 --- /dev/null
 +++ b/content/base/src/nsXSSUtils.cpp
-@@ -0,0 +1,1733 @@
+@@ -0,0 +1,1737 @@
 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 +/* ***** BEGIN LICENSE BLOCK *****
 + * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 + *
 + * The contents of this file are subject to the Mozilla Public License Version
 + * 1.1 (the "License"); you may not use this file except in compliance with
 + * the License. You may obtain a copy of the License at
 + * http://www.mozilla.org/MPL/
@@ -2192,19 +2175,21 @@ new file mode 100644
 +    nsXSSUtils::TrimSafeChars(params, params, QUERY_CHARS);
 +    LOG_XSS_1("POST escaped payload: %s",
 +              NS_ConvertUTF16toUTF8(params).get());
 +    if (!params.IsEmpty()) {
 +      aParams.AppendElement(Parameter(NS_LITERAL_STRING("POST"),
 +                                      params, PR_TRUE, PR_TRUE));
 +    }
 +  } else if(multipart && multipart < separator) {
-+    // TODO: this works, but it's not optimal: it would be
-+    // best to isolate the single parameters. this wastes at lot
-+    // of cpu power during the string matching.
++    // TODO: this works, but it's not optimal: it would be best to
++    // isolate the single parameters (and concatenate them in the
++    // paramarray). this wastes at lot of cpu power during the string
++    // matching to attempt matching data that is not under the control
++    // of the attacker (MIME boundaries)
 +    nsAutoString params;
 +    params.Assign(NS_ConvertASCIItoUTF16(separator+4));
 +
 +    LOG_XSS_1("MIME POST payload: %s",
 +              NS_ConvertUTF16toUTF8(params).get());
 +    if (!params.IsEmpty()) {
 +      aParams.AppendElement(Parameter(NS_LITERAL_STRING("MIMEPOST"),
 +                                          params, PR_TRUE, PR_TRUE));
@@ -2318,39 +2303,41 @@ new file mode 100644
 +
 +void
 +nsXSSUtils::InitializeStatics()
 +{
 +#ifdef PR_LOGGING
 +  gXssPRLog = PR_NewLogModule("XSS");
 +#endif
 +  LOG_XSS("Initialized Statics for XSS Utils");
-+
 +}
 +
 +PRBool
 +nsXSSUtils::FindInlineXSS(const nsAString& aParam, const nsAString& aScript)
 +{
 +  MatchRes mres;
-+  // TODO: cut the script to a maximum length
++    // the script could be cut for efficiency, but since there is a
++    // bound on the parameter length (which is usually a small number), it
++    // probably does not improve performance much.
 +  if (aParam.Length() >= aScript.Length()) {
 +    // base case where the attacker injects the whole script. Since
-+    // the tags/quotes are stripped, the script ends up being shorter.
++    // the tags/quotes are stripped by the parser, the script ends up
++    // being shorter.
 +    nsXSSUtils::P1FastMatchReverse(aParam, aScript, THRESHOLD, mres);
 +  } else if (aParam.Length() >= aScript.Length() * (1-THRESHOLD)) {
 +    // if we do not care about partial injections the only possible
 +    // case of |script| > |param| is due to sanitization increasing
 +    // the size of the script (e.g. add slashes). In this case, it
 +    // makes sense to match only if the length is close enough.
 +    nsXSSUtils::P1FastMatch(aParam, aScript, THRESHOLD, mres);
 +  }
 +  mres.ClearInvalidMatches(THRESHOLD);
 +
 +  for (PRUint32 i = 0; i < mres.elem_.Length(); i++) {
-+    LOG_XSS_2("Match in FindInlineXSS: %d %d\n", mres[i].matchBeg_,
++    LOG_XSS_2("Examining Match in FindInlineXSS: %d %d\n", mres[i].matchBeg_,
 +              mres[i].matchEnd_);
 +    // check: tainted string must not be at the beginning of the script
 +    if (mres[i].matchBeg_ == 0) {
 +      LOG_XSS("Match is at the beginning of script!");
 +      return PR_TRUE;
 +    }
 +  }
 +  return PR_FALSE;
@@ -2374,17 +2361,17 @@ new file mode 100644
 +    nsXSSUtils::P1FastMatch(aParam, url, THRESHOLD, mres);
 +  }
 +  mres.ClearInvalidMatches(THRESHOLD);
 +  PRUint32 safeIndex = GetHostLimit(aURI);
 +  for (PRUint32 i = 0; i < mres.Length(); i++) {
 +    LOG_XSS_2("Match in FindExternalXSS: %d %d\n", mres[i].matchBeg_,
 +              mres[i].matchEnd_);
 +    if (mres[i].matchBeg_  < safeIndex) {
-+      LOG_XSS("Match controls host");
++      LOG_XSS("Match controls host portion");
 +      return PR_TRUE;
 +    }
 +  }
 +  return PR_FALSE;
 +}
 +
 +nsresult
 +nsXSSUtils::CheckInline(const nsAString& aScript, ParameterArray& aParams)
@@ -4069,17 +4056,17 @@ diff --git a/content/base/test/Makefile.
  XPCSHELL_TESTS = \
                 unit \
                 $(NULL)
  # FIXME/bug 575918: out-of-process xpcshell is broken on OS X
  ifneq ($(OS_ARCH),Darwin)
  XPCSHELL_TESTS += unit_ipc
  endif
  
-@@ -537,16 +537,22 @@ _TEST_FILES2 = \
+@@ -537,16 +537,22 @@ include $(topsrcdir)/config/rules.mk
  		test_bug707142.html \
  		file_bug707142_baseline.json \
  		file_bug707142_bom.json \
  		file_bug707142_utf-16.json \
  		test_reentrant_flush.html \
  		test_bug708620.html \
  		file_bug708620.html \
  		file_bug708620-2.html \
@@ -4841,87 +4828,84 @@ diff --git a/content/events/src/nsEventL
    mNoListenerForEventAtom = nsnull;
  
    ls = mListeners.AppendElement();
    ls->mListener = aListener;
    ls->mEventType = aType;
    ls->mTypeAtom = aTypeAtom;
    ls->mFlags = aFlags;
    ls->mHandlerIsString = false;
-+  ls->mXSSHandlerWasString = PR_FALSE;
-+  ls->mXSSChecked = PR_FALSE;
-+  ls->mXSSResult = PR_TRUE;
++  ls->mXSSHandlerWasString = false;
++  ls->mXSSChecked = false;
++  ls->mXSSResult = true;
  
    if (aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) {
      mMayHaveSystemGroupListeners = true;
    }
    if (aFlags & NS_EVENT_FLAG_CAPTURE) {
      mMayHaveCapturingListeners = true;
    }
  
-@@ -416,16 +431,18 @@ nsEventListenerManager::SetJSEventListen
+@@ -416,16 +431,19 @@ nsEventListenerManager::SetJSEventListen
      }
    } else {
      ls->GetJSListener()->SetHandler(aHandler);
    }
  
    if (NS_SUCCEEDED(rv) && ls) {
      // Set flag to indicate possible need for compilation later
      ls->mHandlerIsString = !aHandler;
++    // we only care about handlers that were strings at some point in time.
 +    ls->mXSSHandlerWasString |= !aHandler;
 +
      if (aPermitUntrustedEvents) {
        ls->mFlags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED;
      }
  
      *aListenerStruct = ls;
    } else {
      *aListenerStruct = nsnull;
    }
-@@ -517,16 +534,39 @@ nsEventListenerManager::AddScriptEventLi
+@@ -517,16 +535,35 @@ nsEventListenerManager::AddScriptEventLi
          scriptSample.AppendLiteral(" element");
          csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_SCRIPT,
                                   NS_ConvertUTF8toUTF16(asciiSpec),
                                   scriptSample,
                                   nsnull);
          return NS_OK;
        }
      }
 +
 +    // NOTE: if it's onload, we need to check now because it does not
 +    // go through handleevent later. why?
-+    nsAutoString attr;
-+    aName->ToString(attr);
-+    if (attr.EqualsLiteral("onload")) {
-+      nsRefPtr<nsXSSFilter> xss;
-+      rv = doc->NodePrincipal()->GetXSSFilter(getter_AddRefs(xss));
-+      NS_ENSURE_SUCCESS(rv, rv);
-+
-+      if (xss) {
-+        PR_LOG(gXssPRLog, PR_LOG_DEBUG,
-+               ("XSS:Onload:check"));
-+        if (!xss->PermitsEventListener(aBody)) {
-+          PR_LOG(gXssPRLog, PR_LOG_DEBUG,
-+                 ("XSS:Onload:blocked onload event"));
-+          return NS_OK;
-+        }
-+      }
-+
-+    }
-+
++    // if (aName == nsGkAtoms::onload) {
++    //   nsRefPtr<nsXSSFilter> xss;
++    //   rv = doc->NodePrincipal()->GetXSSFilter(getter_AddRefs(xss));
++    //   NS_ENSURE_SUCCESS(rv, rv);
++
++    //   if (xss) {
++    //     PR_LOG(gXssPRLog, PR_LOG_DEBUG,
++    //            ("XSS:Onload:check"));
++    //     if (!xss->PermitsEventListener(aBody)) {
++    //       PR_LOG(gXssPRLog, PR_LOG_DEBUG,
++    //              ("XSS:Onload:blocked onload event"));
++    //       return NS_ERROR_FAILURE;
++    //     }
++    //   }
++    // }
 +
    }
  
    // This might be the first reference to this language in the global
    // We must init the language before we attempt to fetch its context.
    if (NS_FAILED(global->EnsureScriptEnvironment(aLanguage))) {
      NS_WARNING("Failed to setup script environment for this language");
      // but fall through and let the inevitable failure below handle it.
    }
-@@ -725,24 +765,100 @@ nsEventListenerManager::HandleEventSubTy
+@@ -725,24 +762,103 @@ nsEventListenerManager::HandleEventSubTy
      nsIJSEventListener *jslistener = aListenerStruct->GetJSListener();
      result = CompileEventHandlerInternal(aListenerStruct,
                                           jslistener->GetEventContext() !=
                                             aPusher->GetCurrentScriptContext(),
                                           nsnull);
    }
  
    if (NS_SUCCEEDED(result)) {
@@ -4937,82 +4921,85 @@ diff --git a/content/events/src/nsEventL
    }
  
    return result;
  }
  
  /**
 + * lazy check with the xss filter.
 + */
-+PRBool
++bool
 +nsEventListenerManager::IsEventXSS(nsListenerStruct *aListenerStruct,
 +                                   nsPIDOMEventTarget* aCurrentTarget)
 +{
 +  // only makes sense to check string-based events
 +  if (!aListenerStruct->mXSSHandlerWasString) {
-+    return PR_FALSE;
++    return false;
 +  }
 +  // recycle result
 +  if (aListenerStruct->mXSSChecked) {
 +    PR_LOG(gXssPRLog, PR_LOG_DEBUG,
 +           ("CheckEventForXSS:has previous result"));
 +    return aListenerStruct->mXSSResult;
 +  }
 +
 +  // 1. xss filter
 +  nsIDocument* doc = nsnull;
 +  nsCOMPtr<nsINode> node = do_QueryInterface(aCurrentTarget);
 +  if (!node) {
 +    PR_LOG(gXssPRLog, PR_LOG_DEBUG,
 +           ("CheckEventForXSS:no node"));
-+    return PR_FALSE;
++    nsCOMPtr<nsIWindow
++    return false;
 +  }
-+  doc = node->GetOwnerDocument();
-+  nsIPrincipal* principal = doc->NodePrincipal();
++  nsIPrincipal* principal = node->NodePrincipal();
 +  if (!principal) {
 +    PR_LOG(gXssPRLog, PR_LOG_DEBUG,
 +           ("CheckEventForXSS:no principal"));
-+    return PR_FALSE;
++    return false;
 +  }
 +  nsRefPtr<nsXSSFilter> xss;
-+  nsresult rv = principal->GetXSSFilter(getter_AddRefs(xss));
++  principal->GetXSSFilter(getter_AddRefs(xss));
 +  if (!xss) {
-+    return PR_FALSE;
++    return false;
 +  }
 +  // 2. event body
 +  nsCOMPtr<nsIJSEventListener> jslistener =
 +    do_QueryInterface(aListenerStruct->mListener);
 +  if (!jslistener) {
 +    PR_LOG(gXssPRLog, PR_LOG_DEBUG,
 +           ("CheckEventForXSS:no nsIJSEventListener"));
-+    return PR_FALSE;
++    return false;
 +  }
 +  nsCOMPtr<nsIContent> content =
 +    do_QueryInterface(jslistener->GetEventTarget());
 +  if (!content) {
 +    PR_LOG(gXssPRLog, PR_LOG_DEBUG,
 +           ("CheckEventForXSS:no content"));
-+    return PR_FALSE;
++    return false;
 +  }
 +  nsAutoString handlerBody;
 +  PR_LOG(gXssPRLog, PR_LOG_DEBUG,
 +         ("CheckEventForXSS:content && doc"));
-+  content->GetAttr(kNameSpaceID_None, aListenerStruct->mTypeAtom, handlerBody);
-+  NS_ENSURE_SUCCESS(rv, rv);
++  nsresult rv = content->GetAttr(kNameSpaceID_None, aListenerStruct->mTypeAtom, handlerBody);
++  if (NS_FAILED(rv)) {
++    NS_ERROR("Failed to retrieve attribute value for xss check");
++    return false;
++  }
++
 +  // 3. actual check
++  aListenerStruct->mXSSChecked = true;
 +  if (!xss->PermitsEventListener(handlerBody)) {
 +    PR_LOG(gXssPRLog, PR_LOG_DEBUG,
 +           ("CheckEventForXSS:XSSFilter blocked event handler."));
-+    aListenerStruct->mXSSChecked = PR_TRUE;
-+    aListenerStruct->mXSSResult = PR_TRUE;
-+    return PR_TRUE;
++    aListenerStruct->mXSSResult = true;
++    return true;
 +  }
-+  aListenerStruct->mXSSChecked = PR_TRUE;
-+  aListenerStruct->mXSSResult = PR_FALSE;
-+  return PR_FALSE;
++  aListenerStruct->mXSSResult = false;
++  return false;
 +}
 +
 +/**
  * Causes a check for event listeners and processing by them if they exist.
  * @param an event listener
  */
  
  void
@@ -5048,18 +5035,18 @@ diff --git a/content/events/src/nsEventL
  
    static PRUint32                           mInstanceCount;
    static jsid                               sAddListenerID;
  
    friend class nsEventTargetChainItem;
    static PRUint32                           sCreatedCount;
 +
 +private:
-+  static PRBool IsEventXSS(nsListenerStruct* aListenerStruct,
-+                           nsPIDOMEventTarget* aCurrentTarget);
++  static bool IsEventXSS(nsListenerStruct* aListenerStruct,
++                         nsPIDOMEventTarget* aCurrentTarget);
  };
  
  /**
   * NS_AddSystemEventListener() is a helper function for implementing
   * nsIDOMEventTarget::AddSystemEventListener().
   */
  inline nsresult
  NS_AddSystemEventListener(nsIDOMEventTarget* aTarget,
@@ -5254,35 +5241,34 @@ diff --git a/dom/base/nsJSTimeoutHandler
        if (!str)
          return NS_ERROR_OUT_OF_MEMORY;
  
        expr = ::JS_FlattenString(cx, str);
        if (!expr)
            return NS_ERROR_OUT_OF_MEMORY;
  
        argv[0] = STRING_TO_JSVAL(str);
-@@ -301,16 +303,32 @@ nsJSScriptTimeoutHandler::Init(nsGlobalW
+@@ -301,16 +303,31 @@ nsJSScriptTimeoutHandler::Init(nsGlobalW
          if (!allowsEval) {
            ::JS_ReportError(cx, "call to %s blocked by CSP",
                              *aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
  
            // Note: Our only caller knows to turn NS_ERROR_DOM_TYPE_ERR into NS_OK.
            return NS_ERROR_DOM_TYPE_ERR;
          }
        }
 +      nsRefPtr<nsXSSFilter> xss;
 +      rv = doc->NodePrincipal()->GetXSSFilter(getter_AddRefs(xss));
 +      NS_ENSURE_SUCCESS(rv, rv);
 +
 +      if (xss) {
 +        //xss settimeout
-+        nsDependentJSString nsStr;
-+        nsStr.init(cx, str);
-+        XSSJSAction t = xss_timeout;
-+        if (!xss->PermitsJSAction(nsStr, t)) {
++        nsDependentJSString ns_str;
++        ns_str.init(cx, str);
++        if (!xss->PermitsJSAction(ns_str)) {
 +          ::JS_ReportError(cx, "call to %s blocked by XSS Filter",
 +                           *aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
 +          return NS_ERROR_DOM_TYPE_ERR;
 +        }
 +      }
 +
      } // if there's no document, we don't have to do anything.
  
@@ -5462,42 +5448,41 @@ diff --git a/js/src/js.msg b/js/src/js.m
  MSG_DEF(JSMSG_CANT_WATCH_PROP,        287, 0, JSEXN_TYPEERR, "properties whose names are objects can't be watched")
  MSG_DEF(JSMSG_CSP_BLOCKED_EVAL,       288, 0, JSEXN_ERR, "call to eval() blocked by CSP")
  MSG_DEF(JSMSG_DEBUG_NO_SCOPE_OBJECT,  289, 0, JSEXN_TYPEERR, "declarative Environments don't have binding objects")
  MSG_DEF(JSMSG_EMPTY_CONSEQUENT,       290, 0, JSEXN_SYNTAXERR, "mistyped ; after conditional?")
 +MSG_DEF(JSMSG_XSS_BLOCKED_FUNCTION,   291, 0, JSEXN_ERR, "call to Function() blocked by XSS Filter")
 diff --git a/js/src/jsapi.h b/js/src/jsapi.h
 --- a/js/src/jsapi.h
 +++ b/js/src/jsapi.h
-@@ -1542,16 +1542,24 @@ typedef JSPrincipals *
+@@ -1542,16 +1542,23 @@ typedef JSPrincipals *
  /*
   * Used to check if a CSP instance wants to disable eval() and friends.
   * See js_CheckCSPPermitsJSAction() in jsobj.
   */
  typedef JSBool
  (* JSCSPEvalChecker)(JSContext *cx);
  
  /*
 + * Used to check if an xss filter wants to disable eval() and friends.
 + * See js_CheckXSSPermitsJSAction() in jsobj.
 + */
-+enum XSSJSAction { xss_eval, xss_timeout, xss_function };
 +typedef JSBool
-+(* JSXSSFilterChecker)(JSContext *cx, JSString *str, enum XSSJSAction action);
++(* JSXSSFilterChecker)(JSContext *cx, JSString *str);
 +
 +/*
   * Callback used to ask the embedding for the cross compartment wrapper handler
   * that implements the desired prolicy for this kind of object in the
   * destination compartment.
   */
  typedef JSObject *
  (* JSWrapObjectCallback)(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent,
                           uintN flags);
  
-@@ -4194,16 +4202,17 @@ JS_DropPrincipals(JSContext *cx, JSPrinc
+@@ -4194,16 +4201,17 @@ JS_DropPrincipals(JSContext *cx, JSPrinc
  #endif
  
  
  struct JSSecurityCallbacks {
      JSCheckAccessOp            checkObjectAccess;
      JSPrincipalsTranscoder     principalsTranscoder;
      JSObjectPrincipalsFinder   findObjectPrincipals;
      JSCSPEvalChecker           contentSecurityPolicyAllows;
@@ -5527,60 +5512,58 @@ diff --git a/js/src/jsfun.cpp b/js/src/j
  using namespace mozilla;
  using namespace js;
  using namespace js::gc;
  using namespace js::types;
  
  inline JSObject *
  JSObject::getThrowTypeError() const
  {
-@@ -2056,16 +2058,26 @@ Function(JSContext *cx, uintN argc, Valu
+@@ -2056,16 +2058,25 @@ Function(JSContext *cx, uintN argc, Valu
  
      if (args.length()) {
          JSString *str = ToString(cx, args[args.length() - 1]);
          if (!str)
              return false;
          strAnchor.set(str);
          chars = str->getChars(cx);
          length = str->length();
 +        JSSecurityCallbacks *callbacks = JS_GetSecurityCallbacks(cx);
 +        // this callback is not always defined
 +        if (callbacks && callbacks->xssFilterAllows) {
-+            XSSJSAction f = xss_function;
-+            if (!callbacks->xssFilterAllows(cx, str, f)) {
++            if (!callbacks->xssFilterAllows(cx, str)) {
 +                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
 +                                     JSMSG_XSS_BLOCKED_FUNCTION);
 +                return JS_FALSE;
 +            }
 +        }
      } else {
          chars = cx->runtime->emptyString->chars();
          length = 0;
      }
  
      /*
       * NB: (new Function) is not lexically closed by its caller, it's just an
       * anonymous function in the top-level scope that its constructor inhabits.
 diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp
 --- a/js/src/jsobj.cpp
 +++ b/js/src/jsobj.cpp
-@@ -1145,16 +1145,27 @@ EvalKernel(JSContext *cx, const CallArgs
+@@ -1145,16 +1145,26 @@ EvalKernel(JSContext *cx, const CallArgs
          return true;
      }
      if (!args[0].isString()) {
          args.rval() = args[0];
          return true;
      }
      JSString *str = args[0].toString();
  
 +    // xss filter
 +    JSSecurityCallbacks *callbacks = JS_GetSecurityCallbacks(cx);
 +    if (callbacks && callbacks->xssFilterAllows) {
-+        XSSJSAction e = xss_eval;
-+        if (!callbacks->xssFilterAllows(cx, str, e)) {
++        if (!callbacks->xssFilterAllows(cx, str)) {
 +            JS_ReportError(cx, "call to eval() is an xss attack");
 +            return false;
 +        }
 +    }
 +
 +
      /* ES5 15.1.2.1 steps 2-8. */
  
@@ -5681,46 +5664,44 @@ diff --git a/layout/build/nsLayoutModule
    { NS_CHILDPROCESSMESSAGEMANAGER_CONTRACTID, &kNS_CHILDPROCESSMESSAGEMANAGER_CID },
    { NSCHANNELPOLICY_CONTRACTID, &kNSCHANNELPOLICY_CID },
    { NS_SCRIPTSECURITYMANAGER_CONTRACTID, &kNS_SCRIPTSECURITYMANAGER_CID },
    { NS_GLOBAL_CHANNELEVENTSINK_CONTRACTID, &kNS_SCRIPTSECURITYMANAGER_CID },
    { NS_PRINCIPAL_CONTRACTID, &kNS_PRINCIPAL_CID },
 diff --git a/layout/build/nsLayoutStatics.cpp b/layout/build/nsLayoutStatics.cpp
 --- a/layout/build/nsLayoutStatics.cpp
 +++ b/layout/build/nsLayoutStatics.cpp
-@@ -122,16 +122,19 @@
+@@ -122,16 +122,18 @@
  #include "nsFrameMessageManager.h"
  #include "nsRefreshDriver.h"
  
  #include "nsHyphenationManager.h"
  #include "nsEditorSpellCheck.h"
  #include "nsDOMMemoryReporter.h"
  #include "mozilla/dom/sms/SmsRequestManager.h"
  
-+#include "nsXSSUtils.h"
 +#include "nsXSSFilter.h"
 +
  extern void NS_ShutdownChainItemPool();
  
  using namespace mozilla;
  using namespace mozilla::dom;
  
  nsrefcnt nsLayoutStatics::sLayoutStaticRefcnt = 0;
  
  nsresult
-@@ -259,16 +262,19 @@ nsLayoutStatics::Initialize()
+@@ -259,16 +261,18 @@ nsLayoutStatics::Initialize()
  #endif
  
    nsContentSink::InitializeStatics();
    nsHtml5Module::InitializeStatics();
    nsLayoutUtils::Initialize();
    nsIPresShell::InitializeStatics();
    nsRefreshDriver::InitializeStatics();
  
-+  nsXSSUtils::InitializeStatics();
 +  nsXSSFilter::InitializeStatics();
 +
    nsCORSListenerProxy::Startup();
  
    nsFrameList::Init();
  
    NS_SealStaticAtomTable();
  
@@ -5915,17 +5896,17 @@ diff --git a/netwerk/protocol/data/nsDat
 +        nsRefPtr<nsXSSFilter> xss;
 +        rv = principal->GetXSSFilter(getter_AddRefs(xss));
 +        NS_ENSURE_SUCCESS(rv, rv);
 +        if (xss) {
 +            // TODO: some of these might not be scripts! do we want to
 +            // whitelist static content such as images?
 +            if (!xss->PermitsDataURL(URI())) {
 +                PR_LOG(gXssPRLog, PR_LOG_DEBUG, ("XSS in data URL"));
-+                return NS_ERROR_NOT_INITIALIZED;
++                return NS_ERROR_FAILURE;
 +            }
 +        }
 +    }
 +
      nsCAutoString spec;
      rv = URI()->GetAsciiSpec(spec);
      if (NS_FAILED(rv)) return rv;