Bug 1304140 - Part 1: Implement support for the Large-Allocation header behind the dom.largeAllocationHeader.enabled pref, r=smaug
authorMichael Layzell <michael@thelayzells.com>
Fri, 21 Oct 2016 16:56:51 -0400
changeset 347040 f0cee6a12df706e9f1eb6e6381d3c33967781b57
parent 347039 1e58a5a4ba4a267fc43959b305dd1eb7640ee30e
child 347041 9bbdaf510059a0e2c9f66069d462dbed35d29d03
push id10298
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:33:03 +0000
treeherdermozilla-aurora@7e29173b1641 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1304140
milestone52.0a1
Bug 1304140 - Part 1: Implement support for the Large-Allocation header behind the dom.largeAllocationHeader.enabled pref, r=smaug MozReview-Commit-ID: 5KBIu6Fc3Ea
browser/base/content/tab-content.js
browser/base/content/tabbrowser.xml
browser/components/sessionstore/SessionStore.jsm
browser/modules/E10SUtils.jsm
dom/base/DocGroup.cpp
dom/base/TabGroup.cpp
dom/base/TabGroup.h
dom/base/nsContentUtils.cpp
dom/base/nsContentUtils.h
dom/base/nsFrameLoader.cpp
dom/base/nsFrameLoader.h
dom/base/nsGkAtomList.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PBrowser.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/locales/en-US/chrome/dom/dom.properties
embedding/browser/nsIWebBrowserChrome3.idl
uriloader/base/moz.build
uriloader/base/nsURILoader.cpp
xpfe/appshell/nsContentTreeOwner.cpp
--- a/browser/base/content/tab-content.js
+++ b/browser/base/content/tab-content.js
@@ -617,16 +617,22 @@ var WebBrowserChrome = {
   shouldLoadURI: function(aDocShell, aURI, aReferrer) {
     if (!E10SUtils.shouldLoadURI(aDocShell, aURI, aReferrer)) {
       E10SUtils.redirectLoad(aDocShell, aURI, aReferrer);
       return false;
     }
 
     return true;
   },
+
+  // Try to reload the currently active or currently loading page in a new process.
+  reloadInFreshProcess: function(aDocShell, aURI, aReferrer) {
+    E10SUtils.redirectLoad(aDocShell, aURI, aReferrer, true);
+    return true;
+  }
 };
 
 if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
   let tabchild = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
                          .getInterface(Ci.nsITabChild);
   tabchild.webBrowserChrome = WebBrowserChrome;
 }
 
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1654,16 +1654,17 @@
           }
         ]]></body>
       </method>
 
       <method name="updateBrowserRemoteness">
         <parameter name="aBrowser"/>
         <parameter name="aShouldBeRemote"/>
         <parameter name="aOpener"/>
+        <parameter name="aFreshProcess"/>
         <body>
           <![CDATA[
             let isRemote = aBrowser.getAttribute("remote") == "true";
 
             // If we are passed an opener, we must be making the browser non-remote, and
             // if the browser is _currently_ non-remote, we need the openers to match,
             // because it is already too late to change it.
             if (aOpener) {
@@ -1671,17 +1672,17 @@
                 throw new Exception("Cannot set an opener on a browser which should be remote!");
               }
               if (!isRemote && aBrowser.contentWindow.opener != aOpener) {
                 throw new Exception("Cannot change opener on an already non-remote browser!");
               }
             }
 
             // Abort if we're not going to change anything
-            if (isRemote == aShouldBeRemote) {
+            if (isRemote == aShouldBeRemote && !aFreshProcess) {
               return false;
             }
 
             let tab = this.getTabForBrowser(aBrowser);
             let evt = document.createEvent("Events");
             evt.initEvent("BeforeTabRemotenessChange", true, false);
             tab.dispatchEvent(evt);
 
@@ -1718,18 +1719,28 @@
             // NB: This works with the hack in the browser constructor that
             // turns this normal property into a field.
             aBrowser.relatedBrowser = relatedBrowser;
 
             // Set the opener window on the browser, such that when the frame
             // loader is created the opener is set correctly.
             aBrowser.presetOpenerWindow(aOpener);
 
+            // Set the freshProcess attribute so that the frameloader knows to
+            // create a new process
+            if (aFreshProcess) {
+              aBrowser.setAttribute("freshProcess", "true");
+            }
+
             parent.appendChild(aBrowser);
 
+            // Remove the freshProcess attribute if we set it, as we don't
+            // want it to apply for the next time the frameloader is created
+            aBrowser.removeAttribute("freshProcess");
+
             aBrowser.userTypedValue = oldUserTypedValue;
             if (hadStartedLoad) {
               aBrowser.urlbarChangeTracker.startedLoad();
             }
 
             aBrowser.droppedLinkHandler = droppedLinkHandler;
 
             // Switching a browser's remoteness will create a new frameLoader.
@@ -1782,16 +1793,32 @@
             evt.initEvent("TabRemotenessChange", true, false);
             tab.dispatchEvent(evt);
 
             return true;
           ]]>
         </body>
       </method>
 
