rework etld backend to use a flat hash instead of a tree-hash structure, to reduce memory consumption and eliminate shutdown leaks. bugs 386154 and 386155,

r=biesi
This commit is contained in:
dwitte@stanford.edu 2007-07-25 23:31:49 -07:00
parent c5a45de9ac
commit 4e978ce217
2 changed files with 226 additions and 362 deletions

View File

@ -1,4 +1,4 @@
//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
//* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -21,6 +21,7 @@
*
* Contributor(s):
* Pamela Greene <pamg.bugs@gmail.com> (original author)
* Daniel Witte <dwitte@stanford.edu>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -42,14 +43,12 @@
#include "nsEffectiveTLDService.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsDataHashtable.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsFileStreams.h"
#include "nsIFile.h"
#include "nsIIDNService.h"
#include "nsNetUtil.h"
#include "nsString.h"
// The file name of the list of TLD-like names. A file with this name in the
// system "res" directory will always be used. In addition, if a file with
@ -57,156 +56,60 @@
// also be used, as though those rules were appended to the system file.
#define EFF_TLD_FILENAME NS_LITERAL_CSTRING("effective_tld_names.dat")
// Define this as nonzero to eanble logging of the tree state after the file has
// been loaded.
#define EFF_TLD_SERVICE_DEBUG 0
/*
The list of subdomain rules is stored as a wide tree of SubdomainNodes,
primarily to facilitate multiple levels of wildcards. Each node represents
one level of a particular rule in the list, and stores meta-information about
the rule it represents as well as a list (hash) of all the subdomains beneath
it.
stopOK: If true, this node marks the end of a rule.
exception: If true, this node marks the end of an exception rule.
For example, if the effective-TLD list contains
foo.com
*.bar.com
!baz.bar.com
then the subdomain tree will look like this (conceptually; the actual order
of the nodes in the hashes is not guaranteed):
+--------------+
| com |
| exception: 0 | +--------------+
| stopOK: 0 | | foo |
| children ----|------> | exception: 0 |
+--------------+ | stopOK: 1 |
| children |
+--------------+
| bar |
| exception: 0 | +--------------+
| stopOK: 0 | | * |
| children ----|------> | exception: 0 |
+--------------+ | stopOK: 1 |
| children |
+--------------+
| baz |
| exception: 1 |
| stopOK: 1 |
| children |
+--------------+
*/
struct SubdomainNode;
typedef nsDataHashtable<nsCStringHashKey, SubdomainNode *> SubdomainNodeHash;
struct SubdomainNode {
PRBool exception;
PRBool stopOK;
SubdomainNodeHash children;
};
static void EmptyEffectiveTLDTree();
static nsresult LoadEffectiveTLDFiles();
static nsresult NormalizeHostname(nsCString &aHostname);
static PRInt32 FindEarlierDot(const nsACString &aHostname, PRInt32 aDotLoc);
static SubdomainNode *FindMatchingChildNode(SubdomainNode *parent,
const nsCSubstring &aSubname,
PRBool aCreateNewNode);
nsEffectiveTLDService* nsEffectiveTLDService::sInstance = nsnull;
static SubdomainNode sSubdomainTreeHead;
NS_IMPL_ISUPPORTS1(nsEffectiveTLDService, nsIEffectiveTLDService)
// ----------------------------------------------------------------------
#if defined(EFF_TLD_SERVICE_DEBUG) && EFF_TLD_SERVICE_DEBUG
// LOG_EFF_TLD_NODE
//
// If debugging is enabled, this function is called by LOG_EFF_TLD_TREE to
// recursively print the current state of the effective-TLD tree.
PR_STATIC_CALLBACK(PLDHashOperator)
LOG_EFF_TLD_NODE(const nsACString& aKey, SubdomainNode *aData, void *aLevel)
#define PL_ARENA_CONST_ALIGN_MASK 3
#include "plarena.h"
static PLArenaPool *gArena = nsnull;
#define ARENA_SIZE 512
// equivalent to strdup() - does no error checking,
// we're assuming we're only called with a valid pointer
static char *
ArenaStrDup(const char* str, PLArenaPool* aArena)
{
// Dump this node's information.
PRInt32 *level = (PRInt32 *) aLevel;
for (PRInt32 i = 0; i < *level; i++) printf("-");
if (aData->exception) printf("!");
if (aData->stopOK) printf("^");
printf("'%s'\n", PromiseFlatCString(aKey).get());
// Dump its children's information.
PRInt32 newlevel = (*level) + 1;
aData->children.EnumerateRead(LOG_EFF_TLD_NODE, &newlevel);
return PL_DHASH_NEXT;
void *mem;
PRUint32 size = strlen(str) + 1;
PL_ARENA_ALLOCATE(mem, aArena, size);
if (mem)
memcpy(mem, str, size);
return static_cast<char*>(mem);
}
#endif // EFF_TLD_SERVICE_DEBUG
// LOG_EFF_TLD_TREE
//
// If debugging is enabled, prints the current state of the effective-TLD tree.
void LOG_EFF_TLD_TREE(const char *msg = "",
SubdomainNode *head = &sSubdomainTreeHead)
nsDomainEntry::nsDomainEntry(const char *aDomain)
: mDomain(ArenaStrDup(aDomain, gArena))
, mIsNormal(PR_FALSE)
, mIsException(PR_FALSE)
, mIsWild(PR_FALSE)
{
#if defined(EFF_TLD_SERVICE_DEBUG) && EFF_TLD_SERVICE_DEBUG
if (msg && msg != "")
printf("%s\n", msg);
PRInt32 level = 0;
head->children.EnumerateRead(LOG_EFF_TLD_NODE, &level);
#endif // EFF_TLD_SERVICE_DEBUG
return;
}
// ----------------------------------------------------------------------
// nsEffectiveTLDService::Init
//
// Initializes the root subdomain node and loads the effective-TLD file.
// Returns NS_OK upon successful completion, propagated errors if any were
// encountered during the loading of the file and construction of the
// effective-TLD tree.
nsresult
nsEffectiveTLDService::Init()
{
sSubdomainTreeHead.exception = PR_FALSE;
sSubdomainTreeHead.stopOK = PR_FALSE;
nsresult rv = NS_OK;
if (!sSubdomainTreeHead.children.Init())
rv = NS_ERROR_OUT_OF_MEMORY;
if (!mHash.Init())
return NS_ERROR_OUT_OF_MEMORY;
if (NS_SUCCEEDED(rv))
rv = LoadEffectiveTLDFiles();
// In the event of an error, clear any partially constructed tree.
if (NS_FAILED(rv))
EmptyEffectiveTLDTree();
return rv;
return LoadEffectiveTLDFiles();
}
// nsEffectiveTLDService::nsEffectiveTLDService
//
nsEffectiveTLDService::nsEffectiveTLDService()
{
NS_ASSERTION(!sInstance, "Multiple effective-TLD services being created");
sInstance = this;
}
// nsEffectiveTLDService::~nsEffectiveTLDService
//
nsEffectiveTLDService::~nsEffectiveTLDService()
{
NS_ASSERTION(sInstance == this, "Multiple effective-TLD services exist");
EmptyEffectiveTLDTree();
sInstance = nsnull;
if (gArena) {
PL_FinishArenaPool(gArena);
delete gArena;
}
gArena = nsnull;
}
// nsEffectiveTLDService::getEffectiveTLDLength
@ -218,21 +121,6 @@ NS_IMETHODIMP
nsEffectiveTLDService::GetEffectiveTLDLength(const nsACString &aHostname,
PRUint32 *effTLDLength)
{
// Calcluate a default length: either the level-0 TLD, or the whole string
// length if no dots are present. Make sure to ignore the trailing dot if one
// is there.
PRInt32 nameLength = aHostname.Length();
PRInt32 trailingDotOffset = (nameLength && aHostname.Last() == '.' ? 1 : 0);
PRInt32 defaultTLDLength;
PRInt32 dotLoc = FindEarlierDot(aHostname, nameLength - 1 - trailingDotOffset);
if (dotLoc < 0) {
defaultTLDLength = nameLength;
}
else {
defaultTLDLength = nameLength - dotLoc - 1;
}
*effTLDLength = static_cast<PRUint32>(defaultTLDLength);
// Create a mutable copy of the hostname and normalize it. This will fail
// if the hostname includes invalid characters.
nsCAutoString normHostname(aHostname);
@ -240,234 +128,127 @@ nsEffectiveTLDService::GetEffectiveTLDLength(const nsACString &aHostname,
if (NS_FAILED(rv))
return rv;
// Walk the domain tree looking for matches at each level.
SubdomainNode *node = &sSubdomainTreeHead;
dotLoc = nameLength - trailingDotOffset;
while (dotLoc > 0) {
PRInt32 nextDotLoc = FindEarlierDot(normHostname, dotLoc - 1);
const nsCSubstring &subname = Substring(normHostname, nextDotLoc + 1,
dotLoc - nextDotLoc - 1);
SubdomainNode *child = FindMatchingChildNode(node, subname, false);
if (nsnull == child)
break;
if (child->exception) {
// Exception rules use one fewer levels than were matched.
*effTLDLength = static_cast<PRUint32>(nameLength - dotLoc - 1);
node = child;
// chomp any trailing dot, and remember to add it back later
PRUint32 trailingDot = normHostname.Last() == '.';
if (trailingDot)
normHostname.Truncate(normHostname.Length() - 1);
// walk up the domain tree, most specific to least specific,
// looking for matches at each level. note that a given level may
// have multiple attributes (e.g. IsWild() and IsNormal()).
const char *prevDomain = nsnull;
const char *currDomain = normHostname.get();
const char *nextDot = strchr(currDomain, '.');
const char *end = currDomain + normHostname.Length();
while (1) {
if (!nextDot) {
// we've hit the top domain level; return it by default.
*effTLDLength = end - currDomain;
break;
}
// For a normal match, save the location of the last stop, in case we find
// a non-stop match followed by a non-match further along.
if (child->stopOK)
*effTLDLength = static_cast<PRUint32>(nameLength - nextDotLoc - 1);
node = child;
dotLoc = nextDotLoc;
nsDomainEntry *entry = mHash.GetEntry(currDomain);
if (entry) {
if (entry->IsWild() && prevDomain) {
// wildcard rules imply an eTLD one level inferior to the match.
*effTLDLength = end - prevDomain;
break;
} else if (entry->IsNormal()) {
// specific match
*effTLDLength = end - currDomain;
break;
} else if (entry->IsException()) {
// exception rules imply an eTLD one level superior to the match.
*effTLDLength = end - nextDot - 1;
break;
}
}
prevDomain = currDomain;
currDomain = nextDot + 1;
nextDot = strchr(currDomain, '.');
}
// add on the trailing dot, if applicable
*effTLDLength += trailingDot;
return NS_OK;
}
// ----------------------------------------------------------------------
PR_STATIC_CALLBACK(PLDHashOperator)
DeleteSubdomainNode(const nsACString& aKey, SubdomainNode *aData, void *aUser)
{
// Neither aData nor its children should ever be null in a properly
// constructed tree, but this function may also be called to clear a tree
// that encountered errors during initialization.
if (nsnull != aData && aData->children.IsInitialized()) {
// Delete this node's descendants.
aData->children.EnumerateRead(DeleteSubdomainNode, nsnull);
// Delete this node's hash of children.
aData->children.Clear();
}
return PL_DHASH_NEXT;
}
// EmptyEffectiveTLDTree
//
// Release the memory allocated by the static effective-TLD tree and reset the
// semaphore to indicate that the tree is not loaded.
void
EmptyEffectiveTLDTree()
{
if (sSubdomainTreeHead.children.IsInitialized()) {
sSubdomainTreeHead.children.EnumerateRead(DeleteSubdomainNode, nsnull);
sSubdomainTreeHead.children.Clear();
}
return;
}
// NormalizeHostname
//
// Normalizes characters of hostname. ASCII names are lower-cased, and names
// using other characters are normalized with nsIIDNService::Normalize, which
// follows RFC 3454.
nsresult NormalizeHostname(nsCString &aHostname)
nsresult
nsEffectiveTLDService::NormalizeHostname(nsCString &aHostname)
{
nsresult rv = NS_OK;
if (IsASCII(aHostname)) {
ToLowerCase(aHostname);
}
else {
nsCOMPtr<nsIIDNService> idnServ = do_GetService(NS_IDNSERVICE_CONTRACTID);
if (idnServ)
rv = idnServ->Normalize(aHostname, aHostname);
return NS_OK;
}
return rv;
}
// ----------------------------------------------------------------------
// FillStringInformation
//
// Fills a start pointer and length for the given string.
void
FillStringInformation(const nsACString &aString, const char **start,
PRUint32 *length)
{
nsACString::const_iterator iter;
aString.BeginReading(iter);
*start = iter.get();
*length = iter.size_forward();
return;
}
// FindEarlierDot
//
// Finds the byte location of the next dot (.) at or earlier in the string than
// the given aDotLoc. Returns -1 if no more dots are found.
PRInt32
FindEarlierDot(const nsACString &aHostname, PRInt32 aDotLoc)
{
if (aDotLoc < 0)
return -1;
// Searching for '.' one byte at a time is fine since UTF-8 is a superset of
// 7-bit ASCII.
const char *start;
PRUint32 length;
FillStringInformation(aHostname, &start, &length);
PRInt32 endLoc = length - 1;
if (aDotLoc < endLoc)
endLoc = aDotLoc;
for (const char *where = start + endLoc; where >= start; --where) {
if (*where == '.')
return (where - start);
if (!mIDNService) {
nsresult rv;
mIDNService = do_GetService(NS_IDNSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
}
return -1;
}
// FindEndOfName
//
// Finds the byte loaction of the first space or tab in the string, or the
// length of the string (i.e., one past its end) if no spaces or tabs are found.
PRInt32
FindEndOfName(const nsACString &aHostname) {
// Searching for a space or tab one byte at a time is fine since UTF-8 is a
// superset of 7-bit ASCII.
const char *start;
PRUint32 length;
FillStringInformation(aHostname, &start, &length);
for (const char *where = start; where < start + length; ++where) {
if (*where == ' ' || *where == '\t')
return (where - start);
}
return length;
}
// FindMatchingChildNode
//
// Given a parent node and a candidate subname, searches the parent's children
// for a matching subdomain and returns a pointer to the matching node if one
// was found. If no exact match was found and aCreateNewNode is true, creates
// a new child node for the given subname and returns that, or nsnull if an
// error was encountered (typically because of memory allocation failure) while
// creating the new child.
//
// If no exact match was found and aCreateNewNode is false, looks for a
// wildcard node (*) instead. If no wildcard node is found either, returns
// nsnull.
//
// Typically, aCreateNewNode will be true when the subdomain tree is being
// built, and false when it is being searched to determine a hostname's
// effective TLD.
SubdomainNode *
FindMatchingChildNode(SubdomainNode *parent, const nsCSubstring &aSubname,
PRBool aCreateNewNode)
{
// Make a mutable copy of the name in case we need to strip ! from the start.
nsCAutoString name(aSubname);
PRBool exception = PR_FALSE;
// Is this node an exception?
if (name.Length() > 0 && name.First() == '!') {
exception = PR_TRUE;
name.Cut(0, 1);
}
// Look for an exact match.
SubdomainNode *result = nsnull;
SubdomainNode *match;
if (parent->children.Get(name, &match)) {
result = match;
}
// If the subname wasn't found, optionally create it.
else if (aCreateNewNode) {
SubdomainNode *node = new SubdomainNode;
if (node) {
node->exception = exception;
node->stopOK = PR_FALSE;
if (node->children.Init() && parent->children.Put(name, node))
result = node;
}
}
// Otherwise, if we're not making new nodes, look for a wildcard child.
else if (parent->children.Get(NS_LITERAL_CSTRING("*"), &match)) {
result = match;
}
return result;
return mIDNService->Normalize(aHostname, aHostname);
}
// AddEffectiveTLDEntry
//
// Adds the given domain name rule to the effective-TLD tree.
// Adds the given domain name rule to the effective-TLD hash.
//
// CAUTION: As a side effect, the domain name rule will be normalized: in the
// case of ASCII, it will be lower-cased; otherwise, it will be normalized as
// an IDN.
// CAUTION: As a side effect, the domain name rule will be normalized.
// see NormalizeHostname().
nsresult
AddEffectiveTLDEntry(nsCString &aDomainName) {
SubdomainNode *node = &sSubdomainTreeHead;
nsEffectiveTLDService::AddEffectiveTLDEntry(nsCString &aDomainName)
{
// lazily init the arena pool
if (!gArena) {
gArena = new PLArenaPool;
NS_ENSURE_TRUE(gArena, NS_ERROR_OUT_OF_MEMORY);
PL_INIT_ARENA_POOL(gArena, "eTLDArena", ARENA_SIZE);
}
PRBool isException = PR_FALSE, isWild = PR_FALSE;
// Is this node an exception?
if (aDomainName.First() == '!') {
isException = PR_TRUE;
aDomainName.Cut(0, 1);
// ... or wild?
} else if (StringBeginsWith(aDomainName, NS_LITERAL_CSTRING("*."))) {
isWild = PR_TRUE;
aDomainName.Cut(0, 2);
NS_ASSERTION(!StringBeginsWith(aDomainName, NS_LITERAL_CSTRING("*.")),
"only one wildcard level supported!");
}
// Normalize the domain name.
nsresult rv = NormalizeHostname(aDomainName);
NS_ENSURE_SUCCESS(rv, rv);
PRInt32 dotLoc = FindEndOfName(aDomainName);
while (dotLoc > 0) {
PRInt32 nextDotLoc = FindEarlierDot(aDomainName, dotLoc - 1);
const nsCSubstring &subname = Substring(aDomainName, nextDotLoc + 1,
dotLoc - nextDotLoc - 1);
dotLoc = nextDotLoc;
node = FindMatchingChildNode(node, subname, true);
if (!node)
return NS_ERROR_OUT_OF_MEMORY;
nsDomainEntry *entry = mHash.PutEntry(aDomainName.get());
NS_ENSURE_TRUE(entry, NS_ERROR_FAILURE);
// check for arena string alloc failure
if (!entry->GetKey()) {
mHash.RawRemoveEntry(entry);
return NS_ERROR_OUT_OF_MEMORY;
}
// The last node in an entry is by definition a stop-OK node.
node->stopOK = true;
// add the new flags, without stomping existing ones
entry->IsWild() |= isWild;
entry->IsException() |= isException;
// note: isWild also implies isNormal (e.g. *.co.nz also implies the co.nz eTLD)
entry->IsNormal() |= isWild || !isException;
return NS_OK;
}
@ -516,12 +297,29 @@ LocateEffectiveTLDFile(nsCOMPtr<nsIFile>& foundFile, PRBool aUseProfile)
return rv;
}
void
TruncateAtWhitespace(nsCString &aString)
{
// Searching for a space or tab one byte at a time is fine since UTF-8 is a
// superset of 7-bit ASCII.
nsASingleFragmentCString::const_char_iterator begin, iter, end;
aString.BeginReading(begin);
aString.EndReading(end);
for (iter = begin; iter != end; ++iter) {
if (*iter == ' ' || *iter == '\t') {
aString.Truncate(iter - begin);
break;
}
}
}
// LoadOneEffectiveTLDFile
//
// Loads the contents of the given effective-TLD file, building the tree as it
// goes.
nsresult
LoadOneEffectiveTLDFile(nsCOMPtr<nsIFile>& effTLDFile)
nsEffectiveTLDService::LoadOneEffectiveTLDFile(nsCOMPtr<nsIFile>& effTLDFile)
{
// Open the file as an input stream.
nsCOMPtr<nsIInputStream> fileStream;
@ -536,34 +334,30 @@ LoadOneEffectiveTLDFile(nsCOMPtr<nsIFile>& effTLDFile)
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString lineData;
PRBool moreData = PR_TRUE;
NS_NAMED_LITERAL_CSTRING(commentMarker, "//");
while (moreData) {
rv = lineStream->ReadLine(lineData, &moreData);
if (NS_SUCCEEDED(rv)) {
if (! lineData.IsEmpty() &&
! StringBeginsWith(lineData, commentMarker)) {
rv = AddEffectiveTLDEntry(lineData);
}
}
else {
NS_WARNING("Error reading effective-TLD file; attempting to continue");
PRBool isMore;
NS_NAMED_LITERAL_CSTRING(kCommentMarker, "//");
while (NS_SUCCEEDED(lineStream->ReadLine(lineData, &isMore)) && isMore) {
if (StringBeginsWith(lineData, kCommentMarker))
continue;
TruncateAtWhitespace(lineData);
if (!lineData.IsEmpty()) {
rv = AddEffectiveTLDEntry(lineData);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Error adding effective TLD to list");
}
}
LOG_EFF_TLD_TREE("Effective-TLD tree:");
return rv;
return NS_OK;
}
// LoadEffectiveTLDFiles
//
// Loads the contents of the system and user effective-TLD files.
nsresult
LoadEffectiveTLDFiles()
nsEffectiveTLDService::LoadEffectiveTLDFiles()
{
nsCOMPtr<nsIFile> effTLDFile;
nsresult rv = LocateEffectiveTLDFile(effTLDFile, false);
nsresult rv = LocateEffectiveTLDFile(effTLDFile, PR_FALSE);
// If we didn't find any system effective-TLD file, warn but keep trying. We
// can struggle along using the base TLDs.
@ -575,7 +369,7 @@ LoadEffectiveTLDFiles()
NS_ENSURE_SUCCESS(rv, rv);
}
rv = LocateEffectiveTLDFile(effTLDFile, true);
rv = LocateEffectiveTLDFile(effTLDFile, PR_TRUE);
// Since the profile copy isn't strictly needed, ignore any errors trying to
// find or read it, in order to allow testing using xpcshell.

View File

@ -1,4 +1,4 @@
//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
//* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -38,6 +38,69 @@
#include "nsIEffectiveTLDService.h"
#include "nsTHashtable.h"
#include "nsString.h"
#include "nsCOMPtr.h"
class nsIIDNService;
class nsIFile;
// hash entry class
class nsDomainEntry : public PLDHashEntryHdr
{
public:
// Hash methods
typedef const char* KeyType;
typedef const char* KeyTypePointer;
nsDomainEntry(const char* aDomain);
nsDomainEntry(const nsDomainEntry& toCopy)
{
// if we end up here, things will break. nsTHashtable shouldn't
// allow this, since we set ALLOW_MEMMOVE to true.
NS_NOTREACHED("nsDomainEntry copy constructor is forbidden!");
}
~nsDomainEntry()
{
}
KeyType GetKey() const
{
return mDomain;
}
PRBool KeyEquals(KeyTypePointer aKey) const
{
return !strcmp(mDomain, aKey);
}
static KeyTypePointer KeyToPointer(KeyType aKey)
{
return aKey;
}
static PLDHashNumber HashKey(KeyTypePointer aKey)
{
// PL_DHashStringKey doesn't use the table parameter, so we can safely
// pass nsnull
return PL_DHashStringKey(nsnull, aKey);
}
enum { ALLOW_MEMMOVE = PR_TRUE };
PRPackedBool& IsNormal() { return mIsNormal; }
PRPackedBool& IsException() { return mIsException; }
PRPackedBool& IsWild() { return mIsWild; }
private:
const char *mDomain;
PRPackedBool mIsNormal;
PRPackedBool mIsException;
PRPackedBool mIsWild;
};
class nsEffectiveTLDService : public nsIEffectiveTLDService
{
public:
@ -48,6 +111,13 @@ public:
nsresult Init();
private:
static nsEffectiveTLDService* sInstance;
~nsEffectiveTLDService();
nsresult NormalizeHostname(nsCString &aHostname);
nsresult AddEffectiveTLDEntry(nsCString &aDomainName);
nsresult LoadEffectiveTLDFiles();
nsresult LoadOneEffectiveTLDFile(nsCOMPtr<nsIFile>& effTLDFile);
virtual ~nsEffectiveTLDService();
nsTHashtable<nsDomainEntry> mHash;
nsCOMPtr<nsIIDNService> mIDNService;
};