Bug 1199049 - Part 7: Remove entries from the CORS preflight cache in the parent process when a CORS check in the child process fails; r=jduell

This is necessary because it's possible for one request triggered from
a child to start a CORS preflight in the parent process and get an entry
into the preflight cache, and then a CORS check for the same URL to fail
in the child process later on.  In this case, we need to tell the parent
process to clear its CORS preflight cache entry.
This commit is contained in:
Ehsan Akhgari 2015-09-01 19:42:59 -04:00
Родитель d1029ccc78
Коммит c9ef5ad84e
7 изменённых файлов: 106 добавлений и 11 удалений

Просмотреть файл

@ -2173,6 +2173,26 @@ NS_IMETHODIMP HttpChannelChild::GetClientSetRequestHeaders(RequestHeaderTuples *
return NS_OK;
}
NS_IMETHODIMP
HttpChannelChild::RemoveCorsPreflightCacheEntry(nsIURI* aURI,
nsIPrincipal* aPrincipal)
{
URIParams uri;
SerializeURI(aURI, uri);
PrincipalInfo principalInfo;
nsresult rv = PrincipalToPrincipalInfo(aPrincipal, &principalInfo);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
bool result = false;
// Be careful to not attempt to send a message to the parent after the
// actor has been destroyed.
if (mIPCOpen) {
result = SendRemoveCorsPreflightCacheEntry(uri, principalInfo);
}
return result ? NS_OK : NS_ERROR_FAILURE;
}
//-----------------------------------------------------------------------------
// HttpChannelChild::nsIDivertableChannel
//-----------------------------------------------------------------------------

Просмотреть файл

@ -34,6 +34,7 @@
#include "nsIHttpHeaderVisitor.h"
#include "nsQueryObject.h"
#include "mozilla/BasePrincipal.h"
#include "nsCORSListenerProxy.h"
using mozilla::BasePrincipal;
using mozilla::OriginAttributes;
@ -939,6 +940,24 @@ HttpChannelParent::DivertComplete()
mParentListener = nullptr;
}
bool
HttpChannelParent::RecvRemoveCorsPreflightCacheEntry(const URIParams& uri,
const mozilla::ipc::PrincipalInfo& requestingPrincipal)
{
nsCOMPtr<nsIURI> deserializedURI = DeserializeURI(uri);
if (!deserializedURI) {
return false;
}
nsCOMPtr<nsIPrincipal> principal =
PrincipalInfoToPrincipal(requestingPrincipal);
if (!principal) {
return false;
}
nsCORSListenerProxy::RemoveFromCorsPreflightCache(deserializedURI,
principal);
return true;
}
//-----------------------------------------------------------------------------
// HttpChannelParent::nsIRequestObserver
//-----------------------------------------------------------------------------

Просмотреть файл

@ -141,6 +141,8 @@ protected:
const uint32_t& count) override;
virtual bool RecvDivertOnStopRequest(const nsresult& statusCode) override;
virtual bool RecvDivertComplete() override;
virtual bool RecvRemoveCorsPreflightCacheEntry(const URIParams& uri,
const mozilla::ipc::PrincipalInfo& requestingPrincipal) override;
virtual void ActorDestroy(ActorDestroyReason why) override;
// Supporting function for ADivertableParentChannel.

Просмотреть файл

@ -8,6 +8,7 @@
include protocol PNecko;
include InputStreamParams;
include URIParams;
include PBackgroundSharedTypes;
include protocol PBlob; //FIXME: bug #792908
@ -79,6 +80,11 @@ parent:
// Child has no more events/messages to divert to the parent.
DivertComplete();
// Child has detected a CORS check failure, so needs to tell the parent
// to remove any matching entry from the CORS preflight cache.
RemoveCorsPreflightCacheEntry(URIParams uri,
PrincipalInfo requestingPrincipal);
__delete__();
child:

Просмотреть файл

