Bug 802895 - Docshell related changes for srcdoc iframe r=bz
authorJames Kitchener <jkitch.bug@gmail.com>
Fri, 28 Jun 2013 23:13:22 -0400
changeset 136883 3758ba469a3a30af09a1cf31a17eb0d45c2544ee
parent 136882 da373b72ad88f3d02bf40ed1b59048edec37a72c
child 136884 3330a8c136b678d47de24609d5211f9bb090118c
push id30317
push userbzbarsky@mozilla.com
push dateSat, 29 Jun 2013 03:13:46 +0000
treeherdermozilla-inbound@f3c22357f4f7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs802895
milestone25.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 802895 - Docshell related changes for srcdoc iframe r=bz
content/base/src/nsContentUtils.cpp
docshell/base/Makefile.in
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
docshell/base/nsDocShellLoadInfo.cpp
docshell/base/nsDocShellLoadInfo.h
docshell/base/nsIDocShell.idl
docshell/base/nsIDocShellLoadInfo.idl
docshell/shistory/public/nsISHEntry.idl
docshell/shistory/src/nsSHEntry.cpp
docshell/shistory/src/nsSHEntry.h
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -6095,21 +6095,27 @@ nsContentUtils::SetUpChannelOwner(nsIPri
   bool inherit;
   // We expect URIInheritsSecurityContext to return success for an
   // about:blank URI, so don't call NS_IsAboutBlank() if this call fails.
   // This condition needs to match the one in nsDocShell::InternalLoad where
   // we're checking for things that will use the owner.
   if (aForceOwner || ((NS_SUCCEEDED(URIInheritsSecurityContext(aURI, &inherit)) &&
       (inherit || (aSetUpForAboutBlank && NS_IsAboutBlank(aURI)))))) {
 #ifdef DEBUG
-    // Assert that aForceOwner is only set for null principals
+    // Assert that aForceOwner is only set for null principals for non-srcdoc
+    // loads.  (Strictly speaking not all uses of about:srcdoc would be 
+    // srcdoc loads, but the URI is non-resolvable in cases where it is not).
     if (aForceOwner) {
-      nsCOMPtr<nsIURI> ownerURI;
-      nsresult rv = aLoadingPrincipal->GetURI(getter_AddRefs(ownerURI));
-      MOZ_ASSERT(NS_SUCCEEDED(rv) && SchemeIs(ownerURI, NS_NULLPRINCIPAL_SCHEME));
+      nsAutoCString uriStr;
+      aURI->GetSpec(uriStr);
+      if(!uriStr.EqualsLiteral("about:srcdoc")) {
+        nsCOMPtr<nsIURI> ownerURI;
+        nsresult rv = aLoadingPrincipal->GetURI(getter_AddRefs(ownerURI));
+        MOZ_ASSERT(NS_SUCCEEDED(rv) && SchemeIs(ownerURI, NS_NULLPRINCIPAL_SCHEME));
+      }
     }
 #endif
     aChannel->SetOwner(aLoadingPrincipal);
     return true;
   }
 
   //
   // file: uri special-casing
--- a/docshell/base/Makefile.in
+++ b/docshell/base/Makefile.in
@@ -30,9 +30,10 @@ include $(topsrcdir)/config/rules.mk
 LOCAL_INCLUDES += \
   -I$(srcdir)/../shistory/src \
   -I$(topsrcdir)/dom/base \
   -I$(topsrcdir)/layout/base \
   -I$(topsrcdir)/xpcom/ds \
   -I$(topsrcdir)/layout/generic \
   -I$(topsrcdir)/layout/xul/base/src \
   -I$(topsrcdir)/content/base/src \
+  -I$(topsrcdir)/netwerk/protocol/viewsource \
   $(NULL)
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -84,16 +84,17 @@
 #include "nsITimedChannel.h"
 #include "nsIPrivacyTransitionObserver.h"
 #include "nsIReflowObserver.h"
 #include "nsCPrefetchService.h"
 #include "nsJSON.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIChannel.h"
 #include "IHistory.h"
+#include "nsViewSourceHandler.h"
 
 // we want to explore making the document own the load group
 // so we can associate the document URI with the load group.
 // until this point, we have an evil hack:
 #include "nsIHttpChannelInternal.h"  
 #include "nsPILoadGroupInternal.h"
 
 // Local Includes
@@ -1255,18 +1256,21 @@ nsDocShell::LoadURI(nsIURI * aURI,
     nsresult rv;
     nsCOMPtr<nsIURI> referrer;
     nsCOMPtr<nsIInputStream> postStream;
     nsCOMPtr<nsIInputStream> headersStream;
     nsCOMPtr<nsISupports> owner;
     bool inheritOwner = false;
     bool ownerIsExplicit = false;
     bool sendReferrer = true;
+    bool isSrcdoc = false;
     nsCOMPtr<nsISHEntry> shEntry;
     nsXPIDLString target;
+    nsAutoString srcdoc;
+
     uint32_t loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);    
 
     NS_ENSURE_ARG(aURI);
 
     if (!StartupTimeline::HasRecord(StartupTimeline::FIRST_LOAD_URI) &&
         mItemType == typeContent && !NS_IsAboutBlank(aURI)) {
         StartupTimeline::RecordOnce(StartupTimeline::FIRST_LOAD_URI);
     }
@@ -1283,16 +1287,18 @@ nsDocShell::LoadURI(nsIURI * aURI,
         aLoadInfo->GetOwner(getter_AddRefs(owner));
         aLoadInfo->GetInheritOwner(&inheritOwner);
         aLoadInfo->GetOwnerIsExplicit(&ownerIsExplicit);
         aLoadInfo->GetSHEntry(getter_AddRefs(shEntry));
         aLoadInfo->GetTarget(getter_Copies(target));
         aLoadInfo->GetPostDataStream(getter_AddRefs(postStream));
         aLoadInfo->GetHeadersStream(getter_AddRefs(headersStream));
         aLoadInfo->GetSendReferrer(&sendReferrer);
+        aLoadInfo->GetIsSrcdocLoad(&isSrcdoc);
+        aLoadInfo->GetSrcdocData(srcdoc);
     }
 
 #if defined(PR_LOGGING) && defined(DEBUG)
     if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
         nsAutoCString uristr;
         aURI->GetAsciiSpec(uristr);
         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
                ("nsDocShell[%p]: loading %s with flags 0x%08x",
@@ -1503,28 +1509,32 @@ nsDocShell::LoadURI(nsIURI * aURI,
         flags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
 
     if (aLoadFlags & LOAD_FLAGS_BYPASS_CLASSIFIER)
         flags |= INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER;
 
     if (aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_COOKIES)
         flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES;
 
+    if (isSrcdoc)
+        flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
+
     return InternalLoad(aURI,
                         referrer,
                         owner,
                         flags,
                         target.get(),
                         nullptr,         // No type hint
                         NullString(),    // No forced download
                         postStream,
                         headersStream,
                         loadType,
                         nullptr,         // No SHEntry
                         aFirstParty,
+                        srcdoc,
                         nullptr,         // No nsIDocShell
                         nullptr);        // No nsIRequest
 }
 
 NS_IMETHODIMP
 nsDocShell::LoadStream(nsIInputStream *aStream, nsIURI * aURI,
                        const nsACString &aContentType,
                        const nsACString &aContentCharset,
@@ -4562,17 +4572,17 @@ nsDocShell::LoadErrorPage(nsIURI *aURI, 
 
     nsCOMPtr<nsIURI> errorPageURI;
     nsresult rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return InternalLoad(errorPageURI, nullptr, nullptr,
                         INTERNAL_LOAD_FLAGS_INHERIT_OWNER, nullptr, nullptr,
                         NullString(), nullptr, nullptr, LOAD_ERROR_PAGE,
-                        nullptr, true, nullptr, nullptr);
+                        nullptr, true, NullString(), nullptr,nullptr);
 }
 
 
 NS_IMETHODIMP
 nsDocShell::Reload(uint32_t aReloadFlags)
 {
     if (!IsNavigationAllowed()) {
       return NS_OK; // JS may not handle returning of an error code
@@ -4603,35 +4613,43 @@ nsDocShell::Reload(uint32_t aReloadFlags
         rv = LoadHistoryEntry(mOSHE, loadType);
     }
     else if (mLSHE) { // In case a reload happened before the current load is done
         rv = LoadHistoryEntry(mLSHE, loadType);
     }
     else {
         nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this)));
 
+        // Do not inherit owner from document
+        uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
+        nsAutoString srcdoc;
         nsIPrincipal* principal = nullptr;
         nsAutoString contentTypeHint;
         if (doc) {
             principal = doc->NodePrincipal();
             doc->GetContentType(contentTypeHint);
-        }
-
+
+            if (doc->IsSrcdocDocument()) {
+                doc->GetSrcdocData(srcdoc);
+                flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
+            }
+        }
         rv = InternalLoad(mCurrentURI,
                           mReferrerURI,
                           principal,
-                          INTERNAL_LOAD_FLAGS_NONE, // Do not inherit owner from document
+                          flags,
                           nullptr,         // No window target
                           NS_LossyConvertUTF16toASCII(contentTypeHint).get(),
                           NullString(),    // No forced download
                           nullptr,         // No post data
                           nullptr,         // No headers data
                           loadType,        // Load type
                           nullptr,         // No SHEntry
                           true,
+                          srcdoc,          // srcdoc argument for iframe
                           nullptr,         // No nsIDocShell
                           nullptr);        // No nsIRequest
     }
 
     return rv;
 }
 
 NS_IMETHODIMP
