Bug 692067: Make WebSockets trigger content policies. r=smaug,dveditz
authorKyle Huey <khuey@kylehuey.com>
Wed, 07 Dec 2011 18:19:43 -0500
changeset 83822 0ca37155a57724e9b122b3f736062fc5a1ecdb58
parent 83816 7ab478082ca72615083636938a23486490d029ad
child 83823 ebe8aa6a1f353d295c9f87372b7f3687e9e4c745
push id519
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 00:38:35 +0000
treeherdermozilla-beta@788ea1ef610b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, dveditz
bugs692067
milestone11.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 692067: Make WebSockets trigger content policies. r=smaug,dveditz
content/base/public/nsContentPolicyUtils.h
content/base/public/nsIContentPolicy.idl
content/base/src/contentSecurityPolicy.js
content/base/src/nsNoDataProtocolContentPolicy.cpp
content/base/src/nsWebSocket.cpp
extensions/permissions/nsContentBlocker.cpp
--- a/content/base/public/nsContentPolicyUtils.h
+++ b/content/base/public/nsContentPolicyUtils.h
@@ -134,16 +134,17 @@ NS_CP_ContentTypeName(PRUint32 contentTy
     CASE_RETURN( TYPE_REFRESH           );
     CASE_RETURN( TYPE_XBL               );
     CASE_RETURN( TYPE_PING              );
     CASE_RETURN( TYPE_XMLHTTPREQUEST    );
     CASE_RETURN( TYPE_OBJECT_SUBREQUEST );
     CASE_RETURN( TYPE_DTD               );
     CASE_RETURN( TYPE_FONT              );
     CASE_RETURN( TYPE_MEDIA             );
+    CASE_RETURN( TYPE_WEBSOCKET         );
    default:
     return "<Unknown Type>";
   }
 }
 
 #endif // defined(PR_LOGGING)
 
 #undef CASE_RETURN
--- a/content/base/public/nsIContentPolicy.idl
+++ b/content/base/public/nsIContentPolicy.idl
@@ -132,16 +132,21 @@ interface nsIContentPolicy : nsISupports
    */
   const unsigned long TYPE_FONT = 14;
 
   /**
    * Indicates a video or audio load.
    */
   const unsigned long TYPE_MEDIA = 15;  
 
+  /**
+   * Indicates a WebSocket load.
+   */
+  const unsigned long TYPE_WEBSOCKET = 16;
+
   /* Please update nsContentBlocker when adding new content types. */
 
   //////////////////////////////////////////////////////////////////////
 
   /**
    * Returned from shouldLoad or shouldProcess if the load or process request
    * is rejected based on details of the request.
    */
--- a/content/base/src/contentSecurityPolicy.js
+++ b/content/base/src/contentSecurityPolicy.js
@@ -97,16 +97,17 @@ function ContentSecurityPolicy() {
   csp._MAPPINGS[cp.TYPE_IMAGE]             = cspr_sd.IMG_SRC;
   csp._MAPPINGS[cp.TYPE_STYLESHEET]        = cspr_sd.STYLE_SRC;
   csp._MAPPINGS[cp.TYPE_OBJECT]            = cspr_sd.OBJECT_SRC;
   csp._MAPPINGS[cp.TYPE_OBJECT_SUBREQUEST] = cspr_sd.OBJECT_SRC;
   csp._MAPPINGS[cp.TYPE_SUBDOCUMENT]       = cspr_sd.FRAME_SRC;
   csp._MAPPINGS[cp.TYPE_MEDIA]             = cspr_sd.MEDIA_SRC;
   csp._MAPPINGS[cp.TYPE_FONT]              = cspr_sd.FONT_SRC;
   csp._MAPPINGS[cp.TYPE_XMLHTTPREQUEST]    = cspr_sd.XHR_SRC;
+  csp._MAPPINGS[cp.TYPE_WEBSOCKET]         = cspr_sd.XHR_SRC;
 
 
   /* These must go through the catch-all */
   csp._MAPPINGS[cp.TYPE_XBL]               = cspr_sd.DEFAULT_SRC;
   csp._MAPPINGS[cp.TYPE_PING]              = cspr_sd.DEFAULT_SRC;
   csp._MAPPINGS[cp.TYPE_DTD]               = cspr_sd.DEFAULT_SRC;
 }
 
