1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.client;
15
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.net.UnknownHostException;
19 import java.security.KeyStore;
20 import java.security.SecureRandom;
21 import java.util.Enumeration;
22 import java.util.HashMap;
23 import java.util.LinkedList;
24 import java.util.Map;
25 import java.util.Set;
26
27 import javax.net.ssl.HostnameVerifier;
28 import javax.net.ssl.KeyManager;
29 import javax.net.ssl.KeyManagerFactory;
30 import javax.net.ssl.SSLContext;
31 import javax.net.ssl.SSLSession;
32 import javax.net.ssl.TrustManager;
33 import javax.net.ssl.TrustManagerFactory;
34 import javax.net.ssl.X509TrustManager;
35
36 import org.eclipse.jetty.client.security.Authorization;
37 import org.eclipse.jetty.client.security.RealmResolver;
38 import org.eclipse.jetty.http.HttpBuffers;
39 import org.eclipse.jetty.http.HttpSchemes;
40 import org.eclipse.jetty.io.Buffer;
41 import org.eclipse.jetty.io.ByteArrayBuffer;
42 import org.eclipse.jetty.io.nio.DirectNIOBuffer;
43 import org.eclipse.jetty.io.nio.IndirectNIOBuffer;
44 import org.eclipse.jetty.util.Attributes;
45 import org.eclipse.jetty.util.AttributesMap;
46 import org.eclipse.jetty.util.component.LifeCycle;
47 import org.eclipse.jetty.util.log.Log;
48 import org.eclipse.jetty.util.resource.Resource;
49 import org.eclipse.jetty.util.thread.QueuedThreadPool;
50 import org.eclipse.jetty.util.thread.ThreadPool;
51 import org.eclipse.jetty.util.thread.Timeout;
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 public class HttpClient extends HttpBuffers implements Attributes
82 {
83 public static final int CONNECTOR_SOCKET = 0;
84 public static final int CONNECTOR_SELECT_CHANNEL = 2;
85
86 private int _connectorType = CONNECTOR_SELECT_CHANNEL;
87 private boolean _useDirectBuffers = true;
88 private int _maxConnectionsPerAddress = Integer.MAX_VALUE;
89 private Map<Address, HttpDestination> _destinations = new HashMap<Address, HttpDestination>();
90 ThreadPool _threadPool;
91 Connector _connector;
92 private long _idleTimeout = 20000;
93 private long _timeout = 320000;
94 int _soTimeout = 10000;
95 private Timeout _timeoutQ = new Timeout();
96 private Address _proxy;
97 private Authorization _proxyAuthentication;
98 private Set<String> _noProxy;
99 private int _maxRetries = 3;
100 private LinkedList<String> _registeredListeners;
101
102
103 private String _keyStoreLocation;
104 private String _keyStoreType = "JKS";
105 private String _keyStorePassword;
106 private String _keyManagerAlgorithm = "SunX509";
107 private String _keyManagerPassword;
108 private String _trustStoreLocation;
109 private String _trustStoreType = "JKS";
110 private String _trustStorePassword;
111 private String _trustManagerAlgorithm = "SunX509";
112
113 private SSLContext _sslContext;
114
115 private String _protocol = "TLS";
116 private String _provider;
117 private String _secureRandomAlgorithm;
118
119 private RealmResolver _realmResolver;
120
121 private AttributesMap _attributes=new AttributesMap();
122
123
124 public void dump()
125 {
126 try
127 {
128 for (Map.Entry<Address, HttpDestination> entry : _destinations.entrySet())
129 {
130 Log.info("\n" + entry.getKey() + ":");
131 entry.getValue().dump();
132 }
133 }
134 catch(Exception e)
135 {
136 Log.warn(e);
137 }
138 }
139
140
141 public void send(HttpExchange exchange) throws IOException
142 {
143 boolean ssl = HttpSchemes.HTTPS_BUFFER.equalsIgnoreCase(exchange.getScheme());
144 exchange.setStatus(HttpExchange.STATUS_WAITING_FOR_CONNECTION);
145 HttpDestination destination = getDestination(exchange.getAddress(), ssl);
146 destination.send(exchange);
147 }
148
149
150
151
152
153 public ThreadPool getThreadPool()
154 {
155 return _threadPool;
156 }
157
158
159
160
161
162 public void setThreadPool(ThreadPool threadPool)
163 {
164 _threadPool = threadPool;
165 }
166
167
168
169
170
171
172
173 public Object getAttribute(String name)
174 {
175 return _attributes.getAttribute(name);
176 }
177
178
179
180
181
182 public Enumeration getAttributeNames()
183 {
184 return _attributes.getAttributeNames();
185 }
186
187
188
189
190
191 public void removeAttribute(String name)
192 {
193 _attributes.removeAttribute(name);
194 }
195
196
197
198
199
200
201
202
203
204 public void setAttribute(String name, Object attribute)
205 {
206 _attributes.setAttribute(name,attribute);
207 }
208
209
210
211
212
213
214 public void clearAttributes()
215 {
216 _attributes.clearAttributes();
217 }
218
219
220 public HttpDestination getDestination(Address remote, boolean ssl) throws UnknownHostException, IOException
221 {
222 if (remote == null)
223 throw new UnknownHostException("Remote socket address cannot be null.");
224
225 synchronized (_destinations)
226 {
227 HttpDestination destination = _destinations.get(remote);
228 if (destination == null)
229 {
230 destination = new HttpDestination(this, remote, ssl, _maxConnectionsPerAddress);
231 if (_proxy != null && (_noProxy == null || !_noProxy.contains(remote.getHost())))
232 {
233 destination.setProxy(_proxy);
234 if (_proxyAuthentication != null)
235 destination.setProxyAuthentication(_proxyAuthentication);
236 }
237 _destinations.put(remote, destination);
238 }
239 return destination;
240 }
241 }
242
243
244 public void schedule(Timeout.Task task)
245 {
246 _timeoutQ.schedule(task);
247 }
248
249
250 public void cancel(Timeout.Task task)
251 {
252 task.cancel();
253 }
254
255
256
257
258
259 public boolean getUseDirectBuffers()
260 {
261 return _useDirectBuffers;
262 }
263
264
265 public void setRealmResolver(RealmResolver resolver)
266 {
267 _realmResolver = resolver;
268 }
269
270
271
272
273
274
275
276 public RealmResolver getRealmResolver()
277 {
278 return _realmResolver;
279 }
280
281
282 public boolean hasRealms()
283 {
284 return _realmResolver == null ? false : true;
285 }
286
287
288
289
290
291
292
293
294
295
296
297
298
299 public void registerListener(String listenerClass)
300 {
301 if (_registeredListeners == null)
302 {
303 _registeredListeners = new LinkedList<String>();
304 }
305 _registeredListeners.add(listenerClass);
306 }
307
308 public LinkedList<String> getRegisteredListeners()
309 {
310 return _registeredListeners;
311 }
312
313
314
315
316
317
318
319
320
321
322 public void setUseDirectBuffers(boolean direct)
323 {
324 _useDirectBuffers = direct;
325 }
326
327
328
329
330
331 public int getConnectorType()
332 {
333 return _connectorType;
334 }
335
336
337 public void setConnectorType(int connectorType)
338 {
339 this._connectorType = connectorType;
340 }
341
342
343
344
345
346 @Override
347 protected Buffer newRequestBuffer(int size)
348 {
349 if (_connectorType == CONNECTOR_SOCKET)
350 return new ByteArrayBuffer(size);
351 return _useDirectBuffers?new DirectNIOBuffer(size):new IndirectNIOBuffer(size);
352 }
353
354
355
356
357
358 @Override
359 protected Buffer newRequestHeader(int size)
360 {
361 if (_connectorType == CONNECTOR_SOCKET)
362 return new ByteArrayBuffer(size);
363 return new IndirectNIOBuffer(size);
364 }
365
366
367
368
369
370 @Override
371 protected Buffer newResponseBuffer(int size)
372 {
373 if (_connectorType == CONNECTOR_SOCKET)
374 return new ByteArrayBuffer(size);
375 return _useDirectBuffers?new DirectNIOBuffer(size):new IndirectNIOBuffer(size);
376 }
377
378
379
380
381
382 @Override
383 protected Buffer newResponseHeader(int size)
384 {
385 if (_connectorType == CONNECTOR_SOCKET)
386 return new ByteArrayBuffer(size);
387 return new IndirectNIOBuffer(size);
388 }
389
390
391 public int getMaxConnectionsPerAddress()
392 {
393 return _maxConnectionsPerAddress;
394 }
395
396
397 public void setMaxConnectionsPerAddress(int maxConnectionsPerAddress)
398 {
399 _maxConnectionsPerAddress = maxConnectionsPerAddress;
400 }
401
402
403 protected void doStart() throws Exception
404 {
405 super.doStart();
406
407 _timeoutQ.setNow();
408 _timeoutQ.setDuration(_timeout);
409
410 if (_threadPool == null)
411 {
412 QueuedThreadPool pool = new QueuedThreadPool();
413 pool.setMaxThreads(16);
414 pool.setDaemon(true);
415 pool.setName("HttpClient");
416 _threadPool = pool;
417 }
418
419 if (_threadPool instanceof LifeCycle)
420 {
421 ((LifeCycle)_threadPool).start();
422 }
423
424
425 if (_connectorType == CONNECTOR_SELECT_CHANNEL)
426 {
427
428 _connector = new SelectConnector(this);
429 }
430 else
431 {
432 _connector = new SocketConnector(this);
433 }
434 _connector.start();
435
436 _threadPool.dispatch(new Runnable()
437 {
438 public void run()
439 {
440 while (isRunning())
441 {
442 _timeoutQ.setNow();
443 _timeoutQ.tick();
444 try
445 {
446 Thread.sleep(1000);
447 }
448 catch (InterruptedException e)
449 {
450 }
451 }
452 }
453 });
454
455 }
456
457
458 protected void doStop() throws Exception
459 {
460 _connector.stop();
461 _connector = null;
462 if (_threadPool instanceof LifeCycle)
463 {
464 ((LifeCycle)_threadPool).stop();
465 }
466 for (HttpDestination destination : _destinations.values())
467 {
468 destination.close();
469 }
470
471 _timeoutQ.cancelAll();
472 super.doStop();
473 }
474
475
476 interface Connector extends LifeCycle
477 {
478 public void startConnection(HttpDestination destination) throws IOException;
479
480 }
481
482
483
484
485
486
487
488
489 protected SSLContext getSSLContext() throws IOException
490 {
491 if (_sslContext == null)
492 {
493 if (_keyStoreLocation == null)
494 {
495 _sslContext = getLooseSSLContext();
496 }
497 else
498 {
499 _sslContext = getStrictSSLContext();
500 }
501 }
502 return _sslContext;
503 }
504
505 protected SSLContext getStrictSSLContext() throws IOException
506 {
507
508 try
509 {
510 if (_trustStoreLocation == null)
511 {
512 _trustStoreLocation = _keyStoreLocation;
513 _trustStoreType = _keyStoreType;
514 }
515
516 KeyManager[] keyManagers = null;
517 InputStream keystoreInputStream = null;
518
519 keystoreInputStream = Resource.newResource(_keyStoreLocation).getInputStream();
520 KeyStore keyStore = KeyStore.getInstance(_keyStoreType);
521 keyStore.load(keystoreInputStream, _keyStorePassword == null ? null : _keyStorePassword.toString().toCharArray());
522
523 KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(_keyManagerAlgorithm);
524 keyManagerFactory.init(keyStore, _keyManagerPassword == null ? null : _keyManagerPassword.toString().toCharArray());
525 keyManagers = keyManagerFactory.getKeyManagers();
526
527 TrustManager[] trustManagers = null;
528 InputStream truststoreInputStream = null;
529
530 truststoreInputStream = Resource.newResource(_trustStoreLocation).getInputStream();
531 KeyStore trustStore = KeyStore.getInstance(_trustStoreType);
532 trustStore.load(truststoreInputStream, _trustStorePassword == null ? null : _trustStorePassword.toString().toCharArray());
533
534 TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(_trustManagerAlgorithm);
535 trustManagerFactory.init(trustStore);
536 trustManagers = trustManagerFactory.getTrustManagers();
537
538 SecureRandom secureRandom = _secureRandomAlgorithm == null ? null : SecureRandom.getInstance(_secureRandomAlgorithm);
539 SSLContext context = _provider == null ? SSLContext.getInstance(_protocol) : SSLContext.getInstance(_protocol, _provider);
540 context.init(keyManagers, trustManagers, secureRandom);
541 return context;
542 }
543 catch (Exception e)
544 {
545 e.printStackTrace();
546 throw new IOException("error generating ssl context for " + _keyStoreLocation + " " + e.getMessage());
547 }
548 }
549
550 protected SSLContext getLooseSSLContext() throws IOException
551 {
552
553
554
555 TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager()
556 {
557 public java.security.cert.X509Certificate[] getAcceptedIssuers()
558 {
559 return null;
560 }
561
562 public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
563 {
564 }
565
566 public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
567 {
568 }
569 }};
570
571 HostnameVerifier hostnameVerifier = new HostnameVerifier()
572 {
573 public boolean verify(String urlHostName, SSLSession session)
574 {
575 Log.warn("Warning: URL Host: " + urlHostName + " vs." + session.getPeerHost());
576 return true;
577 }
578 };
579
580
581 try
582 {
583
584 SSLContext sslContext = SSLContext.getInstance("SSL");
585 sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
586 return sslContext;
587 }
588 catch (Exception e)
589 {
590 throw new IOException("issue ignoring certs");
591 }
592 }
593
594
595
596
597
598 public long getIdleTimeout()
599 {
600 return _idleTimeout;
601 }
602
603
604
605
606
607 public void setIdleTimeout(long ms)
608 {
609 _idleTimeout = ms;
610 }
611
612
613 public int getSoTimeout()
614 {
615 return _soTimeout;
616 }
617
618
619 public void setSoTimeout(int so)
620 {
621 _soTimeout = so;
622 }
623
624
625
626
627
628 public long getTimeout()
629 {
630 return _timeout;
631 }
632
633
634
635
636
637 public void setTimeout(long ms)
638 {
639 _timeout = ms;
640 }
641
642
643 public Address getProxy()
644 {
645 return _proxy;
646 }
647
648
649 public void setProxy(Address proxy)
650 {
651 this._proxy = proxy;
652 }
653
654
655 public Authorization getProxyAuthentication()
656 {
657 return _proxyAuthentication;
658 }
659
660
661 public void setProxyAuthentication(Authorization authentication)
662 {
663 _proxyAuthentication = authentication;
664 }
665
666
667 public boolean isProxied()
668 {
669 return this._proxy != null;
670 }
671
672
673 public Set<String> getNoProxy()
674 {
675 return _noProxy;
676 }
677
678
679 public void setNoProxy(Set<String> noProxyAddresses)
680 {
681 _noProxy = noProxyAddresses;
682 }
683
684
685 public int maxRetries()
686 {
687 return _maxRetries;
688 }
689
690
691 public void setMaxRetries(int retries)
692 {
693 _maxRetries = retries;
694 }
695
696 public String getTrustStoreLocation()
697 {
698 return _trustStoreLocation;
699 }
700
701 public void setTrustStoreLocation(String trustStoreLocation)
702 {
703 this._trustStoreLocation = trustStoreLocation;
704 }
705
706 public String getKeyStoreLocation()
707 {
708 return _keyStoreLocation;
709 }
710
711 public void setKeyStoreLocation(String keyStoreLocation)
712 {
713 this._keyStoreLocation = keyStoreLocation;
714 }
715
716 public void setKeyStorePassword(String _keyStorePassword)
717 {
718 this._keyStorePassword = _keyStorePassword;
719 }
720
721 public void setKeyManagerPassword(String _keyManagerPassword)
722 {
723 this._keyManagerPassword = _keyManagerPassword;
724 }
725
726 public void setTrustStorePassword(String _trustStorePassword)
727 {
728 this._trustStorePassword = _trustStorePassword;
729 }
730 }