From 9a77da15300d3ba8070ffa4a9292918cab8cc2f1 Mon Sep 17 00:00:00 2001 From: Jonas Sicking Date: Thu, 17 Mar 2011 09:19:13 -0700 Subject: [PATCH] Bug 641706: Make SpecialPowers able to create a XHR object with full system powers. r=smaug --- content/base/src/nsXMLHttpRequest.cpp | 60 +++++++------------ content/base/src/nsXMLHttpRequest.h | 5 ++ content/base/test/test_bug426308.html | 4 +- content/base/test/test_bug431701.html | 3 +- .../specialpowers/content/specialpowers.js | 13 +++- 5 files changed, 38 insertions(+), 47 deletions(-) diff --git a/content/base/src/nsXMLHttpRequest.cpp b/content/base/src/nsXMLHttpRequest.cpp index 02d95b7daa9..2d489c7c526 100644 --- a/content/base/src/nsXMLHttpRequest.cpp +++ b/content/base/src/nsXMLHttpRequest.cpp @@ -126,19 +126,16 @@ #define XML_HTTP_REQUEST_ABORTED (1 << 7) // Internal #define XML_HTTP_REQUEST_ASYNC (1 << 8) // Internal #define XML_HTTP_REQUEST_PARSEBODY (1 << 9) // Internal -#define XML_HTTP_REQUEST_XSITEENABLED (1 << 10) // Internal, Is any cross-site request allowed? - // Even if this is false the - // access-control spec is supported -#define XML_HTTP_REQUEST_SYNCLOOPING (1 << 11) // Internal -#define XML_HTTP_REQUEST_MULTIPART (1 << 12) // Internal -#define XML_HTTP_REQUEST_GOT_FINAL_STOP (1 << 13) // Internal -#define XML_HTTP_REQUEST_BACKGROUND (1 << 14) // Internal +#define XML_HTTP_REQUEST_SYNCLOOPING (1 << 10) // Internal +#define XML_HTTP_REQUEST_MULTIPART (1 << 11) // Internal +#define XML_HTTP_REQUEST_GOT_FINAL_STOP (1 << 12) // Internal +#define XML_HTTP_REQUEST_BACKGROUND (1 << 13) // Internal // This is set when we've got the headers for a multipart XMLHttpRequest, // but haven't yet started to process the first part. -#define XML_HTTP_REQUEST_MPART_HEADERS (1 << 15) // Internal -#define XML_HTTP_REQUEST_USE_XSITE_AC (1 << 16) // Internal -#define XML_HTTP_REQUEST_NEED_AC_PREFLIGHT (1 << 17) // Internal -#define XML_HTTP_REQUEST_AC_WITH_CREDENTIALS (1 << 18) // Internal +#define XML_HTTP_REQUEST_MPART_HEADERS (1 << 14) // Internal +#define XML_HTTP_REQUEST_USE_XSITE_AC (1 << 15) // Internal +#define XML_HTTP_REQUEST_NEED_AC_PREFLIGHT (1 << 16) // Internal +#define XML_HTTP_REQUEST_AC_WITH_CREDENTIALS (1 << 17) // Internal #define XML_HTTP_REQUEST_LOADSTATES \ (XML_HTTP_REQUEST_UNINITIALIZED | \ @@ -1639,14 +1636,12 @@ nsXMLHttpRequest::GetCurrentHttpChannel() nsresult nsXMLHttpRequest::CheckChannelForCrossSiteRequest(nsIChannel* aChannel) { - // First check if cross-site requests are enabled - if ((mState & XML_HTTP_REQUEST_XSITEENABLED)) { + // First check if cross-site requests are enabled... + if (IsSystemXHR()) { return NS_OK; } - // or if this is a same-origin request. - NS_ASSERTION(!nsContentUtils::IsSystemPrincipal(mPrincipal), - "Shouldn't get here!"); + // ...or if this is a same-origin request. if (nsContentUtils::CheckMayLoad(mPrincipal, aChannel)) { return NS_OK; } @@ -1797,12 +1792,6 @@ nsXMLHttpRequest::OpenRequest(const nsACString& method, channelPolicy); if (NS_FAILED(rv)) return rv; - // Check if we're doing a cross-origin request. - if (nsContentUtils::IsSystemPrincipal(mPrincipal)) { - // Chrome callers are always allowed to read from different origins. - mState |= XML_HTTP_REQUEST_XSITEENABLED; - } - mState &= ~(XML_HTTP_REQUEST_USE_XSITE_AC | XML_HTTP_REQUEST_NEED_AC_PREFLIGHT); @@ -1823,17 +1812,6 @@ nsXMLHttpRequest::Open(const nsACString& method, const nsACString& url, PRBool async, const nsAString& user, const nsAString& password, PRUint8 optional_argc) { - if (nsContentUtils::GetCurrentJSContext()) { - // We're (likely) called from JS - - // Find out if UniversalBrowserRead privileges are enabled - if (nsContentUtils::IsCallerTrustedForRead()) { - mState |= XML_HTTP_REQUEST_XSITEENABLED; - } else { - mState &= ~XML_HTTP_REQUEST_XSITEENABLED; - } - } - if (!optional_argc) { // No optional arguments were passed in. Default async to true. async = PR_TRUE; @@ -1954,8 +1932,8 @@ nsXMLHttpRequest::OnStartRequest(nsIRequest *request, nsISupports *ctxt) nsCOMPtr channel(do_QueryInterface(request)); NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED); - nsCOMPtr documentPrincipal = mPrincipal; - if (nsContentUtils::IsSystemPrincipal(documentPrincipal)) { + nsCOMPtr documentPrincipal; + if (IsSystemXHR()) { // Don't give this document the system principal. We need to keep track of // mPrincipal being system because we use it for various security checks // that should be passing, but the document data shouldn't get a system @@ -1963,6 +1941,8 @@ nsXMLHttpRequest::OnStartRequest(nsIRequest *request, nsISupports *ctxt) nsresult rv; documentPrincipal = do_CreateInstance("@mozilla.org/nullprincipal;1", &rv); NS_ENSURE_SUCCESS(rv, rv); + } else { + documentPrincipal = mPrincipal; } channel->SetOwner(documentPrincipal); @@ -2040,7 +2020,7 @@ nsXMLHttpRequest::OnStartRequest(nsIRequest *request, nsISupports *ctxt) nsCOMPtr responseDoc = do_QueryInterface(mResponseXML); responseDoc->SetPrincipal(documentPrincipal); - if (nsContentUtils::IsSystemPrincipal(mPrincipal)) { + if (IsSystemXHR()) { responseDoc->ForceEnableXULXBL(); } @@ -2420,7 +2400,7 @@ nsXMLHttpRequest::Send(nsIVariant *aBody) if (httpChannel) { httpChannel->GetRequestMethod(method); // If GET, method name will be uppercase - if (!nsContentUtils::IsSystemPrincipal(mPrincipal)) { + if (!IsSystemXHR()) { // Get the referrer for the request. // // If it weren't for history.push/replaceState, we could just use the @@ -2656,7 +2636,7 @@ nsXMLHttpRequest::Send(nsIVariant *aBody) } } - if (!(mState & XML_HTTP_REQUEST_XSITEENABLED)) { + if (!IsSystemXHR()) { // Always create a nsCrossSiteListenerProxy here even if it's // a same-origin request right now, since it could be redirected. listener = new nsCrossSiteListenerProxy(listener, mPrincipal, mChannel, @@ -2853,7 +2833,7 @@ nsXMLHttpRequest::SetRequestHeader(const nsACString& header, } // Check for dangerous cross-site headers - PRBool safeHeader = !!(mState & XML_HTTP_REQUEST_XSITEENABLED); + bool safeHeader = IsSystemXHR(); if (!safeHeader) { // Content-Type isn't always safe, but we'll deal with it in Send() const char *kCrossOriginSafeHeaders[] = { @@ -2862,7 +2842,7 @@ nsXMLHttpRequest::SetRequestHeader(const nsACString& header, }; for (i = 0; i < NS_ARRAY_LENGTH(kCrossOriginSafeHeaders); ++i) { if (header.LowerCaseEqualsASCII(kCrossOriginSafeHeaders[i])) { - safeHeader = PR_TRUE; + safeHeader = true; break; } } diff --git a/content/base/src/nsXMLHttpRequest.h b/content/base/src/nsXMLHttpRequest.h index 84b7f59be35..e42b9e9108a 100644 --- a/content/base/src/nsXMLHttpRequest.h +++ b/content/base/src/nsXMLHttpRequest.h @@ -69,6 +69,7 @@ #include "nsIPrivateDOMEvent.h" #include "nsDOMProgressEvent.h" #include "nsDOMEventTargetWrapperCache.h" +#include "nsContentUtils.h" class nsILoadGroup; class AsyncVerifyRedirectCallbackForwarder; @@ -333,6 +334,10 @@ protected: already_AddRefed GetCurrentHttpChannel(); + bool IsSystemXHR() { + return !!nsContentUtils::IsSystemPrincipal(mPrincipal); + } + /** * Check if aChannel is ok for a cross-site request by making sure no * inappropriate headers are set, and no username/password is set. diff --git a/content/base/test/test_bug426308.html b/content/base/test/test_bug426308.html index 9c4b5180172..b58eda9d7f7 100644 --- a/content/base/test/test_bug426308.html +++ b/content/base/test/test_bug426308.html @@ -22,9 +22,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=426308 const SJS_URL = "http://example.org:80/tests/content/base/test/bug426308-redirect.sjs"; -netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); - -var req = new XMLHttpRequest(); +var req = SpecialPowers.createSystemXHR(); req.open("GET", SJS_URL + "?" + window.location.href, false); req.send(null); diff --git a/content/base/test/test_bug431701.html b/content/base/test/test_bug431701.html index bec8f0ea711..5850fd955ae 100644 --- a/content/base/test/test_bug431701.html +++ b/content/base/test/test_bug431701.html @@ -52,8 +52,7 @@ function createDoc() { function xhrDoc(idx) { return function() { // Defy same-origin restrictions! - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); - var xhr = new XMLHttpRequest(); + var xhr = SpecialPowers.createSystemXHR(); xhr.open("GET", docSources[idx], false); xhr.send(); return xhr.responseXML; diff --git a/testing/mochitest/specialpowers/content/specialpowers.js b/testing/mochitest/specialpowers/content/specialpowers.js index f5d002a2cb0..1a8a15c8096 100644 --- a/testing/mochitest/specialpowers/content/specialpowers.js +++ b/testing/mochitest/specialpowers/content/specialpowers.js @@ -37,13 +37,18 @@ /* This code is loaded in every child process that is started by mochitest in * order to be used as a replacement for UniversalXPConnect */ + +var Ci = Components.interfaces; +var Cc = Components.classes; + function SpecialPowers(window) { this.window = window; bindDOMWindowUtils(this, window); } function bindDOMWindowUtils(sp, window) { - var util = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindowUtils); + var util = window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); // This bit of magic brought to you by the letters // B Z, and E, S and the number 5. // @@ -135,7 +140,6 @@ SpecialPowers.prototype = { //XXX: these APIs really ought to be removed, they're not e10s-safe. // (also they're pretty Firefox-specific) _getTopChromeWindow: function(window) { - var Ci = Components.interfaces; return window.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebNavigation) .QueryInterface(Ci.nsIDocShellTreeItem) @@ -169,6 +173,11 @@ SpecialPowers.prototype = { }, removeChromeEventListener: function(type, listener, capture) { removeEventListener(type, listener, capture); + }, + + createSystemXHR: function() { + return Cc["@mozilla.org/xmlextras/xmlhttprequest;1"] + .createInstance(Ci.nsIXMLHttpRequest); } };