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