001    /*
002    Copyright (c) 1996-2012, Damon Hart-Davis
003    All rights reserved.
004    
005    Redistribution and use in source and binary forms, with or without
006    modification, are permitted provided that the following conditions are
007    met:
008    
009      * Redistributions of source code must retain the above copyright
010        notice, this list of conditions and the following disclaimer.
011    
012      * Redistributions in binary form must reproduce the above copyright
013        notice, this list of conditions and the following disclaimer in the
014        documentation and/or other materials provided with the
015        distribution.
016    
017    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
018    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
019    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
020    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
021    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
022    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
023    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
024    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
025    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
026    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
027    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028    */
029    package org.hd.d.pg2k.svrCore;
030    
031    import org.hd.d.pg2k.svrCore.location.GeoUtils.CCTLD;
032    
033    /**Some simple common host-name utilities.
034     */
035    public final class HostUtils
036        {
037        /**Prevent construction of an instance. */
038        private HostUtils() { }
039    
040        /**Normalise host (Web server) name (ours or a third-party one).
041         * This converts the host name to lower-case and
042         * strips any "www." or "mirror-CC-name." prefix and/or
043         * "." suffix.
044         * <p>
045         * If the name is already normalised,
046         * it is returned unchanged.
047         *
048         * @throws IllegalArgumentException  if arguments are malformed
049         */
050        public static String normaliseVirtualHostName(String name)
051            {
052            if(name == null) { throw new IllegalArgumentException(); }
053    
054            // Must be at least of form "a.b" and is limited by RFC rules not to be huge.
055            if((name.length() < 3) || (name.length() > 255))
056                { throw new IllegalArgumentException(); }
057    
058            // Force names to lower-case.
059            name = name.toLowerCase();
060    
061            final int firstDot = name.indexOf('.');
062    
063            // Strip off standard prefixes...
064            if(name.startsWith("www."))
065                { name = name.substring(4); }
066            else if(isSpecialName(name))
067                { name = name.substring(firstDot+1); }
068            else if(name.startsWith("mmm.")) // "Mobile" prefix.
069                { name = name.substring(4); }
070    
071            // Strip off redundant trailing dot(s)...
072            while(name.endsWith("."))
073                { name = name.substring(0, name.length() - 1); }
074    
075            // Normalised...
076            return(name);
077            }
078    
079        /**Returns true if this looks like a mirror domain-name.
080         * This is a canonical name prefixed with something of the form:
081         * <samp>mirror-cc-x."</samp>
082         * where "cc" is the two-letter country code where the mirror is hosted
083         * (eg uk or us or fr)
084         * and "x" is a descriptive short tag to indicate which mirror instance.
085         *
086         * @param name  host name, must be lower-case and non-null
087         */
088        public static boolean isMirrorName(final String name)
089            {
090            if(!name.startsWith("mirror-")) { return(false); }
091            final int firstDot = name.indexOf('.');
092            if(firstDot <= 10) { return(false); } /* At least "mirror-cc-x." */
093            return(true);
094            }
095    
096        /**Returns true if this appears to be the domain-name of a primary local mirror.
097         * This mirror will be assumed to be the primary mirror
098         * in its geographical area (and thus worth allowing to be spidered by SEs)
099         * iff its name ends with a '1',
100         * so, 'mirror-uk-ww1.something' is a primary mirror and 'mirror-uk-ww2.something' is not.
101         * <p>
102         * (Thus 'mirror-uk-ww11.something' would also be primary, but we don't care yet.)
103         * <p>
104         * This returns true for the full domain name iff
105         * isPrimaryMirrorTag() would return true for the embedded mirror tag.
106         *
107         * @param name  host name, must be lower-case and non-null
108         */
109        public static boolean isPrimaryMirrorName(final String name)
110            {
111            if(!isMirrorName(name)) { return(false); }
112            return(name.charAt(name.indexOf('.') - 1) == '1');
113            }
114    
115        /**Returns true if this tag (initial domain-name component) appears to for a primary local mirror.
116         * A mirror with this tag will be assumed to be the primary mirror
117         * in its geographical area (and thus worth allowing to be spidered by SEs)
118         * iff its name ends with a '1',
119         * so, 'mirror-uk-ww1' is a primary mirror and 'mirror-uk-ww2' is not.
120         * <p>
121         * (Thus 'mirror-uk-ww11' would also be primary, but we don't care yet.)
122         * <p>
123         * This returns true for the tag iff
124         * isPrimaryMirrorName() would return true for the whole name,
125         * though a null tag will cause this routine to return false for simplicity.
126         *
127         * @param  mirror tag, must be lower-case
128         */
129        public static boolean isPrimaryMirrorTag(final String tag)
130            {
131            if(null == tag) { return(false); }
132            return(tag.charAt(tag.length() - 1) == '1');
133            }
134    
135        /**Extract mirror tag from mirror URL/prefix; null if none.
136         * The mirror tag extracted should be of the form
137         * returned by LocalProps.getMirrorTag() for a well-formed server name.
138         */
139        public static String getMirrorTag(final String name)
140            {
141            if(!isMirrorName(name)) { return(null); }
142            final String cc = name.substring(7, 9);
143            if(!CCTLD.isSyntaticallyValidCcTLD(cc)) { return(null); }
144            return(name.substring(7, name.indexOf('.')));
145            }
146    
147        /**Extract country code from mirror URL/prefix; null if none. */
148        public static CCTLD getMirrorCC(final String name)
149            {
150            if(!name.startsWith("mirror-")) { return(null); }
151            if(name.length() < 11) { return(null); }
152            final String cc = name.substring(7, 9);
153            if(!CCTLD.isSyntaticallyValidCcTLD(cc)) { return(null); }
154            return(new CCTLD(cc));
155            }
156    
157        /**Returns true if this looks like a "master" server domain-name.
158         * This is a canonical name prefixed with "master."
159         * and indicates a central server, eg on which uploads are permitted.
160         *
161         * @param name  host name, must be lower-case and non-null
162         */
163        public static boolean isMasterName(final String name)
164            { return(name.startsWith("master.")); }
165    
166        /**Returns true if this looks like a special (mirror or master) domain-name.
167         * @param name  host name, must be lower-case and non-null
168         */
169        public static boolean isSpecialName(final String name)
170            { return(isMirrorName(name) || isMasterName(name)); }
171    
172        /**Make mirror version of standard "generic" domain-name; never null.
173         * Generates hostname of form "mirror-tag.gallery.hd.org".
174         *
175         * @param tag  valid non-null mirror tag
176         */
177        public static String makeMirrorNameGeneric(final String tag)
178            { return("mirror-" + tag + "." + CoreConsts.MAIN_DATA_HOST); }
179        }