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