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