From 1b2ddc8d15c579c559edb9c3c9c2c4e64aa33803 Mon Sep 17 00:00:00 2001 From: "jonas@sicking.cc" Date: Tue, 25 Mar 2008 19:46:08 -0700 Subject: [PATCH] Bug 424923: Remove support for cross-site XHR. r/sr=jst for code changes --- content/base/src/Makefile.in | 1 - content/base/src/nsCrossSiteListenerProxy.cpp | 969 ------------------ content/base/src/nsCrossSiteListenerProxy.h | 109 -- content/base/src/nsSyncLoadService.cpp | 23 +- content/base/src/nsXMLHttpRequest.cpp | 487 +-------- content/base/src/nsXMLHttpRequest.h | 86 -- content/base/test/Makefile.in | 32 +- .../file_CrossSiteXHR2_fail1.xml^headers^ | 2 - .../base/test/file_CrossSiteXHR2_fail2.xml | 2 - .../base/test/file_CrossSiteXHR2_inner.html | 104 -- .../base/test/file_CrossSiteXHR2_pass1.xml | 1 - .../file_CrossSiteXHR2_pass1.xml^headers^ | 2 - .../base/test/file_CrossSiteXHR2_pass2.xml | 2 - .../base/test/file_CrossSiteXHR2_pass3.xml | 1 - .../file_CrossSiteXHR2_pass3.xml^headers^ | 2 - .../file_CrossSiteXHR2_pass3_redirect.xml | 2 - .../base/test/file_CrossSiteXHR3_inner.html | 98 -- .../base/test/file_CrossSiteXHR3_pass1.xml | 1 - .../file_CrossSiteXHR3_pass1.xml^headers^ | 2 - content/base/test/file_CrossSiteXHR_fail1.xml | 1 - content/base/test/file_CrossSiteXHR_fail2.xml | 2 - .../test/file_CrossSiteXHR_fail2.xml^headers^ | 2 - content/base/test/file_CrossSiteXHR_fail3.xml | 4 - content/base/test/file_CrossSiteXHR_fail4.xml | 3 - content/base/test/file_CrossSiteXHR_pass1.xml | 1 - .../test/file_CrossSiteXHR_pass1.xml^headers^ | 2 - content/base/test/file_CrossSiteXHR_pass2.xml | 2 - content/base/test/file_CrossSiteXHR_pass3.xml | 5 - content/base/test/file_XHR_fail1.txt | 1 + content/base/test/file_XHR_fail1.txt^headers^ | 2 + content/base/test/file_XHR_fail1b.txt | 1 + ...sSiteXHR2_fail1.xml => file_XHR_pass1.xml} | 0 content/base/test/file_XHR_pass2.txt | 1 + content/base/test/file_XHR_pass3.txt | 1 + content/base/test/file_XHR_pass3.txt^headers^ | 2 + content/base/test/test_CrossSiteXHR2.html | 37 - content/base/test/test_CrossSiteXHR3.html | 37 - .../{test_CrossSiteXHR.html => test_XHR.html} | 29 +- content/html/document/src/nsHTMLDocument.cpp | 8 - content/html/document/src/nsHTMLDocument.h | 7 - content/html/document/src/nsIHTMLDocument.h | 5 - .../src/xslt/txMozillaStylesheetCompiler.cpp | 95 +- 42 files changed, 114 insertions(+), 2060 deletions(-) delete mode 100644 content/base/src/nsCrossSiteListenerProxy.cpp delete mode 100644 content/base/src/nsCrossSiteListenerProxy.h delete mode 100644 content/base/test/file_CrossSiteXHR2_fail1.xml^headers^ delete mode 100644 content/base/test/file_CrossSiteXHR2_fail2.xml delete mode 100644 content/base/test/file_CrossSiteXHR2_inner.html delete mode 100644 content/base/test/file_CrossSiteXHR2_pass1.xml delete mode 100644 content/base/test/file_CrossSiteXHR2_pass1.xml^headers^ delete mode 100644 content/base/test/file_CrossSiteXHR2_pass2.xml delete mode 100644 content/base/test/file_CrossSiteXHR2_pass3.xml delete mode 100644 content/base/test/file_CrossSiteXHR2_pass3.xml^headers^ delete mode 100644 content/base/test/file_CrossSiteXHR2_pass3_redirect.xml delete mode 100644 content/base/test/file_CrossSiteXHR3_inner.html delete mode 100644 content/base/test/file_CrossSiteXHR3_pass1.xml delete mode 100644 content/base/test/file_CrossSiteXHR3_pass1.xml^headers^ delete mode 100644 content/base/test/file_CrossSiteXHR_fail1.xml delete mode 100644 content/base/test/file_CrossSiteXHR_fail2.xml delete mode 100644 content/base/test/file_CrossSiteXHR_fail2.xml^headers^ delete mode 100644 content/base/test/file_CrossSiteXHR_fail3.xml delete mode 100644 content/base/test/file_CrossSiteXHR_fail4.xml delete mode 100644 content/base/test/file_CrossSiteXHR_pass1.xml delete mode 100644 content/base/test/file_CrossSiteXHR_pass1.xml^headers^ delete mode 100644 content/base/test/file_CrossSiteXHR_pass2.xml delete mode 100644 content/base/test/file_CrossSiteXHR_pass3.xml create mode 100644 content/base/test/file_XHR_fail1.txt create mode 100644 content/base/test/file_XHR_fail1.txt^headers^ create mode 100644 content/base/test/file_XHR_fail1b.txt rename content/base/test/{file_CrossSiteXHR2_fail1.xml => file_XHR_pass1.xml} (100%) create mode 100644 content/base/test/file_XHR_pass2.txt create mode 100644 content/base/test/file_XHR_pass3.txt create mode 100644 content/base/test/file_XHR_pass3.txt^headers^ delete mode 100644 content/base/test/test_CrossSiteXHR2.html delete mode 100644 content/base/test/test_CrossSiteXHR3.html rename content/base/test/{test_CrossSiteXHR.html => test_XHR.html} (62%) diff --git a/content/base/src/Makefile.in b/content/base/src/Makefile.in index 43a5dab7345..43360033e3f 100644 --- a/content/base/src/Makefile.in +++ b/content/base/src/Makefile.in @@ -117,7 +117,6 @@ CPPSRCS = \ nsContentSink.cpp \ nsContentUtils.cpp \ nsCopySupport.cpp \ - nsCrossSiteListenerProxy.cpp \ nsDataDocumentContentPolicy.cpp \ nsDOMAttribute.cpp \ nsDOMAttributeMap.cpp \ diff --git a/content/base/src/nsCrossSiteListenerProxy.cpp b/content/base/src/nsCrossSiteListenerProxy.cpp deleted file mode 100644 index 7110626d539..00000000000 --- a/content/base/src/nsCrossSiteListenerProxy.cpp +++ /dev/null @@ -1,969 +0,0 @@ -/* -*- 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 Foundation. - * Portions created by the Initial Developer are Copyright (C) 2007 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Jonas Sicking (Original Author) - * - * 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 "nsCrossSiteListenerProxy.h" -#include "nsIChannel.h" -#include "nsIHttpChannel.h" -#include "nsDOMError.h" -#include "nsContentUtils.h" -#include "nsIScriptSecurityManager.h" -#include "nsNetUtil.h" -#include "nsIParser.h" -#include "nsParserCIID.h" -#include "nsICharsetAlias.h" -#include "nsMimeTypes.h" -#include "nsIStreamConverterService.h" -#include "nsStringStream.h" -#include "nsParserUtils.h" -#include "nsGkAtoms.h" -#include "nsWhitespaceTokenizer.h" -#include "nsIChannelEventSink.h" - -static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID); - -NS_IMPL_ISUPPORTS7(nsCrossSiteListenerProxy, nsIStreamListener, - nsIRequestObserver, nsIContentSink, nsIXMLContentSink, - nsIExpatSink, nsIChannelEventSink, nsIInterfaceRequestor) - -nsCrossSiteListenerProxy::nsCrossSiteListenerProxy(nsIStreamListener* aOuter, - nsIPrincipal* aRequestingPrincipal, - nsIChannel* aChannel, - nsresult* aResult) - : mOuterListener(aOuter), - mRequestingPrincipal(aRequestingPrincipal), - mAcceptState(eNotSet), - mHasForwardedRequest(PR_FALSE), - mHasBeenCrossSite(PR_FALSE) -{ - aRequestingPrincipal->GetURI(getter_AddRefs(mRequestingURI)); - aChannel->GetNotificationCallbacks(getter_AddRefs(mOuterNotificationCallbacks)); - aChannel->SetNotificationCallbacks(this); - - *aResult = UpdateChannel(aChannel); -} - -nsresult -nsCrossSiteListenerProxy::ForwardRequest(PRBool aFromStop) -{ - if (mHasForwardedRequest) { - return NS_OK; - } - - mHasForwardedRequest = PR_TRUE; - - if (mParser) { - mParser->Terminate(); - mParser = nsnull; - mParserListener = nsnull; - } - - if (mAcceptState != eAccept) { - mAcceptState = eDeny; - mOuterRequest->Cancel(NS_ERROR_DOM_BAD_URI); - mOuterListener->OnStartRequest(mOuterRequest, mOuterContext); - - // Only call OnStopRequest here if we were called from OnStopRequest. - // Otherwise the call to Cancel will make us get an OnStopRequest later - // so we'll forward OnStopRequest then. - if (aFromStop) { - mOuterListener->OnStopRequest(mOuterRequest, mOuterContext, - NS_ERROR_DOM_BAD_URI); - } - - // Clear this data just in case since it should never be forwarded. - mStoredData.Truncate(); - - return NS_ERROR_DOM_BAD_URI; - } - - nsresult rv = mOuterListener->OnStartRequest(mOuterRequest, mOuterContext); - NS_ENSURE_SUCCESS(rv, rv); - - if (!mStoredData.IsEmpty()) { - nsCOMPtr stream; - rv = NS_NewCStringInputStream(getter_AddRefs(stream), mStoredData); - NS_ENSURE_SUCCESS(rv, rv); - - rv = mOuterListener->OnDataAvailable(mOuterRequest, mOuterContext, stream, - 0, mStoredData.Length()); - NS_ENSURE_SUCCESS(rv, rv); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsCrossSiteListenerProxy::OnStartRequest(nsIRequest* aRequest, - nsISupports* aContext) -{ - mOuterRequest = aRequest; - mOuterContext = aContext; - - // Check if the request failed - nsresult status; - nsresult rv = aRequest->GetStatus(&status); - NS_ENSURE_SUCCESS(rv, rv); - if (NS_FAILED(status)) { - mAcceptState = eDeny; - return ForwardRequest(PR_FALSE); - } - - // Check if this was actually a cross domain request - nsCOMPtr channel = do_QueryInterface(aRequest); - if (!channel) { - return NS_ERROR_DOM_BAD_URI; - } - nsCOMPtr finalURI; - channel->GetURI(getter_AddRefs(finalURI)); - - if (!mHasBeenCrossSite) { - mAcceptState = eAccept; - return ForwardRequest(PR_FALSE); - } - - nsCOMPtr http = do_QueryInterface(channel); - if (http) { - PRBool succeeded; - rv = http->GetRequestSucceeded(&succeeded); - NS_ENSURE_SUCCESS(rv, rv); - - if (!succeeded) { - mAcceptState = eDeny; - return ForwardRequest(PR_FALSE); - } - } - - // Get the list of subdomains out of mRequestingURI - nsCString host; - rv = mRequestingURI->GetAsciiHost(host); - NS_ENSURE_SUCCESS(rv, rv); - - PRInt32 nextDot, currDot = 0; - while ((nextDot = host.FindChar('.', currDot)) != -1) { - mReqSubdomains.AppendElement(Substring(host, currDot, nextDot - currDot)); - currDot = nextDot + 1; - } - mReqSubdomains.AppendElement(Substring(host, currDot)); - - // Check the Access-Control header - if (http) { - nsCAutoString ac; - rv = http->GetResponseHeader(NS_LITERAL_CSTRING("Access-Control"), ac); - - if (NS_SUCCEEDED(rv)) { - CheckHeader(ac); - } - } - - if (mAcceptState == eDeny) { - return ForwardRequest(PR_FALSE); - } - - // Set up a parser with us as a sink to look for PIs - mParser = do_CreateInstance(kCParserCID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - mParserListener = do_QueryInterface(mParser); - - mParser->SetCommand(kLoadAsData); - mParser->SetContentSink(this); - mParser->Parse(finalURI); - - // check channel's charset... - nsCAutoString charset(NS_LITERAL_CSTRING("UTF-8")); - PRInt32 charsetSource = kCharsetFromDocTypeDefault; - nsCAutoString charsetVal; - rv = channel->GetContentCharset(charsetVal); - if (NS_SUCCEEDED(rv)) { - nsCOMPtr calias = - do_GetService(NS_CHARSETALIAS_CONTRACTID); - - if (calias) { - nsCAutoString preferred; - rv = calias->GetPreferred(charsetVal, preferred); - if (NS_SUCCEEDED(rv)) { - charset = preferred; - charsetSource = kCharsetFromChannel; - } - } - } - - mParser->SetDocumentCharset(charset, charsetSource); - - nsCAutoString contentType; - channel->GetContentType(contentType); - - // Time to sniff! Note: this should go away once file channels do - // sniffing themselves. - PRBool sniff; - if (NS_SUCCEEDED(finalURI->SchemeIs("file", &sniff)) && sniff && - contentType.Equals(UNKNOWN_CONTENT_TYPE)) { - nsCOMPtr serv = - do_GetService("@mozilla.org/streamConverters;1", &rv); - if (NS_SUCCEEDED(rv)) { - nsCOMPtr converter; - rv = serv->AsyncConvertData(UNKNOWN_CONTENT_TYPE, - "*/*", - mParserListener, - aContext, - getter_AddRefs(converter)); - if (NS_SUCCEEDED(rv)) { - mParserListener = converter; - } - } - } - - // Hold a local reference to make sure the parser doesn't go away - nsCOMPtr stackedListener = mParserListener; - return stackedListener->OnStartRequest(aRequest, aContext); -} - -NS_IMETHODIMP -nsCrossSiteListenerProxy::OnStopRequest(nsIRequest* aRequest, - nsISupports* aContext, - nsresult aStatusCode) -{ - if (mHasForwardedRequest) { - return mOuterListener->OnStopRequest(aRequest, aContext, aStatusCode); - } - - mAcceptState = eDeny; - return ForwardRequest(PR_TRUE); -} - -NS_METHOD -StringSegmentWriter(nsIInputStream *aInStream, - void *aClosure, - const char *aFromSegment, - PRUint32 aToOffset, - PRUint32 aCount, - PRUint32 *aWriteCount) -{ - nsCString* dest = static_cast(aClosure); - - dest->Append(aFromSegment, aCount); - *aWriteCount = aCount; - - return NS_OK; -} - -NS_IMETHODIMP -nsCrossSiteListenerProxy::OnDataAvailable(nsIRequest* aRequest, - nsISupports* aContext, - nsIInputStream* aInputStream, - PRUint32 aOffset, - PRUint32 aCount) -{ - if (mHasForwardedRequest) { - if (mAcceptState != eAccept) { - return NS_ERROR_DOM_BAD_URI; - } - return mOuterListener->OnDataAvailable(aRequest, aContext, aInputStream, - aOffset, aCount); - } - - NS_ASSERTION(mStoredData.Length() == aOffset, - "Stored wrong amount of data"); - - PRUint32 read; - nsresult rv = aInputStream->ReadSegments(StringSegmentWriter, &mStoredData, - aCount, &read); - NS_ENSURE_SUCCESS(rv, rv); - NS_ASSERTION(read == aCount, "didn't store all of the stream"); - - nsCOMPtr stream; - rv = NS_NewCStringInputStream(getter_AddRefs(stream), - Substring(mStoredData, aOffset)); - NS_ENSURE_SUCCESS(rv, rv); - - // Hold a local reference to make sure the parser doesn't go away - nsCOMPtr stackedListener = mParserListener; - rv = stackedListener->OnDataAvailable(aRequest, aContext, stream, aOffset, - aCount); - // When we forward the request we also terminate the parsing which will - // result in an error bubbling up to here. We want to ignore the error - // in that case. - if (mHasForwardedRequest) { - rv = mAcceptState == eAccept ? NS_OK : NS_ERROR_DOM_BAD_URI; - } - return rv; -} - -NS_IMETHODIMP -nsCrossSiteListenerProxy::HandleStartElement(const PRUnichar *aName, - const PRUnichar **aAtts, - PRUint32 aAttsCount, - PRInt32 aIndex, - PRUint32 aLineNumber) -{ - // We're done processing the prolog. - ForwardRequest(PR_FALSE); - - // Stop the parser since we don't want to spend more cycles on parsing - // stuff. - return NS_ERROR_HTMLPARSER_STOPPARSING; -} - -NS_IMETHODIMP -nsCrossSiteListenerProxy::HandleEndElement(const PRUnichar *aName) -{ - NS_ASSERTION(mHasForwardedRequest, "Should have forwarded request"); - - return NS_OK; -} - -NS_IMETHODIMP -nsCrossSiteListenerProxy::HandleComment(const PRUnichar *aName) -{ - return NS_OK; -} - -NS_IMETHODIMP -nsCrossSiteListenerProxy::HandleCDataSection(const PRUnichar *aData, - PRUint32 aLength) -{ - NS_ASSERTION(mHasForwardedRequest, "Should have forwarded request"); - - return NS_OK; -} - -NS_IMETHODIMP -nsCrossSiteListenerProxy::HandleDoctypeDecl(const nsAString & aSubset, - const nsAString & aName, - const nsAString & aSystemId, - const nsAString & aPublicId, - nsISupports *aCatalogData) -{ - return NS_OK; -} - -NS_IMETHODIMP -nsCrossSiteListenerProxy::HandleCharacterData(const PRUnichar *aData, - PRUint32 aLength) -{ - return NS_OK; -} - -NS_IMETHODIMP -nsCrossSiteListenerProxy::HandleProcessingInstruction(const PRUnichar *aTarget, - const PRUnichar *aData) -{ - if (mHasForwardedRequest || - !NS_LITERAL_STRING("access-control").Equals(aTarget)) { - return NS_OK; - } - - nsDependentString data(aData); - - PRBool seenType = PR_FALSE, seenExclude = PR_FALSE; - PRBool ruleIsAllow = PR_FALSE; - nsAutoString itemList, excludeList; - - PRUint32 i; - for (i = 0;; ++i) { - nsAutoString attrName; - if (nsParserUtils::GetQuotedAttrNameAt(data, i, attrName) && - attrName.IsEmpty()) { - break; - } - - nsCOMPtr attr = do_GetAtom(attrName); - - PRBool res; - if (!seenType && attrName.EqualsLiteral("allow")) { - seenType = PR_TRUE; - ruleIsAllow = PR_TRUE; - - res = nsParserUtils::GetQuotedAttributeValue(data, attr, itemList); - } - else if (!seenType && attrName.EqualsLiteral("deny")) { - seenType = PR_TRUE; - ruleIsAllow = PR_FALSE; - - res = nsParserUtils::GetQuotedAttributeValue(data, attr, itemList); - } - else if (!seenExclude && attrName.EqualsLiteral("exclude")) { - seenExclude = PR_TRUE; - - res = nsParserUtils::GetQuotedAttributeValue(data, attr, excludeList); - } - else { - res = PR_FALSE; - } - - if (!res) { - // parsing attribute value failed or unknown/duplicated attribute - mAcceptState = eDeny; - return ForwardRequest(PR_FALSE); - } - } - - PRBool matchesRule = PR_FALSE; - - nsWhitespaceTokenizer itemTok(itemList); - - if (!itemTok.hasMoreTokens()) { - mAcceptState = eDeny; - - return ForwardRequest(PR_FALSE); - } - - while (itemTok.hasMoreTokens()) { - // Order is important here since we always want to call the function - matchesRule = VerifyAndMatchDomainPattern( - NS_ConvertUTF16toUTF8(itemTok.nextToken())) || matchesRule; - } - - nsWhitespaceTokenizer excludeTok(excludeList); - while (excludeTok.hasMoreTokens()) { - // Order is important here since we always want to call the function - matchesRule = !VerifyAndMatchDomainPattern( - NS_ConvertUTF16toUTF8(excludeTok.nextToken())) && matchesRule; - } - - if (matchesRule && mAcceptState != eDeny) { - mAcceptState = ruleIsAllow ? eAccept : eDeny; - } - - if (mAcceptState == eDeny) { - return ForwardRequest(PR_FALSE); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsCrossSiteListenerProxy::HandleXMLDeclaration(const PRUnichar *aVersion, - const PRUnichar *aEncoding, - PRInt32 aStandalone) -{ - return NS_OK; -} - -NS_IMETHODIMP -nsCrossSiteListenerProxy::ReportError(const PRUnichar *aErrorText, - const PRUnichar *aSourceText, - nsIScriptError *aError, - PRBool *_retval) -{ - if (!mHasForwardedRequest) { - mAcceptState = eDeny; - - return ForwardRequest(PR_FALSE); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsCrossSiteListenerProxy::WillBuildModel() -{ - nsCOMPtr dtd; - mParser->GetDTD(getter_AddRefs(dtd)); - NS_ASSERTION(dtd, "missing dtd in WillBuildModel"); - if (dtd && !(dtd->GetType() & NS_IPARSER_FLAG_XML)) { - ForwardRequest(PR_FALSE); - - // Stop the parser since we don't want to spend more cycles on parsing - // stuff. - return NS_ERROR_HTMLPARSER_STOPPARSING; - } - - return NS_OK; -} - -// Moves aIter past the LWS (RFC2616) directly following it. -// Returns PR_TRUE and updates aIter if there was an LWS there, -// PR_FALSE otherwise -static PRBool -EatLWS(const char*& aIter, const char* aEnd) -{ - if (aIter + 1 < aEnd && *aIter == '\r' && *(aIter + 1) == '\n') { - aIter += 2; - } - - PRBool res = PR_FALSE; - while (aIter < aEnd && (*aIter == '\t' || *aIter == ' ')) { - ++aIter; - res = PR_TRUE; - } - - return res; -} - -// Moves aIter past the string, given by aString, directly following it. -// Returns PR_TRUE and updates aIter if the string was there, -// PR_FALSE otherwise -static PRBool -EatString(const char*& aIter, const char* aEnd, const char* aString) -{ - const char* local = aIter; - while (*aString && local < aEnd && *local == *aString) { - ++local; - ++aString; - } - if (*aString) { - return PR_FALSE; - } - - aIter = local; - - return PR_TRUE; -} - -// Moves aIter to the first aChar following it. -// Returns The string between the aIters initial position and the -// found character if one was found. -// Returns an empty string otherwise. -static nsDependentCSubstring -EatToChar(const char*& aIter, const char* aEnd, char aChar) -{ - const char* start = aIter; - while (aIter < aEnd) { - if (*aIter == aChar) { - return Substring(start, aIter); - } - ++aIter; - } - - static char emptyStatic[] = { '\0' }; - - aIter = start; - return Substring(emptyStatic, emptyStatic); -} - -PRBool -nsCrossSiteListenerProxy::MatchPatternList(const char*& aIter, const char* aEnd) -{ - PRBool matchesList = PR_FALSE; - PRBool hasItems = PR_FALSE; - - for (;;) { - const char* start = aIter; - if (!EatLWS(aIter, aEnd)) { - break; - } - - if (!EatString(aIter, aEnd, "<")) { - // restore iterator to before LWS since it wasn't part of the list - aIter = start; - break; - } - - const nsACString& accessItem = EatToChar(aIter, aEnd, '>'); - if (!EatString(aIter, aEnd, ">")) { - mAcceptState = eDeny; - break; - } - - hasItems = PR_TRUE; - - // Order is important here since we always want to call the function - matchesList = VerifyAndMatchDomainPattern(accessItem) || matchesList; - } - - if (!hasItems) { - mAcceptState = eDeny; - } - - return matchesList; -} - -#define DENY_AND_RETURN \ - mAcceptState = eDeny; \ - return - -void -nsCrossSiteListenerProxy::CheckHeader(const nsCString& aHeader) -{ - const char* iter = aHeader.BeginReading(); - const char* end = aHeader.EndReading(); - - // ruleset ::= LWS? rule LWS? ("," LWS? rule LWS?)* - while (iter < end) { - // eat LWS? - EatLWS(iter, end); - - // rule ::= rule-type (LWS pattern)+ (LWS "exclude" (LWS pattern)+)? - // eat rule-type - PRBool ruleIsAllow; - if (EatString(iter, end, "deny")) { - ruleIsAllow = PR_FALSE; - } - else if (EatString(iter, end, "allow")) { - ruleIsAllow = PR_TRUE; - } - else { - DENY_AND_RETURN; - } - - // eat (LWS pattern)+ - PRBool matchesRule = MatchPatternList(iter, end); - - PRBool ateLWS = EatLWS(iter, end); - - // eat (LWS "exclude" (LWS pattern)+)? - if (ateLWS && EatString(iter, end, "exclude")) { - ateLWS = PR_FALSE; - - // Order is important here since we always want to call the function - matchesRule = !MatchPatternList(iter, end) && matchesRule; - } - - if (matchesRule && mAcceptState != eDeny) { - mAcceptState = ruleIsAllow ? eAccept : eDeny; - } - - // eat LWS? - if (!ateLWS) { - EatLWS(iter, end); - } - - if (iter != end) { - if (!EatString(iter, end, ",")) { - DENY_AND_RETURN; - } - } - } -} - -// Moves aIter forward one character if the character at aIter is in [a-zA-Z] -// Returns PR_TRUE and updates aIter if such a character was found. -// PR_FALSE otherwise. -static PRBool -EatAlpha(nsACString::const_iterator& aIter, nsACString::const_iterator& aEnd) -{ - if (aIter != aEnd && ((*aIter >= 'A' && *aIter <= 'Z') || - (*aIter >= 'a' && *aIter <= 'z'))) { - ++aIter; - - return PR_TRUE; - } - - return PR_FALSE; -} - -// Moves aIter forward one character if the character at aIter is in [0-9] -// Returns PR_TRUE and updates aIter if such a character was found. -// PR_FALSE otherwise. -static PRBool -EatDigit(nsACString::const_iterator& aIter, nsACString::const_iterator& aEnd) -{ - if (aIter != aEnd && *aIter >= '0' && *aIter <= '9') { - ++aIter; - - return PR_TRUE; - } - - return PR_FALSE; -} - -// Moves aIter forward one character if the character at aIter is aChar -// Returns PR_TRUE and updates aIter if aChar was found. -// PR_FALSE otherwise. -static PRBool -EatChar(nsACString::const_iterator& aIter, nsACString::const_iterator& aEnd, - char aChar) -{ - if (aIter != aEnd && *aIter == aChar) { - ++aIter; - - return PR_TRUE; - } - - return PR_FALSE; -} - -// Moves aIter forward until it hits a subdomain terminator (* : or whitespace) -// or reaches the end -// access-item ::= (scheme "://")? domain-pattern (":" port)? | "*" -// domain-pattern ::= subdomain | "*." subdomain -// Returns PR_TRUE and updates aIter if a terminator is found. -// PR_FALSE otherwise. -static void -EatSubdomainChars(nsACString::const_iterator& aIter, - nsACString::const_iterator& aEnd) -{ - NS_ASSERTION(aIter.get() <= aEnd.get(), "EatSubdomainChars failed"); - - // Make sure to not allow initial hyphens - if (*aIter == '-') { - return; - } - - while (aIter != aEnd) { - unsigned char c = *aIter; - if (c <= 0x2c || - 0x2e <= c && c <= 0x2f || - 0x3a <= c && c <= 0x40 || - 0x5b <= c && c <= 0x60 || - 0x7b <= c && c <= 0x7f) { - return; - } - ++aIter; - } -} - -static PRBool -ACEEquals(const nsACString &aPattern, const nsCString &domain) -{ - if (aPattern.LowerCaseEqualsASCII(domain.get(), domain.Length())) - return PR_TRUE; - - // Convert subdomain patern to ACE - nsCString acePattern; - if (!NS_StringToACE(aPattern, acePattern)) - return PR_FALSE; - return acePattern.LowerCaseEqualsASCII(domain.get(), domain.Length()); -} - -PRBool -nsCrossSiteListenerProxy::VerifyAndMatchDomainPattern(const nsACString& aPattern) -{ - if (aPattern.EqualsLiteral("*")) { - return PR_TRUE; - } - - // access-item ::= (scheme "://")? domain-pattern (":" port)? | "*" - - nsACString::const_iterator start, iter, end; - aPattern.BeginReading(start); - aPattern.EndReading(end); - - // (scheme "://")? - nsCString patternScheme; - nsACString::const_iterator schemeStart = start, schemeEnd = end; - if (FindInReadable(NS_LITERAL_CSTRING("://"), schemeStart, schemeEnd)) { - // There is a '://' in the string which means that it must start with - // a scheme. - - iter = start; - - if (!EatAlpha(iter, end)) { - DENY_AND_RETURN PR_FALSE; - } - - while(EatAlpha(iter, end) || - EatDigit(iter, end) || - EatChar(iter, end, '+') || - EatChar(iter, end, '-') || - EatChar(iter, end, '.')) {} - - if (iter != schemeStart) { - DENY_AND_RETURN PR_FALSE; - } - - // Set the scheme - patternScheme = Substring(start, iter); - - start = iter.advance(3); - } - - // domain-pattern ::= subdomain | "*." subdomain - PRBool patternHasWild = PR_FALSE; - if (EatChar(start, end, '*')) { - if (!EatChar(start, end, '.')) { - DENY_AND_RETURN PR_FALSE; - } - patternHasWild = PR_TRUE; - } - - nsTArray patternSubdomains; - - // subdomain ::= label | subdomain "." label - do { - iter = start; - - EatSubdomainChars(iter, end); - - const nsDependentCSubstring& label = Substring(start, iter); - if (label.Last() == '-') { - DENY_AND_RETURN PR_FALSE; - } - - start = iter; - - // Save the label - patternSubdomains.AppendElement(label); - } while (EatChar(start, end, '.')); - - // (":" port)? - PRInt32 patternPort = -1; - if (EatChar(start, end, ':')) { - iter = start; - while (EatDigit(iter, end)) {} - - if (iter != start) { - PRInt32 ec; - patternPort = PromiseFlatCString(Substring(start, iter)).ToInteger(&ec); - NS_ASSERTION(NS_SUCCEEDED(ec), "ToInteger failed"); - } - - start = iter; - } - - // Did we consume the whole pattern? - if (start != end) { - DENY_AND_RETURN PR_FALSE; - } - - // Do checks at the end so that we make sure that the whole pattern is - // checked for syntax correctness first. - - // Check scheme - PRBool res; - if (!patternScheme.IsEmpty() && - (NS_FAILED(mRequestingURI->SchemeIs(patternScheme.get(), &res)) || - !res)) { - return PR_FALSE; - } - - // Check port - if (patternPort == -1 && !patternScheme.IsEmpty()) - patternPort = NS_GetDefaultPort(patternScheme.get()); - if (patternPort != -1 && patternPort != NS_GetRealPort(mRequestingURI)) { - return PR_FALSE; - } - - // Check subdomain - PRUint32 patternPos = patternSubdomains.Length(); - PRUint32 reqPos = mReqSubdomains.Length(); - do { - --patternPos; - --reqPos; - if (!ACEEquals(patternSubdomains[patternPos], mReqSubdomains[reqPos])) { - return PR_FALSE; - } - } while (patternPos > 0 && reqPos > 0); - - // Only matches if we've matched all of pattern and, if there is a wildcard, there - // is at least one more entry in mReqSubdomains. - - return patternPos == 0 && - (!patternHasWild || reqPos >= 1); -} - -NS_IMETHODIMP -nsCrossSiteListenerProxy::GetInterface(const nsIID & aIID, void **aResult) -{ - if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) { - *aResult = static_cast(this); - NS_ADDREF_THIS(); - - return NS_OK; - } - - return mOuterNotificationCallbacks ? - mOuterNotificationCallbacks->GetInterface(aIID, aResult) : - NS_ERROR_NO_INTERFACE; -} - -NS_IMETHODIMP -nsCrossSiteListenerProxy::OnChannelRedirect(nsIChannel *aOldChannel, - nsIChannel *aNewChannel, - PRUint32 aFlags) -{ - nsresult rv; - nsCOMPtr outer = - do_GetInterface(mOuterNotificationCallbacks); - if (outer) { - rv = outer->OnChannelRedirect(aOldChannel, aNewChannel, aFlags); - NS_ENSURE_SUCCESS(rv, rv); - } - - return UpdateChannel(aNewChannel); -} - -nsresult -nsCrossSiteListenerProxy::UpdateChannel(nsIChannel* aChannel) -{ - nsCOMPtr uri; - nsresult rv = aChannel->GetURI(getter_AddRefs(uri)); - NS_ENSURE_SUCCESS(rv, rv); - - // Check that the uri is ok to load - rv = nsContentUtils::GetSecurityManager()-> - CheckLoadURIWithPrincipal(mRequestingPrincipal, uri, - nsIScriptSecurityManager::STANDARD); - NS_ENSURE_SUCCESS(rv, rv); - - if (!mHasBeenCrossSite && - NS_SUCCEEDED(mRequestingPrincipal->CheckMayLoad(uri, PR_FALSE))) { - return NS_OK; - } - - nsCString userpass; - uri->GetUserPass(userpass); - NS_ENSURE_TRUE(userpass.IsEmpty(), NS_ERROR_DOM_BAD_URI); - - // It's a cross site load - mHasBeenCrossSite = PR_TRUE; - - // Work out the Referer-Root header - nsCString root, host; - rv = mRequestingURI->GetAsciiHost(host); - NS_ENSURE_SUCCESS(rv, rv); - - if (!host.IsEmpty()) { - nsCString scheme; - rv = mRequestingURI->GetScheme(scheme); - NS_ENSURE_SUCCESS(rv, rv); - - root = scheme + NS_LITERAL_CSTRING("://") + host; - - // If needed, append the port - PRInt32 port; - mRequestingURI->GetPort(&port); - if (port != -1) { - PRInt32 defaultPort = NS_GetDefaultPort(scheme.get()); - if (port != defaultPort) { - root.Append(":"); - root.AppendInt(port); - } - } - } - else { - root.AssignLiteral("null"); - } - - // Now add the access-control-origin header - nsCOMPtr http = do_QueryInterface(aChannel); - NS_ENSURE_TRUE(http, NS_ERROR_FAILURE); - - return http->SetRequestHeader(NS_LITERAL_CSTRING("Access-Control-Origin"), - root, PR_FALSE); -} diff --git a/content/base/src/nsCrossSiteListenerProxy.h b/content/base/src/nsCrossSiteListenerProxy.h deleted file mode 100644 index 1d26167d799..00000000000 --- a/content/base/src/nsCrossSiteListenerProxy.h +++ /dev/null @@ -1,109 +0,0 @@ -/* -*- 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 Foundation. - * Portions created by the Initial Developer are Copyright (C) 2007 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Jonas Sicking (Original Author) - * - * 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 "nsIStreamListener.h" -#include "nsIInterfaceRequestor.h" -#include "nsCOMPtr.h" -#include "nsString.h" -#include "nsIURI.h" -#include "nsTArray.h" -#include "nsIContentSink.h" -#include "nsIXMLContentSink.h" -#include "nsIExpatSink.h" -#include "nsIInterfaceRequestor.h" -#include "nsIChannelEventSink.h" - -class nsIURI; -class nsIParser; -class nsIPrincipal; - -class nsCrossSiteListenerProxy : public nsIStreamListener, - public nsIXMLContentSink, - public nsIExpatSink, - public nsIInterfaceRequestor, - public nsIChannelEventSink -{ -public: - nsCrossSiteListenerProxy(nsIStreamListener* aOuter, - nsIPrincipal* aRequestingPrincipal, - nsIChannel* aChannel, - nsresult* aResult); - - NS_DECL_ISUPPORTS - NS_DECL_NSIREQUESTOBSERVER - NS_DECL_NSISTREAMLISTENER - NS_DECL_NSIEXPATSINK - NS_DECL_NSIINTERFACEREQUESTOR - NS_DECL_NSICHANNELEVENTSINK - - // nsIContentSink - NS_IMETHOD WillTokenize(void) { return NS_OK; } - NS_IMETHOD WillBuildModel(void); - NS_IMETHOD DidBuildModel() { return NS_OK; } - NS_IMETHOD WillInterrupt(void) { return NS_OK; } - NS_IMETHOD WillResume(void) { return NS_OK; } - NS_IMETHOD SetParser(nsIParser* aParser) { return NS_OK; } - virtual void FlushPendingNotifications(mozFlushType aType) { } - NS_IMETHOD SetDocumentCharset(nsACString& aCharset) { return NS_OK; } - virtual nsISupports *GetTarget() { return nsnull; } - -private: - nsresult UpdateChannel(nsIChannel* aChannel); - - nsresult ForwardRequest(PRBool aCallStop); - PRBool MatchPatternList(const char*& aIter, const char* aEnd); - void CheckHeader(const nsCString& aHeader); - PRBool VerifyAndMatchDomainPattern(const nsACString& aDomainPattern); - - nsCOMPtr mOuterListener; - nsCOMPtr mOuterRequest; - nsCOMPtr mOuterContext; - nsCOMPtr mParserListener; - nsCOMPtr mParser; - nsCOMPtr mRequestingURI; - nsCOMPtr mRequestingPrincipal; - nsCOMPtr mOuterNotificationCallbacks; - nsTArray mReqSubdomains; - nsCString mStoredData; - enum { - eAccept, - eDeny, - eNotSet - } mAcceptState; - PRBool mHasForwardedRequest; - PRBool mHasBeenCrossSite; -}; diff --git a/content/base/src/nsSyncLoadService.cpp b/content/base/src/nsSyncLoadService.cpp index 5a5172f7392..936bbeccd0f 100644 --- a/content/base/src/nsSyncLoadService.cpp +++ b/content/base/src/nsSyncLoadService.cpp @@ -59,7 +59,6 @@ #include "nsAutoPtr.h" #include "nsLoadListenerProxy.h" #include "nsStreamUtils.h" -#include "nsCrossSiteListenerProxy.h" /** * This class manages loading a single XML document @@ -219,10 +218,12 @@ nsSyncLoader::LoadDocument(nsIChannel* aChannel, } if (aLoaderPrincipal) { - listener = new nsCrossSiteListenerProxy(listener, aLoaderPrincipal, - mChannel, &rv); - NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY); - NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr docURI; + rv = aChannel->GetOriginalURI(getter_AddRefs(docURI)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aLoaderPrincipal->CheckMayLoad(docURI, PR_TRUE); + NS_ENSURE_SUCCESS(rv, rv); } // Register as a load listener on the document @@ -368,6 +369,18 @@ nsSyncLoader::OnChannelRedirect(nsIChannel *aOldChannel, mChannel = aNewChannel; + nsCOMPtr oldURI; + nsresult rv = aOldChannel->GetURI(getter_AddRefs(oldURI)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr newURI; + rv = aNewChannel->GetURI(getter_AddRefs(newURI)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = nsContentUtils::GetSecurityManager()-> + CheckSameOriginURI(oldURI, newURI, PR_TRUE); + NS_ENSURE_SUCCESS(rv, rv); + return NS_OK; } diff --git a/content/base/src/nsXMLHttpRequest.cpp b/content/base/src/nsXMLHttpRequest.cpp index 42a6f684d89..62c9c5e97bd 100644 --- a/content/base/src/nsXMLHttpRequest.cpp +++ b/content/base/src/nsXMLHttpRequest.cpp @@ -82,7 +82,6 @@ #include "nsContentPolicyUtils.h" #include "nsContentErrors.h" #include "nsLayoutStatics.h" -#include "nsCrossSiteListenerProxy.h" #include "nsDOMError.h" #include "nsIHTMLDocument.h" #include "nsWhitespaceTokenizer.h" @@ -116,10 +115,8 @@ // 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_USE_XSITE_AC (1 << 13) // Internal -#define XML_HTTP_REQUEST_NON_GET (1 << 14) // Internal -#define XML_HTTP_REQUEST_GOT_FINAL_STOP (1 << 15) // Internal -#define XML_HTTP_REQUEST_BACKGROUND (1 << 16) // Internal +#define XML_HTTP_REQUEST_GOT_FINAL_STOP (1 << 13) // Internal +#define XML_HTTP_REQUEST_BACKGROUND (1 << 14) // Internal #define XML_HTTP_REQUEST_LOADSTATES \ (XML_HTTP_REQUEST_UNINITIALIZED | \ @@ -130,8 +127,6 @@ XML_HTTP_REQUEST_SENT | \ XML_HTTP_REQUEST_STOPPED) -#define ACCESS_CONTROL_CACHE_SIZE 100 - #define NS_BADCERTHANDLER_CONTRACTID \ "@mozilla.org/content/xmlhttprequest-bad-cert-handler;1" @@ -245,134 +240,6 @@ nsMultipartProxyListener::OnDataAvailable(nsIRequest *aRequest, count); } -// Class used as streamlistener and notification callback when -// doing the initial GET request for an access-control check -class nsACProxyListener : public nsIStreamListener, - public nsIInterfaceRequestor, - public nsIChannelEventSink -{ -public: - nsACProxyListener(nsIChannel* aOuterChannel, - nsIStreamListener* aOuterListener, - nsISupports* aOuterContext, - nsIPrincipal* aReferrerPrincipal, - const nsACString& aRequestMethod) - : mOuterChannel(aOuterChannel), mOuterListener(aOuterListener), - mOuterContext(aOuterContext), mReferrerPrincipal(aReferrerPrincipal), - mRequestMethod(aRequestMethod) - { } - - NS_DECL_ISUPPORTS - NS_DECL_NSISTREAMLISTENER - NS_DECL_NSIREQUESTOBSERVER - NS_DECL_NSIINTERFACEREQUESTOR - NS_DECL_NSICHANNELEVENTSINK - -private: - nsCOMPtr mOuterChannel; - nsCOMPtr mOuterListener; - nsCOMPtr mOuterContext; - nsCOMPtr mReferrerPrincipal; - nsCString mRequestMethod; -}; - -NS_IMPL_ISUPPORTS4(nsACProxyListener, nsIStreamListener, nsIRequestObserver, - nsIInterfaceRequestor, nsIChannelEventSink) - -NS_IMETHODIMP -nsACProxyListener::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) -{ - nsresult status; - nsresult rv = aRequest->GetStatus(&status); - - if (NS_SUCCEEDED(rv)) { - rv = status; - } - - if (NS_SUCCEEDED(rv)) { - // Everything worked, check to see if there is an expiration time set on - // this access control list. If so go ahead and cache it. - - nsCOMPtr http = do_QueryInterface(aRequest, &rv); - - // The "Access-Control-Max-Age" header should return an age in seconds. - nsCAutoString ageString; - http->GetResponseHeader(NS_LITERAL_CSTRING("Access-Control-Max-Age"), - ageString); - - // Sanitize the string. We only allow 'delta-seconds' as specified by - // http://dev.w3.org/2006/waf/access-control (digits 0-9 with no leading or - // trailing non-whitespace characters). We don't allow a + or - character - // but PR_sscanf does so we ensure that the first character is actually a - // digit. - ageString.StripWhitespace(); - if (ageString.CharAt(0) >= '0' || ageString.CharAt(0) <= '9') { - PRUint64 age; - PRInt32 convertedChars = PR_sscanf(ageString.get(), "%llu", &age); - if ((PRInt32)ageString.Length() == convertedChars && - nsXMLHttpRequest::EnsureACCache()) { - - // String seems fine, go ahead and cache. - nsCOMPtr uri; - http->GetURI(getter_AddRefs(uri)); - - // PR_Now gives microseconds - PRTime expirationTime = PR_Now() + age * PR_USEC_PER_SEC; - nsXMLHttpRequest::sAccessControlCache->PutEntry(uri, mReferrerPrincipal, - expirationTime); - } - } - } - - if (NS_SUCCEEDED(rv)) { - rv = mOuterChannel->AsyncOpen(mOuterListener, mOuterContext); - } - - if (NS_FAILED(rv)) { - mOuterChannel->Cancel(rv); - mOuterListener->OnStartRequest(mOuterChannel, mOuterContext); - mOuterListener->OnStopRequest(mOuterChannel, mOuterContext, rv); - - return rv; - } - - return NS_OK; -} - -NS_IMETHODIMP -nsACProxyListener::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext, - nsresult aStatus) -{ - return NS_OK; -} - -/** nsIStreamListener methods **/ - -NS_IMETHODIMP -nsACProxyListener::OnDataAvailable(nsIRequest *aRequest, - nsISupports *ctxt, - nsIInputStream *inStr, - PRUint32 sourceOffset, - PRUint32 count) -{ - return NS_OK; -} - -NS_IMETHODIMP -nsACProxyListener::OnChannelRedirect(nsIChannel *aOldChannel, - nsIChannel *aNewChannel, - PRUint32 aFlags) -{ - // No redirects allowed for now. - return NS_ERROR_DOM_BAD_URI; -} - -NS_IMETHODIMP -nsACProxyListener::GetInterface(const nsIID & aIID, void **aResult) -{ - return QueryInterface(aIID, aResult); -} - /** * Gets the nsIDocument given the script context. Will return nsnull on failure. * @@ -399,155 +266,11 @@ GetDocumentFromScriptContext(nsIScriptContext *aScriptContext) return doc; } -void -nsAccessControlLRUCache::GetEntry(nsIURI* aURI, - nsIPrincipal* aPrincipal, - PRTime* _retval) -{ - nsCAutoString key; - if (GetCacheKey(aURI, aPrincipal, key)) { - CacheEntry* entry; - if (GetEntryInternal(key, &entry)) { - *_retval = entry->value; - return; - } - } - *_retval = 0; -} - -void -nsAccessControlLRUCache::PutEntry(nsIURI* aURI, - nsIPrincipal* aPrincipal, - PRTime aValue) -{ - nsCString key; - if (!GetCacheKey(aURI, aPrincipal, key)) { - NS_WARNING("Invalid cache key!"); - return; - } - - CacheEntry* entry; - if (GetEntryInternal(key, &entry)) { - // Entry already existed, just update the expiration time and bail. The LRU - // list is updated as a result of the call to GetEntryInternal. - entry->value = aValue; - return; - } - - // This is a new entry, allocate and insert into the table now so that any - // failures don't cause items to be removed from a full cache. - entry = new CacheEntry(key, aValue); - if (!entry) { - NS_WARNING("Failed to allocate new cache entry!"); - return; - } - - if (!mTable.Put(key, entry)) { - // Failed, clean up the new entry. - delete entry; - - NS_WARNING("Failed to add entry to the access control cache!"); - return; - } - - PR_INSERT_LINK(entry, &mList); - - NS_ASSERTION(mTable.Count() <= ACCESS_CONTROL_CACHE_SIZE + 1, - "Something is borked, too many entries in the cache!"); - - // Now enforce the max count. - if (mTable.Count() > ACCESS_CONTROL_CACHE_SIZE) { - // Try to kick out all the expired entries. - PRTime now = PR_Now(); - mTable.Enumerate(RemoveExpiredEntries, &now); - - // If that didn't remove anything then kick out the least recently used - // entry. - if (mTable.Count() > ACCESS_CONTROL_CACHE_SIZE) { - CacheEntry* lruEntry = static_cast(PR_LIST_TAIL(&mList)); - PR_REMOVE_LINK(lruEntry); - - // This will delete 'lruEntry'. - mTable.Remove(lruEntry->key); - - NS_ASSERTION(mTable.Count() >= ACCESS_CONTROL_CACHE_SIZE, - "Somehow tried to remove an entry that was never added!"); - } - } -} - -void -nsAccessControlLRUCache::Clear() -{ - PR_INIT_CLIST(&mList); - mTable.Clear(); -} - -PRBool -nsAccessControlLRUCache::GetEntryInternal(const nsACString& aKey, - CacheEntry** _retval) -{ - if (!mTable.Get(aKey, _retval)) - return PR_FALSE; - - // Move to the head of the list. - PR_REMOVE_LINK(*_retval); - PR_INSERT_LINK(*_retval, &mList); - - return PR_TRUE; -} - -/* static */ PR_CALLBACK PLDHashOperator -nsAccessControlLRUCache::RemoveExpiredEntries(const nsACString& aKey, - nsAutoPtr& aValue, - void* aUserData) -{ - PRTime* now = static_cast(aUserData); - if (*now >= aValue->value) { - // Expired, remove from the list as well as the hash table. - PR_REMOVE_LINK(aValue); - return PL_DHASH_REMOVE; - } - // Keep going. - return PL_DHASH_NEXT; -} - -/* static */ PRBool -nsAccessControlLRUCache::GetCacheKey(nsIURI* aURI, - nsIPrincipal* aPrincipal, - nsACString& _retval) -{ - NS_ASSERTION(aURI, "Null uri!"); - NS_ASSERTION(aPrincipal, "Null principal!"); - - NS_NAMED_LITERAL_CSTRING(space, " "); - - nsCOMPtr uri; - nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri)); - NS_ENSURE_SUCCESS(rv, PR_FALSE); - - nsCAutoString host; - if (uri) { - uri->GetHost(host); - } - - nsCAutoString spec; - rv = aURI->GetSpec(spec); - NS_ENSURE_SUCCESS(rv, PR_FALSE); - - _retval.Assign(host + space + spec); - - return PR_TRUE; -} - ///////////////////////////////////////////// // // ///////////////////////////////////////////// -// Will be initialized in nsXMLHttpRequest::EnsureACCache. -nsAccessControlLRUCache* nsXMLHttpRequest::sAccessControlCache = nsnull; - nsXMLHttpRequest::nsXMLHttpRequest() : mState(XML_HTTP_REQUEST_UNINITIALIZED) { @@ -1122,9 +845,6 @@ nsXMLHttpRequest::Abort() if (mChannel) { mChannel->Cancel(NS_BINDING_ABORTED); } - if (mACGetChannel) { - mACGetChannel->Cancel(NS_BINDING_ABORTED); - } mDocument = nsnull; mResponseBody.Truncate(); mState |= XML_HTTP_REQUEST_ABORTED; @@ -1152,10 +872,6 @@ nsXMLHttpRequest::GetAllResponseHeaders(char **_retval) NS_ENSURE_ARG_POINTER(_retval); *_retval = nsnull; - if (mState & XML_HTTP_REQUEST_USE_XSITE_AC) { - return NS_OK; - } - nsCOMPtr httpChannel = GetCurrentHttpChannel(); if (httpChannel) { @@ -1184,37 +900,6 @@ nsXMLHttpRequest::GetResponseHeader(const nsACString& header, nsresult rv = NS_OK; _retval.Truncate(); - // Check for dangerous headers - if (mState & XML_HTTP_REQUEST_USE_XSITE_AC) { - - // Make sure we don't leak header information from denied cross-site - // requests. - if (mChannel) { - nsresult status; - mChannel->GetStatus(&status); - if (NS_FAILED(status)) { - return NS_OK; - } - } - - const char *kCrossOriginSafeHeaders[] = { - "cache-control", "content-language", "content-type", "expires", - "last-modified", "pragma" - }; - PRBool safeHeader = PR_FALSE; - PRUint32 i; - for (i = 0; i < NS_ARRAY_LENGTH(kCrossOriginSafeHeaders); ++i) { - if (header.LowerCaseEqualsASCII(kCrossOriginSafeHeaders[i])) { - safeHeader = PR_TRUE; - break; - } - } - - if (!safeHeader) { - return NS_OK; - } - } - nsCOMPtr httpChannel = GetCurrentHttpChannel(); if (httpChannel) { @@ -1416,34 +1101,6 @@ IsSameOrigin(nsIPrincipal* aPrincipal, nsIChannel* aChannel) return NS_SUCCEEDED(rv); } -nsresult -nsXMLHttpRequest::CheckChannelForCrossSiteRequest() -{ - // First check if this is a same-origin request, or if cross-site requests - // are enabled. - if ((mState & XML_HTTP_REQUEST_XSITEENABLED) || - IsSameOrigin(mPrincipal, mChannel)) { - return NS_OK; - } - - // This is a cross-site request - - // The request is now cross-site, so update flag. - mState |= XML_HTTP_REQUEST_USE_XSITE_AC; - - // Remove dangerous headers - nsCOMPtr http = do_QueryInterface(mChannel); - if (http) { - PRUint32 i; - for (i = 0; i < mExtraRequestHeaders.Length(); ++i) { - http->SetRequestHeader(mExtraRequestHeaders[i], EmptyCString(), PR_FALSE); - } - mExtraRequestHeaders.Clear(); - } - - return NS_OK; -} - /* noscript void openRequest (in AUTF8String method, in AUTF8String url, in boolean async, in AString user, in AString password); */ NS_IMETHODIMP nsXMLHttpRequest::OpenRequest(const nsACString& method, @@ -1561,46 +1218,11 @@ nsXMLHttpRequest::OpenRequest(const nsACString& method, // Chrome callers are always allowed to read from different origins. mState |= XML_HTTP_REQUEST_XSITEENABLED; } - else if (!(mState & XML_HTTP_REQUEST_XSITEENABLED) && - !IsSameOrigin(mPrincipal, mChannel)) { - mState |= XML_HTTP_REQUEST_USE_XSITE_AC; - } nsCOMPtr httpChannel(do_QueryInterface(mChannel)); if (httpChannel) { rv = httpChannel->SetRequestMethod(method); NS_ENSURE_SUCCESS(rv, rv); - - if (!method.LowerCaseEqualsLiteral("get")) { - mState |= XML_HTTP_REQUEST_NON_GET; - } - } - - // Do we need to set up an initial OPTIONS request to make sure that it is - // safe to make the request? - if ((mState & XML_HTTP_REQUEST_USE_XSITE_AC) && - (mState & XML_HTTP_REQUEST_NON_GET)) { - - // Check to see if this initial OPTIONS request has already been cached in - // our special Access Control Cache. - PRTime expiration = 0; - if (sAccessControlCache) { - sAccessControlCache->GetEntry(uri, mPrincipal, &expiration); - } - - if (expiration <= PR_Now()) { - // Either it wasn't cached or the cached result has expired. Build a - // channel for the OPTIONS request. - rv = NS_NewChannel(getter_AddRefs(mACGetChannel), uri, nsnull, loadGroup, - nsnull, loadFlags); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr acHttp = do_QueryInterface(mACGetChannel); - NS_ASSERTION(acHttp, "Failed to QI to nsIHttpChannel!"); - - rv = acHttp->SetRequestMethod(NS_LITERAL_CSTRING("OPTIONS")); - NS_ENSURE_SUCCESS(rv, rv); - } } ChangeState(XML_HTTP_REQUEST_OPENED); @@ -1644,7 +1266,7 @@ nsXMLHttpRequest::Open(const nsACString& method, const nsACString& url) return NS_ERROR_FAILURE; } - rv = secMan->CheckConnect(cx, targetURI, "XMLHttpRequest", "open-uri"); + rv = secMan->CheckConnect(cx, targetURI, "XMLHttpRequest", "open"); if (NS_FAILED(rv)) { // Security check failed. @@ -1816,13 +1438,6 @@ nsXMLHttpRequest::OnStartRequest(nsIRequest *request, nsISupports *ctxt) getter_AddRefs(mDocument)); NS_ENSURE_SUCCESS(rv, rv); - if (mState & XML_HTTP_REQUEST_USE_XSITE_AC) { - nsCOMPtr htmlDoc = do_QueryInterface(mDocument); - if (htmlDoc) { - htmlDoc->DisableCookieAccess(); - } - } - // Reset responseBody mResponseBody.Truncate(); @@ -2275,9 +1890,6 @@ nsXMLHttpRequest::Send(nsIVariant *aBody) mState |= XML_HTTP_REQUEST_SYNCLOOPING; } - rv = CheckChannelForCrossSiteRequest(); - NS_ENSURE_SUCCESS(rv, rv); - // Hook us up to listen to redirects and the like mChannel->GetNotificationCallbacks(getter_AddRefs(mNotificationCallbacks)); mChannel->SetNotificationCallbacks(this); @@ -2291,15 +1903,6 @@ nsXMLHttpRequest::Send(nsIVariant *aBody) } } - if (!(mState & XML_HTTP_REQUEST_XSITEENABLED)) { - // 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, - &rv); - NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY); - NS_ENSURE_SUCCESS(rv, rv); - } - // Bypass the network cache in cases where it makes no sense: // 1) Multipart responses are very large and would likely be doomed by the // cache once they grow too large, so they are not worth caching. @@ -2316,10 +1919,6 @@ nsXMLHttpRequest::Send(nsIVariant *aBody) else if (mState & XML_HTTP_REQUEST_SYNCLOOPING) { AddLoadFlags(mChannel, nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY); - if (mACGetChannel) { - AddLoadFlags(mACGetChannel, - nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY); - } } // Since we expect XML data, set the type hint accordingly @@ -2327,24 +1926,8 @@ nsXMLHttpRequest::Send(nsIVariant *aBody) // ignoring return value, as this is not critical mChannel->SetContentType(NS_LITERAL_CSTRING("application/xml")); - // If we're doing a cross-site non-GET request we need to first do - // a GET request to the same URI. Set that up if needed - if (mACGetChannel) { - nsCOMPtr acListener = - new nsACProxyListener(mChannel, listener, nsnull, mPrincipal, method); - NS_ENSURE_TRUE(acListener, NS_ERROR_OUT_OF_MEMORY); - - listener = new nsCrossSiteListenerProxy(acListener, mPrincipal, - mACGetChannel, &rv); - NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY); - NS_ENSURE_SUCCESS(rv, rv); - - rv = mACGetChannel->AsyncOpen(listener, nsnull); - } - else { - // Start reading from the channel - rv = mChannel->AsyncOpen(listener, nsnull); - } + // Start reading from the channel + rv = mChannel->AsyncOpen(listener, nsnull); if (NS_FAILED(rv)) { // Drop our ref to the channel to avoid cycles @@ -2383,19 +1966,6 @@ nsXMLHttpRequest::SetRequestHeader(const nsACString& header, { nsresult rv; - // Check that we haven't already opened the channel. We can't rely on - // the channel throwing from mChannel->SetRequestHeader since we might - // still be waiting for mACGetChannel to actually open mChannel - if (mACGetChannel) { - PRBool pending; - rv = mACGetChannel->IsPending(&pending); - NS_ENSURE_SUCCESS(rv, rv); - - if (pending) { - return NS_ERROR_IN_PROGRESS; - } - } - if (!mChannel) // open() initializes mChannel, and open() return NS_ERROR_FAILURE; // must be called before first setRequestHeader() @@ -2427,32 +1997,6 @@ nsXMLHttpRequest::SetRequestHeader(const nsACString& header, return NS_OK; } } - - // Check for dangerous cross-site headers - PRBool safeHeader = !!(mState & XML_HTTP_REQUEST_XSITEENABLED); - if (!safeHeader) { - const char *kCrossOriginSafeHeaders[] = { - "accept", "accept-language" - }; - for (i = 0; i < NS_ARRAY_LENGTH(kCrossOriginSafeHeaders); ++i) { - if (header.LowerCaseEqualsASCII(kCrossOriginSafeHeaders[i])) { - safeHeader = PR_TRUE; - break; - } - } - } - - if (!safeHeader) { - // The header is unsafe for cross-site requests. If this is a cross-site - // request throw an exception... - if (mState & XML_HTTP_REQUEST_USE_XSITE_AC) { - return NS_ERROR_FAILURE; - } - - // ...otherwise just add it to mExtraRequestHeaders so that we can - // remove it in case we're redirected to another site - mExtraRequestHeaders.AppendElement(header); - } } // We need to set, not add to, the header. @@ -2693,18 +2237,19 @@ nsXMLHttpRequest::OnChannelRedirect(nsIChannel *aOldChannel, NS_ENSURE_SUCCESS(rv, rv); } - mChannel = aNewChannel; - - rv = CheckChannelForCrossSiteRequest(); + nsCOMPtr oldURI; + rv = aOldChannel->GetURI(getter_AddRefs(oldURI)); NS_ENSURE_SUCCESS(rv, rv); - // Disable redirects for non-get cross-site requests entirely for now - // Note, do this after the call to CheckChannelForCrossSiteRequest - // to make sure that XML_HTTP_REQUEST_USE_XSITE_AC is up-to-date - if ((mState & XML_HTTP_REQUEST_NON_GET) && - (mState & XML_HTTP_REQUEST_USE_XSITE_AC)) { - return NS_ERROR_DOM_BAD_URI; - } + nsCOMPtr newURI; + rv = aNewChannel->GetURI(getter_AddRefs(newURI)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = nsContentUtils::GetSecurityManager()-> + CheckSameOriginURI(oldURI, newURI, PR_TRUE); + NS_ENSURE_SUCCESS(rv, rv); + + mChannel = aNewChannel; return NS_OK; } diff --git a/content/base/src/nsXMLHttpRequest.h b/content/base/src/nsXMLHttpRequest.h index 20367a38a6d..84b48b9326c 100644 --- a/content/base/src/nsXMLHttpRequest.h +++ b/content/base/src/nsXMLHttpRequest.h @@ -70,65 +70,6 @@ class nsILoadGroup; -class nsAccessControlLRUCache -{ - struct CacheEntry : public PRCList - { - CacheEntry(const nsACString& aKey, PRTime aValue) - : key(aKey), value(aValue) - { - MOZ_COUNT_CTOR(nsAccessControlLRUCache::CacheEntry); - } - - ~CacheEntry() - { - MOZ_COUNT_DTOR(nsAccessControlLRUCache::CacheEntry); - } - - nsCString key; - PRTime value; - }; - -public: - nsAccessControlLRUCache() - { - MOZ_COUNT_CTOR(nsAccessControlLRUCache); - PR_INIT_CLIST(&mList); - } - - ~nsAccessControlLRUCache() - { - Clear(); - MOZ_COUNT_DTOR(nsAccessControlLRUCache); - } - - PRBool Initialize() - { - return mTable.Init(); - } - - void GetEntry(nsIURI* aURI, nsIPrincipal* aPrincipal, - PRTime* _retval); - - void PutEntry(nsIURI* aURI, nsIPrincipal* aPrincipal, - PRTime aValue); - - void Clear(); - -private: - PRBool GetEntryInternal(const nsACString& aKey, CacheEntry** _retval); - - PR_STATIC_CALLBACK(PLDHashOperator) - RemoveExpiredEntries(const nsACString& aKey, nsAutoPtr& aValue, - void* aUserData); - - static PRBool GetCacheKey(nsIURI* aURI, nsIPrincipal* aPrincipal, - nsACString& _retval); - - nsClassHashtable mTable; - PRCList mList; -}; - class nsXMLHttpRequest : public nsIXMLHttpRequest, public nsIJSXMLHttpRequest, public nsIDOMLoadListener, @@ -189,32 +130,6 @@ public: NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXMLHttpRequest, nsIXMLHttpRequest) - static PRBool EnsureACCache() - { - if (sAccessControlCache) - return PR_TRUE; - - nsAutoPtr newCache(new nsAccessControlLRUCache()); - NS_ENSURE_TRUE(newCache, PR_FALSE); - - if (newCache->Initialize()) { - sAccessControlCache = newCache.forget(); - return PR_TRUE; - } - - return PR_FALSE; - } - - static void ShutdownACCache() - { - if (sAccessControlCache) { - delete sAccessControlCache; - sAccessControlCache = nsnull; - } - } - - static nsAccessControlLRUCache* sAccessControlCache; - protected: nsresult DetectCharset(nsACString& aCharset); @@ -281,7 +196,6 @@ protected: // mReadRequest is different from mChannel for multipart requests nsCOMPtr mReadRequest; nsCOMPtr mDocument; - nsCOMPtr mACGetChannel; nsCOMArray mLoadEventListeners; nsCOMArray mErrorEventListeners; diff --git a/content/base/test/Makefile.in b/content/base/test/Makefile.in index 8192f9dfdc4..a8ffceb9fe7 100644 --- a/content/base/test/Makefile.in +++ b/content/base/test/Makefile.in @@ -131,31 +131,6 @@ _TEST_FILES = test_bug5141.html \ test_bug398243.html \ formReset.html \ bug382113_object.html \ - test_CrossSiteXHR.html \ - file_CrossSiteXHR_fail1.xml \ - file_CrossSiteXHR_fail2.xml \ - file_CrossSiteXHR_fail2.xml^headers^ \ - file_CrossSiteXHR_fail3.xml \ - file_CrossSiteXHR_fail4.xml \ - file_CrossSiteXHR_pass1.xml \ - file_CrossSiteXHR_pass1.xml^headers^ \ - file_CrossSiteXHR_pass2.xml \ - file_CrossSiteXHR_pass3.xml \ - test_CrossSiteXHR2.html \ - file_CrossSiteXHR2_inner.html \ - file_CrossSiteXHR2_fail1.xml \ - file_CrossSiteXHR2_fail1.xml^headers^ \ - file_CrossSiteXHR2_fail2.xml \ - file_CrossSiteXHR2_pass1.xml \ - file_CrossSiteXHR2_pass1.xml^headers^ \ - file_CrossSiteXHR2_pass2.xml \ - file_CrossSiteXHR2_pass3.xml \ - file_CrossSiteXHR2_pass3.xml^headers^ \ - file_CrossSiteXHR2_pass3_redirect.xml \ - test_CrossSiteXHR3.html \ - file_CrossSiteXHR3_inner.html \ - file_CrossSiteXHR3_pass1.xml^headers^ \ - file_CrossSiteXHR3_pass1.xml \ test_bug326337.html \ file_bug326337_inner.html \ file_bug326337_outer.html \ @@ -185,6 +160,13 @@ _TEST_FILES = test_bug5141.html \ test_bug421602.html \ test_bug422537.html \ test_bug424212.html \ + test_XHR.html \ + file_XHR_pass1.xml \ + file_XHR_pass2.txt \ + file_XHR_pass3.txt \ + file_XHR_pass3.txt^headers^ \ + file_XHR_fail1.txt \ + file_XHR_fail1.txt^headers^ \ $(NULL) libs:: $(_TEST_FILES) diff --git a/content/base/test/file_CrossSiteXHR2_fail1.xml^headers^ b/content/base/test/file_CrossSiteXHR2_fail1.xml^headers^ deleted file mode 100644 index 4041b985700..00000000000 --- a/content/base/test/file_CrossSiteXHR2_fail1.xml^headers^ +++ /dev/null @@ -1,2 +0,0 @@ -HTTP 200 OK -Access-Control: allow diff --git a/content/base/test/file_CrossSiteXHR2_fail2.xml b/content/base/test/file_CrossSiteXHR2_fail2.xml deleted file mode 100644 index ef3f5a75bb1..00000000000 --- a/content/base/test/file_CrossSiteXHR2_fail2.xml +++ /dev/null @@ -1,2 +0,0 @@ - -hello diff --git a/content/base/test/file_CrossSiteXHR2_inner.html b/content/base/test/file_CrossSiteXHR2_inner.html deleted file mode 100644 index b650b073347..00000000000 --- a/content/base/test/file_CrossSiteXHR2_inner.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - diff --git a/content/base/test/file_CrossSiteXHR2_pass1.xml b/content/base/test/file_CrossSiteXHR2_pass1.xml deleted file mode 100644 index 06826d6c675..00000000000 --- a/content/base/test/file_CrossSiteXHR2_pass1.xml +++ /dev/null @@ -1 +0,0 @@ -hello diff --git a/content/base/test/file_CrossSiteXHR2_pass1.xml^headers^ b/content/base/test/file_CrossSiteXHR2_pass1.xml^headers^ deleted file mode 100644 index 56d5a2e22b0..00000000000 --- a/content/base/test/file_CrossSiteXHR2_pass1.xml^headers^ +++ /dev/null @@ -1,2 +0,0 @@ -HTTP 200 OK -Access-Control: allow diff --git a/content/base/test/file_CrossSiteXHR2_pass2.xml b/content/base/test/file_CrossSiteXHR2_pass2.xml deleted file mode 100644 index 2c1cef2a6a8..00000000000 --- a/content/base/test/file_CrossSiteXHR2_pass2.xml +++ /dev/null @@ -1,2 +0,0 @@ - -hello diff --git a/content/base/test/file_CrossSiteXHR2_pass3.xml b/content/base/test/file_CrossSiteXHR2_pass3.xml deleted file mode 100644 index e3c4ae65ada..00000000000 --- a/content/base/test/file_CrossSiteXHR2_pass3.xml +++ /dev/null @@ -1 +0,0 @@ -wrong, should redirect diff --git a/content/base/test/file_CrossSiteXHR2_pass3.xml^headers^ b/content/base/test/file_CrossSiteXHR2_pass3.xml^headers^ deleted file mode 100644 index 8da0b49d64d..00000000000 --- a/content/base/test/file_CrossSiteXHR2_pass3.xml^headers^ +++ /dev/null @@ -1,2 +0,0 @@ -HTTP 301 Moved Permanently -Location: http://test1.example.org/tests/content/base/test/file_CrossSiteXHR2_pass3_redirect.xml diff --git a/content/base/test/file_CrossSiteXHR2_pass3_redirect.xml b/content/base/test/file_CrossSiteXHR2_pass3_redirect.xml deleted file mode 100644 index 2c1cef2a6a8..00000000000 --- a/content/base/test/file_CrossSiteXHR2_pass3_redirect.xml +++ /dev/null @@ -1,2 +0,0 @@ - -hello diff --git a/content/base/test/file_CrossSiteXHR3_inner.html b/content/base/test/file_CrossSiteXHR3_inner.html deleted file mode 100644 index 2ceedcdbc46..00000000000 --- a/content/base/test/file_CrossSiteXHR3_inner.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - diff --git a/content/base/test/file_CrossSiteXHR3_pass1.xml b/content/base/test/file_CrossSiteXHR3_pass1.xml deleted file mode 100644 index 06826d6c675..00000000000 --- a/content/base/test/file_CrossSiteXHR3_pass1.xml +++ /dev/null @@ -1 +0,0 @@ -hello diff --git a/content/base/test/file_CrossSiteXHR3_pass1.xml^headers^ b/content/base/test/file_CrossSiteXHR3_pass1.xml^headers^ deleted file mode 100644 index c4aec3e1d30..00000000000 --- a/content/base/test/file_CrossSiteXHR3_pass1.xml^headers^ +++ /dev/null @@ -1,2 +0,0 @@ -HTTP 200 OK -Access-Control: allow diff --git a/content/base/test/file_CrossSiteXHR_fail1.xml b/content/base/test/file_CrossSiteXHR_fail1.xml deleted file mode 100644 index a26de53a26d..00000000000 --- a/content/base/test/file_CrossSiteXHR_fail1.xml +++ /dev/null @@ -1 +0,0 @@ -hello diff --git a/content/base/test/file_CrossSiteXHR_fail2.xml b/content/base/test/file_CrossSiteXHR_fail2.xml deleted file mode 100644 index f35f8b1cd4e..00000000000 --- a/content/base/test/file_CrossSiteXHR_fail2.xml +++ /dev/null @@ -1,2 +0,0 @@ - -hello diff --git a/content/base/test/file_CrossSiteXHR_fail2.xml^headers^ b/content/base/test/file_CrossSiteXHR_fail2.xml^headers^ deleted file mode 100644 index 646a36924d7..00000000000 --- a/content/base/test/file_CrossSiteXHR_fail2.xml^headers^ +++ /dev/null @@ -1,2 +0,0 @@ -HTTP 200 OK -Access-Control: allow <*>, deny <*> diff --git a/content/base/test/file_CrossSiteXHR_fail3.xml b/content/base/test/file_CrossSiteXHR_fail3.xml deleted file mode 100644 index 9d0b2e17e38..00000000000 --- a/content/base/test/file_CrossSiteXHR_fail3.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - -hello diff --git a/content/base/test/file_CrossSiteXHR_fail4.xml b/content/base/test/file_CrossSiteXHR_fail4.xml deleted file mode 100644 index a5d3b03d34a..00000000000 --- a/content/base/test/file_CrossSiteXHR_fail4.xml +++ /dev/null @@ -1,3 +0,0 @@ - -> -hello diff --git a/content/base/test/file_CrossSiteXHR_pass1.xml b/content/base/test/file_CrossSiteXHR_pass1.xml deleted file mode 100644 index a26de53a26d..00000000000 --- a/content/base/test/file_CrossSiteXHR_pass1.xml +++ /dev/null @@ -1 +0,0 @@ -hello diff --git a/content/base/test/file_CrossSiteXHR_pass1.xml^headers^ b/content/base/test/file_CrossSiteXHR_pass1.xml^headers^ deleted file mode 100644 index 4c535d9a12b..00000000000 --- a/content/base/test/file_CrossSiteXHR_pass1.xml^headers^ +++ /dev/null @@ -1,2 +0,0 @@ -HTTP 200 OK -Access-Control: allow exclude , deny <*> exclude diff --git a/content/base/test/file_CrossSiteXHR_pass2.xml b/content/base/test/file_CrossSiteXHR_pass2.xml deleted file mode 100644 index f35f8b1cd4e..00000000000 --- a/content/base/test/file_CrossSiteXHR_pass2.xml +++ /dev/null @@ -1,2 +0,0 @@ - -hello diff --git a/content/base/test/file_CrossSiteXHR_pass3.xml b/content/base/test/file_CrossSiteXHR_pass3.xml deleted file mode 100644 index a75a35d45ce..00000000000 --- a/content/base/test/file_CrossSiteXHR_pass3.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - -hello diff --git a/content/base/test/file_XHR_fail1.txt b/content/base/test/file_XHR_fail1.txt new file mode 100644 index 00000000000..462209d8da4 --- /dev/null +++ b/content/base/test/file_XHR_fail1.txt @@ -0,0 +1 @@ +redirect file diff --git a/content/base/test/file_XHR_fail1.txt^headers^ b/content/base/test/file_XHR_fail1.txt^headers^ new file mode 100644 index 00000000000..74d6d705997 --- /dev/null +++ b/content/base/test/file_XHR_fail1.txt^headers^ @@ -0,0 +1,2 @@ +HTTP 301 Moved Permanently +Location: http://example.com/tests/content/base/test/file_XHR_pass2.txt diff --git a/content/base/test/file_XHR_fail1b.txt b/content/base/test/file_XHR_fail1b.txt new file mode 100644 index 00000000000..8944657af12 --- /dev/null +++ b/content/base/test/file_XHR_fail1b.txt @@ -0,0 +1 @@ +hello pass diff --git a/content/base/test/file_CrossSiteXHR2_fail1.xml b/content/base/test/file_XHR_pass1.xml similarity index 100% rename from content/base/test/file_CrossSiteXHR2_fail1.xml rename to content/base/test/file_XHR_pass1.xml diff --git a/content/base/test/file_XHR_pass2.txt b/content/base/test/file_XHR_pass2.txt new file mode 100644 index 00000000000..0d7f879f95e --- /dev/null +++ b/content/base/test/file_XHR_pass2.txt @@ -0,0 +1 @@ +hello pass diff --git a/content/base/test/file_XHR_pass3.txt b/content/base/test/file_XHR_pass3.txt new file mode 100644 index 00000000000..462209d8da4 --- /dev/null +++ b/content/base/test/file_XHR_pass3.txt @@ -0,0 +1 @@ +redirect file diff --git a/content/base/test/file_XHR_pass3.txt^headers^ b/content/base/test/file_XHR_pass3.txt^headers^ new file mode 100644 index 00000000000..fb5056c3821 --- /dev/null +++ b/content/base/test/file_XHR_pass3.txt^headers^ @@ -0,0 +1,2 @@ +HTTP 301 Moved Permanently +Location: file_XHR_pass2.txt diff --git a/content/base/test/test_CrossSiteXHR2.html b/content/base/test/test_CrossSiteXHR2.html deleted file mode 100644 index f7093f2afbb..00000000000 --- a/content/base/test/test_CrossSiteXHR2.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - Test for Cross Site XMLHttpRequest with IDN - - - - - -

