diff --git a/content/html/content/test/Makefile.in b/content/html/content/test/Makefile.in
index 10ab8a72a91..750103d0fff 100644
--- a/content/html/content/test/Makefile.in
+++ b/content/html/content/test/Makefile.in
@@ -300,5 +300,14 @@ _TEST_FILES = \
test_bug694503.html \
$(NULL)
+_BROWSER_TEST_FILES = \
+ browser_bug649778.js \
+ file_bug649778.html \
+ file_bug649778.html^headers^ \
+ $(NULL)
+
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
+
+libs:: $(_BROWSER_TEST_FILES)
+ $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
diff --git a/content/html/content/test/browser_bug649778.js b/content/html/content/test/browser_bug649778.js
new file mode 100644
index 00000000000..ac4b43d101b
--- /dev/null
+++ b/content/html/content/test/browser_bug649778.js
@@ -0,0 +1,67 @@
+// Test for bug 649778 - document.write may cause a document to be written to disk cache even when the page has Cache-Control: no-store
+
+// Globals
+var testPath = "http://mochi.test:8888/browser/content/html/content/test/";
+var popup;
+
+function checkCache(url, policy, shouldExist)
+{
+ var cache = Components.classes["@mozilla.org/network/cache-service;1"].
+ getService(Components.interfaces.nsICacheService);
+ var session = cache.createSession(
+ "wyciwyg", policy,
+ Components.interfaces.nsICache.STREAM_BASED);
+ try {
+ var cacheEntry = session.openCacheEntry(
+ url, Components.interfaces.nsICache.ACCESS_READ, true);
+ is(shouldExist, true, "Entry found");
+ }
+ catch (e) {
+ is(shouldExist, false, "Entry not found");
+ is(e.result, Components.results.NS_ERROR_CACHE_KEY_NOT_FOUND,
+ "Invalid error");
+ }
+}
+
+function getPopupURL() {
+ var sh = popup.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIWebNavigation)
+ .sessionHistory;
+
+ return sh.getEntryAtIndex(sh.index, false).URI.spec;
+}
+
+function testContinue() {
+ var wyciwygURL = getPopupURL();
+ is(wyciwygURL.substring(0, 10), "wyciwyg://", "Unexpected URL.");
+ popup.close()
+
+ checkCache(wyciwygURL, Components.interfaces.nsICache.STORE_ON_DISK, false);
+ checkCache(wyciwygURL, Components.interfaces.nsICache.STORE_IN_MEMORY, true);
+
+ finish();
+}
+
+function waitForWyciwygDocument() {
+ try {
+ var url = getPopupURL();
+ if (url.substring(0, 10) == "wyciwyg://") {
+ setTimeout(testContinue, 0);
+ return;
+ }
+ }
+ catch (e) {
+ }
+ setTimeout(waitForWyciwygDocument, 100);
+}
+
+// Entry point from Mochikit
+function test() {
+ waitForExplicitFinish();
+
+ popup = window.open(testPath + "file_bug649778.html", "popup 0",
+ "height=200,width=200,location=yes," +
+ "menubar=yes,status=yes,toolbar=yes,dependent=yes");
+
+ waitForWyciwygDocument();
+}
diff --git a/content/html/content/test/file_bug649778.html b/content/html/content/test/file_bug649778.html
new file mode 100644
index 00000000000..48a9870e7ee
--- /dev/null
+++ b/content/html/content/test/file_bug649778.html
@@ -0,0 +1,11 @@
+
+
+
+
+
diff --git a/content/html/content/test/file_bug649778.html^headers^ b/content/html/content/test/file_bug649778.html^headers^
new file mode 100644
index 00000000000..4030ea1d3dd
--- /dev/null
+++ b/content/html/content/test/file_bug649778.html^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp
index 15132472fd9..baf1d436ac9 100644
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -136,6 +136,7 @@
#include "mozilla/dom/Element.h"
#include "mozilla/Preferences.h"
#include "nsMimeTypes.h"
+#include "nsIRequest.h"
using namespace mozilla;
using namespace mozilla::dom;
@@ -1419,6 +1420,7 @@ nsHTMLDocument::Open(const nsAString& aContentTypeOrUrl,
nsCOMPtr uri = callerDoc->GetDocumentURI();
nsCOMPtr baseURI = callerDoc->GetBaseURI();
nsCOMPtr callerPrincipal = callerDoc->NodePrincipal();
+ nsCOMPtr callerChannel = callerDoc->GetChannel();
// We're called from script. Make sure the script is from the same
// origin, not just that the caller can access the document. This is
@@ -1490,6 +1492,21 @@ nsHTMLDocument::Open(const nsAString& aContentTypeOrUrl,
rv = channel->SetOwner(callerPrincipal);
NS_ENSURE_SUCCESS(rv, rv);
+ if (callerChannel) {
+ nsLoadFlags callerLoadFlags;
+ rv = callerChannel->GetLoadFlags(&callerLoadFlags);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsLoadFlags loadFlags;
+ rv = channel->GetLoadFlags(&loadFlags);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ loadFlags |= callerLoadFlags & nsIRequest::INHIBIT_PERSISTENT_CACHING;
+
+ rv = channel->SetLoadFlags(loadFlags);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
// Before we reset the doc notify the globalwindow of the change,
// but only if we still have a window (i.e. our window object the
// current inner window in our outer window).
diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp
index 5e34ad7c780..fab0726cd4d 100644
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -978,6 +978,8 @@ nsHttpChannel::ProcessResponse()
LOG(("nsHttpChannel::ProcessResponse [this=%p httpStatus=%u]\n",
this, httpStatus));
+ UpdateInhibitPersistentCachingFlag();
+
if (mTransaction->SSLConnectFailed()) {
if (!ShouldSSLProxyResponseContinue(httpStatus))
return ProcessFailedSSLConnect(httpStatus);
@@ -1783,6 +1785,8 @@ nsHttpChannel::ProcessPartialContent()
// make the cached response be the current response
mResponseHead = mCachedResponseHead;
+ UpdateInhibitPersistentCachingFlag();
+
rv = UpdateExpirationTime();
if (NS_FAILED(rv)) return rv;
@@ -1864,6 +1868,8 @@ nsHttpChannel::ProcessNotModified()
// make the cached response be the current response
mResponseHead = mCachedResponseHead;
+ UpdateInhibitPersistentCachingFlag();
+
rv = UpdateExpirationTime();
if (NS_FAILED(rv)) return rv;
@@ -2848,6 +2854,8 @@ nsHttpChannel::ReadFromCache()
if (mCachedResponseHead)
mResponseHead = mCachedResponseHead;
+ UpdateInhibitPersistentCachingFlag();
+
// if we don't already have security info, try to get it from the cache
// entry. there are two cases to consider here: 1) we are just reading
// from the cache, or 2) this may be due to a 304 not modified response,
@@ -3002,16 +3010,6 @@ nsHttpChannel::InitCacheEntry()
LOG(("nsHttpChannel::InitCacheEntry [this=%p entry=%p]\n",
this, mCacheEntry.get()));
- // The no-store directive within the 'Cache-Control:' header indicates
- // that we must not store the response in a persistent cache.
- if (mResponseHead->NoStore())
- mLoadFlags |= INHIBIT_PERSISTENT_CACHING;
-
- // Only cache SSL content on disk if the pref is set
- if (!gHttpHandler->IsPersistentHttpsCachingEnabled() &&
- mConnectionInfo->UsingSSL())
- mLoadFlags |= INHIBIT_PERSISTENT_CACHING;
-
if (mLoadFlags & INHIBIT_PERSISTENT_CACHING) {
rv = mCacheEntry->SetStoragePolicy(nsICache::STORE_IN_MEMORY);
if (NS_FAILED(rv)) return rv;
@@ -3028,6 +3026,19 @@ nsHttpChannel::InitCacheEntry()
return NS_OK;
}
+void
+nsHttpChannel::UpdateInhibitPersistentCachingFlag()
+{
+ // The no-store directive within the 'Cache-Control:' header indicates
+ // that we must not store the response in a persistent cache.
+ if (mResponseHead->NoStore())
+ mLoadFlags |= INHIBIT_PERSISTENT_CACHING;
+
+ // Only cache SSL content on disk if the pref is set
+ if (!gHttpHandler->IsPersistentHttpsCachingEnabled() &&
+ mConnectionInfo->UsingSSL())
+ mLoadFlags |= INHIBIT_PERSISTENT_CACHING;
+}
nsresult
nsHttpChannel::InitOfflineCacheEntry()
diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h
index 88ce469ab6f..b7bba48b0e8 100644
--- a/netwerk/protocol/http/nsHttpChannel.h
+++ b/netwerk/protocol/http/nsHttpChannel.h
@@ -224,6 +224,7 @@ private:
void CloseCacheEntry(bool doomOnFailure);
void CloseOfflineCacheEntry();
nsresult InitCacheEntry();
+ void UpdateInhibitPersistentCachingFlag();
nsresult InitOfflineCacheEntry();
nsresult AddCacheEntryHeaders(nsICacheEntryDescriptor *entry);
nsresult StoreAuthorizationMetaData(nsICacheEntryDescriptor *entry);
diff --git a/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp b/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
index 690d12575ed..6178ea70301 100644
--- a/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
+++ b/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
@@ -446,6 +446,11 @@ nsWyciwygChannel::WriteToCacheEntryInternal(const nsAString &aData, const nsACSt
if (NS_FAILED(rv)) return rv;
}
+ if (mLoadFlags & INHIBIT_PERSISTENT_CACHING) {
+ rv = mCacheEntry->SetMetaDataElement("inhibit-persistent-caching", "1");
+ if (NS_FAILED(rv)) return rv;
+ }
+
if (mSecurityInfo) {
mCacheEntry->SetSecurityInfo(mSecurityInfo);
}
@@ -720,6 +725,12 @@ nsWyciwygChannel::ReadFromCache()
// Get the stored security info
mCacheEntry->GetSecurityInfo(getter_AddRefs(mSecurityInfo));
+ nsCAutoString tmpStr;
+ rv = mCacheEntry->GetMetaDataElement("inhibit-persistent-caching",
+ getter_Copies(tmpStr));
+ if (NS_SUCCEEDED(rv) && tmpStr == NS_LITERAL_CSTRING("1"))
+ mLoadFlags |= INHIBIT_PERSISTENT_CACHING;
+
// Get a transport to the cached data...
rv = mCacheEntry->OpenInputStream(0, getter_AddRefs(mCacheInputStream));
if (NS_FAILED(rv))