View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2009 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  
87  				public void settingChanged( String name, String newValue, String oldValue )
88  				{
89  					if( newValue == null )
90  						return;
91  
92  					if( name.equals( SSLSettings.KEYSTORE ) || name.equals( SSLSettings.KEYSTORE_PASSWORD ) )
93  					{
94  						try
95  						{
96  							log.info( "Updating keyStore.." );
97  							initKeyMaterial( easySSL );
98  						}
99  						catch( Throwable e )
100 						{
101 							SoapUI.logError( e );
102 						}
103 					}
104 					else if( name.equals( HttpSettings.MAX_CONNECTIONS_PER_HOST ) )
105 					{
106 						log.info( "Updating max connections per host to " + newValue );
107 						connectionManager.getParams().setDefaultMaxConnectionsPerHost( Integer.parseInt( newValue ) );
108 					}
109 					else if( name.equals( HttpSettings.MAX_TOTAL_CONNECTIONS ) )
110 					{
111 						log.info( "Updating max total connections host to " + newValue );
112 						connectionManager.getParams().setMaxTotalConnections( Integer.parseInt( newValue ) );
113 					}
114 				}
115 			} );
116 		}
117 
118 		private void initSSL( EasySSLProtocolSocketFactory easySSL ) throws IOException, GeneralSecurityException
119 		{
120 			initKeyMaterial( easySSL );
121 
122 			/*
123 			 * Commented out for now - EasySSLProtocolSocketFactory already trusts
124 			 * everything! Below is some code that might work for when SoapUI moves
125 			 * away from "EasySSLProtocolSocketFactory".
126 			 * 
127 			 * String trustStore = settings.getString( SSLSettings.TRUSTSTORE, null
128 			 * ); trustStore = trustStore != null ? trustStore.trim() : ""; pass =
129 			 * settings.getString( SSLSettings.TRUSTSTORE_PASSWORD, "" ); pwd =
130 			 * pass.toCharArray(); if ( !"".equals( trustStore ) ) { File f = new
131 			 * File( trustStore ); if ( f.exists() ) { TrustMaterial tm = null; try
132 			 * { tm = new TrustMaterial( trustStore, pwd ); } catch (
133 			 * GeneralSecurityException gse ) { String trimmedPass = pass.trim();
134 			 * if ( "".equals( trimmedPass ) ) { // If the password is all spaces,
135 			 * then we'll allow // loading of the TrustMaterial without a password.
136 			 * tm = new TrustMaterial( trustStore ); } else { log.error(
137 			 * "Failed to load TrustMaterial: " + gse ); } } if ( tm != null ) {
138 			 * easySSL.setTrustMaterial( tm ); log.info(
139 			 * "Added TrustStore from file [" + trustStore + "]" ); } } else {
140 			 * log.error( "Missing trustStore [" + trustStore + "]" ); } }
141 			 */
142 		}
143 
144 		private void initKeyMaterial( EasySSLProtocolSocketFactory easySSL ) throws IOException,
145 				NoSuchAlgorithmException, KeyStoreException, KeyManagementException, CertificateException
146 		{
147 			Settings settings = SoapUI.getSettings();
148 
149 			String keyStore = settings.getString( SSLSettings.KEYSTORE, null );
150 			keyStore = keyStore != null ? keyStore.trim() : "";
151 			String pass = settings.getString( SSLSettings.KEYSTORE_PASSWORD, "" );
152 			char[] pwd = pass.toCharArray();
153 			if( !"".equals( keyStore ) )
154 			{
155 				log.info( "Initializing KeyStore" );
156 
157 				File f = new File( keyStore );
158 				if( f.exists() )
159 				{
160 					KeyMaterial km = null;
161 					try
162 					{
163 						km = new KeyMaterial( keyStore, pwd );
164 						log.info( "Set KeyMaterial from file [" + keyStore + "]" );
165 					}
166 					catch( GeneralSecurityException gse )
167 					{
168 						SoapUI.logError( gse );
169 					}
170 					if( km != null )
171 					{
172 						easySSL.setKeyMaterial( km );
173 					}
174 				}
175 			}
176 			else
177 			{
178 				easySSL.setKeyMaterial( null );
179 			}
180 		}
181 
182 		public HttpClient getHttpClient()
183 		{
184 			return httpClient;
185 		}
186 	}
187 
188 	public static HttpClient getHttpClient()
189 	{
190 		return helper.getHttpClient();
191 	}
192 
193 	public static void applyHttpSettings( HttpMethod httpMethod, Settings settings )
194 	{
195 		// user agent?
196 		String userAgent = settings.getString( HttpSettings.USER_AGENT, null );
197 		if( userAgent != null && userAgent.length() > 0 )
198 			httpMethod.setRequestHeader( "User-Agent", userAgent );
199 
200 		// timeout?
201 		long timeout = settings.getLong( HttpSettings.SOCKET_TIMEOUT, HttpSettings.DEFAULT_SOCKET_TIMEOUT );
202 		httpMethod.getParams().setSoTimeout( ( int )timeout );
203 	}
204 
205 	public static String getResponseCompressionType( HttpMethod method )
206 	{
207 		Header contentType = method.getResponseHeader( "Content-Type" );
208 		Header contentEncoding = method.getResponseHeader( "Content-Encoding" );
209 
210 		String compressionAlg = contentType == null ? null : CompressionSupport.getAvailableAlgorithm( contentType.getValue() );
211 		if( compressionAlg != null )
212 			return compressionAlg;
213 
214 		if( contentEncoding == null )
215 			return null;
216 		else
217 			return CompressionSupport.getAvailableAlgorithm( contentEncoding.getValue() );
218 	}
219 }