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 import java.util.Objects;
37
38 import org.apache.hc.core5.annotation.Contract;
39 import org.apache.hc.core5.annotation.ThreadingBehavior;
40 import org.apache.hc.core5.http.HttpHost;
41 import org.apache.hc.core5.net.NamedEndpoint;
42 import org.apache.hc.core5.util.Args;
43 import org.apache.hc.core5.util.LangUtils;
44
45
46
47
48
49
50 @Contract(threading = ThreadingBehavior.IMMUTABLE)
51 public final class HttpRoute implements RouteInfo, Cloneable {
52
53
54 private final HttpHost targetHost;
55
56
57 private final NamedEndpoint targetName;
58
59
60
61
62
63 private final InetAddress localAddress;
64
65
66 private final List<HttpHost> proxyChain;
67
68
69 private final TunnelType tunnelled;
70
71
72 private final LayerType layered;
73
74
75 private final boolean secure;
76
77 HttpRoute(final HttpHost targetHost,
78 final NamedEndpoint targetName,
79 final InetAddress local,
80 final List<HttpHost> proxies,
81 final boolean secure,
82 final TunnelType tunnelled,
83 final LayerType layered) {
84 Args.notNull(targetHost, "Target host");
85 Args.notNegative(targetHost.getPort(), "Target port");
86 this.targetName = targetName;
87 this.targetHost = targetHost;
88 this.localAddress = local;
89 if (proxies != null && !proxies.isEmpty()) {
90 this.proxyChain = new ArrayList<>(proxies);
91 } else {
92 this.proxyChain = null;
93 }
94 if (tunnelled == TunnelType.TUNNELLED) {
95 Args.check(this.proxyChain != null, "Proxy required if tunnelled");
96 }
97 this.secure = secure;
98 this.tunnelled = tunnelled != null ? tunnelled : TunnelType.PLAIN;
99 this.layered = layered != null ? layered : LayerType.PLAIN;
100 }
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115 public HttpRoute(final HttpHost target, final InetAddress local, final HttpHost[] proxies,
116 final boolean secure, final TunnelType tunnelled, final LayerType layered) {
117 this(target, null, local, proxies != null ? Arrays.asList(proxies) : null,
118 secure, tunnelled, layered);
119 }
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137 public HttpRoute(final HttpHost target, final NamedEndpoint targetName, final InetAddress local, final HttpHost[] proxies,
138 final boolean secure, final TunnelType tunnelled, final LayerType layered) {
139 this(target, targetName, local, proxies != null ? Arrays.asList(proxies) : null,
140 secure, tunnelled, layered);
141 }
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160 public HttpRoute(final HttpHost target, final InetAddress local, final HttpHost proxy,
161 final boolean secure, final TunnelType tunnelled, final LayerType layered) {
162 this(target, null, local, proxy != null ? Collections.singletonList(proxy) : null,
163 secure, tunnelled, layered);
164 }
165
166
167
168
169
170
171
172
173
174
175
176 public HttpRoute(final HttpHost target, final InetAddress local, final boolean secure) {
177 this(target, null, local, Collections.emptyList(), secure, TunnelType.PLAIN, LayerType.PLAIN);
178 }
179
180
181
182
183
184
185
186
187
188
189
190
191
192 public HttpRoute(final HttpHost target, final NamedEndpoint targetName, final InetAddress local, final boolean secure) {
193 this(target, targetName, local, Collections.emptyList(), secure, TunnelType.PLAIN, LayerType.PLAIN);
194 }
195
196
197
198
199
200
201 public HttpRoute(final HttpHost target) {
202 this(target, null, null, Collections.emptyList(), false, TunnelType.PLAIN, LayerType.PLAIN);
203 }
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221 public HttpRoute(final HttpHost target, final NamedEndpoint targetName, final InetAddress local,
222 final HttpHost proxy, final boolean secure) {
223 this(target, targetName, local, Collections.singletonList(Args.notNull(proxy, "Proxy host")), secure,
224 secure ? TunnelType.TUNNELLED : TunnelType.PLAIN,
225 secure ? LayerType.LAYERED : LayerType.PLAIN);
226 }
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241 public HttpRoute(final HttpHost target, final InetAddress local, final HttpHost proxy,
242 final boolean secure) {
243 this(target, null, local, Collections.singletonList(Args.notNull(proxy, "Proxy host")), secure,
244 secure ? TunnelType.TUNNELLED : TunnelType.PLAIN,
245 secure ? LayerType.LAYERED : LayerType.PLAIN);
246 }
247
248
249
250
251
252
253
254
255
256 public HttpRoute(final HttpHost target, final HttpHost proxy) {
257 this(target, null, proxy, false);
258 }
259
260 @Override
261 public HttpHost getTargetHost() {
262 return this.targetHost;
263 }
264
265
266
267
268 @Override
269 public NamedEndpoint getTargetName() {
270 return targetName;
271 }
272
273 @Override
274 public InetAddress getLocalAddress() {
275 return this.localAddress;
276 }
277
278 public InetSocketAddress getLocalSocketAddress() {
279 return this.localAddress != null ? new InetSocketAddress(this.localAddress, 0) : null;
280 }
281
282 @Override
283 public int getHopCount() {
284 return proxyChain != null ? proxyChain.size() + 1 : 1;
285 }
286
287 @Override
288 public HttpHost getHopTarget(final int hop) {
289 Args.notNegative(hop, "Hop index");
290 final int hopcount = getHopCount();
291 Args.check(hop < hopcount, "Hop index exceeds tracked route length");
292 if (hop < hopcount - 1) {
293 return this.proxyChain.get(hop);
294 }
295 return this.targetHost;
296 }
297
298 @Override
299 public HttpHost getProxyHost() {
300 return proxyChain != null && !this.proxyChain.isEmpty() ? this.proxyChain.get(0) : null;
301 }
302
303 @Override
304 public TunnelType getTunnelType() {
305 return this.tunnelled;
306 }
307
308 @Override
309 public boolean isTunnelled() {
310 return (this.tunnelled == TunnelType.TUNNELLED);
311 }
312
313 @Override
314 public LayerType getLayerType() {
315 return this.layered;
316 }
317
318 @Override
319 public boolean isLayered() {
320 return (this.layered == LayerType.LAYERED);
321 }
322
323 @Override
324 public boolean isSecure() {
325 return this.secure;
326 }
327
328
329
330
331
332
333
334
335
336 @Override
337 public boolean equals(final Object obj) {
338 if (this == obj) {
339 return true;
340 }
341 if (obj instanceof HttpRoute) {
342 final HttpRoute that = (HttpRoute) obj;
343 return
344
345 (this.secure == that.secure) &&
346 (this.tunnelled == that.tunnelled) &&
347 (this.layered == that.layered) &&
348 Objects.equals(this.targetHost, that.targetHost) &&
349 Objects.equals(this.targetName, that.targetName) &&
350 Objects.equals(this.localAddress, that.localAddress) &&
351 Objects.equals(this.proxyChain, that.proxyChain);
352 }
353 return false;
354 }
355
356
357
358
359
360
361
362 @Override
363 public int hashCode() {
364 int hash = LangUtils.HASH_SEED;
365 hash = LangUtils.hashCode(hash, this.targetHost);
366 hash = LangUtils.hashCode(hash, this.targetName);
367 hash = LangUtils.hashCode(hash, this.localAddress);
368 if (this.proxyChain != null) {
369 for (final HttpHost element : this.proxyChain) {
370 hash = LangUtils.hashCode(hash, element);
371 }
372 }
373 hash = LangUtils.hashCode(hash, this.secure);
374 hash = LangUtils.hashCode(hash, this.tunnelled);
375 hash = LangUtils.hashCode(hash, this.layered);
376 return hash;
377 }
378
379
380
381
382
383
384 @Override
385 public String toString() {
386 final StringBuilder cab = new StringBuilder(50 + getHopCount()*30);
387 if (this.localAddress != null) {
388 cab.append(this.localAddress);
389 cab.append("->");
390 }
391 cab.append('{');
392 if (this.tunnelled == TunnelType.TUNNELLED) {
393 cab.append('t');
394 }
395 if (this.layered == LayerType.LAYERED) {
396 cab.append('l');
397 }
398 if (this.secure) {
399 cab.append('s');
400 }
401 cab.append("}->");
402 if (this.proxyChain != null) {
403 for (final HttpHost aProxyChain : this.proxyChain) {
404 cab.append(aProxyChain);
405 cab.append("->");
406 }
407 }
408 if (this.targetName != null) {
409 cab.append(this.targetName);
410 cab.append("/");
411 }
412 cab.append("[");
413 cab.append(this.targetHost);
414 cab.append("]");
415 return cab.toString();
416 }
417
418
419 @Override
420 public Object clone() throws CloneNotSupportedException {
421 return super.clone();
422 }
423
424 }