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.http.conn.routing;
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.http.HttpHost;
38 import org.apache.http.annotation.Contract;
39 import org.apache.http.annotation.ThreadingBehavior;
40 import org.apache.http.util.Args;
41 import org.apache.http.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 target, final InetAddress local, final List<HttpHost> proxies,
73 final boolean secure, final TunnelType tunnelled, final LayerType layered) {
74 Args.notNull(target, "Target host");
75 this.targetHost = normalize(target);
76 this.localAddress = local;
77 if (proxies != null && !proxies.isEmpty()) {
78 this.proxyChain = new ArrayList<HttpHost>(proxies);
79 } else {
80 this.proxyChain = null;
81 }
82 if (tunnelled == TunnelType.TUNNELLED) {
83 Args.check(this.proxyChain != null, "Proxy required if tunnelled");
84 }
85 this.secure = secure;
86 this.tunnelled = tunnelled != null ? tunnelled : TunnelType.PLAIN;
87 this.layered = layered != null ? layered : LayerType.PLAIN;
88 }
89
90
91 private static int getDefaultPort(final String schemeName) {
92 if ("http".equalsIgnoreCase(schemeName)) {
93 return 80;
94 } else if ("https".equalsIgnoreCase(schemeName)) {
95 return 443;
96 } else {
97 return -1;
98 }
99
100 }
101
102
103 private static HttpHost normalize(final HttpHost target) {
104 if (target.getPort() >= 0 ) {
105 return target;
106 }
107 final InetAddress address = target.getAddress();
108 final String schemeName = target.getSchemeName();
109 return address != null
110 ? new HttpHost(address, getDefaultPort(schemeName), schemeName)
111 : new HttpHost(target.getHostName(), getDefaultPort(schemeName),
112 schemeName);
113 }
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128 public HttpRoute(final HttpHost target, final InetAddress local, final HttpHost[] proxies,
129 final boolean secure, final TunnelType tunnelled, final LayerType layered) {
130 this(target, local, proxies != null ? Arrays.asList(proxies) : null,
131 secure, tunnelled, layered);
132 }
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151 public HttpRoute(final HttpHost target, final InetAddress local, final HttpHost proxy,
152 final boolean secure, final TunnelType tunnelled, final LayerType layered) {
153 this(target, local, proxy != null ? Collections.singletonList(proxy) : null,
154 secure, tunnelled, layered);
155 }
156
157
158
159
160
161
162
163
164
165
166
167 public HttpRoute(final HttpHost target, final InetAddress local, final boolean secure) {
168 this(target, local, Collections.<HttpHost>emptyList(), secure,
169 TunnelType.PLAIN, LayerType.PLAIN);
170 }
171
172
173
174
175
176
177 public HttpRoute(final HttpHost target) {
178 this(target, null, Collections.<HttpHost>emptyList(), false,
179 TunnelType.PLAIN, LayerType.PLAIN);
180 }
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195 public HttpRoute(final HttpHost target, final InetAddress local, final HttpHost proxy,
196 final boolean secure) {
197 this(target, local, Collections.singletonList(Args.notNull(proxy, "Proxy host")), secure,
198 secure ? TunnelType.TUNNELLED : TunnelType.PLAIN,
199 secure ? LayerType.LAYERED : LayerType.PLAIN);
200 }
201
202
203
204
205
206
207
208
209
210 public HttpRoute(final HttpHost target, final HttpHost proxy) {
211 this(target, null, proxy, false);
212 }
213
214 @Override
215 public HttpHost getTargetHost() {
216 return this.targetHost;
217 }
218
219 @Override
220 public InetAddress getLocalAddress() {
221 return this.localAddress;
222 }
223
224 public InetSocketAddress getLocalSocketAddress() {
225 return this.localAddress != null ? new InetSocketAddress(this.localAddress, 0) : null;
226 }
227
228 @Override
229 public int getHopCount() {
230 return proxyChain != null ? proxyChain.size() + 1 : 1;
231 }
232
233 @Override
234 public HttpHost getHopTarget(final int hop) {
235 Args.notNegative(hop, "Hop index");
236 final int hopcount = getHopCount();
237 Args.check(hop < hopcount, "Hop index exceeds tracked route length");
238 return hop < hopcount - 1 ? this.proxyChain.get(hop) : this.targetHost;
239 }
240
241 @Override
242 public HttpHost getProxyHost() {
243 return proxyChain != null && !this.proxyChain.isEmpty() ? this.proxyChain.get(0) : null;
244 }
245
246 @Override
247 public TunnelType getTunnelType() {
248 return this.tunnelled;
249 }
250
251 @Override
252 public boolean isTunnelled() {
253 return (this.tunnelled == TunnelType.TUNNELLED);
254 }
255
256 @Override
257 public LayerType getLayerType() {
258 return this.layered;
259 }
260
261 @Override
262 public boolean isLayered() {
263 return (this.layered == LayerType.LAYERED);
264 }
265
266 @Override
267 public boolean isSecure() {
268 return this.secure;
269 }
270
271
272
273
274
275
276
277
278
279 @Override
280 public boolean equals(final Object obj) {
281 if (this == obj) {
282 return true;
283 }
284 if (obj instanceof HttpRoute) {
285 final HttpRoute./../../../../org/apache/http/conn/routing/HttpRoute.html#HttpRoute">HttpRoute that = (HttpRoute) obj;
286 return
287
288 (this.secure == that.secure) &&
289 (this.tunnelled == that.tunnelled) &&
290 (this.layered == that.layered) &&
291 LangUtils.equals(this.targetHost, that.targetHost) &&
292 LangUtils.equals(this.localAddress, that.localAddress) &&
293 LangUtils.equals(this.proxyChain, that.proxyChain);
294 }
295 return false;
296 }
297
298
299
300
301
302
303
304 @Override
305 public int hashCode() {
306 int hash = LangUtils.HASH_SEED;
307 hash = LangUtils.hashCode(hash, this.targetHost);
308 hash = LangUtils.hashCode(hash, this.localAddress);
309 if (this.proxyChain != null) {
310 for (final HttpHost element : this.proxyChain) {
311 hash = LangUtils.hashCode(hash, element);
312 }
313 }
314 hash = LangUtils.hashCode(hash, this.secure);
315 hash = LangUtils.hashCode(hash, this.tunnelled);
316 hash = LangUtils.hashCode(hash, this.layered);
317 return hash;
318 }
319
320
321
322
323
324
325 @Override
326 public String toString() {
327 final StringBuilder cab = new StringBuilder(50 + getHopCount()*30);
328 if (this.localAddress != null) {
329 cab.append(this.localAddress);
330 cab.append("->");
331 }
332 cab.append('{');
333 if (this.tunnelled == TunnelType.TUNNELLED) {
334 cab.append('t');
335 }
336 if (this.layered == LayerType.LAYERED) {
337 cab.append('l');
338 }
339 if (this.secure) {
340 cab.append('s');
341 }
342 cab.append("}->");
343 if (this.proxyChain != null) {
344 for (final HttpHost aProxyChain : this.proxyChain) {
345 cab.append(aProxyChain);
346 cab.append("->");
347 }
348 }
349 cab.append(this.targetHost);
350 return cab.toString();
351 }
352
353
354 @Override
355 public Object clone() throws CloneNotSupportedException {
356 return super.clone();
357 }
358
359 }