Bug 1049299 - Correctly calculate 3rd-party cookie status for content-process HTTP channels. r=jduell
authorBlake Kaplan <mrbkap@gmail.com>
Tue, 28 Oct 2014 14:23:00 +0100
changeset 239346 249b822b256a58be0c6b446188b85dbede247f03
parent 239345 df77d22352254d84b0b4f3a57282651b979cf25f
child 239347 6cd46e671a9da906757a04115d4768ce6e13b124
push id660
push userraliiev@mozilla.com
push dateWed, 18 Feb 2015 20:30:48 +0000
treeherdermozilla-release@49e493494178 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjduell
bugs1049299
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1049299 - Correctly calculate 3rd-party cookie status for content-process HTTP channels. r=jduell
docshell/base/nsDocShell.cpp
dom/base/Navigator.cpp
dom/base/ThirdPartyUtil.cpp
embedding/components/webbrowserpersist/nsWebBrowserPersist.cpp
netwerk/ipc/NeckoChannelParams.ipdlh
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/http/HttpBaseChannel.h
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/HttpChannelParent.h
netwerk/protocol/http/nsIHttpChannelInternal.idl
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -10373,18 +10373,18 @@ nsDocShell::DoURILoad(nsIURI * aURI,
       }
     }
 
     //hack
     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
     nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(do_QueryInterface(channel));
     if (httpChannelInternal) {
       if (aForceAllowCookies) {
-        httpChannelInternal->SetForceAllowThirdPartyCookie(true);
-      } 
+        httpChannelInternal->SetThirdPartyFlags(nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW);
+      }
       if (aFirstParty) {
         httpChannelInternal->SetDocumentURI(aURI);
       } else {
         httpChannelInternal->SetDocumentURI(aReferrerURI);
       }
     }
 
     nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(channel));
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1088,17 +1088,20 @@ Navigator::SendBeacon(const nsAString& a
   nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(do_QueryInterface(channel));
   nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = do_GetService(THIRDPARTYUTIL_CONTRACTID);
   if (!httpChannelInternal) {
     aRv.Throw(NS_ERROR_DOM_BAD_URI);
     return false;
   }
   bool isForeign = true;
   thirdPartyUtil->IsThirdPartyWindow(mWindow, uri, &isForeign);
-  httpChannelInternal->SetForceAllowThirdPartyCookie(!isForeign);
+  uint32_t thirdPartyFlags = isForeign ?
+    0 :
+    nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW;
+  httpChannelInternal->SetThirdPartyFlags(thirdPartyFlags);
 
   nsCString mimeType;
   if (!aData.IsNull()) {
     nsCOMPtr<nsIInputStream> in;
 
     if (aData.Value().IsString()) {
       nsCString stringData = NS_ConvertUTF16toUTF8(aData.Value().GetAsString());
       nsCOMPtr<nsIStringInputStream> strStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
--- a/dom/base/ThirdPartyUtil.cpp
+++ b/dom/base/ThirdPartyUtil.cpp
@@ -1,8 +1,10 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 sts=2 ts=8 et tw=80 : */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ThirdPartyUtil.h"
 #include "nsNetUtil.h"
 #include "nsIServiceManager.h"
 #include "nsIHttpChannelInternal.h"
@@ -161,30 +163,57 @@ ThirdPartyUtil::IsThirdPartyChannel(nsIC
                                     nsIURI* aURI,
                                     bool* aResult)
 {
   NS_ENSURE_ARG(aChannel);
   NS_ASSERTION(aResult, "null outparam pointer");
 
   nsresult rv;
   bool doForce = false;
+  bool checkWindowChain = true;
+  bool parentIsThird = false;
   nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal =
     do_QueryInterface(aChannel);
   if (httpChannelInternal) {
-    rv = httpChannelInternal->GetForceAllowThirdPartyCookie(&doForce);
+    uint32_t flags;
+    rv = httpChannelInternal->GetThirdPartyFlags(&flags);
     NS_ENSURE_SUCCESS(rv, rv);
 
+    doForce = (flags & nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW);
+
     // If aURI was not supplied, and we're forcing, then we're by definition
     // not foreign. If aURI was supplied, we still want to check whether it's
     // foreign with respect to the channel URI. (The forcing only applies to
     // whatever window hierarchy exists above the channel.)
     if (doForce && !aURI) {
       *aResult = false;
       return NS_OK;
     }
+
+    if (flags & nsIHttpChannelInternal::THIRD_PARTY_PARENT_IS_THIRD_PARTY) {
+      // Check that the two PARENT_IS_{THIRD,SAME}_PARTY are mutually exclusive.
+      MOZ_ASSERT(!(flags & nsIHttpChannelInternal::THIRD_PARTY_PARENT_IS_SAME_PARTY));
+
+      // If we're not forcing and we know that the window chain of the channel
+      // is third party, then we know now that we're third party.
+      if (!doForce) {
+        *aResult = true;
+        return NS_OK;
+      }
+
+      checkWindowChain = false;
+      parentIsThird = true;
+    } else {
+      // In e10s, we can't check the parent chain in the parent, so we do so
+      // in the child and send the result to the parent.
+      // Note that we only check the window chain if neither
+      // THIRD_PARTY_PARENT_IS_* flag is set.
+      checkWindowChain = !(flags & nsIHttpChannelInternal::THIRD_PARTY_PARENT_IS_SAME_PARTY);
+      parentIsThird = false;
+    }
   }
 
   // Obtain the URI from the channel, and its base domain.
   nsCOMPtr<nsIURI> channelURI;
   aChannel->GetURI(getter_AddRefs(channelURI));
   NS_ENSURE_TRUE(channelURI, NS_ERROR_INVALID_ARG);
 
   nsCString channelDomain;
@@ -201,16 +230,22 @@ ThirdPartyUtil::IsThirdPartyChannel(nsIC
 
     // If it's foreign, or we're forcing, we're done.
     if (result || doForce) {
       *aResult = result;
       return NS_OK;
     }
   }
 
+  // If we've already computed this in the child process, we're done.
+  if (!checkWindowChain) {
+    *aResult = parentIsThird;
+    return NS_OK;
+  }
+
   // Find the associated window and its parent window.
   nsCOMPtr<nsILoadContext> ctx;
   NS_QueryNotificationCallbacks(aChannel, ctx);
   if (!ctx) return NS_ERROR_INVALID_ARG;
 
   // If there is no window, the consumer kicking off the load didn't provide one
   // to the channel. This is limited to loads of certain types of resources. If
   // those loads require cookies, the forceAllowThirdPartyCookie property should
--- a/embedding/components/webbrowserpersist/nsWebBrowserPersist.cpp
+++ b/embedding/components/webbrowserpersist/nsWebBrowserPersist.cpp
@@ -1231,17 +1231,17 @@ nsresult nsWebBrowserPersist::SaveURIInt
         }
     }
 
     if (mPersistFlags & PERSIST_FLAGS_FORCE_ALLOW_COOKIES)
     {
         nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal =
                 do_QueryInterface(inputChannel);
         if (httpChannelInternal)
-            httpChannelInternal->SetForceAllowThirdPartyCookie(true);
+            httpChannelInternal->SetThirdPartyFlags(nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW);
     }
 
     // Set the referrer, post data and headers if any
     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(inputChannel));
     if (httpChannel)
     {
         // Referrer
         if (aReferrer)
--- a/netwerk/ipc/NeckoChannelParams.ipdlh
+++ b/netwerk/ipc/NeckoChannelParams.ipdlh
@@ -37,17 +37,17 @@ struct HttpChannelOpenArgs
   RequestHeaderTuples         requestHeaders;
   nsCString                   requestMethod;
   OptionalInputStreamParams   uploadStream;
   bool                        uploadStreamHasHeaders;
   uint16_t                    priority;
   uint8_t                     redirectionLimit;
   bool                        allowPipelining;
   bool                        allowSTS;
-  bool                        forceAllowThirdPartyCookie;
+  uint32_t                    thirdPartyFlags;
   bool                        resumeAt;
   uint64_t                    startPos;
   nsCString                   entityID;
   bool                        chooseApplicationCache;
   nsCString                   appCacheClientID;
   bool                        allowSpdy;
   OptionalFileDescriptorSet   fds;
   PrincipalInfo               requestingPrincipalInfo;
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -51,17 +51,17 @@ HttpBaseChannel::HttpBaseChannel()
   , mApplyConversion(true)
   , mCanceled(false)
   , mIsPending(false)
   , mWasOpened(false)
   , mRequestObserversCalled(false)
   , mResponseHeadersModified(false)
   , mAllowPipelining(true)
   , mAllowSTS(true)
-  , mForceAllowThirdPartyCookie(false)
+  , mThirdPartyFlags(0)
   , mUploadStreamHasHeaders(false)
   , mInheritApplicationCache(true)
   , mChooseApplicationCache(false)
   , mLoadedFromApplicationCache(false)
   , mChannelIsForDownload(false)
   , mTracingEnabled(true)
   , mTimingEnabled(false)
   , mAllowSpdy(true)
@@ -1424,28 +1424,48 @@ HttpBaseChannel::SetCookie(const char *a
     nsRefPtr<CookieNotifierRunnable> r =
       new CookieNotifierRunnable(this, aCookieHeader);
     NS_DispatchToMainThread(r);
   }
   return rv;
 }
 
 NS_IMETHODIMP
+HttpBaseChannel::GetThirdPartyFlags(uint32_t  *aFlags)
+{
+  *aFlags = mThirdPartyFlags;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::SetThirdPartyFlags(uint32_t aFlags)
+{
+  ENSURE_CALLED_BEFORE_ASYNC_OPEN();
+
+  mThirdPartyFlags = aFlags;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 HttpBaseChannel::GetForceAllowThirdPartyCookie(bool *aForce)
 {
-  *aForce = mForceAllowThirdPartyCookie;
+  *aForce = !!(mThirdPartyFlags & nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::SetForceAllowThirdPartyCookie(bool aForce)
 {
   ENSURE_CALLED_BEFORE_ASYNC_OPEN();
 
-  mForceAllowThirdPartyCookie = aForce;
+  if (aForce)
+    mThirdPartyFlags |= nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW;
+  else
+    mThirdPartyFlags &= ~nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW;
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::GetCanceled(bool *aCanceled)
 {
   *aCanceled = mCanceled;
   return NS_OK;
@@ -2035,19 +2055,18 @@ HttpBaseChannel::SetupReplacementChannel
       httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
                                     oldAcceptValue,
                                     false);
     }
   }
 
   nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(newChannel);
   if (httpInternal) {
-    // convey the mForceAllowThirdPartyCookie flag
-    httpInternal->SetForceAllowThirdPartyCookie(mForceAllowThirdPartyCookie);
-    // convey the spdy flag
+    // Convey third party cookie and spdy flags.
+    httpInternal->SetThirdPartyFlags(mThirdPartyFlags);
     httpInternal->SetAllowSpdy(mAllowSpdy);
 
     // update the DocumentURI indicator since we are being redirected.
     // if this was a top-level document channel, then the new channel
     // should have its mDocumentURI point to newURI; otherwise, we
     // just need to pass along our mDocumentURI to the new channel.
     if (newURI && (mURI == mDocumentURI))
       httpInternal->SetDocumentURI(newURI);
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -155,16 +155,18 @@ public:
   NS_IMETHOD RedirectTo(nsIURI *newURI);
 
   // nsIHttpChannelInternal
   NS_IMETHOD GetDocumentURI(nsIURI **aDocumentURI);
   NS_IMETHOD SetDocumentURI(nsIURI *aDocumentURI);
   NS_IMETHOD GetRequestVersion(uint32_t *major, uint32_t *minor);
   NS_IMETHOD GetResponseVersion(uint32_t *major, uint32_t *minor);
   NS_IMETHOD SetCookie(const char *aCookieHeader);
+  NS_IMETHOD GetThirdPartyFlags(uint32_t *aForce);
+  NS_IMETHOD SetThirdPartyFlags(uint32_t aForce);
   NS_IMETHOD GetForceAllowThirdPartyCookie(bool *aForce);
   NS_IMETHOD SetForceAllowThirdPartyCookie(bool aForce);
   NS_IMETHOD GetCanceled(bool *aCanceled);
   NS_IMETHOD GetChannelIsForDownload(bool *aChannelIsForDownload);
   NS_IMETHOD SetChannelIsForDownload(bool aChannelIsForDownload);
   NS_IMETHOD SetCacheKeysRedirectChain(nsTArray<nsCString> *cacheKeys);
   NS_IMETHOD GetLocalAddress(nsACString& addr);
   NS_IMETHOD GetLocalPort(int32_t* port);
@@ -336,17 +338,17 @@ protected:
   uint32_t                          mCanceled                   : 1;
   uint32_t                          mIsPending                  : 1;
   uint32_t                          mWasOpened                  : 1;
   // if 1 all "http-on-{opening|modify|etc}-request" observers have been called
   uint32_t                          mRequestObserversCalled     : 1;
   uint32_t                          mResponseHeadersModified    : 1;
   uint32_t                          mAllowPipelining            : 1;
   uint32_t                          mAllowSTS                   : 1;
-  uint32_t                          mForceAllowThirdPartyCookie : 1;
+  uint32_t                          mThirdPartyFlags            : 3;
   uint32_t                          mUploadStreamHasHeaders     : 1;
   uint32_t                          mInheritApplicationCache    : 1;
   uint32_t                          mChooseApplicationCache     : 1;
   uint32_t                          mLoadedFromApplicationCache : 1;
   uint32_t                          mChannelIsForDownload       : 1;
   uint32_t                          mTracingEnabled             : 1;
   // True if timing collection is enabled
   uint32_t                          mTimingEnabled              : 1;
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -26,16 +26,17 @@
 #include "mozilla/ipc/URIUtils.h"
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/net/ChannelDiverterChild.h"
 #include "mozilla/net/DNS.h"
 #include "SerializedLoadContext.h"
 #include "nsInputStreamPump.h"
 #include "InterceptedChannel.h"
 #include "nsPerformance.h"
+#include "mozIThirdPartyUtil.h"
 
 using namespace mozilla::dom;
 using namespace mozilla::ipc;
 
 namespace mozilla {
 namespace net {
 
 //-----------------------------------------------------------------------------
@@ -1479,24 +1480,39 @@ HttpChannelChild::ContinueAsyncOpen()
 
   OptionalFileDescriptorSet optionalFDs;
   if (fdSet) {
     optionalFDs = fdSet;
   } else {
     optionalFDs = mozilla::void_t();
   }
 
+  nsCOMPtr<mozIThirdPartyUtil> util(do_GetService(THIRDPARTYUTIL_CONTRACTID));
+  if (util) {
+    bool thirdParty;
+    nsresult rv = util->IsThirdPartyChannel(this, nullptr, &thirdParty);
+    if (NS_FAILED(rv)) {
+      // If we couldn't compute whether this is a third-party load, assume that
+      // it is.
+      thirdParty = true;
+    }
+
+    mThirdPartyFlags |= thirdParty ?
+      nsIHttpChannelInternal::THIRD_PARTY_PARENT_IS_THIRD_PARTY :
+      nsIHttpChannelInternal::THIRD_PARTY_PARENT_IS_SAME_PARTY;
+  }
+
   openArgs.fds() = optionalFDs;
 
   openArgs.uploadStreamHasHeaders() = mUploadStreamHasHeaders;
   openArgs.priority() = mPriority;
   openArgs.redirectionLimit() = mRedirectionLimit;
   openArgs.allowPipelining() = mAllowPipelining;
   openArgs.allowSTS() = mAllowSTS;
-  openArgs.forceAllowThirdPartyCookie() = mForceAllowThirdPartyCookie;
+  openArgs.thirdPartyFlags() = mThirdPartyFlags;
   openArgs.resumeAt() = mSendResumeAt;
   openArgs.startPos() = mStartPos;
   openArgs.entityID() = mEntityID;
   openArgs.chooseApplicationCache() = mChooseApplicationCache;
   openArgs.appCacheClientID() = appCacheClientId;
   openArgs.allowSpdy() = mAllowSpdy;
 
   propagateLoadInfo(mLoadInfo, openArgs);
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -96,18 +96,18 @@ HttpChannelParent::Init(const HttpChanne
   case HttpChannelCreationArgs::THttpChannelOpenArgs:
   {
     const HttpChannelOpenArgs& a = aArgs.get_HttpChannelOpenArgs();
     return DoAsyncOpen(a.uri(), a.original(), a.doc(), a.referrer(),
                        a.apiRedirectTo(), a.loadFlags(), a.requestHeaders(),
                        a.requestMethod(), a.uploadStream(),
                        a.uploadStreamHasHeaders(), a.priority(),
                        a.redirectionLimit(), a.allowPipelining(), a.allowSTS(),
-                       a.forceAllowThirdPartyCookie(), a.resumeAt(),
-                       a.startPos(), a.entityID(), a.chooseApplicationCache(),
+                       a.thirdPartyFlags(), a.resumeAt(), a.startPos(),
+                       a.entityID(), a.chooseApplicationCache(),
                        a.appCacheClientID(), a.allowSpdy(), a.fds(),
                        a.requestingPrincipalInfo(), a.securityFlags(),
                        a.contentPolicyType());
   }
   case HttpChannelCreationArgs::THttpChannelConnectArgs:
   {
     const HttpChannelConnectArgs& cArgs = aArgs.get_HttpChannelConnectArgs();
     return ConnectChannel(cArgs.channelId());
@@ -171,22 +171,22 @@ HttpChannelParent::DoAsyncOpen(  const U
                                  const OptionalURIParams&   aOriginalURI,
                                  const OptionalURIParams&   aDocURI,
                                  const OptionalURIParams&   aReferrerURI,
                                  const OptionalURIParams&   aAPIRedirectToURI,
                                  const uint32_t&            aLoadFlags,
                                  const RequestHeaderTuples& requestHeaders,
                                  const nsCString&           requestMethod,
                                  const OptionalInputStreamParams& uploadStream,
-                                 const bool&              uploadStreamHasHeaders,
+                                 const bool&                uploadStreamHasHeaders,
                                  const uint16_t&            priority,
                                  const uint8_t&             redirectionLimit,
-                                 const bool&              allowPipelining,
-                                 const bool&              allowSTS,
-                                 const bool&              forceAllowThirdPartyCookie,
+                                 const bool&                allowPipelining,
+                                 const bool&                allowSTS,
+                                 const uint32_t&            thirdPartyFlags,
                                  const bool&                doResumeAt,
                                  const uint64_t&            startPos,
                                  const nsCString&           entityID,
                                  const bool&                chooseApplicationCache,
                                  const nsCString&           appCacheClientID,
                                  const bool&                allowSpdy,
                                  const OptionalFileDescriptorSet& aFds,
                                  const ipc::PrincipalInfo&  aRequestingPrincipalInfo,
@@ -299,17 +299,17 @@ HttpChannelParent::DoAsyncOpen(  const U
     mChannel->SetUploadStreamHasHeaders(uploadStreamHasHeaders);
   }
 
   if (priority != nsISupportsPriority::PRIORITY_NORMAL)
     mChannel->SetPriority(priority);
   mChannel->SetRedirectionLimit(redirectionLimit);
   mChannel->SetAllowPipelining(allowPipelining);
   mChannel->SetAllowSTS(allowSTS);
-  mChannel->SetForceAllowThirdPartyCookie(forceAllowThirdPartyCookie);
+  mChannel->SetThirdPartyFlags(thirdPartyFlags);
   mChannel->SetAllowSpdy(allowSpdy);
 
   nsCOMPtr<nsIApplicationCacheChannel> appCacheChan =
     do_QueryObject(mChannel);
   nsCOMPtr<nsIApplicationCacheService> appCacheService =
     do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID);
 
   bool setChooseApplicationCache = chooseApplicationCache;
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -94,17 +94,17 @@ protected:
                    const RequestHeaderTuples& requestHeaders,
                    const nsCString&           requestMethod,
                    const OptionalInputStreamParams& uploadStream,
                    const bool&                uploadStreamHasHeaders,
                    const uint16_t&            priority,
                    const uint8_t&             redirectionLimit,
                    const bool&                allowPipelining,
                    const bool&                allowSTS,
-                   const bool&                forceAllowThirdPartyCookie,
+                   const uint32_t&            thirdPartyFlags,
                    const bool&                doResumeAt,
                    const uint64_t&            startPos,
                    const nsCString&           entityID,
                    const bool&                chooseApplicationCache,
                    const nsCString&           appCacheClientID,
                    const bool&                allowSpdy,
                    const OptionalFileDescriptorSet& aFds,
                    const ipc::PrincipalInfo&  aRequestingPrincipalInfo,
--- a/netwerk/protocol/http/nsIHttpChannelInternal.idl
+++ b/netwerk/protocol/http/nsIHttpChannelInternal.idl
@@ -33,17 +33,17 @@ interface nsIHttpUpgradeListener : nsISu
                               in nsIAsyncOutputStream aSocketOut);
 };
 
 /**
  * Dumping ground for http.  This interface will never be frozen.  If you are
  * using any feature exposed by this interface, be aware that this interface
  * will change and you will be broken.  You have been warned.
  */
-[scriptable, uuid(a95e45c1-b145-487c-b2a9-4e96e814a1b5)]
+[scriptable, uuid(2677e555-8c48-4147-b883-5c2a673f65d5)]
 interface nsIHttpChannelInternal : nsISupports
 {
     /**
      * An http channel can own a reference to the document URI
      */
     attribute nsIURI documentURI;
 
     /**
@@ -73,18 +73,46 @@ interface nsIHttpChannelInternal : nsISu
     void setCookie(in string aCookieHeader);
 
     /**
      * Setup this channel as an application cache fallback channel.
      */
     void setupFallbackChannel(in string aFallbackKey);
 
     /**
-     * Force relevant cookies to be sent with this load even if normally they
-     * wouldn't be.
+     * This flag is set to force relevant cookies to be sent with this load
+     * even if normally they wouldn't be.
+     */
+    const unsigned long THIRD_PARTY_FORCE_ALLOW = 1 << 0;
+
+    /**
+     * This flag is set in the parent if the child has already computed that
+     * it originates from a 3rd party frame (i.e. a 3rd party iframe).
+     */
+    const unsigned long THIRD_PARTY_PARENT_IS_THIRD_PARTY = 1 << 1;
+
+    /**
+     * This flag is set in the parent if the child has already computed that
+     * it is not a 3rd party request due to iframe parentage. However, if
+     * someone calls mozIThirdPartyUtil::IsThirdPartyChannel with a 3rd-party
+     * URI, the result would be true if the URI is third-party from this
+     * channel's URI.
+     */
+    const unsigned long THIRD_PARTY_PARENT_IS_SAME_PARTY = 1 << 2;
+
+    /**
+     * When set, these flags modify the algorithm used to decide whether to
+     * send 3rd party cookies for a given channel.
+     */
+    attribute unsigned long thirdPartyFlags;
+
+    /**
+     * This attribute was added before the "flags" above and is retained here
+     * for compatibility. When set to true, has the same effect as
+     * THIRD_PARTY_FORCE_ALLOW, described above.
      */
     attribute boolean forceAllowThirdPartyCookie;
 
     /**
      * True iff the channel has been canceled.
      */
     readonly attribute boolean canceled;