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 protected Buffer newResponseHeader(int size)
383 {
384 if (_connectorType == CONNECTOR_SOCKET)
385 return new ByteArrayBuffer(size);
386 return new IndirectNIOBuffer(size);
387 }
388
389
390 protected boolean isRequestHeader(Buffer buffer)
391 {
392 if (_connectorType == CONNECTOR_SOCKET)
393 return buffer instanceof ByteArrayBuffer;
394 return buffer instanceof IndirectNIOBuffer;
395 }
396
397
398 protected boolean isResponseHeader(Buffer buffer)
399 {
400 if (_connectorType == CONNECTOR_SOCKET)
401 return buffer instanceof ByteArrayBuffer;
402 return buffer instanceof IndirectNIOBuffer;
403 }
404
405
406
407 public int getMaxConnectionsPerAddress()
408 {
409 return _maxConnectionsPerAddress;
410 }
411
412
413 public void setMaxConnectionsPerAddress(int maxConnectionsPerAddress)
414 {
415 _maxConnectionsPerAddress = maxConnectionsPerAddress;
416 }
417
418
419 protected void doStart() throws Exception
420 {
421 super.doStart();
422
423 _timeoutQ.setNow();
424 _timeoutQ.setDuration(_timeout);
425
426 if (_threadPool == null)
427 {
428 QueuedThreadPool pool = new QueuedThreadPool();
429 pool.setMaxThreads(16);
430 pool.setDaemon(true);
431 pool.setName("HttpClient");
432 _threadPool = pool;
433 }
434
435 if (_threadPool instanceof LifeCycle)
436 {
437 ((LifeCycle)_threadPool).start();
438 }
439
440
441 if (_connectorType == CONNECTOR_SELECT_CHANNEL)
442 {
443
444 _connector = new SelectConnector(this);
445 }
446 else
447 {
448 _connector = new SocketConnector(this);
449 }
450 _connector.start();
451
452 _threadPool.dispatch(new Runnable()
453 {
454 public void run()
455 {
456 while (isRunning())
457 {
458 _timeoutQ.setNow();
459 _timeoutQ.tick();
460 try
461 {
462 Thread.sleep(1000);
463 }
464 catch (InterruptedException e)
465 {
466 }
467 }
468 }
469 });
470
471 }
472
473
474 protected void doStop() throws Exception
475 {
476 _connector.stop();
477 _connector = null;
478 if (_threadPool instanceof LifeCycle)
479 {
480 ((LifeCycle)_threadPool).stop();
481 }
482 for (HttpDestination destination : _destinations.values())
483 {
484 destination.close();
485 }
486
487 _timeoutQ.cancelAll();
488 super.doStop();
489 }
490
491
492 interface Connector extends LifeCycle
493 {
494 public void startConnection(HttpDestination destination) throws IOException;
495
496 }
497
498
499
500
501
502
503
504
505 protected SSLContext getSSLContext() throws IOException
506 {
507 if (_sslContext == null)
508 {
509 if (_keyStoreLocation == null)
510 {
511 _sslContext = getLooseSSLContext();
512 }
513 else
514 {
515 _sslContext = getStrictSSLContext();
516 }
517 }
518 return _sslContext;
519 }
520
521 protected SSLContext getStrictSSLContext() throws IOException
522 {
523
524 try
525 {
526 if (_trustStoreLocation == null)
527 {
528 _trustStoreLocation = _keyStoreLocation;
529 _trustStoreType = _keyStoreType;
530 }
531
532 KeyManager[] keyManagers = null;
533 InputStream keystoreInputStream = null;
534
535 keystoreInputStream = Resource.newResource(_keyStoreLocation).getInputStream();
536 KeyStore keyStore = KeyStore.getInstance(_keyStoreType);
537 keyStore.load(keystoreInputStream, _keyStorePassword == null ? null : _keyStorePassword.toString().toCharArray());
538
539 KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(_keyManagerAlgorithm);
540 keyManagerFactory.init(keyStore, _keyManagerPassword == null ? null : _keyManagerPassword.toString().toCharArray());
541 keyManagers = keyManagerFactory.getKeyManagers();
542
543 TrustManager[] trustManagers = null;
544 InputStream truststoreInputStream = null;
545
546 truststoreInputStream = Resource.newResource(_trustStoreLocation).getInputStream();
547 KeyStore trustStore = KeyStore.getInstance(_trustStoreType);
548 trustStore.load(truststoreInputStream, _trustStorePassword == null ? null : _trustStorePassword.toString().toCharArray());
549
550 TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(_trustManagerAlgorithm);
551 trustManagerFactory.init(trustStore);
552 trustManagers = trustManagerFactory.getTrustManagers();
553
554 SecureRandom secureRandom = _secureRandomAlgorithm == null ? null : SecureRandom.getInstance(_secureRandomAlgorithm);
555 SSLContext context = _provider == null ? SSLContext.getInstance(_protocol) : SSLContext.getInstance(_protocol, _provider);
556 context.init(keyManagers, trustManagers, secureRandom);
557 return context;
558 }
559 catch (Exception e)
560 {
561 e.printStackTrace();
562 throw new IOException("error generating ssl context for " + _keyStoreLocation + " " + e.getMessage());
563 }
564 }
565
566 protected SSLContext getLooseSSLContext() throws IOException
567 {
568
569
570
571 TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager()
572 {
573 public java.security.cert.X509Certificate[] getAcceptedIssuers()
574 {
575 return null;
576 }
577
578 public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
579 {
580 }
581
582 public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
583 {
584 }
585 }};
586
587 HostnameVerifier hostnameVerifier = new HostnameVerifier()
588 {
589 public boolean verify(String urlHostName, SSLSession session)
590 {
591 Log.warn("Warning: URL Host: " + urlHostName + " vs." + session.getPeerHost());
592 return true;
593 }
594 };
595
596
597 try
598 {
599
600 SSLContext sslContext = SSLContext.getInstance("SSL");
601 sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
602 return sslContext;
603 }
604 catch (Exception e)
605 {
606 throw new IOException("issue ignoring certs");
607 }
608 }
609
610
611
612
613
614 public long getIdleTimeout()
615 {
616 return _idleTimeout;
617 }
618
619
620
621
622
623 public void setIdleTimeout(long ms)
624 {
625 _idleTimeout = ms;
626 }
627
628
629 public int getSoTimeout()
630 {
631 return _soTimeout;
632 }
633
634
635 public void setSoTimeout(int so)
636 {
637 _soTimeout = so;
638 }
639
640
641
642
643
644 public long getTimeout()
645 {
646 return _timeout;
647 }
648
649
650
651
652
653 public void setTimeout(long ms)
654 {
655 _timeout = ms;
656 }
657
658
659 public Address getProxy()
660 {
661 return _proxy;
662 }
663
664
665 public void setProxy(Address proxy)
666 {
667 this._proxy = proxy;
668 }
669
670
671 public Authorization getProxyAuthentication()
672 {
673 return _proxyAuthentication;
674 }
675
676
677 public void setProxyAuthentication(Authorization authentication)
678 {
679 _proxyAuthentication = authentication;
680 }
681
682
683 public boolean isProxied()
684 {
685 return this._proxy != null;
686 }
687
688
689 public Set<String> getNoProxy()
690 {
691 return _noProxy;
692 }
693
694
695 public void setNoProxy(Set<String> noProxyAddresses)
696 {
697 _noProxy = noProxyAddresses;
698 }
699
700
701 public int maxRetries()
702 {
703 return _maxRetries;
704 }
705
706
707 public void setMaxRetries(int retries)
708 {
709 _maxRetries = retries;
710 }
711
712 public String getTrustStoreLocation()
713 {
714 return _trustStoreLocation;
715 }
716
717 public void setTrustStoreLocation(String trustStoreLocation)
718 {
719 this._trustStoreLocation = trustStoreLocation;
720 }
721
722 public String getKeyStoreLocation()
723 {
724 return _keyStoreLocation;
725 }
726
727 public void setKeyStoreLocation(String keyStoreLocation)
728 {
729 this._keyStoreLocation = keyStoreLocation;
730 }
731
732 public void setKeyStorePassword(String _keyStorePassword)
733 {
734 this._keyStorePassword = _keyStorePassword;
735 }
736
737 public void setKeyManagerPassword(String _keyManagerPassword)
738 {
739 this._keyManagerPassword = _keyManagerPassword;
740 }
741
742 public void setTrustStorePassword(String _trustStorePassword)
743 {
744 this._trustStorePassword = _trustStorePassword;
745 }
746 }