Bug 818667 - Put HTTP cache into app jars. r=michal.novotny

This commit is contained in:
Josh Matthews 2012-12-28 12:50:23 -05:00
Родитель 84d274cfbc
Коммит b8e77d1643
7 изменённых файлов: 241 добавлений и 23 удалений

Просмотреть файл

@ -77,22 +77,6 @@ AccumulateCacheHitTelemetry(Telemetry::ID deviceHistogram,
}
}
const char *
GetCacheSessionNameForStoragePolicy(nsCacheStoragePolicy storagePolicy,
bool isPrivate)
{
MOZ_ASSERT(!isPrivate || storagePolicy == nsICache::STORE_IN_MEMORY);
switch (storagePolicy) {
case nsICache::STORE_IN_MEMORY:
return isPrivate ? "HTTP-memory-only-PB" : "HTTP-memory-only";
case nsICache::STORE_OFFLINE:
return "HTTP-offline";
default:
return "HTTP";
}
}
// Computes and returns a SHA1 hash of the input buffer. The input buffer
// must be a null-terminated string.
nsresult
@ -2480,6 +2464,18 @@ nsHttpChannel::OnOfflineCacheEntryAvailable(nsICacheEntryDescriptor *aEntry,
return OpenNormalCacheEntry(usingSSL);
}
static void
GetAppInfo(nsIChannel* aChannel, uint32_t* aAppId, bool* aIsInBrowser)
{
nsCOMPtr<nsILoadContext> loadContext;
NS_QueryNotificationCallbacks(aChannel, loadContext);
*aAppId = NECKO_NO_APP_ID;
*aIsInBrowser = false;
if (loadContext) {
loadContext->GetAppId(aAppId);
loadContext->GetIsInBrowserElement(aIsInBrowser);
}
}
nsresult
nsHttpChannel::OpenNormalCacheEntry(bool usingSSL)
@ -2488,9 +2484,14 @@ nsHttpChannel::OpenNormalCacheEntry(bool usingSSL)
nsresult rv;
uint32_t appId;
bool isInBrowser;
GetAppInfo(this, &appId, &isInBrowser);
nsCacheStoragePolicy storagePolicy = DetermineStoragePolicy();
nsDependentCString clientID(
GetCacheSessionNameForStoragePolicy(storagePolicy, mPrivateBrowsing));
nsAutoCString clientID;
nsHttpHandler::GetCacheSessionNameForStoragePolicy(storagePolicy, mPrivateBrowsing,
appId, isInBrowser, clientID);
nsAutoCString cacheKey;
GenerateCacheKey(mPostID, cacheKey);
@ -5897,20 +5898,25 @@ nsHttpChannel::DoInvalidateCacheEntry(const nsCString &key)
// The logic below deviates from the original logic in OpenCacheEntry on
// one point by using only READ_ONLY access-policy. I think this is safe.
uint32_t appId;
bool isInBrowser;
GetAppInfo(this, &appId, &isInBrowser);
// First, find session holding the cache-entry - use current storage-policy
nsCacheStoragePolicy storagePolicy = DetermineStoragePolicy();
const char * clientID =
GetCacheSessionNameForStoragePolicy(storagePolicy, mPrivateBrowsing);
nsAutoCString clientID;
nsHttpHandler::GetCacheSessionNameForStoragePolicy(storagePolicy, mPrivateBrowsing,
appId, isInBrowser, clientID);
LOG(("DoInvalidateCacheEntry [channel=%p session=%s policy=%d key=%s]",
this, clientID, int(storagePolicy), key.get()));
this, clientID.get(), int(storagePolicy), key.get()));
nsresult rv;
nsCOMPtr<nsICacheService> serv =
do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
nsCOMPtr<nsICacheSession> session;
if (NS_SUCCEEDED(rv)) {
rv = serv->CreateSession(clientID, storagePolicy,
rv = serv->CreateSession(clientID.get(), storagePolicy,
nsICache::STREAM_BASED,
getter_AddRefs(session));
}
@ -5922,7 +5928,7 @@ nsHttpChannel::DoInvalidateCacheEntry(const nsCString &key)
}
LOG(("DoInvalidateCacheEntry [channel=%p session=%s policy=%d key=%s rv=%d]",
this, clientID, int(storagePolicy), key.get(), int(rv)));
this, clientID.get(), int(storagePolicy), key.get(), int(rv)));
}
nsCacheStoragePolicy

