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 }