Bug 414540 - RDFXMLDataSource should reject cross-domain redirects. Original patch by Neil Deakin, fixed up with better testing, r+sr=bz

This commit is contained in:
Benjamin Smedberg 2009-01-29 11:45:50 -05:00
parent 0d4109c626
commit b65f2814ef
5 changed files with 159 additions and 2 deletions

View File

@ -49,6 +49,8 @@ LIBXUL_LIBRARY = 1
REQUIRES = xpcom \
string \
rdfutil \
js \
caps \
necko \
content \
htmlparser \

View File

@ -123,6 +123,9 @@
#include "nsNameSpaceMap.h"
#include "nsCRT.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIScriptSecurityManager.h"
#include "nsIChannelEventSink.h"
#include "nsNetUtil.h"
#include "rdfIDataSource.h"
@ -145,7 +148,9 @@ class RDFXMLDataSourceImpl : public nsIRDFDataSource,
public nsIRDFXMLSink,
public nsIRDFXMLSource,
public nsIStreamListener,
public rdfIDataSource
public rdfIDataSource,
public nsIInterfaceRequestor,
public nsIChannelEventSink
{
protected:
enum LoadState {
@ -318,6 +323,12 @@ public:
// nsIStreamListener
NS_DECL_NSISTREAMLISTENER
// nsIInterfaceRequestor
NS_DECL_NSIINTERFACEREQUESTOR
// nsIChannelEventSink
NS_DECL_NSICHANNELEVENTSINK
// rdfIDataSource
NS_IMETHOD VisitAllSubjects(rdfITripleVisitor *aVisitor) {
nsresult rv;
@ -481,9 +492,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(RDFXMLDataSourceImpl)
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
NS_INTERFACE_MAP_ENTRY(rdfIDataSource)
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRDFDataSource)
NS_INTERFACE_MAP_END
// nsIInterfaceRequestor
NS_IMETHODIMP
RDFXMLDataSourceImpl::GetInterface(const nsIID& aIID, void** aSink)
{
return QueryInterface(aIID, aSink);
}
nsresult
RDFXMLDataSourceImpl::BlockingParse(nsIURI* aURL, nsIStreamListener* aConsumer)
@ -877,6 +896,39 @@ RDFXMLDataSourceImpl::SetReadOnly(PRBool aIsReadOnly)
#include "nsITimelineService.h"
// nsIChannelEventSink
// This code is copied from nsSameOriginChecker::OnChannelRedirect. See
// bug 475940 on providing this code in a shared location.
NS_IMETHODIMP
RDFXMLDataSourceImpl::OnChannelRedirect(nsIChannel *aOldChannel,
nsIChannel *aNewChannel,
PRUint32 aFlags)
{
NS_PRECONDITION(aNewChannel, "Redirecting to null channel?");
nsresult rv;
nsCOMPtr<nsIScriptSecurityManager> secMan =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPrincipal> oldPrincipal;
secMan->GetChannelPrincipal(aOldChannel, getter_AddRefs(oldPrincipal));
nsCOMPtr<nsIURI> newURI;
aNewChannel->GetURI(getter_AddRefs(newURI));
nsCOMPtr<nsIURI> newOriginalURI;
aNewChannel->GetOriginalURI(getter_AddRefs(newOriginalURI));
NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI);
rv = oldPrincipal->CheckMayLoad(newURI, PR_FALSE);
if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) {
rv = oldPrincipal->CheckMayLoad(newOriginalURI, PR_FALSE);
}
return rv;
}
NS_IMETHODIMP
RDFXMLDataSourceImpl::Refresh(PRBool aBlocking)
{
@ -925,7 +977,7 @@ RDFXMLDataSourceImpl::Refresh(PRBool aBlocking)
}
else {
// Null LoadGroup ?
rv = NS_OpenURI(this, nsnull, mURL, nsnull);
rv = NS_OpenURI(this, nsnull, mURL, nsnull, nsnull, this);
if (NS_FAILED(rv)) return rv;
// So we don't try to issue two asynchronous loads at once.

View File

@ -40,9 +40,13 @@ topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
MODULE = test_rdf
include $(DEPTH)/config/autoconf.mk
DIRS = rdfcat rdfpoll triplescat
XPCSHELL_TESTS = unit
include $(topsrcdir)/config/rules.mk

9
rdf/tests/unit/sample.rdf Executable file
View File

@ -0,0 +1,9 @@
<?xml version="1.0"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<rdf:Description about="urn:mozilla:sample-data"
dc:title="Sample" />
</rdf:RDF>

View File

@ -0,0 +1,90 @@
do_import_script("netwerk/test/httpserver/httpd.js");
function getRDFService()
{
return Components.classes["@mozilla.org/rdf/rdf-service;1"].
getService(Components.interfaces.nsIRDFService);
}
var server1, server2;
function run_test()
{
var samplefile = do_get_file('rdf/tests/unit/sample.rdf');
server1 = new nsHttpServer();
server1.registerPathHandler("/sample-xs.rdf", xsRedirect);
server1.registerPathHandler("/sample-local.rdf", localRedirect);
server1.registerFile('/sample.rdf', samplefile);
server1.start(4444);
server2 = new nsHttpServer();
server2.registerFile('/sample.rdf', samplefile);
server2.start(4445);
do_test_pending();
new rdfLoadObserver('http://localhost:4444/sample.rdf', true);
new rdfLoadObserver('http://localhost:4445/sample.rdf', true);
new rdfLoadObserver('http://localhost:4444/sample-xs.rdf', false);
new rdfLoadObserver('http://localhost:4444/sample-local.rdf', true);
}
var gPending = 0;
function rdfLoadObserver(uri, shouldPass)
{
this.shouldPass = shouldPass;
this.uri = uri;
++gPending;
var rdfService = getRDFService();
this.ds = rdfService.GetDataSource(uri).
QueryInterface(Components.interfaces.nsIRDFXMLSink);
this.ds.addXMLSinkObserver(this);
}
rdfLoadObserver.prototype =
{
onBeginLoad : function() { },
onInterrupt : function() { },
onResume : function() { },
onEndLoad : function() {
print("Testing results of loading " + this.uri);
var rdfs = getRDFService();
var res = rdfs.GetResource("urn:mozilla:sample-data");
var arc = rdfs.GetResource("http://purl.org/dc/elements/1.1/title");
var answer = this.ds.GetTarget(res, arc, true);
if (answer !== null) {
do_check_true(this.shouldPass);
do_check_true(answer instanceof Components.interfaces.nsIRDFLiteral);
do_check_eq(answer.Value, "Sample");
}
else {
do_check_false(this.shouldPass);
}
gPending -= 1;
if (gPending == 0) {
server1.stop();
server2.stop();
do_test_finished();
}
},
onError : function() { }
}
function xsRedirect(metadata, response)
{
response.setStatusLine(metadata.httpVersion, 301, "Moved Permanently");
response.setHeader("Location", "http://localhost:4445/sample.rdf", false);
}
function localRedirect(metadata, response)
{
response.setStatusLine(metadata.httpVersion, 301, "Moved Permanently");
response.setHeader("Location", "http://localhost:4444/sample.rdf", false);
}