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
318 public LinkedList<String> getRegisteredListeners()
319 {
320 return _registeredListeners;
321 }
322
323
324
325
326
327
328
329
330
331
332 public void setUseDirectBuffers(boolean direct)
333 {
334 _useDirectBuffers = direct;
335 }
336
337
338
339
340
341 public int getConnectorType()
342 {
343 return _connectorType;
344 }
345
346
347 public void setConnectorType(int connectorType)
348 {
349 this._connectorType = connectorType;
350 }
351
352
353
354
355
356 @Override
357 protected Buffer newRequestBuffer(int size)
358 {
359 if (_connectorType == CONNECTOR_SOCKET)
360 return new ByteArrayBuffer(size);
361 return _useDirectBuffers?new DirectNIOBuffer(size):new IndirectNIOBuffer(size);
362 }
363
364
365
366
367
368 @Override
369 protected Buffer newRequestHeader(int size)
370 {
371 if (_connectorType == CONNECTOR_SOCKET)
372 return new ByteArrayBuffer(size);
373 return new IndirectNIOBuffer(size);
374 }
375
376
377
378
379
380 @Override
381 protected Buffer newResponseBuffer(int size)
382 {
383 if (_connectorType == CONNECTOR_SOCKET)
384 return new ByteArrayBuffer(size);
385 return _useDirectBuffers?new DirectNIOBuffer(size):new IndirectNIOBuffer(size);
386 }
387
388
389
390
391
392 @Override
393 protected Buffer newResponseHeader(int size)
394 {
395 if (_connectorType == CONNECTOR_SOCKET)
396 return new ByteArrayBuffer(size);
397 return new IndirectNIOBuffer(size);
398 }
399
400
401 @Override
402 protected boolean isRequestHeader(Buffer buffer)
403 {
404 if (_connectorType == CONNECTOR_SOCKET)
405 return buffer instanceof ByteArrayBuffer;
406 return buffer instanceof IndirectNIOBuffer;
407 }
408
409
410 @Override
411 protected boolean isResponseHeader(Buffer buffer)
412 {
413 if (_connectorType == CONNECTOR_SOCKET)
414 return buffer instanceof ByteArrayBuffer;
415 return buffer instanceof IndirectNIOBuffer;
416 }
417
418
419
420 public int getMaxConnectionsPerAddress()
421 {
422 return _maxConnectionsPerAddress;
423 }
424
425
426 public void setMaxConnectionsPerAddress(int maxConnectionsPerAddress)
427 {
428 _maxConnectionsPerAddress = maxConnectionsPerAddress;
429 }
430
431
432 @Override
433 protected void doStart() throws Exception
434 {
435 super.doStart();
436
437 _timeoutQ.setDuration(_timeout);
438 _timeoutQ.setNow();
439 _idleTimeoutQ.setDuration(_idleTimeout);
440 _idleTimeoutQ.setNow();
441
442 if (_threadPool == null)
443 {
444 QueuedThreadPool pool = new QueuedThreadPool();
445 pool.setMaxThreads(16);
446 pool.setDaemon(true);
447 pool.setName("HttpClient");
448 _threadPool = pool;
449 }
450
451 if (_threadPool instanceof LifeCycle)
452 {
453 ((LifeCycle)_threadPool).start();
454 }
455
456
457 if (_connectorType == CONNECTOR_SELECT_CHANNEL)
458 {
459
460 _connector = new SelectConnector(this);
461 }
462 else
463 {
464 _connector = new SocketConnector(this);
465 }
466 _connector.start();
467
468 _threadPool.dispatch(new Runnable()
469 {
470 public void run()
471 {
472 while (isRunning())
473 {
474 _timeoutQ.tick(System.currentTimeMillis());
475 _idleTimeoutQ.tick(_timeoutQ.getNow());
476 try
477 {
478 Thread.sleep(200);
479 }
480 catch (InterruptedException e)
481 {
482 }
483 }
484 }
485 });
486
487 }
488
489
490 long getNow()
491 {
492 return _timeoutQ.getNow();
493 }
494
495
496 @Override
497 protected void doStop() throws Exception
498 {
499 _connector.stop();
500 _connector = null;
501 if (_threadPool instanceof LifeCycle)
502 {
503 ((LifeCycle)_threadPool).stop();
504 }
505 for (HttpDestination destination : _destinations.values())
506 {
507 destination.close();
508 }
509
510 _timeoutQ.cancelAll();
511 _idleTimeoutQ.cancelAll();
512 super.doStop();
513 }
514
515
516 interface Connector extends LifeCycle
517 {
518 public void startConnection(HttpDestination destination) throws IOException;
519 }
520
521
522
523
524
525
526
527
528 protected SSLContext getSSLContext() throws IOException
529 {
530 if (_sslContext == null)
531 {
532 if (_keyStoreLocation == null)
533 {
534 _sslContext = getLooseSSLContext();
535 }
536 else
537 {
538 _sslContext = getStrictSSLContext();
539 }
540 }
541 return _sslContext;
542 }
543
544 protected SSLContext getStrictSSLContext() throws IOException
545 {
546
547 try
548 {
549 if (_trustStoreLocation == null)
550 {
551 _trustStoreLocation = _keyStoreLocation;
552 _trustStoreType = _keyStoreType;
553 }
554
555 KeyManager[] keyManagers = null;
556 InputStream keystoreInputStream = null;
557
558 keystoreInputStream = Resource.newResource(_keyStoreLocation).getInputStream();
559 KeyStore keyStore = KeyStore.getInstance(_keyStoreType);
560 keyStore.load(keystoreInputStream, _keyStorePassword == null ? null : _keyStorePassword.toString().toCharArray());
561
562 KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(_keyManagerAlgorithm);
563 keyManagerFactory.init(keyStore, _keyManagerPassword == null ? null : _keyManagerPassword.toString().toCharArray());
564 keyManagers = keyManagerFactory.getKeyManagers();
565
566 TrustManager[] trustManagers = null;
567 InputStream truststoreInputStream = null;
568
569 truststoreInputStream = Resource.newResource(_trustStoreLocation).getInputStream();
570 KeyStore trustStore = KeyStore.getInstance(_trustStoreType);
571 trustStore.load(truststoreInputStream, _trustStorePassword == null ? null : _trustStorePassword.toString().toCharArray());
572
573 TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(_trustManagerAlgorithm);
574 trustManagerFactory.init(trustStore);
575 trustManagers = trustManagerFactory.getTrustManagers();
576
577 SecureRandom secureRandom = _secureRandomAlgorithm == null ? null : SecureRandom.getInstance(_secureRandomAlgorithm);
578 SSLContext context = _provider == null ? SSLContext.getInstance(_protocol) : SSLContext.getInstance(_protocol, _provider);
579 context.init(keyManagers, trustManagers, secureRandom);
580 return context;
581 }
582 catch (Exception e)
583 {
584 e.printStackTrace();
585 throw new IOException("error generating ssl context for " + _keyStoreLocation + " " + e.getMessage());
586 }
587 }
588
589 protected SSLContext getLooseSSLContext() throws IOException
590 {
591
592
593
594 TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager()
595 {
596 public java.security.cert.X509Certificate[] getAcceptedIssuers()
597 {
598 return null;
599 }
600
601 public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
602 {
603 }
604
605 public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
606 {
607 }
608 }};
609
610 HostnameVerifier hostnameVerifier = new HostnameVerifier()
611 {
612 public boolean verify(String urlHostName, SSLSession session)
613 {
614 Log.warn("Warning: URL Host: " + urlHostName + " vs." + session.getPeerHost());
615 return true;
616 }
617 };
618
619
620 try
621 {
622
623 SSLContext sslContext = SSLContext.getInstance("SSL");
624 sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
625 return sslContext;
626 }
627 catch (Exception e)
628 {
629 throw new IOException("issue ignoring certs");
630 }
631 }
632
633
634
635
636
637 public long getIdleTimeout()
638 {
639 return _idleTimeout;
640 }
641
642
643
644
645
646 public void setIdleTimeout(long ms)
647 {
648 _idleTimeout = ms;
649 }
650
651
652
653
654
655 @Deprecated
656 public int getSoTimeout()
657 {
658 return Long.valueOf(getTimeout()).intValue();
659 }
660
661
662
663
664
665 @Deprecated
666 public void setSoTimeout(int timeout)
667 {
668 setTimeout(timeout);
669 }
670
671
672
673
674
675 public long getTimeout()
676 {
677 return _timeout;
678 }
679
680
681
682
683
684 public void setTimeout(long timeout)
685 {
686 _timeout = timeout;
687 }
688
689
690
691
692 public int getConnectTimeout()
693 {
694 return _connectTimeout;
695 }
696
697
698
699
700 public void setConnectTimeout(int connectTimeout)
701 {
702 this._connectTimeout = connectTimeout;
703 }
704
705
706 public Address getProxy()
707 {
708 return _proxy;
709 }
710
711
712 public void setProxy(Address proxy)
713 {
714 this._proxy = proxy;
715 }
716
717
718 public Authentication getProxyAuthentication()
719 {
720 return _proxyAuthentication;
721 }
722
723
724 public void setProxyAuthentication(Authentication authentication)
725 {
726 _proxyAuthentication = authentication;
727 }
728
729
730 public boolean isProxied()
731 {
732 return this._proxy != null;
733 }
734
735
736 public Set<String> getNoProxy()
737 {
738 return _noProxy;
739 }
740
741
742 public void setNoProxy(Set<String> noProxyAddresses)
743 {
744 _noProxy = noProxyAddresses;
745 }
746
747
748 public int maxRetries()
749 {
750 return _maxRetries;
751 }
752
753
754 public void setMaxRetries(int retries)
755 {
756 _maxRetries = retries;
757 }
758
759
760 public int maxRedirects()
761 {
762 return _maxRedirects;
763 }
764
765
766 public void setMaxRedirects(int redirects)
767 {
768 _maxRedirects = redirects;
769 }
770
771
772 public String getTrustStoreLocation()
773 {
774 return _trustStoreLocation;
775 }
776
777
778 public void setTrustStoreLocation(String trustStoreLocation)
779 {
780 this._trustStoreLocation = trustStoreLocation;
781 }
782
783
784 public String getKeyStoreLocation()
785 {
786 return _keyStoreLocation;
787 }
788
789
790 public void setKeyStoreLocation(String keyStoreLocation)
791 {
792 this._keyStoreLocation = keyStoreLocation;
793 }
794
795
796 public void setKeyStorePassword(String keyStorePassword)
797 {
798 this._keyStorePassword = new Password(keyStorePassword).toString();
799 }
800
801
802 public void setKeyManagerPassword(String keyManagerPassword)
803 {
804 this._keyManagerPassword = new Password(keyManagerPassword).toString();
805 }
806
807
808 public void setTrustStorePassword(String trustStorePassword)
809 {
810 this._trustStorePassword = new Password(trustStorePassword).toString();
811 }
812
813
814 public String getKeyStoreType()
815 {
816 return this._keyStoreType;
817 }
818
819
820 public void setKeyStoreType(String keyStoreType)
821 {
822 this._keyStoreType = keyStoreType;
823 }
824
825
826 public String getTrustStoreType()
827 {
828 return this._trustStoreType;
829 }
830
831
832 public void setTrustStoreType(String trustStoreType)
833 {
834 this._trustStoreType = trustStoreType;
835 }
836 }