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  package com.eviware.soapui.impl.wsdl.monitor.jettyproxy;
13  
14  import java.io.ByteArrayInputStream;
15  import java.io.IOException;
16  import java.net.InetSocketAddress;
17  import java.util.Enumeration;
18  
19  import javax.servlet.ServletConfig;
20  import javax.servlet.ServletException;
21  import javax.servlet.ServletRequest;
22  import javax.servlet.ServletResponse;
23  import javax.servlet.http.HttpServletRequest;
24  import javax.servlet.http.HttpServletResponse;
25  
26  import org.apache.commons.httpclient.Header;
27  import org.apache.commons.httpclient.HostConfiguration;
28  import org.apache.commons.httpclient.HttpMethodBase;
29  import org.apache.commons.httpclient.HttpState;
30  import org.apache.commons.httpclient.URI;
31  import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
32  import org.apache.commons.httpclient.params.HostParams;
33  import org.mortbay.util.IO;
34  
35  import com.eviware.soapui.impl.wsdl.actions.monitor.SoapMonitorAction.LaunchForm;
36  import com.eviware.soapui.impl.wsdl.monitor.JProxyServletWsdlMonitorMessageExchange;
37  import com.eviware.soapui.impl.wsdl.monitor.SoapMonitor;
38  import com.eviware.soapui.impl.wsdl.submit.transports.http.support.methods.ExtendedGetMethod;
39  import com.eviware.soapui.impl.wsdl.submit.transports.http.support.methods.ExtendedPostMethod;
40  import com.eviware.soapui.impl.wsdl.support.http.HttpClientSupport;
41  import com.eviware.soapui.impl.wsdl.support.http.ProxyUtils;
42  import com.eviware.soapui.impl.wsdl.support.http.SoapUIHostConfiguration;
43  import com.eviware.soapui.model.propertyexpansion.DefaultPropertyExpansionContext;
44  import com.eviware.soapui.support.types.StringToStringMap;
45  import com.eviware.soapui.support.xml.XmlUtils;
46  
47  public class TunnelServlet extends ProxyServlet
48  {
49  	private String sslEndPoint;
50  	private int sslPort = 443;
51  	private String prot = "https://";
52  
53  	public TunnelServlet( SoapMonitor soapMonitor, String sslEndpoint )
54  	{
55  		super( soapMonitor );
56  
57  		if( !sslEndpoint.startsWith( "https" ) )
58  		{
59  			this.prot = "http://";
60  		}
61  		int prefix = sslEndpoint.indexOf( "://" );
62  		int c = sslEndpoint.indexOf( prefix, ':' );
63  		if( c > 0 )
64  		{
65  			this.sslPort = Integer.parseInt( sslEndpoint.substring( c + 1 ) );
66  			this.sslEndPoint = sslEndpoint.substring( prefix, c );
67  		}
68  		else
69  		{
70  			if( prefix > 0 )
71  				this.sslEndPoint = sslEndpoint.substring( prefix + 3 );
72  		}
73  	}
74  
75  	@Override
76  	public void init( ServletConfig config ) throws ServletException
77  	{
78  		this.config = config;
79  		this.context = config.getServletContext();
80  
81  		client = HttpClientSupport.getHttpClient();
82  	}
83  
84  	public void service( ServletRequest request, ServletResponse response ) throws ServletException, IOException
85  	{
86  		monitor.fireOnRequest( request, response );
87  		if( response.isCommitted() )
88  			return;
89  
90  		HttpMethodBase postMethod;
91  
92  		// for this create ui server and port, properties.
93  		InetSocketAddress inetAddress = new InetSocketAddress( sslEndPoint, sslPort );
94  		HttpServletRequest httpRequest = ( HttpServletRequest )request;
95  		if( httpRequest.getMethod().equals( "GET" ) )
96  			postMethod = new ExtendedGetMethod();
97  		else
98  			postMethod = new ExtendedPostMethod();
99  
100 			JProxyServletWsdlMonitorMessageExchange capturedData = new JProxyServletWsdlMonitorMessageExchange( project );
101 			capturedData.setRequestHost( httpRequest.getRemoteHost() );
102 			capturedData.setRequestHeader( httpRequest );
103 			capturedData.setTargetURL( this.prot + inetAddress.getHostName() );
104 
105 		CaptureInputStream capture = new CaptureInputStream( httpRequest.getInputStream() );
106 
107 		// copy headers
108 		Enumeration<?> headerNames = httpRequest.getHeaderNames();
109 		while( headerNames.hasMoreElements() )
110 		{
111 			String hdr = ( String )headerNames.nextElement();
112 			String lhdr = hdr.toLowerCase();
113 
114 			if( "host".equals( lhdr ) )
115 			{
116 				Enumeration<?> vals = httpRequest.getHeaders( hdr );
117 				while( vals.hasMoreElements() )
118 				{
119 					String val = ( String )vals.nextElement();
120 					if( val.startsWith( "127.0.0.1" ) )
121 					{
122 						postMethod.addRequestHeader( hdr, sslEndPoint );
123 					}
124 				}
125 				continue;
126 			}
127 
128 			Enumeration<?> vals = httpRequest.getHeaders( hdr );
129 			while( vals.hasMoreElements() )
130 			{
131 				String val = ( String )vals.nextElement();
132 				if( val != null )
133 				{
134 					postMethod.addRequestHeader( hdr, val );
135 				}
136 			}
137 
138 		}
139 
140 		if( postMethod instanceof ExtendedPostMethod )
141 			( ( ExtendedPostMethod )postMethod ).setRequestEntity( new InputStreamRequestEntity( capture, request
142 					.getContentType() ) );
143 
144 		HostConfiguration hostConfiguration = new HostConfiguration();
145 
146 		httpRequest.getProtocol();
147 		hostConfiguration.getParams().setParameter(
148 				SoapUIHostConfiguration.SOAPUI_SSL_CONFIG,
149 				settings.getString( LaunchForm.SSLTUNNEL_KEYSTOREPATH, "" ) + " "
150 						+ settings.getString( LaunchForm.SSLTUNNEL_KEYSTOREPASSWORD, "" ) );
151 		hostConfiguration.setHost( new URI( this.prot + sslEndPoint, true ) );
152 
153 		hostConfiguration = ProxyUtils.initProxySettings( settings, httpState, hostConfiguration, prot + sslEndPoint,
154 				new DefaultPropertyExpansionContext( project ) );
155 
156 		HostParams param = hostConfiguration.getParams();
157 		if (sslEndPoint.indexOf( "/" ) < 0)
158 			postMethod.setPath( "/" );
159 		else
160 			postMethod.setPath( sslEndPoint.substring( sslEndPoint.indexOf( "/" ), sslEndPoint.length() ) );
161 
162 		monitor.fireBeforeProxy( request, response, postMethod, hostConfiguration );
163 
164 		if( settings.getBoolean( LaunchForm.SSLTUNNEL_REUSESTATE ) )
165 		{
166 			if( httpState == null )
167 				httpState = new HttpState();
168 			client.executeMethod( hostConfiguration, postMethod, httpState );
169 		}
170 		else
171 		{
172 			client.executeMethod( hostConfiguration, postMethod );
173 		}
174 		capturedData.stopCapture();
175 
176 		capturedData.setRequest( capture.getCapturedData() );
177 		capturedData.setRawResponseBody( postMethod.getResponseBody() );
178 		capturedData.setResponseHeader( postMethod );
179 		capturedData.setRawRequestData( getRequestToBytes( request.toString(), postMethod, capture ) );
180 		capturedData.setRawResponseData( getResponseToBytes( response.toString(), postMethod, capturedData
181 				.getRawResponseBody() ) );
182 
183 		monitor.fireAfterProxy( request, response, postMethod, capturedData );
184 
185 		StringToStringMap responseHeaders = capturedData.getResponseHeaders();
186 		// copy headers to response
187 		HttpServletResponse httpResponse = ( HttpServletResponse )response;
188 		for( String name : responseHeaders.keySet() )
189 		{
190 			String header = responseHeaders.get( name );
191 			httpResponse.addHeader( name, header );
192 
193 		}
194 
195 		IO.copy( new ByteArrayInputStream( capturedData.getRawResponseBody() ), httpResponse.getOutputStream() );
196 
197 		postMethod.releaseConnection();
198 
199 		monitor.addMessageExchange( capturedData );
200 		capturedData = null;
201 
202 	}
203 
204 	private byte[] getResponseToBytes( String footer, HttpMethodBase postMethod, byte[] res )
205 	{
206 		String response = footer;
207 
208 		Header[] headers = postMethod.getResponseHeaders();
209 		for( Header header : headers )
210 		{
211 			response += header.toString();
212 		}
213 		response += "\n";
214 		response += XmlUtils.prettyPrintXml( new String( res ) );
215 
216 		return response.getBytes();
217 	}
218 
219 	private byte[] getRequestToBytes( String footer, HttpMethodBase postMethod, CaptureInputStream capture )
220 	{
221 		String request = footer;
222 
223 		// Header[] headers = postMethod.getRequestHeaders();
224 		// for (Header header : headers)
225 		// {
226 		// request += header.toString();
227 		// }
228 		request += "\n";
229 		request += XmlUtils.prettyPrintXml( new String( capture.getCapturedData() ) );
230 
231 		return request.getBytes();
232 	}
233 
234 }