Просмотреть файл

@ -36,6 +36,7 @@
#include "nsSocketTransportService2.h"
#include "nsAlgorithm.h"
#include "ASpdySession.h"
#include "mozIApplicationClearPrivateDataParams.h"
#include "nsIXULAppInfo.h"
@ -325,6 +326,7 @@ nsHttpHandler::Init()
mObserverService->AddObserver(this, "net:prune-dead-connections", true);
mObserverService->AddObserver(this, "net:failed-to-process-uri-content", true);
mObserverService->AddObserver(this, "last-pb-context-exited", true);
mObserverService->AddObserver(this, "webapps-clear-data", true);
}
return NS_OK;
@ -1581,10 +1583,62 @@ nsHttpHandler::GetMisc(nsACString &value)
return NS_OK;
}
/*static*/ void
nsHttpHandler::GetCacheSessionNameForStoragePolicy(
nsCacheStoragePolicy storagePolicy,
bool isPrivate,
uint32_t appId,
bool inBrowser,
nsACString& sessionName)
{
MOZ_ASSERT(!isPrivate || storagePolicy == nsICache::STORE_IN_MEMORY);
switch (storagePolicy) {
case nsICache::STORE_IN_MEMORY:
sessionName.AssignASCII(isPrivate ? "HTTP-memory-only-PB" : "HTTP-memory-only");
break;
case nsICache::STORE_OFFLINE:
sessionName.AssignLiteral("HTTP-offline");
break;
default:
sessionName.AssignLiteral("HTTP");
break;
}
if (appId != NECKO_NO_APP_ID || inBrowser) {
sessionName.Append('~');
sessionName.AppendInt(appId);
sessionName.Append('~');
sessionName.AppendInt(inBrowser);
}
}
//-----------------------------------------------------------------------------
// nsHttpHandler::nsIObserver
//-----------------------------------------------------------------------------
static void
EvictCacheSession(nsCacheStoragePolicy aPolicy,
bool aPrivateBrowsing,
uint32_t aAppId,
bool aInBrowser)
{
nsAutoCString clientId;
nsHttpHandler::GetCacheSessionNameForStoragePolicy(aPolicy,
aPrivateBrowsing,
aAppId, aInBrowser,
clientId);
nsCOMPtr<nsICacheService> serv =
do_GetService(NS_CACHESERVICE_CONTRACTID);
nsCOMPtr<nsICacheSession> session;
nsresult rv = serv->CreateSession(clientId.get(),
nsICache::STORE_ANYWHERE,
nsICache::STREAM_BASED,
getter_AddRefs(session));
if (NS_SUCCEEDED(rv) && session) {
session->EvictEntries();
}
}
NS_IMETHODIMP
nsHttpHandler::Observe(nsISupports *subject,
const char *topic,
@ -1635,6 +1689,45 @@ nsHttpHandler::Observe(nsISupports *subject,
else if (strcmp(topic, "last-pb-context-exited") == 0) {
mPrivateAuthCache.ClearAll();
}
else if (strcmp(topic, "webapps-clear-data") == 0) {
nsCOMPtr<mozIApplicationClearPrivateDataParams> params =
do_QueryInterface(subject);
if (!params) {
NS_ERROR("'webapps-clear-data' notification's subject should be a mozIApplicationClearPrivateDataParams");
return NS_ERROR_UNEXPECTED;
}
uint32_t appId;
bool browserOnly;
nsresult rv = params->GetAppId(&appId);
NS_ENSURE_SUCCESS(rv, rv);
rv = params->GetBrowserOnly(&browserOnly);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(appId != NECKO_UNKNOWN_APP_ID);
// Now we ensure that all unique session name combinations are cleared.
struct {
nsCacheStoragePolicy policy;
bool privateBrowsing;
} policies[] = { {nsICache::STORE_OFFLINE, false},
{nsICache::STORE_IN_MEMORY, false},
{nsICache::STORE_IN_MEMORY, true},
{nsICache::STORE_ON_DISK, false} };
for (uint32_t i = 0; i < NS_ARRAY_LENGTH(policies); i++) {
EvictCacheSession(policies[i].policy,
policies[i].privateBrowsing,
appId, browserOnly);
if (!browserOnly) {
EvictCacheSession(policies[i].policy,
policies[i].privateBrowsing,
appId, true);
}
}
}
return NS_OK;
}

Просмотреть файл

@ -253,6 +253,12 @@ public:
// returns true in between Init and Shutdown states
bool Active() { return mHandlerActive; }
static void GetCacheSessionNameForStoragePolicy(
nsCacheStoragePolicy storagePolicy,
bool isPrivate,
uint32_t appId,
bool inBrowser,
nsACString& sessionName);
private:
//

Просмотреть файл

@ -0,0 +1,108 @@
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource://testing-common/httpd.js");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
var httpserv = null;
var handlers_called = 0;
function cached_handler(metadata, response) {
response.setHeader("Content-Type", "text/plain", false);
response.setHeader("Cache-Control", "max-age=10000", false);
response.setStatusLine(metadata.httpVersion, 200, "OK");
var body = "0123456789";
response.bodyOutputStream.write(body, body.length);
handlers_called++;
}
function makeChan(url, appId, inBrowser) {
var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
var chan = ios.newChannel(url, null, null).QueryInterface(Ci.nsIHttpChannel);
chan.notificationCallbacks = {
appId: appId,
isInBrowserElement: inBrowser,
QueryInterface: function(iid) {
if (iid.equals(Ci.nsILoadContext))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
},
getInterface: function(iid) { return this.QueryInterface(iid); }
};
return chan;
}
var firstTests = [[0, false, 1], [0, true, 1], [1, false, 1], [1, true, 1]];
var secondTests = [[0, false, 0], [0, true, 0], [1, false, 0], [1, true, 1]];
var thirdTests = [[0, false, 0], [0, true, 0], [1, false, 1], [1, true, 1]];
function run_all_tests() {
for (let test of firstTests) {
handlers_called = 0;
var chan = makeChan("http://localhost:4444/cached", test[0], test[1]);
chan.asyncOpen(new ChannelListener(doneFirstLoad, test[2]), null);
yield;
}
// We can't easily cause webapp data to be cleared from the child process, so skip
// the rest of these tests.
let procType = Cc["@mozilla.org/xre/runtime;1"].getService(Ci.nsIXULRuntime).processType;
if (procType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT)
return;
let subject = {
appId: 1,
browserOnly: true,
QueryInterface: XPCOMUtils.generateQI([Ci.mozIApplicationClearPrivateDataParams])
};
Services.obs.notifyObservers(subject, "webapps-clear-data", null);
for (let test of secondTests) {
handlers_called = 0;
var chan = makeChan("http://localhost:4444/cached", test[0], test[1]);
chan.asyncOpen(new ChannelListener(doneFirstLoad, test[2]), null);
yield;
}
subject = {
appId: 1,
browserOnly: false,
QueryInterface: XPCOMUtils.generateQI([Ci.mozIApplicationClearPrivateDataParams])
};
Services.obs.notifyObservers(subject, "webapps-clear-data", null);
for (let test of thirdTests) {
handlers_called = 0;
var chan = makeChan("http://localhost:4444/cached", test[0], test[1]);
chan.asyncOpen(new ChannelListener(doneFirstLoad, test[2]), null);
yield;
}
}
let gTests;
function run_test() {
do_test_pending();
httpserv = new HttpServer();
httpserv.registerPathHandler("/cached", cached_handler);
httpserv.start(4444);
gTests = run_all_tests();
gTests.next();
}
function doneFirstLoad(req, buffer, expected) {
// Load it again, make sure it hits the cache
var chan = makeChan("http://localhost:4444/cached", 0, false);
chan.asyncOpen(new ChannelListener(doneSecondLoad, expected), null);
}
function doneSecondLoad(req, buffer, expected) {
do_check_eq(handlers_called, expected);
try {
gTests.next();
} catch (x) {
do_test_finished();
}
}

Просмотреть файл

@ -94,6 +94,7 @@ fail-if = os == "android"
[test_bug770243.js]
[test_doomentry.js]
[test_cacheflags.js]
[test_cache_jar.js]
[test_channel_close.js]
[test_compareURIs.js]
[test_compressappend.js]

Просмотреть файл

@ -0,0 +1,3 @@
function run_test() {
run_test_in_child("../unit/test_cache_jar.js");
}

Просмотреть файл

@ -4,6 +4,7 @@ tail =
[test_bug248970_cookie_wrap.js]
[test_cacheflags_wrap.js]
[test_cache_jar_wrap.js]
[test_channel_close_wrap.js]
[test_cookie_header_wrap.js]
[test_cookiejars_wrap.js]