View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2007 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.ByteArrayInputStream;
16  import java.io.ByteArrayOutputStream;
17  import java.io.File;
18  import java.io.IOException;
19  import java.io.InputStream;
20  import java.security.GeneralSecurityException;
21  import java.security.KeyManagementException;
22  import java.security.KeyStoreException;
23  import java.security.NoSuchAlgorithmException;
24  import java.security.cert.CertificateException;
25  import java.util.zip.GZIPInputStream;
26  
27  import org.apache.commons.httpclient.Header;
28  import org.apache.commons.httpclient.HttpClient;
29  import org.apache.commons.httpclient.HttpMethodBase;
30  import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
31  import org.apache.commons.httpclient.contrib.ssl.EasySSLProtocolSocketFactory;
32  import org.apache.commons.httpclient.protocol.Protocol;
33  import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
34  import org.apache.commons.ssl.KeyMaterial;
35  import org.apache.log4j.Logger;
36  
37  import com.eviware.soapui.SoapUI;
38  import com.eviware.soapui.model.settings.Settings;
39  import com.eviware.soapui.model.settings.SettingsListener;
40  import com.eviware.soapui.settings.HttpSettings;
41  import com.eviware.soapui.settings.SSLSettings;
42  import com.eviware.soapui.support.Tools;
43  
44  /***
45   * HttpClient related tools
46   * 
47   * @author Ole.Matzura
48   */
49  
50  public class HttpClientSupport
51  {
52  	private final static Helper helper = new Helper();
53  
54  	/***
55  	 * Internal helper to ensure synchronized access..
56  	 */
57  
58  	private static class Helper
59  	{
60  		private HttpClient httpClient;
61  		private final static Logger log = Logger.getLogger( HttpClientSupport.Helper.class );
62  		private EasySSLProtocolSocketFactory easySSL;
63  		private MultiThreadedHttpConnectionManager connectionManager;
64  
65  		public Helper()
66  		{
67  			try
68  			{
69  				easySSL = new EasySSLProtocolSocketFactory();
70  				initSSL( easySSL );
71  
72  				Protocol easyhttps = new Protocol( "https", ( ProtocolSocketFactory ) easySSL, 443 );
73  				Protocol.registerProtocol( "https", easyhttps );
74  			}
75  			catch( Throwable e )
76  			{
77  				SoapUI.logError( e );
78  			}
79  			
80  			Settings settings = SoapUI.getSettings();
81  
82  			connectionManager = new MultiThreadedHttpConnectionManager();
83  			connectionManager.getParams().setDefaultMaxConnectionsPerHost( 
84  						( int ) settings.getLong( HttpSettings.MAX_CONNECTIONS_PER_HOST, 500 ) );
85  			connectionManager.getParams().setMaxTotalConnections( 
86  						( int ) settings.getLong( HttpSettings.MAX_TOTAL_CONNECTIONS, 2000 ) );
87  			httpClient = new HttpClient( connectionManager );
88  			
89  			settings.addSettingsListener( new SettingsListener() {
90  
91  				public void settingChanged( String name, String newValue, String oldValue )
92  				{
93  					if( name.equals( SSLSettings.KEYSTORE ) || name.equals( SSLSettings.KEYSTORE_PASSWORD ))
94  					{
95  						try
96  						{
97  							log.info( "Updating keyStore.." );
98  							initKeyMaterial( easySSL );
99  						}
100 						catch( Throwable e )
101 						{
102 							SoapUI.logError( e );
103 						}
104 					}
105 					else if( name.equals( HttpSettings.MAX_CONNECTIONS_PER_HOST ))
106 					{
107 						log.info( "Updating max connections per host to " + newValue );
108 						connectionManager.getParams().setDefaultMaxConnectionsPerHost( Integer.parseInt( newValue ) );
109 					}
110 					else if( name.equals( HttpSettings.MAX_TOTAL_CONNECTIONS ))
111 					{
112 						log.info( "Updating max total connections host to " + newValue );
113 						connectionManager.getParams().setMaxTotalConnections( Integer.parseInt( newValue ) );
114 					}
115 				}} );
116 		}
117 
118 		private void initSSL( EasySSLProtocolSocketFactory easySSL ) throws IOException,
119 		GeneralSecurityException
120 		{
121 			log.info( "Initializing SSL" );
122 			initKeyMaterial( easySSL );
123 
124 			 /*
125 	       Commented out for now - EasySSLProtocolSocketFactory already
126 	       trusts everything!  Below is some code that might work for when
127 	       SoapUI moves away from "EasySSLProtocolSocketFactory".                     
128 
129 	    String trustStore = settings.getString( SSLSettings.TRUSTSTORE, null );
130 	    trustStore = trustStore != null ? trustStore.trim() : "";
131 	    pass = settings.getString( SSLSettings.TRUSTSTORE_PASSWORD, "" );
132 	    pwd = pass.toCharArray();
133 	    if ( !"".equals( trustStore ) ) {
134 	        File f = new File( trustStore );
135 	        if ( f.exists() ) {
136 	            TrustMaterial tm = null;
137 	            try
138 	            {
139 	                tm = new TrustMaterial( trustStore, pwd );
140 	            }
141 	            catch ( GeneralSecurityException gse )
142 	            {
143 	                String trimmedPass = pass.trim();
144 	                if ( "".equals( trimmedPass ) )
145 	                {
146 	                    // If the password is all spaces, then we'll allow
147 	                    // loading of the TrustMaterial without a password.
148 	                    tm = new TrustMaterial( trustStore );
149 	                }
150 	                else
151 	                {
152 	                    log.error( "Failed to load TrustMaterial: " + gse );
153 	                }
154 	            }
155 	            if ( tm != null )
156 	            {
157 	                easySSL.setTrustMaterial( tm );
158 	                log.info( "Added TrustStore from file [" + trustStore + "]" );
159 	            }
160 	        } else {
161 	            log.error( "Missing trustStore [" + trustStore + "]" );
162 	        }
163 	    }
164 */
165 		}
166 
167 		private void initKeyMaterial( EasySSLProtocolSocketFactory easySSL ) throws IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException, CertificateException
168 		{
169 			Settings settings = SoapUI.getSettings();
170 			
171 			String keyStore = settings.getString( SSLSettings.KEYSTORE, null );
172 			keyStore = keyStore != null ? keyStore.trim() : "";
173 			String pass = settings.getString( SSLSettings.KEYSTORE_PASSWORD, "" );
174 			char[] pwd = pass.toCharArray();
175 			if( !"".equals( keyStore ) )
176 			{
177 				File f = new File( keyStore );
178 				if( f.exists() )
179 				{
180 					KeyMaterial km = null;
181 					try
182 					{
183 						km = new KeyMaterial( keyStore, pwd );
184 						log.info( "Set KeyMaterial from file [" + keyStore + "]" );
185 					}
186 					catch( GeneralSecurityException gse )
187 					{
188 						SoapUI.logError( gse );
189 					}
190 					if( km != null )
191 					{
192 						easySSL.setKeyMaterial( km );
193 					}
194 				}
195 			}
196 			else
197 			{
198 				easySSL.setKeyMaterial( null );
199 			}
200 		}
201 
202 		public HttpClient getHttpClient()
203 		{
204 			return httpClient;
205 		}
206 	}
207 
208 	public static HttpClient getHttpClient()
209 	{
210 		return helper.getHttpClient();
211 	}
212 
213 	public static void applyHttpSettings( HttpMethodBase postMethod, Settings settings )
214 	{
215 		// user agent?
216 		String userAgent = settings.getString( HttpSettings.USER_AGENT, null );
217 		if( userAgent != null && userAgent.length() > 0 )
218 			postMethod.setRequestHeader( "User-Agent", userAgent );
219 
220 		// timeout?
221 		long timeout = settings.getLong( HttpSettings.SOCKET_TIMEOUT,
222 					HttpSettings.DEFAULT_SOCKET_TIMEOUT );
223 		postMethod.getParams().setSoTimeout( ( int ) timeout );
224 	}
225 
226 	public static boolean isZippedResponse( HttpMethodBase method )
227 	{
228 		Header contentType = method.getResponseHeader( "Content-Type" );
229 		Header contentEncoding = method.getResponseHeader( "Content-Encoding" );
230 
231 		if( contentType != null && contentType.getValue().toUpperCase().endsWith( "GZIP" ) )
232 			return true;
233 
234 		if( contentEncoding != null && contentEncoding.getValue().toUpperCase().endsWith( "GZIP" ) )
235 			return true;
236 
237 		return false;
238 	}
239 
240 	public static byte[] decompress( byte[] s )
241 	{
242 		GZIPInputStream zipin;
243 		try
244 		{
245 			InputStream in = new ByteArrayInputStream( s );
246 			zipin = new GZIPInputStream( in );
247 		}
248 		catch( IOException e )
249 		{
250 			SoapUI.logError( e );
251 			return s;
252 		}
253 
254 		try
255 		{
256 			ByteArrayOutputStream out = Tools.readAll( zipin, -1 );
257 			s = out.toByteArray();
258 			out.close();
259 		}
260 		catch( IOException e )
261 		{
262 			SoapUI.logError( e );
263 			return s;
264 		}
265 		try
266 		{
267 			zipin.close();
268 		}
269 		catch( IOException e )
270 		{
271 		}
272 
273 		return s;
274 	}
275 }