+      <method name="switchBrowserIntoFreshProcess">
+        <parameter name="aBrowser"/>
+        <body>
+          <![CDATA[
+            if (!gMultiProcessBrowser) {
+              return this.updateBrowserRemoteness(aBrowser, false);
+            }
+
+            return this.updateBrowserRemoteness(aBrowser,
+                                                /* aShouldBeRemote */ true,
+                                                /* aOpener */ null,
+                                                /* aFreshProcess */ true);
+          ]]>
+        </body>
+      </method>
+
       <method name="updateBrowserRemotenessByURL">
         <parameter name="aBrowser"/>
         <parameter name="aURL"/>
         <body>
           <![CDATA[
             if (!gMultiProcessBrowser)
               return this.updateBrowserRemoteness(aBrowser, false);
 
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -2609,17 +2609,23 @@ var SessionStoreInternal = {
       let window = tab.ownerGlobal;
 
       // The tab or its window might be gone.
       if (!window || !window.__SSi || window.closed) {
         return;
       }
 
       let tabState = TabState.clone(tab);
-      let options = {restoreImmediately: true};
+      let options = {
+        restoreImmediately: true,
+        // We want to make sure that this information is passed to restoreTab
+        // whether or not a historyIndex is passed in. Thus, we extract it from
+        // the loadArguments.
+        reloadInFreshProcess: !!recentLoadArguments.reloadInFreshProcess,
+      };
 
       if (historyIndex >= 0) {
         tabState.index = historyIndex + 1;
         tabState.index = Math.max(1, Math.min(tabState.index, tabState.entries.length));
       } else {
         options.loadArguments = recentLoadArguments;
       }
 
@@ -3269,16 +3275,17 @@ var SessionStoreInternal = {
               "must reset tab before calling restoreTab()");
 
     let restoreImmediately = options.restoreImmediately;
     let loadArguments = options.loadArguments;
     let browser = tab.linkedBrowser;
     let window = tab.ownerGlobal;
     let tabbrowser = window.gBrowser;
     let forceOnDemand = options.forceOnDemand;
+    let reloadInFreshProcess = options.reloadInFreshProcess;
 
     let willRestoreImmediately = restoreImmediately ||
                                  tabbrowser.selectedBrowser == browser ||
                                  loadArguments;
 
     if (!willRestoreImmediately && !forceOnDemand) {
       TabRestoreQueue.add(tab);
     }
@@ -3391,37 +3398,36 @@ var SessionStoreInternal = {
     // Restore tab attributes.
     if ("attributes" in tabData) {
       TabAttributes.set(tab, tabData.attributes);
     }
 
     // This could cause us to ignore MAX_CONCURRENT_TAB_RESTORES a bit, but
     // it ensures each window will have its selected tab loaded.
     if (willRestoreImmediately) {
-      this.restoreTabContent(tab, loadArguments);
+      this.restoreTabContent(tab, loadArguments, reloadInFreshProcess);
     } else if (!forceOnDemand) {
       this.restoreNextTab();
     }
 
     // Decrease the busy state counter after we're done.
     this._setWindowStateReady(window);
   },
 
   /**
    * Kicks off restoring the given tab.
    *
    * @param aTab
    *        the tab to restore
    * @param aLoadArguments
    *        optional load arguments used for loadURI()
-   * @param aRemotenessSwitch
-   *        true if we're restoring a tab's content because we flipped
-   *        its remoteness (out-of-process) state.
+   * @param aReloadInFreshProcess
+   *        true if we want to reload into a fresh process
    */
-  restoreTabContent: function (aTab, aLoadArguments = null) {
+  restoreTabContent: function (aTab, aLoadArguments = null, aReloadInFreshProcess = false) {
     if (aTab.hasAttribute("customizemode")) {
       return;
     }
 
     let browser = aTab.linkedBrowser;
     let window = aTab.ownerGlobal;
     let tabbrowser = window.gBrowser;
     let tabData = TabState.clone(aTab);
@@ -3436,17 +3442,23 @@ var SessionStoreInternal = {
     }
 
     // We have to mark this tab as restoring first, otherwise
     // the "pending" attribute will be applied to the linked
     // browser, which removes it from the display list. We cannot
     // flip the remoteness of any browser that is not being displayed.
     this.markTabAsRestoring(aTab);
 
-    let isRemotenessUpdate = tabbrowser.updateBrowserRemotenessByURL(browser, uri);
+    let isRemotenessUpdate = false;
+    if (aReloadInFreshProcess) {
+      isRemotenessUpdate = tabbrowser.switchBrowserIntoFreshProcess(browser);
+    } else {
+      isRemotenessUpdate = tabbrowser.updateBrowserRemotenessByURL(browser, uri);
+    }
+
     if (isRemotenessUpdate) {
       // We updated the remoteness, so we need to send the history down again.
       //
       // Start a new epoch to discard all frame script messages relating to a
       // previous epoch. All async messages that are still on their way to chrome
       // will be ignored and don't override any tab data set when restoring.
       let epoch = this.startNextEpoch(browser);
 
--- a/browser/modules/E10SUtils.jsm
+++ b/browser/modules/E10SUtils.jsm
@@ -91,27 +91,28 @@ this.E10SUtils = {
     // Inner frames should always load in the current process
     if (aDocShell.QueryInterface(Ci.nsIDocShellTreeItem).sameTypeParent)
       return true;
 
     // If the URI can be loaded in the current process then continue
     return this.canLoadURIInProcess(aURI.spec, Services.appinfo.processType);
   },
 
-  redirectLoad: function(aDocShell, aURI, aReferrer) {
+  redirectLoad: function(aDocShell, aURI, aReferrer, aFreshProcess) {
     // Retarget the load to the correct process
     let messageManager = aDocShell.QueryInterface(Ci.nsIInterfaceRequestor)
                                   .getInterface(Ci.nsIContentFrameMessageManager);
     let sessionHistory = aDocShell.getInterface(Ci.nsIWebNavigation).sessionHistory;
 
     messageManager.sendAsyncMessage("Browser:LoadURI", {
       loadOptions: {
         uri: aURI.spec,
         flags: Ci.nsIWebNavigation.LOAD_FLAGS_NONE,
         referrer: aReferrer ? aReferrer.spec : null,
+        reloadInFreshProcess: !!aFreshProcess,
       },
       historyIndex: sessionHistory.requestedIndex,
     });
     return false;
   },
 
   wrapHandlingUserInput: function(aWindow, aIsHandling, aCallback) {
     var handlingUserInput;
--- a/dom/base/DocGroup.cpp
+++ b/dom/base/DocGroup.cpp
@@ -44,11 +44,10 @@ DocGroup::DocGroup(TabGroup* aTabGroup, 
 DocGroup::~DocGroup()
 {
   MOZ_ASSERT(mDocuments.IsEmpty());
   mTabGroup->mDocGroups.RemoveEntry(mKey);
 }
 
 NS_IMPL_ISUPPORTS(DocGroup, nsISupports)
 
-
 }
 }
--- a/dom/base/TabGroup.cpp
+++ b/dom/base/TabGroup.cpp
@@ -111,16 +111,30 @@ TabGroup::FindItemWithName(const nsAStri
         break;
       }
     }
   }
 
   return NS_OK;
 }
 
+nsTArray<nsPIDOMWindowOuter*>
+TabGroup::GetTopLevelWindows()
+{
+  nsTArray<nsPIDOMWindowOuter*> array;
+
+  for (nsPIDOMWindowOuter* outerWindow : mWindows) {
+    if (!outerWindow->GetScriptableParentOrNull()) {
+      array.AppendElement(outerWindow);
+    }
+  }
+
+  return array;
+}
+
 NS_IMPL_ISUPPORTS(TabGroup, nsISupports)
 
 TabGroup::HashEntry::HashEntry(const nsACString* aKey)
   : nsCStringHashKey(aKey), mDocGroup(nullptr)
 {}
 
 }
 }
--- a/dom/base/TabGroup.h
+++ b/dom/base/TabGroup.h
@@ -92,16 +92,18 @@ public:
   // It is illegal to pass in the special case-insensitive names "_blank",
   // "_self", "_parent" or "_top", as those should be handled elsewhere.
   nsresult
   FindItemWithName(const nsAString& aName,
                    nsIDocShellTreeItem* aRequestor,
                    nsIDocShellTreeItem* aOriginalRequestor,
                    nsIDocShellTreeItem** aFoundItem);
 
+  nsTArray<nsPIDOMWindowOuter*> GetTopLevelWindows();
+
 private:
   ~TabGroup();
   DocGroupMap mDocGroups;
   nsTArray<nsPIDOMWindowOuter*> mWindows;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -109,16 +109,17 @@
 #include "nsIChromeRegistry.h"
 #include "nsIConsoleService.h"
 #include "nsIContent.h"
 #include "nsIContentInlines.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIContentSink.h"
 #include "nsIContentViewer.h"
 #include "nsIDocShell.h"
+#include "nsIDocShellTreeOwner.h"
 #include "nsIDocument.h"
 #include "nsIDocumentEncoder.h"
 #include "nsIDOMChromeWindow.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentType.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMHTMLElement.h"
@@ -204,16 +205,18 @@
 #include "HTMLSplitOnSpacesTokenizer.h"
 #include "nsContentTypeParser.h"
 #include "nsICookiePermission.h"
 #include "mozIThirdPartyUtil.h"
 #include "nsICookieService.h"
 #include "mozilla/EnumSet.h"
 #include "mozilla/BloomFilter.h"
 #include "TabChild.h"
+#include "mozilla/dom/DocGroup.h"
+#include "mozilla/dom/TabGroup.h"
 
 #include "nsIBidiKeyboard.h"
 
 #if defined(XP_WIN)
 // Undefine LoadImage to prevent naming conflict with Windows.
 #undef LoadImage
 #endif
 
@@ -9628,8 +9631,145 @@ nsContentUtils::GetCustomPrototype(nsIDo
 
   RefPtr<CustomElementRegistry> registry(window->CustomElements());
   if (!registry) {
     return;
   }
 
   return registry->GetCustomPrototype(aAtom, aPrototype);
 }
+
+/* static */ bool
+nsContentUtils::AttemptLargeAllocationLoad(nsIHttpChannel* aChannel)
+{
+  MOZ_ASSERT(aChannel);
+
+  nsCOMPtr<nsILoadGroup> loadGroup;
+  nsresult rv = aChannel->GetLoadGroup(getter_AddRefs(loadGroup));
+  if (NS_WARN_IF(NS_FAILED(rv) || !loadGroup)) {
+    return false;
+  }
+
+  nsCOMPtr<nsIInterfaceRequestor> callbacks;
+  rv = loadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
+  if (NS_WARN_IF(NS_FAILED(rv) || !callbacks)) {
+    return false;
+  }
+
+  nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks);
+  if (NS_WARN_IF(!loadContext)) {
+    return false;
+  }
+
+  nsCOMPtr<mozIDOMWindowProxy> window;
+  rv = loadContext->GetAssociatedWindow(getter_AddRefs(window));
+  if (NS_WARN_IF(NS_FAILED(rv) || !window)) {
+    return false;
+  }
+
+  nsPIDOMWindowOuter* outer = nsPIDOMWindowOuter::From(window);
+  if (NS_WARN_IF(!outer)) {
+    return false;
+  }
+
+  nsIDocument* doc = outer->GetExtantDoc();
+
+  // If we aren't in the content process, we cannot perform a cross-process
+  // load, so abort right away
+  if (NS_WARN_IF(!XRE_IsContentProcess())) {
+    if (doc) {
+      nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
+                                      NS_LITERAL_CSTRING("DOM"),
+                                      doc,
+                                      nsContentUtils::eDOM_PROPERTIES,
+                                      "LargeAllocationNonE10S");
+    }
+    return false;
+  }
+
+  // Check if we are a toplevel window
+  if (NS_WARN_IF(outer->GetScriptableParentOrNull())) {
+    if (doc) {
+      nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
+                                      NS_LITERAL_CSTRING("DOM"),
+                                      doc,
+                                      nsContentUtils::eDOM_PROPERTIES,
+                                      "LargeAllocationInIFrame");
+    }
+    return false;
+  }
+
+  // If we have any other toplevel windows in our tab group, then we cannot
+  // perform the navigation.
+  TabGroup* tabGroup = nsGlobalWindow::Cast(outer)->TabGroup();
+  nsTArray<nsPIDOMWindowOuter*> toplevelWindows = tabGroup->GetTopLevelWindows();
+  if (NS_WARN_IF(toplevelWindows.Length() > 1)) {
+    if (doc) {
+      nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
+                                      NS_LITERAL_CSTRING("DOM"),
+                                      doc,
+                                      nsContentUtils::eDOM_PROPERTIES,
+                                      "LargeAllocationRelatedBrowsingContexts");
+    }
+    return false;
+  }
+  MOZ_ASSERT(toplevelWindows.Length() == 1);
+  MOZ_ASSERT(toplevelWindows[0] == outer);
+
+  // Get the request method, and check if it is a GET request. If it is not GET,
+  // then we cannot perform a large allocation load.
+  nsAutoCString requestMethod;
+  rv = aChannel->GetRequestMethod(requestMethod);
+  NS_ENSURE_SUCCESS(rv, false);
+
+  if (NS_WARN_IF(!requestMethod.LowerCaseEqualsLiteral("get"))) {
+    if (doc) {
+      nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
+                                      NS_LITERAL_CSTRING("DOM"),
+                                      doc,
+                                      nsContentUtils::eDOM_PROPERTIES,
+                                      "LargeAllocationNonGetRequest");
+    }
+    return false;
+  }
+
+  TabChild* tabChild = TabChild::GetFrom(outer);
+  NS_ENSURE_TRUE(tabChild, false);
+
+  if (tabChild->TakeIsFreshProcess())  {
+    NS_WARNING("Already in a fresh process, ignoring Large-Allocation header!");
+    if (doc) {
+      nsContentUtils::ReportToConsole(nsIScriptError::infoFlag,
+                                      NS_LITERAL_CSTRING("DOM"),
+                                      doc,
+                                      nsContentUtils::eDOM_PROPERTIES,
+                                      "LargeAllocationSuccess");
+    }
+    return false;
+  }
+
+  // At this point the fress process load should succeed! We just need to get
+  // ourselves a nsIWebBrowserChrome3 to ask to perform the reload. We should
+  // have one, as we have already confirmed that we are running in a content
+  // process.
+  nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
+  outer->GetDocShell()->GetTreeOwner(getter_AddRefs(treeOwner));
+  NS_ENSURE_TRUE(treeOwner, false);
+
+  nsCOMPtr<nsIWebBrowserChrome3> wbc3 = do_GetInterface(treeOwner);
+  NS_ENSURE_TRUE(wbc3, false);
+
+  nsCOMPtr<nsIURI> uri;
+  rv = aChannel->GetURI(getter_AddRefs(uri));
+  NS_ENSURE_SUCCESS(rv, false);
+  NS_ENSURE_TRUE(uri, false);
+
+  nsCOMPtr<nsIURI> referrer;
+  rv = aChannel->GetReferrer(getter_AddRefs(referrer));
+  NS_ENSURE_SUCCESS(rv, false);
+
+  // Actually perform the cross process load
+  bool reloadSucceeded = false;
+  rv = wbc3->ReloadInFreshProcess(outer->GetDocShell(), uri, referrer, &reloadSucceeded);
+  NS_ENSURE_SUCCESS(rv, false);
+
+  return reloadSucceeded;
+}
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2700,16 +2700,18 @@ public:
                                        mozilla::dom::LifecycleCallbackArgs* aArgs = nullptr,
                                        mozilla::dom::CustomElementDefinition* aDefinition = nullptr);
 
   static void GetCustomPrototype(nsIDocument* aDoc,
                                  int32_t aNamespaceID,
                                  nsIAtom* aAtom,
                                  JS::MutableHandle<JSObject*> prototype);
 
