• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

coditory / quark-uri / #3

pending completion
#3

push

github-actions

ogesaku
init

1212 of 1212 new or added lines in 21 files covered. (100.0%)

926 of 1212 relevant lines covered (76.4%)

0.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

70.97
/src/main/java/com/coditory/quark/uri/InetAddressValidator.java
1
package com.coditory.quark.uri;
2

3
import org.jetbrains.annotations.Nullable;
4

5
import java.util.ArrayList;
6
import java.util.Arrays;
7
import java.util.List;
8
import java.util.regex.Matcher;
9
import java.util.regex.Pattern;
10

11
import static com.coditory.quark.uri.Strings.isNullOrBlank;
12

13
public final class InetAddressValidator {
14
    private InetAddressValidator() {
×
15
        throw new UnsupportedOperationException("Do not instantiate utility class");
×
16
    }
17

18
    private static final int MAX_BYTE = 128;
19
    private static final int IPV4_MAX_OCTET_VALUE = 255;
20
    private static final int MAX_UNSIGNED_SHORT = 0xffff;
21
    private static final int BASE_16 = 16;
22
    private static final Pattern IPV4_REGEX = Pattern.compile("^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$");
1✔
23
    private static final int IPV6_MAX_HEX_GROUPS = 8;
24
    private static final int IPV6_MAX_HEX_DIGITS_PER_GROUP = 4;
25

26
    public static void validateInetAddress(@Nullable String inetAddress) {
27
        if (!isValidInetV4Address(inetAddress) && !isValidInetV6Address(inetAddress)) {
1✔
28
            throw new IllegalArgumentException("Expected valid ip address. Got: " + inetAddress);
1✔
29
        }
30
    }
1✔
31

32
    public static void validateInetV4Address(@Nullable String inetAddress) {
33
        if (!isValidInetV4Address(inetAddress)) {
1✔
34
            throw new IllegalArgumentException("Expected valid ip v4 address. Got: " + inetAddress);
1✔
35
        }
36
    }
1✔
37

38
    public static void validateInetV6Address(@Nullable String inetAddress) {
39
        if (!isValidInetV6Address(inetAddress)) {
1✔
40
            throw new IllegalArgumentException("Expected valid ip v6 address. Got: " + inetAddress);
1✔
41
        }
42
    }
1✔
43

44
    public static boolean isValidInetAddress(@Nullable String inetAddress) {
45
        return isValidInetV4Address(inetAddress) || isValidInetV6Address(inetAddress);
×
46
    }
47

48
    public static boolean isValidInetV4Address(@Nullable String inet4Address) {
49
        if (inet4Address == null || inet4Address.isBlank()) {
1✔
50
            return false;
×
51
        }
52
        Matcher matcher = IPV4_REGEX.matcher(inet4Address);
1✔
53
        if (!matcher.matches()) {
1✔
54
            return false;
1✔
55
        }
56
        for (int j = 0; j < matcher.groupCount(); j++) {
1✔
57
            String ipSegment = matcher.group(j + 1);
1✔
58
            if (isNullOrBlank(ipSegment)) {
1✔
59
                return false;
×
60
            }
61
            if (ipSegment.length() > 1 && ipSegment.startsWith("0")) {
1✔
62
                return false;
×
63
            }
64
            Integer iIpSegment = parseIntegerOrNull(ipSegment);
1✔
65
            if (iIpSegment == null || iIpSegment > IPV4_MAX_OCTET_VALUE) {
1✔
66
                return false;
1✔
67
            }
68
        }
69
        return true;
1✔
70
    }
71

72
    private static Integer parseIntegerOrNull(String text) {
73
        if (text == null) {
1✔
74
            return null;
×
75
        }
76
        try {
77
            return Integer.parseInt(text);
1✔
78
        } catch (RuntimeException e) {
×
79
            return null;
×
80
        }
81
    }
82

83
    public static boolean isValidInetV6Address(@Nullable String inet6Address) {
84
        if (inet6Address == null || inet6Address.isBlank()) {
1✔
85
            return false;
×
86
        }
87
        String[] parts;
88
        parts = inet6Address.split("/", -1);
1✔
89
        if (parts.length > 2) {
1✔
90
            return false;
×
91
        }
92
        if (parts.length == 2) {
1✔
93
            if (parts[1].matches("\\d{1,3}")) {
×
94
                int bits = Integer.parseInt(parts[1]);
×
95
                if (bits < 0 || bits > MAX_BYTE) {
×
96
                    return false;
×
97
                }
98
            } else {
×
99
                return false;
×
100
            }
101
        }
102
        parts = parts[0].split("%", -1);
1✔
103
        if (parts.length > 2) {
1✔
104
            return false;
×
105
        } else if (parts.length == 2) {
1✔
106
            if (!parts[1].matches("[^\\s/%]+")) {
×
107
                return false;
×
108
            }
109
        }
110
        inet6Address = parts[0];
1✔
111
        boolean containsCompressedZeroes = inet6Address.contains("::");
1✔
112
        if (containsCompressedZeroes && (inet6Address.indexOf("::") != inet6Address.lastIndexOf("::"))) {
1✔
113
            return false;
1✔
114
        }
115
        if ((inet6Address.startsWith(":") && !inet6Address.startsWith("::"))
1✔
116
                || (inet6Address.endsWith(":") && !inet6Address.endsWith("::"))) {
1✔
117
            return false;
×
118
        }
119
        String[] octets = inet6Address.split(":");
1✔
120
        if (containsCompressedZeroes) {
1✔
121
            List<String> octetList = new ArrayList<>(Arrays.asList(octets));
1✔
122
            if (inet6Address.endsWith("::")) {
1✔
123
                octetList.add("");
×
124
            } else if (inet6Address.startsWith("::") && !octetList.isEmpty()) {
1✔
125
                octetList.remove(0);
1✔
126
            }
127
            octets = octetList.toArray(new String[0]);
1✔
128
        }
129
        if (octets.length > IPV6_MAX_HEX_GROUPS) {
1✔
130
            return false;
1✔
131
        }
132
        int validOctets = 0;
1✔
133
        int emptyOctets = 0; // consecutive empty chunks
1✔
134
        for (int index = 0; index < octets.length; index++) {
1✔
135
            String octet = octets[index];
1✔
136
            if (octet.length() == 0) {
1✔
137
                emptyOctets++;
1✔
138
                if (emptyOctets > 1) {
1✔
139
                    return false;
×
140
                }
141
            } else {
142
                emptyOctets = 0;
1✔
143
                if (index == octets.length - 1 && octet.contains(".")) {
1✔
144
                    if (!isValidInetV4Address(octet)) {
1✔
145
                        return false;
1✔
146
                    }
147
                    validOctets += 2;
1✔
148
                    continue;
1✔
149
                }
150
                if (octet.length() > IPV6_MAX_HEX_DIGITS_PER_GROUP) {
1✔
151
                    return false;
×
152
                }
153
                int octetInt = 0;
1✔
154
                try {
155
                    octetInt = Integer.parseInt(octet, BASE_16);
1✔
156
                } catch (NumberFormatException e) {
×
157
                    return false;
×
158
                }
1✔
159
                if (octetInt < 0 || octetInt > MAX_UNSIGNED_SHORT) {
1✔
160
                    return false;
×
161
                }
162
            }
163
            validOctets++;
1✔
164
        }
165
        return validOctets <= IPV6_MAX_HEX_GROUPS
1✔
166
                && (validOctets == IPV6_MAX_HEX_GROUPS || containsCompressedZeroes);
167
    }
168
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc