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.util.Enumeration;
17  import java.util.HashSet;
18  
19  import javax.servlet.Servlet;
20  import javax.servlet.ServletConfig;
21  import javax.servlet.ServletContext;
22  import javax.servlet.ServletException;
23  import javax.servlet.ServletRequest;
24  import javax.servlet.ServletResponse;
25  import javax.servlet.http.HttpServletRequest;
26  import javax.servlet.http.HttpServletResponse;
27  
28  import org.apache.commons.httpclient.Header;
29  import org.apache.commons.httpclient.HostConfiguration;
30  import org.apache.commons.httpclient.HttpClient;
31  import org.apache.commons.httpclient.HttpMethodBase;
32  import org.apache.commons.httpclient.HttpState;
33  import org.apache.commons.httpclient.URI;
34  import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
35  import org.mortbay.util.IO;
36  
37  import com.eviware.soapui.impl.wsdl.WsdlProject;
38  import com.eviware.soapui.impl.wsdl.actions.monitor.SoapMonitorAction.LaunchForm;
39  import com.eviware.soapui.impl.wsdl.monitor.JProxyServletWsdlMonitorMessageExchange;
40  import com.eviware.soapui.impl.wsdl.monitor.SoapMonitor;
41  import com.eviware.soapui.impl.wsdl.submit.transports.http.support.methods.ExtendedGetMethod;
42  import com.eviware.soapui.impl.wsdl.submit.transports.http.support.methods.ExtendedPostMethod;
43  import com.eviware.soapui.model.settings.Settings;
44  import com.eviware.soapui.support.types.StringToStringMap;
45  import com.eviware.soapui.support.xml.XmlUtils;
46  
47  public class ProxyServlet implements Servlet
48  {
49  
50  	protected ServletConfig config;
51  	protected ServletContext context;
52  	protected HttpClient client;
53  	protected SoapMonitor monitor;
54  	protected WsdlProject project;
55  	protected HttpState httpState = new HttpState();
56  	protected Settings settings;
57  
58  	static HashSet<String> dontProxyHeaders = new HashSet<String>();
59  	{
60  		dontProxyHeaders.add( "proxy-connection" );
61  		dontProxyHeaders.add( "connection" );
62  		dontProxyHeaders.add( "keep-alive" );
63  		dontProxyHeaders.add( "transfer-encoding" );
64  		dontProxyHeaders.add( "te" );
65  		dontProxyHeaders.add( "trailer" );
66  		dontProxyHeaders.add( "proxy-authorization" );
67  		dontProxyHeaders.add( "proxy-authenticate" );
68  		dontProxyHeaders.add( "upgrade" );
69  	}
70  
71  	public ProxyServlet( SoapMonitor soapMonitor )
72  	{
73  		this.monitor = soapMonitor;
74  		this.project = monitor.getProject();
75  		settings = project.getSettings();
76  	}
77  
78  	public void destroy()
79  	{
80  	}
81  
82  	public ServletConfig getServletConfig()
83  	{
84  		return config;
85  	}
86  
87  	public String getServletInfo()
88  	{
89  		return "SoapUI Monitor";
90  	}
91  
92  	public void init( ServletConfig config ) throws ServletException
93  	{
94  
95  		this.config = config;
96  		this.context = config.getServletContext();
97  
98  		client = new HttpClient();
99  
100 	}
101 
102 	public synchronized void service( ServletRequest request, ServletResponse response ) throws ServletException,
103 			IOException
104 	{
105 		monitor.fireOnRequest( request, response );
106 		if( response.isCommitted() )
107 			return;
108 
109 		HttpMethodBase method;
110 		HttpServletRequest httpRequest = ( HttpServletRequest )request;
111 		if( httpRequest.getMethod().equals( "GET" ) )
112 			method = new ExtendedGetMethod();
113 		else
114 			method = new ExtendedPostMethod();
115 
116 		// for this create ui server and port, properties.
117 		JProxyServletWsdlMonitorMessageExchange capturedData = new JProxyServletWsdlMonitorMessageExchange( project );
118 		capturedData.setRequestHost( httpRequest.getServerName() );
119 		capturedData.setRequestHeader( httpRequest );
120 		capturedData.setTargetURL( httpRequest.getRequestURL().toString() );
121 
122 		CaptureInputStream capture = new CaptureInputStream( httpRequest.getInputStream() );
123 
124 		// check connection header
125 		String connectionHeader = httpRequest.getHeader( "Connection" );
126 		if( connectionHeader != null )
127 		{
128 			connectionHeader = connectionHeader.toLowerCase();
129 			if( connectionHeader.indexOf( "keep-alive" ) < 0 && connectionHeader.indexOf( "close" ) < 0 )
130 				connectionHeader = null;
131 		}
132 
133 		// copy headers
134 		boolean xForwardedFor = false;
135 		@SuppressWarnings( "unused" )
136 		long contentLength = -1;
137 		Enumeration<?> headerNames = httpRequest.getHeaderNames();
138 		while( headerNames.hasMoreElements() )
139 		{
140 			String hdr = ( String )headerNames.nextElement();
141 			String lhdr = hdr.toLowerCase();
142 
143 			if( dontProxyHeaders.contains( lhdr ) )
144 				continue;
145 			if( connectionHeader != null && connectionHeader.indexOf( lhdr ) >= 0 )
146 				continue;
147 
148 			if( "content-length".equals( lhdr ) )
149 				contentLength = request.getContentLength();
150 
151 			Enumeration<?> vals = httpRequest.getHeaders( hdr );
152 			while( vals.hasMoreElements() )
153 			{
154 				String val = ( String )vals.nextElement();
155 				if( val != null )
156 				{
157 					method.setRequestHeader( lhdr, val );
158 					xForwardedFor |= "X-Forwarded-For".equalsIgnoreCase( hdr );
159 				}
160 			}
161 		}
162 
163 		// Proxy headers
164 		method.setRequestHeader( "Via", "SoapUI Monitor" );
165 		if( !xForwardedFor )
166 			method.addRequestHeader( "X-Forwarded-For", request.getRemoteAddr() );
167 
168 		if( method instanceof ExtendedPostMethod )
169 			( ( ExtendedPostMethod )method ).setRequestEntity( new InputStreamRequestEntity( capture, request
170 					.getContentType() ) );
171 
172 		HostConfiguration hostConfiguration = new HostConfiguration();
173 
174 		StringBuffer url = new StringBuffer( "http://" );
175 		url.append( httpRequest.getServerName() );
176 		if( httpRequest.getServerPort() != 80 )
177 			url.append( ":" + httpRequest.getServerPort() );
178 		if( httpRequest.getServletPath() != null )
179 		{
180 			url.append( httpRequest.getServletPath() );
181 			method.setPath( httpRequest.getServletPath() );
182 			if( httpRequest.getQueryString() != null )
183 			{
184 				url.append( "?" + httpRequest.getQueryString() );
185 				method.setPath( httpRequest.getServletPath() + "?" + httpRequest.getQueryString() );
186 			}
187 		}
188 		hostConfiguration.setHost( new URI( url.toString(), true ) );
189 
190 		// SoapUI.log("PROXY to:" + url);
191 
192 		monitor.fireBeforeProxy( request, response, method, hostConfiguration );
193 
194 		if( settings.getBoolean( LaunchForm.SSLTUNNEL_REUSESTATE ) )
195 		{
196 			if( httpState == null )
197 				httpState = new HttpState();
198 			client.executeMethod( hostConfiguration, method, httpState );
199 		}
200 		else
201 		{
202 			client.executeMethod( hostConfiguration, method );
203 		}
204 
205 		// wait for transaction to end and store it.
206 		capturedData.stopCapture();
207 
208 		capturedData.setRequest( capture.getCapturedData() );
209 		capturedData.setRawResponseBody( method.getResponseBody() );
210 		capturedData.setResponseHeader( method );
211 		capturedData.setRawRequestData( getRequestToBytes( request.toString(), method, capture ) );
212 		capturedData.setRawResponseData( getResponseToBytes( response.toString(), method, capturedData
213 				.getRawResponseBody() ) );
214 
215 		monitor.fireAfterProxy( request, response, method, capturedData );
216 
217 		if( !response.isCommitted() )
218 		{
219 			StringToStringMap responseHeaders = capturedData.getResponseHeaders();
220 			// capturedData = null;
221 
222 			// copy headers to response
223 			HttpServletResponse httpResponse = ( HttpServletResponse )response;
224 			for( String name : responseHeaders.keySet() )
225 			{
226 				String header = responseHeaders.get( name );
227 				if( !httpResponse.containsHeader( name ) )
228 					httpResponse.addHeader( name, header );
229 			}
230 
231 			IO.copy( new ByteArrayInputStream( capturedData.getRawResponseBody() ), httpResponse.getOutputStream() );
232 		}
233 
234 		monitor.addMessageExchange( capturedData );
235 	}
236 
237 	private byte[] getResponseToBytes( String footer, HttpMethodBase postMethod, byte[] res )
238 	{
239 		String response = footer;
240 
241 		Header[] headers = postMethod.getResponseHeaders();
242 		for( Header header : headers )
243 		{
244 			response += header.toString();
245 		}
246 		response += "\n";
247 		response += XmlUtils.prettyPrintXml( new String( res ) );
248 
249 		return response.getBytes();
250 	}
251 
252 	private byte[] getRequestToBytes( String footer, HttpMethodBase postMethod, CaptureInputStream capture )
253 	{
254 		String request = footer;
255 
256 		// Header[] headers = postMethod.getRequestHeaders();
257 		// for (Header header : headers)
258 		// {
259 		// request += header.toString();
260 		// }
261 		request += "\n";
262 		request += XmlUtils.prettyPrintXml( new String( capture.getCapturedData() ) );
263 
264 		return request.getBytes();
265 	}
266 
267 }