- - - - -
-
-
- - diff --git a/content/base/test/test_CrossSiteXHR3.html b/content/base/test/test_CrossSiteXHR3.html deleted file mode 100644 index 46d6ed620d5..00000000000 --- a/content/base/test/test_CrossSiteXHR3.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - Test for Cross Site XMLHttpRequest with Referer-Root - - - - - -

- - - - -
-
-
- - diff --git a/content/base/test/test_CrossSiteXHR.html b/content/base/test/test_XHR.html similarity index 62% rename from content/base/test/test_CrossSiteXHR.html rename to content/base/test/test_XHR.html index e7f671912ed..17d3eedab10 100644 --- a/content/base/test/test_CrossSiteXHR.html +++ b/content/base/test/test_XHR.html @@ -1,7 +1,7 @@ - Test for Cross Site XMLHttpRequest + Test for XMLHttpRequest @@ -14,17 +14,16 @@
 
 
diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp index 7778a9d77ac..18068c29cb8 100644 --- a/content/html/document/src/nsHTMLDocument.cpp +++ b/content/html/document/src/nsHTMLDocument.cpp @@ -1987,10 +1987,6 @@ nsHTMLDocument::GetCookie(nsAString& aCookie) aCookie.Truncate(); // clear current cookie in case service fails; // no cookie isn't an error condition. - if (mDisableCookieAccess) { - return NS_OK; - } - // not having a cookie service isn't an error nsCOMPtr service = do_GetService(NS_COOKIESERVICE_CONTRACTID); if (service) { @@ -2017,10 +2013,6 @@ nsHTMLDocument::GetCookie(nsAString& aCookie) NS_IMETHODIMP nsHTMLDocument::SetCookie(const nsAString& aCookie) { - if (mDisableCookieAccess) { - return NS_OK; - } - // not having a cookie service isn't an error nsCOMPtr service = do_GetService(NS_COOKIESERVICE_CONTRACTID); if (service && mDocumentURI) { diff --git a/content/html/document/src/nsHTMLDocument.h b/content/html/document/src/nsHTMLDocument.h index 3cdffd89bcb..a25da1cb774 100644 --- a/content/html/document/src/nsHTMLDocument.h +++ b/content/html/document/src/nsHTMLDocument.h @@ -208,11 +208,6 @@ public: return mEditingState; } - virtual void DisableCookieAccess() - { - mDisableCookieAccess = PR_TRUE; - } - virtual nsIContent* GetBodyContentExternal(); void EndUpdate(nsUpdateType aUpdateType); @@ -391,8 +386,6 @@ protected: // SetContentType() on this document? PRInt32 mDefaultNamespaceID; - PRBool mDisableCookieAccess; - // Parser used for constructing document fragments. nsCOMPtr mFragmentParser; }; diff --git a/content/html/document/src/nsIHTMLDocument.h b/content/html/document/src/nsIHTMLDocument.h index 736d66b4886..1c15f4616e2 100644 --- a/content/html/document/src/nsIHTMLDocument.h +++ b/content/html/document/src/nsIHTMLDocument.h @@ -173,11 +173,6 @@ public: virtual nsresult GetDocumentAllResult(const nsAString& aID, nsISupports** aResult) = 0; - /** - * Disables getting and setting cookies - */ - virtual void DisableCookieAccess() = 0; - /** * Get the first child of the root , but don't do * anything -related (like nsIDOMHTMLDocument::GetBody). diff --git a/content/xslt/src/xslt/txMozillaStylesheetCompiler.cpp b/content/xslt/src/xslt/txMozillaStylesheetCompiler.cpp index adffb4a286c..4c551635ee2 100644 --- a/content/xslt/src/xslt/txMozillaStylesheetCompiler.cpp +++ b/content/xslt/src/xslt/txMozillaStylesheetCompiler.cpp @@ -70,7 +70,6 @@ #include "nsAttrName.h" #include "nsIScriptError.h" #include "nsIURL.h" -#include "nsCrossSiteListenerProxy.h" #include "nsDOMError.h" static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID); @@ -96,6 +95,7 @@ getSpec(nsIChannel* aChannel, nsAString& aSpec) class txStylesheetSink : public nsIXMLContentSink, public nsIExpatSink, public nsIStreamListener, + public nsIChannelEventSink, public nsIInterfaceRequestor { public: @@ -105,6 +105,7 @@ public: NS_DECL_NSIEXPATSINK NS_DECL_NSISTREAMLISTENER NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSICHANNELEVENTSINK NS_DECL_NSIINTERFACEREQUESTOR // nsIContentSink @@ -136,12 +137,13 @@ txStylesheetSink::txStylesheetSink(txStylesheetCompiler* aCompiler, mListener = do_QueryInterface(aParser); } -NS_IMPL_ISUPPORTS6(txStylesheetSink, +NS_IMPL_ISUPPORTS7(txStylesheetSink, nsIXMLContentSink, nsIContentSink, nsIExpatSink, nsIStreamListener, nsIRequestObserver, + nsIChannelEventSink, nsIInterfaceRequestor) NS_IMETHODIMP @@ -373,6 +375,29 @@ txStylesheetSink::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext, return rv; } +NS_IMETHODIMP +txStylesheetSink::OnChannelRedirect(nsIChannel *aOldChannel, + nsIChannel *aNewChannel, + PRUint32 aFlags) +{ + NS_PRECONDITION(aNewChannel, "Redirecting to null channel?"); + + nsCOMPtr oldURI; + nsresult rv = aOldChannel->GetURI(getter_AddRefs(oldURI)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr newURI; + rv = aNewChannel->GetURI(getter_AddRefs(newURI)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = nsContentUtils::GetSecurityManager()-> + CheckSameOriginURI(oldURI, newURI, PR_TRUE); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + + NS_IMETHODIMP txStylesheetSink::GetInterface(const nsIID& aIID, void** aResult) { @@ -396,7 +421,7 @@ txStylesheetSink::GetInterface(const nsIID& aIID, void** aResult) return NS_OK; } - return NS_ERROR_NO_INTERFACE; + return QueryInterface(aIID, aResult); } class txCompileObserver : public txACompileObserver @@ -469,19 +494,13 @@ txCompileObserver::loadURI(const nsAString& aUri, GetCodebasePrincipal(referrerUri, getter_AddRefs(referrerPrincipal)); NS_ENSURE_SUCCESS(rv, rv); - // Content Policy - PRInt16 shouldLoad = nsIContentPolicy::ACCEPT; - rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_STYLESHEET, - uri, - referrerPrincipal, - nsnull, - NS_LITERAL_CSTRING("application/xml"), - nsnull, - &shouldLoad); + // Do security check + rv = nsContentUtils:: + CheckSecurityBeforeLoad(uri, referrerPrincipal, + nsIScriptSecurityManager::STANDARD, PR_FALSE, + nsIContentPolicy::TYPE_STYLESHEET, + nsnull, NS_LITERAL_CSTRING("application/xml")); NS_ENSURE_SUCCESS(rv, rv); - if (NS_CP_REJECTED(shouldLoad)) { - return NS_ERROR_DOM_BAD_URI; - } return startLoad(uri, aCompiler, referrerPrincipal); } @@ -537,13 +556,7 @@ txCompileObserver::startLoad(nsIURI* aUri, txStylesheetCompiler* aCompiler, parser->SetContentSink(sink); parser->Parse(aUri); - // Always install in case of redirects - nsCOMPtr listener = - new nsCrossSiteListenerProxy(sink, aReferrerPrincipal, channel, &rv); - NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY); - NS_ENSURE_SUCCESS(rv, rv); - - return channel->AsyncOpen(listener, parser); + return channel->AsyncOpen(sink, parser); } nsresult @@ -554,20 +567,14 @@ TX_LoadSheet(nsIURI* aUri, txMozillaXSLTProcessor* aProcessor, aUri->GetSpec(spec); PR_LOG(txLog::xslt, PR_LOG_ALWAYS, ("TX_LoadSheet: %s\n", spec.get())); - // Content Policy - PRInt16 shouldLoad = nsIContentPolicy::ACCEPT; - nsresult rv = - NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_STYLESHEET, - aUri, - aCallerPrincipal, - aProcessor->GetSourceContentModel(), - NS_LITERAL_CSTRING("application/xml"), - nsnull, - &shouldLoad); + // Pass source document as the context + nsresult rv = nsContentUtils:: + CheckSecurityBeforeLoad(aUri, aCallerPrincipal, + nsIScriptSecurityManager::STANDARD, PR_FALSE, + nsIContentPolicy::TYPE_STYLESHEET, + aProcessor->GetSourceContentModel(), + NS_LITERAL_CSTRING("application/xml")); NS_ENSURE_SUCCESS(rv, rv); - if (NS_CP_REJECTED(shouldLoad)) { - return NS_ERROR_DOM_BAD_URI; - } nsRefPtr observer = new txCompileObserver(aProcessor, aLoadGroup); @@ -709,19 +716,13 @@ txSyncCompileObserver::loadURI(const nsAString& aUri, GetCodebasePrincipal(referrerUri, getter_AddRefs(referrerPrincipal)); NS_ENSURE_SUCCESS(rv, rv); - // Content Policy - PRInt16 shouldLoad = nsIContentPolicy::ACCEPT; - rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_STYLESHEET, - uri, - referrerPrincipal, - nsnull, - NS_LITERAL_CSTRING("application/xml"), - nsnull, - &shouldLoad); + // Security checks + rv = nsContentUtils:: + CheckSecurityBeforeLoad(uri, referrerPrincipal, + nsIScriptSecurityManager::STANDARD, + PR_FALSE, nsIContentPolicy::TYPE_STYLESHEET, + nsnull, NS_LITERAL_CSTRING("application/xml")); NS_ENSURE_SUCCESS(rv, rv); - if (NS_CP_REJECTED(shouldLoad)) { - return NS_ERROR_DOM_BAD_URI; - } // This is probably called by js, a loadGroup for the channel doesn't // make sense.