@ -10,6 +10,7 @@
#include "nsCORSListenerProxy.h"
#include "nsIChannel.h"
#include "nsIHttpChannel.h"
#include "nsIHttpChannelChild.h"
#include "nsIHttpChannelInternal.h"
#include "nsError.h"
#include "nsContentUtils.h"
@ -501,15 +502,24 @@ nsCORSListenerProxy::OnStartRequest(nsIRequest* aRequest,
nsresult rv = CheckRequestApproved(aRequest);
mRequestApproved = NS_SUCCEEDED(rv);
if (!mRequestApproved) {
if (sPreflightCache) {
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
if (channel) {
nsCOMPtr<nsIURI> uri;
NS_GetFinalChannelURI(channel, getter_AddRefs(uri));
if (uri) {
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
if (channel) {
nsCOMPtr<nsIURI> uri;
NS_GetFinalChannelURI(channel, getter_AddRefs(uri));
if (uri) {
if (sPreflightCache) {
// OK to use mRequestingPrincipal since preflights never get
// redirected.
sPreflightCache->RemoveEntries(uri, mRequestingPrincipal);
} else {
nsCOMPtr<nsIHttpChannelChild> httpChannelChild =
do_QueryInterface(channel);
if (httpChannelChild) {
rv = httpChannelChild->RemoveCorsPreflightCacheEntry(uri, mRequestingPrincipal);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
}
}
}
@ -732,13 +742,22 @@ nsCORSListenerProxy::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
!NS_IsHSTSUpgradeRedirect(aOldChannel, aNewChannel, aFlags)) {
rv = CheckRequestApproved(aOldChannel);
if (NS_FAILED(rv)) {
if (sPreflightCache) {
nsCOMPtr<nsIURI> oldURI;
NS_GetFinalChannelURI(aOldChannel, getter_AddRefs(oldURI));
if (oldURI) {
nsCOMPtr<nsIURI> oldURI;
NS_GetFinalChannelURI(aOldChannel, getter_AddRefs(oldURI));
if (oldURI) {
if (sPreflightCache) {
// OK to use mRequestingPrincipal since preflights never get
// redirected.
sPreflightCache->RemoveEntries(oldURI, mRequestingPrincipal);
} else {
nsCOMPtr<nsIHttpChannelChild> httpChannelChild =
do_QueryInterface(aOldChannel);
if (httpChannelChild) {
rv = httpChannelChild->RemoveCorsPreflightCacheEntry(oldURI, mRequestingPrincipal);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
}
}
aOldChannel->Cancel(NS_ERROR_DOM_BAD_URI);
@ -1260,6 +1279,16 @@ nsCORSPreflightListener::GetInterface(const nsIID & aIID, void **aResult)
return QueryInterface(aIID, aResult);
}
void
nsCORSListenerProxy::RemoveFromCorsPreflightCache(nsIURI* aURI,
nsIPrincipal* aRequestingPrincipal)
{
MOZ_ASSERT(XRE_IsParentProcess());
if (sPreflightCache) {
sPreflightCache->RemoveEntries(aURI, aRequestingPrincipal);
}
}
nsresult
NS_StartCORSPreflight(nsIChannel* aRequestChannel,
nsIStreamListener* aListener,

Просмотреть файл

@ -33,6 +33,12 @@ NS_StartCORSPreflight(nsIChannel* aRequestChannel,
nsTArray<nsCString>& aACUnsafeHeaders,
nsIChannel** aPreflightChannel);
namespace mozilla {
namespace net {
class HttpChannelParent;
}
}
enum class DataURIHandling
{
Allow,
@ -73,6 +79,12 @@ public:
void SetInterceptController(nsINetworkInterceptController* aInterceptController);
private:
// Only HttpChannelParent can call RemoveFromCorsPreflightCache
friend class mozilla::net::HttpChannelParent;
static void RemoveFromCorsPreflightCache(nsIURI* aURI,
nsIPrincipal* aRequestingPrincipal);
~nsCORSListenerProxy();
nsresult UpdateChannel(nsIChannel* aChannel, DataURIHandling aAllowDataURI);

Просмотреть файл

@ -7,7 +7,10 @@
[ptr] native RequestHeaderTuples(mozilla::net::RequestHeaderTuples);
[uuid(3842c5e9-b5b1-400c-8eb7-936a3316ff21)]
interface nsIPrincipal;
interface nsIURI;
[uuid(81acb360-edd2-428e-935f-300a32efb649)]
interface nsIHttpChannelChild : nsISupports
{
void addCookiesToRequest();
@ -18,4 +21,8 @@ interface nsIHttpChannelChild : nsISupports
// Headers that the channel client has set via SetRequestHeader.
readonly attribute RequestHeaderTuples clientSetRequestHeaders;
// This method is called by nsCORSListenerProxy if we need to remove
// an entry from the CORS preflight cache in the parent process.
void removeCorsPreflightCacheEntry(in nsIURI aURI, in nsIPrincipal aRequestingPrincipal);
};