001/*
002 * Copyright 2015-2024 the original author or authors
003 *
004 * This software is licensed under the Apache License, Version 2.0,
005 * the GNU Lesser General Public License version 2 or later ("LGPL")
006 * and the WTFPL.
007 * You may choose either license to govern your use of this software only
008 * upon the condition that you accept all of the terms of either
009 * the Apache License 2.0, the LGPL 2.1+ or the WTFPL.
010 */
011package org.minidns.dnslabel;
012
013/**
014 * A LDH (<b>L</b>etters, <b>D</b>igits, <b>H</b>yphen) label, which is the
015 * classical label form.
016 * <p>
017 * Note that it is a common misconception that LDH labels can not start with a
018 * digit. The origin of this misconception is likely that
019 * <a href="https://datatracker.ietf.org/doc/html/rfc1034#section-3.5">RFC 1034
020 * § 3.5</a> specified
021 * </p>
022 * <blockquote>
023 * They [i.e, DNS labels] must start with a letter, end with a letter or digit,
024 * and have as interior characters only letters, digits, and hyphen.
025 * </blockquote>.
026 * However, this was relaxed in
027 * <a href="https://datatracker.ietf.org/doc/html/rfc1123#page-13">RFC 1123 §
028 * 2.1</a>
029 * <blockquote>
030 * One aspect of host name syntax is hereby changed: the restriction on the first
031 * character is relaxed to allow either a letter or a digit.
032 * </blockquote>
033 * and later summarized in
034 * <a href="https://datatracker.ietf.org/doc/html/rfc3696#section-2">RFC 3696 §
035 * 2</a>:
036 * <blockquote>
037 * If the hyphen is used, it is not permitted to appear at either the beginning
038 * or end of a label.
039 * </blockquote>
040 * Furthermore
041 * <a href="https://datatracker.ietf.org/doc/html/rfc5890#section-2.3.1">RFC
042 * 5890 § 2.3.1</a> only mentions the requirement that hyphen must not be the
043 * first or last character of a LDH label.
044 *
045 * @see <a href="https://tools.ietf.org/html/rfc5890#section-2.3.1">RFC 5890 §
046 *      2.3.1. LDH Label</a>
047 *
048 */
049public abstract class LdhLabel extends DnsLabel {
050
051    protected LdhLabel(String label) {
052        super(label);
053    }
054
055    public static boolean isLdhLabel(String label) {
056        if (label.isEmpty()) {
057            return false;
058        }
059
060        if (LeadingOrTrailingHyphenLabel.isLeadingOrTrailingHypenLabelInternal(label)) {
061            return false;
062        }
063
064        return consistsOnlyOfLettersDigitsAndHypen(label);
065    }
066
067    protected static LdhLabel fromInternal(String label) {
068        assert isLdhLabel(label);
069
070        if (ReservedLdhLabel.isReservedLdhLabel(label)) {
071            // Label starts with '??--'. Now let us see if it is a XN-Label, starting with 'xn--', but be aware that the
072            // 'xn' part is case insensitive. The XnLabel.isXnLabelInternal(String) method takes care of this.
073            if (XnLabel.isXnLabelInternal(label)) {
074                return XnLabel.fromInternal(label);
075            } else {
076                return new ReservedLdhLabel(label);
077            }
078        }
079        return new NonReservedLdhLabel(label);
080    }
081}