mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Bug 1192955 - Use channel->ascynOpen2 for PING in docshell/base/nsDocShell.cpp (r=sicking)
This commit is contained in:
parent
ecdc701ca0
commit
dad90516d6
@ -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
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user