@@ -8462,17 +8480,19 @@ void CopyFavicon(nsIURI *aOldURI, nsIURI
 
 class InternalLoadEvent : public nsRunnable
 {
 public:
     InternalLoadEvent(nsDocShell* aDocShell, nsIURI * aURI, nsIURI * aReferrer,
                       nsISupports * aOwner, uint32_t aFlags,
                       const char* aTypeHint, nsIInputStream * aPostData,
                       nsIInputStream * aHeadersData, uint32_t aLoadType,
-                      nsISHEntry * aSHEntry, bool aFirstParty) :
+                      nsISHEntry * aSHEntry, bool aFirstParty,
+                      const nsAString &aSrcdoc) :
+        mSrcdoc(aSrcdoc),
         mDocShell(aDocShell),
         mURI(aURI),
         mReferrer(aReferrer),
         mOwner(aOwner),
         mPostData(aPostData),
         mHeadersData(aHeadersData),
         mSHEntry(aSHEntry),
         mFlags(aFlags),
@@ -8485,24 +8505,25 @@ public:
         }
     }
 
     NS_IMETHOD Run() {
         return mDocShell->InternalLoad(mURI, mReferrer, mOwner, mFlags,
                                        nullptr, mTypeHint.get(),
                                        NullString(), mPostData, mHeadersData,
                                        mLoadType, mSHEntry, mFirstParty,
-                                       nullptr, nullptr);
+                                       mSrcdoc, nullptr, nullptr);
     }
 
 private:
 
     // Use IDL strings so .get() returns null by default
     nsXPIDLString mWindowTarget;
     nsXPIDLCString mTypeHint;