+  static bool AttemptLargeAllocationLoad(nsIHttpChannel* aChannel);
+
 private:
   static bool InitializeEventTable();
 
   static nsresult EnsureStringBundle(PropertiesFile aFile);
 
   static bool CanCallerAccess(nsIPrincipal* aSubjectPrincipal,
                                 nsIPrincipal* aPrincipal);
 
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -169,20 +169,27 @@ nsFrameLoader::nsFrameLoader(Element* aO
   , mHideCalled(false)
   , mNetworkCreated(aNetworkCreated)
   , mRemoteBrowserShown(false)
   , mRemoteFrame(false)
   , mClipSubdocument(true)
   , mClampScrollPosition(true)
   , mObservingOwnerContent(false)
   , mVisible(true)
+  , mFreshProcess(false)
 {
   mRemoteFrame = ShouldUseRemoteProcess();
   MOZ_ASSERT(!mRemoteFrame || !aOpener,
              "Cannot pass aOpener for a remote frame!");
+
+  // Check if we are supposed to load into a fresh process
+  mFreshProcess = mOwnerContent->AttrValueIs(kNameSpaceID_None,
+                                             nsGkAtoms::freshProcess,
+                                             nsGkAtoms::_true,
+                                             eCaseMatters);
 }
 
 nsFrameLoader::~nsFrameLoader()
 {
   if (mMessageManager) {
     mMessageManager->Disconnect();
   }
   MOZ_RELEASE_ASSERT(mDestroyCalled);
@@ -2722,17 +2729,18 @@ nsFrameLoader::TryRemoteBrowser()
   PROFILER_LABEL("nsFrameLoader", "CreateRemoteBrowser",
     js::ProfileEntry::Category::OTHER);
 
   MutableTabContext context;
   nsresult rv = GetNewTabContext(&context);
   NS_ENSURE_SUCCESS(rv, false);
 
   nsCOMPtr<Element> ownerElement = mOwnerContent;
-  mRemoteBrowser = ContentParent::CreateBrowserOrApp(context, ownerElement, openerContentParent);
+  mRemoteBrowser = ContentParent::CreateBrowserOrApp(context, ownerElement,
+                                                     openerContentParent, mFreshProcess);
   if (!mRemoteBrowser) {
     return false;
   }
 
   MaybeUpdatePrimaryTabParent(eTabParentChanged);
 
   mChildID = mRemoteBrowser->Manager()->ChildID();
 
--- a/dom/base/nsFrameLoader.h
+++ b/dom/base/nsFrameLoader.h
@@ -392,11 +392,12 @@ private:
   bool mClipSubdocument : 1;
   bool mClampScrollPosition : 1;
   bool mObservingOwnerContent : 1;
 
   // Backs nsIFrameLoader::{Get,Set}Visible.  Visibility state here relates to
   // whether this frameloader's <iframe mozbrowser> is setVisible(true)'ed, and
   // doesn't necessarily correlate with docshell/document visibility.
   bool mVisible : 1;
+  bool mFreshProcess : 1;
 };
 
 #endif
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -414,16 +414,17 @@ GK_ATOM(formnovalidate, "formnovalidate"
 GK_ATOM(formtarget, "formtarget")
 GK_ATOM(frame, "frame")
 GK_ATOM(frameborder, "frameborder")
 GK_ATOM(frameset, "frameset")
 GK_ATOM(from, "from")
 GK_ATOM(fullscreenchange, "fullscreenchange")
 GK_ATOM(fullscreenerror, "fullscreenerror")
 GK_ATOM(functionAvailable, "function-available")
+GK_ATOM(freshProcess, "freshProcess")
 GK_ATOM(generateId, "generate-id")
 GK_ATOM(getter, "getter")
 GK_ATOM(glyphchar, "glyphchar")
 GK_ATOM(glyphid, "glyphid")
 GK_ATOM(grid, "grid")
 GK_ATOM(grippy, "grippy")
 GK_ATOM(group, "group")
 GK_ATOM(groupingSeparator, "grouping-separator")
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -514,16 +514,17 @@ ContentParentsMemoryReporter::CollectRep
                             numQueuedMessages, desc, aData);
   }
 
   return NS_OK;
 }
 
 nsDataHashtable<nsStringHashKey, ContentParent*>* ContentParent::sAppContentParents;
 nsTArray<ContentParent*>* ContentParent::sNonAppContentParents;
