Package com.fides

Source Code of com.fides.GrinderTCPProxy$TCPProxy$FilterChain

//   Copyright 2012 Giuseppe Iacono, Felipe Munoz Castillo
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

package com.fides;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import net.grinder.plugin.http.tcpproxyfilter.ConnectionCache;
import net.grinder.plugin.http.tcpproxyfilter.ConnectionHandlerFactoryImplementation;
import net.grinder.plugin.http.tcpproxyfilter.HTTPRecordingImplementation;
import net.grinder.plugin.http.tcpproxyfilter.HTTPRequestFilter;
import net.grinder.plugin.http.tcpproxyfilter.HTTPResponseFilter;
import net.grinder.plugin.http.tcpproxyfilter.ProcessHTTPRecordingWithXSLT;
import net.grinder.plugin.http.tcpproxyfilter.ProcessHTTPRecordingWithXSLT.BuiltInStyleSheet;
import net.grinder.plugin.http.tcpproxyfilter.ProcessHTTPRecordingWithXSLT.StyleSheetFile;
import net.grinder.plugin.http.tcpproxyfilter.RegularExpressionsImplementation;
import net.grinder.tools.tcpproxy.CommentSourceImplementation;
import net.grinder.tools.tcpproxy.CompositeFilter;
import net.grinder.tools.tcpproxy.ConnectionDetails;
import net.grinder.tools.tcpproxy.EchoFilter;
import net.grinder.tools.tcpproxy.EndPoint;
import net.grinder.tools.tcpproxy.HTTPProxyTCPProxyEngine;
import net.grinder.tools.tcpproxy.NullFilter;
import net.grinder.tools.tcpproxy.PortForwarderTCPProxyEngine;
import net.grinder.tools.tcpproxy.TCPProxyConsole;
import net.grinder.tools.tcpproxy.TCPProxyEngine;
import net.grinder.tools.tcpproxy.TCPProxyFilter;
import net.grinder.tools.tcpproxy.TCPProxySSLSocketFactory;
import net.grinder.tools.tcpproxy.TCPProxySSLSocketFactoryImplementation;
import net.grinder.tools.tcpproxy.UpdatableCommentSource;
import net.grinder.util.AbstractMainClass;
import net.grinder.util.AttributeStringParserImplementation;
import net.grinder.util.SimpleStringEscaper;
import net.grinder.util.http.URIParserImplementation;

