Getting a 'base' Domain from a Domain
Here's a simple one: How do you reliably get the base domain from full domain name or URI? Specifically I've run into this scenario in a few recent applications when creating the Forms Auth Cookie in my ASP.NET applications where I explicitly need to force the domain name to the common base domain. So, www.west-wind.com, store.west-wind.com, west-wind.com, dev.west-wind.com all should return west-wind.com.
Here's the code where I need to use this type of logic for issuing an AuthTicket explicitly:
private void IssueAuthTicket(UserState userState, bool rememberMe) { FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, userState.UserId, DateTime.Now, DateTime.Now.AddDays(10), rememberMe, userState.ToString()); string ticketString = FormsAuthentication.Encrypt(ticket); HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, ticketString); cookie.HttpOnly = true; if (rememberMe) cookie.Expires = DateTime.Now.AddDays(10); // write out a domain cookie cookie.Domain = Request.Url.GetBaseDomain(); HttpContext.Response.Cookies.Add(cookie); }
Now unfortunately there's no Uri.GetBaseDomain() method unfortunately, as I was surprised to find out. So I ended up creating one:
public static class NetworkUtils { /// <summary> /// Retrieves a base domain name from a full domain name. /// For example: www.west-wind.com produces west-wind.com /// </summary> /// <param name="domainName">Dns Domain name as a string</param> /// <returns></returns> public static string GetBaseDomain(string domainName) { var tokens = domainName.Split('.'); // only split 3 segments like www.west-wind.com if (tokens == null || tokens.Length != 3) return domainName; var tok = new List<string>(tokens); var remove = tokens.Length - 2; tok.RemoveRange(0, remove); return tok[0] + "." + tok[1]; ; } /// <summary> /// Returns the base domain from a domain name /// Example: http://www.west-wind.com returns west-wind.com /// </summary> /// <param name="uri"></param> /// <returns></returns> public static string GetBaseDomain(this Uri uri) { if (uri.HostNameType == UriHostNameType.Dns) return GetBaseDomain(uri.DnsSafeHost); return uri.Host; } }
I've had a need for this so frequently it warranted a couple of helpers. The second Uri helper is an Extension method to the Uri class, which is what's used the in the first code sample. This is the preferred way to call this since the URI class can differentiate between Dns names and IP Addresses. If you use the first string based version there's a little more guessing going on if a URL is an IP Address.
There are a couple of small twists in dealing with 'domain names'. When passing a string only there's a possibility to not actually pass domain name, but end up passing an IP address, so the code explicitly checks for three domain segments (can there be more than 3?). IP4 Addresses have 4 and IP6 have none so they'll fall through. Then there are things like localhost or a NetBios machine name which also come back on URL strings, but also shouldn't be handled.
Anyway, small thing but maybe somebody else will find this useful.
The Voices of Reason
# re: Getting a 'base' Domain from a Domain
For now this will work for me, since I'm working with a known set of domains. Heck, maybe it's even easier to just put a CookieDomain config flag and make it configurable.
But I wonder if there would be some 'safe' way to figure out the base domain?
# re: Getting a 'base' Domain from a Domain
:)
# re: Getting a 'base' Domain from a Domain
You certainly can't reliably figure this out using only string manipulation - you have to ask the DNS records.
# re: Getting a 'base' Domain from a Domain
var domainString = "www.mirror.co.uk"; var RE_RootDomain = new Regex(@"([\w\d\-]{2,}\.(?:co.uk|[\w]{2,}))$", RegexOptions.IgnoreCase); if (RE_RootDomain.IsMatch(domainString)){ var rootDomain = RE_RootDomain.Match(domainString).Groups[1].Value; }
Matched "co.uk" as TLD.
TLD must be at least 2 chr. or "co.uk".
Domain without TLD must be at least 2 chr.
# re: Getting a 'base' Domain from a Domain
internal static string GetBaseDomain( this Uri uri )
{
//see for more: http://data.iana.org/TLD/tlds-alpha-by-domain.txt
var tld = new[] { ".nl" , ".be" , ".de" , ".eu" , ".fr" , ".com" , ".net" , ".info" , ".org" , ".biz" , ".co.uk" , ".nu" , ".tv" } ;
for ( int i = 0 ; i < tld.Length ; i++ )
{
if ( uri.Host.EndsWith( tld[ i ] ) )
{
int dot = uri.Host.Substring( 0 , uri.Host.Length - tld[ i ].Length ).LastIndexOf( '.' ) ;
//if dot equals -1 (when '.' is not found) +1 will bump to 0 (for example if host equals test.com)
//if dot greater than or equal 0 (when '.' is found) +1 will exclude the '.' (for eaxmple if host equals www.test.com)
return uri.Host.Substring( dot + 1 ) ;
}
}
return uri.Host;
}
# re: Getting a 'base' Domain from a Domain
# re: Getting a 'base' Domain from a Domain
# re: Getting a 'base' Domain from a Domain
# re: Getting a 'base' Domain from a Domain
There's a list maintained at http://publicsuffix.org/ which contains a lot of rules for domains (Filip W pointed to a copy of this within some source code from Mozilla in an earlier comment). There used to be a rule engine implementation on a google code site which was taken down (though is still available at www.softpedia.com/progDownload/DomainNameParser-Download-137099.html). Not sure why the original implementation was taken down, but there are another couple of implementations on github: https://github.com/interlinkone/interlinkONE.PublicSuffix (I've not tested this).
# re: Getting a 'base' Domain from a Domain
Uri myUri = new Uri("http://forums.asp.net/t/1110512.aspx?");
string host = myUri.Host;
more methods to get domain name...
http://net-informations.com/faq/asp/domain.htm
steve
# re: Getting a 'base' Domain from a Domain