+nsTArray<ContentParent*>* ContentParent::sLargeAllocationContentParents;
 nsTArray<ContentParent*>* ContentParent::sPrivateContent;
 StaticAutoPtr<LinkedList<ContentParent> > ContentParent::sContentParents;
 #if defined(XP_LINUX) && defined(MOZ_CONTENT_SANDBOX)
 UniquePtr<SandboxBrokerPolicyFactory> ContentParent::sSandboxBrokerPolicyFactory;
 #endif
 
 // This is true when subprocess launching is enabled.  This is the
 // case between StartUp() and ShutDown() or JoinAllSubprocesses().
@@ -743,58 +744,77 @@ ContentParent::JoinAllSubprocesses()
   }
 
   sCanLaunchSubprocesses = false;
 }
 
 /*static*/ already_AddRefed<ContentParent>
 ContentParent::GetNewOrUsedBrowserProcess(bool aForBrowserElement,
                                           ProcessPriority aPriority,
-                                          ContentParent* aOpener)
-{
-  if (!sNonAppContentParents)
-    sNonAppContentParents = new nsTArray<ContentParent*>();
-
-  int32_t maxContentProcesses = Preferences::GetInt("dom.ipc.processCount", 1);
-  if (maxContentProcesses < 1)
-    maxContentProcesses = 1;
-
-  if (sNonAppContentParents->Length() >= uint32_t(maxContentProcesses)) {
-    uint32_t startIdx = rand() % sNonAppContentParents->Length();
+                                          ContentParent* aOpener,
+                                          bool aFreshProcess)
+{
+  nsTArray<ContentParent*>* contentParents;
+  int32_t maxContentParents;
+
+  // Decide which pool of content parents we are going to be pulling from based
+  // on the aFreshProcess flag.
+  if (aFreshProcess) {
+    if (!sLargeAllocationContentParents) {
+      sLargeAllocationContentParents = new nsTArray<ContentParent*>();
+    }
+    contentParents = sLargeAllocationContentParents;
+
+    maxContentParents = Preferences::GetInt("dom.ipc.dedicatedProcessCount", 2);
+  } else {
+    if (!sNonAppContentParents) {
+      sNonAppContentParents = new nsTArray<ContentParent*>();
+    }
+    contentParents = sNonAppContentParents;
+
+    maxContentParents = Preferences::GetInt("dom.ipc.processCount", 1);
+  }
+
+  if (maxContentParents < 1) {
+    maxContentParents = 1;
+  }
+
+  if (contentParents->Length() >= uint32_t(maxContentParents)) {
+    uint32_t startIdx = rand() % contentParents->Length();
     uint32_t currIdx = startIdx;
     do {
-    RefPtr<ContentParent> p = (*sNonAppContentParents)[currIdx];
-    NS_ASSERTION(p->IsAlive(), "Non-alive contentparent in sNonAppContntParents?");
-    if (p->mOpener == aOpener) {
-      return p.forget();
-    }
-    currIdx = (currIdx + 1) % sNonAppContentParents->Length();
+      RefPtr<ContentParent> p = (*contentParents)[currIdx];
+      NS_ASSERTION(p->IsAlive(), "Non-alive contentparent in sNonAppContntParents?");
+      if (p->mOpener == aOpener) {
+        return p.forget();
+      }
+      currIdx = (currIdx + 1) % contentParents->Length();
     } while (currIdx != startIdx);
   }
 
   // Try to take and transform the preallocated process into browser.
   RefPtr<ContentParent> p = PreallocatedProcessManager::Take();
   if (p) {
     p->TransformPreallocatedIntoBrowser(aOpener);
   } else {
     // Failed in using the preallocated process: fork from the chrome process.
     p = new ContentParent(/* app = */ nullptr,
                           aOpener,
                           aForBrowserElement,
-                           /* isForPreallocated = */ false);
+                          /* isForPreallocated = */ false);
 
     if (!p->LaunchSubprocess(aPriority)) {
       return nullptr;
     }
 
     p->Init();
   }
   p->ForwardKnownInfo();
 
-  sNonAppContentParents->AppendElement(p);
+  contentParents->AppendElement(p);
   return p.forget();
 }
 
 /*static*/ ProcessPriority
 ContentParent::GetInitialProcessPriority(Element* aFrameElement)
 {
   // Frames with mozapptype == critical which are expecting a system message
   // get FOREGROUND_HIGH priority.
@@ -1043,17 +1063,18 @@ ContentParent::RecvInitVideoDecoderManag
 {
   GPUProcessManager::Get()->CreateContentVideoDecoderManager(OtherPid(), aEndpoint);
   return true;
 }
 
 /*static*/ TabParent*
 ContentParent::CreateBrowserOrApp(const TabContext& aContext,
                                   Element* aFrameElement,
-                                  ContentParent* aOpenerContentParent)
+                                  ContentParent* aOpenerContentParent,
+                                  bool aFreshProcess)
 {
   PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
 
   if (!sCanLaunchSubprocesses) {
     return nullptr;
   }
 
   if (TabParent* parent = TabParent::GetNextTabParent()) {
@@ -1078,17 +1099,19 @@ ContentParent::CreateBrowserOrApp(const 
       constructorSender = CreateContentBridgeParent(aContext, initialPriority,
                                                     openerTabId, &tabId);
     } else {
       if (aOpenerContentParent) {
         constructorSender = aOpenerContentParent;
       } else {
         constructorSender =
           GetNewOrUsedBrowserProcess(aContext.IsMozBrowserElement(),
-                                     initialPriority);
+                                     initialPriority,
+                                     nullptr,
+                                     aFreshProcess);
         if (!constructorSender) {
           return nullptr;
         }
       }
       tabId = AllocateTabId(openerTabId,
                             aContext.AsIPCTabContext(),
                             constructorSender->ChildID());
     }
@@ -1126,16 +1149,20 @@ ContentParent::CreateBrowserOrApp(const 
         // DeallocPBrowserParent() releases this ref.
         tp.forget().take(), tabId,
         aContext.AsIPCTabContext(),
         chromeFlags,
         constructorSender->ChildID(),
         constructorSender->IsForApp(),
         constructorSender->IsForBrowser());
 
+      if (aFreshProcess) {
+        Unused << browser->SendSetFreshProcess();
+      }
+
       if (browser) {
         RefPtr<TabParent> constructedTabParent = TabParent::GetFrom(browser);
         constructedTabParent->SetOwnerElement(aFrameElement);
         return constructedTabParent;
       }
     }
     return nullptr;
   }
