View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2008 eviware.com 
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of version 2.1 of the GNU Lesser General Public License as published by 
6    *  the Free Software Foundation.
7    *
8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
10   *  See the GNU Lesser General Public License for more details at gnu.org.
11   */
12  
13  package com.eviware.soapui.impl.wsdl.support.http;
14  
15  import java.io.File;
16  import java.io.IOException;
17  import java.security.GeneralSecurityException;
18  import java.security.KeyManagementException;
19  import java.security.KeyStoreException;
20  import java.security.NoSuchAlgorithmException;
21  import java.security.cert.CertificateException;
22  
23  import org.apache.commons.httpclient.Header;
24  import org.apache.commons.httpclient.HttpClient;
25  import org.apache.commons.httpclient.HttpMethod;
26  import org.apache.commons.httpclient.contrib.ssl.EasySSLProtocolSocketFactory;
27  import org.apache.commons.httpclient.protocol.Protocol;
28  import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
29  import org.apache.commons.ssl.KeyMaterial;
30  import org.apache.log4j.Logger;
31  
32  import com.eviware.soapui.SoapUI;
33  import com.eviware.soapui.impl.wsdl.support.CompressionSupport;
34  import com.eviware.soapui.model.settings.Settings;
35  import com.eviware.soapui.model.settings.SettingsListener;
36  import com.eviware.soapui.settings.HttpSettings;
37  import com.eviware.soapui.settings.SSLSettings;
38  
39  /***
40   * HttpClient related tools
41   * 
42   * @author Ole.Matzura
43   */
44  
45  public class HttpClientSupport
46  {
47  	private final static Helper helper = new Helper();
48  
49  	/***
50  	 * Internal helper to ensure synchronized access..
51  	 */
52  
53  	private static class Helper
54  	{
55  		private HttpClient httpClient;
56  		private final static Logger log = Logger.getLogger( HttpClientSupport.Helper.class );
57  		private SoapUIEasySSLProtocolSocketFactory easySSL;
58  		private SoapUIMultiThreadedHttpConnectionManager connectionManager;
59  
60  		public Helper()
61  		{
62  			try
63  			{
64  				easySSL = new SoapUIEasySSLProtocolSocketFactory();
65  				initSSL( easySSL );
66  
67  				Protocol easyhttps = new Protocol( "https", ( ProtocolSocketFactory ) easySSL, 443 );
68  				Protocol.registerProtocol( "https", easyhttps );
69  			}
70  			catch( Throwable e )
71  			{
72  				SoapUI.logError( e );
73  			}
74  			
75  			Settings settings = SoapUI.getSettings();
76  
77  			connectionManager = new SoapUIMultiThreadedHttpConnectionManager();
78  			connectionManager.getParams().setDefaultMaxConnectionsPerHost( 
79  						( int ) settings.getLong( HttpSettings.MAX_CONNECTIONS_PER_HOST, 500 ) );
80  			connectionManager.getParams().setMaxTotalConnections( 
81  						( int ) settings.getLong( HttpSettings.MAX_TOTAL_CONNECTIONS, 2000 ) );
82  			httpClient = new HttpClient( connectionManager );
83  			
84  			settings.addSettingsListener( new SettingsListener() {
85  
86  				public void settingChanged( String name, String newValue, String oldValue )
87  				{
88  					if( newValue == null )
89  						return;
90  					
91  					if( name.equals( SSLSettings.KEYSTORE ) || name.equals( SSLSettings.KEYSTORE_PASSWORD ))
92  					{
93  						try
94  						{
95  							log.info( "Updating keyStore.." );
96  							initKeyMaterial( easySSL );
97  						}
98  						catch( Throwable e )
99  						{
100 							SoapUI.logError( e );
101 						}
102 					}
103 					else if( name.equals( HttpSettings.MAX_CONNECTIONS_PER_HOST ))
104 					{
105 						log.info( "Updating max connections per host to " + newValue );
106 						connectionManager.getParams().setDefaultMaxConnectionsPerHost( Integer.parseInt( newValue ) );
107 					}
108 					else if( name.equals( HttpSettings.MAX_TOTAL_CONNECTIONS ))
109 					{
110 						log.info( "Updating max total connections host to " + newValue );
111 						connectionManager.getParams().setMaxTotalConnections( Integer.parseInt( newValue ) );
112 					}
113 				}} );
114 		}
115 
116 		private void initSSL( EasySSLProtocolSocketFactory easySSL ) throws IOException,
117 		GeneralSecurityException
118 		{
119 			initKeyMaterial( easySSL );
120 
121 			 /*
122 	       Commented out for now - EasySSLProtocolSocketFactory already
123 	       trusts everything!  Below is some code that might work for when
124 	       SoapUI moves away from "EasySSLProtocolSocketFactory".                     
125 
126 	    String trustStore = settings.getString( SSLSettings.TRUSTSTORE, null );
127 	    trustStore = trustStore != null ? trustStore.trim() : "";
128 	    pass = settings.getString( SSLSettings.TRUSTSTORE_PASSWORD, "" );
129 	    pwd = pass.toCharArray();
130 	    if ( !"".equals( trustStore ) ) {
131 	        File f = new File( trustStore );
132 	        if ( f.exists() ) {
133 	            TrustMaterial tm = null;
134 	            try
135 	            {
136 	                tm = new TrustMaterial( trustStore, pwd );
137 	            }
138 	            catch ( GeneralSecurityException gse )
139 	            {
140 	                String trimmedPass = pass.trim();
141 	                if ( "".equals( trimmedPass ) )
142 	                {
143 	                    // If the password is all spaces, then we'll allow
144 	                    // loading of the TrustMaterial without a password.
145 	                    tm = new TrustMaterial( trustStore );
146 	                }
147 	                else
148 	                {
149 	                    log.error( "Failed to load TrustMaterial: " + gse );
150 	                }
151 	            }
152 	            if ( tm != null )
153 	            {
154 	                easySSL.setTrustMaterial( tm );
155 	                log.info( "Added TrustStore from file [" + trustStore + "]" );
156 	            }
157 	        } else {
158 	            log.error( "Missing trustStore [" + trustStore + "]" );
159 	        }
160 	    }
161 */
162 		}
163 
164 		private void initKeyMaterial( EasySSLProtocolSocketFactory easySSL ) throws IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException, CertificateException
165 		{
166 			Settings settings = SoapUI.getSettings();
167 			
168 			String keyStore = settings.getString( SSLSettings.KEYSTORE, null );
169 			keyStore = keyStore != null ? keyStore.trim() : "";
170 			String pass = settings.getString( SSLSettings.KEYSTORE_PASSWORD, "" );
171 			char[] pwd = pass.toCharArray();
172 			if( !"".equals( keyStore ) )
173 			{
174 				log.info( "Initializing KeyStore" );
175 
176 				File f = new File( keyStore );
177 				if( f.exists() )
178 				{
179 					KeyMaterial km = null;
180 					try
181 					{
182 						km = new KeyMaterial( keyStore, pwd );
183 						log.info( "Set KeyMaterial from file [" + keyStore + "]" );
184 					}
185 					catch( GeneralSecurityException gse )
186 					{
187 						SoapUI.logError( gse );
188 					}
189 					if( km != null )
190 					{
191 						easySSL.setKeyMaterial( km );
192 					}
193 				}
194 			}
195 			else
196 			{
197 				easySSL.setKeyMaterial( null );
198 			}
199 		}
200 
201 		public HttpClient getHttpClient()
202 		{
203 			return httpClient;
204 		}
205 	}
206 
207 	public static HttpClient getHttpClient()
208 	{
209 		return helper.getHttpClient();
210 	}
211 
212 	public static void applyHttpSettings( HttpMethod httpMethod, Settings settings )
213 	{
214 		// user agent?
215 		String userAgent = settings.getString( HttpSettings.USER_AGENT, null );
216 		if( userAgent != null && userAgent.length() > 0 )
217 			httpMethod.setRequestHeader( "User-Agent", userAgent );
218 
219 		// timeout?
220 		long timeout = settings.getLong( HttpSettings.SOCKET_TIMEOUT,
221 					HttpSettings.DEFAULT_SOCKET_TIMEOUT );
222 		httpMethod.getParams().setSoTimeout( ( int ) timeout );
223 	}
224 
225 	public static String getResponseCompressionType( HttpMethod method )
226  	{
227  		Header contentType = method.getResponseHeader( "Content-Type" );
228  		Header contentEncoding = method.getResponseHeader( "Content-Encoding" );
229 
230  		if( contentType == null )
231  			return null;
232  		
233  		String compressionAlg = CompressionSupport.getAvailableAlgorithm(contentType.getValue());
234  		if ( compressionAlg != null )
235  			return compressionAlg;
236  		
237  		if ( contentEncoding == null )
238  			return null;
239  		else
240  			return CompressionSupport.getAvailableAlgorithm(contentEncoding.getValue());
241 	}
242 }