src/share/classes/com/sun/jndi/dns/DnsName.java

Print this page




  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.jndi.dns;
  27 
  28 
  29 import java.util.ArrayList;
  30 import java.util.Comparator;
  31 import java.util.Enumeration;
  32 import java.util.Iterator;
  33 
  34 import javax.naming.*;
  35 
  36 
  37 /**
  38  * <tt>DnsName</tt> implements compound names for DNS as specified by
  39  * RFCs 1034 and 1035, and as updated and clarified by RFCs 1123 and 2181.
  40  *
  41  * <p> The labels in a domain name correspond to JNDI atomic names.
  42  * Each label must be less than 64 octets in length, and only the
  43  * optional root label at the end of the name may be 0 octets long.
  44  * The sum of the lengths of all labels in a name, plus the number of
  45  * non-root labels plus 1, must be less than 256.  The textual
  46  * representation of a domain name consists of the labels, escaped as
  47  * needed, dot-separated, and ordered right-to-left.
  48  *
  49  * <p> A label consists of a sequence of octets, each of which may
  50  * have any value from 0 to 255.
  51  *
  52  * <p> <em>Host names</em> are a subset of domain names.


  94  * are case-insensitive.  When comparing names containing non-ASCII
  95  * octets, <tt>DnsName</tt> uses case-insensitive comparison
  96  * between pairs of ASCII values, and exact binary comparison
  97  * otherwise.
  98 
  99  * <p> A <tt>DnsName</tt> instance is not synchronized against
 100  * concurrent access by multiple threads.
 101  *
 102  * @author Scott Seligman
 103  */
 104 
 105 
 106 public final class DnsName implements Name {
 107 
 108     // If non-null, the domain name represented by this DnsName.
 109     private String domain = "";
 110 
 111     // The labels of this domain name, as a list of strings.  Index 0
 112     // corresponds to the leftmost (least significant) label:  note that
 113     // this is the reverse of the ordering used by the Name interface.
 114     private ArrayList labels = new ArrayList();
 115 
 116     // The number of octets needed to carry this domain name in a DNS
 117     // packet.  Equal to the sum of the lengths of each label, plus the
 118     // number of non-root labels, plus 1.  Must remain less than 256.
 119     private short octets = 1;
 120 
 121 
 122     /**
 123      * Constructs a <tt>DnsName</tt> representing the empty domain name.
 124      */
 125     public DnsName() {
 126     }
 127 
 128     /**
 129      * Constructs a <tt>DnsName</tt> representing a given domain name.
 130      *
 131      * @param   name    the domain name to parse
 132      * @throws InvalidNameException if <tt>name</tt> does not conform
 133      *          to DNS syntax.
 134      */
 135     public DnsName(String name) throws InvalidNameException {
 136         parse(name);
 137     }
 138 
 139     /*
 140      * Returns a new DnsName with its name components initialized to
 141      * the components of "n" in the range [beg,end).  Indexing is as
 142      * for the Name interface, with 0 being the most significant.
 143      */
 144     private DnsName(DnsName n, int beg, int end) {
 145         // Compute indexes into "labels", which has least-significant label
 146         // at index 0 (opposite to the convention used for "beg" and "end").
 147         int b = n.size() - end;
 148         int e = n.size() - beg;
 149         labels.addAll(n.labels.subList(b, e));
 150 
 151         if (size() == n.size()) {
 152             domain = n.domain;
 153             octets = n.octets;
 154         } else {
 155             Iterator iter = labels.iterator();
 156             while (iter.hasNext()) {
 157                 String label = (String) iter.next();
 158                 if (label.length() > 0) {
 159                     octets += (short) (label.length() + 1);
 160                 }
 161             }
 162         }
 163     }
 164 
 165 
 166     public String toString() {
 167         if (domain == null) {
 168             StringBuffer buf = new StringBuffer();
 169             Iterator iter = labels.iterator();
 170             while (iter.hasNext()) {
 171                 String label = (String) iter.next();
 172                 if (buf.length() > 0 || label.length() == 0) {
 173                     buf.append('.');
 174                 }
 175                 escape(buf, label);
 176             }
 177             domain = buf.toString();
 178         }
 179         return domain;
 180     }
 181 
 182     /**
 183      * Does this domain name follow <em>host name</em> syntax?
 184      */
 185     public boolean isHostName() {
 186         Iterator iter = labels.iterator();
 187         while (iter.hasNext()) {
 188             if (!isHostNameLabel((String) iter.next())) {
 189                 return false;
 190             }
 191         }
 192         return true;
 193     }
 194 
 195     public short getOctets() {
 196         return octets;
 197     }
 198 
 199     public int size() {
 200         return labels.size();
 201     }
 202 
 203     public boolean isEmpty() {
 204         return (size() == 0);
 205     }
 206 
 207     public int hashCode() {
 208         int h = 0;


 224     public int compareTo(Object obj) {
 225         Name n = (Name) obj;
 226         return compareRange(0, size(), n);      // never 0 if sizes differ
 227     }
 228 
 229     public boolean startsWith(Name n) {
 230         return ((size() >= n.size()) &&
 231                 (compareRange(0, n.size(), n) == 0));
 232     }
 233 
 234     public boolean endsWith(Name n) {
 235         return ((size() >= n.size()) &&
 236                 (compareRange(size() - n.size(), size(), n) == 0));
 237     }
 238 
 239     public String get(int pos) {
 240         if (pos < 0 || pos >= size()) {
 241             throw new ArrayIndexOutOfBoundsException();
 242         }
 243         int i = size() - pos - 1;       // index of "pos" component in "labels"
 244         return (String) labels.get(i);
 245     }
 246 
 247     public Enumeration getAll() {
 248         return new Enumeration() {
 249             int pos = 0;
 250             public boolean hasMoreElements() {
 251                 return (pos < size());
 252             }
 253             public Object nextElement() {
 254                 if (pos < size()) {
 255                     return get(pos++);
 256                 }
 257                 throw new java.util.NoSuchElementException();
 258             }
 259         };
 260     }
 261 
 262     public Name getPrefix(int pos) {
 263         return new DnsName(this, 0, pos);
 264     }
 265 
 266     public Name getSuffix(int pos) {
 267         return new DnsName(this, pos, size());
 268     }
 269 
 270     public Object clone() {
 271         return new DnsName(this, 0, size());
 272     }
 273 
 274     public Object remove(int pos) {
 275         if (pos < 0 || pos >= size()) {
 276             throw new ArrayIndexOutOfBoundsException();
 277         }
 278         int i = size() - pos - 1;     // index of element to remove in "labels"
 279         String label = (String) labels.remove(i);
 280         int len = label.length();
 281         if (len > 0) {
 282             octets -= (short) (len + 1);
 283         }
 284         domain = null;          // invalidate "domain"
 285         return label;
 286     }
 287 
 288     public Name add(String comp) throws InvalidNameException {
 289         return add(size(), comp);
 290     }
 291 
 292     public Name add(int pos, String comp) throws InvalidNameException {
 293         if (pos < 0 || pos > size()) {
 294             throw new ArrayIndexOutOfBoundsException();
 295         }
 296         // Check for empty labels:  may have only one, and only at end.
 297         int len = comp.length();
 298         if ((pos > 0 && len == 0) ||
 299             (pos == 0 && hasRootLabel())) {


 513                 return false;
 514             }
 515         }
 516         return !(label.startsWith("-") || label.endsWith("-"));
 517     }
 518 
 519     private static boolean isHostNameChar(char c) {
 520         return (c == '-' ||
 521                 c >= 'a' && c <= 'z' ||
 522                 c >= 'A' && c <= 'Z' ||
 523                 c >= '0' && c <= '9');
 524     }
 525 
 526     private static boolean isDigit(char c) {
 527         return (c >= '0' && c <= '9');
 528     }
 529 
 530     /*
 531      * Append a label to buf, escaping as needed.
 532      */
 533     private static void escape(StringBuffer buf, String label) {
 534         for (int i = 0; i < label.length(); i++) {
 535             char c = label.charAt(i);
 536             if (c == '.' || c == '\\') {
 537                 buf.append('\\');
 538             }
 539             buf.append(c);
 540         }
 541     }
 542 
 543     /*
 544      * Compares two labels, ignoring case for ASCII values.
 545      * Returns negative, zero, or positive as the first label
 546      * is less than, equal to, or greater than the second.
 547      * See keyForLabel().
 548      */
 549     private static int compareLabels(String label1, String label2) {
 550         int min = Math.min(label1.length(), label2.length());
 551         for (int i = 0; i < min; i++) {
 552             char c1 = label1.charAt(i);
 553             char c2 = label2.charAt(i);




  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.jndi.dns;
  27 
  28 
  29 import java.util.ArrayList;
  30 import java.util.Comparator;
  31 import java.util.Enumeration;

  32 
  33 import javax.naming.*;
  34 
  35 
  36 /**
  37  * <tt>DnsName</tt> implements compound names for DNS as specified by
  38  * RFCs 1034 and 1035, and as updated and clarified by RFCs 1123 and 2181.
  39  *
  40  * <p> The labels in a domain name correspond to JNDI atomic names.
  41  * Each label must be less than 64 octets in length, and only the
  42  * optional root label at the end of the name may be 0 octets long.
  43  * The sum of the lengths of all labels in a name, plus the number of
  44  * non-root labels plus 1, must be less than 256.  The textual
  45  * representation of a domain name consists of the labels, escaped as
  46  * needed, dot-separated, and ordered right-to-left.
  47  *
  48  * <p> A label consists of a sequence of octets, each of which may
  49  * have any value from 0 to 255.
  50  *
  51  * <p> <em>Host names</em> are a subset of domain names.


  93  * are case-insensitive.  When comparing names containing non-ASCII
  94  * octets, <tt>DnsName</tt> uses case-insensitive comparison
  95  * between pairs of ASCII values, and exact binary comparison
  96  * otherwise.
  97 
  98  * <p> A <tt>DnsName</tt> instance is not synchronized against
  99  * concurrent access by multiple threads.
 100  *
 101  * @author Scott Seligman
 102  */
 103 
 104 
 105 public final class DnsName implements Name {
 106 
 107     // If non-null, the domain name represented by this DnsName.
 108     private String domain = "";
 109 
 110     // The labels of this domain name, as a list of strings.  Index 0
 111     // corresponds to the leftmost (least significant) label:  note that
 112     // this is the reverse of the ordering used by the Name interface.
 113     private ArrayList<String> labels = new ArrayList<>();
 114 
 115     // The number of octets needed to carry this domain name in a DNS
 116     // packet.  Equal to the sum of the lengths of each label, plus the
 117     // number of non-root labels, plus 1.  Must remain less than 256.
 118     private short octets = 1;
 119 
 120 
 121     /**
 122      * Constructs a <tt>DnsName</tt> representing the empty domain name.
 123      */
 124     public DnsName() {
 125     }
 126 
 127     /**
 128      * Constructs a <tt>DnsName</tt> representing a given domain name.
 129      *
 130      * @param   name    the domain name to parse
 131      * @throws InvalidNameException if <tt>name</tt> does not conform
 132      *          to DNS syntax.
 133      */
 134     public DnsName(String name) throws InvalidNameException {
 135         parse(name);
 136     }
 137 
 138     /*
 139      * Returns a new DnsName with its name components initialized to
 140      * the components of "n" in the range [beg,end).  Indexing is as
 141      * for the Name interface, with 0 being the most significant.
 142      */
 143     private DnsName(DnsName n, int beg, int end) {
 144         // Compute indexes into "labels", which has least-significant label
 145         // at index 0 (opposite to the convention used for "beg" and "end").
 146         int b = n.size() - end;
 147         int e = n.size() - beg;
 148         labels.addAll(n.labels.subList(b, e));
 149 
 150         if (size() == n.size()) {
 151             domain = n.domain;
 152             octets = n.octets;
 153         } else {
 154             for (String label: labels) {


 155                 if (label.length() > 0) {
 156                     octets += (short) (label.length() + 1);
 157                 }
 158             }
 159         }
 160     }
 161 
 162 
 163     public String toString() {
 164         if (domain == null) {
 165             StringBuilder buf = new StringBuilder();
 166             for (String label: labels) {


 167                 if (buf.length() > 0 || label.length() == 0) {
 168                     buf.append('.');
 169                 }
 170                 escape(buf, label);
 171             }
 172             domain = buf.toString();
 173         }
 174         return domain;
 175     }
 176 
 177     /**
 178      * Does this domain name follow <em>host name</em> syntax?
 179      */
 180     public boolean isHostName() {
 181         for (String label: labels) {
 182             if (!isHostNameLabel(label)) {

 183                 return false;
 184             }
 185         }
 186         return true;
 187     }
 188 
 189     public short getOctets() {
 190         return octets;
 191     }
 192 
 193     public int size() {
 194         return labels.size();
 195     }
 196 
 197     public boolean isEmpty() {
 198         return (size() == 0);
 199     }
 200 
 201     public int hashCode() {
 202         int h = 0;


 218     public int compareTo(Object obj) {
 219         Name n = (Name) obj;
 220         return compareRange(0, size(), n);      // never 0 if sizes differ
 221     }
 222 
 223     public boolean startsWith(Name n) {
 224         return ((size() >= n.size()) &&
 225                 (compareRange(0, n.size(), n) == 0));
 226     }
 227 
 228     public boolean endsWith(Name n) {
 229         return ((size() >= n.size()) &&
 230                 (compareRange(size() - n.size(), size(), n) == 0));
 231     }
 232 
 233     public String get(int pos) {
 234         if (pos < 0 || pos >= size()) {
 235             throw new ArrayIndexOutOfBoundsException();
 236         }
 237         int i = size() - pos - 1;       // index of "pos" component in "labels"
 238         return labels.get(i);
 239     }
 240 
 241     public Enumeration<String> getAll() {
 242         return new Enumeration<String>() {
 243             int pos = 0;
 244             public boolean hasMoreElements() {
 245                 return (pos < size());
 246             }
 247             public String nextElement() {
 248                 if (pos < size()) {
 249                     return get(pos++);
 250                 }
 251                 throw new java.util.NoSuchElementException();
 252             }
 253         };
 254     }
 255 
 256     public Name getPrefix(int pos) {
 257         return new DnsName(this, 0, pos);
 258     }
 259 
 260     public Name getSuffix(int pos) {
 261         return new DnsName(this, pos, size());
 262     }
 263 
 264     public Object clone() {
 265         return new DnsName(this, 0, size());
 266     }
 267 
 268     public Object remove(int pos) {
 269         if (pos < 0 || pos >= size()) {
 270             throw new ArrayIndexOutOfBoundsException();
 271         }
 272         int i = size() - pos - 1;     // index of element to remove in "labels"
 273         String label = labels.remove(i);
 274         int len = label.length();
 275         if (len > 0) {
 276             octets -= (short) (len + 1);
 277         }
 278         domain = null;          // invalidate "domain"
 279         return label;
 280     }
 281 
 282     public Name add(String comp) throws InvalidNameException {
 283         return add(size(), comp);
 284     }
 285 
 286     public Name add(int pos, String comp) throws InvalidNameException {
 287         if (pos < 0 || pos > size()) {
 288             throw new ArrayIndexOutOfBoundsException();
 289         }
 290         // Check for empty labels:  may have only one, and only at end.
 291         int len = comp.length();
 292         if ((pos > 0 && len == 0) ||
 293             (pos == 0 && hasRootLabel())) {


 507                 return false;
 508             }
 509         }
 510         return !(label.startsWith("-") || label.endsWith("-"));
 511     }
 512 
 513     private static boolean isHostNameChar(char c) {
 514         return (c == '-' ||
 515                 c >= 'a' && c <= 'z' ||
 516                 c >= 'A' && c <= 'Z' ||
 517                 c >= '0' && c <= '9');
 518     }
 519 
 520     private static boolean isDigit(char c) {
 521         return (c >= '0' && c <= '9');
 522     }
 523 
 524     /*
 525      * Append a label to buf, escaping as needed.
 526      */
 527     private static void escape(StringBuilder buf, String label) {
 528         for (int i = 0; i < label.length(); i++) {
 529             char c = label.charAt(i);
 530             if (c == '.' || c == '\\') {
 531                 buf.append('\\');
 532             }
 533             buf.append(c);
 534         }
 535     }
 536 
 537     /*
 538      * Compares two labels, ignoring case for ASCII values.
 539      * Returns negative, zero, or positive as the first label
 540      * is less than, equal to, or greater than the second.
 541      * See keyForLabel().
 542      */
 543     private static int compareLabels(String label1, String label2) {
 544         int min = Math.min(label1.length(), label2.length());
 545         for (int i = 0; i < min; i++) {
 546             char c1 = label1.charAt(i);
 547             char c2 = label2.charAt(i);