@@ -1238,16 +1265,20 @@ ContentParent::CreateBrowserOrApp(const 
     RefPtr<TabParent>(tp).forget().take(),
     tabId,
     aContext.AsIPCTabContext(),
     chromeFlags,
     parent->ChildID(),
     parent->IsForApp(),
     parent->IsForBrowser());
 
+  if (aFreshProcess) {
+    Unused << browser->SendSetFreshProcess();
+  }
+
   if (browser) {
     RefPtr<TabParent> constructedTabParent = TabParent::GetFrom(browser);
     constructedTabParent->SetOwnerElement(aFrameElement);
   }
 
   if (isInContentProcess) {
     // Just return directly without the following check in content process.
     return TabParent::GetFrom(browser);
@@ -1599,21 +1630,31 @@ ContentParent::MarkAsDead()
   if (!mAppManifestURL.IsEmpty()) {
     if (sAppContentParents) {
       sAppContentParents->Remove(mAppManifestURL);
       if (!sAppContentParents->Count()) {
         delete sAppContentParents;
         sAppContentParents = nullptr;
       }
     }
-  } else if (sNonAppContentParents) {
-    sNonAppContentParents->RemoveElement(this);
-    if (!sNonAppContentParents->Length()) {
-      delete sNonAppContentParents;
-      sNonAppContentParents = nullptr;
+  } else {
+    if (sNonAppContentParents) {
+      sNonAppContentParents->RemoveElement(this);
+      if (!sNonAppContentParents->Length()) {
+        delete sNonAppContentParents;
+        sNonAppContentParents = nullptr;
+      }
+    }
+
+    if (sLargeAllocationContentParents) {
+      sLargeAllocationContentParents->RemoveElement(this);
+      if (!sLargeAllocationContentParents->Length()) {
+        delete sLargeAllocationContentParents;
+        sLargeAllocationContentParents = nullptr;
+      }
     }
   }
 
   if (sPrivateContent) {
     sPrivateContent->RemoveElement(this);
     if (!sPrivateContent->Length()) {
       delete sPrivateContent;
       sPrivateContent = nullptr;
@@ -2128,18 +2169,20 @@ ContentParent::~ContentParent()
     mForceKillTimer->Cancel();
   }
 
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   // We should be removed from all these lists in ActorDestroy.
   MOZ_ASSERT(!sPrivateContent || !sPrivateContent->Contains(this));
   if (mAppManifestURL.IsEmpty()) {
-    MOZ_ASSERT(!sNonAppContentParents ||
-               !sNonAppContentParents->Contains(this));
+    MOZ_ASSERT((!sNonAppContentParents ||
+                !sNonAppContentParents->Contains(this)) &&
+               (!sLargeAllocationContentParents ||
+                !sLargeAllocationContentParents->Contains(this)));
   } else {
     // In general, we expect sAppContentParents->Get(mAppManifestURL) to be
     // nullptr.  But it could be that we created another ContentParent for
     // this app after we did this->ActorDestroy(), so the right check is
     // that sAppContentParents->Get(mAppManifestURL) != this.
     MOZ_ASSERT(!sAppContentParents ||
                sAppContentParents->Get(mAppManifestURL) != this);
   }
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -130,32 +130,34 @@ public:
    * 1. browser iframe
    * 2. remote xul <browser>
    * 3. normal iframe
    */
   static already_AddRefed<ContentParent>
   GetNewOrUsedBrowserProcess(bool aForBrowserElement = false,
                              hal::ProcessPriority aPriority =
                              hal::ProcessPriority::PROCESS_PRIORITY_FOREGROUND,
-                             ContentParent* aOpener = nullptr);
+                             ContentParent* aOpener = nullptr,
+                             bool aFreshProcess = false);
 
   /**
    * Create a subprocess suitable for use as a preallocated app process.
    */
   static already_AddRefed<ContentParent> PreallocateAppProcess();
 
   /**
    * Get or create a content process for the given TabContext.  aFrameElement
    * should be the frame/iframe element with which this process will
    * associated.
    */
   static TabParent*
   CreateBrowserOrApp(const TabContext& aContext,
                      Element* aFrameElement,
-                     ContentParent* aOpenerContentParent);
+                     ContentParent* aOpenerContentParent,
+                     bool aFreshProcess = false);
 
   static void GetAll(nsTArray<ContentParent*>& aArray);
 
   static void GetAllEvenIfDead(nsTArray<ContentParent*>& aArray);
 
   enum CPIteratorPolicy {
     eLive,
     eAll
@@ -568,16 +570,17 @@ protected:
   bool ShouldContinueFromReplyTimeout() override;
 
   void OnVarChanged(const GfxVarUpdate& aVar) override;
   void OnCompositorUnexpectedShutdown() override;
 
 private:
   static nsDataHashtable<nsStringHashKey, ContentParent*> *sAppContentParents;
   static nsTArray<ContentParent*>* sNonAppContentParents;
+  static nsTArray<ContentParent*>* sLargeAllocationContentParents;
   static nsTArray<ContentParent*>* sPrivateContent;
   static StaticAutoPtr<LinkedList<ContentParent> > sContentParents;
 
   static void JoinProcessesIOThread(const nsTArray<ContentParent*>* aProcesses,
                                     Monitor* aMonitor, bool* aDone);
 
   // Take the preallocated process and transform it into a "real" app process,
   // for the specified manifest URL.  If there is no preallocated process (or
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -898,16 +898,22 @@ child:
                                             uint32_t aTargetLocalIndex);
 
     /**
      * Notify that the session history asssociates to this PBrowser has become
      * an inactive history in the grouped session history.
      */
     async NotifyPartialSessionHistoryDeactive();
 
+    /**
+     * Tell the child that it is a fresh process created for a Large-Allocation
+     * load.
+     */
+    async SetFreshProcess();
+
 /*
  * FIXME: write protocol!
 
 state LIVE:
     send LoadURL goto LIVE;
 //etc.
     send Destroy goto DYING;
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -114,16 +114,18 @@
 #include "nsDeviceContext.h"
 #include "nsSandboxFlags.h"
 #include "FrameLayerBuilder.h"
 #include "VRManagerChild.h"
 #include "nsICommandParams.h"
 #include "nsISHistory.h"
 #include "nsQueryObject.h"
 #include "GroupedSHistory.h"
+#include "nsIHttpChannel.h"
+#include "mozilla/dom/DocGroup.h"
 
 #ifdef NS_PRINTING
 #include "nsIPrintSession.h"
 #include "nsIPrintSettings.h"
 #include "nsIPrintSettingsService.h"
 #include "nsIWebBrowserPrint.h"
 #endif
 
@@ -550,16 +552,17 @@ TabChild::TabChild(nsIContentChild* aMan
   , mDPI(0)
   , mRounding(0)
   , mDefaultScale(0)
   , mIsTransparent(false)
   , mIPCOpen(false)
   , mParentIsActive(false)
   , mDidSetRealShowInfo(false)
   , mDidLoadURLInit(false)
+  , mIsFreshProcess(false)
   , mLayerObserverEpoch(0)
 #if defined(XP_WIN) && defined(ACCESSIBILITY)
   , mNativeWindowHandle(0)
 #endif
 {
   // In the general case having the TabParent tell us if APZ is enabled or not
   // doesn't really work because the TabParent itself may not have a reference
   // to the owning widget during initialization. Instead we assume that this
@@ -3334,16 +3337,23 @@ TabChild::RecvThemeChanged(nsTArray<Look
     RefPtr<nsPresContext> presContext = presShell->GetPresContext();
     if (presContext) {
       presContext->ThemeChanged();
     }
   }
   return true;
 }
 
+bool
+TabChild::RecvSetFreshProcess()
+{
+  mIsFreshProcess = true;
+  return true;
+}
+
 mozilla::plugins::PPluginWidgetChild*
 TabChild::AllocPPluginWidgetChild()
 {
     return new mozilla::plugins::PluginWidgetChild();
 }
 
 bool
 TabChild::DeallocPPluginWidgetChild(mozilla::plugins::PPluginWidgetChild* aActor)
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -38,16 +38,17 @@
 #include "AudioChannelService.h"
 #include "PuppetWidget.h"
 #include "mozilla/layers/GeckoContentController.h"
 #include "nsISHistoryListener.h"
 #include "nsIPartialSHistoryListener.h"
 
 class nsICachedFileDescriptorListener;
 class nsIDOMWindowUtils;
+class nsIHttpChannel;
 
 namespace mozilla {
 namespace layout {
 class RenderFrameChild;
 } // namespace layout
 
 namespace layers {
 class APZChild;
@@ -670,16 +671,23 @@ public:
 
   // Request that the docshell be marked as active.
   void ForcePaint(uint64_t aLayerObserverEpoch);
 
 #if defined(XP_WIN) && defined(ACCESSIBILITY)
   uintptr_t GetNativeWindowHandle() const { return mNativeWindowHandle; }
 #endif
 
+  bool TakeIsFreshProcess()
+  {
+    bool wasFreshProcess = mIsFreshProcess;
+    mIsFreshProcess = false;
+    return wasFreshProcess;
+  }
+
 protected:
   virtual ~TabChild();
 
   virtual PRenderFrameChild* AllocPRenderFrameChild() override;
 
   virtual bool DeallocPRenderFrameChild(PRenderFrameChild* aFrame) override;
 
   virtual bool RecvDestroy() override;
@@ -707,16 +715,18 @@ protected:
 
   virtual bool RecvNotifyAttachGroupedSessionHistory(const uint32_t& aOffset) override;
 
   virtual bool RecvNotifyPartialSessionHistoryActive(const uint32_t& aGlobalLength,
                                                      const uint32_t& aTargetLocalIndex) override;
 
   virtual bool RecvNotifyPartialSessionHistoryDeactive() override;
 
+  virtual bool RecvSetFreshProcess() override;
+
 private:
   void HandleDoubleTap(const CSSPoint& aPoint, const Modifiers& aModifiers,
                        const ScrollableLayerGuid& aGuid);
 
   // Notify others that our TabContext has been updated.
   //
   // You should call this after calling TabContext::SetTabContext().  We also
   // call this during Init().
@@ -799,16 +809,17 @@ private:
   bool mIsTransparent;
 
   bool mIPCOpen;
   bool mParentIsActive;
   bool mAsyncPanZoomEnabled;
   CSSSize mUnscaledInnerSize;
   bool mDidSetRealShowInfo;
   bool mDidLoadURLInit;
+  bool mIsFreshProcess;
 
   AutoTArray<bool, NUMBER_OF_AUDIO_CHANNELS> mAudioChannelsActive;
 
   RefPtr<layers::IAPZCTreeManager> mApzcTreeManager;
   // APZChild clears this pointer from its destructor, so it shouldn't be a
   // dangling pointer.
   layers::APZChild* mAPZChild;
 
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -305,8 +305,18 @@ BiquadFilterChannelCountChangeWarning=Bi
 UnanimatablePacedProperty=Paced property ā€˜%1$Sā€™ is not an animatable property.
 # LOCALIZATION NOTE: Do not translate ".jpeg"
 GenericImageNameJPEG=image.jpeg
 # LOCALIZATION NOTE: Do not translate ".gif"
 GenericImageNameGIF=image.gif
 # LOCALIZATION NOTE: Do not translate ".png"
 GenericImageNamePNG=image.png
 GenericFileName=file
+# LOCALIZATION NOTE: Do not translate "Large-Allocation", as it is a literal header name
+LargeAllocationSuccess=This page was loaded in a new process due to a Large-Allocation header.
+# LOCALIZATION NOTE: Do not translate "Large-Allocation", as it is a literal header name. Do not translate GET.
+LargeAllocationNonGetRequest=A Large-Allocation header was ignored due to the load being triggered by a non-GET request.
+# LOCALIZATION NOTE: Do not translate "Large-Allocation", as it is a literal header name
+LargeAllocationRelatedBrowsingContexts=A Large-Allocation header was ignored due to the presence of windows which have a reference to this browsing context.
+# LOCALIZATION NOTE: Do not translate "Large-Allocation", as it is a literal header name
+LargeAllocationInIFrame=A Large-Allocation header was ignored due to the load occuring within an iframe.
+# LOCALIZATION NOTE: Do not translate "Large-Allocation", as it is a literal header name
+LargeAllocationNonE10S=A Large-Allocation header was ignored due to the document not being loaded out of process.
--- a/embedding/browser/nsIWebBrowserChrome3.idl
+++ b/embedding/browser/nsIWebBrowserChrome3.idl
@@ -42,9 +42,20 @@ interface nsIWebBrowserChrome3 : nsIWebB
    * @param aURI
    *        The URI being loaded.
    * @param aReferrer
    *        The referrer of the load.
    */
   bool shouldLoadURI(in nsIDocShell    aDocShell,
                      in nsIURI         aURI,
                      in nsIURI         aReferrer);
+
+  /**
+   * Attempts to load the currently loaded page into a fresh process to increase
+   * available memory.
+   *
+   * @param aDocShell
+   *        The docshell performing the load.
+   */
+  bool reloadInFreshProcess(in nsIDocShell aDocShell,
+                            in nsIURI aURI,
+                            in nsIURI aReferrer);
 };
