1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.newsclub.net.unix;
19
20 import java.io.UnsupportedEncodingException;
21 import java.net.SocketException;
22 import java.net.URI;
23 import java.net.URLDecoder;
24 import java.net.URLEncoder;
25 import java.util.Objects;
26 import java.util.regex.Matcher;
27 import java.util.regex.Pattern;
28
29
30
31
32
33
34 public final class HostAndPort {
35 private static final Pattern PAT_HOST_AND_PORT = Pattern.compile(
36 "^//((?<userinfo>[^/\\@]*)\\@)?(?<host>[^/\\:]+)(?:\\:(?<port>[0-9]+))?");
37 private final String hostname;
38 private final int port;
39
40
41
42
43
44
45
46 public HostAndPort(String hostname, int port) {
47 this.hostname = hostname;
48 this.port = port;
49 }
50
51 @Override
52 public int hashCode() {
53 final int prime = 31;
54 int result = 1;
55 result = prime * result + ((getHostname() == null) ? 0 : getHostname().hashCode());
56 result = prime * result + getPort();
57 return result;
58 }
59
60 @Override
61 public boolean equals(Object obj) {
62 if (this == obj) {
63 return true;
64 }
65 if (!(obj instanceof HostAndPort)) {
66 return false;
67 }
68 HostAndPort other = (HostAndPort) obj;
69 if (getHostname() == null) {
70 if (other.getHostname() != null) {
71 return false;
72 }
73 } else if (!getHostname().equals(other.getHostname())) {
74 return false;
75 }
76
77 return getPort() == other.getPort();
78 }
79
80 @Override
81 public String toString() {
82 if (getPort() == -1) {
83 return getHostname();
84 } else {
85 return getHostname() + ":" + getPort();
86 }
87 }
88
89
90
91
92
93
94
95
96 public static HostAndPort parseFrom(URI u) throws SocketException {
97 String host = u.getHost();
98 if (host != null) {
99 return new HostAndPort(host, u.getPort());
100 }
101 String raw = u.getRawSchemeSpecificPart();
102 Matcher m = PAT_HOST_AND_PORT.matcher(raw);
103 if (!m.find()) {
104 throw new SocketException("Cannot parse URI: " + u);
105 }
106 try {
107 host = URLDecoder.decode(m.group("host"), "UTF-8");
108 } catch (UnsupportedEncodingException e) {
109 throw new IllegalStateException(e);
110 }
111
112 String portStr = m.group("port");
113 int port;
114 if (portStr == null) {
115 port = -1;
116 } else {
117 port = Integer.parseInt(portStr);
118 }
119
120 return new HostAndPort(host, port);
121 }
122
123 private static String urlEncode(String s) {
124 try {
125 return URLEncoder.encode(s, "UTF-8");
126 } catch (UnsupportedEncodingException e) {
127 throw new IllegalStateException(e);
128 }
129 }
130
131
132
133
134
135
136 public String getHostname() {
137 return hostname;
138 }
139
140
141
142
143
144
145 public int getPort() {
146 return port;
147 }
148
149
150
151
152
153
154
155 public URI toURI(String scheme) {
156 return toURI(scheme, null, null, null, null);
157 }
158
159
160
161
162
163
164
165
166
167 public URI toURI(String scheme, URI template) {
168 if (template == null) {
169 return toURI(scheme, null, null, null, null);
170 }
171
172 String rawAuthority = template.getRawAuthority();
173 int at = rawAuthority.indexOf('@');
174 if (at >= 0) {
175 rawAuthority = rawAuthority.substring(0, at);
176 } else if (rawAuthority.length() > 0 && template.getHost() == null) {
177
178 rawAuthority = null;
179 } else if (rawAuthority.length() > 0 && template.getAuthority().equals(template.getHost())) {
180
181 rawAuthority = null;
182 } else if (rawAuthority.length() > 0 && template.getAuthority().equals(template.getHost() + ":"
183 + template.getPort())) {
184
185 rawAuthority = null;
186 }
187
188 return toURI(scheme, rawAuthority, template.getRawPath(), template.getRawQuery(), template
189 .getRawFragment());
190 }
191
192
193
194
195
196
197
198
199
200
201
202
203 public URI toURI(String scheme, String rawAuthority, String rawPath, String rawQuery,
204 String rawFragment) {
205 Objects.requireNonNull(scheme);
206 if (rawPath != null && !rawPath.isEmpty()) {
207 if (!rawPath.startsWith("/")) {
208 throw new IllegalArgumentException("Path must be absolute: " + rawPath);
209 }
210 }
211
212 return URI.create(scheme + "://" + (rawAuthority == null ? "" : rawAuthority + "@") + urlEncode(
213 getHostname()).replace("%2C", ",") + (port <= 0 ? "" : (":" + port)) + (rawPath == null ? ""
214 : rawPath) + (rawQuery == null ? "" : "?" + rawQuery) + (rawFragment == null ? "" : "#"
215 + rawFragment));
216 }
217 }