+    nsString mSrcdoc;
 
     nsRefPtr<nsDocShell> mDocShell;
     nsCOMPtr<nsIURI> mURI;
     nsCOMPtr<nsIURI> mReferrer;
     nsCOMPtr<nsISupports> mOwner;
     nsCOMPtr<nsIInputStream> mPostData;
     nsCOMPtr<nsIInputStream> mHeadersData;
     nsCOMPtr<nsISHEntry> mSHEntry;
@@ -8536,16 +8557,17 @@ nsDocShell::InternalLoad(nsIURI * aURI,
                          const PRUnichar *aWindowTarget,
                          const char* aTypeHint,
                          const nsAString& aFileName,
                          nsIInputStream * aPostData,
                          nsIInputStream * aHeadersData,
                          uint32_t aLoadType,
                          nsISHEntry * aSHEntry,
                          bool aFirstParty,
+                         const nsAString &aSrcdoc,
                          nsIDocShell** aDocShell,
                          nsIRequest** aRequest)
 {
     nsresult rv = NS_OK;
     mOriginalUriString.Truncate();
 
 #ifdef PR_LOGGING
     if (gDocShellLeakLog && PR_LOG_TEST(gDocShellLeakLog, PR_LOG_DEBUG)) {
@@ -8774,16 +8796,17 @@ nsDocShell::InternalLoad(nsIURI * aURI,
                                               nullptr,         // No window target
                                               aTypeHint,
                                               NullString(),    // No forced download
                                               aPostData,
                                               aHeadersData,
                                               aLoadType,
                                               aSHEntry,
                                               aFirstParty,
+                                              aSrcdoc,
                                               aDocShell,
                                               aRequest);
             if (rv == NS_ERROR_NO_CONTENT) {
                 // XXXbz except we never reach this code!
                 if (isNewWindow) {
                     //
                     // At this point, a new window has been created, but the
                     // URI did not have any data associated with it...
@@ -8855,17 +8878,17 @@ nsDocShell::InternalLoad(nsIURI * aURI,
             if (LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {
                 mLoadType = LOAD_NORMAL_REPLACE;
             }
             
             // Do this asynchronously
             nsCOMPtr<nsIRunnable> ev =
                 new InternalLoadEvent(this, aURI, aReferrer, aOwner, aFlags,
                                       aTypeHint, aPostData, aHeadersData,
-                                      aLoadType, aSHEntry, aFirstParty);
+                                      aLoadType, aSHEntry, aFirstParty, aSrcdoc);
             return NS_DispatchToCurrentThread(ev);
         }
 
         // Just ignore this load attempt
         return NS_OK;
     }
 
     // Before going any further vet loads initiated by external programs.
@@ -9262,24 +9285,31 @@ nsDocShell::InternalLoad(nsIURI * aURI,
         if (NS_FAILED(rv)) {
             if (oldEntry)
                 oldEntry->SyncPresentationState();
 
             aSHEntry->SyncPresentationState();
         }
     }
 
+    nsAutoString srcdoc;
+    if (aFlags & INTERNAL_LOAD_FLAGS_IS_SRCDOC)
+      srcdoc = aSrcdoc;
+    else
+      srcdoc = NullString();
+
     nsCOMPtr<nsIRequest> req;
     rv = DoURILoad(aURI, aReferrer,
                    !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER),
                    owner, aTypeHint, aFileName, aPostData, aHeadersData,
                    aFirstParty, aDocShell, getter_AddRefs(req),
                    (aFlags & INTERNAL_LOAD_FLAGS_FIRST_LOAD) != 0,
                    (aFlags & INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER) != 0,
-                   (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES) != 0);
+                   (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES) != 0,
+                   srcdoc);
     if (req && aRequest)
         NS_ADDREF(*aRequest = req);
 
     if (NS_FAILED(rv)) {
         nsCOMPtr<nsIChannel> chan(do_QueryInterface(req));
         DisplayLoadError(rv, aURI, nullptr, chan);
     }
 
@@ -9347,17 +9377,18 @@ nsDocShell::DoURILoad(nsIURI * aURI,
                       const nsAString & aFileName,
                       nsIInputStream * aPostData,
                       nsIInputStream * aHeadersData,
                       bool aFirstParty,
                       nsIDocShell ** aDocShell,
                       nsIRequest ** aRequest,
                       bool aIsNewWindowTarget,
                       bool aBypassClassifier,
-                      bool aForceAllowCookies)
+                      bool aForceAllowCookies,
+                      const nsAString &aSrcdoc)
 {
 #ifdef MOZ_VISUAL_EVENT_TRACER
     nsAutoCString urlSpec;
     aURI->GetAsciiSpec(urlSpec);
     MOZ_EVENT_TRACER_NAME_OBJECT(this, urlSpec.BeginReading());
     MOZ_EVENT_TRACER_EXEC(this, "docshell::pageload");
 #endif
 
@@ -9396,38 +9427,62 @@ nsDocShell::DoURILoad(nsIURI * aURI,
                 channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SUBDOCUMENT);
             }
         }
     }
 
     // open a channel for the url
     nsCOMPtr<nsIChannel> channel;
 