--- a/uriloader/base/moz.build
+++ b/uriloader/base/moz.build
@@ -1,14 +1,16 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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('/ipc/chromium/chromium-config.mozbuild')
+
 XPIDL_SOURCES += [
     'nsCURILoader.idl',
     'nsIContentHandler.idl',
     'nsIDocumentLoader.idl',
     'nsITransfer.idl',
     'nsIURIContentListener.idl',
     'nsIURILoader.idl',
     'nsIWebProgress.idl',
--- a/uriloader/base/nsURILoader.cpp
+++ b/uriloader/base/nsURILoader.cpp
@@ -44,16 +44,17 @@
 #include "nsIMIMEHeaderParam.h"
 #include "nsNetCID.h"
 
 #include "nsMimeTypes.h"
 
 #include "nsDocLoader.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Preferences.h"
+#include "nsContentUtils.h"
 
 mozilla::LazyLogModule nsURILoader::mLog("URILoader");
 
 #define LOG(args) MOZ_LOG(nsURILoader::mLog, mozilla::LogLevel::Debug, args)
 #define LOG_ERROR(args) MOZ_LOG(nsURILoader::mLog, mozilla::LogLevel::Error, args)
 #define LOG_ENABLED() MOZ_LOG_TEST(nsURILoader::mLog, mozilla::LogLevel::Debug)
 
 #define NS_PREF_DISABLE_BACKGROUND_HANDLING \
@@ -229,16 +230,33 @@ NS_IMETHODIMP nsDocumentOpenInfo::OnStar
       return NS_OK;
     }
 
     LOG(("  HTTP response status: %d", responseCode));
 
     if (204 == responseCode || 205 == responseCode) {
       return NS_BINDING_ABORTED;
     }
