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))