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