diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index d06dc992df93..89d024c23692 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -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 //----------------------------------------------------------------------------- diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index f01236df06ee..6cb370ca219e 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -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 deserializedURI = DeserializeURI(uri); + if (!deserializedURI) { + return false; + } + nsCOMPtr principal = + PrincipalInfoToPrincipal(requestingPrincipal); + if (!principal) { + return false; + } + nsCORSListenerProxy::RemoveFromCorsPreflightCache(deserializedURI, + principal); + return true; +} + //----------------------------------------------------------------------------- // HttpChannelParent::nsIRequestObserver //----------------------------------------------------------------------------- diff --git a/netwerk/protocol/http/HttpChannelParent.h b/netwerk/protocol/http/HttpChannelParent.h index 8788a862cf8e..8afe3237dc1a 100644 --- a/netwerk/protocol/http/HttpChannelParent.h +++ b/netwerk/protocol/http/HttpChannelParent.h @@ -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. diff --git a/netwerk/protocol/http/PHttpChannel.ipdl b/netwerk/protocol/http/PHttpChannel.ipdl index 4ead186b2867..1456b961acf0 100644 --- a/netwerk/protocol/http/PHttpChannel.ipdl +++ b/netwerk/protocol/http/PHttpChannel.ipdl @@ -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: diff --git a/netwerk/protocol/http/nsCORSListenerProxy.cpp b/netwerk/protocol/http/nsCORSListenerProxy.cpp index 4ffcdc565e83..b1054891e562 100644 --- a/netwerk/protocol/http/nsCORSListenerProxy.cpp +++ b/netwerk/protocol/http/nsCORSListenerProxy.cpp @@ -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 channel = do_QueryInterface(aRequest); - if (channel) { - nsCOMPtr uri; - NS_GetFinalChannelURI(channel, getter_AddRefs(uri)); - if (uri) { + nsCOMPtr channel = do_QueryInterface(aRequest); + if (channel) { + nsCOMPtr 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 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 oldURI; - NS_GetFinalChannelURI(aOldChannel, getter_AddRefs(oldURI)); - if (oldURI) { + nsCOMPtr 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 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, diff --git a/netwerk/protocol/http/nsCORSListenerProxy.h b/netwerk/protocol/http/nsCORSListenerProxy.h index 8d790e8b0e5a..947d3e7a8ad6 100644 --- a/netwerk/protocol/http/nsCORSListenerProxy.h +++ b/netwerk/protocol/http/nsCORSListenerProxy.h @@ -33,6 +33,12 @@ NS_StartCORSPreflight(nsIChannel* aRequestChannel, nsTArray& 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); diff --git a/netwerk/protocol/http/nsIHttpChannelChild.idl b/netwerk/protocol/http/nsIHttpChannelChild.idl index 93911f7c19ab..8d9e016163dd 100644 --- a/netwerk/protocol/http/nsIHttpChannelChild.idl +++ b/netwerk/protocol/http/nsIHttpChannelChild.idl @@ -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); };