зеркало из https://github.com/mozilla/pjs.git
Bug 193011: frame recursion limits re-added/docshell limit removed (backout
of bug 98158 and follow-on patches). Also re-fixes bug 98158. r=darin, sr=dbaron
This commit is contained in:
Родитель
ca9574bfda
Коммит
dcdf4824bb
|
@ -60,14 +60,28 @@
|
||||||
|
|
||||||
#include "nsIScriptSecurityManager.h"
|
#include "nsIScriptSecurityManager.h"
|
||||||
|
|
||||||
#include "nsIURI.h"
|
#include "nsIURL.h"
|
||||||
#include "nsNetUtil.h"
|
#include "nsNetUtil.h"
|
||||||
|
|
||||||
#include "nsHTMLAtoms.h"
|
#include "nsHTMLAtoms.h"
|
||||||
#include "nsINameSpaceManager.h"
|
#include "nsINameSpaceManager.h"
|
||||||
|
|
||||||
// Bug 98158: Limit to the number of total docShells in one page.
|
// Bug 136580: Limit to the number of nested content frames that can have the
|
||||||
#define MAX_NUMBER_DOCSHELLS 100
|
// same URL. This is to stop content that is recursively loading
|
||||||
|
// itself. Note that "#foo" on the end of URL doesn't affect
|
||||||
|
// whether it's considered identical, but "?foo" or ";foo" are
|
||||||
|
// considered and compared.
|
||||||
|
#define MAX_SAME_URL_CONTENT_FRAMES 3
|
||||||
|
|
||||||
|
// Bug 8065: Limit content frame depth to some reasonable level. This
|
||||||
|
// does not count chrome frames when determining depth, nor does it
|
||||||
|
// prevent chrome recursion. Number is fairly arbitrary, but meant to
|
||||||
|
// keep number of shells to a reasonable number on accidental recursion with a
|
||||||
|
// small (but not 1) branching factor. With large branching factors the number
|
||||||
|
// of shells can rapidly become huge and run us out of memory. To solve that,
|
||||||
|
// we'd need to re-institute a fixed version of bug 98158.
|
||||||
|
#define MAX_DEPTH_CONTENT_FRAMES 10
|
||||||
|
|
||||||
|
|
||||||
class nsFrameLoader : public nsIFrameLoader
|
class nsFrameLoader : public nsIFrameLoader
|
||||||
{
|
{
|
||||||
|
@ -84,8 +98,6 @@ public:
|
||||||
NS_IMETHOD GetDocShell(nsIDocShell **aDocShell);
|
NS_IMETHOD GetDocShell(nsIDocShell **aDocShell);
|
||||||
NS_IMETHOD Destroy();
|
NS_IMETHOD Destroy();
|
||||||
|
|
||||||
PRInt32 GetDocShellChildCount(nsIDocShellTreeNode *aParentNode);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
nsresult GetPresContext(nsIPresContext **aPresContext);
|
nsresult GetPresContext(nsIPresContext **aPresContext);
|
||||||
nsresult EnsureDocShell();
|
nsresult EnsureDocShell();
|
||||||
|
@ -215,6 +227,98 @@ nsFrameLoader::LoadFrame()
|
||||||
return rv; // We're not
|
return rv; // We're not
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Bug 136580: Check for recursive frame loading
|
||||||
|
// pre-grab these for speed
|
||||||
|
nsCAutoString prepath;
|
||||||
|
nsCAutoString filepath;
|
||||||
|
nsCAutoString query;
|
||||||
|
nsCAutoString param;
|
||||||
|
rv = uri->GetPrePath(prepath);
|
||||||
|
NS_ENSURE_SUCCESS(rv,rv);
|
||||||
|
nsCOMPtr<nsIURL> aURL(do_QueryInterface(uri, &rv)); // QI can fail
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
rv = aURL->GetFilePath(filepath);
|
||||||
|
NS_ENSURE_SUCCESS(rv,rv);
|
||||||
|
rv = aURL->GetQuery(query);
|
||||||
|
NS_ENSURE_SUCCESS(rv,rv);
|
||||||
|
rv = aURL->GetParam(param);
|
||||||
|
NS_ENSURE_SUCCESS(rv,rv);
|
||||||
|
} else {
|
||||||
|
// Not a URL, so punt and just take the whole path. Note that if you
|
||||||
|
// have a self-referential-via-refs non-URL (can't happen via nsSimpleURI,
|
||||||
|
// but could in theory with an external protocol handler) frameset it will
|
||||||
|
// recurse down to the depth limit before stopping, but it will stop.
|
||||||
|
rv = uri->GetPath(filepath);
|
||||||
|
NS_ENSURE_SUCCESS(rv,rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
PRInt32 matchCount = 0;
|
||||||
|
nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
|
||||||
|
nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
|
||||||
|
treeItem->GetParent(getter_AddRefs(parentAsItem));
|
||||||
|
while (parentAsItem) {
|
||||||
|
// Only interested in checking for recursion in content
|
||||||
|
PRInt32 parentType;
|
||||||
|
parentAsItem->GetItemType(&parentType);
|
||||||
|
if (parentType != nsIDocShellTreeItem::typeContent) {
|
||||||
|
break; // Not content
|
||||||
|
}
|
||||||
|
// Check the parent URI with the URI we're loading
|
||||||
|
nsCOMPtr<nsIWebNavigation> parentAsNav(do_QueryInterface(parentAsItem));
|
||||||
|
if (parentAsNav) {
|
||||||
|
// Does the URI match the one we're about to load?
|
||||||
|
nsCOMPtr<nsIURI> parentURI;
|
||||||
|
parentAsNav->GetCurrentURI(getter_AddRefs(parentURI));
|
||||||
|
if (parentURI) {
|
||||||
|
// Bug 98158/193011: We need to ignore data after the #
|
||||||
|
// Note that this code is back-stopped by the maximum-depth checks.
|
||||||
|
|
||||||
|
// Check prepath (foo://blah@bar:port/) and filepath
|
||||||
|
// (/dir/dir/file.ext), but not # extensions.
|
||||||
|
// There's no easy way to get the URI without extension
|
||||||
|
// directly, so check prepath, filepath and query/param (if any)
|
||||||
|
|
||||||
|
// Note that while in theory a CGI could return different data for
|
||||||
|
// the same query string, the spec states that it shouldn't, so
|
||||||
|
// we'll compare queries (and params).
|
||||||
|
nsCAutoString parentPrePath;
|
||||||
|
nsCAutoString parentFilePath;
|
||||||
|
nsCAutoString parentQuery;
|
||||||
|
nsCAutoString parentParam;
|
||||||
|
rv = parentURI->GetPrePath(parentPrePath);
|
||||||
|
NS_ENSURE_SUCCESS(rv,rv);
|
||||||
|
nsCOMPtr<nsIURL> parentURL(do_QueryInterface(parentURI, &rv)); // QI can fail
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
rv = parentURL->GetFilePath(parentFilePath);
|
||||||
|
NS_ENSURE_SUCCESS(rv,rv);
|
||||||
|
rv = parentURL->GetQuery(parentQuery);
|
||||||
|
NS_ENSURE_SUCCESS(rv,rv);
|
||||||
|
rv = parentURL->GetParam(parentParam);
|
||||||
|
NS_ENSURE_SUCCESS(rv,rv);
|
||||||
|
} else {
|
||||||
|
rv = uri->GetPath(filepath);
|
||||||
|
NS_ENSURE_SUCCESS(rv,rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
// filepath will often not match; test it first
|
||||||
|
if (filepath.Equals(parentFilePath) &&
|
||||||
|
query.Equals(parentQuery) &&
|
||||||
|
prepath.Equals(parentPrePath) &&
|
||||||
|
param.Equals(parentParam))
|
||||||
|
{
|
||||||
|
matchCount++;
|
||||||
|
if (matchCount >= MAX_SAME_URL_CONTENT_FRAMES) {
|
||||||
|
NS_WARNING("Too many nested content frames have the same url (recursion?) so giving up");
|
||||||
|
return NS_ERROR_UNEXPECTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nsIDocShellTreeItem* temp = parentAsItem;
|
||||||
|
temp->GetParent(getter_AddRefs(parentAsItem));
|
||||||
|
}
|
||||||
|
|
||||||
// Kick off the load...
|
// Kick off the load...
|
||||||
rv = mDocShell->LoadURI(uri, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE,
|
rv = mDocShell->LoadURI(uri, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE,
|
||||||
PR_FALSE);
|
PR_FALSE);
|
||||||
|
@ -266,28 +370,6 @@ nsFrameLoader::Destroy()
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Count the total number of docshell children in each page.
|
|
||||||
*/
|
|
||||||
PRInt32
|
|
||||||
nsFrameLoader::GetDocShellChildCount(nsIDocShellTreeNode* aParentNode)
|
|
||||||
{
|
|
||||||
PRInt32 retval = 1;
|
|
||||||
|
|
||||||
PRInt32 childCount;
|
|
||||||
PRInt32 i;
|
|
||||||
aParentNode->GetChildCount(&childCount);
|
|
||||||
for(i=0;i<childCount;i++)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIDocShellTreeItem> child;
|
|
||||||
aParentNode->GetChildAt(i,getter_AddRefs(child));
|
|
||||||
nsCOMPtr<nsIDocShellTreeNode> childAsNode(do_QueryInterface(child));
|
|
||||||
retval += GetDocShellChildCount(childAsNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsFrameLoader::GetPresContext(nsIPresContext **aPresContext)
|
nsFrameLoader::GetPresContext(nsIPresContext **aPresContext)
|
||||||
{
|
{
|
||||||
|
@ -325,26 +407,36 @@ nsFrameLoader::EnsureDocShell()
|
||||||
GetPresContext(getter_AddRefs(presContext));
|
GetPresContext(getter_AddRefs(presContext));
|
||||||
NS_ENSURE_TRUE(presContext, NS_ERROR_UNEXPECTED);
|
NS_ENSURE_TRUE(presContext, NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
|
// Bug 8065: Don't exceed some maximum depth in content frames
|
||||||
|
// (MAX_DEPTH_CONTENT_FRAMES)
|
||||||
|
PRInt32 depth = 0;
|
||||||
nsCOMPtr<nsISupports> parentAsSupports;
|
nsCOMPtr<nsISupports> parentAsSupports;
|
||||||
presContext->GetContainer(getter_AddRefs(parentAsSupports));
|
presContext->GetContainer(getter_AddRefs(parentAsSupports));
|
||||||
|
|
||||||
// bug98158:count the children under the root docshell.
|
|
||||||
// if the total number of children under the root docshell
|
|
||||||
// beyond the limit,return a error.
|
|
||||||
if (parentAsSupports) {
|
if (parentAsSupports) {
|
||||||
nsCOMPtr<nsIDocShellTreeItem> parentAsItem = do_QueryInterface(parentAsSupports);
|
nsCOMPtr<nsIDocShellTreeItem> parentAsItem =
|
||||||
|
do_QueryInterface(parentAsSupports);
|
||||||
|
|
||||||
nsCOMPtr<nsIDocShellTreeItem> root;
|
while (parentAsItem) {
|
||||||
parentAsItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
|
++depth;
|
||||||
|
|
||||||
nsCOMPtr<nsIDocShellTreeNode> rootNode(do_QueryInterface(root));
|
if (depth >= MAX_DEPTH_CONTENT_FRAMES) {
|
||||||
|
NS_WARNING("Too many nested content frames so giving up");
|
||||||
|
|
||||||
PRInt32 childrenCount;
|
return NS_ERROR_UNEXPECTED; // Too deep, give up! (silently?)
|
||||||
childrenCount = GetDocShellChildCount(rootNode);
|
}
|
||||||
|
|
||||||
if(childrenCount >= MAX_NUMBER_DOCSHELLS) {
|
// Only count depth on content, not chrome.
|
||||||
NS_WARNING("Too many docshell (recursion?) so giving up");
|
// If we wanted to limit total depth, skip the following check:
|
||||||
return NS_ERROR_FAILURE;
|
PRInt32 parentType;
|
||||||
|
parentAsItem->GetItemType(&parentType);
|
||||||
|
|
||||||
|
if (nsIDocShellTreeItem::typeContent == parentType) {
|
||||||
|
nsIDocShellTreeItem* temp = parentAsItem;
|
||||||
|
temp->GetParent(getter_AddRefs(parentAsItem));
|
||||||
|
} else {
|
||||||
|
break; // we have exited content, stop counting, depth is OK!
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче