View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2010 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.submit.transports.http;
14  
15  import java.net.InetAddress;
16  import java.util.ArrayList;
17  import java.util.List;
18  
19  import org.apache.commons.httpclient.Header;
20  import org.apache.commons.httpclient.HostConfiguration;
21  import org.apache.commons.httpclient.HttpClient;
22  import org.apache.commons.httpclient.HttpMethodBase;
23  import org.apache.commons.httpclient.HttpState;
24  import org.apache.commons.httpclient.URI;
25  import org.apache.log4j.Logger;
26  
27  import com.eviware.soapui.SoapUI;
28  import com.eviware.soapui.impl.support.AbstractHttpRequestInterface;
29  import com.eviware.soapui.impl.support.http.HttpRequestInterface;
30  import com.eviware.soapui.impl.wsdl.AbstractWsdlModelItem;
31  import com.eviware.soapui.impl.wsdl.WsdlProject;
32  import com.eviware.soapui.impl.wsdl.submit.RequestFilter;
33  import com.eviware.soapui.impl.wsdl.submit.transports.http.support.attachments.MimeMessageResponse;
34  import com.eviware.soapui.impl.wsdl.submit.transports.http.support.methods.ExtendedDeleteMethod;
35  import com.eviware.soapui.impl.wsdl.submit.transports.http.support.methods.ExtendedGetMethod;
36  import com.eviware.soapui.impl.wsdl.submit.transports.http.support.methods.ExtendedHeadMethod;
37  import com.eviware.soapui.impl.wsdl.submit.transports.http.support.methods.ExtendedOptionsMethod;
38  import com.eviware.soapui.impl.wsdl.submit.transports.http.support.methods.ExtendedPostMethod;
39  import com.eviware.soapui.impl.wsdl.submit.transports.http.support.methods.ExtendedPutMethod;
40  import com.eviware.soapui.impl.wsdl.submit.transports.http.support.methods.ExtendedTraceMethod;
41  import com.eviware.soapui.impl.wsdl.support.PathUtils;
42  import com.eviware.soapui.impl.wsdl.support.http.HttpClientSupport;
43  import com.eviware.soapui.impl.wsdl.support.http.SoapUIHostConfiguration;
44  import com.eviware.soapui.impl.wsdl.support.wss.WssCrypto;
45  import com.eviware.soapui.model.iface.Request;
46  import com.eviware.soapui.model.iface.Response;
47  import com.eviware.soapui.model.iface.SubmitContext;
48  import com.eviware.soapui.model.propertyexpansion.PropertyExpander;
49  import com.eviware.soapui.model.settings.Settings;
50  import com.eviware.soapui.model.support.ModelSupport;
51  import com.eviware.soapui.settings.HttpSettings;
52  import com.eviware.soapui.support.StringUtils;
53  import com.eviware.soapui.support.types.StringToStringMap;
54  import com.eviware.soapui.support.types.StringToStringsMap;
55  
56  /***
57   * HTTP transport that uses HttpClient to send/receive SOAP messages
58   * 
59   * @author Ole.Matzura
60   */
61  
62  public class HttpClientRequestTransport implements BaseHttpRequestTransport
63  {
64  	private List<RequestFilter> filters = new ArrayList<RequestFilter>();
65  	private final static Logger log = Logger.getLogger( HttpClientRequestTransport.class );
66  
67  	public HttpClientRequestTransport()
68  	{
69  	}
70  
71  	public void addRequestFilter( RequestFilter filter )
72  	{
73  		filters.add( filter );
74  	}
75  
76  	public void removeRequestFilter( RequestFilter filter )
77  	{
78  		filters.remove( filter );
79  	}
80  
81  	public void abortRequest( SubmitContext submitContext )
82  	{
83  		HttpMethodBase postMethod = ( HttpMethodBase )submitContext.getProperty( HTTP_METHOD );
84  		if( postMethod != null )
85  			postMethod.abort();
86  	}
87  
88  	public Response sendRequest( SubmitContext submitContext, Request request ) throws Exception
89  	{
90  		AbstractHttpRequestInterface<?> httpRequest = ( AbstractHttpRequestInterface<?> )request;
91  
92  		HttpClient httpClient = HttpClientSupport.getHttpClient();
93  		ExtendedHttpMethod httpMethod = createHttpMethod( httpRequest );
94  		boolean createdState = false;
95  
96  		HttpState httpState = ( HttpState )submitContext.getProperty( SubmitContext.HTTP_STATE_PROPERTY );
97  		if( httpState == null )
98  		{
99  			httpState = new HttpState();
100 			submitContext.setProperty( SubmitContext.HTTP_STATE_PROPERTY, httpState );
101 			createdState = true;
102 		}
103 
104 		HostConfiguration hostConfiguration = new HostConfiguration();
105 
106 		String localAddress = System.getProperty( "soapui.bind.address", httpRequest.getBindAddress() );
107 		if( localAddress == null || localAddress.trim().length() == 0 )
108 			localAddress = SoapUI.getSettings().getString( HttpSettings.BIND_ADDRESS, null );
109 
110 		if( localAddress != null && localAddress.trim().length() > 0 )
111 		{
112 			try
113 			{
114 				hostConfiguration.setLocalAddress( InetAddress.getByName( localAddress ) );
115 			}
116 			catch( Exception e )
117 			{
118 				SoapUI.logError( e );
119 			}
120 		}
121 
122 		submitContext.removeProperty( RESPONSE );
123 		submitContext.setProperty( HTTP_METHOD, httpMethod );
124 		submitContext.setProperty( POST_METHOD, httpMethod );
125 		submitContext.setProperty( HTTP_CLIENT, httpClient );
126 		submitContext.setProperty( REQUEST_CONTENT, httpRequest.getRequestContent() );
127 		submitContext.setProperty( HOST_CONFIGURATION, hostConfiguration );
128 		submitContext.setProperty( WSDL_REQUEST, httpRequest );
129 		submitContext.setProperty( RESPONSE_PROPERTIES, new StringToStringMap() );
130 
131 		for( RequestFilter filter : filters )
132 		{
133 			filter.filterRequest( submitContext, httpRequest );
134 		}
135 
136 		try
137 		{
138 			Settings settings = httpRequest.getSettings();
139 
140 			// custom http headers last so they can be overridden
141 			StringToStringsMap headers = httpRequest.getRequestHeaders();
142 
143 			// first remove so we don't get any unwanted duplicates
144 			for( String header : headers.keySet() )
145 			{
146 				httpMethod.removeRequestHeader( header );
147 			}
148 
149 			// now add
150 			for( String header : headers.keySet() )
151 			{
152 				for( String headerValue : headers.get( header ) )
153 				{
154 					headerValue = PropertyExpander.expandProperties( submitContext, headerValue );
155 					httpMethod.addRequestHeader( header, headerValue );
156 				}
157 			}
158 
159 			// do request
160 			WsdlProject project = ( WsdlProject )ModelSupport.getModelItemProject( httpRequest );
161 			WssCrypto crypto = null;
162 			if( project != null && project.getWssContainer() != null )
163 			{
164 				crypto = project.getWssContainer().getCryptoByName(
165 						PropertyExpander.expandProperties( submitContext, httpRequest.getSslKeystore() ) );
166 			}
167 
168 			if( crypto != null && WssCrypto.STATUS_OK.equals( crypto.getStatus() ) )
169 			{
170 				hostConfiguration.getParams().setParameter( SoapUIHostConfiguration.SOAPUI_SSL_CONFIG,
171 						crypto.getSource() + " " + crypto.getPassword() );
172 			}
173 
174 			// dump file?
175 			httpMethod.setDumpFile( PathUtils.expandPath( httpRequest.getDumpFile(),
176 					( AbstractWsdlModelItem<?> )httpRequest, submitContext ) );
177 
178 			// fix absolute URIs due to peculiarity in httpclient
179 			URI uri = ( URI )submitContext.getProperty( BaseHttpRequestTransport.REQUEST_URI );
180 			if( uri != null && uri.isAbsoluteURI() )
181 			{
182 				hostConfiguration.setHost( uri.getHost(), uri.getPort() );
183 				String str = uri.toString();
184 				int ix = str.indexOf( '/', str.indexOf( "//" ) + 2 );
185 				if( ix != -1 )
186 				{
187 					uri = new URI( str.substring( ix ), true );
188 					String qs = httpMethod.getQueryString();
189 					httpMethod.setURI( uri );
190 					if( StringUtils.hasContent( qs ) )
191 						httpMethod.setQueryString( qs );
192 
193 					submitContext.setProperty( BaseHttpRequestTransport.REQUEST_URI, uri );
194 				}
195 			}
196 
197 			// include request time?
198 			if( settings.getBoolean( HttpSettings.INCLUDE_REQUEST_IN_TIME_TAKEN ) )
199 				httpMethod.initStartTime();
200 
201 			// submit!
202 			httpClient.executeMethod( hostConfiguration, httpMethod, httpState );
203 			httpMethod.getTimeTaken();
204 		}
205 		catch( Throwable t )
206 		{
207 			httpMethod.setFailed( t );
208 
209 			if( t instanceof Exception )
210 				throw ( Exception )t;
211 
212 			SoapUI.logError( t );
213 			throw new Exception( t );
214 		}
215 		finally
216 		{
217 			for( int c = filters.size() - 1; c >= 0; c-- )
218 			{
219 				filters.get( c ).afterRequest( submitContext, httpRequest );
220 			}
221 
222 			if( !submitContext.hasProperty( RESPONSE ) )
223 			{
224 				createDefaultResponse( submitContext, httpRequest, httpMethod );
225 			}
226 
227 			Response response = ( Response )submitContext.getProperty( BaseHttpRequestTransport.RESPONSE );
228 			StringToStringMap responseProperties = ( StringToStringMap )submitContext
229 					.getProperty( BaseHttpRequestTransport.RESPONSE_PROPERTIES );
230 
231 			for( String key : responseProperties.keySet() )
232 			{
233 				response.setProperty( key, responseProperties.get( key ) );
234 			}
235 
236 			if( httpMethod != null )
237 			{
238 				httpMethod.releaseConnection();
239 			}
240 			else
241 				log.error( "PostMethod is null" );
242 
243 			if( createdState )
244 			{
245 				submitContext.setProperty( SubmitContext.HTTP_STATE_PROPERTY, null );
246 			}
247 		}
248 
249 		return ( Response )submitContext.getProperty( BaseHttpRequestTransport.RESPONSE );
250 	}
251 
252 	private void createDefaultResponse( SubmitContext submitContext, AbstractHttpRequestInterface<?> httpRequest,
253 			ExtendedHttpMethod httpMethod )
254 	{
255 		String requestContent = ( String )submitContext.getProperty( BaseHttpRequestTransport.REQUEST_CONTENT );
256 
257 		// check content-type for multiplart
258 		Header responseContentTypeHeader = httpMethod.getResponseHeader( "Content-Type" );
259 		Response response = null;
260 
261 		if( responseContentTypeHeader != null
262 				&& responseContentTypeHeader.getValue().toUpperCase().startsWith( "MULTIPART" ) )
263 		{
264 			response = new MimeMessageResponse( httpRequest, httpMethod, requestContent, submitContext );
265 		}
266 		else
267 		{
268 			response = new SinglePartHttpResponse( httpRequest, httpMethod, requestContent, submitContext );
269 		}
270 
271 		submitContext.setProperty( BaseHttpRequestTransport.RESPONSE, response );
272 	}
273 
274 	private ExtendedHttpMethod createHttpMethod( AbstractHttpRequestInterface<?> httpRequest )
275 	{
276 		if( httpRequest instanceof HttpRequestInterface<?> )
277 		{
278 			HttpRequestInterface<?> restRequest = ( HttpRequestInterface<?> )httpRequest;
279 			switch( restRequest.getMethod() )
280 			{
281 			case GET :
282 				return new ExtendedGetMethod();
283 			case HEAD :
284 				return new ExtendedHeadMethod();
285 			case DELETE :
286 				return new ExtendedDeleteMethod();
287 			case PUT :
288 				return new ExtendedPutMethod();
289 			case OPTIONS :
290 				return new ExtendedOptionsMethod();
291 			case TRACE :
292 				return new ExtendedTraceMethod();
293 			}
294 		}
295 
296 		ExtendedPostMethod extendedPostMethod = new ExtendedPostMethod();
297 
298 		extendedPostMethod.setAfterRequestInjection( httpRequest.getAfterRequestInjection() );
299 		return extendedPostMethod;
300 	}
301 
302 }