/*! * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program 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. * * Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved. */ package org.pentaho.platform.web.servlet; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.pentaho.platform.api.engine.IPentahoSession; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.web.servlet.messages.Messages; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Iterator; import java.util.Map; /** * * This servlet is used to Proxy a Servlet request to another server for processing and returns that result to the * caller as if this Servlet actiually serviced it. Setup the proxy by editing the <b>web.xml</b> to map the servlet * name you want to proxy to the Proxy Servlet class. * <p> * * <pre> * <servlet> * <servlet-name>ViewAction</servlet-name> * <servlet-class>com.pentaho.ui.servlet.ProxyServlet</servlet-class> * <init-param> * <param-name>ProxyURL</param-name> * <param-value>http://my.remoteserver.com:8080/pentaho</param-value> * </init-param> * </servlet> * </pre> * * In the above example, all requests to /ViewAction will be forwarded to the ViewAction Servlet running on the Pentaho * server atmy.remoteserver.com:8080 * * <p> * NOTES: * <p> * * For this to be useful, both Pentaho servers should be using the same database repository. * <p> * The recieving server should have the ProxyTrustingFilter enabled to handle authicentation. * <p> * This Servlet only works with GET requests. All requests in the Pentaho BI Platform are currently gets. * * @see com.pentaho.test.servlet.ProxyTrustingFilter * @author Doug Moran * */ public class ProxyServlet extends ServletBase { /** * */ private static final long serialVersionUID = 4680027723733552639L; private static final Log logger = LogFactory.getLog( ProxyServlet.class ); @Override public Log getLogger() { return ProxyServlet.logger; } String proxyURL = null; // "http://localhost:8080/pentaho"; String errorURL = null; // The URL to redirect to if the user is invalid /** * Base Constructor */ public ProxyServlet() { super(); } @Override public void init( final ServletConfig servletConfig ) throws ServletException { proxyURL = servletConfig.getInitParameter( "ProxyURL" ); //$NON-NLS-1$ if ( ( proxyURL == null ) ) { error( Messages.getInstance().getString( "ProxyServlet.ERROR_0001_NO_PROXY_URL_SPECIFIED" ) ); //$NON-NLS-1$ } else { proxyURL.trim(); try { URL url = new URL( proxyURL ); // Just doing this to verify // it's good info( Messages.getInstance().getString( "ProxyServlet.INFO_0001_URL_SELECTED", url.toExternalForm() ) ); // using 'url' to get rid of unused var compiler warning //$NON-NLS-1$ } catch ( Throwable t ) { error( Messages.getInstance().getErrorString( "ProxyServlet.ERROR_0002_INVALID_URL", proxyURL ) ); //$NON-NLS-1$ proxyURL = null; } } errorURL = servletConfig.getInitParameter( "ErrorURL" ); super.init( servletConfig ); } protected void doProxy( final HttpServletRequest request, final HttpServletResponse response ) throws IOException { if ( proxyURL == null ) { // Got nothing from web.xml return; } String servletPath = request.getServletPath(); // System .out.println( ">>>>>>>> REQ: " + request.getRequestURL().toString() ); //$NON-NLS-1$//$NON-NLS-2$ PentahoSystem.systemEntryPoint(); try { String theUrl = proxyURL + servletPath; PostMethod method = new PostMethod( theUrl ); // Copy the parameters from the request to the proxy // System .out.print( ">>>>>>>> PARAMS: " ); //$NON-NLS-1$ Map paramMap = request.getParameterMap(); Map.Entry entry; String[] array; for ( Iterator it = paramMap.entrySet().iterator(); it.hasNext(); ) { entry = (Map.Entry) it.next(); array = (String[]) entry.getValue(); for ( String element : array ) { method.addParameter( (String) entry.getKey(), element ); // System.out.print( (String)entry.getKey() + "=" + array[i] // + "&" ); //$NON-NLS-1$ //$NON-NLS-2$ } } // System.out.println( "" ); //$NON-NLS-1$ // Just in case someone is trying to spoof the proxy method.removeParameter( "_TRUST_USER_" ); //$NON-NLS-1$ // Get the user from the session IPentahoSession userSession = getPentahoSession( request ); String name = userSession.getName(); // Add the trusted user from the session if ( ( name != null ) && ( name.length() > 0 ) ) { method.addParameter( "_TRUST_USER_", name ); //$NON-NLS-1$ // System.out.println( ">>>>>>>> USR: " + name ); //$NON-NLS-1$ } else if ( ( errorURL != null ) && ( errorURL.trim().length() > 0 ) ) { response.sendRedirect( errorURL ); // System.out.println( ">>>>>>>> REDIR: " + errorURL ); // //$NON-NLS-1$ return; } // System.out.println( ">>>>>>>> PROXY: " + theUrl ); //$NON-NLS-1$ debug( Messages.getInstance().getString( "ProxyServlet.DEBUG_0001_OUTPUT_URL", theUrl ) ); //$NON-NLS-1$ // Now do the request HttpClient client = new HttpClient(); try { // Execute the method. int statusCode = client.executeMethod( method ); if ( statusCode != HttpStatus.SC_OK ) { error( Messages.getInstance().getErrorString( "ProxyServlet.ERROR_0003_REMOTE_HTTP_CALL_FAILED", method.getStatusLine().toString() ) ); //$NON-NLS-1$ return; } setHeader( "Content-Type", method, response ); //$NON-NLS-1$ setHeader( "Content-Length", method, response ); //$NON-NLS-1$ InputStream inStr = method.getResponseBodyAsStream(); ServletOutputStream outStr = response.getOutputStream(); int inCnt = 0; byte[] buf = new byte[2048]; while ( -1 != ( inCnt = inStr.read( buf ) ) ) { outStr.write( buf, 0, inCnt ); } } catch ( HttpException e ) { error( Messages.getInstance().getErrorString( "ProxyServlet.ERROR_0004_PROTOCOL_FAILURE" ), e ); //$NON-NLS-1$ e.printStackTrace(); } catch ( IOException e ) { error( Messages.getInstance().getErrorString( "ProxyServlet.ERROR_0005_TRANSPORT_FAILURE" ), e ); //$NON-NLS-1$ e.printStackTrace(); } finally { method.releaseConnection(); } } finally { PentahoSystem.systemExitPoint(); } } void setHeader( final String headerStr, final HttpMethod method, final HttpServletResponse response ) { Header header = method.getResponseHeader( headerStr ); if ( header != null ) { response.setHeader( headerStr, header.getValue() ); } } @Override protected void service( final HttpServletRequest arg0, final HttpServletResponse arg1 ) throws ServletException, IOException { // TODO Auto-generated method stub super.service( arg0, arg1 ); } @Override protected void doPost( final HttpServletRequest request, final HttpServletResponse response ) throws ServletException, IOException { doProxy( request, response ); } @Override protected void doGet( final HttpServletRequest request, final HttpServletResponse response ) throws ServletException, IOException { doProxy( request, response ); } }