Bug 375314 - discriminate ping and xmlhttprequests in content policy check. Patch by Wladimir Palant <trev.moz@adblockplus.org>, r=jst, sr=peterv.
authorkherron@fmailbox.com
Sun, 17 Jun 2007 06:50:50 -0700
changeset 2501 3af04d3b0c7e1eb387ebe568d5fb425da6f8c941
parent 2500 bb5dccb429596cfb494e8534c24f2db1bc458673
child 2502 e563340d2f71e38fd86c45109d5bd99940e5bbd8
push id1
push userbsmedberg@mozilla.com
push dateThu, 20 Mar 2008 16:49:24 +0000
treeherdermozilla-central@61007906a1f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjst, peterv
bugs375314
milestone1.9a6pre
Bug 375314 - discriminate ping and xmlhttprequests in content policy check. Patch by Wladimir Palant <trev.moz@adblockplus.org>, r=jst, sr=peterv.
content/base/public/nsContentPolicyUtils.h
content/base/public/nsIContentPolicy.idl
content/base/src/nsNoDataProtocolContentPolicy.cpp
content/base/src/nsXMLHttpRequest.cpp
content/base/test/Makefile.in
content/base/test/test_bug375314.html
content/xbl/src/nsXBLService.cpp
docshell/base/nsWebShell.cpp
extensions/permissions/nsContentBlocker.cpp
extensions/permissions/nsContentBlocker.h
modules/plugin/base/src/nsPluginHostImpl.cpp
--- a/content/base/public/nsContentPolicyUtils.h
+++ b/content/base/public/nsContentPolicyUtils.h
@@ -117,25 +117,29 @@ NS_CP_ResponseName(PRInt16 response)
  *
  * @param contentType the content type code
  * @return the name of the given content type code
  */
 inline const char *
 NS_CP_ContentTypeName(PRUint32 contentType)
 {
   switch (contentType) {
-    CASE_RETURN( TYPE_OTHER      );
-    CASE_RETURN( TYPE_SCRIPT     );
-    CASE_RETURN( TYPE_IMAGE      );
-    CASE_RETURN( TYPE_STYLESHEET );
-    CASE_RETURN( TYPE_OBJECT     );
-    CASE_RETURN( TYPE_DOCUMENT   );
-    CASE_RETURN( TYPE_SUBDOCUMENT);
-    CASE_RETURN( TYPE_REFRESH    );
-  default:
+    CASE_RETURN( TYPE_OTHER             );
+    CASE_RETURN( TYPE_SCRIPT            );
+    CASE_RETURN( TYPE_IMAGE             );
+    CASE_RETURN( TYPE_STYLESHEET        );
+    CASE_RETURN( TYPE_OBJECT            );
+    CASE_RETURN( TYPE_DOCUMENT          );
+    CASE_RETURN( TYPE_SUBDOCUMENT       );
+    CASE_RETURN( TYPE_REFRESH           );
+    CASE_RETURN( TYPE_XBL               );
+    CASE_RETURN( TYPE_PING              );
+    CASE_RETURN( TYPE_XMLHTTPREQUEST    );
+    CASE_RETURN( TYPE_OBJECT_SUBREQUEST );
+   default:
     return "<Unknown Type>";
   }
 }
 
 #endif // defined(PR_LOGGING)
 
 #undef CASE_RETURN
 
--- a/content/base/public/nsIContentPolicy.idl
+++ b/content/base/public/nsIContentPolicy.idl
@@ -46,17 +46,17 @@ interface nsIDOMNode;
  * Interface for content policy mechanism.  Implementations of this
  * interface can be used to control loading of various types of out-of-line
  * content, or processing of certain types of in-line content.
  *
  * WARNING: do not block the caller from shouldLoad or shouldProcess (e.g.,
  * by launching a dialog to prompt the user for something).
  */
 