import org.picocontainer.DefaultPicoContainer;
import org.picocontainer.PicoContainer;
import org.picocontainer.behaviors.Caching;
import org.picocontainer.monitors.ConsoleComponentMonitor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Run TCPProxy process.
*
* @goal TCPProxy
*
* @author Giuseppe Iacono
*/
public class GrinderTCPProxy extends GrinderPropertiesConfigure
  public final static class TCPProxy extends AbstractMainClass
  {
    private static final String USAGE = "  java "
        + TCPProxy.class.getName()
        + " <options>"
        + "\n\n"
        + "Commonly used options:"
        + "\n  [-http [oldjython|jython|clojure|<stylesheet>]]"
        + "\n                               See below."
        + "\n  [-console]                   Display the console."
        + "\n  [-requestfilter <filter>]    Add a request filter."
        + "\n  [-responsefilter <filter>]   Add a response filter."
        + "\n  [-localhost <host name/ip>]  Default is localhost."
        + "\n  [-localport <port>]          Default is 8001."
        + "\n  [-keystore <file>]           Key store details for"
        + "\n  [-keystorepassword <pass>]   SSL certificates."
        + "\n  [-keystoretype <type>]       Default is JSSE dependent."
        + "\n\n"
        + "Other options:"
        + "\n  [-properties <file>]         Properties to pass to the filters."
        + "\n  [-remotehost <host name>]    Default is localhost."
        + "\n  [-remoteport <port>]         Default is 7001."
        + "\n  [-timeout <seconds>]         Proxy engine timeout."
        + "\n  [-httpproxy <host> <port>]   Route via HTTP/HTTPS proxy."
        + "\n  [-httpsproxy <host> <port>]  Override -httpproxy settings for"
        + "\n                               HTTPS."
        + "\n  [-ssl]                       Use SSL when port forwarding."
        + "\n  [-colour]                    Be pretty on ANSI terminals."
        + "\n  [-component <class>]         Register a component class with"
        + "\n                               the filter PicoContainer."
        + "\n  [-debug]                     Make PicoContainer chatty."
        + "\n\n"
        + "<filter> is the name of a class that implements "
        + TCPProxyFilter.class.getName()
        + " or one of NONE, ECHO. The default "
        + "is ECHO. Multiple filters can be specified for each stream."
        + "\n\n"
        + "By default, the TCPProxy listens as an HTTP/HTTPS Proxy on "
        + "<localhost:localport>."
        + "\n\n"
        + "If either -remotehost or -remoteport is specified, the TCPProxy "
        + "acts a simple port forwarder between <localhost:localport> and "
        + "<remotehost:remoteport>. Specify -ssl for SSL support."
        + "\n\n"
        + "-http sets up request and response filters to produce a test script "
        + "suitable for use with the HTTP plugin. The keywords 'oldjython', "
        + "'jython', or 'clojure' can be used to set the script language; or the "
        + "filename of an alternative XSLT style sheet can be provided. The "
        + "default is 'oldjython' which creates a Jython script based on the "
        + "traditional (non-DCR) instrumentation."
        + "\n\n"
        + "-timeout is how long the TCPProxy will wait for a request "
        + "before timing out and freeing the local port. The TCPProxy will "
        + "not time out if there are active connections."
        + "\n\n"
        + "-console displays a simple control window that allows the TCPProxy "
        + "to be shutdown cleanly. This is needed because some shells, e.g. "
        + "Cygwin bash, do not allow Java processes to be interrupted cleanly, "
        + "so filters cannot rely on standard shutdown hooks. "
        + "\n\n"
        + "-httpproxy and -httpsproxy allow output to be directed through "
        + "another HTTP/HTTPS proxy; this may help you reach the Internet. "
        + "These options are not supported in port forwarding mode."
        + "\n\n" + "Typical usage: " + "\n  java " + TCPProxy.class
        + " -http -console > grinder.py" + "\n\n";

    /**
     * Entry point.
     *
     * @param args
     *            Command line arguments.
     */
    public static void main(String[] args)
    {
      final Logger logger = LoggerFactory.getLogger("tcpproxy");

      try {
        final TCPProxy tcpProxy = new TCPProxy(args, logger);
        tcpProxy.run();
      } catch (LoggedInitialisationException e) {
        System.exit(1);
      } catch (Throwable e) {
        logger.error("Could not initialise", e);
        System.exit(2);
      }

      System.exit(0);
    }

    private final DefaultPicoContainer m_filterContainer = new DefaultPicoContainer(
        new Caching());

    private final TCPProxyEngine m_proxyEngine;

    /**
     * Package scope for unit tests.
     */
    TCPProxy(String[] args, Logger logger) throws Exception
    {
      super(logger, USAGE);
     
      String tcpProxyDirectory = GrinderPropertiesConfigure.getTCP_PROXY_DIRECTORY();

      // make sure the fileOutput exists
      File fileOutput = new File(tcpProxyDirectory);
      if (fileOutput != null && !fileOutput.exists()) {
        fileOutput.mkdirs();             
      }
     
      String pathTest = tcpProxyDirectory + File.separator + "grinder.py";
      OutputStream out = new FileOutputStream(pathTest)
     
      final PrintWriter output = new PrintWriter(out);
     
      m_filterContainer.addComponent(output);

      m_filterContainer.addComponent(logger);

      final UpdatableCommentSource commentSource = new CommentSourceImplementation();
      m_filterContainer.addComponent(commentSource);

      // Default values.
      int localPort = 8001;
      String remoteHost = "localhost";
      String localHost = "localhost";
      int remotePort = 7001;
      boolean useSSLPortForwarding = false;
      File keyStoreFile = null;
      char[] keyStorePassword = null;
      String keyStoreType = null;
      boolean isHTTPProxy = true;
      boolean console = false;
      EndPoint chainedHTTPProxy = null;
      EndPoint chainedHTTPSProxy = null;
      int timeout = 0;
      boolean useColour = false;

      final FilterChain requestFilterChain = new FilterChain("request");
      final FilterChain responseFilterChain = new FilterChain("response");

      try {
        // Parse 1.
        for (int i = 0; i < args.length; i++) {
          if ("-properties".equalsIgnoreCase(args[i])) {
            final Properties properties = new Properties();
            final FileInputStream in = new FileInputStream(
                new File(args[++i]));
            try {
              properties.load(in);
            } finally {
              in.close();
            }
            System.getProperties().putAll(properties);
          }
        }

        // Parse 2.
        for (int i = 0; i < args.length; i++) {
          if ("-requestfilter".equalsIgnoreCase(args[i])) {
            requestFilterChain.add(args[++i]);
          } else if ("-responsefilter".equalsIgnoreCase(args[i])) {
            responseFilterChain.add(args[++i]);
          } else if ("-component".equalsIgnoreCase(args[i])) {
            final Class<?> componentClass;

            try {
              componentClass = Class.forName(args[++i]);
            } catch (ClassNotFoundException e) {
              throw barfError("Class '" + args[i]
                  + "' not found.");
            }
            m_filterContainer.addComponent(componentClass);
          } else if ("-http".equalsIgnoreCase(args[i])) {
            requestFilterChain.add(HTTPRequestFilter.class);
            responseFilterChain.add(HTTPResponseFilter.class);
            m_filterContainer
                .addComponent(AttributeStringParserImplementation.class);
            m_filterContainer.addComponent(ConnectionCache.class);
            m_filterContainer
                .addComponent(ConnectionHandlerFactoryImplementation.class);
            m_filterContainer
                .addComponent(HTTPRecordingImplementation.class);
            m_filterContainer
                .addComponent(ProcessHTTPRecordingWithXSLT.class);
            m_filterContainer
                .addComponent(RegularExpressionsImplementation.class);
            m_filterContainer
                .addComponent(URIParserImplementation.class);
            m_filterContainer
                .addComponent(SimpleStringEscaper.class);

            if (i + 1 < args.length && !args[i + 1].startsWith("-")) {
              final String s = args[++i];

              if ("oldjython".equals(s)) {
                // Default.
              } else if ("jython".equals(s)) {
                m_filterContainer
                    .addComponent(BuiltInStyleSheet.Jython);
              } else if ("clojure".equals(s)) {
                m_filterContainer
                    .addComponent(BuiltInStyleSheet.Clojure);
              } else {
                m_filterContainer
                    .addComponent(new StyleSheetFile(
                        new File(s)));
              }
            }
          } else if ("-localhost".equalsIgnoreCase(args[i])) {
            localHost = args[++i];
          } else if ("-localport".equalsIgnoreCase(args[i])) {
            localPort = Integer.parseInt(args[++i]);
          } else if ("-remotehost".equalsIgnoreCase(args[i])) {
            remoteHost = args[++i];
            isHTTPProxy = false;
          } else if ("-remoteport".equalsIgnoreCase(args[i])) {
            remotePort = Integer.parseInt(args[++i]);
            isHTTPProxy = false;
          } else if ("-ssl".equalsIgnoreCase(args[i])) {
            useSSLPortForwarding = true;
          } else if ("-keystore".equalsIgnoreCase(args[i])) {
            keyStoreFile = new File(args[++i]);
          } else if ("-keystorepassword".equalsIgnoreCase(args[i])
              || "-storepass".equalsIgnoreCase(args[i])) {
            keyStorePassword = args[++i].toCharArray();
          } else if ("-keystoretype".equalsIgnoreCase(args[i])
              || "-storetype".equalsIgnoreCase(args[i])) {
            keyStoreType = args[++i];
          } else if ("-timeout".equalsIgnoreCase(args[i])) {
            timeout = Integer.parseInt(args[++i]) * 1000;
          } else if ("-console".equalsIgnoreCase(args[i])) {
            console = true;
          } else if ("-colour".equalsIgnoreCase(args[i])
              || "-color".equalsIgnoreCase(args[i])) {
            useColour = true;
          } else if ("-properties".equalsIgnoreCase(args[i])) {
            /* Already handled */
            ++i;
          } else if ("-httpproxy".equalsIgnoreCase(args[i])) {
            chainedHTTPProxy = new EndPoint(args[++i],
                Integer.parseInt(args[++i]));
          } else if ("-httpsproxy".equalsIgnoreCase(args[i])) {
            chainedHTTPSProxy = new EndPoint(args[++i],
                Integer.parseInt(args[++i]));
          } else if ("-debug".equalsIgnoreCase(args[i])) {
            m_filterContainer
                .changeMonitor(new ConsoleComponentMonitor(
                    System.err));
          } else if ("-initialtest".equalsIgnoreCase(args[i])) {
            final String argument = i + 1 < args.length ? args[++i]
                : "123";
            throw barfError("-initialTest is no longer supported. "
                + "Use -DHTTPPlugin.initialTest=" + argument
                + " or the -properties option instead.");
          } else {
            throw barfUsage();
          }
        }
      } catch (FileNotFoundException fnfe) {
        throw barfError(fnfe.getMessage());
      } catch (IndexOutOfBoundsException e) {
        throw barfUsage();
      } catch (NumberFormatException e) {
        throw barfUsage();
      }

      if (timeout < 0) {
        throw barfError("Timeout must be non-negative.");
      }

      final EndPoint localEndPoint = new EndPoint(localHost, localPort);
      final EndPoint remoteEndPoint = new EndPoint(remoteHost, remotePort);

      if (chainedHTTPSProxy == null && chainedHTTPProxy != null) {
        chainedHTTPSProxy = chainedHTTPProxy;
      }

      if (chainedHTTPSProxy != null && !isHTTPProxy) {
        throw barfError("Routing through a HTTP/HTTPS proxy is not supported "
            + "in port forwarding mode.");
      }

      final TCPProxyFilter requestFilter = requestFilterChain
          .resolveFilter();
      final TCPProxyFilter responseFilter = responseFilterChain
          .resolveFilter();

      final StringBuilder startMessage = new StringBuilder();

      startMessage.append("Initialising as ");

      if (isHTTPProxy) {
        startMessage.append("an HTTP/HTTPS proxy");
      } else {
        if (useSSLPortForwarding) {
          startMessage.append("an SSL port forwarder");
        } else {
          startMessage.append("a TCP port forwarder");
        }
      }

      startMessage.append(" with the parameters:");
      startMessage.append("\n   Request filters:    ");
      startMessage.append(requestFilter);
      startMessage.append("\n   Response filters:   ");
      startMessage.append(responseFilter);
      startMessage.append("\n   Local address:      " + localEndPoint);

      if (!isHTTPProxy) {
        startMessage.append("\n   Remote address:     "
            + remoteEndPoint);
      }

      if (chainedHTTPProxy != null) {
        startMessage.append("\n   HTTP proxy:         "
            + chainedHTTPProxy);
      }

      if (chainedHTTPSProxy != null) {
        startMessage.append("\n   HTTPS proxy:        "
            + chainedHTTPSProxy);
      }

      if (keyStoreFile != null) {
        startMessage.append("\n   Key store:          ");
        startMessage.append(keyStoreFile.toString());

        // Key store password is optional.
        if (keyStorePassword != null) {
          startMessage.append("\n   Key store password: ");
          for (int i = 0; i < keyStorePassword.length; ++i) {
            startMessage.append('*');
          }
        }

        // Key store type can be null => use whatever
        // KeyStore.getDefaultType() says (we can't print the default
        // here without loading the JSSE).
        if (keyStoreType != null) {
          startMessage.append("\n   Key store type:     "
              + keyStoreType);
        }
      }

      logger.info(startMessage.toString());

      System.out.println("Valor de keyStoreFile: " + keyStoreFile);
     
      final TCPProxySSLSocketFactory sslSocketFactory = keyStoreFile != null ? new TCPProxySSLSocketFactoryImplementation(
          keyStoreFile, keyStorePassword, keyStoreType)
          : new TCPProxySSLSocketFactoryImplementation();

      m_filterContainer.start();

      if (isHTTPProxy) {
        m_proxyEngine = new HTTPProxyTCPProxyEngine(sslSocketFactory,
            requestFilter, responseFilter, output, logger,
            localEndPoint, useColour, timeout, chainedHTTPProxy,
            chainedHTTPSProxy);
      } else {
        if (useSSLPortForwarding) {
          m_proxyEngine = new PortForwarderTCPProxyEngine(
              sslSocketFactory, requestFilter, responseFilter,
              output, logger, new ConnectionDetails(
                  localEndPoint, remoteEndPoint, true),
              useColour, timeout);
        } else {
          m_proxyEngine = new PortForwarderTCPProxyEngine(
              requestFilter, responseFilter, output, logger,
              new ConnectionDetails(localEndPoint,
                  remoteEndPoint, false), useColour, timeout);
        }
      }

      if (console) {
        new TCPProxyConsole(m_proxyEngine, commentSource);
      }

      logger.info("Engine initialised, listening on port " + localPort);
    }

    private void run()
    {
      final Runnable shutdown = new Runnable() {
        private boolean m_stopped = false;

        public synchronized void run() {
          if (!m_stopped) {
            m_stopped = true;
            m_proxyEngine.stop();
            m_filterContainer.stop();
            m_filterContainer.dispose();
          }
        }
      };

      Runtime.getRuntime().addShutdownHook(new Thread(shutdown));

      m_proxyEngine.run();
      shutdown.run();

      getLogger().info("Engine exited");
    }

    private final class FilterChain
    {
      private final String m_type;
      private final List<String> m_filterKeys = new ArrayList<String>();
      private int m_value;

      public FilterChain(String type) {
        m_type = type;
      }

      public void add(Class<? extends TCPProxyFilter> theClass)
      {
        final String key = m_type + ++m_value;
        m_filterContainer.addComponent(key, theClass);
        m_filterKeys.add(key);
      }

      @SuppressWarnings("unchecked")
      public void add(String filterClassName)
          throws LoggedInitialisationException
      {
        if ("NONE".equals(filterClassName)) {
          add(NullFilter.class);
        } else if ("ECHO".equals(filterClassName)) {
          add(EchoFilter.class);
        } else {
          final Class<?> filterClass;

          try {
            filterClass = Class.forName(filterClassName);
          } catch (ClassNotFoundException e) {
            throw barfError("Class '" + filterClassName
                + "' not found.");
          }

          if (!TCPProxyFilter.class.isAssignableFrom(filterClass)) {
            throw barfError("The class '" + filterClass.getName()
                + "' does not implement the interface: '"
                + TCPProxyFilter.class.getName() + "'.");
          }

          add((Class<? extends TCPProxyFilter>) filterClass);
        }
      }

      public TCPProxyFilter resolveFilter()
      {
        if (m_filterKeys.size() == 0) {
          add(EchoFilter.class);
        }

        final CompositeFilter result = new CompositeFilter();

        for (String key : m_filterKeys) {
          result.add((TCPProxyFilter) m_filterContainer
              .getComponent(key));
        }

        return result;
      }
    }

    /**
     * Accessor for unit tests.
     */
    PicoContainer getFilterContainer() {
      return m_filterContainer;
    }
  }
 
  @Override
  protected String getJythonVersion() {   
    return GrinderPropertiesConfigure.GRINDER_JYTHON_VERSION;
  }

  public void execute()
  {
    String[] args = new String[2];
   
    args[0] = "-console";
    args[1] = "-http";

    TCPProxy.main(args);
  }
}


TOP

Related Classes of com.fides.GrinderTCPProxy$TCPProxy$FilterChain

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.