-    rv = NS_NewChannel(getter_AddRefs(channel),
-                       aURI,
-                       nullptr,
-                       nullptr,
-                       static_cast<nsIInterfaceRequestor *>(this),
-                       loadFlags,
-                       channelPolicy);
-    if (NS_FAILED(rv)) {
-        if (rv == NS_ERROR_UNKNOWN_PROTOCOL) {
-            // This is a uri with a protocol scheme we don't know how
-            // to handle.  Embedders might still be interested in
-            // handling the load, though, so we fire a notification
-            // before throwing the load away.
-            bool abort = false;
-            nsresult rv2 = mContentListener->OnStartURIOpen(aURI, &abort);
-            if (NS_SUCCEEDED(rv2) && abort) {
-                // Hey, they're handling the load for us!  How convenient!
-                return NS_OK;
+    bool isSrcdoc = !aSrcdoc.IsVoid();
+    if (!isSrcdoc) {
+        rv = NS_NewChannel(getter_AddRefs(channel),
+                           aURI,
+                           nullptr,
+                           nullptr,
+                           static_cast<nsIInterfaceRequestor *>(this),
+                           loadFlags,
+                           channelPolicy);
+        if (NS_FAILED(rv)) {
+            if (rv == NS_ERROR_UNKNOWN_PROTOCOL) {
+                // This is a uri with a protocol scheme we don't know how
+                // to handle.  Embedders might still be interested in
+                // handling the load, though, so we fire a notification
+                // before throwing the load away.
+                bool abort = false;
+                nsresult rv2 = mContentListener->OnStartURIOpen(aURI, &abort);
+                if (NS_SUCCEEDED(rv2) && abort) {
+                    // Hey, they're handling the load for us!  How convenient!
+                    return NS_OK;
+                }
             }
-        }
-            
-        return rv;
+            return rv;
+        }
+    }
+    else {
+        nsAutoCString scheme;
+        rv = aURI->GetScheme(scheme);
+        NS_ENSURE_SUCCESS(rv,rv);
+        bool isViewSource;
+        aURI->SchemeIs("view-source",&isViewSource);
+
+        if (isViewSource) {
+            nsViewSourceHandler *vsh = nsViewSourceHandler::GetInstance();
+            NS_ENSURE_TRUE(vsh,NS_ERROR_FAILURE);
+
+            rv = vsh->NewSrcdocChannel(aURI, aSrcdoc,getter_AddRefs(channel));
+            NS_ENSURE_SUCCESS(rv, rv);
+        }
+        else {
+            rv = NS_NewInputStreamChannel(getter_AddRefs(channel),aURI,
+                                          aSrcdoc,
+                                          NS_LITERAL_CSTRING("text/html"),
+                                          true);
+            NS_ENSURE_SUCCESS(rv, rv);
+        }
     }
 
     nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
         do_QueryInterface(channel);
     if (appCacheChannel) {
         // Any document load should not inherit application cache.
         appCacheChannel->SetInheritApplicationCache(false);
 
@@ -9575,17 +9630,18 @@ nsDocShell::DoURILoad(nsIURI * aURI,
     if (mSandboxFlags & SANDBOXED_ORIGIN) {
         ownerPrincipal = do_CreateInstance("@mozilla.org/nullprincipal;1");
     } else {
         // Not sandboxed - we allow the content to assume its natural owner.
         ownerPrincipal = do_QueryInterface(aOwner);
     }
 
     nsContentUtils::SetUpChannelOwner(ownerPrincipal, channel, aURI, true,
-                                      (mSandboxFlags & SANDBOXED_ORIGIN));
+                                      (mSandboxFlags & SANDBOXED_ORIGIN) ||
+                                      isSrcdoc);
 
     nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(channel);
     if (scriptChannel) {
         // Allow execution against our context if the principals match
         scriptChannel->
             SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
     }
 
@@ -10633,16 +10689,26 @@ nsDocShell::AddToSessionHistory(nsIURI *
                   inputStream,       // Post data stream
                   nullptr,            // LayoutHistory state
                   cacheKey,          // CacheKey
                   mContentTypeHint,  // Content-type
                   owner,             // Channel or provided owner
                   mHistoryID,
                   mDynamicallyCreated);
     entry->SetReferrerURI(referrerURI);
+    nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(aChannel);
+    if (inStrmChan) {
+        bool isSrcdocChannel;
+        inStrmChan->GetIsSrcdocChannel(&isSrcdocChannel);
+        if (isSrcdocChannel) {
+            nsAutoString srcdoc;
+            inStrmChan->GetSrcdocData(srcdoc);
+            entry->SetSrcdocData(srcdoc);
+        }
+    }
     /* If cache got a 'no-store', ask SH not to store
      * HistoryLayoutState. By default, SH will set this
      * flag to true and save HistoryLayoutState.
      */    
     if (discardLayoutState) {
         entry->SetSaveLayoutStateFlag(false);
     }
     if (cacheChannel) {
@@ -10779,28 +10845,43 @@ nsDocShell::LoadHistoryEntry(nsISHEntry 
       rv = ConfirmRepost(&repost);
       if (NS_FAILED(rv)) return rv;
 
       // If the user pressed cancel in the dialog, return.  We're done here.
       if (!repost)
         return NS_BINDING_ABORTED;
     }
 
+    // Do not inherit owner from document (security-critical!);
+    uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
+
+    nsAutoString srcdoc;
+    bool isSrcdoc;
+    aEntry->GetIsSrcdocEntry(&isSrcdoc);
+    if (isSrcdoc) {
+        aEntry->GetSrcdocData(srcdoc);
+        flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
+    }
+    else {
+        srcdoc = NullString();
+    }
+
     rv = InternalLoad(uri,
                       referrerURI,
                       owner,
-                      INTERNAL_LOAD_FLAGS_NONE, // Do not inherit owner from document (security-critical!)
+                      flags,
                       nullptr,            // No window target
                       contentType.get(),  // Type hint
                       NullString(),       // No forced file download
                       postData,           // Post data stream
                       nullptr,            // No headers stream
                       aLoadType,          // Load type
                       aEntry,             // SHEntry
                       true,
+                      srcdoc,
                       nullptr,            // No nsIDocShell
                       nullptr);           // No nsIRequest
     return rv;
 }
 
 NS_IMETHODIMP nsDocShell::GetShouldSaveLayoutState(bool* aShould)
 {
     *aShould = false;
@@ -12230,16 +12311,17 @@ nsDocShell::OnLinkClickSync(nsIContent *
                              target.get(),              // Window target
                              NS_LossyConvertUTF16toASCII(typeHint).get(),
                              aFileName,                 // Download as file
                              aPostDataStream,           // Post data stream
                              aHeadersDataStream,        // Headers stream
                              LOAD_LINK,                 // Load type
                              nullptr,                   // No SHEntry
                              true,                      // first party site
+                             NullString(),              // No srcdoc
                              aDocShell,                 // DocShell out-param
                              aRequest);                 // Request out-param
   if (NS_SUCCEEDED(rv)) {
     DispatchPings(aContent, referer);
   }
   return rv;
 }
 
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -284,30 +284,33 @@ protected:
     // If that fails too, we force creation of a content viewer and use the
     // resulting principal.  If aConsiderCurrentDocument is false, we just look
     // at the parent.
     nsIPrincipal* GetInheritedPrincipal(bool aConsiderCurrentDocument);
 
     // Actually open a channel and perform a URI load.  Note: whatever owner is
     // passed to this function will be set on the channel.  Callers who wish to
     // not have an owner on the channel should just pass null.
+    // If aSrcdoc is not void, the load will be considered as a srcdoc load,
+    // and the contents of aSrcdoc will be loaded instead of aURI.
     virtual nsresult DoURILoad(nsIURI * aURI,
                                nsIURI * aReferrer,
                                bool aSendReferrer,
                                nsISupports * aOwner,
                                const char * aTypeHint,
                                const nsAString & aFileName,
                                nsIInputStream * aPostData,
                                nsIInputStream * aHeadersData,
                                bool firstParty,
                                nsIDocShell ** aDocShell,
                                nsIRequest ** aRequest,
                                bool aIsNewWindowTarget,
                                bool aBypassClassifier,
-                               bool aForceAllowCookies);
+                               bool aForceAllowCookies,
+                               const nsAString &aSrcdoc);
     NS_IMETHOD AddHeadersToChannel(nsIInputStream * aHeadersData, 
                                   nsIChannel * aChannel);
     virtual nsresult DoChannelLoad(nsIChannel * aChannel,
                                    nsIURILoader * aURILoader,
                                    bool aBypassClassifier);
 
     nsresult ScrollToAnchor(nsACString & curHash, nsACString & newHash,
                             uint32_t aLoadType);
--- a/docshell/base/nsDocShellLoadInfo.cpp
+++ b/docshell/base/nsDocShellLoadInfo.cpp
@@ -11,17 +11,18 @@
 //*****************************************************************************
 //***    nsDocShellLoadInfo: Object Management
 //*****************************************************************************
 
 nsDocShellLoadInfo::nsDocShellLoadInfo()
   : mInheritOwner(false),
     mOwnerIsExplicit(false),
     mSendReferrer(true),
-    mLoadType(nsIDocShellLoadInfo::loadNormal)
+    mLoadType(nsIDocShellLoadInfo::loadNormal),
+    mIsSrcdocLoad(false)
 {
 }
 
 nsDocShellLoadInfo::~nsDocShellLoadInfo()
 {
 }
 
 //*****************************************************************************
@@ -183,15 +184,35 @@ NS_IMETHODIMP nsDocShellLoadInfo::GetSen
 }
 
 NS_IMETHODIMP nsDocShellLoadInfo::SetSendReferrer(bool aSendReferrer)
 {
    mSendReferrer = aSendReferrer;
    return NS_OK;
 }
 
+NS_IMETHODIMP nsDocShellLoadInfo::GetIsSrcdocLoad(bool* aIsSrcdocLoad)
+{
+   *aIsSrcdocLoad = mIsSrcdocLoad;
+   return NS_OK;
+}
+
+NS_IMETHODIMP nsDocShellLoadInfo::GetSrcdocData(nsAString &aSrcdocData)
+{
+   aSrcdocData = mSrcdocData;
+   return NS_OK;
+}
+
+NS_IMETHODIMP nsDocShellLoadInfo::SetSrcdocData(const nsAString &aSrcdocData)
+{
+   mSrcdocData = aSrcdocData;
+   mIsSrcdocLoad = true;
+   return NS_OK;
+}
+
+
 //*****************************************************************************
 // nsDocShellLoadInfo: Helpers
 //*****************************************************************************   
 
 //*****************************************************************************
 // nsDocShellLoadInfo: Accessors
 //*****************************************************************************   
--- a/docshell/base/nsDocShellLoadInfo.h
+++ b/docshell/base/nsDocShellLoadInfo.h
@@ -35,11 +35,13 @@ protected:
   bool                             mInheritOwner;
   bool                             mOwnerIsExplicit;
   bool                             mSendReferrer;
   nsDocShellInfoLoadType           mLoadType;
   nsCOMPtr<nsISHEntry>             mSHEntry;
   nsString                         mTarget;
   nsCOMPtr<nsIInputStream>         mPostDataStream;
   nsCOMPtr<nsIInputStream>         mHeadersStream;
+  bool                             mIsSrcdocLoad;
+  nsString                         mSrcdocData;
 };
 
 #endif /* nsDocShellLoadInfo_h__ */
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -37,17 +37,17 @@ interface nsILayoutHistoryState;
 interface nsISecureBrowserUI;
 interface nsIDOMStorage;
 interface nsIPrincipal;
 interface nsIWebBrowserPrint;
 interface nsIVariant;
 interface nsIPrivacyTransitionObserver;
 interface nsIReflowObserver;
 
