1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.hc.client5.http;
29
30 import java.net.InetAddress;
31 import java.net.InetSocketAddress;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.Collections;
35 import java.util.List;
36
37 import org.apache.hc.core5.annotation.Contract;
38 import org.apache.hc.core5.annotation.ThreadingBehavior;
39 import org.apache.hc.core5.http.HttpHost;
40 import org.apache.hc.core5.util.Args;
41 import org.apache.hc.core5.util.LangUtils;
42
43
44
45
46
47
48 @Contract(threading = ThreadingBehavior.IMMUTABLE)
49 public final class HttpRoute implements RouteInfo, Cloneable {
50
51
52 private final HttpHost targetHost;
53
54
55
56
57
58 private final InetAddress localAddress;
59
60
61 private final List<HttpHost> proxyChain;
62
63
64 private final TunnelType tunnelled;
65
66
67 private final LayerType layered;
68
69
70 private final boolean secure;
71
72 private HttpRoute(final HttpHost targetHost, final InetAddress local, final List<HttpHost> proxies,
73 final boolean secure, final TunnelType tunnelled, final LayerType layered) {
74 Args.notNull(targetHost, "Target host");
75 Args.notNegative(targetHost.getPort(), "Target port");
76 this.targetHost = targetHost;
77 this.localAddress = local;
78 if (proxies != null && !proxies.isEmpty()) {
79 this.proxyChain = new ArrayList<>(proxies);
80 } else {
81 this.proxyChain = null;
82 }
83 if (tunnelled == TunnelType.TUNNELLED) {
84 Args.check(this.proxyChain != null, "Proxy required if tunnelled");
85 }
86 this.secure = secure;
87 this.tunnelled = tunnelled != null ? tunnelled : TunnelType.PLAIN;
88 this.layered = layered != null ? layered : LayerType.PLAIN;
89 }
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 public HttpRoute(final HttpHost target, final InetAddress local, final HttpHost[] proxies,
105 final boolean secure, final TunnelType tunnelled, final LayerType layered) {
106 this(target, local, proxies != null ? Arrays.asList(proxies) : null,
107 secure, tunnelled, layered);
108 }
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127 public HttpRoute(final HttpHost target, final InetAddress local, final HttpHost proxy,
128 final boolean secure, final TunnelType tunnelled, final LayerType layered) {
129 this(target, local, proxy != null ? Collections.singletonList(proxy) : null,
130 secure, tunnelled, layered);
131 }
132
133
134
135
136
137
138
139
140
141
142
143 public HttpRoute(final HttpHost target, final InetAddress local, final boolean secure) {
144 this(target, local, Collections.<HttpHost>emptyList(), secure,
145 TunnelType.PLAIN, LayerType.PLAIN);
146 }
147
148
149
150
151
152
153 public HttpRoute(final HttpHost target) {
154 this(target, null, Collections.<HttpHost>emptyList(), false,
155 TunnelType.PLAIN, LayerType.PLAIN);
156 }
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171 public HttpRoute(final HttpHost target, final InetAddress local, final HttpHost proxy,
172 final boolean secure) {
173 this(target, local, Collections.singletonList(Args.notNull(proxy, "Proxy host")), secure,
174 secure ? TunnelType.TUNNELLED : TunnelType.PLAIN,
175 secure ? LayerType.LAYERED : LayerType.PLAIN);
176 }
177
178
179
180
181
182
183
184
185
186 public HttpRoute(final HttpHost target, final HttpHost proxy) {
187 this(target, null, proxy, false);
188 }
189
190 @Override
191 public HttpHost getTargetHost() {
192 return this.targetHost;
193 }
194
195 @Override
196 public InetAddress getLocalAddress() {
197 return this.localAddress;
198 }
199
200 public InetSocketAddress getLocalSocketAddress() {
201 return this.localAddress != null ? new InetSocketAddress(this.localAddress, 0) : null;
202 }
203
204 @Override
205 public int getHopCount() {
206 return proxyChain != null ? proxyChain.size() + 1 : 1;
207 }
208
209 @Override
210 public HttpHost getHopTarget(final int hop) {
211 Args.notNegative(hop, "Hop index");
212 final int hopcount = getHopCount();
213 Args.check(hop < hopcount, "Hop index exceeds tracked route length");
214 if (hop < hopcount - 1) {
215 return this.proxyChain.get(hop);
216 }
217 return this.targetHost;
218 }
219
220 @Override
221 public HttpHost getProxyHost() {
222 return proxyChain != null && !this.proxyChain.isEmpty() ? this.proxyChain.get(0) : null;
223 }
224
225 @Override
226 public TunnelType getTunnelType() {
227 return this.tunnelled;
228 }
229
230 @Override
231 public boolean isTunnelled() {
232 return (this.tunnelled == TunnelType.TUNNELLED);
233 }
234
235 @Override
236 public LayerType getLayerType() {
237 return this.layered;
238 }
239
240 @Override
241 public boolean isLayered() {
242 return (this.layered == LayerType.LAYERED);
243 }
244
245 @Override
246 public boolean isSecure() {
247 return this.secure;
248 }
249
250
251
252
253
254
255
256
257
258 @Override
259 public boolean equals(final Object obj) {
260 if (this == obj) {
261 return true;
262 }
263 if (obj instanceof HttpRoute) {
264 final HttpRoute./../../../../org/apache/hc/client5/http/HttpRoute.html#HttpRoute">HttpRoute that = (HttpRoute) obj;
265 return
266
267 (this.secure == that.secure) &&
268 (this.tunnelled == that.tunnelled) &&
269 (this.layered == that.layered) &&
270 LangUtils.equals(this.targetHost, that.targetHost) &&
271 LangUtils.equals(this.localAddress, that.localAddress) &&
272 LangUtils.equals(this.proxyChain, that.proxyChain);
273 }
274 return false;
275 }
276
277
278
279
280
281
282
283 @Override
284 public int hashCode() {
285 int hash = LangUtils.HASH_SEED;
286 hash = LangUtils.hashCode(hash, this.targetHost);
287 hash = LangUtils.hashCode(hash, this.localAddress);
288 if (this.proxyChain != null) {
289 for (final HttpHost element : this.proxyChain) {
290 hash = LangUtils.hashCode(hash, element);
291 }
292 }
293 hash = LangUtils.hashCode(hash, this.secure);
294 hash = LangUtils.hashCode(hash, this.tunnelled);
295 hash = LangUtils.hashCode(hash, this.layered);
296 return hash;
297 }
298
299
300
301
302
303
304 @Override
305 public String toString() {
306 final StringBuilder cab = new StringBuilder(50 + getHopCount()*30);
307 if (this.localAddress != null) {
308 cab.append(this.localAddress);
309 cab.append("->");
310 }
311 cab.append('{');
312 if (this.tunnelled == TunnelType.TUNNELLED) {
313 cab.append('t');
314 }
315 if (this.layered == LayerType.LAYERED) {
316 cab.append('l');
317 }
318 if (this.secure) {
319 cab.append('s');
320 }
321 cab.append("}->");
322 if (this.proxyChain != null) {
323 for (final HttpHost aProxyChain : this.proxyChain) {
324 cab.append(aProxyChain);
325 cab.append("->");
326 }
327 }
328 cab.append(this.targetHost);
329 return cab.toString();
330 }
331
332
333 @Override
334 public Object clone() throws CloneNotSupportedException {
335 return super.clone();
336 }
337
338 }