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