-[scriptable, builtinclass, uuid(f453d2ee-bac7-46f9-a553-df918f0cc0d0)]
+[scriptable, builtinclass, uuid(cdeb1ed0-7794-4e5f-964e-bb9d753d1686)]
 interface nsIDocShell : nsIDocShellTreeItem
 {
   /**
    * Loads a given URI.  This will give priority to loading the requested URI
    * in the object implementing	this interface.  If it can't be loaded here
    * however, the URL dispatcher will go through its normal process of content
    * loading.
    *
@@ -101,16 +101,19 @@ interface nsIDocShell : nsIDocShellTreeI
 
   // This flag marks the first load in this object
   // @see nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD
   const long INTERNAL_LOAD_FLAGS_FIRST_LOAD              = 0x8;
 
   const long INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER       = 0x10;
   const long INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES     = 0x20;
 
+  // Whether the load should be treated as srcdoc load, rather than a URI one.
+  const long INTERNAL_LOAD_FLAGS_IS_SRCDOC               = 0x40;
+
   /**
    * Loads the given URI.  This method is identical to loadURI(...) except
    * that its parameter list is broken out instead of being packaged inside
    * of an nsIDocShellLoadInfo object...
    *
    * @param aURI            - The URI to load.
    * @param aReferrer       - Referring URI
    * @param aOwner          - Owner (security principal) 
@@ -123,29 +126,33 @@ interface nsIDocShell : nsIDocShellTreeI
    *                          data.  May be null or empty if no hint.
    * @param aFileName       - Non-null when the link should be downloaded as
                               the given filename.
    * @param aPostDataStream - Post data stream (if POSTing)
    * @param aHeadersStream  - Stream containing "extra" request headers...
    * @param aLoadFlags      - Flags to modify load behaviour. Flags are defined
    *                          in nsIWebNavigation.
    * @param aSHEntry        - Active Session History entry (if loading from SH)
+   * @param aSrcdoc           When INTERNAL_LOAD_FLAGS_IS_SRCDOC is set, the
+   *                          contents of this parameter will be loaded instead
+   *                          of aURI.
    */
   [noscript]void internalLoad(in nsIURI aURI,
                               in nsIURI aReferrer,
                               in nsISupports aOwner,
                               in uint32_t aFlags,
                               in wstring aWindowTarget,
                               in string aTypeHint,
                               in AString aFileName,
                               in nsIInputStream aPostDataStream,
                               in nsIInputStream aHeadersStream,
                               in unsigned long aLoadFlags,
                               in nsISHEntry aSHEntry,
                               in boolean firstParty,
+                              in AString aSrcdoc,
                               out nsIDocShell aDocShell,
                               out nsIRequest aRequest);
 
   /**
    * Do either a history.pushState() or history.replaceState() operation,
    * depending on the value of aReplace.
    */
   [implicit_jscontext]
--- a/docshell/base/nsIDocShellLoadInfo.idl
+++ b/docshell/base/nsIDocShellLoadInfo.idl
@@ -12,17 +12,17 @@
  */
  
 interface nsIURI;
 interface nsIInputStream;
 interface nsISHEntry;
 
 typedef long nsDocShellInfoLoadType;
 
-[scriptable, uuid(5b041ea4-6655-434c-b3d3-cbbc9441f86a)]
+[scriptable, uuid(5df91211-37db-47e9-8f83-2d5b0cb2eb9e)]
 interface nsIDocShellLoadInfo : nsISupports
 {
     /** This is the referrer for the load. */
     attribute nsIURI referrer;
 
     /** The owner of the load, that is, the entity responsible for 
      *  causing the load to occur. This should be a nsIPrincipal typically.
      */
@@ -77,9 +77,21 @@ interface nsIDocShellLoadInfo : nsISuppo
 
     /** Additional headers */
     attribute nsIInputStream headersStream;
 
     /** True if the referrer should be sent, false if it shouldn't be
      *  sent, even if it's available. This attribute defaults to true.
      */
     attribute boolean sendReferrer;
+
+    /** True if the docshell has been created to load an iframe where the
+     * srcdoc attribute has been set.  Set when srcdocData is specified.
+     */
+    readonly attribute boolean isSrcdocLoad;
+
+    /** When set, the load will be interpreted as a srcdoc load, where contents
+     * of this string will be loaded instead of the URI.  Setting srcdocData
+     * sets isSrcdocLoad to true
+     */
+    attribute AString srcdocData;
+
 };
--- a/docshell/shistory/public/nsISHEntry.idl
+++ b/docshell/shistory/public/nsISHEntry.idl
@@ -24,17 +24,17 @@ interface nsIBFCacheEntry;
 struct nsIntRect;
 class nsDocShellEditorData;
 class nsSHEntryShared;
 %}
 [ref] native nsIntRect(nsIntRect);
 [ptr] native nsDocShellEditorDataPtr(nsDocShellEditorData);
 [ptr] native nsSHEntryShared(nsSHEntryShared);
 
