• 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

80.23
/src/main/java/com/coditory/quark/uri/UriComponentsParser.java
1
package com.coditory.quark.uri;
2

3
import java.util.ArrayList;
4
import java.util.LinkedHashMap;
5
import java.util.List;
6
import java.util.Map;
7
import java.util.regex.Matcher;
8
import java.util.regex.Pattern;
9

10
import static com.coditory.quark.uri.Nullable.onNotNull;
11
import static com.coditory.quark.uri.Preconditions.expectNonNull;
12
import static com.coditory.quark.uri.Strings.isNotNullOrEmpty;
13

14
class UriComponentsParser {
×
15
    private static final Pattern QUERY_PARAM_PATTERN = Pattern.compile("([^&=]+)(=?)([^&]+)?");
1✔
16
    private static final String SCHEME_PATTERN = "([^:/?#]+):";
17
    private static final String USERINFO_PATTERN = "([^@\\[/?#]*)";
18
    private static final String HOST_IPV4_PATTERN = "[^\\[/?#:]*";
19
    private static final String HOST_IPV6_PATTERN = "\\[[\\p{XDigit}:.]*[%\\p{Alnum}]*]";
20
    private static final String HOST_PATTERN = "(" + HOST_IPV6_PATTERN + "|" + HOST_IPV4_PATTERN + ")";
21
    private static final String PORT_PATTERN = "([^/?#]*)";
22
    private static final String PATH_PATTERN = "([^?#]*)";
23
    private static final String QUERY_PATTERN = "([^#]*)";
24
    private static final String LAST_PATTERN = "(.*)";
25

26
    // Regex patterns that matches URIs. See RFC 3986, appendix B
27
    private static final Pattern URI_PATTERN = Pattern.compile(
1✔
28
            "^(" + SCHEME_PATTERN + ")?" +
29
                    "(//(" + USERINFO_PATTERN + "@)?" + HOST_PATTERN + "(:" + PORT_PATTERN + ")?" + ")?" +
30
                    PATH_PATTERN + "(\\?" + QUERY_PATTERN + ")?" + "(#" + LAST_PATTERN + ")?");
31

32
    static UriBuilder parseHttpUrl(String uri) {
33
        expectNonNull(uri, "uri");
1✔
34
        try {
35
            UriBuilder builder = UriComponentsParser.parseUri(uri);
1✔
36
            UriComponents components = builder.buildUriComponents();
1✔
37
            if (!components.isHttpUrl()) {
1✔
38
                throw new InvalidHttpUrlException("Invalid http url: \"" + uri + "\"");
1✔
39
            }
40
            return builder;
1✔
41
        } catch (InvalidUriException e) {
1✔
42
            InvalidUriException root = Throwables.getRootCauseOfType(e, InvalidUriException.class);
1✔
43
            String suffix = root == null ? "" : ". Cause: " + root.getMessage();
1✔
44
            throw new InvalidHttpUrlException("Could not parse http url: \"" + uri + "\"" + suffix, root);
1✔
45
        } catch (RuntimeException e) {
1✔
46
            throw new InvalidHttpUrlException("Could not parse http url: \"" + uri + "\"", e);
1✔
47
        }
48
    }
49

50
    static UriBuilder parseHttpUrlOrNull(String uri) {
51
        expectNonNull(uri, "uri");
×
52
        UriBuilder builder = UriComponentsParser.parseUriOrNull(uri);
×
53
        if (builder == null) {
×
54
            return null;
×
55
        }
56
        UriComponents components = builder.buildUriComponents();
×
57
        if (!components.isHttpUrl()) {
×
58
            return null;
×
59
        }
60
        return builder;
×
61
    }
62

63
    static UriBuilder parseUri(String uri) {
64
        expectNonNull(uri, "uri");
1✔
65
        Matcher matcher = URI_PATTERN.matcher(uri);
1✔
66
        if (!matcher.matches()) {
1✔
67
            throw new InvalidUriException("Could not parse uri: \"" + uri + "\"");
×
68
        }
69
        try {
70
            return parseUri(uri, matcher);
1✔
71
        } catch (InvalidUriException e) {
1✔
72
            throw new InvalidUriException("Could not parse uri: \"" + uri + "\". Cause: " + e.getMessage());
1✔
73
        } catch (RuntimeException e) {
1✔
74
            throw new InvalidUriException("Could not parse uri: \"" + uri + "\"");
1✔
75
        }
76
    }
77

78
    static UriBuilder parseUriOrNull(String uri) {
79
        expectNonNull(uri, "uri");
×
80
        Matcher matcher = URI_PATTERN.matcher(uri);
×
81
        if (!matcher.matches()) {
×
82
            return null;
×
83
        }
84
        try {
85
            return parseUri(uri, matcher);
×
86
        } catch (RuntimeException e) {
×
87
            return null;
×
88
        }
89
    }
90

91
    private static UriBuilder parseUri(String uri, Matcher matcher) {
92
        UriBuilder builder = new UriBuilder();
1✔
93
        String scheme = matcher.group(2);
1✔
94
        String userInfo = matcher.group(5);
1✔
95
        String host = matcher.group(6);
1✔
96
        String port = matcher.group(8);
1✔
97
        String path = matcher.group(9);
1✔
98
        String query = matcher.group(11);
1✔
99
        String fragment = matcher.group(13);
1✔
100
        boolean opaque = false;
1✔
101
        if (isNotNullOrEmpty(scheme)) {
1✔
102
            String rest = uri.substring(scheme.length());
1✔
103
            if (!rest.startsWith(":/")) {
1✔
104
                opaque = true;
1✔
105
            }
106
            builder.setScheme(UriRfc.SCHEME.validateAndDecode(scheme));
1✔
107
        } else if (uri.startsWith("//")) {
1✔
108
            builder.setProtocolRelative(true);
1✔
109
        }
110
        if (opaque) {
1✔
111
            String ssp = uri.substring(scheme.length()).substring(1);
1✔
112
            if (isNotNullOrEmpty(fragment)) {
1✔
113
                ssp = ssp.substring(0, ssp.length() - (fragment.length() + 1));
1✔
114
            }
115
            builder.setSchemeSpecificPart(UriRfc.SCHEME_SPECIFIC_PART.validateAndDecode(ssp));
1✔
116
        } else {
1✔
117
            onNotNull(userInfo, it -> builder.setUserInfo(UriRfc.USER_INFO.validateAndDecode(it)));
1✔
118
            onNotNull(host, it -> builder.setHost(UriRfc.HOST.validateAndDecode(it)));
1✔
119
            onNotNull(port, it -> {
1✔
120
                String decodedPort = UriRfc.PORT.validateAndDecode(it);
1✔
121
                builder.setPort(Integer.parseInt(decodedPort));
1✔
122
            });
1✔
123
            onNotNull(path, builder::setPath);
1✔
124
            onNotNull(query, q -> builder.setQueryMultiParams(parseQuery(q)));
1✔
125
        }
126
        onNotNull(fragment, it -> builder.setFragment(UriRfc.FRAGMENT.validateAndDecode(it)));
1✔
127
        builder.validate();
1✔
128
        return builder;
1✔
129
    }
130

131
    static Map<String, List<String>> parseQuery(String query) {
132
        expectNonNull(query, "query");
1✔
133
        Matcher matcher = QUERY_PARAM_PATTERN.matcher(query);
1✔
134
        UriRfc.QUERY.checkValidEncoded(query);
1✔
135
        Map<String, List<String>> result = new LinkedHashMap<>();
1✔
136
        while (matcher.find()) {
1✔
137
            String name = matcher.group(1);
1✔
138
            String decodedName = UriRfc.QUERY_PARAM.validateAndDecode(name);
1✔
139
            String value = matcher.group(3);
1✔
140
            String normalizedValue = value != null ? value : "";
1✔
141
            result
1✔
142
                    .computeIfAbsent(decodedName, k -> new ArrayList<>())
1✔
143
                    .add(UriRfc.QUERY_PARAM.validateAndDecode(normalizedValue));
1✔
144
        }
1✔
145
        return result;
1✔
146
    }
147
}
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