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.filters;
14  
15  import java.io.File;
16  import java.io.UnsupportedEncodingException;
17  import java.net.URLDecoder;
18  import java.net.URLEncoder;
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  import javax.activation.DataHandler;
23  import javax.activation.FileDataSource;
24  import javax.mail.MessagingException;
25  import javax.mail.internet.MimeBodyPart;
26  import javax.mail.internet.MimeMessage;
27  import javax.mail.internet.MimeMultipart;
28  import javax.mail.internet.PreencodedMimeBodyPart;
29  
30  import org.apache.commons.httpclient.HttpMethod;
31  import org.apache.commons.httpclient.URI;
32  import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
33  import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
34  import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
35  import org.apache.commons.httpclient.methods.StringRequestEntity;
36  import org.apache.xmlbeans.XmlBoolean;
37  
38  import com.eviware.soapui.SoapUI;
39  import com.eviware.soapui.impl.rest.RestRequest;
40  import com.eviware.soapui.impl.rest.support.RestParamProperty;
41  import com.eviware.soapui.impl.rest.support.RestParamsPropertyHolder;
42  import com.eviware.soapui.impl.support.http.HttpRequestInterface;
43  import com.eviware.soapui.impl.wsdl.submit.transports.http.BaseHttpRequestTransport;
44  import com.eviware.soapui.impl.wsdl.submit.transports.http.support.attachments.AttachmentDataSource;
45  import com.eviware.soapui.impl.wsdl.submit.transports.http.support.attachments.AttachmentUtils;
46  import com.eviware.soapui.impl.wsdl.submit.transports.http.support.attachments.RestRequestDataSource;
47  import com.eviware.soapui.impl.wsdl.submit.transports.http.support.attachments.RestRequestMimeMessageRequestEntity;
48  import com.eviware.soapui.impl.wsdl.support.FileAttachment;
49  import com.eviware.soapui.impl.wsdl.support.PathUtils;
50  import com.eviware.soapui.model.iface.Attachment;
51  import com.eviware.soapui.model.iface.SubmitContext;
52  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionUtils;
53  import com.eviware.soapui.support.StringUtils;
54  import com.eviware.soapui.support.editor.inspectors.attachments.ContentTypeHandler;
55  import com.eviware.soapui.support.types.StringToStringMap;
56  
57  /***
58   * RequestFilter that adds SOAP specific headers
59   * 
60   * @author Ole.Matzura
61   */
62  
63  public class HttpRequestFilter extends AbstractRequestFilter
64  {
65  	@SuppressWarnings( "deprecation" )
66  	@Override
67  	public void filterHttpRequest( SubmitContext context, HttpRequestInterface<?> request )
68  	{
69  		HttpMethod httpMethod = ( HttpMethod )context.getProperty( BaseHttpRequestTransport.HTTP_METHOD );
70  
71  		String path = PropertyExpansionUtils.expandProperties( context, request.getPath() );
72  		StringBuffer query = new StringBuffer();
73  
74  		StringToStringMap responseProperties = ( StringToStringMap )context
75  				.getProperty( BaseHttpRequestTransport.RESPONSE_PROPERTIES );
76  
77  		MimeMultipart formMp = "multipart/form-data".equals( request.getMediaType() )
78  				&& httpMethod instanceof EntityEnclosingMethod ? new MimeMultipart() : null;
79  
80  		RestParamsPropertyHolder params = request.getParams();
81  		for( int c = 0; c < params.getPropertyCount(); c++ )
82  		{
83  			RestParamProperty param = params.getPropertyAt( c );
84  
85  			String value = PropertyExpansionUtils.expandProperties( context, param.getValue() );
86  			responseProperties.put( param.getName(), value );
87  
88  			if( value != null /* && formMp == null */&& !param.isDisableUrlEncoding() )
89  			{
90  				try
91  				{
92  					String encoding = System.getProperty( "soapui.request.encoding", request.getEncoding() );
93  
94  					if( StringUtils.hasContent( encoding ) )
95  						value = URLEncoder.encode( value, encoding );
96  					else
97  						value = URLEncoder.encode( value );
98  				}
99  				catch( UnsupportedEncodingException e1 )
100 				{
101 					SoapUI.logError( e1 );
102 					value = URLEncoder.encode( value );
103 				}
104 				// URLEncoder replaces space with "+", but we want "%20".
105 				value = value.replaceAll( "//+", "%20" );
106 			}
107 
108 			if( !StringUtils.hasContent( value ) && !param.getRequired() )
109 				continue;
110 
111 			switch( param.getStyle() )
112 			{
113 			case HEADER :
114 				httpMethod.setRequestHeader( param.getName(), value );
115 				break;
116 			case QUERY :
117 				if( formMp == null || !request.isPostQueryString() )
118 				{
119 					if( query.length() > 0 )
120 						query.append( '&' );
121 
122 					query.append( URLEncoder.encode( param.getName() ) );
123 					query.append( '=' );
124 					if( StringUtils.hasContent( value ) )
125 						query.append( value );
126 				}
127 				else
128 				{
129 					try
130 					{
131 						addFormMultipart( request, formMp, param.getName(), value );
132 					}
133 					catch( MessagingException e )
134 					{
135 						e.printStackTrace();
136 					}
137 				}
138 
139 				break;
140 			case TEMPLATE :
141 				path = path.replaceAll( "//{" + param.getName() + "//}", value );
142 				break;
143 			case MATRIX :
144 				if( param.getType().equals( XmlBoolean.type.getName() ) )
145 				{
146 					if( value.toUpperCase().equals( "TRUE" ) || value.equals( "1" ) )
147 					{
148 						path += ";" + param.getName();
149 					}
150 				}
151 				else
152 				{
153 					path += ";" + param.getName();
154 					if( StringUtils.hasContent( value ) )
155 					{
156 						path += "=" + value;
157 					}
158 				}
159 			case PLAIN :
160 				break;
161 			}
162 		}
163 		
164 		String prefix = null;
165 		if( path.contains("://") )
166 		{
167 			prefix = path.substring(0, path.indexOf("://") + 3);
168 			path = path.substring(prefix.length());
169 		}
170 		path = path.replaceAll("/{2,}", "/");
171 		if( prefix != null )
172 			path = prefix+path;
173 
174 		if( PathUtils.isHttpPath( path ) )
175 		{
176 			try
177 			{
178 				// URI(String) automatically URLencodes the input, so we need to
179 				// decode it first...
180 				httpMethod.setURI( new URI( URLDecoder.decode( path ) ) );
181 			}
182 			catch( Exception e )
183 			{
184 				e.printStackTrace();
185 			}
186 		}
187 		else if( StringUtils.hasContent( path ) )
188 		{
189 			httpMethod.setPath( path );
190 		}
191 
192 		if( query.length() > 0 && !request.isPostQueryString() )
193 		{
194 			httpMethod.setQueryString( query.toString() );
195 		}
196 
197 		if( request instanceof RestRequest )
198 		{
199 			String acceptEncoding = ( ( RestRequest )request ).getAccept();
200 			if( StringUtils.hasContent( acceptEncoding ) )
201 			{
202 				httpMethod.setRequestHeader( "Accept", acceptEncoding );
203 			}
204 		}
205 
206 		String encoding = System.getProperty( "soapui.request.encoding", StringUtils.unquote( request.getEncoding() ) );
207 
208 		if( formMp != null )
209 		{
210 			// create request message
211 			try
212 			{
213 				if( request.hasRequestBody() && httpMethod instanceof EntityEnclosingMethod )
214 				{
215 					String requestContent = PropertyExpansionUtils.expandProperties( context, request.getRequestContent(),
216 							request.isEntitizeProperties() );
217 					if( StringUtils.hasContent( requestContent ) )
218 					{
219 						initRootPart( request, requestContent, formMp );
220 					}
221 				}
222 
223 				for( Attachment attachment : request.getAttachments() )
224 				{
225 					MimeBodyPart part = new PreencodedMimeBodyPart( "binary" );
226 
227 					if( attachment instanceof FileAttachment<?> )
228 						part.setDisposition( "form-data; name=\"" + attachment.getName() + "\" filename=\""
229 								+ ( ( FileAttachment<?> )attachment ).getName() + "\"" );
230 					else
231 					part.setDisposition( "form-data; name=\"" + attachment.getName() + "\"" );
232 					
233 					part.setDataHandler( new DataHandler( new AttachmentDataSource( attachment ) ) );
234 
235 					formMp.addBodyPart( part );
236 				}
237 
238 				MimeMessage message = new MimeMessage( AttachmentUtils.JAVAMAIL_SESSION );
239 				message.setContent( formMp );
240 				message.saveChanges();
241 				RestRequestMimeMessageRequestEntity mimeMessageRequestEntity = new RestRequestMimeMessageRequestEntity(
242 						message, request );
243 				( ( EntityEnclosingMethod )httpMethod ).setRequestEntity( mimeMessageRequestEntity );
244 				httpMethod.setRequestHeader( "Content-Type", mimeMessageRequestEntity.getContentType() );
245 				httpMethod.setRequestHeader( "MIME-Version", "1.0" );
246 			}
247 			catch( Throwable e )
248 			{
249 				SoapUI.logError( e );
250 			}
251 		}
252 		else if( request.hasRequestBody() && httpMethod instanceof EntityEnclosingMethod )
253 		{
254 			httpMethod.setRequestHeader( "Content-Type", getContentTypeHeader( request.getMediaType(), encoding ) );
255 
256 			if( request.isPostQueryString() )
257 			{
258 				( ( EntityEnclosingMethod )httpMethod ).setRequestEntity( new StringRequestEntity( query.toString() ) );
259 			}
260 			else
261 			{
262 				String requestContent = PropertyExpansionUtils.expandProperties( context, request.getRequestContent(),
263 						request.isEntitizeProperties() );
264 				List<Attachment> attachments = new ArrayList<Attachment>();
265 
266 				for( Attachment attachment : request.getAttachments() )
267 				{
268 					if( attachment.getContentType().equals( request.getMediaType() ) )
269 					{
270 						attachments.add( attachment );
271 					}
272 				}
273 
274 				if( StringUtils.hasContent( requestContent ) && attachments.isEmpty() )
275 				{
276 					try
277 					{
278 						byte[] content = encoding == null ? requestContent.getBytes() : requestContent.getBytes( encoding );
279 						( ( EntityEnclosingMethod )httpMethod ).setRequestEntity( new ByteArrayRequestEntity( content ) );
280 					}
281 					catch( UnsupportedEncodingException e )
282 					{
283 						( ( EntityEnclosingMethod )httpMethod ).setRequestEntity( new ByteArrayRequestEntity( requestContent
284 								.getBytes() ) );
285 					}
286 				}
287 				else if( attachments.size() > 0 )
288 				{
289 					try
290 					{
291 						MimeMultipart mp = null;
292 
293 						if( StringUtils.hasContent( requestContent ) )
294 						{
295 							mp = new MimeMultipart();
296 							initRootPart( request, requestContent, mp );
297 						}
298 						else if( attachments.size() == 1 )
299 						{
300 							( ( EntityEnclosingMethod )httpMethod ).setRequestEntity( new InputStreamRequestEntity(
301 									attachments.get( 0 ).getInputStream() ) );
302 
303 							httpMethod.setRequestHeader( "Content-Type", getContentTypeHeader( request.getMediaType(),
304 									encoding ) );
305 						}
306 
307 						if( ( ( EntityEnclosingMethod )httpMethod ).getRequestEntity() == null )
308 						{
309 							if( mp == null )
310 								mp = new MimeMultipart();
311 
312 							// init mimeparts
313 							AttachmentUtils.addMimeParts( request, attachments, mp, new StringToStringMap() );
314 
315 							// create request message
316 							MimeMessage message = new MimeMessage( AttachmentUtils.JAVAMAIL_SESSION );
317 							message.setContent( mp );
318 							message.saveChanges();
319 							RestRequestMimeMessageRequestEntity mimeMessageRequestEntity = new RestRequestMimeMessageRequestEntity(
320 									message, request );
321 							( ( EntityEnclosingMethod )httpMethod ).setRequestEntity( mimeMessageRequestEntity );
322 							httpMethod.setRequestHeader( "Content-Type", getContentTypeHeader( mimeMessageRequestEntity
323 									.getContentType(), encoding ) );
324 							httpMethod.setRequestHeader( "MIME-Version", "1.0" );
325 						}
326 					}
327 					catch( Exception e )
328 					{
329 						e.printStackTrace();
330 					}
331 				}
332 			}
333 		}
334 	}
335 
336 	private String getContentTypeHeader( String contentType, String encoding )
337 	{
338 		return ( encoding == null || encoding.trim().length() == 0 ) ? contentType : contentType + ";charset=" + encoding;
339 	}
340 
341 	private void addFormMultipart( HttpRequestInterface<?> request, MimeMultipart formMp, String name, String value )
342 			throws MessagingException
343 	{
344 		MimeBodyPart part = new MimeBodyPart();
345 
346 		if( value.startsWith( "file:" ) )
347 		{
348 			String fileName = value.substring( 5 );
349 			File file = new File( fileName );
350 			part.setDisposition( "form-data; name=\"" + name + "\"; filename=\"" + file.getName() + "\"" );
351 			if( file.exists() )
352 			{
353 				part.setDataHandler( new DataHandler( new FileDataSource( file ) ) );
354 			}
355 			else
356 			{
357 				for( Attachment attachment : request.getAttachments() )
358 				{
359 					if( attachment.getName().equals( fileName ) )
360 					{
361 						part.setDataHandler( new DataHandler( new AttachmentDataSource( attachment ) ) );
362 						break;
363 					}
364 				}
365 			}
366 
367 			part.setHeader( "Content-Type", ContentTypeHandler.getContentTypeFromFilename( file.getName() ) );
368 			part.setHeader( "Content-Transfer-Encoding", "binary" );
369 		}
370 		else
371 		{
372 			part.setDisposition( "form-data; name=\"" + name + "\"" );
373 			part.setText( value, System.getProperty( "soapui.request.encoding", request.getEncoding() ) );
374 		}
375 
376 		if( part != null )
377 		{
378 			formMp.addBodyPart( part );
379 		}
380 	}
381 
382 	protected void initRootPart( HttpRequestInterface<?> wsdlRequest, String requestContent, MimeMultipart mp )
383 			throws MessagingException
384 	{
385 		MimeBodyPart rootPart = new PreencodedMimeBodyPart( "8bit" );
386 		// rootPart.setContentID( AttachmentUtils.ROOTPART_SOAPUI_ORG );
387 		mp.addBodyPart( rootPart, 0 );
388 
389 		DataHandler dataHandler = new DataHandler( new RestRequestDataSource( wsdlRequest, requestContent ) );
390 		rootPart.setDataHandler( dataHandler );
391 	}
392 }