-[scriptable, uuid(6443FD72-A50F-4B8B-BB82-BB1FA04CB15D)]
+[scriptable, uuid(162EA0EB-E577-4B9A-AF9D-A94E8350B029)]
 interface nsISHEntry : nsIHistoryEntry
 {
     /** URI for the document */
     void setURI(in nsIURI aURI);
 
     /** Referrer URI */
     attribute nsIURI referrerURI;
 
@@ -232,16 +232,30 @@ interface nsISHEntry : nsIHistoryEntry
 
     /**
      * Does this SHEntry correspond to the same document as aEntry?  This is
      * true iff the two SHEntries have the same BFCacheEntry.  So in
      * particular, sharesDocumentWith(aEntry) is guaranteed to return true if
      * it's preceeded by a call to adoptBFCacheEntry(aEntry).
      */
     boolean sharesDocumentWith(in nsISHEntry aEntry);
+
+    /**
+     * True if this SHEntry corresponds to a document created by a srcdoc iframe.
+     * Set when a value is assigned to  srcdocData.
+     */
+    readonly attribute boolean isSrcdocEntry;
+
+    /**
+     * Contents of the srcdoc attribute in a srcdoc iframe to be loaded instead
+     * of the URI.  Similar to a Data URI, this information is needed to
+     * recreate the document at a later stage.
+     * Setting this sets isSrcdocEntry to true
+     */
+    attribute AString srcdocData;
 };
 
 [scriptable, uuid(bb66ac35-253b-471f-a317-3ece940f04c5)]
 interface nsISHEntryInternal : nsISupports
 {
     [notxpcom] void RemoveFromBFCacheAsync();
     [notxpcom] void RemoveFromBFCacheSync();
 
--- a/docshell/shistory/src/nsSHEntry.cpp
+++ b/docshell/shistory/src/nsSHEntry.cpp
@@ -30,16 +30,17 @@ static uint32_t gEntryID = 0;
 
 nsSHEntry::nsSHEntry()
   : mLoadType(0)
   , mID(gEntryID++)
   , mScrollPositionX(0)
   , mScrollPositionY(0)
   , mParent(nullptr)
   , mURIWasModified(false)
+  , mIsSrcdocEntry(false)
 {
   mShared = new nsSHEntryShared();
 }
 
 nsSHEntry::nsSHEntry(const nsSHEntry &other)
   : mShared(other.mShared)
   , mURI(other.mURI)
   , mReferrerURI(other.mReferrerURI)
@@ -47,16 +48,18 @@ nsSHEntry::nsSHEntry(const nsSHEntry &ot
   , mPostData(other.mPostData)
   , mLoadType(0)         // XXX why not copy?
   , mID(other.mID)
   , mScrollPositionX(0)  // XXX why not copy?
   , mScrollPositionY(0)  // XXX why not copy?
   , mParent(other.mParent)
   , mURIWasModified(other.mURIWasModified)
   , mStateData(other.mStateData)
+  , mIsSrcdocEntry(other.mIsSrcdocEntry)
+  , mSrcdocData(other.mSrcdocData)
 {
 }
 
 static bool
 ClearParentPtr(nsISHEntry* aEntry, void* /* aData */)
 {
   if (aEntry) {
     aEntry->SetParent(nullptr);
@@ -486,16 +489,40 @@ nsSHEntry::SharesDocumentWith(nsISHEntry
 
 NS_IMETHODIMP
 nsSHEntry::AbandonBFCacheEntry()
 {
   mShared = nsSHEntryShared::Duplicate(mShared);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsSHEntry::GetIsSrcdocEntry(bool* aIsSrcdocEntry)
+{
+  *aIsSrcdocEntry = mIsSrcdocEntry;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSHEntry::GetSrcdocData(nsAString &aSrcdocData)
+{
+  aSrcdocData = mSrcdocData;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSHEntry::SetSrcdocData(const nsAString &aSrcdocData)
+{
+  mSrcdocData = aSrcdocData;
+  mIsSrcdocEntry = true;
+  return NS_OK;
+}
+
+
+
 //*****************************************************************************
 //    nsSHEntry: nsISHContainer
 //*****************************************************************************
 
 NS_IMETHODIMP 
 nsSHEntry::GetChildCount(int32_t * aCount)
 {
   *aCount = mChildren.Count();
--- a/docshell/shistory/src/nsSHEntry.h
+++ b/docshell/shistory/src/nsSHEntry.h
@@ -57,11 +57,13 @@ private:
   uint32_t                 mLoadType;
   uint32_t                 mID;
   int32_t                  mScrollPositionX;
   int32_t                  mScrollPositionY;
   nsISHEntry*              mParent;
   nsCOMArray<nsISHEntry>   mChildren;
   bool                     mURIWasModified;
   nsCOMPtr<nsIStructuredCloneContainer> mStateData;
+  bool                     mIsSrcdocEntry;
+  nsString                 mSrcdocData;
 };
 
 #endif /* nsSHEntry_h */