/*
* soapUI, copyright (C) 2004-2011 eviware.com
*
* soapUI is free software; you can redistribute it and/or modify it under the
* terms of version 2.1 of the GNU Lesser General Public License as published by
* the Free Software Foundation.
*
* soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details at gnu.org.
*/
package com.eviware.soapui.impl.wsdl.monitor.jettyproxy;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Enumeration;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.mortbay.util.IO;
import com.eviware.soapui.impl.wsdl.actions.monitor.SoapMonitorAction.LaunchForm;
import com.eviware.soapui.impl.wsdl.actions.monitor.SoapMonitorAction.SecurityTabForm;
import com.eviware.soapui.impl.wsdl.monitor.CaptureInputStream;
import com.eviware.soapui.impl.wsdl.monitor.JProxyServletWsdlMonitorMessageExchange;
import com.eviware.soapui.impl.wsdl.monitor.SoapMonitor;
import com.eviware.soapui.impl.wsdl.submit.transports.http.ExtendedHttpMethod;
import com.eviware.soapui.impl.wsdl.submit.transports.http.support.methods.ExtendedGetMethod;
import com.eviware.soapui.impl.wsdl.submit.transports.http.support.methods.ExtendedPostMethod;
import com.eviware.soapui.impl.wsdl.support.http.HttpClientSupport;
import com.eviware.soapui.impl.wsdl.support.http.ProxyUtils;
import com.eviware.soapui.impl.wsdl.support.http.SoapUIHostConfiguration;
import com.eviware.soapui.model.propertyexpansion.DefaultPropertyExpansionContext;
import com.eviware.soapui.support.types.StringToStringsMap;
import com.eviware.soapui.support.xml.XmlUtils;
public class TunnelServlet extends ProxyServlet
{
private String sslEndPoint;
private int sslPort = 443;
private String prot = "https://";
public TunnelServlet( SoapMonitor soapMonitor, String sslEndpoint )
{
super( soapMonitor );
if( !sslEndpoint.startsWith( "https" ) )
{
this.prot = "http://";
}
int prefix = sslEndpoint.indexOf( "://" );
int c = sslEndpoint.indexOf( prefix, ':' );
if( c > 0 )
{
this.sslPort = Integer.parseInt( sslEndpoint.substring( c + 1 ) );
this.sslEndPoint = sslEndpoint.substring( prefix, c );
}
else
{
if( prefix > 0 )
this.sslEndPoint = sslEndpoint.substring( prefix + 3 );
}
}
@Override
public void init( ServletConfig config ) throws ServletException
{
this.config = config;
this.context = config.getServletContext();
}
public void service( ServletRequest request, ServletResponse response ) throws ServletException, IOException
{
monitor.fireOnRequest( request, response );
if( response.isCommitted() )
return;
ExtendedHttpMethod postMethod;
// for this create ui server and port, properties.
InetSocketAddress inetAddress = new InetSocketAddress( sslEndPoint, sslPort );
HttpServletRequest httpRequest = ( HttpServletRequest )request;
if( httpRequest.getMethod().equals( "GET" ) )
postMethod = new ExtendedGetMethod();
else
postMethod = new ExtendedPostMethod();
JProxyServletWsdlMonitorMessageExchange capturedData = new JProxyServletWsdlMonitorMessageExchange( project );
capturedData.setRequestHost( httpRequest.getRemoteHost() );
capturedData.setRequestHeader( httpRequest );
capturedData.setTargetURL( this.prot + inetAddress.getHostName() );
CaptureInputStream capture = new CaptureInputStream( httpRequest.getInputStream() );
// copy headers
Enumeration<?> headerNames = httpRequest.getHeaderNames();
while( headerNames.hasMoreElements() )
{
String hdr = ( String )headerNames.nextElement();
String lhdr = hdr.toLowerCase();
if( "host".equals( lhdr ) )
{
Enumeration<?> vals = httpRequest.getHeaders( hdr );
while( vals.hasMoreElements() )
{
String val = ( String )vals.nextElement();
if( val.startsWith( "127.0.0.1" ) )
{
postMethod.addRequestHeader( hdr, sslEndPoint );
}
}
continue;
}
Enumeration<?> vals = httpRequest.getHeaders( hdr );
while( vals.hasMoreElements() )
{
String val = ( String )vals.nextElement();
if( val != null )
{
postMethod.addRequestHeader( hdr, val );
}
}
}
if( postMethod instanceof ExtendedPostMethod )
( ( ExtendedPostMethod )postMethod ).setRequestEntity( new InputStreamRequestEntity( capture, request
.getContentType() ) );
HostConfiguration hostConfiguration = new HostConfiguration();
httpRequest.getProtocol();
hostConfiguration.getParams().setParameter(
SoapUIHostConfiguration.SOAPUI_SSL_CONFIG,
settings.getString( SecurityTabForm.SSLTUNNEL_KEYSTOREPATH, "" ) + " "
+ settings.getString( SecurityTabForm.SSLTUNNEL_KEYSTOREPASSWORD, "" ) );
hostConfiguration.setHost( new URI( this.prot + sslEndPoint, true ) );
hostConfiguration = ProxyUtils.initProxySettings( settings, httpState, hostConfiguration, prot + sslEndPoint,
new DefaultPropertyExpansionContext( project ) );
if( sslEndPoint.indexOf( "/" ) < 0 )
postMethod.setPath( "/" );
else
postMethod.setPath( sslEndPoint.substring( sslEndPoint.indexOf( "/" ), sslEndPoint.length() ) );
monitor.fireBeforeProxy( request, response, postMethod, hostConfiguration );
if( settings.getBoolean( LaunchForm.SSLTUNNEL_REUSESTATE ) )
{
if( httpState == null )
httpState = new HttpState();
HttpClientSupport.getHttpClient().executeMethod( hostConfiguration, postMethod, httpState );
}
else
{
HttpClientSupport.getHttpClient().executeMethod( hostConfiguration, postMethod );
}
capturedData.stopCapture();
capturedData.setRequest( capture.getCapturedData() );
capturedData.setRawResponseBody( postMethod.getResponseBody() );
capturedData.setResponseHeader( postMethod );
capturedData.setRawRequestData( getRequestToBytes( request.toString(), postMethod, capture ) );
capturedData.setRawResponseData( getResponseToBytes( response.toString(), postMethod,
capturedData.getRawResponseBody() ) );
monitor.fireAfterProxy( request, response, postMethod, capturedData );
StringToStringsMap responseHeaders = capturedData.getResponseHeaders();
// copy headers to response
HttpServletResponse httpResponse = ( HttpServletResponse )response;
for( String name : responseHeaders.keySet() )
{
for( String header : responseHeaders.get( name ) )
httpResponse.addHeader( name, header );
}
IO.copy( new ByteArrayInputStream( capturedData.getRawResponseBody() ), httpResponse.getOutputStream() );
postMethod.releaseConnection();
synchronized( this )
{
monitor.addMessageExchange( capturedData );
}
capturedData = null;
}
private byte[] getResponseToBytes( String footer, ExtendedHttpMethod postMethod, byte[] res )
{
String response = footer;
Header[] headers = postMethod.getResponseHeaders();
for( Header header : headers )
{
response += header.toString();
}
response += "\n";
response += XmlUtils.prettyPrintXml( new String( res ) );
return response.getBytes();
}
private byte[] getRequestToBytes( String footer, ExtendedHttpMethod postMethod, CaptureInputStream capture )
{
String request = footer;
// Header[] headers = postMethod.getRequestHeaders();
// for (Header header : headers)
// {
// request += header.toString();
// }
request += "\n";
request += XmlUtils.prettyPrintXml( new String( capture.getCapturedData() ) );
return request.getBytes();
}
}