--- a/content/base/src/nsNoDataProtocolContentPolicy.cpp
+++ b/content/base/src/nsNoDataProtocolContentPolicy.cpp
@@ -63,19 +63,22 @@ 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 necessarily open external apps
+  // TYPE_WEBSOCKET loads can only go to ws:// or wss://, so we don't need to
+  // concern ourselves with them.
   if (aContentType != TYPE_DOCUMENT &&
       aContentType != TYPE_SUBDOCUMENT &&
-      aContentType != TYPE_OBJECT) {
+      aContentType != TYPE_OBJECT &&
+      aContentType != TYPE_WEBSOCKET) {
 
     // The following are just quick-escapes for the most common cases
     // where we would allow the content to be loaded anyway.
     nsCAutoString scheme;
     aContentLocation->GetScheme(scheme);
     if (scheme.EqualsLiteral("http") ||
         scheme.EqualsLiteral("https") ||
         scheme.EqualsLiteral("ftp") ||
--- a/content/base/src/nsWebSocket.cpp
+++ b/content/base/src/nsWebSocket.cpp
@@ -71,16 +71,18 @@
 #include "nsIJSContextStack.h"
 #include "nsJSUtils.h"
 #include "nsIScriptError.h"
 #include "nsNetUtil.h"
 #include "nsILoadGroup.h"
 #include "mozilla/Preferences.h"
 #include "nsDOMLists.h"
 #include "xpcpublic.h"
+#include "nsContentPolicyUtils.h"
+#include "nsContentErrors.h"
 
 using namespace mozilla;
 
 #define UTF_8_REPLACEMENT_CHAR    static_cast<PRUnichar>(0xFFFD)
 
 #define ENSURE_TRUE_AND_FAIL_IF_FAILED(x, ret)                            \
   PR_BEGIN_MACRO                                                          \
     if (NS_UNLIKELY(!(x))) {                                              \
@@ -1271,25 +1273,26 @@ nsWebSocket::Init(nsIPrincipal* aPrincip
 
     mInnerWindowID = nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx);
   }
 
   // parses the url
   rv = ParseURL(PromiseFlatString(aURL));
   NS_ENSURE_SUCCESS(rv, rv);
 
+  nsCOMPtr<nsIDocument> originDoc =
+    nsContentUtils::GetDocumentFromScriptContext(mScriptContext);
+
   // Don't allow https:// to open ws://
   if (!mSecure &&
       !Preferences::GetBool("network.websocket.allowInsecureFromHTTPS",
                             false)) {
     // Confirmed we are opening plain ws:// and want to prevent this from a
     // secure context (e.g. https). Check the security context of the document
     // associated with this script, which is the same as associated with mOwner.
-    nsCOMPtr<nsIDocument> originDoc =
-      nsContentUtils::GetDocumentFromScriptContext(mScriptContext);
     if (originDoc && originDoc->GetSecurityInfo())
       return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   // Assign the sub protocol list and scan it for illegal values
   for (PRUint32 index = 0; index < protocolArray.Length(); ++index) {
     for (PRUint32 i = 0; i < protocolArray[index].Length(); ++i) {
       if (protocolArray[index][i] < static_cast<PRUnichar>(0x0021) ||
@@ -1297,16 +1300,33 @@ nsWebSocket::Init(nsIPrincipal* aPrincip
         return NS_ERROR_DOM_SYNTAX_ERR;
     }
 
     if (!mRequestedProtocolList.IsEmpty())
       mRequestedProtocolList.Append(NS_LITERAL_CSTRING(", "));
     AppendUTF16toUTF8(protocolArray[index], mRequestedProtocolList);
   }
 
+  // Check content policy.
+  PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
+  rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_WEBSOCKET,
+                                 mURI,
+                                 mPrincipal,
+                                 originDoc,
+                                 EmptyCString(),
+                                 nsnull,
+                                 &shouldLoad,
+                                 nsContentUtils::GetContentPolicy(),
+                                 nsContentUtils::GetSecurityManager());
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_CP_REJECTED(shouldLoad)) {
+    // Disallowed by content policy.
+    return NS_ERROR_CONTENT_BLOCKED;
+  }
+
   // the constructor should throw a SYNTAX_ERROR only if it fails to parse the
   // url parameter, so we don't care about the EstablishConnection result.
   EstablishConnection();
 
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
--- a/extensions/permissions/nsContentBlocker.cpp
+++ b/extensions/permissions/nsContentBlocker.cpp
@@ -63,17 +63,18 @@ static const char *kTypeString[] = {"oth
                                     "subdocument",
                                     "refresh",
                                     "xbl",
                                     "ping",
                                     "xmlhttprequest",
                                     "objectsubrequest",
                                     "dtd",
                                     "font",
-                                    "media"};
+                                    "media",
+                                    "websocket"};
 
 #define NUMBER_OF_TYPES NS_ARRAY_LENGTH(kTypeString)
 PRUint8 nsContentBlocker::mBehaviorPref[NUMBER_OF_TYPES];
 
 NS_IMPL_ISUPPORTS3(nsContentBlocker, 
                    nsIContentPolicy,
                    nsIObserver,
                    nsSupportsWeakReference)