+
+    static bool sLargeAllocationHeaderEnabled = false;
+    static bool sCachedLargeAllocationPref = false;
+    if (!sCachedLargeAllocationPref) {
+      sCachedLargeAllocationPref = true;
+      mozilla::Preferences::AddBoolVarCache(&sLargeAllocationHeaderEnabled,
+                                            "dom.largeAllocationHeader.enabled");
+    }
+
+    if (sLargeAllocationHeaderEnabled) {
+      // If we have a Large-Allocation header, let's check if we should perform a process switch.
+      nsAutoCString largeAllocationHeader;
+      rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Large-Allocation"), largeAllocationHeader);
+      if (NS_SUCCEEDED(rv) && nsContentUtils::AttemptLargeAllocationLoad(httpChannel)) {
+        return NS_BINDING_ABORTED;
+      }
+    }
   }
 
   //
   // Make sure that the transaction has succeeded, so far...
   //
   nsresult status;
 
   rv = request->GetStatus(&status);
--- a/xpfe/appshell/nsContentTreeOwner.cpp
+++ b/xpfe/appshell/nsContentTreeOwner.cpp
@@ -399,16 +399,26 @@ NS_IMETHODIMP nsContentTreeOwner::Should
 
   if (xulBrowserWindow)
     return xulBrowserWindow->ShouldLoadURI(aDocShell, aURI, aReferrer, _retval);
 
   *_retval = true;
   return NS_OK;
 }
 
+NS_IMETHODIMP nsContentTreeOwner::ReloadInFreshProcess(nsIDocShell* aDocShell,
+                                                       nsIURI* aURI,
+                                                       nsIURI* aReferrer,
+                                                       bool* aRetVal)
+{
+  NS_WARNING("Cannot reload in fresh process from a nsContentTreeOwner!");
+  *aRetVal = false;
+  return NS_OK;
+}
+
 //*****************************************************************************
 // nsContentTreeOwner::nsIWebBrowserChrome2
 //*****************************************************************************   
 
 NS_IMETHODIMP nsContentTreeOwner::SetStatusWithContext(uint32_t aStatusType,
                                                        const nsAString &aStatusText,
                                                        nsISupports *aStatusContext)
 {