From f2278605c170c1eb359a3d410f0f91a5eda64cc1 Mon Sep 17 00:00:00 2001 From: Sid Stamm Date: Fri, 22 Jan 2010 13:38:21 -0800 Subject: [PATCH] Bug 515437 CSP connection code, r=jst,dveditz sr=jst --- caps/idl/nsIPrincipal.idl | 8 +- caps/include/nsPrincipal.h | 1 + caps/src/nsNullPrincipal.cpp | 15 ++ caps/src/nsPrincipal.cpp | 20 +++ caps/src/nsSystemPrincipal.cpp | 14 ++ content/base/src/Makefile.in | 1 + content/base/src/nsCSPService.cpp | 198 +++++++++++++++++++++++++++ content/base/src/nsCSPService.h | 57 ++++++++ content/base/src/nsDocument.cpp | 118 ++++++++++++++++ content/base/src/nsDocument.h | 2 + content/base/src/nsGkAtomList.h | 2 + content/base/test/Makefile.in | 4 + content/base/test/file_CSP.sjs | 44 ++++++ content/base/test/file_CSP_main.html | 55 ++++++++ content/base/test/file_CSP_main.js | 16 +++ content/base/test/test_CSP.html | 127 +++++++++++++++++ layout/build/nsLayoutModule.cpp | 61 +++++++++ 17 files changed, 742 insertions(+), 1 deletion(-) create mode 100644 content/base/src/nsCSPService.cpp create mode 100644 content/base/src/nsCSPService.h create mode 100644 content/base/test/file_CSP.sjs create mode 100644 content/base/test/file_CSP_main.html create mode 100644 content/base/test/file_CSP_main.js create mode 100644 content/base/test/test_CSP.html diff --git a/caps/idl/nsIPrincipal.idl b/caps/idl/nsIPrincipal.idl index 127f8949ca5..4762b253a98 100644 --- a/caps/idl/nsIPrincipal.idl +++ b/caps/idl/nsIPrincipal.idl @@ -47,11 +47,12 @@ struct JSPrincipals; %} interface nsIURI; +interface nsIContentSecurityPolicy; [ptr] native JSContext(JSContext); [ptr] native JSPrincipals(JSPrincipals); -[scriptable, uuid(b8268b9a-2403-44ed-81e3-614075c92034)] +[scriptable, uuid(799ab95c-0038-4e0f-b705-74c21f185bb5)] interface nsIPrincipal : nsISerializable { /** @@ -241,4 +242,9 @@ 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; }; diff --git a/caps/include/nsPrincipal.h b/caps/include/nsPrincipal.h index 1a933163efd..155460b32e8 100644 --- a/caps/include/nsPrincipal.h +++ b/caps/include/nsPrincipal.h @@ -138,6 +138,7 @@ protected: DomainPolicy* mSecurityPolicy; + nsCOMPtr mCSP; nsCOMPtr mCodebase; nsCOMPtr mDomain; PRPackedBool mTrusted; diff --git a/caps/src/nsNullPrincipal.cpp b/caps/src/nsNullPrincipal.cpp index 63171280293..5ee01973f2f 100644 --- a/caps/src/nsNullPrincipal.cpp +++ b/caps/src/nsNullPrincipal.cpp @@ -251,6 +251,21 @@ nsNullPrincipal::GetURI(nsIURI** aURI) return NS_EnsureSafeToReturn(mURI, aURI); } +NS_IMETHODIMP +nsNullPrincipal::GetCsp(nsIContentSecurityPolicy** aCsp) +{ + // CSP on a null principal makes no sense + *aCsp = nsnull; + return NS_OK; +} + +NS_IMETHODIMP +nsNullPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp) +{ + // CSP on a null principal makes no sense + return NS_ERROR_NOT_AVAILABLE; +} + NS_IMETHODIMP nsNullPrincipal::GetDomain(nsIURI** aDomain) { diff --git a/caps/src/nsPrincipal.cpp b/caps/src/nsPrincipal.cpp index e6124df9d86..f469e0dea90 100644 --- a/caps/src/nsPrincipal.cpp +++ b/caps/src/nsPrincipal.cpp @@ -57,6 +57,7 @@ #include "nsIPrefService.h" #include "nsIClassInfoImpl.h" #include "nsDOMError.h" +#include "nsIContentSecurityPolicy.h" #include "nsPrincipal.h" @@ -774,6 +775,25 @@ nsPrincipal::GetCertificate(nsISupports** aCertificate) return NS_OK; } +NS_IMETHODIMP +nsPrincipal::GetCsp(nsIContentSecurityPolicy** aCsp) +{ + NS_IF_ADDREF(*aCsp = mCSP); + return NS_OK; +} + +NS_IMETHODIMP +nsPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp) +{ + // If CSP was already set, it should not be destroyed! Instead, it should + // get set anew when a new principal is created. + if (mCSP) + return NS_ERROR_ALREADY_INITIALIZED; + + mCSP = aCsp; + return NS_OK; +} + NS_IMETHODIMP nsPrincipal::GetHashValue(PRUint32* aValue) { diff --git a/caps/src/nsSystemPrincipal.cpp b/caps/src/nsSystemPrincipal.cpp index 7673e85467c..2abb7d17ef0 100644 --- a/caps/src/nsSystemPrincipal.cpp +++ b/caps/src/nsSystemPrincipal.cpp @@ -223,6 +223,20 @@ nsSystemPrincipal::GetHasCertificate(PRBool* aResult) return NS_OK; } +NS_IMETHODIMP +nsSystemPrincipal::GetCsp(nsIContentSecurityPolicy** aCsp) +{ + *aCsp = nsnull; + return NS_OK; +} + +NS_IMETHODIMP +nsSystemPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp) +{ + // CSP on a null principal makes no sense + return NS_OK; +} + NS_IMETHODIMP nsSystemPrincipal::GetDomain(nsIURI** aDomain) { diff --git a/content/base/src/Makefile.in b/content/base/src/Makefile.in index 50c448ab74e..f40d1ba8876 100644 --- a/content/base/src/Makefile.in +++ b/content/base/src/Makefile.in @@ -79,6 +79,7 @@ CPPSRCS = \ nsContentUtils.cpp \ nsCopySupport.cpp \ nsCrossSiteListenerProxy.cpp \ + nsCSPService.cpp \ nsDataDocumentContentPolicy.cpp \ nsDOMAttribute.cpp \ nsDOMAttributeMap.cpp \ diff --git a/content/base/src/nsCSPService.cpp b/content/base/src/nsCSPService.cpp new file mode 100644 index 00000000000..25596c18c63 --- /dev/null +++ b/content/base/src/nsCSPService.cpp @@ -0,0 +1,198 @@ +/* -*- 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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brandon Sterne + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prlog.h" +#include "nsString.h" +#include "nsCOMPtr.h" +#include "nsIURI.h" +#include "nsIPrincipal.h" +#include "nsIObserver.h" +#include "nsIDocument.h" +#include "nsIContent.h" +#include "nsContentUtils.h" +#include "nsCSPService.h" +#include "nsIContentSecurityPolicy.h" + +/* Keeps track of whether or not CSP is enabled */ +static PRBool gCSPEnabled = PR_TRUE; + +#ifdef PR_LOGGING +static PRLogModuleInfo* gCspPRLog; +#endif + +CSPService::CSPService() +{ + nsContentUtils::AddBoolPrefVarCache("security.csp.enable", &gCSPEnabled); + +#ifdef PR_LOGGING + if (!gCspPRLog) + gCspPRLog = PR_NewLogModule("CSP"); +#endif +} + +CSPService::~CSPService() +{ +} + +NS_IMPL_ISUPPORTS1(CSPService, nsIContentPolicy) + +/* nsIContentPolicy implementation */ +NS_IMETHODIMP +CSPService::ShouldLoad(PRUint32 aContentType, + nsIURI *aContentLocation, + nsIURI *aRequestOrigin, + nsISupports *aRequestContext, + const nsACString &aMimeTypeGuess, + nsISupports *aExtra, + PRInt16 *aDecision) +{ + if (!aContentLocation) + return NS_ERROR_FAILURE; + +#ifdef PR_LOGGING + { + nsCAutoString location; + aContentLocation->GetSpec(location); + PR_LOG(gCspPRLog, PR_LOG_DEBUG, + ("CSPService::ShouldLoad called for %s", location.get())); + } +#endif + // default decision, CSP can revise it if there's a policy to enforce + *aDecision = nsIContentPolicy::ACCEPT; + + // No need to continue processing if CSP is disabled + if (!gCSPEnabled) + return NS_OK; + + // find the nsDocument that initiated this request and see if it has a + // CSP policy object + nsresult rv; + nsCOMPtr node(do_QueryInterface(aRequestContext)); + nsCOMPtr principal; + nsCOMPtr csp; + if (node) { + principal = node->NodePrincipal(); + principal->GetCsp(getter_AddRefs(csp)); + + if (csp) { +#ifdef PR_LOGGING + nsAutoString policy; + csp->GetPolicy(policy); + PR_LOG(gCspPRLog, PR_LOG_DEBUG, + ("Document has CSP: %s", + NS_ConvertUTF16toUTF8(policy).get())); +#endif + // obtain the enforcement decision + csp->ShouldLoad(aContentType, + aContentLocation, + aRequestOrigin, + aRequestContext, + aMimeTypeGuess, + aExtra, + aDecision); + } + } +#ifdef PR_LOGGING + else { + nsCAutoString uriSpec; + aContentLocation->GetSpec(uriSpec); + PR_LOG(gCspPRLog, PR_LOG_DEBUG, + ("COULD NOT get nsINode for location: %s", uriSpec.get())); + } +#endif + + return NS_OK; +} + +NS_IMETHODIMP +CSPService::ShouldProcess(PRUint32 aContentType, + nsIURI *aContentLocation, + nsIURI *aRequestOrigin, + nsISupports *aRequestContext, + const nsACString &aMimeTypeGuess, + nsISupports *aExtra, + PRInt16 *aDecision) +{ + if (!aContentLocation) + return NS_ERROR_FAILURE; + + // default decision is to accept the item + *aDecision = nsIContentPolicy::ACCEPT; + + // No need to continue processing if CSP is disabled + if (!gCSPEnabled) + return NS_OK; + + // find the nsDocument that initiated this request and see if it has a + // CSP policy object + nsresult rv; + nsCOMPtr node(do_QueryInterface(aRequestContext)); + nsCOMPtr principal; + nsCOMPtr csp; + if (node) { + principal = node->NodePrincipal(); + principal->GetCsp(getter_AddRefs(csp)); + + if (csp) { +#ifdef PR_LOGGING + nsAutoString policy; + csp->GetPolicy(policy); + PR_LOG(gCspPRLog, PR_LOG_DEBUG, + ("shouldProcess - document has policy: %s", + NS_ConvertUTF16toUTF8(policy).get())); +#endif + // obtain the enforcement decision + csp->ShouldProcess(aContentType, + aContentLocation, + aRequestOrigin, + aRequestContext, + aMimeTypeGuess, + aExtra, + aDecision); + } + } +#ifdef PR_LOGGING + else { + nsCAutoString uriSpec; + aContentLocation->GetSpec(uriSpec); + PR_LOG(gCspPRLog, PR_LOG_DEBUG, + ("COULD NOT get nsINode for location: %s", uriSpec.get())); + } +#endif + return NS_OK; +} diff --git a/content/base/src/nsCSPService.h b/content/base/src/nsCSPService.h new file mode 100644 index 00000000000..a1e056164cd --- /dev/null +++ b/content/base/src/nsCSPService.h @@ -0,0 +1,57 @@ +/* -*- 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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brandon Sterne + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsXPCOM.h" +#include "nsIContentPolicy.h" + +#define CSPSERVICE_CONTRACTID "@mozilla.org/cspservice;1" +#define CSPSERVICE_CID \ + { 0x8d2f40b2, 0x4875, 0x4c95, \ + { 0x97, 0xd9, 0x3f, 0x7d, 0xca, 0x2c, 0xb4, 0x60 } } +class CSPService : public nsIContentPolicy +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSICONTENTPOLICY + + CSPService(); + virtual ~CSPService(); + +private: + PRBool mEnabled; +}; diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index d48850d3276..7a1c90a2655 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -181,6 +181,9 @@ static NS_DEFINE_CID(kDOMEventGroupCID, NS_DOMEVENTGROUP_CID); #include "nsSVGUtils.h" #endif // MOZ_SMIL +// FOR CSP (autogenerated by xpidl) +#include "nsIContentSecurityPolicy.h" + #ifdef MOZ_LOGGING // so we can get logging even in release builds @@ -188,8 +191,12 @@ static NS_DEFINE_CID(kDOMEventGroupCID, NS_DOMEVENTGROUP_CID); #endif #include "prlog.h" +/* Keeps track of whether or not CSP is enabled */ +static PRBool gCSPEnabled = PR_TRUE; + #ifdef PR_LOGGING static PRLogModuleInfo* gDocumentLeakPRLog; +static PRLogModuleInfo* gCspPRLog; #endif void @@ -1495,8 +1502,13 @@ nsDocument::nsDocument(const char* aContentType) if (gDocumentLeakPRLog) PR_LOG(gDocumentLeakPRLog, PR_LOG_DEBUG, ("DOCUMENT %p created", this)); + + if (!gCspPRLog) + gCspPRLog = PR_NewLogModule("CSP"); #endif + nsContentUtils::AddBoolPrefVarCache("security.csp.enable", &gCSPEnabled); + // Start out mLastStyleSheetSet as null, per spec SetDOMStringToNull(mLastStyleSheetSet); } @@ -2251,10 +2263,114 @@ nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel, RetrieveRelevantHeaders(aChannel); mChannel = aChannel; + + nsresult rv = InitCSP(); + NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } +nsresult +nsDocument::InitCSP() +{ + if (gCSPEnabled) { + nsAutoString cspHeaderValue; + nsAutoString cspROHeaderValue; + + this->GetHeaderData(nsGkAtoms::headerCSP, cspHeaderValue); + this->GetHeaderData(nsGkAtoms::headerCSPReportOnly, cspROHeaderValue); + + PRBool system = PR_FALSE; + nsIScriptSecurityManager *ssm = nsContentUtils::GetSecurityManager(); + + if (NS_SUCCEEDED(ssm->IsSystemPrincipal(NodePrincipal(), &system)) && system) { + // only makes sense to register new CSP if this document is not priviliged + return NS_OK; + } + + if (cspHeaderValue.IsEmpty() && cspROHeaderValue.IsEmpty()) { + // no CSP header present, stop processing + return NS_OK; + } + +#ifdef PR_LOGGING + PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("CSP header specified for document %p", this)); +#endif + + nsresult rv; + nsCOMPtr mCSP; + mCSP = do_CreateInstance("@mozilla.org/contentsecuritypolicy;1", &rv); + + if (NS_FAILED(rv)) { +#ifdef PR_LOGGING + PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("Failed to create CSP object: %x", rv)); +#endif + return rv; + } + + // Store the request context for violation reports + nsCOMPtr httpChannel = do_QueryInterface(mChannel); + mCSP->ScanRequestData(httpChannel); + + // Start parsing the policy + nsCOMPtr chanURI; + mChannel->GetURI(getter_AddRefs(chanURI)); + +#ifdef PR_LOGGING + PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("CSP Loaded")); +#endif + + // ReportOnly mode is enabled *only* if there are no regular-strength CSP + // headers present. If there are, then we ignore the ReportOnly mode and + // toss a warning into the error console, proceeding with enforcing the + // regular-strength CSP. + if (cspHeaderValue.IsEmpty()) { + mCSP->SetReportOnlyMode(true); + mCSP->RefinePolicy(cspROHeaderValue, chanURI); +#ifdef PR_LOGGING + { + PR_LOG(gCspPRLog, PR_LOG_DEBUG, + ("CSP (report only) refined, policy: \"%s\"", + NS_ConvertUTF16toUTF8(cspROHeaderValue).get())); + } +#endif + } else { + //XXX(sstamm): maybe we should post a warning when both read only and regular + // CSP headers are present. + mCSP->RefinePolicy(cspHeaderValue, chanURI); +#ifdef PR_LOGGING + { + PR_LOG(gCspPRLog, PR_LOG_DEBUG, + ("CSP refined, policy: \"%s\"", + NS_ConvertUTF16toUTF8(cspHeaderValue).get())); + } +#endif + } + + //Copy into principal + nsIPrincipal* principal = GetPrincipal(); + + if (principal) { + principal->SetCsp(mCSP); +#ifdef PR_LOGGING + PR_LOG(gCspPRLog, PR_LOG_DEBUG, + ("Inserted CSP into principal %p", principal)); + } + else { + PR_LOG(gCspPRLog, PR_LOG_DEBUG, + ("Couldn't copy CSP into absent principal %p", principal)); +#endif + } + } +#ifdef PR_LOGGING + 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; +} + void nsDocument::StopDocumentLoad() { @@ -6648,6 +6764,8 @@ nsDocument::RetrieveRelevantHeaders(nsIChannel *aChannel) "content-disposition", "refresh", "x-dns-prefetch-control", + "x-content-security-policy", + "x-content-security-policy-read-only", // add more http headers if you need // XXXbz don't add content-location support without reading bug // 238654 and its dependencies/dups first. diff --git a/content/base/src/nsDocument.h b/content/base/src/nsDocument.h index 905ee09f562..57df5f658a8 100644 --- a/content/base/src/nsDocument.h +++ b/content/base/src/nsDocument.h @@ -1213,6 +1213,8 @@ private: void PostUnblockOnloadEvent(); void DoUnblockOnload(); + nsresult InitCSP(); + /** * See if aDocument is a child of this. If so, return the frame element in * this document that holds currentDoc (or an ancestor). diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h index 8cd6af9acc3..cc800ee4a12 100644 --- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -1007,6 +1007,8 @@ GK_ATOM(withParam, "with-param") GK_ATOM(wizard, "wizard") GK_ATOM(wrap, "wrap") GK_ATOM(headerDNSPrefetchControl,"x-dns-prefetch-control") +GK_ATOM(headerCSP, "x-content-security-policy") +GK_ATOM(headerCSPReportOnly, "x-content-security-policy-report-only") GK_ATOM(xml, "xml") GK_ATOM(xmlns, "xmlns") GK_ATOM(xmp, "xmp") diff --git a/content/base/test/Makefile.in b/content/base/test/Makefile.in index fa81473572a..6f8b2cf6222 100644 --- a/content/base/test/Makefile.in +++ b/content/base/test/Makefile.in @@ -333,6 +333,10 @@ _TEST_FILES = test_bug5141.html \ test_bug503481b.html \ file_bug503481b_inner.html \ test_viewport_scroll.html \ + test_CSP.html \ + file_CSP.sjs \ + file_CSP_main.html \ + file_CSP_main.js \ $(NULL) # Disabled; see bug 492181 diff --git a/content/base/test/file_CSP.sjs b/content/base/test/file_CSP.sjs new file mode 100644 index 00000000000..b31158ca853 --- /dev/null +++ b/content/base/test/file_CSP.sjs @@ -0,0 +1,44 @@ +// SJS file for CSP mochitests + +function handleRequest(request, response) +{ + var query = {}; + request.queryString.split('&').forEach(function (val) { + var [name, value] = val.split('='); + query[name] = unescape(value); + }); + + var isPreflight = request.method == "OPTIONS"; + + + //avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + if ("main" in query) { + var xhr = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"] + .createInstance(Components.interfaces.nsIXMLHttpRequest); + //serve the main page with a CSP header! + // -- anything served from 'self' (localhost:8888) will be allowed, + // -- anything served from other hosts (example.com:80) will be blocked. + // -- XHR tests are set up in the file_CSP_main.js file which is sourced. + response.setHeader("X-Content-Security-Policy", + "allow 'self'", + false); + xhr.open("GET", "http://localhost:8888/tests/content/base/test/file_CSP_main.html", false); + xhr.send(null); + if(xhr.status == 200) { + response.write(xhr.responseText); + } + } else { + if ("type" in query) { + response.setHeader("Content-Type", unescape(query['type']), false); + } else { + response.setHeader("Content-Type", "text/html", false); + } + + if ("content" in query) { + response.setHeader("Content-Type", "text/html", false); + response.write(unescape(query['content'])); + } + } +} diff --git a/content/base/test/file_CSP_main.html b/content/base/test/file_CSP_main.html new file mode 100644 index 00000000000..8951d4ac084 --- /dev/null +++ b/content/base/test/file_CSP_main.html @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
arbitrary good
+
arbitrary_bad
+ + diff --git a/content/base/test/file_CSP_main.js b/content/base/test/file_CSP_main.js new file mode 100644 index 00000000000..f2d12ff85e8 --- /dev/null +++ b/content/base/test/file_CSP_main.js @@ -0,0 +1,16 @@ +// some javascript for the CSP XHR tests +// + +try { + var xhr_good = new XMLHttpRequest(); + var xhr_good_uri ="http://localhost:8888/tests/content/base/test/file_CSP.sjs?testid=xhr_good"; + xhr_good.open("GET", xhr_good_uri, true); + xhr_good.send(null); +} catch(e) {} + +try { + var xhr_bad = new XMLHttpRequest(); + var xhr_bad_uri ="http://example.com/tests/content/base/test/file_CSP.sjs?testid=xhr_bad"; + xhr_bad.open("GET", xhr_bad_uri, true); + xhr_bad.send(null); +} catch(e) {} diff --git a/content/base/test/test_CSP.html b/content/base/test/test_CSP.html new file mode 100644 index 00000000000..3875e387fa1 --- /dev/null +++ b/content/base/test/test_CSP.html @@ -0,0 +1,127 @@ + + + + Test for Content Security Policy Connections + + + + + +

+ + + + + + + diff --git a/layout/build/nsLayoutModule.cpp b/layout/build/nsLayoutModule.cpp index 52be6f8fd3f..dbe1f0be1ed 100644 --- a/layout/build/nsLayoutModule.cpp +++ b/layout/build/nsLayoutModule.cpp @@ -268,6 +268,7 @@ static void Shutdown(); #endif #include "nsGeolocation.h" +#include "nsCSPService.h" // Transformiix /* {0C351177-0159-4500-86B0-A219DFDE4258} */ @@ -848,6 +849,60 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGeolocation, Init) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsGeolocationService, nsGeolocationService::GetGeolocationService) +static NS_METHOD +CSPServiceRegistration(nsIComponentManager *aCompMgr, + nsIFile *aPath, + const char *registryLocation, + const char *componentType, + const nsModuleComponentInfo *info) +{ + nsresult rv; + nsCOMPtr servman = do_QueryInterface((nsISupports*)aCompMgr, &rv); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr catman; + rv = servman->GetServiceByContractID(NS_CATEGORYMANAGER_CONTRACTID, + NS_GET_IID(nsICategoryManager), + getter_AddRefs(catman)); + if (NS_FAILED(rv)) + return rv; + + nsXPIDLCString previous; + rv = catman->AddCategoryEntry("content-policy", + "CSPService", + CSPSERVICE_CONTRACTID, + PR_TRUE, + PR_TRUE, + getter_Copies(previous)); + return rv; +} + +static NS_METHOD +CSPServiceUnregistration(nsIComponentManager *aCompMgr, + nsIFile *aPath, + const char *registryLocation, + const nsModuleComponentInfo *info){ + nsresult rv; + + nsCOMPtr servman = do_QueryInterface((nsISupports*)aCompMgr, &rv); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr catman; + rv = servman->GetServiceByContractID(NS_CATEGORYMANAGER_CONTRACTID, + NS_GET_IID(nsICategoryManager), + getter_AddRefs(catman)); + if (NS_FAILED(rv)) return rv; + + rv = catman->DeleteCategoryEntry("content-policy", + "CSPService", + PR_TRUE); + + return rv; +} + +NS_GENERIC_FACTORY_CONSTRUCTOR(CSPService) + // The list of components we register static const nsModuleComponentInfo gComponents[] = { #ifdef DEBUG @@ -1453,6 +1508,12 @@ static const nsModuleComponentInfo gComponents[] = { "@mozilla.org/focus-manager;1", CreateFocusManager }, + { "Content Security Policy Service", + CSPSERVICE_CID, + CSPSERVICE_CONTRACTID, + CSPServiceConstructor, + CSPServiceRegistration, + CSPServiceUnregistration }, { "Event Listener Service", NS_EVENTLISTENERSERVICE_CID,