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:
rjesup%wgate.com 2003-08-08 13:06:40 +00:00
Родитель ca9574bfda
Коммит dcdf4824bb
1 изменённых файлов: 131 добавлений и 39 удалений

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

@ -60,14 +60,28 @@
#include "nsIScriptSecurityManager.h"
#include "nsIURI.h"
#include "nsIURL.h"
#include "nsNetUtil.h"
#include "nsHTMLAtoms.h"
#include "nsINameSpaceManager.h"
// Bug 98158: Limit to the number of total docShells in one page.
#define MAX_NUMBER_DOCSHELLS 100
// Bug 136580: Limit to the number of nested content frames that can have the
// 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
{
@ -84,8 +98,6 @@ public:
NS_IMETHOD GetDocShell(nsIDocShell **aDocShell);
NS_IMETHOD Destroy();
PRInt32 GetDocShellChildCount(nsIDocShellTreeNode *aParentNode);
protected:
nsresult GetPresContext(nsIPresContext **aPresContext);
nsresult EnsureDocShell();
@ -215,6 +227,98 @@ nsFrameLoader::LoadFrame()
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...
rv = mDocShell->LoadURI(uri, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE,
PR_FALSE);
@ -266,28 +370,6 @@ nsFrameLoader::Destroy()
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
nsFrameLoader::GetPresContext(nsIPresContext **aPresContext)
{
@ -325,26 +407,36 @@ nsFrameLoader::EnsureDocShell()
GetPresContext(getter_AddRefs(presContext));
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;
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) {
nsCOMPtr<nsIDocShellTreeItem> parentAsItem = do_QueryInterface(parentAsSupports);
nsCOMPtr<nsIDocShellTreeItem> parentAsItem =
do_QueryInterface(parentAsSupports);
nsCOMPtr<nsIDocShellTreeItem> root;
parentAsItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
while (parentAsItem) {
++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;
childrenCount = GetDocShellChildCount(rootNode);
return NS_ERROR_UNEXPECTED; // Too deep, give up! (silently?)
}
if(childrenCount >= MAX_NUMBER_DOCSHELLS) {
NS_WARNING("Too many docshell (recursion?) so giving up");
return NS_ERROR_FAILURE;
// Only count depth on content, not chrome.
// If we wanted to limit total depth, skip the following check:
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!
}
}
}