зеркало из https://github.com/mozilla/pjs.git
Bug 460335 - disallow redirects when updating an application cache, r=dcamp, sr=cbiesinger
This commit is contained in:
Родитель
da8a84b61d
Коммит
2e9f407d6e
|
@ -66,6 +66,8 @@ _TEST_FILES = \
|
|||
test_foreign.html \
|
||||
test_fallback.html \
|
||||
test_overlap.html \
|
||||
test_redirectManifest.html \
|
||||
test_redirectUpdateItem.html \
|
||||
overlap.cacheManifest \
|
||||
overlap.cacheManifest^headers^ \
|
||||
test_updatingManifest.html \
|
||||
|
@ -84,6 +86,8 @@ _TEST_FILES = \
|
|||
bypass.cacheManifest \
|
||||
bypass.cacheManifest^headers^ \
|
||||
bypass.html \
|
||||
dynamicRedirect.sjs \
|
||||
explicitRedirect.sjs \
|
||||
fallback.html \
|
||||
fallback2.html \
|
||||
fallbackTop.html \
|
||||
|
@ -99,8 +103,10 @@ _TEST_FILES = \
|
|||
onwhitelist.html^headers^ \
|
||||
updatingIframe.sjs \
|
||||
updatingImplicit.html \
|
||||
manifestRedirect.sjs \
|
||||
missingFile.cacheManifest \
|
||||
missingFile.cacheManifest^headers^ \
|
||||
redirects.sjs \
|
||||
simpleManifest.cacheManifest \
|
||||
simpleManifest.cacheManifest^headers^ \
|
||||
updatingManifest.sjs \
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
function handleRequest(request, response)
|
||||
{
|
||||
var match = request.queryString.match(/^state=(.*)$/);
|
||||
if (match)
|
||||
{
|
||||
response.setStatusLine(request.httpVersion, 200, "No content");
|
||||
setState("state", match[1]);
|
||||
response.write("state='" + match[1] + "'");
|
||||
}
|
||||
|
||||
if (request.queryString == "")
|
||||
{
|
||||
switch (getState("state"))
|
||||
{
|
||||
case "": // The default value
|
||||
response.setStatusLine(request.httpVersion, 307, "Moved temporarly");
|
||||
response.setHeader("Location", "http://example.com/non-existing-dynamic.html");
|
||||
response.setHeader("Content-Type", "text/html");
|
||||
break;
|
||||
case "on":
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.setHeader("Content-Type", "text/html");
|
||||
response.write("<html><body>Dynamic page</body></html>");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
function handleRequest(request, response)
|
||||
{
|
||||
var match = request.queryString.match(/^state=(.*)$/);
|
||||
if (match)
|
||||
{
|
||||
response.setStatusLine(request.httpVersion, 200, "No content");
|
||||
setState("state", match[1]);
|
||||
response.write("state='" + match[1] + "'");
|
||||
}
|
||||
|
||||
if (request.queryString == "")
|
||||
{
|
||||
switch (getState("state"))
|
||||
{
|
||||
case "": // The default value
|
||||
response.setStatusLine(request.httpVersion, 307, "Moved temporarly");
|
||||
response.setHeader("Location", "http://example.com/non-existing-explicit.html");
|
||||
response.setHeader("Content-Type", "text/html");
|
||||
break;
|
||||
case "on":
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.setHeader("Content-Type", "text/html");
|
||||
response.write("<html><body>Explicit page</body></html>");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
function handleRequest(request, response)
|
||||
{
|
||||
response.setStatusLine(request.httpVersion, 307, "Moved temporarly");
|
||||
response.setHeader("Location", "http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/updating.cacheManifest");
|
||||
response.setHeader("Content-Type", "text/cache-manifest");
|
||||
}
|
|
@ -44,6 +44,8 @@ applicationCache.oncached = function() {
|
|||
// Now delete the manifest and refresh, we should get an "obsolete" message.
|
||||
applicationCache.oncached = fail;
|
||||
applicationCache.onupdateready = fail;
|
||||
applicationCache.onnoupdate = fail;
|
||||
applicationCache.onerror = fail;
|
||||
applicationCache.onobsolete = obsolete;
|
||||
|
||||
// Make the obsoleting.sjs return 404 NOT FOUND code
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
ver1manifest =
|
||||
"CACHE MANIFEST\n" +
|
||||
"# v1\n" +
|
||||
"\n" +
|
||||
"http://localhost:8888/tests/SimpleTest/SimpleTest.js\n" +
|
||||
"http://localhost:8888/MochiKit/packed.js\n" +
|
||||
"http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/offlineTests.js\n" +
|
||||
"http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/explicitRedirect.sjs";
|
||||
|
||||
ver2manifest =
|
||||
"CACHE MANIFEST\n" +
|
||||
"# v2\n" +
|
||||
"\n" +
|
||||
"http://localhost:8888/tests/SimpleTest/SimpleTest.js\n" +
|
||||
"http://localhost:8888/MochiKit/packed.js\n" +
|
||||
"http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/offlineTests.js\n" +
|
||||
"http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/explicitRedirect.sjs";
|
||||
|
||||
ver3manifest =
|
||||
"CACHE MANIFEST\n" +
|
||||
"# v3\n" +
|
||||
"\n" +
|
||||
"http://localhost:8888/tests/SimpleTest/SimpleTest.js\n" +
|
||||
"http://localhost:8888/MochiKit/packed.js\n" +
|
||||
"http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/offlineTests.js\n" +
|
||||
"http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/explicitRedirect.sjs";
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
var match = request.queryString.match(/^state=(.*)$/);
|
||||
if (match)
|
||||
{
|
||||
response.setStatusLine(request.httpVersion, 204, "No content");
|
||||
setState("state", match[1]);
|
||||
}
|
||||
|
||||
if (request.queryString == "")
|
||||
{
|
||||
response.setStatusLine(request.httpVersion, 200, "Ok");
|
||||
response.setHeader("Content-Type", "text/cache-manifest");
|
||||
response.setHeader("Cache-Control", "no-cache");
|
||||
switch (getState("state"))
|
||||
{
|
||||
case "": // The default value
|
||||
response.write(ver1manifest + "\n#" + getState("state"));
|
||||
break;
|
||||
case "second":
|
||||
response.write(ver2manifest + "\n#" + getState("state"));
|
||||
break;
|
||||
case "third":
|
||||
response.write(ver3manifest + "\n#" + getState("state"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml" manifest="http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/manifestRedirect.sjs">
|
||||
<head>
|
||||
<title>Fail update on manifest redirection test</title>
|
||||
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/dom/tests/mochitest/ajax/offline/offlineTests.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
function manifestCached()
|
||||
{
|
||||
OfflineTests.ok(false, "Manifest must not be cached");
|
||||
finish();
|
||||
}
|
||||
|
||||
function manifestError()
|
||||
{
|
||||
OfflineTest.ok(true, "Error expected");
|
||||
finish();
|
||||
}
|
||||
|
||||
function finish()
|
||||
{
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
if (OfflineTest.setup()) {
|
||||
applicationCache.onerror = OfflineTest.priv(manifestError);
|
||||
applicationCache.oncached = OfflineTest.priv(manifestCached);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,128 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml" manifest="http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/redirects.sjs">
|
||||
<head>
|
||||
<title>Entries redirection handling during update test</title>
|
||||
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/dom/tests/mochitest/ajax/offline/offlineTests.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var gCurrentManifestVersion = 1;
|
||||
|
||||
function manifestCached()
|
||||
{
|
||||
OfflineTest.checkCache(
|
||||
"http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/dynamicRedirect.sjs", false);
|
||||
OfflineTest.checkCache(
|
||||
"http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/explicitRedirect.sjs", true);
|
||||
OfflineTest.is(gCurrentManifestVersion, 1, "Cached event for manifest version one");
|
||||
|
||||
// Now add one dynamic entry (now with content overriden redirect sjs)
|
||||
applicationCache.mozAdd(
|
||||
"http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/dynamicRedirect.sjs");
|
||||
|
||||
// Wait for the dynamic entry be added to the cache...
|
||||
OfflineTest.waitForAdd(
|
||||
"http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/dynamicRedirect.sjs",
|
||||
function() {
|
||||
// ...check it is there...
|
||||
OfflineTest.checkCache(
|
||||
"http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/dynamicRedirect.sjs", true);
|
||||
|
||||
// ...revert state of the dynamic entry on the server, now we get the redirect...
|
||||
OfflineTest.setSJSState(
|
||||
"http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/dynamicRedirect.sjs",
|
||||
"");
|
||||
|
||||
// ...update manifest to the new version on the server...
|
||||
OfflineTest.setSJSState(
|
||||
"http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/redirects.sjs",
|
||||
"second");
|
||||
gCurrentManifestVersion = 2;
|
||||
|
||||
// ...and finally invoke the cache update.
|
||||
applicationCache.update();
|
||||
});
|
||||
}
|
||||
|
||||
function manifestUpdated()
|
||||
{
|
||||
switch (gCurrentManifestVersion)
|
||||
{
|
||||
case 2:
|
||||
// Check the dynamic entry was removed from the cache (because of the redirect)...
|
||||
OfflineTest.checkCache(
|
||||
"http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/dynamicRedirect.sjs", false);
|
||||
|
||||
// ...return back redirect for the explicit entry...
|
||||
OfflineTest.setSJSState(
|
||||
"http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/explicitRedirect.sjs",
|
||||
"");
|
||||
|
||||
// ...update the manifest to the third version...
|
||||
OfflineTest.setSJSState(
|
||||
"http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/redirects.sjs",
|
||||
"third");
|
||||
gCurrentManifestVersion = 3;
|
||||
|
||||
// ...and invoke the cache update, now we must get error.
|
||||
applicationCache.update();
|
||||
break;
|
||||
|
||||
case 3:
|
||||
OfflineTest.ok(false, "Update didn't fail for third version of the manifest");
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function manifestError()
|
||||
{
|
||||
switch (gCurrentManifestVersion)
|
||||
{
|
||||
case 1:
|
||||
OfflineTest.ok(false, "Error not expected when caching the first version of the manifest");
|
||||
finish();
|
||||
break;
|
||||
case 2:
|
||||
OfflineTest.ok(false, "Error not expected when updating to second version of the manifest");
|
||||
finish();
|
||||
break;
|
||||
case 3:
|
||||
OfflineTest.ok(true, "Error expected when updating to third version of the manifest");
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function finish()
|
||||
{
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
if (OfflineTest.setup()) {
|
||||
applicationCache.onerror = OfflineTest.priv(manifestError);
|
||||
applicationCache.onupdateready = OfflineTest.priv(manifestUpdated);
|
||||
applicationCache.oncached = OfflineTest.priv(manifestCached);
|
||||
|
||||
// Override sjs redirects on the server, it will now return 200 OK and the content
|
||||
OfflineTest.setSJSState(
|
||||
"http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/explicitRedirect.sjs",
|
||||
"on");
|
||||
OfflineTest.setSJSState(
|
||||
"http://localhost:8888/tests/dom/tests/mochitest/ajax/offline/dynamicRedirect.sjs",
|
||||
"on");
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
|
@ -494,6 +494,13 @@ nsOfflineCacheUpdateItem::OnChannelRedirect(nsIChannel *aOldChannel,
|
|||
nsIChannel *aNewChannel,
|
||||
PRUint32 aFlags)
|
||||
{
|
||||
if (!(aFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) {
|
||||
// Don't allow redirect in case of non-internal redirect and cancel
|
||||
// the channel to clean the cache entry.
|
||||
aOldChannel->Cancel(NS_ERROR_ABORT);
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> newURI;
|
||||
nsresult rv = aNewChannel->GetURI(getter_AddRefs(newURI));
|
||||
if (NS_FAILED(rv))
|
||||
|
@ -502,7 +509,7 @@ nsOfflineCacheUpdateItem::OnChannelRedirect(nsIChannel *aOldChannel,
|
|||
nsCOMPtr<nsICachingChannel> oldCachingChannel =
|
||||
do_QueryInterface(aOldChannel);
|
||||
nsCOMPtr<nsICachingChannel> newCachingChannel =
|
||||
do_QueryInterface(aOldChannel);
|
||||
do_QueryInterface(aNewChannel);
|
||||
if (newCachingChannel) {
|
||||
rv = newCachingChannel->SetCacheForOfflineUse(PR_TRUE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -581,6 +588,42 @@ nsOfflineCacheUpdateItem::GetReadyState(PRUint16 *aReadyState)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsOfflineCacheUpdateItem::GetRequestSucceeded(PRBool * succeeded)
|
||||
{
|
||||
*succeeded = PR_FALSE;
|
||||
|
||||
if (!mChannel)
|
||||
return NS_OK;
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRBool reqSucceeded;
|
||||
rv = httpChannel->GetRequestSucceeded(&reqSucceeded);
|
||||
if (NS_ERROR_NOT_AVAILABLE == rv)
|
||||
return NS_OK;
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!reqSucceeded) {
|
||||
LOG(("Request failed"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult channelStatus;
|
||||
rv = httpChannel->GetStatus(&channelStatus);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (NS_FAILED(channelStatus)) {
|
||||
LOG(("Channel status=0x%08x", channelStatus));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*succeeded = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsOfflineCacheUpdateItem::GetStatus(PRUint16 *aStatus)
|
||||
{
|
||||
|
@ -596,15 +639,6 @@ nsOfflineCacheUpdateItem::GetStatus(PRUint16 *aStatus)
|
|||
PRUint32 httpStatus;
|
||||
rv = httpChannel->GetResponseStatus(&httpStatus);
|
||||
if (rv == NS_ERROR_NOT_AVAILABLE) {
|
||||
// Someone's calling this before we got a response... Check our
|
||||
// ReadyState. If we're at RECEIVING or LOADED, then this means the
|
||||
// connection errored before we got any data; return a somewhat
|
||||
// sensible error code in that case.
|
||||
if (mState >= nsIDOMLoadStatus::RECEIVING) {
|
||||
*aStatus = NS_ERROR_NOT_AVAILABLE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*aStatus = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1241,11 +1275,11 @@ nsOfflineCacheUpdate::HandleManifest(PRBool *aDoUpdate)
|
|||
// Be pessimistic
|
||||
*aDoUpdate = PR_FALSE;
|
||||
|
||||
PRUint16 status;
|
||||
nsresult rv = mManifestItem->GetStatus(&status);
|
||||
PRBool succeeded;
|
||||
nsresult rv = mManifestItem->GetRequestSucceeded(&succeeded);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (status == 0 || status >= 400 || !mManifestItem->ParseSucceeded()) {
|
||||
if (!succeeded || !mManifestItem->ParseSucceeded()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -1375,12 +1409,12 @@ nsOfflineCacheUpdate::LoadCompleted()
|
|||
nsRefPtr<nsOfflineCacheUpdateItem> item = mItems[mCurrentItem];
|
||||
mCurrentItem++;
|
||||
|
||||
PRUint16 status;
|
||||
rv = item->GetStatus(&status);
|
||||
PRBool succeeded;
|
||||
rv = item->GetRequestSucceeded(&succeeded);
|
||||
|
||||
// Check for failures. 4XX and 5XX errors on items explicitly
|
||||
// Check for failures. 3XX, 4XX and 5XX errors on items explicitly
|
||||
// listed in the manifest will cause the update to fail.
|
||||
if (NS_FAILED(rv) || status == 0 || status >= 400) {
|
||||
if (NS_FAILED(rv) || !succeeded) {
|
||||
if (item->mItemType &
|
||||
(nsIApplicationCache::ITEM_EXPLICIT |
|
||||
nsIApplicationCache::ITEM_FALLBACK)) {
|
||||
|
|
|
@ -102,6 +102,7 @@ public:
|
|||
|
||||
nsresult OpenChannel();
|
||||
nsresult Cancel();
|
||||
nsresult GetRequestSucceeded(PRBool * succeeded);
|
||||
|
||||
private:
|
||||
nsOfflineCacheUpdate* mUpdate;
|
||||
|
|
Загрузка…
Ссылка в новой задаче