Bug 649778 - document.write may cause a document to be written to disk cache even when the page has Cache-Control: no-store

This commit is contained in:
Michal Novotny 2012-01-30 18:03:52 +01:00
parent 25b7486df1
commit 5f0cb87300
8 changed files with 138 additions and 10 deletions

View File

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

View File

@ -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();
}

View File

@ -0,0 +1,11 @@
<html>
<script>
function test() {
document.open();
document.write('<html><body>WYCIWYG DOCUMENT</body></html>');
document.close();
}
</script>
<body onload="setTimeout(test, 0);">
</body>
</html>

View File

@ -0,0 +1 @@
Cache-Control: no-store

View File

@ -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<nsIURI> uri = callerDoc->GetDocumentURI();
nsCOMPtr<nsIURI> baseURI = callerDoc->GetBaseURI();
nsCOMPtr<nsIPrincipal> callerPrincipal = callerDoc->NodePrincipal();
nsCOMPtr<nsIChannel> 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).

View File

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

View File

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

View File

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