Bug 1192955 - Use channel->ascynOpen2 for PING in docshell/base/nsDocShell.cpp (r=sicking)

This commit is contained in:
Christoph Kerschbaumer 2015-08-13 08:53:28 -07:00
parent ecdc701ca0
commit dad90516d6
2 changed files with 30 additions and 146 deletions

View File

@ -318,43 +318,6 @@ PingsEnabled(int32_t* aMaxPerLink, bool* aRequireSameHost)
return allow;
}
static bool
CheckPingURI(nsIURI* aURI, nsIContent* aContent)
{
if (!aURI) {
return false;
}
// Check with nsIScriptSecurityManager
nsCOMPtr<nsIScriptSecurityManager> ssmgr =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
NS_ENSURE_TRUE(ssmgr, false);
nsresult rv = ssmgr->CheckLoadURIWithPrincipal(
aContent->NodePrincipal(), aURI, nsIScriptSecurityManager::STANDARD);
if (NS_FAILED(rv)) {
return false;
}
// Ignore non-HTTP(S)
bool match;
if ((NS_FAILED(aURI->SchemeIs("http", &match)) || !match) &&
(NS_FAILED(aURI->SchemeIs("https", &match)) || !match)) {
return false;
}
// Check with contentpolicy
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_PING,
aURI,
aContent->NodePrincipal(),
aContent,
EmptyCString(), // mime hint
nullptr, // extra
&shouldLoad);
return NS_SUCCEEDED(rv) && NS_CP_ACCEPTED(shouldLoad);
}
typedef void (*ForEachPingCallback)(void* closure, nsIContent* content,
nsIURI* uri, nsIIOService* ios);
@ -405,7 +368,12 @@ ForEachPing(nsIContent* aContent, ForEachPingCallback aCallback, void* aClosure)
ios->NewURI(NS_ConvertUTF16toUTF8(tokenizer.nextToken()),
doc->GetDocumentCharacterSet().get(),
baseURI, getter_AddRefs(uri));
if (CheckPingURI(uri, aContent)) {
// Explicitly not allow loading data: URIs
bool isDataScheme =
(NS_SUCCEEDED(uri->SchemeIs("data", &isDataScheme)) && isDataScheme);
if (!isDataScheme) {
aCallback(aClosure, aContent, uri, ios);
}
}
@ -425,55 +393,32 @@ OnPingTimeout(nsITimer* aTimer, void* aClosure)
}
}
// Check to see if two URIs have the same host or not
static bool
IsSameHost(nsIURI* aUri1, nsIURI* aUri2)
{
nsAutoCString host1, host2;
aUri1->GetAsciiHost(host1);
aUri2->GetAsciiHost(host2);
return host1.Equals(host2);
}
class nsPingListener final
: public nsIStreamListener
, public nsIInterfaceRequestor
, public nsIChannelEventSink
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSICHANNELEVENTSINK
nsPingListener(bool aRequireSameHost, nsIContent* aContent,
nsILoadGroup* aLoadGroup)
: mRequireSameHost(aRequireSameHost)
, mContent(aContent)
, mLoadGroup(aLoadGroup)
nsPingListener()
{
}
void SetLoadGroup(nsILoadGroup* aLoadGroup) {
mLoadGroup = aLoadGroup;
}
nsresult StartTimeout();
void SetInterceptController(nsINetworkInterceptController* aInterceptController)
{
mInterceptController = aInterceptController;
}
private:
~nsPingListener();
bool mRequireSameHost;
nsCOMPtr<nsIContent> mContent;
nsCOMPtr<nsILoadGroup> mLoadGroup;
nsCOMPtr<nsITimer> mTimer;
nsCOMPtr<nsINetworkInterceptController> mInterceptController;
};
NS_IMPL_ISUPPORTS(nsPingListener, nsIStreamListener, nsIRequestObserver,
nsIInterfaceRequestor, nsIChannelEventSink)
NS_IMPL_ISUPPORTS(nsPingListener, nsIStreamListener, nsIRequestObserver)
nsPingListener::~nsPingListener()
{
@ -530,57 +475,6 @@ nsPingListener::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext,
return NS_OK;
}
NS_IMETHODIMP
nsPingListener::GetInterface(const nsIID& aIID, void** aResult)
{
if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
nsCOMPtr<nsIChannelEventSink> copy(this);
*aResult = copy.forget().take();
return NS_OK;
}
if (aIID.Equals(NS_GET_IID(nsINetworkInterceptController)) &&
mInterceptController) {
nsCOMPtr<nsINetworkInterceptController> copy(mInterceptController);
*aResult = copy.forget().take();
return NS_OK;
}
return NS_ERROR_NO_INTERFACE;
}
NS_IMETHODIMP
nsPingListener::AsyncOnChannelRedirect(nsIChannel* aOldChan,
nsIChannel* aNewChan,
uint32_t aFlags,
nsIAsyncVerifyRedirectCallback* aCallback)
{
nsCOMPtr<nsIURI> newURI;
aNewChan->GetURI(getter_AddRefs(newURI));
if (!CheckPingURI(newURI, mContent)) {
return NS_ERROR_ABORT;
}
if (!mRequireSameHost) {
aCallback->OnRedirectVerifyCallback(NS_OK);
return NS_OK;
}
// XXXbz should this be using something more like the nsContentUtils
// same-origin checker?
nsCOMPtr<nsIURI> oldURI;
aOldChan->GetURI(getter_AddRefs(oldURI));
NS_ENSURE_STATE(oldURI && newURI);
if (!IsSameHost(oldURI, newURI)) {
return NS_ERROR_ABORT;
}
aCallback->OnRedirectVerifyCallback(NS_OK);
return NS_OK;
}
struct MOZ_STACK_CLASS SendPingInfo
{
int32_t numPings;
@ -601,21 +495,15 @@ SendPing(void* aClosure, nsIContent* aContent, nsIURI* aURI,
return;
}
if (info->requireSameHost) {
// Make sure the referrer and the given uri share the same origin. We
// only require the same hostname. The scheme and port may differ.
if (!IsSameHost(aURI, info->referrer)) {
return;
}
}
nsIDocument* doc = aContent->OwnerDoc();
nsCOMPtr<nsIChannel> chan;
NS_NewChannel(getter_AddRefs(chan),
aURI,
doc,
nsILoadInfo::SEC_NORMAL,
info->requireSameHost
? nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED
: nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
nsIContentPolicy::TYPE_PING,
nullptr, // aLoadGroup
nullptr, // aCallbacks
@ -714,25 +602,12 @@ SendPing(void* aClosure, nsIContent* aContent, nsIURI* aURI,
if (!loadGroup) {
return;
}
nsCOMPtr<nsIInterfaceRequestor> callbacks = do_QueryInterface(info->docShell);
loadGroup->SetNotificationCallbacks(callbacks);
chan->SetLoadGroup(loadGroup);
// Construct a listener that merely discards any response. If successful at
// opening the channel, then it is not necessary to hold a reference to the
// channel. The networking subsystem will take care of that for us.
nsPingListener* pingListener =
new nsPingListener(info->requireSameHost, aContent, loadGroup);
nsCOMPtr<nsINetworkInterceptController> interceptController =
do_QueryInterface(info->docShell);
pingListener->SetInterceptController(interceptController);
nsCOMPtr<nsIStreamListener> listener(pingListener);
// Observe redirects as well:
nsCOMPtr<nsIInterfaceRequestor> callbacks = do_QueryInterface(listener);
NS_ASSERTION(callbacks, "oops");
loadGroup->SetNotificationCallbacks(callbacks);
chan->AsyncOpen(listener, nullptr);
nsRefPtr<nsPingListener> pingListener = new nsPingListener();
chan->AsyncOpen2(pingListener);
// Even if AsyncOpen failed, we still count this as a successful ping. It's
// possible that AsyncOpen may have failed after triggering some background
@ -744,7 +619,11 @@ SendPing(void* aClosure, nsIContent* aContent, nsIURI* aURI,
// If we failed to setup the timer, then we should just cancel the channel
// because we won't be able to ensure that it goes away in a timely manner.
chan->Cancel(NS_ERROR_ABORT);
return;
}
// if the channel openend successfully, then make the pingListener hold
// a strong reference to the loadgroup which is released in ::OnStopRequest
pingListener->SetLoadGroup(loadGroup);
}
// Spec: http://whatwg.org/specs/web-apps/current-work/#ping

View File

@ -145,12 +145,17 @@ DoContentSecurityChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo)
}
case nsIContentPolicy::TYPE_REFRESH:
case nsIContentPolicy::TYPE_XBL:
case nsIContentPolicy::TYPE_PING: {
case nsIContentPolicy::TYPE_XBL: {
MOZ_ASSERT(false, "contentPolicyType not supported yet");
break;
}
case nsIContentPolicy::TYPE_PING: {
mimeTypeGuess = EmptyCString();
requestingContext = aLoadInfo->LoadingNode();
break;
}
case nsIContentPolicy::TYPE_XMLHTTPREQUEST: {
// alias nsIContentPolicy::TYPE_DATAREQUEST:
requestingContext = aLoadInfo->LoadingNode();