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