-[scriptable,uuid(3bb1a3c8-3073-41e0-9a26-a7671955fb65)]
+[scriptable,uuid(a32a984a-7a6b-ea92-75fe-1166be801a0e)]
 interface nsIContentPolicy : nsISupports
 {
   const unsigned long TYPE_OTHER       = 1;
 
   /**
    * Indicates an executable script (such as JavaScript).
    */
   const unsigned long TYPE_SCRIPT      = 2;
@@ -95,16 +95,36 @@ interface nsIContentPolicy : nsISupports
    * to be loaded (the actual load triggered by the refresh will go through
    * shouldLoad as expected).
    *
    * shouldProcess will get this for, e.g., META Refresh elements and HTTP
    * Refresh headers.
    */
   const unsigned long TYPE_REFRESH     = 8;
 
+  /**
+   * Indicates an XBL binding request, triggered either by -moz-binding CSS
+   * property or Document.addBinding method.
+   */
+  const unsigned long TYPE_XBL         = 9;
+
+  /**
+   * Indicates a ping triggered by a click on <A PING="..."> element.
+   */
+  const unsigned long TYPE_PING        = 10;
+
+  /**
+   * Indicates an XMLHttpRequest.
+   */
+  const unsigned long TYPE_XMLHTTPREQUEST = 11;
+
+  /**
+   * Indicates a request by a plugin.
+   */
+  const unsigned long TYPE_OBJECT_SUBREQUEST = 12;
 
   //////////////////////////////////////////////////////////////////////
 
   /**
    * Returned from shouldLoad or shouldProcess if the load or process request
    * is rejected based on details of the request.
    */
   const short REJECT_REQUEST = -1;
--- a/content/base/src/nsNoDataProtocolContentPolicy.cpp
+++ b/content/base/src/nsNoDataProtocolContentPolicy.cpp
@@ -62,20 +62,19 @@ nsNoDataProtocolContentPolicy::ShouldLoa
                                           const nsACString &aMimeGuess,
                                           nsISupports *aExtra,
                                           PRInt16 *aDecision)
 {
   *aDecision = nsIContentPolicy::ACCEPT;
 
   // Don't block for TYPE_OBJECT since such URIs are sometimes loaded by the
   // plugin, so they don't neccesarily open external apps
-  if (aContentType == TYPE_OTHER ||
-      aContentType == TYPE_SCRIPT ||
-      aContentType == TYPE_IMAGE ||
-      aContentType == TYPE_STYLESHEET) {
+  if (aContentType != TYPE_DOCUMENT &&
+      aContentType != TYPE_SUBDOCUMENT &&
+      aContentType != TYPE_OBJECT) {
     nsCAutoString scheme;
     aContentLocation->GetScheme(scheme);
     // Fast-track for the common cases
     if (scheme.EqualsLiteral("http") ||
         scheme.EqualsLiteral("https") ||
         scheme.EqualsLiteral("ftp") ||
         scheme.EqualsLiteral("file") ||
         scheme.EqualsLiteral("chrome")) {
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -1039,17 +1039,17 @@ nsXMLHttpRequest::OpenRequest(const nsAC
 
   rv = NS_NewURI(getter_AddRefs(uri), url, nsnull, GetBaseURI());
   if (NS_FAILED(rv)) return rv;
 
   // mScriptContext should be initialized because of GetBaseURI() above.
   // Still need to consider the case that doc is nsnull however.
   nsCOMPtr<nsIDocument> doc = GetDocumentFromScriptContext(mScriptContext);
   PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
-  rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OTHER,
+  rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_XMLHTTPREQUEST,
                                  uri,
                                  (doc ? doc->GetDocumentURI() : nsnull),
                                  doc,
                                  EmptyCString(), //mime guess
                                  nsnull,         //extra
                                  &shouldLoad);
   if (NS_FAILED(rv)) return rv;
   if (NS_CP_REJECTED(shouldLoad)) {
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -77,12 +77,13 @@ include $(topsrcdir)/config/rules.mk
 		test_bug367164.html \
 		test_bug371576-1.html \
 		test_bug371576-2.html \
 		test_bug371576-3.html \
 		test_bug371576-4.html \
 		test_bug371576-5.html \
 		test_bug372086.html \
 		test_bug373181.xhtml \
+		test_bug375314.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $^ $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug375314.html
@@ -0,0 +1,197 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=375314
+-->
+<head>
+  <title>Test for Bug 375314</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=375314">Mozilla Bug 375314</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 375314 **/
+
+netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+var lastContentType = -1;
+const testURL = window.location.href + "/this/is/the/test/url";
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+// Content policy / factory implementation for the test
+var policyID = Components.ID("{b80e19d0-878f-d41b-2654-194714a4115c}");
+var policyName = "@mozilla.org/testpolicy;1";
+var policy = {
+  // nsISupports implementation
+  QueryInterface: function(iid) {
+    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+    if (iid.equals(Ci.nsISupports) ||
+        iid.equals(Ci.nsIFactory) ||
+        iid.equals(Ci.nsIContentPolicy))
+      return this;
+
+    throw Components.results.NS_ERROR_NO_INTERFACE;
+  },
+
+  // nsIFactory implementation
+  createInstance: function(outer, iid) {
+    return this.QueryInterface(iid);
+  },
+
+  // nsIContentPolicy implementation
+  shouldLoad: function(contentType, contentLocation, requestOrigin, context, mimeTypeGuess, extra) {
+    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+    // Remember last content type seen for the test url
+    if (contentLocation.spec == testURL) {
+      lastContentType = contentType;
+      return Ci.nsIContentPolicy.REJECT_REQUEST;
+    }
+
+    return Ci.nsIContentPolicy.ACCEPT;
+  },
+
+  shouldProcess: function(contentType, contentLocation, requestOrigin, context, mimeTypeGuess, extra) {
+    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+    return Ci.nsIContentPolicy.ACCEPT;
+  }
+}
+
+// Register content policy
+var componentManager = Components.manager
+                                 .QueryInterface(Ci.nsIComponentRegistrar);
+componentManager.registerFactory(policyID, "Test content policy", policyName, policy);
+
+var categoryManager = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
+categoryManager.addCategoryEntry("content-policy", policyName, policyName, false, true);
+
+// Try creating different request types
+var tests = ["SCRIPT", "IMAGE", "STYLESHEET", "OBJECT", "DOCUMENT", "SUBDOCUMENT", "XBL", "PING", "XMLHTTPREQUEST"];
+var curTest = -1;
+
+SimpleTest.waitForExplicitFinish();
+setTimeout(runNextTest, 0);
+
+function runNextTest() {
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+  if (curTest >= 0) {
+    var type = "TYPE_" + tests[curTest];
+    is(lastContentType, Ci.nsIContentPolicy[type], "Content policies triggered for " + type);
+  }
+
+  curTest++;
+  if (curTest < tests.length) {
+    var method = "request_" + tests[curTest].toLowerCase();
+    try {
+      window[method]();
+    } catch(e) {}
+    setTimeout(runNextTest, 0);
+  }
+  else {
+    // Unregister content policy
+    categoryManager.deleteCategoryEntry("content-policy", policyName, false);
+
+    setTimeout(function() {
+      // Component must be unregistered delayed, otherwise other content
+      // policy will not be removed from the category correctly
+      netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+      componentManager.unregisterFactory(policyID, policy);
+    }, 0);
+
+    SimpleTest.finish();
+  }
+}
+
+// Request creating functions
+
+function request_script() {
+  var content = $("content");
+
+  var script = document.createElement("script");
+  script.setAttribute("type", "text/javascript")
+  script.setAttribute("src", testURL)
+  content.appendChild(script);
+}
+
+function request_image() {
+  var content = $("content");
+
+  var image = new Image();
+  image.src = testURL;
+}
+
+function request_stylesheet() {
+  var content = $("content");
+
+  var stylesheet = document.createElement("link");
+  stylesheet.setAttribute("rel", "stylesheet");
+  stylesheet.setAttribute("type", "text/css");
+  stylesheet.setAttribute("href", testURL);
+  content.appendChild(stylesheet);
+}
+
+function request_object() {
+  var content = $("content");
+
+  var object = document.createElement("embed");
+  object.setAttribute("src", testURL);
+  content.appendChild(object);
+}
+
+function request_document() {
+  top.location.href = testURL;
+}
+
+function request_subdocument() {
+  var content = $("content");
+
+  var frame = document.createElement("iframe");
+  frame.setAttribute("src", testURL);
+  content.appendChild(frame);
+}
+
+function request_xbl() {
+  var content = $("content");
+
+  var div = document.createElement("div");
+  content.appendChild(div);
+
+  document.addBinding(div, testURL);
+}
+
+function request_ping() {
+  var content = $("content");
+
+  var a = document.createElement("a");
+  a.setAttribute("href", "javascript:void(0)");
+  a.setAttribute("ping", testURL);
+  content.appendChild(a);
+
+  var event = document.createEvent("MouseEvents");
+  event.initMouseEvent("click", true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
+  a.dispatchEvent(event);
+}
+
+function request_xmlhttprequest() {
+  var request = new XMLHttpRequest();
+  request.open("GET", testURL, false);
+  request.send(null);
+}
+
+</script>
+</pre>
+</body>
+</html>
+
--- a/content/xbl/src/nsXBLService.cpp
+++ b/content/xbl/src/nsXBLService.cpp
@@ -529,17 +529,17 @@ nsXBLService::LoadBindings(nsIContent* a
   // any. Since we're not done loading this binding yet, that will reenter
   // this method and we'll end up creating a binding and then immediately
   // clobbering it in our table.  That makes things very confused, leading to
   // misbehavior and crashes.
   rv = nsContentUtils::CheckSecurityBeforeLoad(aURL,
                                                document->NodePrincipal(),
                                                nsIScriptSecurityManager::ALLOW_CHROME,
                                                PR_TRUE,
-                                               nsIContentPolicy::TYPE_OTHER,
+                                               nsIContentPolicy::TYPE_XBL,
                                                document);
   NS_ENSURE_SUCCESS(rv, rv);
 
   PRBool ready;
   nsRefPtr<nsXBLBinding> newBinding;
   if (NS_FAILED(rv = GetBinding(aContent, aURL, PR_FALSE, &ready,
                                 getter_AddRefs(newBinding)))) {
     return rv;
@@ -966,17 +966,17 @@ nsXBLService::LoadBindingDocumentInfo(ns
   NS_PRECONDITION(aBindingURI, "Must have a binding URI");
   
   nsresult rv;
   if (aBoundDocument) {
     rv = nsContentUtils::
       CheckSecurityBeforeLoad(aBindingURI, aBoundDocument->NodePrincipal(),
                               nsIScriptSecurityManager::ALLOW_CHROME,
                               PR_TRUE,
-                              nsIContentPolicy::TYPE_OTHER,
+                              nsIContentPolicy::TYPE_XBL,
                               aBoundDocument);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   *aResult = nsnull;
   nsCOMPtr<nsIXBLDocumentInfo> info;
 
   nsCOMPtr<nsIURI> documentURI;
--- a/docshell/base/nsWebShell.cpp
+++ b/docshell/base/nsWebShell.cpp
@@ -220,17 +220,17 @@ CheckPingURI(nsIURI* uri, nsIContent* co
 
   // Check with contentpolicy
   PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
   nsIURI* docURI = nsnull;
   nsIDocument* doc = content->GetOwnerDoc();
   if (doc) {
     docURI = doc->GetDocumentURI();
   }
-  rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OTHER,
+  rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_PING,
                                  uri,
                                  docURI,
                                  content,
                                  EmptyCString(), // mime hint
                                  nsnull, //extra
                                  &shouldLoad);
   return NS_SUCCEEDED(rv) && NS_CP_ACCEPTED(shouldLoad);
 }
--- a/extensions/permissions/nsContentBlocker.cpp
+++ b/extensions/permissions/nsContentBlocker.cpp
@@ -55,17 +55,21 @@
 // From nsIContentPolicy
 static const char *kTypeString[NUMBER_OF_TYPES] = {"other", 
                                                    "script",
                                                    "image",
                                                    "stylesheet",
                                                    "object",
                                                    "document",
                                                    "subdocument",
-                                                   "refresh"};
+                                                   "refresh",
+                                                   "xbl",
+                                                   "ping",
+                                                   "xmlhttprequest",
+                                                   "objectsubrequest"};
 
 
 NS_IMPL_ISUPPORTS3(nsContentBlocker, 
                    nsIContentPolicy,
                    nsIObserver,
                    nsSupportsWeakReference)
 
 nsContentBlocker::nsContentBlocker()
--- a/extensions/permissions/nsContentBlocker.h
+++ b/extensions/permissions/nsContentBlocker.h
@@ -42,17 +42,17 @@
 #include "nsIPermissionManager.h"
 #include "nsIPrefBranch2.h"
 
 class nsIPrefBranch;
 
 ////////////////////////////////////////////////////////////////////////////////
 
 // number of permission types in nsIContentPolicy
-#define NUMBER_OF_TYPES 8
+#define NUMBER_OF_TYPES 12
 
 class nsContentBlocker : public nsIContentPolicy,
                          public nsIObserver,
                          public nsSupportsWeakReference
 {
 public:
 
   // nsISupports
--- a/modules/plugin/base/src/nsPluginHostImpl.cpp
+++ b/modules/plugin/base/src/nsPluginHostImpl.cpp
@@ -5748,17 +5748,17 @@ NS_IMETHODIMP nsPluginHostImpl::NewPlugi
   if (NS_SUCCEEDED(rv))
   {
     nsCOMPtr<nsIPluginTagInfo2> pti2 = do_QueryInterface(owner);
     nsCOMPtr<nsIDOMElement> element;
     if (pti2)
       pti2->GetDOMElement(getter_AddRefs(element));
 
     PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
-    rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OTHER,
+    rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OBJECT_SUBREQUEST,
                                    url,
                                    (doc ? doc->GetDocumentURI() : nsnull),
                                    element,
                                    EmptyCString(), //mime guess
                                    nsnull,         //extra
                                    &shouldLoad);
     if (NS_FAILED(rv)) return rv;
     if (NS_CP_REJECTED(shouldLoad)) {