mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 389508: Cross site XMLHttpRequest. r=jst/biesi sr/dveditz/biesi
This commit is contained in:
parent
4afa23fd6d
commit
24c4c1d539
@ -664,11 +664,6 @@ public:
|
||||
|
||||
virtual nsresult AddXMLEventsContent(nsIContent * aXMLEventsElement) = 0;
|
||||
|
||||
virtual PRBool IsLoadedAsData()
|
||||
{
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an element with the specified name, prefix and namespace ID.
|
||||
* If aDocumentDefaultType is true we create an element of the default type
|
||||
@ -876,7 +871,11 @@ public:
|
||||
{
|
||||
return mMarkedCCGeneration;
|
||||
}
|
||||
|
||||
|
||||
PRBool IsLoadedAsData()
|
||||
{
|
||||
return mLoadedAsData;
|
||||
}
|
||||
|
||||
protected:
|
||||
~nsIDocument()
|
||||
@ -940,6 +939,10 @@ protected:
|
||||
|
||||
PRPackedBool mShellsAreHidden;
|
||||
|
||||
// True if we're loaded as data and therefor has any dangerous stuff, such
|
||||
// as scripts and plugins, disabled.
|
||||
PRPackedBool mLoadedAsData;
|
||||
|
||||
// The bidi options for this document. What this bitfield means is
|
||||
// defined in nsBidiUtils.h
|
||||
PRUint32 mBidiOptions;
|
||||
|
@ -113,6 +113,7 @@ CPPSRCS = \
|
||||
nsContentSink.cpp \
|
||||
nsContentUtils.cpp \
|
||||
nsCopySupport.cpp \
|
||||
nsCrossSiteListenerProxy.cpp \
|
||||
nsDataDocumentContentPolicy.cpp \
|
||||
nsDOMAttribute.cpp \
|
||||
nsDOMAttributeMap.cpp \
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,97 +1,97 @@
|
||||
/* -*- 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 <jonas@sicking.cc> (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"
|
||||
|
||||
class nsIURI;
|
||||
class nsIParser;
|
||||
class nsIPrincipal;
|
||||
|
||||
class nsCrossSiteListenerProxy : public nsIStreamListener,
|
||||
public nsIXMLContentSink,
|
||||
public nsIExpatSink
|
||||
{
|
||||
public:
|
||||
nsCrossSiteListenerProxy(nsIStreamListener* aOuter,
|
||||
nsIPrincipal* aRequestingPrincipal);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIEXPATSINK
|
||||
|
||||
// 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 ForwardRequest();
|
||||
PRBool MatchPatternList(const char*& aIter, const char* aEnd);
|
||||
void CheckHeader(const nsCString& aHeader);
|
||||
PRBool VerifyAndMatchDomainPattern(const nsACString& aDomainPattern);
|
||||
|
||||
nsCOMPtr<nsIStreamListener> mOuter;
|
||||
nsCOMPtr<nsIRequest> mOuterRequest;
|
||||
nsCOMPtr<nsISupports> mOuterContext;
|
||||
nsCOMPtr<nsIStreamListener> mParserListener;
|
||||
nsCOMPtr<nsIParser> mParser;
|
||||
nsCOMPtr<nsIURI> mRequestingURI;
|
||||
nsTArray<nsCString> mReqSubdomains;
|
||||
nsCString mStoredData;
|
||||
enum {
|
||||
eAccept,
|
||||
eDeny,
|
||||
eNotSet
|
||||
} mAcceptState;
|
||||
PRBool mHasForwardedRequest;
|
||||
};
|
||||
/* -*- 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 <jonas@sicking.cc> (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"
|
||||
|
||||
class nsIURI;
|
||||
class nsIParser;
|
||||
class nsIPrincipal;
|
||||
|
||||
class nsCrossSiteListenerProxy : public nsIStreamListener,
|
||||
public nsIXMLContentSink,
|
||||
public nsIExpatSink
|
||||
{
|
||||
public:
|
||||
nsCrossSiteListenerProxy(nsIStreamListener* aOuter,
|
||||
nsIPrincipal* aRequestingPrincipal);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIEXPATSINK
|
||||
|
||||
// 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 ForwardRequest(PRBool aCallStop);
|
||||
PRBool MatchPatternList(const char*& aIter, const char* aEnd);
|
||||
void CheckHeader(const nsCString& aHeader);
|
||||
PRBool VerifyAndMatchDomainPattern(const nsACString& aDomainPattern);
|
||||
|
||||
nsCOMPtr<nsIStreamListener> mOuter;
|
||||
nsCOMPtr<nsIRequest> mOuterRequest;
|
||||
nsCOMPtr<nsISupports> mOuterContext;
|
||||
nsCOMPtr<nsIStreamListener> mParserListener;
|
||||
nsCOMPtr<nsIParser> mParser;
|
||||
nsCOMPtr<nsIURI> mRequestingURI;
|
||||
nsTArray<nsCString> mReqSubdomains;
|
||||
nsCString mStoredData;
|
||||
enum {
|
||||
eAccept,
|
||||
eDeny,
|
||||
eNotSet
|
||||
} mAcceptState;
|
||||
PRBool mHasForwardedRequest;
|
||||
};
|
||||
|
@ -1428,6 +1428,19 @@ nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nsCRT::strcmp(kLoadAsData, aCommand) == 0) {
|
||||
mLoadedAsData = PR_TRUE;
|
||||
// We need to disable script & style loading in this case.
|
||||
// We leave them disabled even in EndLoad(), and let anyone
|
||||
// who puts the document on display to worry about enabling.
|
||||
|
||||
// Do not load/process scripts when loading as data
|
||||
ScriptLoader()->SetEnabled(PR_FALSE);
|
||||
|
||||
// styles
|
||||
CSSLoader()->SetEnabled(PR_FALSE); // Do not load/process styles when loading as data
|
||||
}
|
||||
|
||||
if (aReset) {
|
||||
Reset(aChannel, aLoadGroup);
|
||||
}
|
||||
|
@ -3426,6 +3426,13 @@ nsGenericElement::AddScriptEventListener(nsIAtom* aEventName,
|
||||
const nsAString& aValue,
|
||||
PRBool aDefer)
|
||||
{
|
||||
nsIDocument *ownerDoc = GetOwnerDoc();
|
||||
if (!ownerDoc || ownerDoc->IsLoadedAsData()) {
|
||||
// Make this a no-op rather than throwing an error to avoid
|
||||
// the error causing problems setting the attribute.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_PRECONDITION(aEventName, "Must have event name!");
|
||||
nsCOMPtr<nsISupports> target;
|
||||
PRBool defer = PR_TRUE;
|
||||
@ -3437,8 +3444,6 @@ nsGenericElement::AddScriptEventListener(nsIAtom* aEventName,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (manager) {
|
||||
nsIDocument *ownerDoc = GetOwnerDoc();
|
||||
|
||||
defer = defer && aDefer; // only defer if everyone agrees...
|
||||
|
||||
PRUint32 lang = GetScriptTypeID();
|
||||
|
@ -847,6 +847,11 @@ nsObjectLoadingContent::LoadObject(nsIURI* aURI,
|
||||
}
|
||||
|
||||
// Security checks
|
||||
if (doc->IsLoadedAsData()) {
|
||||
Fallback(PR_FALSE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Can't do security checks without a URI - hopefully the plugin will take
|
||||
// care of that
|
||||
// Null URIs happen when the URL to load is specified via other means than the
|
||||
|
@ -47,20 +47,19 @@
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIParserService.h"
|
||||
|
||||
#define SKIP_WHITESPACE(iter, end_iter) \
|
||||
#define SKIP_WHITESPACE(iter, end_iter, end_res) \
|
||||
while ((iter) != (end_iter) && nsCRT::IsAsciiSpace(*(iter))) { \
|
||||
++(iter); \
|
||||
} \
|
||||
if ((iter) == (end_iter)) \
|
||||
break
|
||||
if ((iter) == (end_iter)) { \
|
||||
return (end_res); \
|
||||
}
|
||||
|
||||
#define SKIP_ATTR_NAME(iter, end_iter) \
|
||||
while ((iter) != (end_iter) && !nsCRT::IsAsciiSpace(*(iter)) && \
|
||||
*(iter) != '=') { \
|
||||
++(iter); \
|
||||
} \
|
||||
if ((iter) == (end_iter)) \
|
||||
break
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsParserUtils::GetQuotedAttributeValue(const nsString& aSource, nsIAtom *aName,
|
||||
@ -73,29 +72,33 @@ nsParserUtils::GetQuotedAttributeValue(const nsString& aSource, nsIAtom *aName,
|
||||
const PRUnichar *iter;
|
||||
|
||||
while (start != end) {
|
||||
SKIP_WHITESPACE(start, end);
|
||||
SKIP_WHITESPACE(start, end, PR_FALSE)
|
||||
iter = start;
|
||||
SKIP_ATTR_NAME(iter, end);
|
||||
SKIP_ATTR_NAME(iter, end)
|
||||
|
||||
if (start == iter) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// Remember the attr name.
|
||||
const nsDependentSubstring & attrName = Substring(start, iter);
|
||||
|
||||
// Now check whether this is a valid name="value" pair.
|
||||
start = iter;
|
||||
SKIP_WHITESPACE(start, end);
|
||||
SKIP_WHITESPACE(start, end, PR_FALSE)
|
||||
if (*start != '=') {
|
||||
// No '=', so this is not a name="value" pair. We don't know
|
||||
// what it is, and we have no way to handle it.
|
||||
break;
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// Have to skip the value.
|
||||
++start;
|
||||
SKIP_WHITESPACE(start, end);
|
||||
SKIP_WHITESPACE(start, end, PR_FALSE)
|
||||
PRUnichar q = *start;
|
||||
if (q != kQuote && q != kApostrophe) {
|
||||
// Not a valid quoted value, so bail.
|
||||
break;
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
++start; // Point to the first char of the value.
|
||||
@ -107,7 +110,7 @@ nsParserUtils::GetQuotedAttributeValue(const nsString& aSource, nsIAtom *aName,
|
||||
|
||||
if (iter == end) {
|
||||
// Oops, unterminated quoted string.
|
||||
break;
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// At this point attrName holds the name of the "attribute" and
|
||||
@ -168,6 +171,74 @@ nsParserUtils::GetQuotedAttributeValue(const nsString& aSource, nsIAtom *aName,
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsParserUtils::GetQuotedAttrNameAt(const nsString& aSource, PRUint32 aIndex,
|
||||
nsAString& aName)
|
||||
{
|
||||
aName.Truncate();
|
||||
|
||||
const PRUnichar *start = aSource.get();
|
||||
const PRUnichar *end = start + aSource.Length();
|
||||
const PRUnichar *iter;
|
||||
PRUint32 currIndex = 0;
|
||||
|
||||
for (;;) {
|
||||
SKIP_WHITESPACE(start, end, PR_TRUE)
|
||||
|
||||
iter = start;
|
||||
SKIP_ATTR_NAME(iter, end)
|
||||
|
||||
if (start == iter) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// Remember the attr name.
|
||||
const nsDependentSubstring & attrName = Substring(start, iter);
|
||||
|
||||
// Now check whether this is a valid name="value" pair.
|
||||
start = iter;
|
||||
SKIP_WHITESPACE(start, end, PR_FALSE);
|
||||
if (*start != '=') {
|
||||
// No '=', so this is not a name="value" pair. We don't know
|
||||
// what it is, and we have no way to handle it.
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// Have to skip the value.
|
||||
++start;
|
||||
SKIP_WHITESPACE(start, end, PR_FALSE);
|
||||
PRUnichar q = *start;
|
||||
if (q != kQuote && q != kApostrophe) {
|
||||
// Not a valid quoted value, so bail.
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// Scan to the end of the value.
|
||||
do {
|
||||
++start;
|
||||
} while (start != end && *start != q);
|
||||
|
||||
if (start == end) {
|
||||
// Oops, unterminated quoted string.
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// At this point attrName holds the name of the "attribute"
|
||||
|
||||
if (aIndex == currIndex) {
|
||||
aName = attrName;
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// Resume scanning after the end of the attribute value (past the quote
|
||||
// char).
|
||||
++start;
|
||||
++currIndex;
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// Returns PR_TRUE if the language name is a version of JavaScript and
|
||||
// PR_FALSE otherwise
|
||||
|
@ -57,11 +57,32 @@ public:
|
||||
* @param aName the name of the attribute to get the value for
|
||||
* @param aValue [out] the value for the attribute with name specified in
|
||||
* aAttribute. Empty if the attribute isn't present.
|
||||
* @return PR_TRUE if the attribute exists and was successfully parsed.
|
||||
* PR_FALSE if the attribute doesn't exist, or has a malformed
|
||||
* value, such as an unknown or unterminated entity.
|
||||
*/
|
||||
static PRBool
|
||||
GetQuotedAttributeValue(const nsString& aSource, nsIAtom *aName,
|
||||
nsAString& aValue);
|
||||
|
||||
/**
|
||||
* This will parse aSource, to extract the name of the pseudo attribute
|
||||
* at the specified index. See
|
||||
* http://www.w3.org/TR/xml-stylesheet/#NT-StyleSheetPI for the specification
|
||||
* which is used to parse aSource.
|
||||
*
|
||||
* @param aSource the string to parse
|
||||
* @param aIndex the index of the attribute to get the value for
|
||||
* @param aName [out] the name for the attribute with specified index.
|
||||
* Empty if there aren't enough attributes.
|
||||
* @return PR_TRUE if parsing succeeded, even if there aren't enough
|
||||
* attributes.
|
||||
* PR_FALSE if parsing failed.
|
||||
*/
|
||||
static PRBool
|
||||
GetQuotedAttrNameAt(const nsString& aSource, PRUint32 aIndex,
|
||||
nsAString& aName);
|
||||
|
||||
static PRBool
|
||||
IsJavaScriptLanguage(const nsString& aName, PRUint32 *aVerFlags);
|
||||
|
||||
|
@ -83,7 +83,10 @@
|
||||
#include "nsContentPolicyUtils.h"
|
||||
#include "nsContentErrors.h"
|
||||
#include "nsLayoutStatics.h"
|
||||
#include "nsCrossSiteListenerProxy.h"
|
||||
#include "nsDOMError.h"
|
||||
#include "nsIHTMLDocument.h"
|
||||
#include "nsWhitespaceTokenizer.h"
|
||||
|
||||
#define LOAD_STR "load"
|
||||
#define ERROR_STR "error"
|
||||
@ -106,9 +109,13 @@
|
||||
#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
|
||||
#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_USE_XSITE_AC (1 << 13) // Internal
|
||||
#define XML_HTTP_REQUEST_NON_GET (1 << 14) // Internal
|
||||
|
||||
#define XML_HTTP_REQUEST_LOADSTATES \
|
||||
(XML_HTTP_REQUEST_UNINITIALIZED | \
|
||||
@ -220,6 +227,114 @@ 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,
|
||||
const nsACString& aRequestMethod)
|
||||
: mOuterChannel(aOuterChannel), mOuterListener(aOuterListener),
|
||||
mOuterContext(aOuterContext), mRequestMethod(aRequestMethod)
|
||||
{ }
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NSICHANNELEVENTSINK
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIChannel> mOuterChannel;
|
||||
nsCOMPtr<nsIStreamListener> mOuterListener;
|
||||
nsCOMPtr<nsISupports> mOuterContext;
|
||||
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;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> http;
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
http = do_QueryInterface(aRequest, &rv);
|
||||
}
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = NS_ERROR_DOM_BAD_URI;
|
||||
nsCString allow;
|
||||
http->GetResponseHeader(NS_LITERAL_CSTRING("Allow"), allow);
|
||||
nsCWhitespaceTokenizer tok(allow);
|
||||
while (tok.hasMoreTokens()) {
|
||||
if (mRequestMethod.Equals(tok.nextToken(),
|
||||
nsCaseInsensitiveCStringComparator())) {
|
||||
rv = NS_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
static nsIScriptContext *
|
||||
GetCurrentContext()
|
||||
@ -767,6 +882,9 @@ nsXMLHttpRequest::Abort()
|
||||
if (mChannel) {
|
||||
mChannel->Cancel(NS_BINDING_ABORTED);
|
||||
}
|
||||
if (mACGetChannel) {
|
||||
mACGetChannel->Cancel(NS_BINDING_ABORTED);
|
||||
}
|
||||
mDocument = nsnull;
|
||||
mState |= XML_HTTP_REQUEST_ABORTED;
|
||||
|
||||
@ -789,6 +907,10 @@ nsXMLHttpRequest::GetAllResponseHeaders(char **_retval)
|
||||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
*_retval = nsnull;
|
||||
|
||||
if (mState & XML_HTTP_REQUEST_USE_XSITE_AC) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
|
||||
|
||||
if (httpChannel) {
|
||||
@ -817,6 +939,26 @@ nsXMLHttpRequest::GetResponseHeader(const nsACString& header,
|
||||
nsresult rv = NS_OK;
|
||||
_retval.Truncate();
|
||||
|
||||
// Check for dangerous headers
|
||||
if (mState & XML_HTTP_REQUEST_USE_XSITE_AC) {
|
||||
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<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
|
||||
|
||||
if (httpChannel) {
|
||||
@ -988,6 +1130,56 @@ nsXMLHttpRequest::GetCurrentHttpChannel()
|
||||
return httpChannel;
|
||||
}
|
||||
|
||||
static PRBool
|
||||
IsSameOrigin(nsIPrincipal* aPrincipal, nsIChannel* aChannel)
|
||||
{
|
||||
nsCOMPtr<nsIURI> codebase;
|
||||
nsresult rv = aPrincipal->GetURI(getter_AddRefs(codebase));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIURI> channelURI;
|
||||
rv = aChannel->GetURI(getter_AddRefs(channelURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = nsContentUtils::GetSecurityManager()->CheckSameOriginURI(codebase, channelURI);
|
||||
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 and set XMLHttpRequest-Security-Check
|
||||
nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(mChannel);
|
||||
if (http) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < mExtraRequestHeaders.Length(); ++i) {
|
||||
http->SetRequestHeader(mExtraRequestHeaders[i], EmptyCString(), PR_FALSE);
|
||||
}
|
||||
mExtraRequestHeaders.Clear();
|
||||
}
|
||||
|
||||
// Cancel if username/password is supplied to avoid brute-force password
|
||||
// hacking
|
||||
nsCOMPtr<nsIURI> channelURI;
|
||||
nsresult rv = mChannel->GetURI(getter_AddRefs(channelURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCString userpass;
|
||||
channelURI->GetUserPass(userpass);
|
||||
return userpass.IsEmpty() ? NS_OK : NS_ERROR_DOM_BAD_URI;
|
||||
}
|
||||
|
||||
/* noscript void openRequest (in AUTF8String method, in AUTF8String url, in boolean async, in AString user, in AString password); */
|
||||
NS_IMETHODIMP
|
||||
@ -1002,11 +1194,25 @@ nsXMLHttpRequest::OpenRequest(const nsACString& method,
|
||||
|
||||
// Disallow HTTP/1.1 TRACE method (see bug 302489)
|
||||
// and MS IIS equivalent TRACK (see bug 381264)
|
||||
if (method.LowerCaseEqualsASCII("trace") ||
|
||||
method.LowerCaseEqualsASCII("track")) {
|
||||
if (method.LowerCaseEqualsLiteral("trace") ||
|
||||
method.LowerCaseEqualsLiteral("track")) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// Get the principal.
|
||||
// XXX This should be done at construction time.
|
||||
nsCOMPtr<nsIDocument> doc =
|
||||
do_QueryInterface(nsContentUtils::GetDocumentFromCaller());
|
||||
if (doc) {
|
||||
mPrincipal = doc->NodePrincipal();
|
||||
}
|
||||
else {
|
||||
nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
|
||||
if (secMan) {
|
||||
secMan->GetSubjectPrincipal(getter_AddRefs(mPrincipal));
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
PRBool authp = PR_FALSE;
|
||||
@ -1046,7 +1252,7 @@ nsXMLHttpRequest::OpenRequest(const nsACString& method,
|
||||
|
||||
// mScriptContext should be initialized because of GetBaseURI() above.
|
||||
// Still need to consider the case that doc is nsnull however.
|
||||
nsCOMPtr<nsIDocument> doc = GetDocumentFromScriptContext(mScriptContext);
|
||||
doc = GetDocumentFromScriptContext(mScriptContext);
|
||||
PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
|
||||
rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_XMLHTTPREQUEST,
|
||||
uri,
|
||||
@ -1095,11 +1301,36 @@ nsXMLHttpRequest::OpenRequest(const nsACString& method,
|
||||
loadFlags);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Check if we're doing a cross-origin request.
|
||||
if (!(mState & XML_HTTP_REQUEST_XSITEENABLED) &&
|
||||
!IsSameOrigin(mPrincipal, mChannel)) {
|
||||
mState |= XML_HTTP_REQUEST_USE_XSITE_AC;
|
||||
}
|
||||
|
||||
//mChannel->SetAuthTriedWithPrehost(authp);
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> 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 GET 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)) {
|
||||
rv = NS_NewChannel(getter_AddRefs(mACGetChannel), uri, nsnull, loadGroup, nsnull,
|
||||
loadFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> acHttp = do_QueryInterface(mACGetChannel);
|
||||
rv = acHttp->SetRequestHeader(
|
||||
NS_LITERAL_CSTRING("XMLHttpRequest-Security-Check"), method, PR_FALSE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
ChangeState(XML_HTTP_REQUEST_OPENED);
|
||||
@ -1143,7 +1374,7 @@ nsXMLHttpRequest::Open(const nsACString& method, const nsACString& url)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
rv = secMan->CheckConnect(cx, targetURI, "XMLHttpRequest","open");
|
||||
rv = secMan->CheckConnect(cx, targetURI, "XMLHttpRequest", "open-uri");
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
// Security check failed.
|
||||
@ -1295,6 +1526,13 @@ nsXMLHttpRequest::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
||||
getter_AddRefs(mDocument));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mState & XML_HTTP_REQUEST_USE_XSITE_AC) {
|
||||
nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
|
||||
if (htmlDoc) {
|
||||
htmlDoc->DisableCookieAccess();
|
||||
}
|
||||
}
|
||||
|
||||
// Reset responseBody
|
||||
mResponseBody.Truncate();
|
||||
|
||||
@ -1551,18 +1789,6 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
|
||||
// if there are no event listeners set and we are doing
|
||||
// an asynchronous call.
|
||||
|
||||
nsCOMPtr<nsIDocument> doc =
|
||||
do_QueryInterface(nsContentUtils::GetDocumentFromCaller());
|
||||
if (doc) {
|
||||
mPrincipal = doc->NodePrincipal();
|
||||
}
|
||||
else {
|
||||
nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
|
||||
if (secMan) {
|
||||
secMan->GetSubjectPrincipal(getter_AddRefs(mPrincipal));
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore argument if method is GET, there is no point in trying to
|
||||
// upload anything
|
||||
nsCAutoString method;
|
||||
@ -1723,18 +1949,27 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
|
||||
mScriptContext = GetCurrentContext();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
nsCOMPtr<nsIStreamListener> listener;
|
||||
// Create our listener
|
||||
nsCOMPtr<nsIStreamListener> listener = this;
|
||||
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);
|
||||
NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
if (mState & XML_HTTP_REQUEST_MULTIPART) {
|
||||
listener = new nsMultipartProxyListener(this);
|
||||
listener = new nsMultipartProxyListener(listener);
|
||||
if (!listener) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
} else {
|
||||
listener = this;
|
||||
}
|
||||
|
||||
// Bypass the network cache in cases where it makes no sense:
|
||||
@ -1753,6 +1988,10 @@ 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
|
||||
@ -1760,8 +1999,22 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
|
||||
// ignoring return value, as this is not critical
|
||||
mChannel->SetContentType(NS_LITERAL_CSTRING("application/xml"));
|
||||
|
||||
// Start reading from the channel
|
||||
rv = mChannel->AsyncOpen(listener, nsnull);
|
||||
// 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<nsIStreamListener> acListener =
|
||||
new nsACProxyListener(mChannel, listener, nsnull, method);
|
||||
NS_ENSURE_TRUE(acListener, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
listener = new nsCrossSiteListenerProxy(acListener, mPrincipal);
|
||||
NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
rv = mACGetChannel->AsyncOpen(acListener, nsnull);
|
||||
}
|
||||
else {
|
||||
// Start reading from the channel
|
||||
rv = mChannel->AsyncOpen(listener, nsnull);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
// Drop our ref to the channel to avoid cycles
|
||||
@ -1798,7 +2051,23 @@ NS_IMETHODIMP
|
||||
nsXMLHttpRequest::SetRequestHeader(const nsACString& header,
|
||||
const nsACString& value)
|
||||
{
|
||||
if (!mChannel) // open() initializes mChannel, and open()
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
|
||||
if (!httpChannel) // open() initializes mChannel, and open()
|
||||
return NS_ERROR_FAILURE; // must be called before first setRequestHeader()
|
||||
|
||||
// Prevent modification to certain HTTP headers (see bug 302263), unless
|
||||
@ -1810,31 +2079,55 @@ nsXMLHttpRequest::SetRequestHeader(const nsACString& header,
|
||||
}
|
||||
|
||||
PRBool privileged;
|
||||
nsresult rv = secMan->IsCapabilityEnabled("UniversalBrowserWrite",
|
||||
&privileged);
|
||||
rv = secMan->IsCapabilityEnabled("UniversalBrowserWrite", &privileged);
|
||||
if (NS_FAILED(rv))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (!privileged) {
|
||||
// Check for dangerous headers
|
||||
const char *kInvalidHeaders[] = {
|
||||
"host", "content-length", "transfer-encoding", "via", "upgrade"
|
||||
"accept-charset", "accept-encoding", "connection", "content-length",
|
||||
"content-transfer-encoding", "date", "expect", "host", "keep-alive",
|
||||
"proxy-connection", "referer", "referer-root", "te", "trailer",
|
||||
"transfer-encoding", "upgrade", "via", "xmlhttprequest-security-check"
|
||||
};
|
||||
for (size_t i = 0; i < NS_ARRAY_LENGTH(kInvalidHeaders); ++i) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < NS_ARRAY_LENGTH(kInvalidHeaders); ++i) {
|
||||
if (header.LowerCaseEqualsASCII(kInvalidHeaders[i])) {
|
||||
NS_WARNING("refusing to set request 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);
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
|
||||
|
||||
if (httpChannel) {
|
||||
// We need to set, not add to, the header.
|
||||
return httpChannel->SetRequestHeader(header, value, PR_FALSE);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
// We need to set, not add to, the header.
|
||||
return httpChannel->SetRequestHeader(header, value, PR_FALSE);
|
||||
}
|
||||
|
||||
/* readonly attribute long readyState; */
|
||||
@ -2025,51 +2318,26 @@ nsXMLHttpRequest::OnChannelRedirect(nsIChannel *aOldChannel,
|
||||
{
|
||||
NS_PRECONDITION(aNewChannel, "Redirect without a channel?");
|
||||
|
||||
if (mScriptContext && !(mState & XML_HTTP_REQUEST_XSITEENABLED)) {
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIJSContextStack> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", & rv));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
JSContext *cx = (JSContext *)mScriptContext->GetNativeContext();
|
||||
if (!cx)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
|
||||
if (!secMan) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> newURI;
|
||||
rv = aNewChannel->GetURI(getter_AddRefs(newURI)); // The redirected URI
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
stack->Push(cx);
|
||||
|
||||
rv = secMan->CheckSameOrigin(cx, newURI);
|
||||
|
||||
stack->Pop(&cx);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
// The security manager set a pending exception. Since we're
|
||||
// running under the event loop, we need to report it.
|
||||
::JS_ReportPendingException(cx);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
if (mChannelEventSink) {
|
||||
nsresult rv =
|
||||
rv =
|
||||
mChannelEventSink->OnChannelRedirect(aOldChannel, aNewChannel, aFlags);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
mChannel = aNewChannel;
|
||||
|
||||
rv = CheckChannelForCrossSiteRequest();
|
||||
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;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -157,11 +157,20 @@ protected:
|
||||
void ClearEventListeners();
|
||||
already_AddRefed<nsIHttpChannel> GetCurrentHttpChannel();
|
||||
|
||||
/**
|
||||
* Check if mChannel is ok for a cross-site request by making sure no
|
||||
* inappropriate headers are set, and no username/password is set.
|
||||
*
|
||||
* Also updates the XML_HTTP_REQUEST_USE_XSITE_AC bit.
|
||||
*/
|
||||
nsresult CheckChannelForCrossSiteRequest();
|
||||
|
||||
nsCOMPtr<nsISupports> mContext;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
nsCOMPtr<nsIRequest> mReadRequest;
|
||||
nsCOMPtr<nsIDOMDocument> mDocument;
|
||||
nsCOMPtr<nsIChannel> mACGetChannel;
|
||||
|
||||
nsCOMArray<nsIDOMEventListener> mLoadEventListeners;
|
||||
nsCOMArray<nsIDOMEventListener> mErrorEventListeners;
|
||||
@ -209,6 +218,10 @@ protected:
|
||||
nsCOMPtr<nsIProgressEventSink> mProgressEventSink;
|
||||
|
||||
PRUint32 mState;
|
||||
|
||||
// List of potentially dangerous headers explicitly set using
|
||||
// SetRequestHeader.
|
||||
nsTArray<nsCString> mExtraRequestHeaders;
|
||||
};
|
||||
|
||||
|
||||
|
@ -85,6 +85,16 @@ _TEST_FILES = test_bug5141.html \
|
||||
test_bug375314.html \
|
||||
test_bug382113.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 \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
|
@ -1964,6 +1964,10 @@ 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<nsICookieService> service = do_GetService(NS_COOKIESERVICE_CONTRACTID);
|
||||
if (service) {
|
||||
@ -1990,6 +1994,10 @@ 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<nsICookieService> service = do_GetService(NS_COOKIESERVICE_CONTRACTID);
|
||||
if (service && mDocumentURI) {
|
||||
|
@ -207,6 +207,11 @@ public:
|
||||
return mEditingState != eOff;
|
||||
}
|
||||
|
||||
virtual void DisableCookieAccess()
|
||||
{
|
||||
mDisableCookieAccess = PR_TRUE;
|
||||
}
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsHTMLDocument, nsDocument)
|
||||
|
||||
protected:
|
||||
@ -389,6 +394,8 @@ protected:
|
||||
// XXXbz should this be reset if someone manually calls
|
||||
// SetContentType() on this document?
|
||||
PRInt32 mDefaultNamespaceID;
|
||||
|
||||
PRBool mDisableCookieAccess;
|
||||
};
|
||||
|
||||
#endif /* nsHTMLDocument_h___ */
|
||||
|
@ -152,6 +152,11 @@ public:
|
||||
*/
|
||||
virtual nsresult GetDocumentAllResult(const nsAString& aID,
|
||||
nsISupports** aResult) = 0;
|
||||
|
||||
/**
|
||||
* Disables getting and setting cookies
|
||||
*/
|
||||
virtual void DisableCookieAccess() = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIHTMLDocument, NS_IHTMLDOCUMENT_IID)
|
||||
|
@ -561,28 +561,18 @@ nsXMLDocument::StartDocumentLoad(const char* aCommand,
|
||||
PRBool aReset,
|
||||
nsIContentSink* aSink)
|
||||
{
|
||||
if (nsCRT::strcmp(kLoadAsData, aCommand) == 0) {
|
||||
mLoadedAsData = PR_TRUE;
|
||||
// We need to disable script & style loading in this case.
|
||||
// We leave them disabled even in EndLoad(), and let anyone
|
||||
// who puts the document on display to worry about enabling.
|
||||
|
||||
// Do not load/process scripts when loading as data
|
||||
ScriptLoader()->SetEnabled(PR_FALSE);
|
||||
|
||||
// styles
|
||||
CSSLoader()->SetEnabled(PR_FALSE); // Do not load/process styles when loading as data
|
||||
} else if (nsCRT::strcmp("loadAsInteractiveData", aCommand) == 0) {
|
||||
mLoadedAsInteractiveData = PR_TRUE;
|
||||
aCommand = kLoadAsData; // XBL, for example, needs scripts and styles
|
||||
}
|
||||
|
||||
nsresult rv = nsDocument::StartDocumentLoad(aCommand,
|
||||
aChannel, aLoadGroup,
|
||||
aContainer,
|
||||
aDocListener, aReset, aSink);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (nsCRT::strcmp("loadAsInteractiveData", aCommand) == 0) {
|
||||
mLoadedAsInteractiveData = PR_TRUE;
|
||||
aCommand = kLoadAsData; // XBL, for example, needs scripts and styles
|
||||
}
|
||||
|
||||
|
||||
PRInt32 charsetSource = kCharsetFromDocTypeDefault;
|
||||
nsCAutoString charset(NS_LITERAL_CSTRING("UTF-8"));
|
||||
TryChannelCharset(aChannel, charsetSource, charset);
|
||||
@ -656,13 +646,6 @@ nsXMLDocument::EndLoad()
|
||||
nsDocument::EndLoad();
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsXMLDocument::IsLoadedAsData()
|
||||
{
|
||||
return mLoadedAsData;
|
||||
}
|
||||
|
||||
|
||||
// nsIDOMNode interface
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -75,8 +75,6 @@ public:
|
||||
|
||||
virtual void EndLoad();
|
||||
|
||||
virtual PRBool IsLoadedAsData();
|
||||
|
||||
// nsIDOMNode interface
|
||||
NS_IMETHOD CloneNode(PRBool aDeep, nsIDOMNode** aReturn);
|
||||
|
||||
@ -112,7 +110,6 @@ protected:
|
||||
// cannot be null.
|
||||
PRPackedBool mChannelIsPending;
|
||||
PRPackedBool mCrossSiteAccessEnabled;
|
||||
PRPackedBool mLoadedAsData;
|
||||
PRPackedBool mLoadedAsInteractiveData;
|
||||
PRPackedBool mAsync;
|
||||
PRPackedBool mLoopingForSyncLoad;
|
||||
|
@ -443,6 +443,7 @@ pref("capability.policy.mailnews.WebServiceProxyFactory.onError", "noAccess");
|
||||
// XMLExtras
|
||||
pref("capability.policy.default.XMLHttpRequest.channel", "noAccess");
|
||||
pref("capability.policy.default.XMLHttpRequest.getInterface", "noAccess");
|
||||
pref("capability.policy.default.XMLHttpRequest.open-uri", "allAccess");
|
||||
pref("capability.policy.default.DOMParser.parseFromStream", "noAccess");
|
||||
|
||||
// Clipboard
|
||||
|
Loading…
Reference in New Issue
Block a user