Contact   •   Products   •   Search

Rick Strahl's Web Log

Wind, waves, code and everything in between...
ASP.NET • C# • HTML5 • JavaScript • AngularJs

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.

Make Donation
Posted in ASP.NET  Networking  


Feedback for this Post

 
# re: Getting a 'base' Domain from a Domain
by Prescott April 25, 2012 @ 12:05am
There could be more than 3 - I logged into my hotmail account: http://col108.mail.live.com
# re: Getting a 'base' Domain from a Domain
by Rick Strahl April 25, 2012 @ 12:11am
Yup - several people commented on that on twitter as well. There are also things like myDomain.co.uk which would be valid.

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
by Filip W April 25, 2012 @ 12:56am
Rick, now all you need to do is extended these helpers to facilitate this list http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1

:)
# re: Getting a 'base' Domain from a Domain
by James Hart April 25, 2012 @ 6:03am
I think the closest concept DNS has to the 'base domain' that you seem to be after is probably the 'start of authority', or SOA record. You can query a DNS server for the SOA record for a hostname, and it should return a record indicating at what level in the name hierarchy that hostname is defined. If you query SOA for www.west-wind.com, for example, it tells you that west-wind.com is the SOA. For Prescott's col108.mail.live.com, the SOA record is at live.com. For www.somedomain.co.uk it would be somedomain.co.uk. For www.boston.k12.ma.us (a school district website) it returns boston.k12.ma.us.

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
by Carsten Petersen April 25, 2012 @ 8:44am
It might be better to use a Regex to find the most general "formats". It would be something like:

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
by Sander April 26, 2012 @ 12:55am
needed something similar, ended up with this:

        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
by Rick Strahl April 26, 2012 @ 12:59am
@Sander - yes, that looks good. I was thinking if I need more than the simple specific domains I'm dealing with then a white list of domain extensions would do the trick. Thanks!
# re: Getting a 'base' Domain from a Domain
by Steven Quick April 26, 2012 @ 3:04pm
Why not just make "BaseDomain" a web.config setting with a transformation for dev (localhost), beta (beta.west-wind.com) and live (west-wind.com)?
# re: Getting a 'base' Domain from a Domain
by Rick Strahl April 26, 2012 @ 3:23pm
@Steven - essentially that's what I did except I used the FormsAuthentication domain key for it since that's what the domain is used for.
# re: Getting a 'base' Domain from a Domain
by Richard Lawley August 15, 2012 @ 7:57am
I appreciate this is a bit late, but I've had to do something similar recently. The solution you have here works fine for a restricted set of domains, but gets completely broken by some other international domains. For example, domain.com and domain.uk.com are both valid "base" domains, but "uk.com" is not (it's a TLD).

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
by steve April 10, 2014 @ 12:03am
you can get domain name like the following:

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
 


West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2014