Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/com/sun/jndi/dns/DnsName.java
38924 views
1
/*
2
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
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.
52
* Their labels contain only ASCII letters, digits, and hyphens, and
53
* none may begin or end with a hyphen. While names not conforming to
54
* these rules may be valid domain names, they will not be usable by a
55
* number of DNS applications, and should in most cases be avoided.
56
*
57
* <p> DNS does not specify an encoding (such as UTF-8) to use for
58
* octets with non-ASCII values. As of this writing there is some
59
* work going on in this area, but it is not yet finalized.
60
* <tt>DnsName</tt> currently converts any non-ASCII octets into
61
* characters using ISO-LATIN-1 encoding, in effect taking the
62
* value of each octet and storing it directly into the low-order byte
63
* of a Java character and <i>vice versa</i>. As a consequence, no
64
* character in a DNS name will ever have a non-zero high-order byte.
65
* When the work on internationalizing domain names has stabilized
66
* (see for example <i>draft-ietf-idn-idna-10.txt</i>), <tt>DnsName</tt>
67
* may be updated to conform to that work.
68
*
69
* <p> Backslash (<tt>\</tt>) is used as the escape character in the
70
* textual representation of a domain name. The character sequence
71
* `<tt>\DDD</tt>', where <tt>DDD</tt> is a 3-digit decimal number
72
* (with leading zeros if needed), represents the octet whose value
73
* is <tt>DDD</tt>. The character sequence `<tt>\C</tt>', where
74
* <tt>C</tt> is a character other than <tt>'0'</tt> through
75
* <tt>'9'</tt>, represents the octet whose value is that of
76
* <tt>C</tt> (again using ISO-LATIN-1 encoding); this is particularly
77
* useful for escaping <tt>'.'</tt> or backslash itself. Backslash is
78
* otherwise not allowed in a domain name. Note that escape characters
79
* are interpreted when a name is parsed. So, for example, the character
80
* sequences `<tt>S</tt>', `<tt>\S</tt>', and `<tt>\083</tt>' each
81
* represent the same one-octet name. The <tt>toString()</tt> method
82
* does not generally insert escape sequences except where necessary.
83
* If, however, the <tt>DnsName</tt> was constructed using unneeded
84
* escapes, those escapes may appear in the <tt>toString</tt> result.
85
*
86
* <p> Atomic names passed as parameters to methods of
87
* <tt>DnsName</tt>, and those returned by them, are unescaped. So,
88
* for example, <tt>(new&nbsp;DnsName()).add("a.b")</tt> creates an
89
* object representing the one-label domain name <tt>a\.b</tt>, and
90
* calling <tt>get(0)</tt> on this object returns <tt>"a.b"</tt>.
91
*
92
* <p> While DNS names are case-preserving, comparisons between them
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;
203
for (int i = 0; i < size(); i++) {
204
h = 31 * h + getKey(i).hashCode();
205
}
206
return h;
207
}
208
209
public boolean equals(Object obj) {
210
if (!(obj instanceof Name) || (obj instanceof CompositeName)) {
211
return false;
212
}
213
Name n = (Name) obj;
214
return ((size() == n.size()) && // shortcut: do sizes differ?
215
(compareTo(obj) == 0));
216
}
217
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())) {
294
throw new InvalidNameException(
295
"Empty label must be the last label in a domain name");
296
}
297
// Check total name length.
298
if (len > 0) {
299
if (octets + len + 1 >= 256) {
300
throw new InvalidNameException("Name too long");
301
}
302
octets += (short) (len + 1);
303
}
304
305
int i = size() - pos; // index for insertion into "labels"
306
verifyLabel(comp);
307
labels.add(i, comp);
308
309
domain = null; // invalidate "domain"
310
return this;
311
}
312
313
public Name addAll(Name suffix) throws InvalidNameException {
314
return addAll(size(), suffix);
315
}
316
317
public Name addAll(int pos, Name n) throws InvalidNameException {
318
if (n instanceof DnsName) {
319
// "n" is a DnsName so we can insert it as a whole, rather than
320
// verifying and inserting it component-by-component.
321
// More code, but less work.
322
DnsName dn = (DnsName) n;
323
324
if (dn.isEmpty()) {
325
return this;
326
}
327
// Check for empty labels: may have only one, and only at end.
328
if ((pos > 0 && dn.hasRootLabel()) ||
329
(pos == 0 && hasRootLabel())) {
330
throw new InvalidNameException(
331
"Empty label must be the last label in a domain name");
332
}
333
334
short newOctets = (short) (octets + dn.octets - 1);
335
if (newOctets > 255) {
336
throw new InvalidNameException("Name too long");
337
}
338
octets = newOctets;
339
int i = size() - pos; // index for insertion into "labels"
340
labels.addAll(i, dn.labels);
341
342
// Preserve "domain" if we're appending or prepending,
343
// otherwise invalidate it.
344
if (isEmpty()) {
345
domain = dn.domain;
346
} else if (domain == null || dn.domain == null) {
347
domain = null;
348
} else if (pos == 0) {
349
domain += (dn.domain.equals(".") ? "" : ".") + dn.domain;
350
} else if (pos == size()) {
351
domain = dn.domain + (domain.equals(".") ? "" : ".") + domain;
352
} else {
353
domain = null;
354
}
355
356
} else if (n instanceof CompositeName) {
357
n = (DnsName) n; // force ClassCastException
358
359
} else { // "n" is a compound name, but not a DnsName.
360
// Add labels least-significant first: sometimes more efficient.
361
for (int i = n.size() - 1; i >= 0; i--) {
362
add(pos, n.get(i));
363
}
364
}
365
return this;
366
}
367
368
369
boolean hasRootLabel() {
370
return (!isEmpty() &&
371
get(0).equals(""));
372
}
373
374
/*
375
* Helper method for public comparison methods. Lexicographically
376
* compares components of this name in the range [beg,end) with
377
* all components of "n". Indexing is as for the Name interface,
378
* with 0 being the most significant. Returns negative, zero, or
379
* positive as these name components are less than, equal to, or
380
* greater than those of "n".
381
*/
382
private int compareRange(int beg, int end, Name n) {
383
if (n instanceof CompositeName) {
384
n = (DnsName) n; // force ClassCastException
385
}
386
// Loop through labels, starting with most significant.
387
int minSize = Math.min(end - beg, n.size());
388
for (int i = 0; i < minSize; i++) {
389
String label1 = get(i + beg);
390
String label2 = n.get(i);
391
392
int j = size() - (i + beg) - 1; // index of label1 in "labels"
393
// assert (label1 == labels.get(j));
394
395
int c = compareLabels(label1, label2);
396
if (c != 0) {
397
return c;
398
}
399
}
400
return ((end - beg) - n.size()); // longer range wins
401
}
402
403
/*
404
* Returns a key suitable for hashing the label at index i.
405
* Indexing is as for the Name interface, with 0 being the most
406
* significant.
407
*/
408
String getKey(int i) {
409
return keyForLabel(get(i));
410
}
411
412
413
/*
414
* Parses a domain name, setting the values of instance vars accordingly.
415
*/
416
private void parse(String name) throws InvalidNameException {
417
418
StringBuffer label = new StringBuffer(); // label being parsed
419
420
for (int i = 0; i < name.length(); i++) {
421
char c = name.charAt(i);
422
423
if (c == '\\') { // found an escape sequence
424
c = getEscapedOctet(name, i++);
425
if (isDigit(name.charAt(i))) { // sequence is \DDD
426
i += 2; // consume remaining digits
427
}
428
label.append(c);
429
430
} else if (c != '.') { // an unescaped octet
431
label.append(c);
432
433
} else { // found '.' separator
434
add(0, label.toString()); // check syntax, then add label
435
// to end of name
436
label.delete(0, i); // clear buffer for next label
437
}
438
}
439
440
// If name is neither "." nor "", the octets (zero or more)
441
// from the rightmost dot onward are now added as the final
442
// label of the name. Those two are special cases in that for
443
// all other domain names, the number of labels is one greater
444
// than the number of dot separators.
445
if (!name.equals("") && !name.equals(".")) {
446
add(0, label.toString());
447
}
448
449
domain = name; // do this last, since add() sets it to null
450
}
451
452
/*
453
* Returns (as a char) the octet indicated by the escape sequence
454
* at a given position within a domain name.
455
* @throws InvalidNameException if a valid escape sequence is not found.
456
*/
457
private static char getEscapedOctet(String name, int pos)
458
throws InvalidNameException {
459
try {
460
// assert (name.charAt(pos) == '\\');
461
char c1 = name.charAt(++pos);
462
if (isDigit(c1)) { // sequence is `\DDD'
463
char c2 = name.charAt(++pos);
464
char c3 = name.charAt(++pos);
465
if (isDigit(c2) && isDigit(c3)) {
466
return (char)
467
((c1 - '0') * 100 + (c2 - '0') * 10 + (c3 - '0'));
468
} else {
469
throw new InvalidNameException(
470
"Invalid escape sequence in " + name);
471
}
472
} else { // sequence is `\C'
473
return c1;
474
}
475
} catch (IndexOutOfBoundsException e) {
476
throw new InvalidNameException(
477
"Invalid escape sequence in " + name);
478
}
479
}
480
481
/*
482
* Checks that this label is valid.
483
* @throws InvalidNameException if label is not valid.
484
*/
485
private static void verifyLabel(String label) throws InvalidNameException {
486
if (label.length() > 63) {
487
throw new InvalidNameException(
488
"Label exceeds 63 octets: " + label);
489
}
490
// Check for two-byte characters.
491
for (int i = 0; i < label.length(); i++) {
492
char c = label.charAt(i);
493
if ((c & 0xFF00) != 0) {
494
throw new InvalidNameException(
495
"Label has two-byte char: " + label);
496
}
497
}
498
}
499
500
/*
501
* Does this label conform to host name syntax?
502
*/
503
private static boolean isHostNameLabel(String label) {
504
for (int i = 0; i < label.length(); i++) {
505
char c = label.charAt(i);
506
if (!isHostNameChar(c)) {
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);
548
if (c1 >= 'A' && c1 <= 'Z') {
549
c1 += 'a' - 'A'; // to lower case
550
}
551
if (c2 >= 'A' && c2 <= 'Z') {
552
c2 += 'a' - 'A'; // to lower case
553
}
554
if (c1 != c2) {
555
return (c1 - c2);
556
}
557
}
558
return (label1.length() - label2.length()); // the longer one wins
559
}
560
561
/*
562
* Returns a key suitable for hashing a label. Two labels map to
563
* the same key iff they are equal, taking possible case-folding
564
* into account. See compareLabels().
565
*/
566
private static String keyForLabel(String label) {
567
StringBuffer buf = new StringBuffer(label.length());
568
for (int i = 0; i < label.length(); i++) {
569
char c = label.charAt(i);
570
if (c >= 'A' && c <= 'Z') {
571
c += 'a' - 'A'; // to lower case
572
}
573
buf.append(c);
574
}
575
return buf.toString();
576
}
577
578
579
/**
580
* Serializes only the domain name string, for compactness and to avoid
581
* any implementation dependency.
582
*
583
* @serialdata The domain name string.
584
*/
585
private void writeObject(java.io.ObjectOutputStream s)
586
throws java.io.IOException {
587
s.writeObject(toString());
588
}
589
590
private void readObject(java.io.ObjectInputStream s)
591
throws java.io.IOException, ClassNotFoundException {
592
try {
593
parse((String) s.readObject());
594
} catch (InvalidNameException e) {
595
// shouldn't happen
596
throw new java.io.StreamCorruptedException(
597
"Invalid name: " + domain);
598
}
599
}
600
601
private static final long serialVersionUID = 7040187611324710271L;
602
}
603
604